├── .gitignore ├── CONTRIBUTING.adoc ├── LICENSE ├── NOTICE ├── PULL_REQUEST_TEMPLATE.md ├── README.md ├── auth ├── auth.go ├── auth_test.go ├── authfakes │ └── fake_auth_client.go └── init_test.go ├── bin └── test ├── commands ├── access_tokens_service.go ├── access_tokens_service_test.go ├── artifact_reference.go ├── artifact_reference_test.go ├── artifactreference │ ├── artifact_reference_client.go │ ├── artifact_reference_client_test.go │ ├── artifactreferencefakes │ │ └── fake_pivnet_client.go │ └── init_test.go ├── commandsfakes │ ├── fake_artifact_reference_client.go │ ├── fake_authenticator.go │ ├── fake_curl_client.go │ ├── fake_dependency_specifier_client.go │ ├── fake_eulaclient.go │ ├── fake_file_group_client.go │ ├── fake_login_client.go │ ├── fake_logout_client.go │ ├── fake_pivnet_versions_client.go │ ├── fake_product_client.go │ ├── fake_product_file_client.go │ ├── fake_rchandler.go │ ├── fake_release_client.go │ ├── fake_release_dependency_client.go │ ├── fake_release_type_client.go │ ├── fake_release_upgrade_path_client.go │ ├── fake_subscription_group_client.go │ └── fake_user_group_client.go ├── curl.go ├── curl │ ├── curl_client.go │ ├── curl_client_test.go │ ├── curlfakes │ │ └── fake_pivnet_client.go │ └── init_test.go ├── curl_test.go ├── dependency_specifiers.go ├── dependency_specifiers_test.go ├── dependencyspecifier │ ├── dependency_specifier_client.go │ ├── dependency_specifier_client_test.go │ ├── dependencyspecifierfakes │ │ └── fake_pivnet_client.go │ └── init_test.go ├── eula.go ├── eula │ ├── eula_client.go │ ├── eula_client_test.go │ ├── eulafakes │ │ └── fake_pivnet_client.go │ └── init_test.go ├── eula_test.go ├── file_group.go ├── file_group_test.go ├── filegroup │ ├── file_group_client.go │ ├── file_group_client_test.go │ ├── filegroupfakes │ │ └── fake_pivnet_client.go │ └── init_test.go ├── help.go ├── init_test.go ├── login.go ├── login │ ├── init_test.go │ ├── login_client.go │ ├── login_client_test.go │ └── loginfakes │ │ ├── fake_pivnet_client.go │ │ └── fake_rchandler.go ├── login_test.go ├── logout.go ├── logout │ ├── init_test.go │ ├── logout_client.go │ ├── logout_client_test.go │ └── logoutfakes │ │ └── fake_rchandler.go ├── logout_test.go ├── pivnet.go ├── pivnet_test.go ├── pivnet_versions.go ├── pivnet_versions_test.go ├── pivnetversions │ ├── init_test.go │ ├── pivnet_versions_client.go │ ├── pivnet_versions_client_test.go │ └── pivnetversionsfakes │ │ └── fake_pivnet_client.go ├── product.go ├── product │ ├── init_test.go │ ├── product_client.go │ ├── product_client_test.go │ └── productfakes │ │ └── fake_pivnet_client.go ├── product_file.go ├── product_file_test.go ├── product_test.go ├── productfile │ ├── init_test.go │ ├── product_file_client.go │ ├── product_file_client_test.go │ └── productfilefakes │ │ ├── fake_file_summer.go │ │ ├── fake_filter.go │ │ └── fake_pivnet_client.go ├── release.go ├── release │ ├── init_test.go │ ├── release_client.go │ ├── release_client_test.go │ └── releasefakes │ │ └── fake_pivnet_client.go ├── release_dependency.go ├── release_dependency_test.go ├── release_test.go ├── release_type.go ├── release_type_test.go ├── release_upgrade_path.go ├── release_upgrade_path_test.go ├── releasedependency │ ├── init_test.go │ ├── release_dependency_client.go │ ├── release_dependency_client_test.go │ └── releasedependencyfakes │ │ └── fake_pivnet_client.go ├── releasetype │ ├── init_test.go │ ├── release_type_client.go │ ├── release_type_client_test.go │ └── releasetypefakes │ │ └── fake_pivnet_client.go ├── releaseupgradepath │ ├── init_test.go │ ├── release_upgrade_path_client.go │ ├── release_upgrade_path_client_test.go │ └── releaseupgradepathfakes │ │ ├── fake_filter.go │ │ └── fake_pivnet_client.go ├── subscription_group.go ├── subscription_group_test.go ├── subscriptiongroup │ ├── init_test.go │ ├── subscription_group_client.go │ ├── subscription_group_client_test.go │ └── subscriptiongroupfakes │ │ └── fake_pivnet_client.go ├── user_group.go ├── user_group_test.go ├── usergroup │ ├── init_test.go │ ├── user_group_client.go │ ├── user_group_client_test.go │ └── usergroupfakes │ │ └── fake_pivnet_client.go └── version.go ├── docs ├── content │ ├── about │ │ ├── license.md │ │ └── project-management.md │ ├── development │ │ ├── contributing.md │ │ ├── dependencies.md │ │ ├── prerequisites.md │ │ └── testing.md │ ├── examples │ │ └── usage.md │ ├── index.md │ ├── installation │ │ └── installing-the-cli.md │ └── reference │ │ ├── accept-eula.md │ │ ├── add-file-group.md │ │ ├── add-product-file.md │ │ ├── add-release-dependency.md │ │ ├── add-release-upgrade-path.md │ │ ├── add-user-group-member.md │ │ ├── add-user-group.md │ │ ├── create-dependency-specifier.md │ │ ├── create-file-group.md │ │ ├── create-product-file.md │ │ ├── create-release.md │ │ ├── create-user-group.md │ │ ├── curl.md │ │ ├── delete-dependency-specifier.md │ │ ├── delete-file-group.md │ │ ├── delete-product-file.md │ │ ├── delete-release.md │ │ ├── delete-user-group.md │ │ ├── dependency-specifier.md │ │ ├── dependency-specifiers.md │ │ ├── download-product-files.md │ │ ├── eula.md │ │ ├── eulas.md │ │ ├── file-group.md │ │ ├── file-groups.md │ │ ├── help.md │ │ ├── login.md │ │ ├── logout.md │ │ ├── product-file.md │ │ ├── product-files.md │ │ ├── product.md │ │ ├── products.md │ │ ├── release-dependencies.md │ │ ├── release-types.md │ │ ├── release-upgrade-paths.md │ │ ├── release.md │ │ ├── releases.md │ │ ├── remove-file-group.md │ │ ├── remove-product-file.md │ │ ├── remove-release-dependency.md │ │ ├── remove-release-upgrade-path.md │ │ ├── remove-user-group-member.md │ │ ├── remove-user-group.md │ │ ├── update-file-group.md │ │ ├── update-product-file.md │ │ ├── update-release.md │ │ ├── update-user-group.md │ │ ├── user-group.md │ │ ├── user-groups.md │ │ └── version.md ├── mkdocs.yml ├── readme.md └── theme │ └── material │ ├── 404.html │ ├── __init__.py │ ├── assets │ ├── images │ │ ├── favicon.png │ │ └── icons │ │ │ ├── bitbucket.4ebea66e.svg │ │ │ ├── github.a4034fb1.svg │ │ │ └── gitlab.348cdb3a.svg │ ├── javascripts │ │ ├── application.0cf9b500.js │ │ ├── lunr │ │ │ ├── lunr.da.js │ │ │ ├── lunr.de.js │ │ │ ├── lunr.du.js │ │ │ ├── lunr.es.js │ │ │ ├── lunr.fi.js │ │ │ ├── lunr.fr.js │ │ │ ├── lunr.hu.js │ │ │ ├── lunr.it.js │ │ │ ├── lunr.jp.js │ │ │ ├── lunr.multi.js │ │ │ ├── lunr.no.js │ │ │ ├── lunr.pt.js │ │ │ ├── lunr.ro.js │ │ │ ├── lunr.ru.js │ │ │ ├── lunr.stemmer.support.js │ │ │ ├── lunr.sv.js │ │ │ ├── lunr.tr.js │ │ │ └── tinyseg.js │ │ └── modernizr.1aa3b519.js │ └── stylesheets │ │ ├── application-palette.6079476c.css │ │ └── application.8d40d89b.css │ ├── base.html │ ├── main.html │ ├── mkdocs_theme.yml │ └── partials │ ├── footer.html │ ├── header.html │ ├── hero.html │ ├── integrations │ ├── analytics.html │ └── disqus.html │ ├── language.html │ ├── language │ ├── ar.html │ ├── ca.html │ ├── da.html │ ├── de.html │ ├── en.html │ ├── es.html │ ├── fa.html │ ├── fi.html │ ├── fr.html │ ├── gl.html │ ├── he.html │ ├── hu.html │ ├── it.html │ ├── ja.html │ ├── kr.html │ ├── nl.html │ ├── no.html │ ├── pl.html │ ├── pt.html │ ├── ru.html │ ├── sv.html │ ├── tr.html │ ├── uk.html │ ├── vi.html │ ├── zh-Hant.html │ └── zh.html │ ├── nav-item.html │ ├── nav.html │ ├── search.html │ ├── social.html │ ├── source.html │ ├── tabs-item.html │ ├── tabs.html │ ├── toc-item.html │ └── toc.html ├── errorhandler ├── error_handler.go ├── error_handler_test.go ├── errorhandlerfakes │ └── fake_error_handler.go └── init_test.go ├── filter ├── filter.go ├── filter_suite_test.go └── filter_test.go ├── go.mod ├── go.sum ├── gp ├── gp.go ├── gp_test.go ├── gpfakes │ └── fake_access_token_service.go └── init_test.go ├── hostwarning ├── host_warning.go ├── host_warning_suit_test.go └── host_warning_test.go ├── init_test.go ├── main.go ├── main_test.go ├── open_source_licenses.txt ├── printer ├── init_test.go ├── printer.go ├── printer_test.go └── printerfakes │ └── fake_printer.go ├── rc ├── filesystem │ ├── filesystem.go │ ├── filesystem_test.go │ ├── filesystem_unix_test.go │ └── init_test.go ├── init_test.go ├── profile.go ├── profile_test.go ├── rc.go ├── rc_test.go └── rcfakes │ └── fake_pivnet_rcread_writer.go ├── semver ├── init_test.go ├── semver.go └── semver_test.go ├── ui └── color.go └── version └── version.go /.gitignore: -------------------------------------------------------------------------------- 1 | pivnet-cli 2 | docs/site/ 3 | vendor 4 | .idea 5 | .gobincache 6 | 7 | -------------------------------------------------------------------------------- /CONTRIBUTING.adoc: -------------------------------------------------------------------------------- 1 | If you have not previously done so, please fill out and 2 | submit the https://cla.pivotal.io/sign/pivotal[Contributor License Agreement]. 3 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Pivotal Network CLI 2 | 3 | Copyright (c) 2015-2016 Pivotal, Inc. All Rights Reserved. 4 | 5 | This product is licensed to you under the Apache License, Version 2.0 (the "License"). 6 | You may not use this product except in compliance with the License. 7 | 8 | This product may include a number of subcomponents with separate copyright notices 9 | and license terms. Your use of these subcomponents is subject to the terms and 10 | conditions of the subcomponent's license, as noted in the LICENSE file. 11 | -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Thank you for contributing to the Pivnet CLI! 2 | 3 | - Have you made this pull request to the `master` branch? 4 | - Have you [run the tests locally](https://github.com/pivotal-cf/pivnet-cli#running-the-tests)? 5 | -------------------------------------------------------------------------------- /auth/auth.go: -------------------------------------------------------------------------------- 1 | package auth 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/pivotal-cf/pivnet-cli/v3/errorhandler" 7 | ) 8 | 9 | //go:generate counterfeiter . AuthClient 10 | type AuthClient interface { 11 | Auth() (bool, error) 12 | } 13 | 14 | type Authenticator struct { 15 | eh errorhandler.ErrorHandler 16 | } 17 | 18 | func NewAuthenticator(eh errorhandler.ErrorHandler) *Authenticator { 19 | return &Authenticator{ 20 | eh: eh, 21 | } 22 | } 23 | 24 | func (a *Authenticator) AuthenticateClient(client AuthClient) error { 25 | ok, err := client.Auth() 26 | if err != nil { 27 | return a.eh.HandleError(err) 28 | } 29 | 30 | if !ok { 31 | err = fmt.Errorf("Credentials rejected - please login again") 32 | return a.eh.HandleError(err) 33 | } 34 | 35 | return nil 36 | } 37 | -------------------------------------------------------------------------------- /auth/auth_test.go: -------------------------------------------------------------------------------- 1 | package auth_test 2 | 3 | import ( 4 | "fmt" 5 | 6 | . "github.com/onsi/ginkgo" 7 | . "github.com/onsi/gomega" 8 | "github.com/pivotal-cf/pivnet-cli/v3/auth" 9 | "github.com/pivotal-cf/pivnet-cli/v3/auth/authfakes" 10 | "github.com/pivotal-cf/pivnet-cli/v3/errorhandler/errorhandlerfakes" 11 | ) 12 | 13 | var _ = Describe("Authenticator", func() { 14 | var ( 15 | fakeErrorHandler *errorhandlerfakes.FakeErrorHandler 16 | 17 | authenticator *auth.Authenticator 18 | ) 19 | 20 | BeforeEach(func() { 21 | fakeErrorHandler = &errorhandlerfakes.FakeErrorHandler{} 22 | authenticator = auth.NewAuthenticator(fakeErrorHandler) 23 | }) 24 | 25 | Describe("AuthenticateClient", func() { 26 | var ( 27 | fakeAuthClient *authfakes.FakeAuthClient 28 | 29 | authOk bool 30 | authError error 31 | ) 32 | 33 | BeforeEach(func() { 34 | fakeAuthClient = &authfakes.FakeAuthClient{} 35 | 36 | authOk = true 37 | authError = nil 38 | }) 39 | 40 | JustBeforeEach(func() { 41 | fakeAuthClient.AuthReturns(authOk, authError) 42 | }) 43 | 44 | It("invokes the provided client", func() { 45 | err := authenticator.AuthenticateClient(fakeAuthClient) 46 | Expect(err).NotTo(HaveOccurred()) 47 | 48 | Expect(fakeAuthClient.AuthCallCount()).To(Equal(1)) 49 | }) 50 | 51 | Context("when client auth returns an error", func() { 52 | BeforeEach(func() { 53 | authError = fmt.Errorf("auth error") 54 | }) 55 | 56 | It("handles the error", func() { 57 | err := authenticator.AuthenticateClient(fakeAuthClient) 58 | Expect(err).NotTo(HaveOccurred()) 59 | 60 | Expect(fakeErrorHandler.HandleErrorCallCount()).To(Equal(1)) 61 | Expect(fakeErrorHandler.HandleErrorArgsForCall(0)).To(Equal(authError)) 62 | }) 63 | }) 64 | 65 | Context("when client auth returns not ok", func() { 66 | BeforeEach(func() { 67 | authOk = false 68 | }) 69 | 70 | It("handles an error", func() { 71 | err := authenticator.AuthenticateClient(fakeAuthClient) 72 | Expect(err).NotTo(HaveOccurred()) 73 | 74 | Expect(fakeErrorHandler.HandleErrorCallCount()).To(Equal(1)) 75 | Expect(fakeErrorHandler.HandleErrorArgsForCall(0).Error()).To(ContainSubstring("login again")) 76 | }) 77 | }) 78 | }) 79 | }) 80 | -------------------------------------------------------------------------------- /auth/authfakes/fake_auth_client.go: -------------------------------------------------------------------------------- 1 | // Code generated by counterfeiter. DO NOT EDIT. 2 | package authfakes 3 | 4 | import ( 5 | "sync" 6 | 7 | "github.com/pivotal-cf/pivnet-cli/v3/auth" 8 | ) 9 | 10 | type FakeAuthClient struct { 11 | AuthStub func() (bool, error) 12 | authMutex sync.RWMutex 13 | authArgsForCall []struct { 14 | } 15 | authReturns struct { 16 | result1 bool 17 | result2 error 18 | } 19 | authReturnsOnCall map[int]struct { 20 | result1 bool 21 | result2 error 22 | } 23 | invocations map[string][][]interface{} 24 | invocationsMutex sync.RWMutex 25 | } 26 | 27 | func (fake *FakeAuthClient) Auth() (bool, error) { 28 | fake.authMutex.Lock() 29 | ret, specificReturn := fake.authReturnsOnCall[len(fake.authArgsForCall)] 30 | fake.authArgsForCall = append(fake.authArgsForCall, struct { 31 | }{}) 32 | fake.recordInvocation("Auth", []interface{}{}) 33 | fake.authMutex.Unlock() 34 | if fake.AuthStub != nil { 35 | return fake.AuthStub() 36 | } 37 | if specificReturn { 38 | return ret.result1, ret.result2 39 | } 40 | fakeReturns := fake.authReturns 41 | return fakeReturns.result1, fakeReturns.result2 42 | } 43 | 44 | func (fake *FakeAuthClient) AuthCallCount() int { 45 | fake.authMutex.RLock() 46 | defer fake.authMutex.RUnlock() 47 | return len(fake.authArgsForCall) 48 | } 49 | 50 | func (fake *FakeAuthClient) AuthCalls(stub func() (bool, error)) { 51 | fake.authMutex.Lock() 52 | defer fake.authMutex.Unlock() 53 | fake.AuthStub = stub 54 | } 55 | 56 | func (fake *FakeAuthClient) AuthReturns(result1 bool, result2 error) { 57 | fake.authMutex.Lock() 58 | defer fake.authMutex.Unlock() 59 | fake.AuthStub = nil 60 | fake.authReturns = struct { 61 | result1 bool 62 | result2 error 63 | }{result1, result2} 64 | } 65 | 66 | func (fake *FakeAuthClient) AuthReturnsOnCall(i int, result1 bool, result2 error) { 67 | fake.authMutex.Lock() 68 | defer fake.authMutex.Unlock() 69 | fake.AuthStub = nil 70 | if fake.authReturnsOnCall == nil { 71 | fake.authReturnsOnCall = make(map[int]struct { 72 | result1 bool 73 | result2 error 74 | }) 75 | } 76 | fake.authReturnsOnCall[i] = struct { 77 | result1 bool 78 | result2 error 79 | }{result1, result2} 80 | } 81 | 82 | func (fake *FakeAuthClient) Invocations() map[string][][]interface{} { 83 | fake.invocationsMutex.RLock() 84 | defer fake.invocationsMutex.RUnlock() 85 | fake.authMutex.RLock() 86 | defer fake.authMutex.RUnlock() 87 | copiedInvocations := map[string][][]interface{}{} 88 | for key, value := range fake.invocations { 89 | copiedInvocations[key] = value 90 | } 91 | return copiedInvocations 92 | } 93 | 94 | func (fake *FakeAuthClient) recordInvocation(key string, args []interface{}) { 95 | fake.invocationsMutex.Lock() 96 | defer fake.invocationsMutex.Unlock() 97 | if fake.invocations == nil { 98 | fake.invocations = map[string][][]interface{}{} 99 | } 100 | if fake.invocations[key] == nil { 101 | fake.invocations[key] = [][]interface{}{} 102 | } 103 | fake.invocations[key] = append(fake.invocations[key], args) 104 | } 105 | 106 | var _ auth.AuthClient = new(FakeAuthClient) 107 | -------------------------------------------------------------------------------- /auth/init_test.go: -------------------------------------------------------------------------------- 1 | package auth_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/onsi/ginkgo" 7 | . "github.com/onsi/gomega" 8 | ) 9 | 10 | func TestAuth(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "Auth Suite") 13 | } 14 | -------------------------------------------------------------------------------- /bin/test: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eu 4 | 5 | # In seconds 6 | SLOW_SPEC_THRESHOLD="${SLOW_SPEC_THRESHOLD:-60}" 7 | 8 | my_dir="$( cd "$( dirname "${0}" )" && pwd )" 9 | base_dir="$( cd "${my_dir}/.." && pwd )" 10 | 11 | pushd "${base_dir}" > /dev/null 12 | CGO_ENABLED=1 ginkgo \ 13 | -r \ 14 | -race \ 15 | -p \ 16 | -randomizeAllSpecs \ 17 | -randomizeSuites \ 18 | -keepGoing \ 19 | -slowSpecThreshold="${SLOW_SPEC_THRESHOLD}" \ 20 | "$@" 21 | popd > /dev/null 22 | 23 | -------------------------------------------------------------------------------- /commands/access_tokens_service.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "fmt" 5 | "github.com/pivotal-cf/go-pivnet/v7" 6 | "github.com/pivotal-cf/pivnet-cli/v3/gp" 7 | "github.com/pivotal-cf/pivnet-cli/v3/rc" 8 | "time" 9 | ) 10 | 11 | var CreateAccessTokenService = func( 12 | rc RCHandler, 13 | profileName string, 14 | refreshToken string, 15 | host string, 16 | skipSSLValidation bool, 17 | ) gp.AccessTokenService { 18 | tokenService := pivnet.NewAccessTokenOrLegacyToken(refreshToken, host, skipSSLValidation, "Pivnet CLI") 19 | serviceThatSavesRc := CreateSaveTokenDecorator(rc, tokenService, profileName, refreshToken, host) 20 | return serviceThatSavesRc 21 | } 22 | 23 | type SaveTokenDecorator struct { 24 | WrappedService gp.AccessTokenService 25 | ProfileName string 26 | RefreshToken string 27 | Host string 28 | Rc RCHandler 29 | } 30 | 31 | func (o SaveTokenDecorator) AccessToken() (string, error) { 32 | pivnetProfile, err := o.Rc.ProfileForName(o.ProfileName) 33 | 34 | if err == nil && pivnetProfile != nil && validAccessToken(pivnetProfile) && o.notDuringLogin(pivnetProfile) { 35 | return pivnetProfile.AccessToken, nil 36 | } 37 | 38 | accessToken, err := o.WrappedService.AccessToken() 39 | if err != nil { 40 | return "", fmt.Errorf("could not get access token %s", err) 41 | } 42 | 43 | err = o.Rc.SaveProfile(o.ProfileName, o.RefreshToken, o.Host, accessToken, o.accessTokenExpiry()) 44 | if err != nil { 45 | return "", fmt.Errorf("failed to save profile %s", err) 46 | } 47 | 48 | return accessToken, nil 49 | } 50 | 51 | func (o SaveTokenDecorator) accessTokenExpiry() int64 { 52 | return time.Now().Add(time.Hour).Unix() 53 | } 54 | 55 | func (o SaveTokenDecorator) notDuringLogin(pivnetProfile *rc.PivnetProfile) bool { 56 | return pivnetProfile.Host == o.Host && pivnetProfile.APIToken == o.RefreshToken 57 | } 58 | 59 | func CreateSaveTokenDecorator(rc RCHandler, accessTokenService gp.AccessTokenService, profileName string, refreshToken string, host string) gp.AccessTokenService { 60 | return SaveTokenDecorator { 61 | WrappedService: accessTokenService, 62 | ProfileName: profileName, 63 | RefreshToken: refreshToken, 64 | Host: host, 65 | Rc: rc, 66 | } 67 | } 68 | 69 | func validAccessToken(pivnetProfile *rc.PivnetProfile) bool { 70 | return pivnetProfile.AccessToken != "" && pivnetProfile.AccessTokenExpiry > time.Now().Unix() 71 | } 72 | -------------------------------------------------------------------------------- /commands/artifactreference/init_test.go: -------------------------------------------------------------------------------- 1 | package artifactreference_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/onsi/ginkgo" 7 | . "github.com/onsi/gomega" 8 | ) 9 | 10 | func TestCommands(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "ArtifactReference suite") 13 | } 14 | -------------------------------------------------------------------------------- /commands/commandsfakes/fake_logout_client.go: -------------------------------------------------------------------------------- 1 | // Code generated by counterfeiter. DO NOT EDIT. 2 | package commandsfakes 3 | 4 | import ( 5 | "sync" 6 | 7 | "github.com/pivotal-cf/pivnet-cli/v3/commands" 8 | ) 9 | 10 | type FakeLogoutClient struct { 11 | LogoutStub func(string) error 12 | logoutMutex sync.RWMutex 13 | logoutArgsForCall []struct { 14 | arg1 string 15 | } 16 | logoutReturns struct { 17 | result1 error 18 | } 19 | logoutReturnsOnCall map[int]struct { 20 | result1 error 21 | } 22 | invocations map[string][][]interface{} 23 | invocationsMutex sync.RWMutex 24 | } 25 | 26 | func (fake *FakeLogoutClient) Logout(arg1 string) error { 27 | fake.logoutMutex.Lock() 28 | ret, specificReturn := fake.logoutReturnsOnCall[len(fake.logoutArgsForCall)] 29 | fake.logoutArgsForCall = append(fake.logoutArgsForCall, struct { 30 | arg1 string 31 | }{arg1}) 32 | fake.recordInvocation("Logout", []interface{}{arg1}) 33 | fake.logoutMutex.Unlock() 34 | if fake.LogoutStub != nil { 35 | return fake.LogoutStub(arg1) 36 | } 37 | if specificReturn { 38 | return ret.result1 39 | } 40 | fakeReturns := fake.logoutReturns 41 | return fakeReturns.result1 42 | } 43 | 44 | func (fake *FakeLogoutClient) LogoutCallCount() int { 45 | fake.logoutMutex.RLock() 46 | defer fake.logoutMutex.RUnlock() 47 | return len(fake.logoutArgsForCall) 48 | } 49 | 50 | func (fake *FakeLogoutClient) LogoutCalls(stub func(string) error) { 51 | fake.logoutMutex.Lock() 52 | defer fake.logoutMutex.Unlock() 53 | fake.LogoutStub = stub 54 | } 55 | 56 | func (fake *FakeLogoutClient) LogoutArgsForCall(i int) string { 57 | fake.logoutMutex.RLock() 58 | defer fake.logoutMutex.RUnlock() 59 | argsForCall := fake.logoutArgsForCall[i] 60 | return argsForCall.arg1 61 | } 62 | 63 | func (fake *FakeLogoutClient) LogoutReturns(result1 error) { 64 | fake.logoutMutex.Lock() 65 | defer fake.logoutMutex.Unlock() 66 | fake.LogoutStub = nil 67 | fake.logoutReturns = struct { 68 | result1 error 69 | }{result1} 70 | } 71 | 72 | func (fake *FakeLogoutClient) LogoutReturnsOnCall(i int, result1 error) { 73 | fake.logoutMutex.Lock() 74 | defer fake.logoutMutex.Unlock() 75 | fake.LogoutStub = nil 76 | if fake.logoutReturnsOnCall == nil { 77 | fake.logoutReturnsOnCall = make(map[int]struct { 78 | result1 error 79 | }) 80 | } 81 | fake.logoutReturnsOnCall[i] = struct { 82 | result1 error 83 | }{result1} 84 | } 85 | 86 | func (fake *FakeLogoutClient) Invocations() map[string][][]interface{} { 87 | fake.invocationsMutex.RLock() 88 | defer fake.invocationsMutex.RUnlock() 89 | fake.logoutMutex.RLock() 90 | defer fake.logoutMutex.RUnlock() 91 | copiedInvocations := map[string][][]interface{}{} 92 | for key, value := range fake.invocations { 93 | copiedInvocations[key] = value 94 | } 95 | return copiedInvocations 96 | } 97 | 98 | func (fake *FakeLogoutClient) recordInvocation(key string, args []interface{}) { 99 | fake.invocationsMutex.Lock() 100 | defer fake.invocationsMutex.Unlock() 101 | if fake.invocations == nil { 102 | fake.invocations = map[string][][]interface{}{} 103 | } 104 | if fake.invocations[key] == nil { 105 | fake.invocations[key] = [][]interface{}{} 106 | } 107 | fake.invocations[key] = append(fake.invocations[key], args) 108 | } 109 | 110 | var _ commands.LogoutClient = new(FakeLogoutClient) 111 | -------------------------------------------------------------------------------- /commands/commandsfakes/fake_release_type_client.go: -------------------------------------------------------------------------------- 1 | // Code generated by counterfeiter. DO NOT EDIT. 2 | package commandsfakes 3 | 4 | import ( 5 | "sync" 6 | 7 | "github.com/pivotal-cf/pivnet-cli/v3/commands" 8 | ) 9 | 10 | type FakeReleaseTypeClient struct { 11 | ListStub func() error 12 | listMutex sync.RWMutex 13 | listArgsForCall []struct { 14 | } 15 | listReturns struct { 16 | result1 error 17 | } 18 | listReturnsOnCall map[int]struct { 19 | result1 error 20 | } 21 | invocations map[string][][]interface{} 22 | invocationsMutex sync.RWMutex 23 | } 24 | 25 | func (fake *FakeReleaseTypeClient) List() error { 26 | fake.listMutex.Lock() 27 | ret, specificReturn := fake.listReturnsOnCall[len(fake.listArgsForCall)] 28 | fake.listArgsForCall = append(fake.listArgsForCall, struct { 29 | }{}) 30 | fake.recordInvocation("List", []interface{}{}) 31 | fake.listMutex.Unlock() 32 | if fake.ListStub != nil { 33 | return fake.ListStub() 34 | } 35 | if specificReturn { 36 | return ret.result1 37 | } 38 | fakeReturns := fake.listReturns 39 | return fakeReturns.result1 40 | } 41 | 42 | func (fake *FakeReleaseTypeClient) ListCallCount() int { 43 | fake.listMutex.RLock() 44 | defer fake.listMutex.RUnlock() 45 | return len(fake.listArgsForCall) 46 | } 47 | 48 | func (fake *FakeReleaseTypeClient) ListCalls(stub func() error) { 49 | fake.listMutex.Lock() 50 | defer fake.listMutex.Unlock() 51 | fake.ListStub = stub 52 | } 53 | 54 | func (fake *FakeReleaseTypeClient) ListReturns(result1 error) { 55 | fake.listMutex.Lock() 56 | defer fake.listMutex.Unlock() 57 | fake.ListStub = nil 58 | fake.listReturns = struct { 59 | result1 error 60 | }{result1} 61 | } 62 | 63 | func (fake *FakeReleaseTypeClient) ListReturnsOnCall(i int, result1 error) { 64 | fake.listMutex.Lock() 65 | defer fake.listMutex.Unlock() 66 | fake.ListStub = nil 67 | if fake.listReturnsOnCall == nil { 68 | fake.listReturnsOnCall = make(map[int]struct { 69 | result1 error 70 | }) 71 | } 72 | fake.listReturnsOnCall[i] = struct { 73 | result1 error 74 | }{result1} 75 | } 76 | 77 | func (fake *FakeReleaseTypeClient) Invocations() map[string][][]interface{} { 78 | fake.invocationsMutex.RLock() 79 | defer fake.invocationsMutex.RUnlock() 80 | fake.listMutex.RLock() 81 | defer fake.listMutex.RUnlock() 82 | copiedInvocations := map[string][][]interface{}{} 83 | for key, value := range fake.invocations { 84 | copiedInvocations[key] = value 85 | } 86 | return copiedInvocations 87 | } 88 | 89 | func (fake *FakeReleaseTypeClient) recordInvocation(key string, args []interface{}) { 90 | fake.invocationsMutex.Lock() 91 | defer fake.invocationsMutex.Unlock() 92 | if fake.invocations == nil { 93 | fake.invocations = map[string][][]interface{}{} 94 | } 95 | if fake.invocations[key] == nil { 96 | fake.invocations[key] = [][]interface{}{} 97 | } 98 | fake.invocations[key] = append(fake.invocations[key], args) 99 | } 100 | 101 | var _ commands.ReleaseTypeClient = new(FakeReleaseTypeClient) 102 | -------------------------------------------------------------------------------- /commands/curl.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import "github.com/pivotal-cf/pivnet-cli/v3/commands/curl" 4 | 5 | type Args struct { 6 | URL string `positional-arg-name:"URL" description:"URL without host or API prefix e.g. /products/p-mysql/releases/3451"` 7 | } 8 | 9 | type CurlCommand struct { 10 | Method string `long:"request" short:"X" description:"Custom method e.g. PATCH"` 11 | Data string `long:"data" short:"d" description:"Request data e.g. '{\"foo\":\"bar\"}'"` 12 | Args Args `positional-args:"yes" required:"true"` 13 | } 14 | 15 | //go:generate counterfeiter . CurlClient 16 | type CurlClient interface { 17 | MakeRequest(method string, body string, url string) error 18 | } 19 | 20 | var NewCurlClient = func(client curl.PivnetClient) CurlClient { 21 | return curl.NewCurlClient( 22 | client, 23 | ErrorHandler, 24 | Pivnet.Format, 25 | OutputWriter, 26 | Printer, 27 | ) 28 | } 29 | 30 | func (command *CurlCommand) Execute(args []string) error { 31 | err := Init(true) 32 | if err != nil { 33 | return err 34 | } 35 | 36 | client := NewPivnetClient() 37 | err = Auth.AuthenticateClient(client) 38 | if err != nil { 39 | return err 40 | } 41 | 42 | return NewCurlClient(client).MakeRequest(command.Method, command.Data, command.Args.URL) 43 | } 44 | -------------------------------------------------------------------------------- /commands/curl/curl_client.go: -------------------------------------------------------------------------------- 1 | package curl 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | 8 | "io" 9 | "net/http" 10 | "strings" 11 | 12 | "github.com/pivotal-cf/pivnet-cli/v3/errorhandler" 13 | "github.com/pivotal-cf/pivnet-cli/v3/printer" 14 | ) 15 | 16 | //go:generate counterfeiter . PivnetClient 17 | type PivnetClient interface { 18 | MakeRequest(method string, url string, expectedResponseCode int, body io.Reader) (*http.Response, error) 19 | } 20 | 21 | type CurlClient struct { 22 | pivnetClient PivnetClient 23 | eh errorhandler.ErrorHandler 24 | format string 25 | outputWriter io.Writer 26 | printer printer.Printer 27 | } 28 | 29 | func NewCurlClient( 30 | pivnetClient PivnetClient, 31 | eh errorhandler.ErrorHandler, 32 | format string, 33 | outputWriter io.Writer, 34 | printer printer.Printer, 35 | ) *CurlClient { 36 | return &CurlClient{ 37 | pivnetClient: pivnetClient, 38 | eh: eh, 39 | format: format, 40 | outputWriter: outputWriter, 41 | printer: printer, 42 | } 43 | } 44 | 45 | func (c *CurlClient) MakeRequest( 46 | method string, 47 | data string, 48 | url string, 49 | ) error { 50 | expectedResponseCode := 0 51 | var body io.Reader 52 | if data != "" { 53 | body = strings.NewReader(data) 54 | } 55 | 56 | var output interface{} 57 | resp, err := c.pivnetClient.MakeRequest( 58 | method, 59 | url, 60 | expectedResponseCode, 61 | body, 62 | ) 63 | if err != nil { 64 | return c.eh.HandleError(err) 65 | } 66 | defer resp.Body.Close() 67 | 68 | contentType := resp.Header.Get("Content-Type") 69 | 70 | if strings.ToLower(contentType) == "text/csv" { 71 | bodyBytes, err := ioutil.ReadAll(resp.Body) 72 | if err != nil { 73 | return c.eh.HandleError(err) 74 | } 75 | 76 | fmt.Println(string(bodyBytes)) 77 | 78 | return nil 79 | } 80 | 81 | err = json.NewDecoder(resp.Body).Decode(&output) 82 | if err != nil { 83 | return c.eh.HandleError(err) 84 | } 85 | 86 | c.printInterface(output) 87 | 88 | return nil 89 | } 90 | 91 | func (c *CurlClient) printInterface(object interface{}) error { 92 | if c.format == printer.PrintAsYAML { 93 | return c.printer.PrintYAML(object) 94 | } 95 | 96 | return c.printer.PrintJSON(object) 97 | } 98 | -------------------------------------------------------------------------------- /commands/curl/init_test.go: -------------------------------------------------------------------------------- 1 | package curl_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/onsi/ginkgo" 7 | . "github.com/onsi/gomega" 8 | ) 9 | 10 | func TestCommands(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "Curl commands suite") 13 | } 14 | -------------------------------------------------------------------------------- /commands/curl_test.go: -------------------------------------------------------------------------------- 1 | package commands_test 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | 8 | . "github.com/onsi/ginkgo" 9 | . "github.com/onsi/gomega" 10 | "github.com/pivotal-cf/pivnet-cli/v3/commands" 11 | "github.com/pivotal-cf/pivnet-cli/v3/commands/commandsfakes" 12 | "github.com/pivotal-cf/pivnet-cli/v3/commands/curl" 13 | ) 14 | 15 | var _ = Describe("curl commands", func() { 16 | var ( 17 | field reflect.StructField 18 | 19 | fakeCurlClient *commandsfakes.FakeCurlClient 20 | ) 21 | 22 | BeforeEach(func() { 23 | fakeCurlClient = &commandsfakes.FakeCurlClient{} 24 | 25 | commands.NewCurlClient = func(curl.PivnetClient) commands.CurlClient { 26 | return fakeCurlClient 27 | } 28 | }) 29 | 30 | Describe("CurlCommand", func() { 31 | var ( 32 | cmd *commands.CurlCommand 33 | ) 34 | 35 | BeforeEach(func() { 36 | cmd = &commands.CurlCommand{} 37 | }) 38 | 39 | It("invokes the curl client", func() { 40 | err := cmd.Execute(nil) 41 | 42 | Expect(err).NotTo(HaveOccurred()) 43 | 44 | Expect(fakeCurlClient.MakeRequestCallCount()).To(Equal(1)) 45 | }) 46 | 47 | Context("when the curl client returns an error", func() { 48 | var ( 49 | expectedErr error 50 | ) 51 | 52 | BeforeEach(func() { 53 | expectedErr = errors.New("expected error") 54 | fakeCurlClient.MakeRequestReturns(expectedErr) 55 | }) 56 | 57 | It("forwards the error", func() { 58 | err := cmd.Execute(nil) 59 | 60 | Expect(err).To(Equal(expectedErr)) 61 | }) 62 | }) 63 | 64 | Context("when Init returns an error", func() { 65 | BeforeEach(func() { 66 | initErr = fmt.Errorf("init error") 67 | }) 68 | 69 | It("forwards the error", func() { 70 | err := cmd.Execute(nil) 71 | 72 | Expect(err).To(Equal(initErr)) 73 | }) 74 | }) 75 | 76 | Context("when Authentication returns an error", func() { 77 | BeforeEach(func() { 78 | authErr = fmt.Errorf("auth error") 79 | }) 80 | 81 | It("forwards the error", func() { 82 | err := cmd.Execute(nil) 83 | 84 | Expect(err).To(Equal(authErr)) 85 | }) 86 | }) 87 | 88 | Describe("Method flag", func() { 89 | BeforeEach(func() { 90 | field = fieldFor(commands.CurlCommand{}, "Method") 91 | }) 92 | 93 | It("is not required", func() { 94 | Expect(isRequired(field)).To(BeFalse()) 95 | }) 96 | 97 | It("contains long name", func() { 98 | Expect(longTag(field)).To(Equal("request")) 99 | }) 100 | 101 | It("contains short name", func() { 102 | Expect(shortTag(field)).To(Equal("X")) 103 | }) 104 | }) 105 | 106 | Describe("Data flag", func() { 107 | BeforeEach(func() { 108 | field = fieldFor(commands.CurlCommand{}, "Data") 109 | }) 110 | 111 | It("is not required", func() { 112 | Expect(isRequired(field)).To(BeFalse()) 113 | }) 114 | 115 | It("contains long name", func() { 116 | Expect(longTag(field)).To(Equal("data")) 117 | }) 118 | 119 | It("contains short name", func() { 120 | Expect(shortTag(field)).To(Equal("d")) 121 | }) 122 | }) 123 | }) 124 | }) 125 | -------------------------------------------------------------------------------- /commands/dependencyspecifier/init_test.go: -------------------------------------------------------------------------------- 1 | package dependencyspecifier_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/onsi/ginkgo" 7 | . "github.com/onsi/gomega" 8 | ) 9 | 10 | func TestCommands(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "DependencySpecifier commands suite") 13 | } 14 | -------------------------------------------------------------------------------- /commands/eula.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import "github.com/pivotal-cf/pivnet-cli/v3/commands/eula" 4 | 5 | type EULAsCommand struct { 6 | } 7 | 8 | type EULACommand struct { 9 | EULASlug string `long:"eula-slug" description:"EULA slug e.g. pivotal_software_eula" required:"true"` 10 | } 11 | 12 | type AcceptEULACommand struct { 13 | ProductSlug string `long:"product-slug" short:"p" description:"Product slug e.g. p-mysql" required:"true"` 14 | ReleaseVersion string `long:"release-version" short:"r" description:"Release version e.g. 0.1.2-rc1" required:"true"` 15 | } 16 | 17 | //go:generate counterfeiter . EULAClient 18 | type EULAClient interface { 19 | List() error 20 | Get(eulaSlug string) error 21 | AcceptEULA(productSlug string, releaseVersion string) error 22 | } 23 | 24 | var NewEULAClient = func(client eula.PivnetClient) EULAClient { 25 | return eula.NewEULAClient( 26 | client, 27 | ErrorHandler, 28 | Pivnet.Format, 29 | OutputWriter, 30 | Printer, 31 | ) 32 | } 33 | 34 | func (command *EULAsCommand) Execute(args []string) error { 35 | err := Init(true) 36 | if err != nil { 37 | return err 38 | } 39 | 40 | client := NewPivnetClient() 41 | err = Auth.AuthenticateClient(client) 42 | if err != nil { 43 | return err 44 | } 45 | 46 | return NewEULAClient(client).List() 47 | } 48 | 49 | func (command *EULACommand) Execute(args []string) error { 50 | err := Init(true) 51 | if err != nil { 52 | return err 53 | } 54 | 55 | client := NewPivnetClient() 56 | err = Auth.AuthenticateClient(client) 57 | if err != nil { 58 | return err 59 | } 60 | 61 | return NewEULAClient(client).Get(command.EULASlug) 62 | } 63 | 64 | func (command *AcceptEULACommand) Execute(args []string) error { 65 | err := Init(true) 66 | if err != nil { 67 | return err 68 | } 69 | 70 | client := NewPivnetClient() 71 | err = Auth.AuthenticateClient(client) 72 | if err != nil { 73 | return err 74 | } 75 | 76 | return NewEULAClient(client).AcceptEULA(command.ProductSlug, command.ReleaseVersion) 77 | } 78 | -------------------------------------------------------------------------------- /commands/eula/init_test.go: -------------------------------------------------------------------------------- 1 | package eula_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/onsi/ginkgo" 7 | . "github.com/onsi/gomega" 8 | ) 9 | 10 | func TestCommands(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "EULA commands suite") 13 | } 14 | -------------------------------------------------------------------------------- /commands/filegroup/init_test.go: -------------------------------------------------------------------------------- 1 | package filegroup_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/onsi/ginkgo" 7 | . "github.com/onsi/gomega" 8 | ) 9 | 10 | func TestCommands(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "FileGroup commands suite") 13 | } 14 | -------------------------------------------------------------------------------- /commands/help.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import "errors" 4 | 5 | var ErrShowHelpMessage = errors.New("help command invoked") 6 | 7 | type HelpCommand struct{} 8 | 9 | func (command *HelpCommand) Execute(args []string) error { 10 | // Reset flags to avoid overriding defaults 11 | Pivnet.ProfileName = "" 12 | 13 | return ErrShowHelpMessage 14 | } 15 | -------------------------------------------------------------------------------- /commands/init_test.go: -------------------------------------------------------------------------------- 1 | package commands_test 2 | 3 | import ( 4 | "github.com/pivotal-cf/pivnet-cli/v3/gp" 5 | "github.com/pivotal-cf/pivnet-cli/v3/gp/gpfakes" 6 | "reflect" 7 | "testing" 8 | 9 | . "github.com/onsi/ginkgo" 10 | . "github.com/onsi/gomega" 11 | "github.com/pivotal-cf/pivnet-cli/v3/commands" 12 | "github.com/pivotal-cf/pivnet-cli/v3/commands/commandsfakes" 13 | "github.com/pivotal-cf/pivnet-cli/v3/printer" 14 | ) 15 | 16 | const ( 17 | apiPrefix = "/api/v2" 18 | apiToken = "some-api-token" 19 | ) 20 | 21 | func TestCommands(t *testing.T) { 22 | RegisterFailHandler(Fail) 23 | RunSpecs(t, "Commands Suite") 24 | } 25 | 26 | var ( 27 | fakeAuthenticator *commandsfakes.FakeAuthenticator 28 | fakeAccessTokenService *gpfakes.FakeAccessTokenService 29 | authErr error 30 | 31 | initInvocationArg bool 32 | initErr error 33 | 34 | origInitFunc func(bool) error 35 | ) 36 | 37 | var _ = BeforeSuite(func() { 38 | origInitFunc = commands.Init 39 | 40 | commands.Pivnet = commands.PivnetCommand{ 41 | Format: printer.PrintAsJSON, 42 | } 43 | }) 44 | 45 | var _ = BeforeEach(func() { 46 | fakeAuthenticator = &commandsfakes.FakeAuthenticator{} 47 | fakeAccessTokenService = &gpfakes.FakeAccessTokenService{} 48 | commands.Auth = fakeAuthenticator 49 | authErr = nil 50 | 51 | initErr = nil 52 | 53 | commands.CreateAccessTokenService = func(rc commands.RCHandler, 54 | profileName string, 55 | refreshToken string, 56 | host string, 57 | skipSSLValidation bool, 58 | ) gp.AccessTokenService { 59 | return fakeAccessTokenService 60 | } 61 | }) 62 | 63 | var _ = JustBeforeEach(func() { 64 | commands.Init = func(arg bool) error { 65 | initInvocationArg = arg 66 | return initErr 67 | } 68 | 69 | fakeAuthenticator.AuthenticateClientReturns(authErr) 70 | }) 71 | 72 | func fieldFor(command interface{}, name string) reflect.StructField { 73 | field, success := reflect.TypeOf(command).FieldByName(name) 74 | Expect(success).To(BeTrue(), "Expected %s field to exist on command", name) 75 | return field 76 | } 77 | 78 | func longTag(f reflect.StructField) string { 79 | return f.Tag.Get("long") 80 | } 81 | 82 | func shortTag(f reflect.StructField) string { 83 | return f.Tag.Get("short") 84 | } 85 | 86 | var alias = func(f reflect.StructField) string { 87 | return f.Tag.Get("alias") 88 | } 89 | 90 | var command = func(f reflect.StructField) string { 91 | return f.Tag.Get("command") 92 | } 93 | 94 | var isRequired = func(f reflect.StructField) bool { 95 | return f.Tag.Get("required") == "true" 96 | } 97 | 98 | var defaultVal = func(f reflect.StructField) string { 99 | return f.Tag.Get("default") 100 | } 101 | -------------------------------------------------------------------------------- /commands/login.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "github.com/pivotal-cf/pivnet-cli/v3/commands/login" 5 | ) 6 | 7 | type LoginCommand struct { 8 | APIToken string `long:"api-token" description:"Pivnet API Token (Pivnet legacy token or UAA refresh token)" required:"true"` 9 | Host string `long:"host" description:"Pivnet API Host" default:"https://network.tanzu.vmware.com"` 10 | } 11 | 12 | //go:generate counterfeiter . LoginClient 13 | type LoginClient interface { 14 | Login(name string, apiToken string, host string) error 15 | } 16 | 17 | var NewLoginClient = func(client login.PivnetClient) LoginClient { 18 | return login.NewLoginClient( 19 | client, 20 | RC, 21 | ErrorHandler, 22 | Pivnet.Format, 23 | OutputWriter, 24 | Printer, 25 | ) 26 | } 27 | 28 | func (command *LoginCommand) Execute([]string) error { 29 | err := Init(false) 30 | if err != nil { 31 | return err 32 | } 33 | 34 | sanitizeWriters(command.APIToken) 35 | 36 | accessTokenService := CreateAccessTokenService(RC, Pivnet.ProfileName, command.APIToken, command.Host, Pivnet.SkipSSLValidation) 37 | 38 | client := NewPivnetClientWithToken(accessTokenService, command.Host) 39 | 40 | return NewLoginClient(client).Login( 41 | Pivnet.ProfileName, 42 | command.APIToken, 43 | command.Host, 44 | ) 45 | } 46 | -------------------------------------------------------------------------------- /commands/login/init_test.go: -------------------------------------------------------------------------------- 1 | package login_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/onsi/ginkgo" 7 | . "github.com/onsi/gomega" 8 | ) 9 | 10 | func TestCommands(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "Login commands suite") 13 | } 14 | -------------------------------------------------------------------------------- /commands/login/login_client.go: -------------------------------------------------------------------------------- 1 | package login 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | 7 | "github.com/pivotal-cf/pivnet-cli/v3/errorhandler" 8 | "github.com/pivotal-cf/pivnet-cli/v3/printer" 9 | "github.com/pivotal-cf/pivnet-cli/v3/ui" 10 | ) 11 | 12 | //go:generate counterfeiter . PivnetClient 13 | type PivnetClient interface { 14 | Auth() (bool, error) 15 | } 16 | 17 | //go:generate counterfeiter . RCHandler 18 | type RCHandler interface { 19 | SaveProfile(profileName string, apiToken string, host string, accessToken string, accessTokenExpiry int64) error 20 | } 21 | 22 | type LoginClient struct { 23 | pivnetClient PivnetClient 24 | rcHandler RCHandler 25 | eh errorhandler.ErrorHandler 26 | format string 27 | outputWriter io.Writer 28 | printer printer.Printer 29 | } 30 | 31 | func NewLoginClient( 32 | pivnetClient PivnetClient, 33 | rcHandler RCHandler, 34 | eh errorhandler.ErrorHandler, 35 | format string, 36 | outputWriter io.Writer, 37 | printer printer.Printer, 38 | ) *LoginClient { 39 | return &LoginClient{ 40 | pivnetClient: pivnetClient, 41 | rcHandler: rcHandler, 42 | eh: eh, 43 | format: format, 44 | outputWriter: outputWriter, 45 | printer: printer, 46 | } 47 | } 48 | 49 | func (c *LoginClient) Login( 50 | profileName string, 51 | apiToken string, 52 | host string, 53 | ) error { 54 | const legacyAPITokenLength = 20 55 | if len(apiToken) <= legacyAPITokenLength { 56 | message := "Warning: The use of static Pivnet API tokens is deprecated and will be removed. Please see https://network.tanzu.vmware.com/docs/api#how-to-authenticate for details on the new UAA API Token mechanism." 57 | coloredMessage := ui.ErrorColor.SprintFunc()(message) 58 | fmt.Fprintln(c.outputWriter, coloredMessage) 59 | } 60 | 61 | ok, err := c.pivnetClient.Auth() 62 | if err != nil { 63 | return c.eh.HandleError(err) 64 | } 65 | 66 | if !ok { 67 | err := fmt.Errorf("Failed to login") 68 | return c.eh.HandleError(err) 69 | } 70 | 71 | return c.printLogin() 72 | } 73 | 74 | func (c *LoginClient) printLogin() error { 75 | switch c.format { 76 | 77 | case printer.PrintAsTable: 78 | message := "Logged-in successfully" 79 | coloredMessage := ui.SuccessColor.SprintFunc()(message) 80 | 81 | _, err := fmt.Fprintln(c.outputWriter, coloredMessage) 82 | 83 | return err 84 | } 85 | 86 | return nil 87 | } 88 | -------------------------------------------------------------------------------- /commands/login/login_client_test.go: -------------------------------------------------------------------------------- 1 | package login_test 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | . "github.com/onsi/ginkgo" 7 | . "github.com/onsi/gomega" 8 | "github.com/pivotal-cf/pivnet-cli/v3/commands/login" 9 | "github.com/pivotal-cf/pivnet-cli/v3/commands/login/loginfakes" 10 | "github.com/pivotal-cf/pivnet-cli/v3/errorhandler/errorhandlerfakes" 11 | "github.com/pivotal-cf/pivnet-cli/v3/printer" 12 | ) 13 | 14 | var _ = Describe("login commands", func() { 15 | var ( 16 | fakePivnetClient *loginfakes.FakePivnetClient 17 | fakeRCHandler *loginfakes.FakeRCHandler 18 | fakeErrorHandler *errorhandlerfakes.FakeErrorHandler 19 | 20 | outBuffer bytes.Buffer 21 | 22 | client *login.LoginClient 23 | ) 24 | 25 | BeforeEach(func() { 26 | fakePivnetClient = &loginfakes.FakePivnetClient{} 27 | fakeRCHandler = &loginfakes.FakeRCHandler{} 28 | 29 | outBuffer = bytes.Buffer{} 30 | 31 | fakeErrorHandler = &errorhandlerfakes.FakeErrorHandler{} 32 | 33 | client = login.NewLoginClient( 34 | fakePivnetClient, 35 | fakeRCHandler, 36 | fakeErrorHandler, 37 | printer.PrintAsJSON, 38 | &outBuffer, 39 | printer.NewPrinter(&outBuffer), 40 | ) 41 | }) 42 | 43 | Describe("Login", func() { 44 | var ( 45 | profileName string 46 | apiToken string 47 | host string 48 | 49 | authResult bool 50 | authErr error 51 | 52 | saveProfileErr error 53 | ) 54 | 55 | BeforeEach(func() { 56 | profileName = "some-login-slug" 57 | apiToken = "some-api-token" 58 | host = "some-host" 59 | 60 | authResult = true 61 | authErr = nil 62 | 63 | saveProfileErr = nil 64 | }) 65 | 66 | JustBeforeEach(func() { 67 | fakePivnetClient.AuthReturns(authResult, authErr) 68 | fakeRCHandler.SaveProfileReturns(saveProfileErr) 69 | }) 70 | 71 | It("authenticates", func() { 72 | err := client.Login( 73 | profileName, 74 | apiToken, 75 | host, 76 | ) 77 | Expect(err).NotTo(HaveOccurred()) 78 | 79 | Expect(fakePivnetClient.AuthCallCount()).To(Equal(1)) 80 | }) 81 | 82 | Context("when there is an error authenticating", func() { 83 | BeforeEach(func() { 84 | authErr = fmt.Errorf("auth error") 85 | }) 86 | 87 | It("invokes the error handler", func() { 88 | err := client.Login( 89 | profileName, 90 | apiToken, 91 | host, 92 | ) 93 | Expect(err).NotTo(HaveOccurred()) 94 | 95 | Expect(fakeErrorHandler.HandleErrorCallCount()).To(Equal(1)) 96 | Expect(fakeErrorHandler.HandleErrorArgsForCall(0)).To(Equal(authErr)) 97 | }) 98 | }) 99 | 100 | Context("when authenticating fails", func() { 101 | BeforeEach(func() { 102 | authResult = false 103 | }) 104 | 105 | It("invokes the error handler", func() { 106 | err := client.Login( 107 | profileName, 108 | apiToken, 109 | host, 110 | ) 111 | Expect(err).NotTo(HaveOccurred()) 112 | 113 | Expect(fakeErrorHandler.HandleErrorCallCount()).To(Equal(1)) 114 | Expect(fakeErrorHandler.HandleErrorArgsForCall(0).Error()).To(ContainSubstring("login")) 115 | }) 116 | }) 117 | }) 118 | }) 119 | -------------------------------------------------------------------------------- /commands/login/loginfakes/fake_pivnet_client.go: -------------------------------------------------------------------------------- 1 | // Code generated by counterfeiter. DO NOT EDIT. 2 | package loginfakes 3 | 4 | import ( 5 | "sync" 6 | 7 | "github.com/pivotal-cf/pivnet-cli/v3/commands/login" 8 | ) 9 | 10 | type FakePivnetClient struct { 11 | AuthStub func() (bool, error) 12 | authMutex sync.RWMutex 13 | authArgsForCall []struct { 14 | } 15 | authReturns struct { 16 | result1 bool 17 | result2 error 18 | } 19 | authReturnsOnCall map[int]struct { 20 | result1 bool 21 | result2 error 22 | } 23 | invocations map[string][][]interface{} 24 | invocationsMutex sync.RWMutex 25 | } 26 | 27 | func (fake *FakePivnetClient) Auth() (bool, error) { 28 | fake.authMutex.Lock() 29 | ret, specificReturn := fake.authReturnsOnCall[len(fake.authArgsForCall)] 30 | fake.authArgsForCall = append(fake.authArgsForCall, struct { 31 | }{}) 32 | fake.recordInvocation("Auth", []interface{}{}) 33 | fake.authMutex.Unlock() 34 | if fake.AuthStub != nil { 35 | return fake.AuthStub() 36 | } 37 | if specificReturn { 38 | return ret.result1, ret.result2 39 | } 40 | fakeReturns := fake.authReturns 41 | return fakeReturns.result1, fakeReturns.result2 42 | } 43 | 44 | func (fake *FakePivnetClient) AuthCallCount() int { 45 | fake.authMutex.RLock() 46 | defer fake.authMutex.RUnlock() 47 | return len(fake.authArgsForCall) 48 | } 49 | 50 | func (fake *FakePivnetClient) AuthCalls(stub func() (bool, error)) { 51 | fake.authMutex.Lock() 52 | defer fake.authMutex.Unlock() 53 | fake.AuthStub = stub 54 | } 55 | 56 | func (fake *FakePivnetClient) AuthReturns(result1 bool, result2 error) { 57 | fake.authMutex.Lock() 58 | defer fake.authMutex.Unlock() 59 | fake.AuthStub = nil 60 | fake.authReturns = struct { 61 | result1 bool 62 | result2 error 63 | }{result1, result2} 64 | } 65 | 66 | func (fake *FakePivnetClient) AuthReturnsOnCall(i int, result1 bool, result2 error) { 67 | fake.authMutex.Lock() 68 | defer fake.authMutex.Unlock() 69 | fake.AuthStub = nil 70 | if fake.authReturnsOnCall == nil { 71 | fake.authReturnsOnCall = make(map[int]struct { 72 | result1 bool 73 | result2 error 74 | }) 75 | } 76 | fake.authReturnsOnCall[i] = struct { 77 | result1 bool 78 | result2 error 79 | }{result1, result2} 80 | } 81 | 82 | func (fake *FakePivnetClient) Invocations() map[string][][]interface{} { 83 | fake.invocationsMutex.RLock() 84 | defer fake.invocationsMutex.RUnlock() 85 | fake.authMutex.RLock() 86 | defer fake.authMutex.RUnlock() 87 | copiedInvocations := map[string][][]interface{}{} 88 | for key, value := range fake.invocations { 89 | copiedInvocations[key] = value 90 | } 91 | return copiedInvocations 92 | } 93 | 94 | func (fake *FakePivnetClient) recordInvocation(key string, args []interface{}) { 95 | fake.invocationsMutex.Lock() 96 | defer fake.invocationsMutex.Unlock() 97 | if fake.invocations == nil { 98 | fake.invocations = map[string][][]interface{}{} 99 | } 100 | if fake.invocations[key] == nil { 101 | fake.invocations[key] = [][]interface{}{} 102 | } 103 | fake.invocations[key] = append(fake.invocations[key], args) 104 | } 105 | 106 | var _ login.PivnetClient = new(FakePivnetClient) 107 | -------------------------------------------------------------------------------- /commands/login_test.go: -------------------------------------------------------------------------------- 1 | package commands_test 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "reflect" 8 | 9 | . "github.com/onsi/ginkgo" 10 | . "github.com/onsi/gomega" 11 | "github.com/pivotal-cf/pivnet-cli/v3/commands" 12 | "github.com/pivotal-cf/pivnet-cli/v3/commands/commandsfakes" 13 | "github.com/pivotal-cf/pivnet-cli/v3/commands/login" 14 | ) 15 | 16 | var _ = Describe("login commands", func() { 17 | var ( 18 | field reflect.StructField 19 | 20 | fakeLoginClient *commandsfakes.FakeLoginClient 21 | ) 22 | 23 | BeforeEach(func() { 24 | fakeLoginClient = &commandsfakes.FakeLoginClient{} 25 | 26 | commands.NewLoginClient = func(login.PivnetClient) commands.LoginClient { 27 | return fakeLoginClient 28 | } 29 | }) 30 | 31 | Describe("LoginCommand", func() { 32 | var ( 33 | cmd commands.LoginCommand 34 | ) 35 | 36 | BeforeEach(func() { 37 | cmd.APIToken = "some-api-token" 38 | }) 39 | 40 | It("invokes the Login client", func() { 41 | err := cmd.Execute(nil) 42 | 43 | Expect(err).NotTo(HaveOccurred()) 44 | 45 | Expect(fakeLoginClient.LoginCallCount()).To(Equal(1)) 46 | }) 47 | 48 | It("invokes the Init function with 'false'", func() { 49 | err := cmd.Execute(nil) 50 | 51 | Expect(err).NotTo(HaveOccurred()) 52 | 53 | Expect(initInvocationArg).To(BeFalse()) 54 | }) 55 | 56 | Context("when the Login client returns an error", func() { 57 | var ( 58 | expectedErr error 59 | ) 60 | 61 | BeforeEach(func() { 62 | expectedErr = errors.New("expected error") 63 | fakeLoginClient.LoginReturns(expectedErr) 64 | }) 65 | 66 | It("forwards the error", func() { 67 | err := cmd.Execute(nil) 68 | 69 | Expect(err).To(Equal(expectedErr)) 70 | }) 71 | }) 72 | 73 | Context("when Init returns an error", func() { 74 | BeforeEach(func() { 75 | initErr = fmt.Errorf("init error") 76 | }) 77 | 78 | It("forwards the error", func() { 79 | err := cmd.Execute(nil) 80 | 81 | Expect(err).To(Equal(initErr)) 82 | }) 83 | }) 84 | 85 | It("sanitizes new api token", func() { 86 | outBuffer := bytes.Buffer{} 87 | commands.OutputWriter = &outBuffer 88 | 89 | err := cmd.Execute(nil) 90 | Expect(err).NotTo(HaveOccurred()) 91 | 92 | _, err = fmt.Fprintf(commands.OutputWriter, apiToken) 93 | Expect(err).NotTo(HaveOccurred()) 94 | 95 | Expect(outBuffer.String()).Should(ContainSubstring("*** redacted api token ***")) 96 | Expect(outBuffer.String()).ShouldNot(ContainSubstring(apiToken)) 97 | }) 98 | 99 | Describe("APIToken flag", func() { 100 | BeforeEach(func() { 101 | field = fieldFor(cmd, "APIToken") 102 | }) 103 | 104 | It("is required", func() { 105 | Expect(isRequired(field)).To(BeTrue()) 106 | }) 107 | 108 | It("contains long name", func() { 109 | Expect(longTag(field)).To(Equal("api-token")) 110 | }) 111 | }) 112 | 113 | Describe("Host flag", func() { 114 | BeforeEach(func() { 115 | field = fieldFor(cmd, "Host") 116 | }) 117 | 118 | It("contains long flag", func() { 119 | Expect(longTag(field)).To(Equal("host")) 120 | }) 121 | 122 | It("is not required", func() { 123 | Expect(isRequired(field)).To(BeFalse()) 124 | }) 125 | 126 | It("has a default value", func() { 127 | Expect(defaultVal(field)).To(Equal("https://network.tanzu.vmware.com")) 128 | }) 129 | }) 130 | 131 | }) 132 | }) 133 | -------------------------------------------------------------------------------- /commands/logout.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import "github.com/pivotal-cf/pivnet-cli/v3/commands/logout" 4 | 5 | type LogoutCommand struct { 6 | } 7 | 8 | //go:generate counterfeiter . LogoutClient 9 | type LogoutClient interface { 10 | Logout(profileName string) error 11 | } 12 | 13 | var NewLogoutClient = func() LogoutClient { 14 | return logout.NewLogoutClient( 15 | RC, 16 | ErrorHandler, 17 | Pivnet.Format, 18 | OutputWriter, 19 | Printer, 20 | ) 21 | } 22 | 23 | func (command *LogoutCommand) Execute([]string) error { 24 | err := Init(false) 25 | if err != nil { 26 | return err 27 | } 28 | 29 | return NewLogoutClient().Logout( 30 | Pivnet.ProfileName, 31 | ) 32 | } 33 | -------------------------------------------------------------------------------- /commands/logout/init_test.go: -------------------------------------------------------------------------------- 1 | package logout_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/onsi/ginkgo" 7 | . "github.com/onsi/gomega" 8 | ) 9 | 10 | func TestCommands(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "Logout commands suite") 13 | } 14 | -------------------------------------------------------------------------------- /commands/logout/logout_client.go: -------------------------------------------------------------------------------- 1 | package logout 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | 7 | "github.com/pivotal-cf/pivnet-cli/v3/errorhandler" 8 | "github.com/pivotal-cf/pivnet-cli/v3/printer" 9 | "github.com/pivotal-cf/pivnet-cli/v3/ui" 10 | ) 11 | 12 | //go:generate counterfeiter . RCHandler 13 | type RCHandler interface { 14 | RemoveProfileWithName(profileName string) error 15 | } 16 | 17 | type LogoutClient struct { 18 | rcHandler RCHandler 19 | eh errorhandler.ErrorHandler 20 | format string 21 | outputWriter io.Writer 22 | printer printer.Printer 23 | } 24 | 25 | func NewLogoutClient( 26 | rcHandler RCHandler, 27 | eh errorhandler.ErrorHandler, 28 | format string, 29 | outputWriter io.Writer, 30 | printer printer.Printer, 31 | ) *LogoutClient { 32 | return &LogoutClient{ 33 | rcHandler: rcHandler, 34 | eh: eh, 35 | format: format, 36 | outputWriter: outputWriter, 37 | printer: printer, 38 | } 39 | } 40 | 41 | func (c *LogoutClient) Logout(profileName string) error { 42 | err := c.rcHandler.RemoveProfileWithName(profileName) 43 | if err != nil { 44 | return c.eh.HandleError(err) 45 | } 46 | 47 | return c.printLogout() 48 | } 49 | 50 | func (c *LogoutClient) printLogout() error { 51 | switch c.format { 52 | 53 | case printer.PrintAsTable: 54 | message := "Logged-out successfully" 55 | coloredMessage := ui.SuccessColor.SprintFunc()(message) 56 | 57 | _, err := fmt.Fprintln(c.outputWriter, coloredMessage) 58 | 59 | return err 60 | } 61 | 62 | return nil 63 | } 64 | -------------------------------------------------------------------------------- /commands/logout/logout_client_test.go: -------------------------------------------------------------------------------- 1 | package logout_test 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | 7 | . "github.com/onsi/ginkgo" 8 | . "github.com/onsi/gomega" 9 | "github.com/pivotal-cf/pivnet-cli/v3/commands/logout" 10 | "github.com/pivotal-cf/pivnet-cli/v3/commands/logout/logoutfakes" 11 | "github.com/pivotal-cf/pivnet-cli/v3/errorhandler/errorhandlerfakes" 12 | "github.com/pivotal-cf/pivnet-cli/v3/printer" 13 | ) 14 | 15 | var _ = Describe("logout commands", func() { 16 | var ( 17 | fakeRCHandler *logoutfakes.FakeRCHandler 18 | fakeErrorHandler *errorhandlerfakes.FakeErrorHandler 19 | 20 | outBuffer bytes.Buffer 21 | 22 | client *logout.LogoutClient 23 | ) 24 | 25 | BeforeEach(func() { 26 | fakeRCHandler = &logoutfakes.FakeRCHandler{} 27 | 28 | outBuffer = bytes.Buffer{} 29 | 30 | fakeErrorHandler = &errorhandlerfakes.FakeErrorHandler{} 31 | 32 | client = logout.NewLogoutClient( 33 | fakeRCHandler, 34 | fakeErrorHandler, 35 | printer.PrintAsJSON, 36 | &outBuffer, 37 | printer.NewPrinter(&outBuffer), 38 | ) 39 | }) 40 | 41 | Describe("Logout", func() { 42 | var ( 43 | profileName string 44 | 45 | removeProfileErr error 46 | ) 47 | 48 | BeforeEach(func() { 49 | profileName = "some-logout-slug" 50 | 51 | removeProfileErr = nil 52 | }) 53 | 54 | JustBeforeEach(func() { 55 | fakeRCHandler.RemoveProfileWithNameReturns(removeProfileErr) 56 | }) 57 | 58 | It("removes profile", func() { 59 | err := client.Logout(profileName) 60 | Expect(err).NotTo(HaveOccurred()) 61 | 62 | Expect(fakeRCHandler.RemoveProfileWithNameCallCount()).To(Equal(1)) 63 | invokedProfileName := fakeRCHandler.RemoveProfileWithNameArgsForCall(0) 64 | 65 | Expect(invokedProfileName).To(Equal(profileName)) 66 | }) 67 | 68 | Context("when removing profile returns an error", func() { 69 | BeforeEach(func() { 70 | removeProfileErr = fmt.Errorf("remove profile error") 71 | }) 72 | 73 | It("invokes the error handler", func() { 74 | err := client.Logout(profileName) 75 | Expect(err).NotTo(HaveOccurred()) 76 | 77 | Expect(fakeErrorHandler.HandleErrorCallCount()).To(Equal(1)) 78 | Expect(fakeErrorHandler.HandleErrorArgsForCall(0)).To(Equal(removeProfileErr)) 79 | }) 80 | }) 81 | }) 82 | }) 83 | -------------------------------------------------------------------------------- /commands/logout_test.go: -------------------------------------------------------------------------------- 1 | package commands_test 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | 7 | . "github.com/onsi/ginkgo" 8 | . "github.com/onsi/gomega" 9 | "github.com/pivotal-cf/pivnet-cli/v3/commands" 10 | "github.com/pivotal-cf/pivnet-cli/v3/commands/commandsfakes" 11 | ) 12 | 13 | var _ = Describe("logout commands", func() { 14 | var ( 15 | fakeLogoutClient *commandsfakes.FakeLogoutClient 16 | ) 17 | 18 | BeforeEach(func() { 19 | fakeLogoutClient = &commandsfakes.FakeLogoutClient{} 20 | 21 | commands.NewLogoutClient = func() commands.LogoutClient { 22 | return fakeLogoutClient 23 | } 24 | }) 25 | 26 | Describe("LogoutCommand", func() { 27 | var ( 28 | cmd commands.LogoutCommand 29 | ) 30 | 31 | It("invokes the Logout client", func() { 32 | err := cmd.Execute(nil) 33 | 34 | Expect(err).NotTo(HaveOccurred()) 35 | 36 | Expect(fakeLogoutClient.LogoutCallCount()).To(Equal(1)) 37 | }) 38 | 39 | It("invokes the Init function with 'false'", func() { 40 | err := cmd.Execute(nil) 41 | 42 | Expect(err).NotTo(HaveOccurred()) 43 | 44 | Expect(initInvocationArg).To(BeFalse()) 45 | }) 46 | 47 | Context("when the Logout client returns an error", func() { 48 | var ( 49 | expectedErr error 50 | ) 51 | 52 | BeforeEach(func() { 53 | expectedErr = errors.New("expected error") 54 | fakeLogoutClient.LogoutReturns(expectedErr) 55 | }) 56 | 57 | It("forwards the error", func() { 58 | err := cmd.Execute(nil) 59 | 60 | Expect(err).To(Equal(expectedErr)) 61 | }) 62 | }) 63 | 64 | Context("when Init returns an error", func() { 65 | BeforeEach(func() { 66 | initErr = fmt.Errorf("init error") 67 | }) 68 | 69 | It("forwards the error", func() { 70 | err := cmd.Execute(nil) 71 | 72 | Expect(err).To(Equal(initErr)) 73 | }) 74 | }) 75 | }) 76 | }) 77 | -------------------------------------------------------------------------------- /commands/pivnet_versions.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "github.com/pivotal-cf/pivnet-cli/v3/commands/pivnetversions" 5 | ) 6 | 7 | type PivnetVersionsCommand struct { 8 | } 9 | 10 | //go:generate counterfeiter . PivnetVersionsClient 11 | type PivnetVersionsClient interface { 12 | List() error 13 | Warn(currentVersion string) string 14 | } 15 | 16 | var NewPivnetVersionsClient = func(client pivnetversions.PivnetClient) PivnetVersionsClient { 17 | return pivnetversions.NewPivnetVersionsClient( 18 | client, 19 | ErrorHandler, 20 | Pivnet.Format, 21 | OutputWriter, 22 | Printer, 23 | ) 24 | } 25 | 26 | func (command *PivnetVersionsCommand) Execute(args []string) error { 27 | err := Init(true) 28 | if err != nil { 29 | return err 30 | } 31 | 32 | client := NewPivnetClient() 33 | err = Auth.AuthenticateClient(client) 34 | if err != nil { 35 | return err 36 | } 37 | 38 | return NewPivnetVersionsClient(client).List() 39 | } 40 | -------------------------------------------------------------------------------- /commands/pivnet_versions_test.go: -------------------------------------------------------------------------------- 1 | package commands_test 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | . "github.com/onsi/ginkgo" 7 | . "github.com/onsi/gomega" 8 | "github.com/pivotal-cf/pivnet-cli/v3/commands" 9 | "github.com/pivotal-cf/pivnet-cli/v3/commands/commandsfakes" 10 | "github.com/pivotal-cf/pivnet-cli/v3/commands/pivnetversions" 11 | ) 12 | 13 | var _ = Describe("pivnet versions command", func() { 14 | var ( 15 | fakePivnetVersionsClient *commandsfakes.FakePivnetVersionsClient 16 | ) 17 | 18 | BeforeEach(func() { 19 | fakePivnetVersionsClient = &commandsfakes.FakePivnetVersionsClient{} 20 | 21 | commands.NewPivnetVersionsClient = func(pivnetversions.PivnetClient) commands.PivnetVersionsClient { 22 | return fakePivnetVersionsClient 23 | } 24 | }) 25 | 26 | Describe("PivnetVersionsCommand", func() { 27 | var ( 28 | cmd *commands.PivnetVersionsCommand 29 | ) 30 | 31 | BeforeEach(func() { 32 | cmd = &commands.PivnetVersionsCommand{} 33 | }) 34 | 35 | It("invokes the PivnetVersions client", func() { 36 | err := cmd.Execute(nil) 37 | 38 | Expect(err).NotTo(HaveOccurred()) 39 | 40 | Expect(fakePivnetVersionsClient.ListCallCount()).To(Equal(1)) 41 | }) 42 | 43 | Context("when the PivnetVersions client returns an error", func() { 44 | var ( 45 | expectedErr error 46 | ) 47 | 48 | BeforeEach(func() { 49 | expectedErr = errors.New("expected error") 50 | fakePivnetVersionsClient.ListReturns(expectedErr) 51 | }) 52 | 53 | It("forwards the error", func() { 54 | err := cmd.Execute(nil) 55 | 56 | Expect(err).To(Equal(expectedErr)) 57 | }) 58 | }) 59 | 60 | Context("when Init returns an error", func() { 61 | BeforeEach(func() { 62 | initErr = fmt.Errorf("init error") 63 | }) 64 | 65 | It("forwards the error", func() { 66 | err := cmd.Execute(nil) 67 | 68 | Expect(err).To(Equal(initErr)) 69 | }) 70 | }) 71 | 72 | Context("when Authentication returns an error", func() { 73 | BeforeEach(func() { 74 | authErr = fmt.Errorf("auth error") 75 | }) 76 | 77 | It("forwards the error", func() { 78 | err := cmd.Execute(nil) 79 | 80 | Expect(err).To(Equal(authErr)) 81 | }) 82 | }) 83 | }) 84 | }) 85 | -------------------------------------------------------------------------------- /commands/pivnetversions/init_test.go: -------------------------------------------------------------------------------- 1 | package pivnetversions_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/onsi/ginkgo" 7 | . "github.com/onsi/gomega" 8 | ) 9 | 10 | func TestCommands(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "PivnetVersions commands suite") 13 | } 14 | -------------------------------------------------------------------------------- /commands/pivnetversions/pivnet_versions_client.go: -------------------------------------------------------------------------------- 1 | package pivnetversions 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | 7 | "github.com/olekukonko/tablewriter" 8 | "github.com/pivotal-cf/go-pivnet/v7" 9 | "github.com/pivotal-cf/pivnet-cli/v3/errorhandler" 10 | "github.com/pivotal-cf/pivnet-cli/v3/printer" 11 | "github.com/pivotal-cf/pivnet-cli/v3/semver" 12 | ) 13 | 14 | //go:generate counterfeiter . PivnetClient 15 | type PivnetClient interface { 16 | PivnetVersions() (pivnet.PivnetVersions, error) 17 | } 18 | 19 | type PivnetVersionsClient struct { 20 | pivnetClient PivnetClient 21 | eh errorhandler.ErrorHandler 22 | format string 23 | outputWriter io.Writer 24 | printer printer.Printer 25 | } 26 | 27 | func NewPivnetVersionsClient( 28 | pivnetClient PivnetClient, 29 | eh errorhandler.ErrorHandler, 30 | format string, 31 | outputWriter io.Writer, 32 | printer printer.Printer, 33 | ) *PivnetVersionsClient { 34 | return &PivnetVersionsClient{ 35 | pivnetClient: pivnetClient, 36 | eh: eh, 37 | format: format, 38 | outputWriter: outputWriter, 39 | printer: printer, 40 | } 41 | } 42 | 43 | func (c *PivnetVersionsClient) List() error { 44 | pivnetVersions, err := c.pivnetClient.PivnetVersions() 45 | if err != nil { 46 | return c.eh.HandleError(err) 47 | } 48 | 49 | switch c.format { 50 | case printer.PrintAsTable: 51 | table := tablewriter.NewWriter(c.outputWriter) 52 | table.SetHeader([]string{"Pivnet Component", "Latest Release Version"}) 53 | table.Append([]string{"Pivnet CLI", pivnetVersions.PivnetCliVersion}) 54 | table.Append([]string{"Pivnet Resource", pivnetVersions.PivnetResourceVersion}) 55 | table.Render() 56 | return nil 57 | case printer.PrintAsJSON: 58 | return c.printer.PrintJSON(pivnetVersions) 59 | case printer.PrintAsYAML: 60 | return c.printer.PrintYAML(pivnetVersions) 61 | } 62 | 63 | return nil 64 | } 65 | 66 | func (c *PivnetVersionsClient) Warn(currentVersion string) string { 67 | pivnetVersions, err := c.pivnetClient.PivnetVersions() 68 | if err == nil { 69 | comparison, err := semver.Compare(currentVersion, pivnetVersions.PivnetCliVersion) 70 | if err == nil && comparison < 0 { 71 | return fmt.Sprintf("Warning: Your version of Pivnet CLI (%s) does not match the currently released version (%s).", currentVersion, pivnetVersions.PivnetCliVersion) 72 | } else { 73 | return "" 74 | } 75 | } else { 76 | return "" 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /commands/pivnetversions/pivnet_versions_client_test.go: -------------------------------------------------------------------------------- 1 | package pivnetversions_test 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "errors" 7 | 8 | . "github.com/onsi/ginkgo" 9 | . "github.com/onsi/gomega" 10 | pivnet "github.com/pivotal-cf/go-pivnet/v7" 11 | "github.com/pivotal-cf/pivnet-cli/v3/commands/pivnetversions" 12 | "github.com/pivotal-cf/pivnet-cli/v3/commands/pivnetversions/pivnetversionsfakes" 13 | "github.com/pivotal-cf/pivnet-cli/v3/errorhandler/errorhandlerfakes" 14 | "github.com/pivotal-cf/pivnet-cli/v3/printer" 15 | ) 16 | 17 | var _ = Describe("pivnetversions commands", func() { 18 | var ( 19 | fakePivnetClient *pivnetversionsfakes.FakePivnetClient 20 | 21 | fakeErrorHandler *errorhandlerfakes.FakeErrorHandler 22 | 23 | outBuffer bytes.Buffer 24 | 25 | pivnetVersions pivnet.PivnetVersions 26 | 27 | client *pivnetversions.PivnetVersionsClient 28 | ) 29 | 30 | BeforeEach(func() { 31 | fakePivnetClient = &pivnetversionsfakes.FakePivnetClient{} 32 | 33 | outBuffer = bytes.Buffer{} 34 | 35 | fakeErrorHandler = &errorhandlerfakes.FakeErrorHandler{} 36 | 37 | pivnetVersions = pivnet.PivnetVersions{"1.2.3", "3.2.1"} 38 | 39 | fakePivnetClient.PivnetVersionsReturns(pivnetVersions, nil) 40 | 41 | client = pivnetversions.NewPivnetVersionsClient( 42 | fakePivnetClient, 43 | fakeErrorHandler, 44 | printer.PrintAsJSON, 45 | &outBuffer, 46 | printer.NewPrinter(&outBuffer), 47 | ) 48 | }) 49 | 50 | Describe("PivnetVersions.List", func() { 51 | It("lists all PivnetVersions", func() { 52 | err := client.List() 53 | Expect(err).NotTo(HaveOccurred()) 54 | 55 | var returnedPivnetVersions pivnet.PivnetVersions 56 | err = json.Unmarshal(outBuffer.Bytes(), &returnedPivnetVersions) 57 | Expect(err).NotTo(HaveOccurred()) 58 | 59 | Expect(returnedPivnetVersions).To(Equal(pivnetVersions)) 60 | }) 61 | 62 | Context("when there is an error", func() { 63 | var ( 64 | expectedErr error 65 | ) 66 | 67 | BeforeEach(func() { 68 | expectedErr = errors.New("pivnetversions error") 69 | fakePivnetClient.PivnetVersionsReturns(pivnet.PivnetVersions{}, expectedErr) 70 | }) 71 | 72 | It("invokes the error handler", func() { 73 | err := client.List() 74 | Expect(err).NotTo(HaveOccurred()) 75 | 76 | Expect(fakeErrorHandler.HandleErrorCallCount()).To(Equal(1)) 77 | Expect(fakeErrorHandler.HandleErrorArgsForCall(0)).To(Equal(expectedErr)) 78 | }) 79 | }) 80 | }) 81 | 82 | Describe("PivnetVersions.Warn", func() { 83 | It("returns a warning if the current Pivnet CLI version is out of date", func() { 84 | result := client.Warn("1.2.2") 85 | Expect(result).NotTo(BeEmpty()) 86 | }) 87 | 88 | It("returns empty if the current Pivnet CLI version is up to date", func() { 89 | result := client.Warn("1.2.3") 90 | Expect(result).To(BeEmpty()) 91 | }) 92 | 93 | It("returns empty if the current Pivnet CLI version is newer", func() { 94 | result := client.Warn("1.2.4") 95 | Expect(result).To(BeEmpty()) 96 | }) 97 | 98 | It("returns empty if there is an error getting the latest Pivnet CLI version", func() { 99 | expectedErr := errors.New("pivnetversions error") 100 | fakePivnetClient.PivnetVersionsReturns(pivnet.PivnetVersions{}, expectedErr) 101 | 102 | result := client.Warn("1.2.3") 103 | Expect(result).To(BeEmpty()) 104 | }) 105 | }) 106 | }) 107 | -------------------------------------------------------------------------------- /commands/product.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import "github.com/pivotal-cf/pivnet-cli/v3/commands/product" 4 | 5 | type ProductCommand struct { 6 | ProductSlug string `long:"product-slug" short:"p" description:"Product slug e.g. p-mysql" required:"true"` 7 | } 8 | 9 | type ProductsCommand struct { 10 | } 11 | 12 | type ProductSlugsCommand struct { 13 | ProductSlug string `long:"product-slug" short:"p" description:"Product slug e.g. p-mysql" required:"true"` 14 | } 15 | 16 | //go:generate counterfeiter . ProductClient 17 | type ProductClient interface { 18 | List() error 19 | Get(productSlug string) error 20 | SlugAlias(productSlug string) error 21 | } 22 | 23 | var NewProductClient = func(client product.PivnetClient) ProductClient { 24 | return product.NewProductClient( 25 | client, 26 | ErrorHandler, 27 | Pivnet.Format, 28 | OutputWriter, 29 | Printer, 30 | ) 31 | } 32 | 33 | func (command *ProductsCommand) Execute([]string) error { 34 | err := Init(true) 35 | if err != nil { 36 | return err 37 | } 38 | 39 | client := NewPivnetClient() 40 | err = Auth.AuthenticateClient(client) 41 | if err != nil { 42 | return err 43 | } 44 | 45 | return NewProductClient(client).List() 46 | } 47 | 48 | func (command *ProductCommand) Execute([]string) error { 49 | err := Init(true) 50 | if err != nil { 51 | return err 52 | } 53 | 54 | client := NewPivnetClient() 55 | err = Auth.AuthenticateClient(client) 56 | if err != nil { 57 | return err 58 | } 59 | 60 | return NewProductClient(client).Get(command.ProductSlug) 61 | } 62 | 63 | func (command *ProductSlugsCommand) Execute([]string) error { 64 | err := Init(true) 65 | if err != nil { 66 | return err 67 | } 68 | 69 | client := NewPivnetClient() 70 | err = Auth.AuthenticateClient(client) 71 | if err != nil { 72 | return err 73 | } 74 | 75 | return NewProductClient(client).SlugAlias(command.ProductSlug) 76 | } 77 | -------------------------------------------------------------------------------- /commands/product/init_test.go: -------------------------------------------------------------------------------- 1 | package product_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/onsi/ginkgo" 7 | . "github.com/onsi/gomega" 8 | ) 9 | 10 | func TestCommands(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "Product commands suite") 13 | } 14 | -------------------------------------------------------------------------------- /commands/productfile/init_test.go: -------------------------------------------------------------------------------- 1 | package productfile_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/onsi/ginkgo" 7 | . "github.com/onsi/gomega" 8 | ) 9 | 10 | func TestCommands(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "ProductFile suite") 13 | } 14 | -------------------------------------------------------------------------------- /commands/release/init_test.go: -------------------------------------------------------------------------------- 1 | package release_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/onsi/ginkgo" 7 | . "github.com/onsi/gomega" 8 | ) 9 | 10 | func TestCommands(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "Release suite") 13 | } 14 | -------------------------------------------------------------------------------- /commands/release_type.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import "github.com/pivotal-cf/pivnet-cli/v3/commands/releasetype" 4 | 5 | type ReleaseTypesCommand struct { 6 | } 7 | 8 | //go:generate counterfeiter . ReleaseTypeClient 9 | type ReleaseTypeClient interface { 10 | List() error 11 | } 12 | 13 | var NewReleaseTypeClient = func(client releasetype.PivnetClient) ReleaseTypeClient { 14 | return releasetype.NewReleaseTypeClient( 15 | client, 16 | ErrorHandler, 17 | Pivnet.Format, 18 | OutputWriter, 19 | Printer, 20 | ) 21 | } 22 | 23 | func (command *ReleaseTypesCommand) Execute(args []string) error { 24 | err := Init(true) 25 | if err != nil { 26 | return err 27 | } 28 | 29 | client := NewPivnetClient() 30 | err = Auth.AuthenticateClient(client) 31 | if err != nil { 32 | return err 33 | } 34 | 35 | return NewReleaseTypeClient(client).List() 36 | } 37 | -------------------------------------------------------------------------------- /commands/release_type_test.go: -------------------------------------------------------------------------------- 1 | package commands_test 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | 7 | . "github.com/onsi/ginkgo" 8 | . "github.com/onsi/gomega" 9 | "github.com/pivotal-cf/pivnet-cli/v3/commands" 10 | "github.com/pivotal-cf/pivnet-cli/v3/commands/commandsfakes" 11 | "github.com/pivotal-cf/pivnet-cli/v3/commands/releasetype" 12 | ) 13 | 14 | var _ = Describe("release types commands", func() { 15 | var ( 16 | fakeReleaseTypeClient *commandsfakes.FakeReleaseTypeClient 17 | ) 18 | 19 | BeforeEach(func() { 20 | fakeReleaseTypeClient = &commandsfakes.FakeReleaseTypeClient{} 21 | 22 | commands.NewReleaseTypeClient = func(releasetype.PivnetClient) commands.ReleaseTypeClient { 23 | return fakeReleaseTypeClient 24 | } 25 | }) 26 | 27 | Describe("ReleaseTypesCommand", func() { 28 | var ( 29 | cmd *commands.ReleaseTypesCommand 30 | ) 31 | 32 | BeforeEach(func() { 33 | cmd = &commands.ReleaseTypesCommand{} 34 | }) 35 | 36 | It("invokes the ReleaseType client", func() { 37 | err := cmd.Execute(nil) 38 | 39 | Expect(err).NotTo(HaveOccurred()) 40 | 41 | Expect(fakeReleaseTypeClient.ListCallCount()).To(Equal(1)) 42 | }) 43 | 44 | Context("when the ReleaseType client returns an error", func() { 45 | var ( 46 | expectedErr error 47 | ) 48 | 49 | BeforeEach(func() { 50 | expectedErr = errors.New("expected error") 51 | fakeReleaseTypeClient.ListReturns(expectedErr) 52 | }) 53 | 54 | It("forwards the error", func() { 55 | err := cmd.Execute(nil) 56 | 57 | Expect(err).To(Equal(expectedErr)) 58 | }) 59 | }) 60 | 61 | Context("when Init returns an error", func() { 62 | BeforeEach(func() { 63 | initErr = fmt.Errorf("init error") 64 | }) 65 | 66 | It("forwards the error", func() { 67 | err := cmd.Execute(nil) 68 | 69 | Expect(err).To(Equal(initErr)) 70 | }) 71 | }) 72 | 73 | Context("when Authentication returns an error", func() { 74 | BeforeEach(func() { 75 | authErr = fmt.Errorf("auth error") 76 | }) 77 | 78 | It("forwards the error", func() { 79 | err := cmd.Execute(nil) 80 | 81 | Expect(err).To(Equal(authErr)) 82 | }) 83 | }) 84 | 85 | }) 86 | }) 87 | -------------------------------------------------------------------------------- /commands/release_upgrade_path.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import "github.com/pivotal-cf/pivnet-cli/v3/commands/releaseupgradepath" 4 | 5 | type ReleaseUpgradePathsCommand struct { 6 | ProductSlug string `long:"product-slug" short:"p" description:"Product slug e.g. p-mysql" required:"true"` 7 | ReleaseVersion string `long:"release-version" short:"r" description:"Release version e.g. 0.1.2-rc1" required:"true"` 8 | } 9 | 10 | type AddReleaseUpgradePathCommand struct { 11 | ProductSlug string `long:"product-slug" short:"p" description:"Product slug e.g. p-mysql" required:"true"` 12 | ReleaseVersion string `long:"release-version" short:"r" description:"Release version e.g. 0.1.2-rc1" required:"true"` 13 | PreviousReleaseVersion string `long:"previous-release-version" short:"u" description:"Regex for previous release version e.g. 0.1.*" required:"true"` 14 | } 15 | 16 | type RemoveReleaseUpgradePathCommand struct { 17 | ProductSlug string `long:"product-slug" short:"p" description:"Product slug e.g. p-mysql" required:"true"` 18 | ReleaseVersion string `long:"release-version" short:"r" description:"Release version e.g. 0.1.2-rc1" required:"true"` 19 | PreviousReleaseVersion string `long:"previous-release-version" short:"u" description:"Regex for previous release version e.g. 0.1.*" required:"true"` 20 | } 21 | 22 | //go:generate counterfeiter . ReleaseUpgradePathClient 23 | type ReleaseUpgradePathClient interface { 24 | List(productSlug string, releaseVersion string) error 25 | Add(productSlug string, releaseVersion string, previousReleaseVersion string) error 26 | Remove(productSlug string, releaseVersion string, previousReleaseVersion string) error 27 | } 28 | 29 | var NewReleaseUpgradePathClient = func(client releaseupgradepath.PivnetClient) ReleaseUpgradePathClient { 30 | return releaseupgradepath.NewReleaseUpgradePathClient( 31 | client, 32 | ErrorHandler, 33 | Pivnet.Format, 34 | OutputWriter, 35 | Printer, 36 | Filter, 37 | Pivnet.Logger, 38 | ) 39 | } 40 | 41 | func (command *ReleaseUpgradePathsCommand) Execute([]string) error { 42 | err := Init(true) 43 | if err != nil { 44 | return err 45 | } 46 | 47 | client := NewPivnetClient() 48 | err = Auth.AuthenticateClient(client) 49 | if err != nil { 50 | return err 51 | } 52 | 53 | return NewReleaseUpgradePathClient(client).List(command.ProductSlug, command.ReleaseVersion) 54 | } 55 | 56 | func (command *AddReleaseUpgradePathCommand) Execute([]string) error { 57 | err := Init(true) 58 | if err != nil { 59 | return err 60 | } 61 | 62 | client := NewPivnetClient() 63 | err = Auth.AuthenticateClient(client) 64 | if err != nil { 65 | return err 66 | } 67 | 68 | return NewReleaseUpgradePathClient(client).Add( 69 | command.ProductSlug, 70 | command.ReleaseVersion, 71 | command.PreviousReleaseVersion, 72 | ) 73 | } 74 | 75 | func (command *RemoveReleaseUpgradePathCommand) Execute([]string) error { 76 | err := Init(true) 77 | if err != nil { 78 | return err 79 | } 80 | 81 | client := NewPivnetClient() 82 | err = Auth.AuthenticateClient(client) 83 | if err != nil { 84 | return err 85 | } 86 | 87 | return NewReleaseUpgradePathClient(client).Remove( 88 | command.ProductSlug, 89 | command.ReleaseVersion, 90 | command.PreviousReleaseVersion, 91 | ) 92 | } 93 | -------------------------------------------------------------------------------- /commands/releasedependency/init_test.go: -------------------------------------------------------------------------------- 1 | package releasedependency_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/onsi/ginkgo" 7 | . "github.com/onsi/gomega" 8 | ) 9 | 10 | func TestCommands(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "ReleaseDependency commands suite") 13 | } 14 | -------------------------------------------------------------------------------- /commands/releasetype/init_test.go: -------------------------------------------------------------------------------- 1 | package releasetype_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/onsi/ginkgo" 7 | . "github.com/onsi/gomega" 8 | ) 9 | 10 | func TestCommands(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "ReleaseType commands suite") 13 | } 14 | -------------------------------------------------------------------------------- /commands/releasetype/release_type_client.go: -------------------------------------------------------------------------------- 1 | package releasetype 2 | 3 | import ( 4 | "io" 5 | 6 | "github.com/olekukonko/tablewriter" 7 | pivnet "github.com/pivotal-cf/go-pivnet/v7" 8 | "github.com/pivotal-cf/pivnet-cli/v3/errorhandler" 9 | "github.com/pivotal-cf/pivnet-cli/v3/printer" 10 | ) 11 | 12 | //go:generate counterfeiter . PivnetClient 13 | type PivnetClient interface { 14 | ReleaseTypes() ([]pivnet.ReleaseType, error) 15 | } 16 | 17 | type ReleaseTypeClient struct { 18 | pivnetClient PivnetClient 19 | eh errorhandler.ErrorHandler 20 | format string 21 | outputWriter io.Writer 22 | printer printer.Printer 23 | } 24 | 25 | func NewReleaseTypeClient( 26 | pivnetClient PivnetClient, 27 | eh errorhandler.ErrorHandler, 28 | format string, 29 | outputWriter io.Writer, 30 | printer printer.Printer, 31 | ) *ReleaseTypeClient { 32 | return &ReleaseTypeClient{ 33 | pivnetClient: pivnetClient, 34 | eh: eh, 35 | format: format, 36 | outputWriter: outputWriter, 37 | printer: printer, 38 | } 39 | } 40 | 41 | func (c *ReleaseTypeClient) List() error { 42 | releaseTypes, err := c.pivnetClient.ReleaseTypes() 43 | if err != nil { 44 | return c.eh.HandleError(err) 45 | } 46 | 47 | switch c.format { 48 | case printer.PrintAsTable: 49 | table := tablewriter.NewWriter(c.outputWriter) 50 | table.SetHeader([]string{"Release Types"}) 51 | 52 | for _, r := range releaseTypes { 53 | table.Append([]string{string(r)}) 54 | } 55 | table.Render() 56 | return nil 57 | case printer.PrintAsJSON: 58 | return c.printer.PrintJSON(releaseTypes) 59 | case printer.PrintAsYAML: 60 | return c.printer.PrintYAML(releaseTypes) 61 | } 62 | 63 | return nil 64 | } 65 | -------------------------------------------------------------------------------- /commands/releasetype/release_type_client_test.go: -------------------------------------------------------------------------------- 1 | package releasetype_test 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "errors" 7 | 8 | . "github.com/onsi/ginkgo" 9 | . "github.com/onsi/gomega" 10 | pivnet "github.com/pivotal-cf/go-pivnet/v7" 11 | "github.com/pivotal-cf/pivnet-cli/v3/commands/releasetype" 12 | "github.com/pivotal-cf/pivnet-cli/v3/commands/releasetype/releasetypefakes" 13 | "github.com/pivotal-cf/pivnet-cli/v3/errorhandler/errorhandlerfakes" 14 | "github.com/pivotal-cf/pivnet-cli/v3/printer" 15 | ) 16 | 17 | var _ = Describe("releasetype commands", func() { 18 | var ( 19 | fakePivnetClient *releasetypefakes.FakePivnetClient 20 | 21 | fakeErrorHandler *errorhandlerfakes.FakeErrorHandler 22 | 23 | outBuffer bytes.Buffer 24 | 25 | releasetypes []pivnet.ReleaseType 26 | 27 | client *releasetype.ReleaseTypeClient 28 | ) 29 | 30 | BeforeEach(func() { 31 | fakePivnetClient = &releasetypefakes.FakePivnetClient{} 32 | 33 | outBuffer = bytes.Buffer{} 34 | 35 | fakeErrorHandler = &errorhandlerfakes.FakeErrorHandler{} 36 | 37 | releasetypes = []pivnet.ReleaseType{ 38 | pivnet.ReleaseType("release-type-A"), 39 | pivnet.ReleaseType("release-type-B"), 40 | } 41 | 42 | fakePivnetClient.ReleaseTypesReturns(releasetypes, nil) 43 | 44 | client = releasetype.NewReleaseTypeClient( 45 | fakePivnetClient, 46 | fakeErrorHandler, 47 | printer.PrintAsJSON, 48 | &outBuffer, 49 | printer.NewPrinter(&outBuffer), 50 | ) 51 | }) 52 | 53 | Describe("ReleaseTypes", func() { 54 | It("lists all ReleaseTypes", func() { 55 | err := client.List() 56 | Expect(err).NotTo(HaveOccurred()) 57 | 58 | var returnedReleaseTypes []pivnet.ReleaseType 59 | err = json.Unmarshal(outBuffer.Bytes(), &returnedReleaseTypes) 60 | Expect(err).NotTo(HaveOccurred()) 61 | 62 | Expect(returnedReleaseTypes).To(Equal(releasetypes)) 63 | }) 64 | 65 | Context("when there is an error", func() { 66 | var ( 67 | expectedErr error 68 | ) 69 | 70 | BeforeEach(func() { 71 | expectedErr = errors.New("releasetypes error") 72 | fakePivnetClient.ReleaseTypesReturns(nil, expectedErr) 73 | }) 74 | 75 | It("invokes the error handler", func() { 76 | err := client.List() 77 | Expect(err).NotTo(HaveOccurred()) 78 | 79 | Expect(fakeErrorHandler.HandleErrorCallCount()).To(Equal(1)) 80 | Expect(fakeErrorHandler.HandleErrorArgsForCall(0)).To(Equal(expectedErr)) 81 | }) 82 | }) 83 | }) 84 | }) 85 | -------------------------------------------------------------------------------- /commands/releaseupgradepath/init_test.go: -------------------------------------------------------------------------------- 1 | package releaseupgradepath_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/onsi/ginkgo" 7 | . "github.com/onsi/gomega" 8 | ) 9 | 10 | func TestCommands(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "ReleaseUpgradePath suite") 13 | } 14 | -------------------------------------------------------------------------------- /commands/subscription_group.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "github.com/pivotal-cf/pivnet-cli/v3/commands/subscriptiongroup" 5 | ) 6 | 7 | type SubscriptionGroupsCommand struct{} 8 | 9 | type SubscriptionGroupCommand struct { 10 | SubscriptionGroupID int `long:"subscription-group-id" short:"i" description:"Subscription group ID e.g. 1234" required:"true"` 11 | } 12 | 13 | type AddSubscriptionGroupMemberCommand struct { 14 | SubscriptionGroupID int `long:"subscription-group-id" short:"i" description:"Subscription group ID e.g. 1234" required:"true"` 15 | MemberEmail string `long:"member-email" description:"Email of member to add e.g. example@example.net" required:"true"` 16 | IsAdmin string `long:"admin" description:"Whether the user should be an admin e.g. --admin=[true|false]"` 17 | } 18 | 19 | type RemoveSubscriptionGroupMemberCommand struct { 20 | SubscriptionGroupID int `long:"subscription-group-id" short:"i" description:"Subscription group ID e.g. 1234" required:"true"` 21 | MemberEmail string `long:"member-email" description:"Email of member to add e.g. example@example.net" required:"true"` 22 | } 23 | 24 | //go:generate counterfeiter . SubscriptionGroupClient 25 | type SubscriptionGroupClient interface { 26 | List() error 27 | Get(subscriptionGroupID int) error 28 | AddMember(subscriptionGroupID int, memberEmail string, isAdmin string) error 29 | RemoveMember(subscriptionGroupID int, memberEmail string) error 30 | } 31 | 32 | var NewSubscriptionGroupClient = func(client subscriptiongroup.PivnetClient) SubscriptionGroupClient { 33 | return subscriptiongroup.NewSubscriptionGroupClient( 34 | client, 35 | ErrorHandler, 36 | Pivnet.Format, 37 | OutputWriter, 38 | Printer, 39 | ) 40 | } 41 | 42 | func (command *SubscriptionGroupsCommand) Execute([]string) error { 43 | err := Init(true) 44 | if err != nil { 45 | return err 46 | } 47 | 48 | client := NewPivnetClient() 49 | err = Auth.AuthenticateClient(client) 50 | if err != nil { 51 | return err 52 | } 53 | 54 | return NewSubscriptionGroupClient(client).List() 55 | } 56 | 57 | func (command *SubscriptionGroupCommand) Execute([]string) error { 58 | err := Init(true) 59 | if err != nil { 60 | return err 61 | } 62 | 63 | client := NewPivnetClient() 64 | err = Auth.AuthenticateClient(client) 65 | if err != nil { 66 | return err 67 | } 68 | 69 | return NewSubscriptionGroupClient(client).Get(command.SubscriptionGroupID) 70 | } 71 | 72 | func (command *AddSubscriptionGroupMemberCommand) Execute([]string) error { 73 | err := Init(true) 74 | if err != nil { 75 | return err 76 | } 77 | 78 | client := NewPivnetClient() 79 | err = Auth.AuthenticateClient(client) 80 | if err != nil { 81 | return err 82 | } 83 | 84 | return NewSubscriptionGroupClient(client).AddMember(command.SubscriptionGroupID, command.MemberEmail, command.IsAdmin) 85 | } 86 | 87 | func (command *RemoveSubscriptionGroupMemberCommand) Execute([]string) error { 88 | err := Init(true) 89 | if err != nil { 90 | return err 91 | } 92 | 93 | client := NewPivnetClient() 94 | err = Auth.AuthenticateClient(client) 95 | if err != nil { 96 | return err 97 | } 98 | 99 | return NewSubscriptionGroupClient(client).RemoveMember(command.SubscriptionGroupID, command.MemberEmail) 100 | } 101 | -------------------------------------------------------------------------------- /commands/subscriptiongroup/init_test.go: -------------------------------------------------------------------------------- 1 | package subscriptiongroup_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/onsi/ginkgo" 7 | . "github.com/onsi/gomega" 8 | ) 9 | 10 | func TestCommands(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "SubscriptionGroup suite") 13 | } 14 | -------------------------------------------------------------------------------- /commands/usergroup/init_test.go: -------------------------------------------------------------------------------- 1 | package usergroup_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/onsi/ginkgo" 7 | . "github.com/onsi/gomega" 8 | ) 9 | 10 | func TestCommands(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "UserGroup suite") 13 | } 14 | -------------------------------------------------------------------------------- /commands/version.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | type VersionCommand struct{} 4 | 5 | func (command *VersionCommand) Execute(args []string) error { 6 | Pivnet.VersionFunc() 7 | return nil 8 | } 9 | -------------------------------------------------------------------------------- /docs/content/about/project-management.md: -------------------------------------------------------------------------------- 1 | # Project Management 2 | 3 | The CI for this project can be found 4 | [here](https://pivnet.ci.cf-app.com/teams/main/pipelines/pivnet-cli) 5 | and the scripts can be found in the 6 | [pivnet-ci repo](https://github.com/pivotal-cf/pivnet-ci). 7 | 8 | The roadmap is captured in [Pivotal Tracker](https://www.pivotaltracker.com/projects/1474244). 9 | -------------------------------------------------------------------------------- /docs/content/development/contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | If you have not previously done so, please fill out and 4 | submit the https://cla.pivotal.io/sign/pivotal[Contributor License Agreement]. 5 | 6 | Please make all pull requests to the `develop` branch, and 7 | [ensure the tests pass locally](https://github.com/pivotal-cf/pivnet-cli#running-the-tests). 8 | -------------------------------------------------------------------------------- /docs/content/development/dependencies.md: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | 3 | Dependencies are vendored in the `vendor` directory, according to the 4 | [golang 1.5 vendor experiment](https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0ahUKEwi7puWg7ZrLAhUN1WMKHeT4A7oQFggdMAA&url=https%3A%2F%2Fgolang.org%2Fs%2Fgo15vendor&usg=AFQjCNEPCAjj1lnni5apHdA7rW0crWs7Zw). 5 | 6 | No action is require to fetch the vendored dependencies. 7 | -------------------------------------------------------------------------------- /docs/content/development/prerequisites.md: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | 3 | A valid install of golang >= 1.6 is required. 4 | -------------------------------------------------------------------------------- /docs/content/development/testing.md: -------------------------------------------------------------------------------- 1 | # Testing 2 | 3 | Install the ginkgo executable with: 4 | 5 | ``` 6 | go get -u github.com/onsi/ginkgo/ginkgo 7 | ``` 8 | 9 | The tests require a valid Pivotal Network API token and host. 10 | 11 | Refer to the 12 | [official docs](https://network.tanzu.vmware.com/docs/api#how-to-authenticate) 13 | for more details on obtaining a Pivotal Network API token. 14 | 15 | It is advised to run the acceptance tests against the Pivotal Network integration 16 | environment endpoint i.e. `HOST='https://pivnet-integration.cfapps.io'`. 17 | 18 | Run the tests with the following command: 19 | 20 | ``` 21 | API_TOKEN=my-token \ 22 | HOST='https://pivnet-integration.cfapps.io' \ 23 | ./bin/test_all 24 | ``` 25 | -------------------------------------------------------------------------------- /docs/content/examples/usage.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | Using the Pivnet CLI requires a valid `Pivotal Network API token` or `UAA Refresh Token`. 4 | 5 | Refer to the 6 | [official docs](https://network.tanzu.vmware.com/docs/api#how-to-authenticate) 7 | for more details on obtaining a Pivotal Network API token. 8 | 9 | Example usage: 10 | 11 | ```sh 12 | $ pivnet login --api-token='my-api-token' 13 | $ pivnet products 14 | 15 | +-----+------------------------------------------------------+--------------------------------+ 16 | | ID | SLUG | NAME | 17 | +-----+------------------------------------------------------+--------------------------------+ 18 | | 60 | elastic-runtime | Pivotal Cloud Foundry Elastic | 19 | | | | Runtime | 20 | +-----+------------------------------------------------------+--------------------------------+ 21 | 22 | $ pivnet release --product-slug=elastic-runtime --release-version=1.8.8 --format json \ 23 | | jq '{"id": .id, "release_date": .release_date, "release_type": .release_type}' 24 | 25 | { 26 | "id": 2555, 27 | "release_date": "2016-10-13", 28 | "release_type": "Security Release" 29 | } 30 | ``` 31 | 32 | # Batch Command Examples 33 | 34 | The Pivnet UI has few places to edit content in batches. Batch processing is relegated to the [Pivnet Resource](https://github.com/pivotal-cf/pivnet-resource) and Pivnet CLI. 35 | 36 | Many commands require release versions. You could use the following pipeline to product a list of release versions: 37 | 38 | ```sh 39 | $ pivnet --format=json releases --product-slug=MY_PRODUCT_SLUG | jq '.[].version' 40 | "1.10.5" 41 | "1.10.4" 42 | "1.10.3" 43 | "1.10.2" 44 | "1.10.1" 45 | "1.10.0" 46 | ... 47 | ``` 48 | 49 | If you wanted to, for example, a remove a user group from all releases, you could use a pipeline similar to the following: 50 | 51 | ```sh 52 | $ pivnet --format=json releases --product-slug=MY_PRODUCT_SLUG | jq '.[].version' | xargs -I{} pivnet remove-user-group --product-slug=MY_PRODUCT_SLUG --release-version={} --user-group-id=USER_GROUP_ID_TO_REMOVE 53 | ``` 54 | 55 | Similarly, you could, for example, add an Elastic Runtime 2.0.0 release dependency to all "1.10.*" releases for a product with a pipeline similar to the following: 56 | 57 | ```sh 58 | $ pivnet --format=json releases --product-slug=MY_PRODUCT_SLUG | jq -r '.[].version' | grep '^1\.10\.' | xargs -I{} pivnet add-release-dependency --product-slug=MY_PRODUCT_SLUG --release-version={} --dependent-product-slug=elastic-runtime --dependent-release-version=2.0.0 59 | ``` 60 | 61 | -------------------------------------------------------------------------------- /docs/content/index.md: -------------------------------------------------------------------------------- 1 | # Pivnet CLI 2 | 3 | Interact with [Pivotal Network](https://network.tanzu.vmware.com) from the command-line. 4 | -------------------------------------------------------------------------------- /docs/content/installation/installing-the-cli.md: -------------------------------------------------------------------------------- 1 | # Installing The CLI 2 | 3 | Binaries for various operating systems are provided with each release on the 4 | [releases page](https://github.com/pivotal-cf/pivnet-cli/releases). 5 | 6 | Install for OSX via [homebrew](http://brew.sh/) as follows: 7 | 8 | ```sh 9 | brew install pivotal/tap/pivnet-cli 10 | ``` 11 | 12 | To install on linux, download the latest binary 13 | (see [latest release](https://github.com/pivotal-cf/pivnet-cli/releases/latest)) 14 | and ensure the file is executable and on the path. 15 | -------------------------------------------------------------------------------- /docs/content/reference/accept-eula.md: -------------------------------------------------------------------------------- 1 | # Accept EULA (aliases: ae) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] accept-eula [accept-eula-OPTIONS] 6 | 7 | Note: 8 | Available to select users only. Some users may be required to accept the EULA through the provided link 9 | 10 | Application Options: 11 | -v, --version Print the version of this CLI and exit 12 | --format=[table|json|yaml] Format to print as (default: table) 13 | --verbose Display verbose output 14 | --profile= Name of profile (default: default) 15 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 16 | 17 | Help Options: 18 | -h, --help Show this help message 19 | 20 | [accept-eula command options] 21 | -p, --product-slug= Product slug e.g. p-mysql 22 | -r, --release-version= Release version e.g. 0.1.2-rc1 23 | 24 | ``` 25 | -------------------------------------------------------------------------------- /docs/content/reference/add-file-group.md: -------------------------------------------------------------------------------- 1 | # Add file group to release (aliases: afg) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] add-file-group [add-file-group-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [add-file-group command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | -i, --file-group-id= Filegroup ID e.g. 1234 20 | -r, --release-version= Release version e.g. 0.1.2-rc1 21 | 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/content/reference/add-product-file.md: -------------------------------------------------------------------------------- 1 | # Add product file to release (aliases: apf) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] add-product-file [add-product-file-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [add-product-file command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | -r, --release-version= Release version e.g. 0.1.2-rc1 20 | -i, --product-file-id= Product file ID e.g. 1234 21 | -f, --file-group-id= File group ID e.g. 1234 22 | 23 | ``` 24 | -------------------------------------------------------------------------------- /docs/content/reference/add-release-dependency.md: -------------------------------------------------------------------------------- 1 | # Add release dependency (aliases: ard) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] add-release-dependency [add-release-dependency-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [add-release-dependency command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | -r, --release-version= Release version e.g. 0.1.2-rc1 20 | -s, --dependent-product-slug= Dependent product slug e.g. p-mysql 21 | -u, --dependent-release-version= Dependent release version e.g. 0.1.2-rc1 22 | 23 | ``` 24 | -------------------------------------------------------------------------------- /docs/content/reference/add-release-upgrade-path.md: -------------------------------------------------------------------------------- 1 | # Add release upgrade path (aliases: arup) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] add-release-upgrade-path [add-release-upgrade-path-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [add-release-upgrade-path command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | -r, --release-version= Release version e.g. 0.1.2-rc1 20 | -u, --previous-release-version= Regex for previous release version e.g. 0.1.* 21 | 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/content/reference/add-user-group-member.md: -------------------------------------------------------------------------------- 1 | # Add user group member to group (aliases: augm) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] add-user-group-member [add-user-group-member-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [add-user-group-member command options] 18 | -i, --user-group-id= User group ID e.g. 1234 19 | --member-email= Member email address e.g. 1234 20 | --admin Whether the user should be an admin 21 | 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/content/reference/add-user-group.md: -------------------------------------------------------------------------------- 1 | # Add user group to release (aliases: aug) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] add-user-group [add-user-group-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [add-user-group command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | -r, --release-version= Release version e.g. 0.1.2-rc1 20 | -i, --user-group-id= User Group ID e.g. 1234 21 | 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/content/reference/create-dependency-specifier.md: -------------------------------------------------------------------------------- 1 | # Create dependency specifier (aliases: cds) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] create-dependency-specifier [create-dependency-specifier-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [create-dependency-specifier command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | -r, --release-version= Release version e.g. 0.1.2-rc1 20 | -s, --dependent-product-slug= Dependent product slug e.g. p-mysql 21 | -u, --specifier= Specifier e.g. 1.2.* 22 | 23 | ``` 24 | -------------------------------------------------------------------------------- /docs/content/reference/create-file-group.md: -------------------------------------------------------------------------------- 1 | # Create file group (aliases: cfg) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] create-file-group [create-file-group-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [create-file-group command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | --name= Name e.g. my_file_group 20 | 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/content/reference/create-product-file.md: -------------------------------------------------------------------------------- 1 | # Create product file (aliases: cpf) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] create-product-file [create-product-file-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [create-product-file command options] 18 | -p, --product-slug= Product slug e.g. 'p-mysql' 19 | --name= Name e.g. 'p-mysql 1.7.13' 20 | --aws-object-key= AWS Object Key e.g. 'product_files/P-MySQL/p-mysql-1.7.13.pivotal' 21 | --file-type= File Type e.g. 'Software' 22 | --file-version= File Version e.g. '1.7.13' 23 | --md5= MD5 of file 24 | --description= Description of file 25 | --docs-url= URL of docs for file 26 | --included-file= Name of included file 27 | --platform= Platform of file 28 | --released-at= When file is marked for release e.g. '2016/01/16' 29 | --system-requirement= System-requirement of file 30 | 31 | ``` 32 | -------------------------------------------------------------------------------- /docs/content/reference/create-release.md: -------------------------------------------------------------------------------- 1 | # Create release (aliases: cr) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] create-release [create-release-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [create-release command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | -r, --release-version= Release version e.g. 0.1.2-rc1 20 | -t, --release-type= Release type e.g. 'Minor Release' 21 | -e, --eula-slug= EULA slug e.g. pivotal_software_eula 22 | 23 | ``` 24 | -------------------------------------------------------------------------------- /docs/content/reference/create-user-group.md: -------------------------------------------------------------------------------- 1 | # Create user group (aliases: cug) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] create-user-group [create-user-group-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [create-user-group command options] 18 | --name= Name e.g. all_users 19 | --description= Description e.g. 'All users in the world' 20 | --member= Email addresses of members to be added 21 | 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/content/reference/curl.md: -------------------------------------------------------------------------------- 1 | # Curl an endpoint (aliases: c) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] curl [curl-OPTIONS] URL 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [curl command options] 18 | -X, --request= Custom method e.g. PATCH 19 | -d, --data= Request data e.g. '{"foo":"bar"}' 20 | 21 | [curl command arguments] 22 | URL: URL without host or API prefix e.g. /products/p-mysql/releases/3451 23 | 24 | ``` 25 | -------------------------------------------------------------------------------- /docs/content/reference/delete-dependency-specifier.md: -------------------------------------------------------------------------------- 1 | # Delete dependency specifier (aliases: dds) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] delete-dependency-specifier [delete-dependency-specifier-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [delete-dependency-specifier command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | -r, --release-version= Release version e.g. 0.1.2-rc1 20 | -i, --dependency-specifier-id= Dependency specifier ID e.g. 1234 21 | 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/content/reference/delete-file-group.md: -------------------------------------------------------------------------------- 1 | # Delete file group (aliases: dfg) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] delete-file-group [delete-file-group-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [delete-file-group command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | -i, --file-group-id= File group ID e.g. 1234 20 | 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/content/reference/delete-product-file.md: -------------------------------------------------------------------------------- 1 | # Delete product file (aliases: dpf) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] delete-product-file [delete-product-file-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [delete-product-file command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | -i, --product-file-id= Product file ID e.g. 1234 20 | 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/content/reference/delete-release.md: -------------------------------------------------------------------------------- 1 | # Delete release (aliases: dr) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] delete-release [delete-release-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [delete-release command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | -r, --release-version= Release version e.g. 0.1.2-rc1 20 | 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/content/reference/delete-user-group.md: -------------------------------------------------------------------------------- 1 | # Delete user group (aliases: dug) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] delete-user-group [delete-user-group-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [delete-user-group command options] 18 | -i, --user-group-id= User group ID e.g. 1234 19 | 20 | ``` 21 | -------------------------------------------------------------------------------- /docs/content/reference/dependency-specifier.md: -------------------------------------------------------------------------------- 1 | # Get dependency specifier (aliases: ds) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] dependency-specifier [dependency-specifier-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [dependency-specifier command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | -r, --release-version= Release version e.g. 0.1.2-rc1 20 | -i, --dependency-specifier-id= Dependency specifier ID e.g. 1234 21 | 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/content/reference/dependency-specifiers.md: -------------------------------------------------------------------------------- 1 | # List dependency specifiers (aliases: dss) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] dependency-specifiers [dependency-specifiers-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [dependency-specifiers command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | -r, --release-version= Release version e.g. 0.1.2-rc1 20 | 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/content/reference/download-product-files.md: -------------------------------------------------------------------------------- 1 | # Download product files (aliases: dlpf) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] download-product-files [download-product-files-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [download-product-files command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | -r, --release-version= Release version e.g. 0.1.2-rc1 20 | -i, --product-file-id= Product file ID e.g. 1234 21 | -g, --glob= Glob to match product name e.g. *aws* 22 | -d, --download-dir= Local existing directory to download files to e.g. /tmp/my-file/ (default: .) 23 | --accept-eula Automatically accept EULA if necessary (available to pivots only) 24 | 25 | ``` 26 | -------------------------------------------------------------------------------- /docs/content/reference/eula.md: -------------------------------------------------------------------------------- 1 | # Show EULA (aliases: e) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] eula [eula-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [eula command options] 18 | --eula-slug= EULA slug e.g. pivotal_software_eula 19 | 20 | ``` 21 | -------------------------------------------------------------------------------- /docs/content/reference/eulas.md: -------------------------------------------------------------------------------- 1 | # List EULAs (aliases: es) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] eulas 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | ``` 18 | -------------------------------------------------------------------------------- /docs/content/reference/file-group.md: -------------------------------------------------------------------------------- 1 | # Show file group (aliases: fg) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] file-group [file-group-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [file-group command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | -i, --file-group-id= Filegroup ID e.g. 1234 20 | 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/content/reference/file-groups.md: -------------------------------------------------------------------------------- 1 | # List file groups (aliases: fgs) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] file-groups [file-groups-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [file-groups command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | -r, --release-version= Release version e.g. 0.1.2-rc1 20 | 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/content/reference/login.md: -------------------------------------------------------------------------------- 1 | # Log in to Pivotal Network. (aliases: l) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] login [login-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [login command options] 18 | --api-token= Pivnet API Token (Pivnet legacy token or UAA refresh token) 19 | --host= Pivnet API Host (default: https://network.tanzu.vmware.com) 20 | 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/content/reference/logout.md: -------------------------------------------------------------------------------- 1 | # Log out from Pivotal Network. 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] logout 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | ``` 18 | -------------------------------------------------------------------------------- /docs/content/reference/product-file.md: -------------------------------------------------------------------------------- 1 | # Show product file (aliases: pf) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] product-file [product-file-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [product-file command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | -r, --release-version= Release version e.g. 0.1.2-rc1 20 | -i, --product-file-id= Product file ID e.g. 1234 21 | 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/content/reference/product-files.md: -------------------------------------------------------------------------------- 1 | # List product files (aliases: pfs) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] product-files [product-files-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [product-files command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | -r, --release-version= Release version e.g. 0.1.2-rc1 20 | 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/content/reference/product.md: -------------------------------------------------------------------------------- 1 | # Show product (aliases: p) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] product [product-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [product command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | 20 | ``` 21 | -------------------------------------------------------------------------------- /docs/content/reference/products.md: -------------------------------------------------------------------------------- 1 | # List products (aliases: ps) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] products 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | ``` 18 | -------------------------------------------------------------------------------- /docs/content/reference/release-dependencies.md: -------------------------------------------------------------------------------- 1 | # List release dependencies (aliases: rds) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] release-dependencies [release-dependencies-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [release-dependencies command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | -r, --release-version= Release version e.g. 0.1.2-rc1 20 | 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/content/reference/release-types.md: -------------------------------------------------------------------------------- 1 | # List release types (aliases: rts) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] release-types 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | ``` 18 | -------------------------------------------------------------------------------- /docs/content/reference/release-upgrade-paths.md: -------------------------------------------------------------------------------- 1 | # List release upgrade paths (aliases: rups) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] release-upgrade-paths [release-upgrade-paths-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [release-upgrade-paths command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | -r, --release-version= Release version e.g. 0.1.2-rc1 20 | 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/content/reference/release.md: -------------------------------------------------------------------------------- 1 | # Show release (aliases: r) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] release [release-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [release command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | -r, --release-version= Release version e.g. 0.1.2-rc1 20 | 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/content/reference/releases.md: -------------------------------------------------------------------------------- 1 | # List releases (aliases: rs) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] releases [releases-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [releases command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | 20 | ``` 21 | -------------------------------------------------------------------------------- /docs/content/reference/remove-file-group.md: -------------------------------------------------------------------------------- 1 | # Remove file group from release (aliases: rfg) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] remove-file-group [remove-file-group-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [remove-file-group command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | -i, --file-group-id= Filegroup ID e.g. 1234 20 | -r, --release-version= Release version e.g. 0.1.2-rc1 21 | 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/content/reference/remove-product-file.md: -------------------------------------------------------------------------------- 1 | # Remove product file from release (aliases: rpf) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] remove-product-file [remove-product-file-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [remove-product-file command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | -r, --release-version= Release version e.g. 0.1.2-rc1 20 | -i, --product-file-id= Product file ID e.g. 1234 21 | -f, --file-group-id= File group ID e.g. 1234 22 | 23 | ``` 24 | -------------------------------------------------------------------------------- /docs/content/reference/remove-release-dependency.md: -------------------------------------------------------------------------------- 1 | # Remove release dependency (aliases: rrd) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] remove-release-dependency [remove-release-dependency-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [remove-release-dependency command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | -r, --release-version= Release version e.g. 0.1.2-rc1 20 | -s, --dependent-product-slug= Dependent product slug e.g. p-mysql 21 | -u, --dependent-release-version= Dependent release version e.g. 0.1.2-rc1 22 | 23 | ``` 24 | -------------------------------------------------------------------------------- /docs/content/reference/remove-release-upgrade-path.md: -------------------------------------------------------------------------------- 1 | # Remove release upgrade path (aliases: rrup) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] remove-release-upgrade-path [remove-release-upgrade-path-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [remove-release-upgrade-path command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | -r, --release-version= Release version e.g. 0.1.2-rc1 20 | -u, --previous-release-version= Regex for previous release version e.g. 0.1.* 21 | 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/content/reference/remove-user-group-member.md: -------------------------------------------------------------------------------- 1 | # Remove user group member from group (aliases: rugm) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] remove-user-group-member [remove-user-group-member-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [remove-user-group-member command options] 18 | -i, --user-group-id= User group ID e.g. 1234 19 | --member-email= Member email address e.g. 1234 20 | 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/content/reference/remove-user-group.md: -------------------------------------------------------------------------------- 1 | # Remove user group from release (aliases: rug) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] remove-user-group [remove-user-group-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [remove-user-group command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | -r, --release-version= Release version e.g. 0.1.2-rc1 20 | -i, --user-group-id= User Group ID e.g. 1234 21 | 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/content/reference/update-file-group.md: -------------------------------------------------------------------------------- 1 | # Update file group (aliases: ufg) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] update-file-group [update-file-group-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [update-file-group command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | -i, --file-group-id= Filegroup ID e.g. 1234 20 | --name= Name e.g. my_file_group 21 | 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/content/reference/update-product-file.md: -------------------------------------------------------------------------------- 1 | # Update product file (aliases: upf) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] update-product-file [update-product-file-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [update-product-file command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | -i, --product-file-id= Product file ID e.g. 1234 20 | --name= Name e.g. p-mysql 1.7.13 21 | --file-version= File Version e.g. '1.7.13' 22 | --md5= MD5 of file 23 | --description= File description e.g. 'This is a file description.' 24 | 25 | ``` 26 | -------------------------------------------------------------------------------- /docs/content/reference/update-release.md: -------------------------------------------------------------------------------- 1 | # Update release (aliases: ur) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] update-release [update-release-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [update-release command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | -r, --release-version= Release version e.g. 0.1.2-rc1 20 | --availability=[admins|selected-user-groups|all] Release availability. Optional. 21 | --release-type=[all-in-one|major|minor|service|maintenance|security|alpha|beta|edge] Release type. Optional. 22 | 23 | ``` 24 | -------------------------------------------------------------------------------- /docs/content/reference/update-user-group.md: -------------------------------------------------------------------------------- 1 | # Update user group (aliases: uug) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] update-user-group [update-user-group-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [update-user-group command options] 18 | -i, --user-group-id= User group ID e.g. 1234 19 | --name= Name e.g. all_users 20 | --description= Description e.g. 'All users in the world' 21 | 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/content/reference/user-group.md: -------------------------------------------------------------------------------- 1 | # Show user group (aliases: ug) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] user-group [user-group-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [user-group command options] 18 | -i, --user-group-id= User group ID e.g. 1234 19 | 20 | ``` 21 | -------------------------------------------------------------------------------- /docs/content/reference/user-groups.md: -------------------------------------------------------------------------------- 1 | # List user groups (aliases: ugs) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] user-groups [user-groups-OPTIONS] 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | [user-groups command options] 18 | -p, --product-slug= Product slug e.g. p-mysql 19 | -r, --release-version= Release version e.g. 0.1.2-rc1 20 | 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/content/reference/version.md: -------------------------------------------------------------------------------- 1 | # Print the version of this CLI and exit (aliases: v) 2 | 3 | ``` 4 | Usage: 5 | pivnet [OPTIONS] version 6 | 7 | Application Options: 8 | -v, --version Print the version of this CLI and exit 9 | --format=[table|json|yaml] Format to print as (default: table) 10 | --verbose Display verbose output 11 | --profile= Name of profile (default: default) 12 | --config= Path to config file (default: /Users/pivotal/.pivnetrc) 13 | 14 | Help Options: 15 | -h, --help Show this help message 16 | 17 | ``` 18 | -------------------------------------------------------------------------------- /docs/readme.md: -------------------------------------------------------------------------------- 1 | ### Development 2 | 3 | For local development, use the following Docker command to build docs and preview on localhost:8000: 4 | 5 | `$ docker run --rm -it -p 8000:8000 -v "${PWD}:/docs" squidfunk/mkdocs-material:2.7.2` 6 | 7 | 8 | For building the site in the `site` folder, use the following Docker command: 9 | 10 | `$ docker run --rm -it -v "${PWD}:/docs" squidfunk/mkdocs-material:2.7.2 build` 11 | 12 | 13 | For publishing the site in the `site` folder, use the following command (prerequisite: `npm install -g gh-pages`): 14 | 15 | `gh-pages -d site --message 'Auto-generated commit [#157322604]'` 16 | -------------------------------------------------------------------------------- /docs/theme/material/404.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 |

404 - Not found

4 | {% endblock %} 5 | -------------------------------------------------------------------------------- /docs/theme/material/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pivotal-cf/pivnet-cli/8720ca395fdf2aac53b24da931aa42a6ac6c0caa/docs/theme/material/__init__.py -------------------------------------------------------------------------------- /docs/theme/material/assets/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pivotal-cf/pivnet-cli/8720ca395fdf2aac53b24da931aa42a6ac6c0caa/docs/theme/material/assets/images/favicon.png -------------------------------------------------------------------------------- /docs/theme/material/assets/images/icons/bitbucket.4ebea66e.svg: -------------------------------------------------------------------------------- 1 | 3 | 20 | 21 | -------------------------------------------------------------------------------- /docs/theme/material/assets/images/icons/github.a4034fb1.svg: -------------------------------------------------------------------------------- 1 | 3 | 18 | 19 | -------------------------------------------------------------------------------- /docs/theme/material/assets/images/icons/gitlab.348cdb3a.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | 7 | 8 | 9 | 12 | 13 | 14 | 17 | 18 | 19 | 22 | 23 | 24 | 27 | 28 | 29 | 32 | 33 | 34 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /docs/theme/material/assets/javascripts/lunr/lunr.jp.js: -------------------------------------------------------------------------------- 1 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r="2"==e.version[0];e.jp=function(){this.pipeline.reset(),this.pipeline.add(e.jp.stopWordFilter,e.jp.stemmer),r?this.tokenizer=e.jp.tokenizer:(e.tokenizer&&(e.tokenizer=e.jp.tokenizer),this.tokenizerFn&&(this.tokenizerFn=e.jp.tokenizer))};var t=new e.TinySegmenter;e.jp.tokenizer=function(n){if(!arguments.length||null==n||null==n)return[];if(Array.isArray(n))return n.map(function(t){return r?new e.Token(t.toLowerCase()):t.toLowerCase()});for(var i=n.toString().toLowerCase().replace(/^\s+/,""),o=i.length-1;o>=0;o--)if(/\S/.test(i.charAt(o))){i=i.substring(0,o+1);break}return t.segment(i).filter(function(e){return!!e}).map(function(t){return r?new e.Token(t):t})},e.jp.stemmer=function(e){return e},e.Pipeline.registerFunction(e.jp.stemmer,"stemmer-jp"),e.jp.wordCharacters="一二三四五六七八九十百千万億兆一-龠々〆ヵヶぁ-んァ-ヴーア-ン゙a-zA-Za-zA-Z0-90-9",e.jp.stopWordFilter=function(t){if(-1===e.jp.stopWordFilter.stopWords.indexOf(r?t.toString():t))return t},e.jp.stopWordFilter=e.generateStopWordFilter("これ それ あれ この その あの ここ そこ あそこ こちら どこ だれ なに なん 何 私 貴方 貴方方 我々 私達 あの人 あのかた 彼女 彼 です あります おります います は が の に を で え から まで より も どの と し それで しかし".split(" ")),e.Pipeline.registerFunction(e.jp.stopWordFilter,"stopWordFilter-jp")}}); -------------------------------------------------------------------------------- /docs/theme/material/assets/javascripts/lunr/lunr.multi.js: -------------------------------------------------------------------------------- 1 | !function(e,i){"function"==typeof define&&define.amd?define(i):"object"==typeof exports?module.exports=i():i()(e.lunr)}(this,function(){return function(e){e.multiLanguage=function(){for(var i=Array.prototype.slice.call(arguments),t=i.join("-"),r="",n=[],s=[],p=0;p 2 | 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to 5 | # deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | # IN THE SOFTWARE. 20 | 21 | # Language for theme localization 22 | language: en 23 | 24 | # Text direction (can be ltr or rtl), default: ltr 25 | direction: 26 | 27 | # Feature flags for functionality that alters behavior significantly, and thus 28 | # may be a matter of taste 29 | feature: 30 | 31 | # Another layer on top of the main navigation for larger screens in the form 32 | # of tabs, especially useful for larger documentation projects 33 | tabs: false 34 | 35 | # Sets the primary and accent color palettes as defined in the Material Design 36 | # documentation - possible values can be looked up in the getting started guide 37 | palette: 38 | 39 | # Primary color used for header, sidebar and links, default: indigo 40 | primary: 41 | 42 | # Accent color for highlighting user interaction, default: indigo 43 | accent: 44 | 45 | # Fonts used by Material, automatically loaded from Google Fonts - see the site 46 | # for a list of available fonts 47 | font: 48 | 49 | # Default font for text 50 | text: Roboto 51 | 52 | # Fixed-width font for code listings 53 | code: Roboto Mono 54 | 55 | # Favicon to be rendered 56 | favicon: assets/images/favicon.png 57 | 58 | # The logo of the documentation shown in the header and navigation can either 59 | # be a Material Icon ligature (see https://material.io/icons/) or an image URL 60 | logo: 61 | icon: "\uE80C" 62 | 63 | # Material includes the search in the header as a partial, not as a separate 64 | # template, so it's correct that search.html is missing 65 | include_search_page: false 66 | 67 | # Material doesn't use MkDocs search functionality but provides its own. For 68 | # this reason, only the search index needs to be built 69 | search_index_only: true 70 | 71 | # Static pages to build 72 | static_templates: 73 | - 404.html 74 | -------------------------------------------------------------------------------- /docs/theme/material/partials/footer.html: -------------------------------------------------------------------------------- 1 | {% import "partials/language.html" as lang with context %} 2 | 59 | -------------------------------------------------------------------------------- /docs/theme/material/partials/header.html: -------------------------------------------------------------------------------- 1 |
2 | 51 |
52 | -------------------------------------------------------------------------------- /docs/theme/material/partials/hero.html: -------------------------------------------------------------------------------- 1 | {% set feature = config.theme.feature %} 2 | {% set class = "md-hero" %} 3 | {% if not feature.tabs %} 4 | {% set class = "md-hero md-hero--expand" %} 5 | {% endif %} 6 |
7 |
8 | {{ page.meta.hero }} 9 |
10 |
11 | -------------------------------------------------------------------------------- /docs/theme/material/partials/integrations/analytics.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/theme/material/partials/integrations/disqus.html: -------------------------------------------------------------------------------- 1 | {% set disqus = config.extra.disqus %} 2 | {% if page and page.meta and page.meta.disqus is string %} 3 | {% set disqus = page.meta.disqus %} 4 | {% endif %} 5 | {% if not page.is_homepage and disqus %} 6 |

{{ lang.t("meta.comments") }}

7 |
8 | 21 | {% endif %} 22 | -------------------------------------------------------------------------------- /docs/theme/material/partials/language.html: -------------------------------------------------------------------------------- 1 | {% import "partials/language/" + config.theme.language + ".html" as lang %} 2 | {% import "partials/language/en.html" as fallback %} 3 | {% macro t(key) %}{{ { 4 | "direction": config.theme.direction, 5 | "search.language": ( 6 | config.extra.search | default({}) 7 | ).language, 8 | "search.tokenizer": ( 9 | config.extra.search | default({}) 10 | ).tokenizer | default("", true), 11 | }[key] or lang.t(key) or fallback.t(key) }}{% endmacro %} 12 | -------------------------------------------------------------------------------- /docs/theme/material/partials/language/ar.html: -------------------------------------------------------------------------------- 1 | {% macro t(key) %}{{ { 2 | "language": "ar", 3 | "direction": "rtl", 4 | "clipboard.copy": "نسخ إلى الحافظة", 5 | "clipboard.copied": "تم النسخ الى الحافظة", 6 | "edit.link.title": "عدل الصفحة", 7 | "footer.previous": "السابقة", 8 | "footer.next": "التالية", 9 | "meta.comments": "التعليقات", 10 | "meta.source": "المصدر", 11 | "search.language": "", 12 | "search.pipeline.stopwords": false, 13 | "search.pipeline.trimmer": false, 14 | "search.placeholder": "بحث", 15 | "search.result.placeholder": "اكتب لبدء البحث", 16 | "search.result.none": "لا توجد نتائج", 17 | "search.result.one": "نتائج البحث مستند واحد", 18 | "search.result.other": "نتائج البحث # مستندات", 19 | "skip.link.title": "انتقل إلى المحتوى", 20 | "source.link.title": "اذهب إلى المصدر", 21 | "toc.title": "جدول المحتويات" 22 | }[key] }}{% endmacro %} 23 | -------------------------------------------------------------------------------- /docs/theme/material/partials/language/ca.html: -------------------------------------------------------------------------------- 1 | {% macro t(key) %}{{ { 2 | "language": "ca", 3 | "clipboard.copy": "Còpia al porta-retalls", 4 | "clipboard.copied": "Copiat al porta-retalls", 5 | "edit.link.title": "Edita aquesta pàgina", 6 | "footer.previous": "Anterior", 7 | "footer.next": "Següent", 8 | "meta.comments": "Comentaris", 9 | "meta.source": "Codi font", 10 | "search.language": "", 11 | "search.placeholder": "Cerca", 12 | "search.result.placeholder": "Escriu per a començar a cercar", 13 | "search.result.none": "Cap document coincideix", 14 | "search.result.one": "1 document coincident", 15 | "search.result.other": "# documents coincidents", 16 | "skip.link.title": "Salta el contingut", 17 | "source.link.title": "Ves al repositori", 18 | "toc.title": "Taula de continguts" 19 | }[key] }}{% endmacro %} 20 | -------------------------------------------------------------------------------- /docs/theme/material/partials/language/da.html: -------------------------------------------------------------------------------- 1 | {% macro t(key) %}{{ { 2 | "language": "da", 3 | "clipboard.copy": "Kopiér til udklipsholderen", 4 | "clipboard.copied": "Kopieret til udklipsholderen", 5 | "edit.link.title": "Redigér denne side", 6 | "footer.previous": "Forrige", 7 | "footer.next": "Næste", 8 | "meta.comments": "Kommentarer", 9 | "meta.source": "Kilde", 10 | "search.language": "da", 11 | "search.placeholder": "Søg", 12 | "search.result.placeholder": "Indtask søgeord", 13 | "search.result.none": "Ingen resultater fundet", 14 | "search.result.one": "1 resultat", 15 | "search.result.other": "# resultater", 16 | "skip.link.title": "Gå til indholdet", 17 | "source.link.title": "Åbn arkiv", 18 | "toc.title": "Indholdsfortegnelse" 19 | }[key] }}{% endmacro %} 20 | -------------------------------------------------------------------------------- /docs/theme/material/partials/language/de.html: -------------------------------------------------------------------------------- 1 | {% macro t(key) %}{{ { 2 | "language": "de", 3 | "clipboard.copy": "In Zwischenablage kopieren", 4 | "clipboard.copied": "In Zwischenablage kopiert", 5 | "edit.link.title": "Seite editieren", 6 | "footer.previous": "Zurück", 7 | "footer.next": "Weiter", 8 | "meta.comments": "Kommentare", 9 | "meta.source": "Quellcode", 10 | "search.language": "de", 11 | "search.placeholder": "Suche", 12 | "search.result.placeholder": "Suchbegriff eingeben", 13 | "search.result.none": "Keine Suchergebnisse", 14 | "search.result.one": "1 Suchergebnis", 15 | "search.result.other": "# Suchergebnisse", 16 | "skip.link.title": "Zum Inhalt", 17 | "source.link.title": "Quellcode", 18 | "toc.title": "Inhaltsverzeichnis" 19 | }[key] }}{% endmacro %} 20 | -------------------------------------------------------------------------------- /docs/theme/material/partials/language/en.html: -------------------------------------------------------------------------------- 1 | {% macro t(key) %}{{ { 2 | "language": "en", 3 | "direction": "ltr", 4 | "clipboard.copy": "Copy to clipboard", 5 | "clipboard.copied": "Copied to clipboard", 6 | "edit.link.title": "Edit this page", 7 | "footer.previous": "Previous", 8 | "footer.next": "Next", 9 | "meta.comments": "Comments", 10 | "meta.source": "Source", 11 | "search.language": "en", 12 | "search.pipeline.stopwords": true, 13 | "search.pipeline.trimmer": true, 14 | "search.placeholder": "Search", 15 | "search.result.placeholder": "Type to start searching", 16 | "search.result.none": "No matching documents", 17 | "search.result.one": "1 matching document", 18 | "search.result.other": "# matching documents", 19 | "search.tokenizer": "[\s\-]+", 20 | "skip.link.title": "Skip to content", 21 | "source.link.title": "Go to repository", 22 | "toc.title": "Table of contents" 23 | }[key] }}{% endmacro %} 24 | -------------------------------------------------------------------------------- /docs/theme/material/partials/language/es.html: -------------------------------------------------------------------------------- 1 | {% macro t(key) %}{{ { 2 | "language": "es", 3 | "clipboard.copy": "Copiar al portapapeles", 4 | "clipboard.copied": "Copiado al portapapeles", 5 | "edit.link.title": "Editar esta página", 6 | "footer.previous": "Anterior", 7 | "footer.next": "Siguiente", 8 | "meta.comments": "Comentarios", 9 | "meta.source": "Fuente", 10 | "search.language": "es", 11 | "search.placeholder": "Búsqueda", 12 | "search.result.placeholder": "Teclee para comenzar búsqueda", 13 | "search.result.none": "No se encontraron documentos", 14 | "search.result.one": "1 documento encontrado", 15 | "search.result.other": "# documentos encontrados", 16 | "skip.link.title": "Saltar a contenido", 17 | "source.link.title": "Ir al repositorio", 18 | "toc.title": "Tabla de contenidos" 19 | }[key] }}{% endmacro %} 20 | -------------------------------------------------------------------------------- /docs/theme/material/partials/language/fa.html: -------------------------------------------------------------------------------- 1 | {% macro t(key) %}{{ { 2 | "language": "fa", 3 | "direction": "rtl", 4 | "clipboard.copy": "کپی کردن", 5 | "clipboard.copied": "کپی شد", 6 | "edit.link.title": "این صفحه را ویرایش کنید", 7 | "footer.previous": "قبلی", 8 | "footer.next": "بعدی", 9 | "meta.comments": "نظرات", 10 | "meta.source": "منبع", 11 | "search.language": "", 12 | "search.pipeline.stopwords": false, 13 | "search.pipeline.trimmer": false, 14 | "search.placeholder": "جستجو", 15 | "search.result.placeholder": "برای شروع جستجو تایپ کنید", 16 | "search.result.none": "سندی یافت نشد", 17 | "search.result.one": "1 سند یافت شد", 18 | "search.result.other": "# سند یافت شد", 19 | "skip.link.title": "پرش به محتویات", 20 | "source.link.title": "رفتن به مخزن", 21 | "toc.title": "فهرست موضوعات" 22 | }[key] }}{% endmacro %} 23 | -------------------------------------------------------------------------------- /docs/theme/material/partials/language/fi.html: -------------------------------------------------------------------------------- 1 | {% macro t(key) %}{{ { 2 | "language": "fi", 3 | "clipboard.copy": "Kopioi leikepöydälle", 4 | "clipboard.copied": "Kopioitu leikepöydälle", 5 | "edit.link.title": "Muokkaa tätä sivua", 6 | "footer.previous": "Edellinen", 7 | "footer.next": "Seuraava", 8 | "meta.comments": "Kommentit", 9 | "meta.source": "Lähdekodi", 10 | "search.language": "fi", 11 | "search.placeholder": "Hae", 12 | "search.result.placeholder": "Kirjoita aloittaaksesi haun", 13 | "search.result.none": "Ei täsmääviä dokumentteja", 14 | "search.result.one": "1 täsmäävä dokumentti", 15 | "search.result.other": "# täsmäävää dokumenttia", 16 | "skip.link.title": "Hyppää sisältöön", 17 | "source.link.title": "Mene repositoryyn", 18 | "toc.title": "Sisällysluettelo" 19 | }[key] }}{% endmacro %} 20 | -------------------------------------------------------------------------------- /docs/theme/material/partials/language/fr.html: -------------------------------------------------------------------------------- 1 | {% macro t(key) %}{{ { 2 | "language": "fr", 3 | "clipboard.copy": "Copier dans le presse-papier", 4 | "clipboard.copied": "Copié dans le presse-papier", 5 | "edit.link.title": "Editer cette page", 6 | "footer.previous": "Précédent", 7 | "footer.next": "Suivant", 8 | "meta.comments": "Commentaires", 9 | "meta.source": "Source", 10 | "search.language": "fr", 11 | "search.placeholder": "Rechercher", 12 | "search.result.placeholder": "Taper pour démarrer la recherche", 13 | "search.result.none": "Aucun document trouvé", 14 | "search.result.one": "1 document trouvé", 15 | "search.result.other": "# documents trouvés", 16 | "source.link.title": "Aller au dépôt", 17 | "toc.title": "Table des matières" 18 | }[key] }}{% endmacro %} 19 | -------------------------------------------------------------------------------- /docs/theme/material/partials/language/gl.html: -------------------------------------------------------------------------------- 1 | {% macro t(key) %}{{ { 2 | "language": "gl", 3 | "clipboard.copy": "Copiar no cortapapeis", 4 | "clipboard.copied": "Copiado no cortapapeis", 5 | "edit.link.title": "Editar esta páxina", 6 | "footer.previous": "Anterior", 7 | "footer.next": "Seguinte", 8 | "meta.comments": "Comentarios", 9 | "meta.source": "Fonte", 10 | "search.language": "es", 11 | "search.placeholder": "Busca", 12 | "search.result.placeholder": "Insira un termo", 13 | "search.result.none": "Sen resultados", 14 | "search.result.one": "1 resultado atopado", 15 | "search.result.other": "# resultados atopados", 16 | "skip.link.title": "Ir ao contido", 17 | "source.link.title": "Ir ao repositorio", 18 | "toc.title": "Táboa de contidos" 19 | }[key] }}{% endmacro %} 20 | -------------------------------------------------------------------------------- /docs/theme/material/partials/language/he.html: -------------------------------------------------------------------------------- 1 | {% macro t(key) %}{{ { 2 | "language": "he", 3 | "direction": "rtl", 4 | "clipboard.copy": "העתק ללוח", 5 | "clipboard.copied": "הועתק ללוח", 6 | "edit.link.title": "ערוך דף זה", 7 | "footer.previous": "קודם", 8 | "footer.next": "הַבָּא", 9 | "meta.comments": "הערות", 10 | "meta.source": "מָקוֹר", 11 | "search.language": "", 12 | "search.pipeline.stopwords": false, 13 | "search.pipeline.trimmer": false, 14 | "search.placeholder": "לחפש", 15 | "search.result.placeholder": "הקלד כדי להתחיל לחפש", 16 | "search.result.none": "אין מסמכים תואמים", 17 | "search.result.one": "1 מסמך תואם", 18 | "search.result.other": "# מסמך תואם", 19 | "skip.link.title": "דלג לתוכן", 20 | "source.link.title": "עבור אל מאגר", 21 | "toc.title": "תוכן העניינים" 22 | }[key] }}{% endmacro %} 23 | -------------------------------------------------------------------------------- /docs/theme/material/partials/language/hu.html: -------------------------------------------------------------------------------- 1 | {% macro t(key) %}{{ { 2 | "language": "hu", 3 | "clipboard.copy": "Másolás vágólapra", 4 | "clipboard.copied": "Vágólapra másolva", 5 | "edit.link.title": "Oldal szerkesztése", 6 | "footer.previous": "Előző", 7 | "footer.next": "Következő", 8 | "meta.comments": "Hozzászólások", 9 | "meta.source": "Forrás", 10 | "search.language": "hu", 11 | "search.placeholder": "Keresés", 12 | "search.result.placeholder": "Kereséshez írj ide valamit", 13 | "search.result.none": "Nincs találat", 14 | "search.result.one": "1 egyező dokumentum", 15 | "search.result.other": "# egyező dokumentum", 16 | "skip.link.title": "Kihagyás", 17 | "source.link.title": "Főoldalra ugrás", 18 | "toc.title": "Tartalomjegyzék" 19 | }[key] }}{% endmacro %} 20 | -------------------------------------------------------------------------------- /docs/theme/material/partials/language/it.html: -------------------------------------------------------------------------------- 1 | {% macro t(key) %}{{ { 2 | "language": "it", 3 | "clipboard.copy": "Copia", 4 | "clipboard.copied": "Copiato", 5 | "edit.link.title": "Modifica", 6 | "footer.previous": "Precedente", 7 | "footer.next": "Prossimo", 8 | "meta.comments": "Commenti", 9 | "meta.source": "Sorgente", 10 | "search.language": "it", 11 | "search.placeholder": "Cerca", 12 | "search.result.placeholder": "Scrivi per iniziare a cercare", 13 | "search.result.none": "Nessun documento trovato", 14 | "search.result.one": "1 documento trovato", 15 | "search.result.other": "# documenti trovati", 16 | "skip.link.title": "Vai al contenuto", 17 | "source.link.title": "Apri repository", 18 | "toc.title": "Indice" 19 | }[key] }}{% endmacro %} 20 | -------------------------------------------------------------------------------- /docs/theme/material/partials/language/ja.html: -------------------------------------------------------------------------------- 1 | {% macro t(key) %}{{ { 2 | "language": "ja", 3 | "clipboard.copy": "クリップボードへコピー", 4 | "clipboard.copied": "コピーしました", 5 | "edit.link.title": "編集", 6 | "footer.previous": "前", 7 | "footer.next": "次", 8 | "meta.comments": "コメント", 9 | "meta.source": "ソース", 10 | "search.language": "jp", 11 | "search.placeholder": "検索", 12 | "search.result.placeholder": "検索キーワードを入力してください", 13 | "search.result.none": "何も見つかりませんでした", 14 | "search.result.one": "1件見つかりました", 15 | "search.result.other": "#件見つかりました", 16 | "search.tokenizer": "[\s\- 、。,.]+", 17 | "source.link.title": "リポジトリへ", 18 | "toc.title": "目次" 19 | }[key] }}{% endmacro %} 20 | -------------------------------------------------------------------------------- /docs/theme/material/partials/language/kr.html: -------------------------------------------------------------------------------- 1 | {% macro t(key) %}{{ { 2 | "language": "kr", 3 | "clipboard.copy": "클립보드로 복사", 4 | "clipboard.copied": "클립보드에 복사됨", 5 | "edit.link.title": "이 페이지를 편집", 6 | "footer.previous": "이전", 7 | "footer.next": "다음", 8 | "meta.comments": "댓글", 9 | "meta.source": "출처", 10 | "search.language": "jp", 11 | "search.placeholder": "검색", 12 | "search.result.placeholder": "검색어를 입력하세요", 13 | "search.result.none": "검색어와 일치하는 문서가 없습니다", 14 | "search.result.one": "1개의 일치하는 문서", 15 | "search.result.other": "#개의 일치하는 문서", 16 | "source.link.title": "저장소로 이동", 17 | "toc.title": "목차" 18 | }[key] }}{% endmacro %} 19 | -------------------------------------------------------------------------------- /docs/theme/material/partials/language/nl.html: -------------------------------------------------------------------------------- 1 | {% macro t(key) %}{{ { 2 | "language": "nl", 3 | "clipboard.copy": "Kopiëren naar klembord", 4 | "clipboard.copied": "Gekopieerd naar klembord", 5 | "edit.link.title": "Wijzig deze pagina", 6 | "footer.previous": "Vorige", 7 | "footer.next": "Volgende", 8 | "meta.comments": "Reacties", 9 | "meta.source": "Bron", 10 | "search.language": "du", 11 | "search.placeholder": "Zoeken", 12 | "search.result.placeholder": "Typ om te beginnen met zoeken", 13 | "search.result.none": "Geen overeenkomende documenten", 14 | "search.result.one": "1 overeenkomende document", 15 | "search.result.other": "# overeenkomende documenten", 16 | "skip.link.title": "Ga naar inhoud", 17 | "source.link.title": "Ga naar repository", 18 | "toc.title": "Inhoudstafel" 19 | }[key] }}{% endmacro %} 20 | -------------------------------------------------------------------------------- /docs/theme/material/partials/language/no.html: -------------------------------------------------------------------------------- 1 | {% macro t(key) %}{{ { 2 | "language": "no", 3 | "clipboard.copy": "Kopier til utklippstavlen", 4 | "clipboard.copied": "Kopiert til utklippstavlen", 5 | "edit.link.title": "Rediger denne siden", 6 | "footer.previous": "Forrige", 7 | "footer.next": "Neste", 8 | "meta.comments": "Kommentarer", 9 | "meta.source": "Kilde", 10 | "search.language": "no", 11 | "search.placeholder": "Søk", 12 | "search.result.placeholder": "Skriv søkeord", 13 | "search.result.none": "Ingen treff", 14 | "search.result.one": "1 treff", 15 | "search.result.other": "# treff", 16 | "skip.link.title": "Gå til innhold", 17 | "source.link.title": "Gå til kilde", 18 | "toc.title": "Innholdsfortegnelse" 19 | }[key] }}{% endmacro %} 20 | -------------------------------------------------------------------------------- /docs/theme/material/partials/language/pl.html: -------------------------------------------------------------------------------- 1 | {% macro t(key) %}{{ { 2 | "language": "pl", 3 | "clipboard.copy": "Kopiuj do schowka", 4 | "clipboard.copied": "Skopiowane", 5 | "edit.link.title": "Edytuj tę stronę", 6 | "footer.previous": "Poprzednia strona", 7 | "footer.next": "Następna strona", 8 | "meta.comments": "Komentarze", 9 | "meta.source": "Kod źródłowy", 10 | "search.language": "", 11 | "search.pipeline.stopwords": false, 12 | "search.pipeline.trimmer": false, 13 | "search.placeholder": "Szukaj", 14 | "search.result.placeholder": "Zacznij pisać, aby szukać", 15 | "search.result.none": "Brak wyników wyszukiwania", 16 | "search.result.one": "Wyniki wyszukiwania: 1", 17 | "search.result.other": "Wyniki wyszukiwania: #", 18 | "skip.link.title": "Przejdź do treści", 19 | "source.link.title": "Idź do repozytorium", 20 | "toc.title": "Spis treści" 21 | }[key] }}{% endmacro %} 22 | -------------------------------------------------------------------------------- /docs/theme/material/partials/language/pt.html: -------------------------------------------------------------------------------- 1 | {% macro t(key) %}{{ { 2 | "language": "pt", 3 | "clipboard.copy": "Copiar para área de transferência", 4 | "clipboard.copied": "Copiado para área de transferência", 5 | "edit.link.title": "Editar esta página", 6 | "footer.previous": "Anterior", 7 | "footer.next": "Próximo", 8 | "meta.comments": "Comentários", 9 | "meta.source": "Fonte", 10 | "search.language": "pt", 11 | "search.placeholder": "Buscar", 12 | "search.result.placeholder": "Digite para iniciar a busca", 13 | "search.result.none": "Nenhum resultado encontrado", 14 | "search.result.one": "1 resultado encontrado", 15 | "search.result.other": "# resultados encontrados", 16 | "skip.link.title": "Ir para o conteúdo", 17 | "source.link.title": "Ir ao repositório", 18 | "toc.title": "Índice" 19 | }[key] }}{% endmacro %} 20 | -------------------------------------------------------------------------------- /docs/theme/material/partials/language/ru.html: -------------------------------------------------------------------------------- 1 | {% macro t(key) %}{{ { 2 | "language": "ru", 3 | "clipboard.copy": "Копировать в буфер", 4 | "clipboard.copied": "Скопировано в буфер", 5 | "edit.link.title": "Редактировать страницу", 6 | "footer.previous": "Назад", 7 | "footer.next": "Вперед", 8 | "meta.comments": "Комментарии", 9 | "meta.source": "Исходный код", 10 | "search.language": "ru", 11 | "search.placeholder": "Поиск", 12 | "search.result.placeholder": "Начните печатать для поиска", 13 | "search.result.none": "Совпадений не найдено", 14 | "search.result.one": "Найдено 1 совпадение", 15 | "search.result.other": "Найдено # совпадений", 16 | "skip.link.title": "Перейти к содержанию", 17 | "source.link.title": "Перейти к репозиторию", 18 | "toc.title": "Содержание" 19 | }[key] }}{% endmacro %} 20 | -------------------------------------------------------------------------------- /docs/theme/material/partials/language/sv.html: -------------------------------------------------------------------------------- 1 | {% macro t(key) %}{{ { 2 | "language": "sv", 3 | "clipboard.copy": "Kopiera till urklipp", 4 | "clipboard.copied": "Kopierat till urklipp", 5 | "edit.link.title": "Redigera sidan", 6 | "footer.previous": "Föregående", 7 | "footer.next": "Nästa", 8 | "meta.comments": "Kommentarer", 9 | "meta.source": "Källa", 10 | "search.language": "sv", 11 | "search.placeholder": "Sök", 12 | "search.result.placeholder": "Skriv sökord", 13 | "search.result.none": "Inga sökresultat", 14 | "search.result.one": "1 sökresultat", 15 | "search.result.other": "# sökresultat", 16 | "skip.link.title": "Gå till innehållet", 17 | "source.link.title": "Gå till datakatalog", 18 | "toc.title": "Innehållsförteckning" 19 | }[key] }}{% endmacro %} 20 | -------------------------------------------------------------------------------- /docs/theme/material/partials/language/tr.html: -------------------------------------------------------------------------------- 1 | {% macro t(key) %}{{ { 2 | "language": "tr", 3 | "clipboard.copy": "Kopyala", 4 | "clipboard.copied": "Kopyalandı", 5 | "edit.link.title": "Düzenle", 6 | "footer.previous": "Önceki", 7 | "footer.next": "Sonraki", 8 | "meta.comments": "Yorumlar", 9 | "meta.source": "Kaynak", 10 | "search.language": "tr", 11 | "search.placeholder": "Ara", 12 | "search.result.placeholder": "Aramaya başlamak için yazın", 13 | "search.result.none": "Eşleşen doküman bulunamadı", 14 | "search.result.one": "1 doküman bulundu", 15 | "search.result.other": "# doküman bulundu", 16 | "source.link.title": "Depoya git", 17 | "toc.title": "İçindekiler" 18 | }[key] }}{% endmacro %} 19 | -------------------------------------------------------------------------------- /docs/theme/material/partials/language/uk.html: -------------------------------------------------------------------------------- 1 | {% macro t(key) %}{{ { 2 | "language": "uk", 3 | "clipboard.copy": "Скопіювати в буфер", 4 | "clipboard.copied": "Скопійовано в буфер", 5 | "edit.link.title": "Редагувати сторінку", 6 | "footer.previous": "Назад", 7 | "footer.next": "Вперед", 8 | "meta.comments": "Коментарі", 9 | "meta.source": "Вихідний код", 10 | "search.language": "ru", 11 | "search.placeholder": "Пошук", 12 | "search.result.placeholder": "Розпочніть писати для пошуку", 13 | "search.result.none": "Збігів не знайдено", 14 | "search.result.one": "Знайдено 1 збіг", 15 | "search.result.other": "Знайдено # збігів", 16 | "skip.link.title": "Перейти до змісту", 17 | "source.link.title": "Перейти до репозиторію", 18 | "toc.title": "Зміст" 19 | }[key] }}{% endmacro %} 20 | -------------------------------------------------------------------------------- /docs/theme/material/partials/language/vi.html: -------------------------------------------------------------------------------- 1 | {% macro t(key) %}{{ { 2 | "language": "vi", 3 | "clipboard.copy": "Sao chép vào bộ nhớ", 4 | "clipboard.copied": "Sao chép xong", 5 | "edit.link.title": "Chỉnh sửa", 6 | "footer.previous": "Trước", 7 | "footer.next": "Sau", 8 | "meta.comments": "Bình luận", 9 | "meta.source": "Mã nguồn", 10 | "search.placeholder": "Tìm kiếm", 11 | "search.result.placeholder": "Nhập để bắt đầu tìm kiếm", 12 | "search.result.none": "Không tìm thấy tài liệu liên quan", 13 | "search.result.one": "1 tài liệu liên quan", 14 | "search.result.other": "# tài liệu liên quan", 15 | "skip.link.title": "Vào thẳng nội dung", 16 | "source.link.title": "Đến kho lưu trữ mã nguồn", 17 | "toc.title": "Mục lục" 18 | }[key] }}{% endmacro %} 19 | -------------------------------------------------------------------------------- /docs/theme/material/partials/language/zh-Hant.html: -------------------------------------------------------------------------------- 1 | {% macro t(key) %}{{ { 2 | "language": "zh-Hant", 3 | "clipboard.copy": "拷貝", 4 | "clipboard.copied": "已拷貝", 5 | "edit.link.title": "編輯此頁", 6 | "footer.previous": "上一頁", 7 | "footer.next": "下一頁", 8 | "meta.comments": "評論", 9 | "meta.source": "來源", 10 | "search.language": "jp", 11 | "search.placeholder": "搜尋", 12 | "search.result.placeholder": "鍵入以開始檢索", 13 | "search.result.none": "沒有找到符合條件的結果", 14 | "search.result.one": "找到 1 个符合條件的結果", 15 | "search.result.other": "# 個符合條件的結果", 16 | "search.tokenizer": "[\,\。]+", 17 | "skip.link.title": "跳轉至", 18 | "source.link.title": "前往 Github 倉庫", 19 | "toc.title": "目錄" 20 | }[key] }}{% endmacro %} 21 | -------------------------------------------------------------------------------- /docs/theme/material/partials/language/zh.html: -------------------------------------------------------------------------------- 1 | {% macro t(key) %}{{ { 2 | "language": "zh", 3 | "clipboard.copy": "复制", 4 | "clipboard.copied": "已复制", 5 | "edit.link.title": "编辑此页", 6 | "footer.previous": "后退", 7 | "footer.next": "前进", 8 | "meta.comments": "评论", 9 | "meta.source": "来源", 10 | "search.language": "jp", 11 | "search.placeholder": "搜索", 12 | "search.result.placeholder": "键入以开始搜索", 13 | "search.result.none": "没有找到符合条件的结果", 14 | "search.result.one": "找到 1 个符合条件的结果", 15 | "search.result.other": "# 个符合条件的结果", 16 | "search.tokenizer": "[\,\。]+", 17 | "skip.link.title": "跳转至", 18 | "source.link.title": "前往 Github 仓库", 19 | "toc.title": "目录" 20 | }[key] }}{% endmacro %} 21 | -------------------------------------------------------------------------------- /docs/theme/material/partials/nav-item.html: -------------------------------------------------------------------------------- 1 | {% set class = "md-nav__item" %} 2 | {% if nav_item.active %} 3 | {% set class = "md-nav__item md-nav__item--active" %} 4 | {% endif %} 5 | {% if nav_item.children %} 6 |
  • 7 | {% if nav_item.active %} 8 | 9 | {% else %} 10 | 11 | {% endif %} 12 | 15 | 28 |
  • 29 | {% elif nav_item == page %} 30 |
  • 31 | {% set toc_ = page.toc %} 32 | 33 | {% if toc_ | first is defined and "\x3ch1 id=" in page.content %} 34 | {% set toc_ = (toc_ | first).children %} 35 | {% endif %} 36 | {% if toc_ | first is defined %} 37 | 40 | {% endif %} 41 | 42 | {{ nav_item.title }} 43 | 44 | {% if toc_ | first is defined %} 45 | {% include "partials/toc.html" %} 46 | {% endif %} 47 |
  • 48 | {% else %} 49 |
  • 50 | 51 | {{ nav_item.title }} 52 | 53 |
  • 54 | {% endif %} 55 | -------------------------------------------------------------------------------- /docs/theme/material/partials/nav.html: -------------------------------------------------------------------------------- 1 | 27 | -------------------------------------------------------------------------------- /docs/theme/material/partials/search.html: -------------------------------------------------------------------------------- 1 | {% import "partials/language.html" as lang with context %} 2 | 24 | -------------------------------------------------------------------------------- /docs/theme/material/partials/social.html: -------------------------------------------------------------------------------- 1 | {% if config.extra.social %} 2 | 9 | {% endif %} 10 | -------------------------------------------------------------------------------- /docs/theme/material/partials/source.html: -------------------------------------------------------------------------------- 1 | {% import "partials/language.html" as lang with context %} 2 | {% set platform = config.extra.repo_icon or config.repo_url %} 3 | {% if "github" in platform %} 4 | {% set repo_type = "github" %} 5 | {% elif "gitlab" in platform %} 6 | {% set repo_type = "gitlab" %} 7 | {% elif "bitbucket" in platform %} 8 | {% set repo_type = "bitbucket" %} 9 | {% else %} 10 | {% set repo_type = "" %} 11 | {% endif %} 12 | {% block repo %} 13 | 14 | {% if repo_type %} 15 |
    16 | 17 | 18 | 19 |
    20 | {% endif %} 21 |
    22 | {{ config.repo_name }} 23 |
    24 |
    25 | {% endblock %} 26 | -------------------------------------------------------------------------------- /docs/theme/material/partials/tabs-item.html: -------------------------------------------------------------------------------- 1 | {% if nav_item.is_homepage %} 2 |
  • 3 | {% if not page.ancestors | length and nav | selectattr("url", page.url) %} 4 | 5 | {{ nav_item.title }} 6 | 7 | {% else %} 8 | 9 | {{ nav_item.title }} 10 | 11 | {% endif %} 12 |
  • 13 | {% elif nav_item.children and nav_item.children | length > 0 %} 14 | {% set title = title | default(nav_item.title) %} 15 | {% if (nav_item.children | first).children | length > 0 %} 16 | {% set nav_item = nav_item.children | first %} 17 | {% include "partials/tabs-item.html" %} 18 | {% else %} 19 |
  • 20 | {% if nav_item.active %} 21 | 22 | {{ title }} 23 | 24 | {% else %} 25 | 26 | {{ title }} 27 | 28 | {% endif %} 29 |
  • 30 | {% endif %} 31 | {% endif %} 32 | -------------------------------------------------------------------------------- /docs/theme/material/partials/tabs.html: -------------------------------------------------------------------------------- 1 | {% set class = "md-tabs" %} 2 | {% if page.ancestors | length > 0 %} 3 | {% set class = "md-tabs md-tabs--active" %} 4 | {% endif %} 5 | 14 | -------------------------------------------------------------------------------- /docs/theme/material/partials/toc-item.html: -------------------------------------------------------------------------------- 1 |
  • 2 | 3 | {{ toc_item.title }} 4 | 5 | {% if toc_item.children %} 6 | 13 | {% endif %} 14 |
  • 15 | -------------------------------------------------------------------------------- /docs/theme/material/partials/toc.html: -------------------------------------------------------------------------------- 1 | {% import "partials/language.html" as lang with context %} 2 | 34 | -------------------------------------------------------------------------------- /errorhandler/error_handler.go: -------------------------------------------------------------------------------- 1 | package errorhandler 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "io" 7 | "strings" 8 | 9 | "github.com/pivotal-cf/go-pivnet/v7" 10 | "github.com/pivotal-cf/pivnet-cli/v3/printer" 11 | "github.com/pivotal-cf/pivnet-cli/v3/ui" 12 | ) 13 | 14 | var ( 15 | ErrAlreadyHandled = errors.New("error already handled") 16 | RedFunc = ui.ErrorColor.SprintFunc() 17 | ) 18 | 19 | //go:generate counterfeiter . ErrorHandler 20 | 21 | type ErrorHandler interface { 22 | HandleError(err error) error 23 | } 24 | 25 | type errorHandler struct { 26 | format string 27 | outputWriter io.Writer 28 | logWriter io.Writer 29 | } 30 | 31 | func NewErrorHandler( 32 | format string, 33 | outputWriter io.Writer, 34 | logWriter io.Writer, 35 | ) ErrorHandler { 36 | return &errorHandler{ 37 | format: format, 38 | outputWriter: outputWriter, 39 | logWriter: logWriter, 40 | } 41 | } 42 | 43 | func (h errorHandler) HandleError(err error) error { 44 | if err == nil { 45 | return nil 46 | } 47 | 48 | var message string 49 | 50 | switch err.(type) { 51 | case pivnet.ErrUnauthorized: 52 | message = fmt.Sprintf("Failed to authenticate - please provide valid API token") 53 | case pivnet.ErrNotFound: 54 | message = fmt.Sprintf("Pivnet error: %s", err.Error()) 55 | case pivnet.ErrPivnetOther: 56 | e := err.(pivnet.ErrPivnetOther) 57 | 58 | var errorMessages []string 59 | for _, pivErr := range e.Errors { 60 | errorMessages = append(errorMessages, fmt.Sprintln("- ", pivErr)) 61 | } 62 | 63 | message = fmt.Sprintf( 64 | "Pivnet returned %d - %s.%s%s", 65 | e.ResponseCode, 66 | e.Message, 67 | fmt.Sprintln(), 68 | strings.Join(errorMessages, ""), 69 | ) 70 | default: 71 | message = err.Error() 72 | } 73 | 74 | coloredMessage := fmt.Sprintf(RedFunc(message)) 75 | 76 | switch h.format { 77 | case printer.PrintAsJSON: 78 | _ = h.printLogln(coloredMessage) 79 | 80 | return ErrAlreadyHandled 81 | 82 | case printer.PrintAsYAML: 83 | _ = h.printLogln(coloredMessage) 84 | 85 | return ErrAlreadyHandled 86 | 87 | default: 88 | h.println(coloredMessage) 89 | return ErrAlreadyHandled 90 | } 91 | } 92 | 93 | func (h errorHandler) println(message string) error { 94 | _, err := h.outputWriter.Write([]byte(fmt.Sprintln(message))) 95 | return err 96 | } 97 | 98 | func (h errorHandler) printLogln(message string) error { 99 | _, err := h.logWriter.Write([]byte(fmt.Sprintln(message))) 100 | return err 101 | } 102 | -------------------------------------------------------------------------------- /errorhandler/init_test.go: -------------------------------------------------------------------------------- 1 | package errorhandler_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/onsi/ginkgo" 7 | . "github.com/onsi/gomega" 8 | ) 9 | 10 | const () 11 | 12 | func TestErrors(t *testing.T) { 13 | RegisterFailHandler(Fail) 14 | RunSpecs(t, "Errors Suite") 15 | } 16 | -------------------------------------------------------------------------------- /filter/filter.go: -------------------------------------------------------------------------------- 1 | package filter 2 | 3 | import ( 4 | "path/filepath" 5 | "regexp" 6 | "strings" 7 | 8 | pivnet "github.com/pivotal-cf/go-pivnet/v7" 9 | "github.com/pivotal-cf/go-pivnet/v7/logger" 10 | ) 11 | 12 | type Filter struct { 13 | l logger.Logger 14 | } 15 | 16 | func NewFilter(l logger.Logger) *Filter { 17 | return &Filter{ 18 | l: l, 19 | } 20 | } 21 | 22 | // ReleasesByVersion returns all releases that match the provided version regex 23 | func (f Filter) ReleasesByVersion(releases []pivnet.Release, version string) ([]pivnet.Release, error) { 24 | filteredReleases := make([]pivnet.Release, 0) 25 | 26 | for _, release := range releases { 27 | match, err := regexp.MatchString(version, release.Version) 28 | if err != nil { 29 | return nil, err 30 | } 31 | 32 | if match { 33 | filteredReleases = append(filteredReleases, release) 34 | } 35 | } 36 | 37 | return filteredReleases, nil 38 | } 39 | 40 | func (f Filter) ProductFileKeysByGlobs( 41 | productFiles []pivnet.ProductFile, 42 | globs []string, 43 | ) ([]pivnet.ProductFile, error) { 44 | f.l.Debug("filter.ProductFilesKeysByGlobs", logger.Data{"globs": globs}) 45 | 46 | filtered := []pivnet.ProductFile{} 47 | for _, p := range productFiles { 48 | parts := strings.Split(p.AWSObjectKey, "/") 49 | fileName := parts[len(parts)-1] 50 | 51 | for _, pattern := range globs { 52 | matched, err := filepath.Match(pattern, fileName) 53 | if err != nil { 54 | return nil, err 55 | } 56 | 57 | if matched { 58 | filtered = append(filtered, p) 59 | } 60 | } 61 | } 62 | 63 | return filtered, nil 64 | } 65 | -------------------------------------------------------------------------------- /filter/filter_suite_test.go: -------------------------------------------------------------------------------- 1 | package filter_test 2 | 3 | import ( 4 | . "github.com/onsi/ginkgo" 5 | . "github.com/onsi/gomega" 6 | 7 | "testing" 8 | ) 9 | 10 | func TestFilter(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "Filter Suite") 13 | } 14 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/pivotal-cf/pivnet-cli/v3 2 | 3 | require ( 4 | github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect 5 | github.com/fatih/color v1.13.0 6 | github.com/golang/protobuf v1.3.1 // indirect 7 | github.com/jessevdk/go-flags v1.4.0 8 | github.com/mattn/go-colorable v0.1.12 // indirect 9 | github.com/mattn/go-runewidth v0.0.8 // indirect 10 | github.com/olekukonko/tablewriter v0.0.4 11 | github.com/onsi/ginkgo v1.8.0 12 | github.com/onsi/gomega v1.9.0 13 | github.com/pivotal-cf/go-pivnet/v7 v7.0.1 14 | github.com/robdimsdale/sanitizer v0.0.0-20160522134901-ab2334cb7539 15 | github.com/shirou/gopsutil v3.21.11+incompatible // indirect 16 | github.com/yusufpapurcu/wmi v1.2.2 // indirect 17 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect 18 | golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68 // indirect 19 | gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect 20 | gopkg.in/yaml.v2 v2.2.8 21 | ) 22 | 23 | go 1.13 24 | -------------------------------------------------------------------------------- /gp/init_test.go: -------------------------------------------------------------------------------- 1 | package gp_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/onsi/ginkgo" 7 | . "github.com/onsi/gomega" 8 | ) 9 | 10 | const () 11 | 12 | func TestErrors(t *testing.T) { 13 | RegisterFailHandler(Fail) 14 | RunSpecs(t, "GP Suite") 15 | } 16 | -------------------------------------------------------------------------------- /hostwarning/host_warning.go: -------------------------------------------------------------------------------- 1 | package hostwarning 2 | 3 | import "fmt" 4 | 5 | type HostWarning struct { 6 | host string 7 | } 8 | 9 | func NewHostWarning(host string) *HostWarning { 10 | return &HostWarning{ 11 | host: host, 12 | } 13 | } 14 | 15 | func (hw HostWarning) Warn() string { 16 | if hw.host != "https://network.tanzu.vmware.com" && hw.host != "" { 17 | return fmt.Sprintf( "\nWarning: You are currently targeting %s\n", hw.host) 18 | } 19 | return "" 20 | } 21 | -------------------------------------------------------------------------------- /hostwarning/host_warning_suit_test.go: -------------------------------------------------------------------------------- 1 | package hostwarning_test 2 | 3 | import ( 4 | . "github.com/onsi/ginkgo" 5 | . "github.com/onsi/gomega" 6 | "testing" 7 | ) 8 | 9 | func TestFilter(t *testing.T) { 10 | RegisterFailHandler(Fail) 11 | RunSpecs(t, "Hostwarning Suite") 12 | } 13 | -------------------------------------------------------------------------------- /hostwarning/host_warning_test.go: -------------------------------------------------------------------------------- 1 | package hostwarning_test 2 | 3 | import ( 4 | "github.com/pivotal-cf/pivnet-cli/v3/hostwarning" 5 | 6 | . "github.com/onsi/ginkgo" 7 | . "github.com/onsi/gomega" 8 | ) 9 | 10 | var _ = Describe("Host Warning", func() { 11 | 12 | var ( 13 | hw *hostwarning.HostWarning 14 | host string 15 | ) 16 | 17 | JustBeforeEach(func() { 18 | hw = hostwarning.NewHostWarning(host) 19 | }) 20 | 21 | Describe("Warn", func() { 22 | 23 | Context("host is NOT production", func() { 24 | BeforeEach(func() { 25 | host = "http://localhost:3000" 26 | }) 27 | It("returns a warning", func() { 28 | Expect(hw.Warn()).To(ContainSubstring("Warning: You are currently targeting http://localhost:3000")) 29 | }) 30 | }) 31 | 32 | Context("host is production", func() { 33 | BeforeEach(func() { 34 | host = "https://network.tanzu.vmware.com" 35 | }) 36 | It("does not return a warning", func() { 37 | Expect(hw.Warn()).To(Equal("")) 38 | }) 39 | }) 40 | 41 | Context("host is empty", func() { 42 | BeforeEach(func() { 43 | host = "" 44 | }) 45 | It("does not return a warning", func() { 46 | Expect(hw.Warn()).To(Equal("")) 47 | }) 48 | }) 49 | }) 50 | }) 51 | -------------------------------------------------------------------------------- /init_test.go: -------------------------------------------------------------------------------- 1 | package main_test 2 | 3 | import ( 4 | "time" 5 | 6 | . "github.com/onsi/ginkgo" 7 | . "github.com/onsi/gomega" 8 | "github.com/onsi/gomega/gexec" 9 | 10 | "testing" 11 | ) 12 | 13 | const ( 14 | executableTimeout = 5 * time.Second 15 | ) 16 | 17 | var ( 18 | pivnetBinPath string 19 | ) 20 | 21 | func TestCLI(t *testing.T) { 22 | RegisterFailHandler(Fail) 23 | RunSpecs(t, "CLI Executable Suite") 24 | } 25 | 26 | var _ = BeforeSuite(func() { 27 | By("Compiling binary") 28 | var err error 29 | pivnetBinPath, err = gexec.Build("github.com/pivotal-cf/pivnet-cli/v3", "-race", "--tags", "forceposix", "-ldflags", "-X main.buildVersion=0.0.0") 30 | Expect(err).ShouldNot(HaveOccurred()) 31 | }) 32 | 33 | var _ = AfterSuite(func() { 34 | gexec.CleanupBuildArtifacts() 35 | }) 36 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/pivotal-cf/pivnet-cli/v3/rc" 6 | "github.com/pivotal-cf/pivnet-cli/v3/rc/filesystem" 7 | "os" 8 | 9 | "github.com/jessevdk/go-flags" 10 | "github.com/pivotal-cf/pivnet-cli/v3/commands" 11 | "github.com/pivotal-cf/pivnet-cli/v3/errorhandler" 12 | "github.com/pivotal-cf/pivnet-cli/v3/version" 13 | "github.com/pivotal-cf/pivnet-cli/v3/hostwarning" 14 | ) 15 | 16 | var ( 17 | // buildVersion is deliberately left uninitialized so it can be set at compile-time 18 | buildVersion string 19 | ) 20 | 21 | func main() { 22 | if buildVersion == "" { 23 | version.Version = "dev" 24 | } else { 25 | version.Version = buildVersion 26 | } 27 | 28 | parser := flags.NewParser(&commands.Pivnet, flags.HelpFlag) 29 | 30 | if len(os.Args) > 1 && os.Args[1] == "manpage" { 31 | parser.WriteManPage(os.Stdout) 32 | return 33 | } 34 | 35 | _, err := parser.Parse() 36 | if err != nil { 37 | if err == commands.ErrShowHelpMessage { 38 | helpParser := flags.NewParser(&commands.Pivnet, flags.HelpFlag) 39 | helpParser.NamespaceDelimiter = "-" 40 | _, _ = helpParser.ParseArgs([]string{"-h"}) 41 | helpParser.WriteHelp(os.Stdout) 42 | os.Exit(0) 43 | } 44 | 45 | // Do not consider the built-in help an error 46 | if e, ok := err.(*flags.Error); ok { 47 | if e.Type == flags.ErrHelp { 48 | fmt.Fprintln(os.Stdout, err.Error()) 49 | os.Exit(0) 50 | } 51 | } 52 | 53 | if err == errorhandler.ErrAlreadyHandled { 54 | os.Exit(1) 55 | } 56 | 57 | coloredMessage := fmt.Sprintf(errorhandler.RedFunc(err.Error())) 58 | fmt.Fprintln(os.Stderr, coloredMessage) 59 | os.Exit(1) 60 | } else { 61 | pivnetClient := commands.NewPivnetClient() 62 | client := commands.NewPivnetVersionsClient(pivnetClient) 63 | result := client.Warn(version.Version) 64 | if result != "" { 65 | fmt.Fprintf(os.Stderr, "\n%s\n", result) 66 | } 67 | 68 | rcFileReadWriter := filesystem.NewPivnetRCReadWriter(commands.Pivnet.ConfigFile) 69 | rch := rc.NewRCHandler(rcFileReadWriter) 70 | if commands.Pivnet.Profile != nil { 71 | profile, err := rch.ProfileForName(commands.Pivnet.Profile.Name) 72 | if err == nil && profile != nil { 73 | fmt.Fprint(os.Stderr, hostwarning.NewHostWarning(profile.Host).Warn()) 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /printer/init_test.go: -------------------------------------------------------------------------------- 1 | package printer_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/onsi/ginkgo" 7 | . "github.com/onsi/gomega" 8 | ) 9 | 10 | func TestPrinter(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "Printer Suite") 13 | } 14 | -------------------------------------------------------------------------------- /printer/printer.go: -------------------------------------------------------------------------------- 1 | package printer 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io" 7 | 8 | "gopkg.in/yaml.v2" 9 | ) 10 | 11 | const ( 12 | PrintAsTable = "table" 13 | PrintAsJSON = "json" 14 | PrintAsYAML = "yaml" 15 | ) 16 | 17 | //go:generate counterfeiter . Printer 18 | 19 | type Printer interface { 20 | PrintYAML(interface{}) error 21 | PrintJSON(interface{}) error 22 | Println(message string) error 23 | } 24 | 25 | type printer struct { 26 | outputWriter io.Writer 27 | } 28 | 29 | func NewPrinter(outputWriter io.Writer) Printer { 30 | return &printer{ 31 | outputWriter: outputWriter, 32 | } 33 | } 34 | 35 | func (p printer) PrintYAML(object interface{}) (err error) { 36 | // We have to do the recovery ourselves here because go-yaml panics 37 | // when it fails to marshal, unlike JSON which returns an error. 38 | // This logic is heavily inspired by the equivalent in the 39 | // json package in the standard library. 40 | defer func() { 41 | if r := recover(); r != nil { 42 | if rString, ok := r.(string); ok { 43 | err = fmt.Errorf(rString) 44 | return 45 | } 46 | panic(r) 47 | } 48 | }() 49 | 50 | b, err := yaml.Marshal(object) 51 | if err != nil { 52 | return err 53 | } 54 | 55 | output := fmt.Sprintf("---\n%s\n", string(b)) 56 | _, err = p.outputWriter.Write([]byte(output)) 57 | return err 58 | } 59 | 60 | func (p printer) PrintJSON(object interface{}) error { 61 | b, err := json.Marshal(object) 62 | if err != nil { 63 | return err 64 | } 65 | 66 | _, err = p.outputWriter.Write(b) 67 | return err 68 | } 69 | 70 | func (p printer) Println(message string) error { 71 | _, err := p.outputWriter.Write([]byte(fmt.Sprintln(message))) 72 | return err 73 | } 74 | -------------------------------------------------------------------------------- /printer/printer_test.go: -------------------------------------------------------------------------------- 1 | package printer_test 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | 7 | . "github.com/onsi/ginkgo" 8 | . "github.com/onsi/gomega" 9 | "github.com/pivotal-cf/pivnet-cli/v3/printer" 10 | ) 11 | 12 | var _ = Describe("Printer", func() { 13 | var ( 14 | p printer.Printer 15 | 16 | outputWriter *bytes.Buffer 17 | ) 18 | 19 | BeforeEach(func() { 20 | outputWriter = &bytes.Buffer{} 21 | 22 | p = printer.NewPrinter(outputWriter) 23 | }) 24 | 25 | Describe("Println", func() { 26 | It("Prints a line", func() { 27 | err := p.Println("some message") 28 | 29 | Expect(err).NotTo(HaveOccurred()) 30 | 31 | Expect(outputWriter.String()).To(Equal("some message\n")) 32 | }) 33 | 34 | Context("when writing fails", func() { 35 | BeforeEach(func() { 36 | writer := errWriter{} 37 | p = printer.NewPrinter(writer) 38 | }) 39 | 40 | It("returns an error", func() { 41 | err := p.Println("") 42 | 43 | Expect(err).To(HaveOccurred()) 44 | }) 45 | }) 46 | }) 47 | 48 | Describe("PrintJSON", func() { 49 | It("Prints object as JSON", func() { 50 | object := map[string]interface{}{ 51 | "bar": 1234, 52 | "foo": "foo val", 53 | } 54 | err := p.PrintJSON(object) 55 | 56 | Expect(err).NotTo(HaveOccurred()) 57 | 58 | expectedString := `{ 59 | "foo": "foo val", 60 | "bar": 1234 61 | } 62 | ` 63 | 64 | Expect(outputWriter.String()).To(MatchJSON(expectedString)) 65 | }) 66 | 67 | Context("when marshalling the object fails", func() { 68 | It("returns an error", func() { 69 | object := map[string]interface{}{ 70 | "foo": make(chan string), 71 | } 72 | err := p.PrintJSON(object) 73 | 74 | Expect(err).To(HaveOccurred()) 75 | }) 76 | }) 77 | 78 | Context("when writing fails", func() { 79 | BeforeEach(func() { 80 | writer := errWriter{} 81 | p = printer.NewPrinter(writer) 82 | }) 83 | 84 | It("returns an error", func() { 85 | err := p.PrintJSON(struct{}{}) 86 | 87 | Expect(err).To(HaveOccurred()) 88 | }) 89 | }) 90 | }) 91 | 92 | Describe("PrintYAML", func() { 93 | It("Prints object as YAML", func() { 94 | object := map[string]interface{}{ 95 | "bar": 1234, 96 | "foo": "foo val", 97 | } 98 | err := p.PrintYAML(object) 99 | 100 | Expect(err).NotTo(HaveOccurred()) 101 | 102 | expectedString := `--- 103 | foo: "foo val" 104 | bar: 1234 105 | ` 106 | 107 | Expect(outputWriter.String()).To(MatchYAML(expectedString)) 108 | }) 109 | 110 | Context("when marshalling the object fails", func() { 111 | It("returns an error", func() { 112 | object := map[string]interface{}{ 113 | "foo": make(chan string), 114 | } 115 | err := p.PrintYAML(object) 116 | 117 | Expect(err).To(HaveOccurred()) 118 | }) 119 | }) 120 | 121 | Context("when writing fails", func() { 122 | BeforeEach(func() { 123 | writer := errWriter{} 124 | p = printer.NewPrinter(writer) 125 | }) 126 | 127 | It("returns an error", func() { 128 | err := p.PrintYAML(struct{}{}) 129 | 130 | Expect(err).To(HaveOccurred()) 131 | }) 132 | }) 133 | }) 134 | }) 135 | 136 | type errWriter struct { 137 | } 138 | 139 | func (w errWriter) Write([]byte) (int, error) { 140 | return 0, fmt.Errorf("Error writer erroring out") 141 | } 142 | -------------------------------------------------------------------------------- /rc/filesystem/filesystem.go: -------------------------------------------------------------------------------- 1 | package filesystem 2 | 3 | import ( 4 | "io/ioutil" 5 | "os" 6 | ) 7 | 8 | type PivnetRCReadWriter struct { 9 | configFilepath string 10 | } 11 | 12 | func NewPivnetRCReadWriter(configFilepath string) *PivnetRCReadWriter { 13 | return &PivnetRCReadWriter{ 14 | configFilepath: configFilepath, 15 | } 16 | } 17 | 18 | // loadPivnetRC does not return an error if the file does not exist 19 | // but will return an error for other reasons e.g. the file cannot be read. 20 | func (h *PivnetRCReadWriter) ReadFromFile() ([]byte, error) { 21 | _, err := os.Stat(h.configFilepath) 22 | if err != nil { 23 | if os.IsNotExist(err) { 24 | return nil, nil 25 | } 26 | return nil, err 27 | } 28 | 29 | pivnetRCBytes, err := ioutil.ReadFile(h.configFilepath) 30 | if err != nil { 31 | return nil, err 32 | } 33 | 34 | return pivnetRCBytes, nil 35 | } 36 | 37 | const ( 38 | fileModeUserReadWrite = 0600 39 | ) 40 | 41 | type PivnetRCWriter struct { 42 | configFilepath string 43 | } 44 | 45 | func (h *PivnetRCReadWriter) WriteToFile(contents []byte) error { 46 | err := ioutil.WriteFile(h.configFilepath, contents, fileModeUserReadWrite) 47 | if err != nil { 48 | return err 49 | } 50 | 51 | err = os.Chmod(h.configFilepath, fileModeUserReadWrite) 52 | if err != nil { 53 | return err 54 | } 55 | 56 | return nil 57 | } 58 | -------------------------------------------------------------------------------- /rc/filesystem/filesystem_test.go: -------------------------------------------------------------------------------- 1 | package filesystem_test 2 | 3 | import ( 4 | "io/ioutil" 5 | "os" 6 | "path/filepath" 7 | 8 | . "github.com/onsi/ginkgo" 9 | . "github.com/onsi/gomega" 10 | "github.com/pivotal-cf/pivnet-cli/v3/rc/filesystem" 11 | ) 12 | 13 | var _ = Describe("PivnetRCReadWriter", func() { 14 | var ( 15 | rcReadWriter *filesystem.PivnetRCReadWriter 16 | 17 | tempDir string 18 | configFilepath string 19 | ) 20 | 21 | BeforeEach(func() { 22 | var err error 23 | tempDir, err = ioutil.TempDir("", "") 24 | Expect(err).NotTo(HaveOccurred()) 25 | 26 | configFilepath = filepath.Join(tempDir, ".pivnetrc") 27 | 28 | rcReadWriter = filesystem.NewPivnetRCReadWriter(configFilepath) 29 | }) 30 | 31 | AfterEach(func() { 32 | err := os.RemoveAll(tempDir) 33 | Expect(err).NotTo(HaveOccurred()) 34 | }) 35 | 36 | Describe("ReadFromFile", func() { 37 | var ( 38 | contents []byte 39 | ) 40 | 41 | BeforeEach(func() { 42 | contents = []byte("some contents") 43 | 44 | err := ioutil.WriteFile(configFilepath, contents, os.ModePerm) 45 | Expect(err).NotTo(HaveOccurred()) 46 | }) 47 | 48 | Describe("ReadFromFile", func() { 49 | It("reads from file", func() { 50 | b, err := rcReadWriter.ReadFromFile() 51 | Expect(err).NotTo(HaveOccurred()) 52 | 53 | Expect(b).To(Equal(contents)) 54 | }) 55 | 56 | Context("when profile file does not exist", func() { 57 | It("returns empty profile without error", func() { 58 | otherFilepath := filepath.Join(tempDir, "other-file") 59 | rcReadWriter = filesystem.NewPivnetRCReadWriter(otherFilepath) 60 | 61 | b, err := rcReadWriter.ReadFromFile() 62 | 63 | Expect(err).NotTo(HaveOccurred()) 64 | Expect(b).To(BeNil()) 65 | }) 66 | }) 67 | }) 68 | }) 69 | 70 | Describe("Write", func() { 71 | var ( 72 | contents []byte 73 | 74 | existingContents []byte 75 | ) 76 | 77 | BeforeEach(func() { 78 | contents = []byte("some contents") 79 | 80 | existingContents = []byte("some-existing-contents") 81 | }) 82 | 83 | JustBeforeEach(func() { 84 | err := ioutil.WriteFile(configFilepath, existingContents, os.ModePerm) 85 | Expect(err).NotTo(HaveOccurred()) 86 | }) 87 | 88 | Describe("WriteToFile", func() { 89 | It("creates new file", func() { 90 | otherFilepath := filepath.Join(tempDir, "other-file") 91 | rcReadWriter = filesystem.NewPivnetRCReadWriter(otherFilepath) 92 | 93 | err := rcReadWriter.WriteToFile(contents) 94 | Expect(err).NotTo(HaveOccurred()) 95 | 96 | b, err := ioutil.ReadFile(otherFilepath) 97 | Expect(err).NotTo(HaveOccurred()) 98 | 99 | Expect(b).To(Equal(contents)) 100 | }) 101 | 102 | It("overwrites existing file", func() { 103 | err := rcReadWriter.WriteToFile(contents) 104 | Expect(err).NotTo(HaveOccurred()) 105 | 106 | b, err := ioutil.ReadFile(configFilepath) 107 | Expect(err).NotTo(HaveOccurred()) 108 | 109 | Expect(b).To(Equal(contents)) 110 | }) 111 | }) 112 | }) 113 | }) 114 | -------------------------------------------------------------------------------- /rc/filesystem/filesystem_unix_test.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package filesystem_test 4 | 5 | import ( 6 | "io/ioutil" 7 | "os" 8 | "path/filepath" 9 | 10 | . "github.com/onsi/ginkgo" 11 | . "github.com/onsi/gomega" 12 | "github.com/pivotal-cf/pivnet-cli/v3/rc/filesystem" 13 | ) 14 | 15 | var _ = Describe("PivnetRCReadWriter", func() { 16 | var ( 17 | rcReadWriter *filesystem.PivnetRCReadWriter 18 | 19 | tempDir string 20 | configFilepath string 21 | ) 22 | 23 | BeforeEach(func() { 24 | var err error 25 | tempDir, err = ioutil.TempDir("", "") 26 | Expect(err).NotTo(HaveOccurred()) 27 | 28 | configFilepath = filepath.Join(tempDir, ".pivnetrc") 29 | 30 | rcReadWriter = filesystem.NewPivnetRCReadWriter(configFilepath) 31 | }) 32 | 33 | AfterEach(func() { 34 | err := os.RemoveAll(tempDir) 35 | Expect(err).NotTo(HaveOccurred()) 36 | }) 37 | 38 | Describe("ReadFromFile", func() { 39 | var ( 40 | contents []byte 41 | ) 42 | 43 | BeforeEach(func() { 44 | contents = []byte("some contents") 45 | 46 | err := ioutil.WriteFile(configFilepath, contents, os.ModePerm) 47 | Expect(err).NotTo(HaveOccurred()) 48 | }) 49 | 50 | Describe("ReadFromFile", func() { 51 | Context("when profile file cannot be read", func() { 52 | JustBeforeEach(func() { 53 | err := os.Chmod(configFilepath, 0) 54 | Expect(err).NotTo(HaveOccurred()) 55 | }) 56 | 57 | It("returns an error", func() { 58 | _, err := rcReadWriter.ReadFromFile() 59 | 60 | Expect(err).To(HaveOccurred()) 61 | }) 62 | }) 63 | }) 64 | }) 65 | 66 | Describe("Write", func() { 67 | var ( 68 | contents []byte 69 | 70 | existingContents []byte 71 | ) 72 | 73 | BeforeEach(func() { 74 | contents = []byte("some contents") 75 | 76 | existingContents = []byte("some-existing-contents") 77 | }) 78 | 79 | JustBeforeEach(func() { 80 | err := ioutil.WriteFile(configFilepath, existingContents, os.ModePerm) 81 | Expect(err).NotTo(HaveOccurred()) 82 | }) 83 | 84 | Describe("WriteToFile", func() { 85 | It("writes file with user-only read/write (i.e. 0600) permissions", func() { 86 | err := rcReadWriter.WriteToFile(contents) 87 | Expect(err).NotTo(HaveOccurred()) 88 | 89 | info, err := os.Stat(configFilepath) 90 | Expect(err).NotTo(HaveOccurred()) 91 | 92 | Expect(info.Mode()).To(Equal(os.FileMode(0600))) 93 | }) 94 | }) 95 | }) 96 | }) 97 | 98 | -------------------------------------------------------------------------------- /rc/filesystem/init_test.go: -------------------------------------------------------------------------------- 1 | package filesystem_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/onsi/ginkgo" 7 | . "github.com/onsi/gomega" 8 | ) 9 | 10 | func TestRCFilesystem(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "RC Filesystem Suite") 13 | } 14 | -------------------------------------------------------------------------------- /rc/init_test.go: -------------------------------------------------------------------------------- 1 | package rc_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/onsi/ginkgo" 7 | . "github.com/onsi/gomega" 8 | ) 9 | 10 | func TestRC(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "RC Suite") 13 | } 14 | -------------------------------------------------------------------------------- /rc/profile.go: -------------------------------------------------------------------------------- 1 | package rc 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type PivnetProfile struct { 8 | Name string `yaml:"name"` 9 | APIToken string `yaml:"api_token"` 10 | Host string `yaml:"host"` 11 | AccessToken string `yaml:"access_token"` 12 | AccessTokenExpiry int64 `yaml:"access_token_expiry"` 13 | } 14 | 15 | func (p *PivnetProfile) Validate() error { 16 | if p.Name == "" { 17 | return fmt.Errorf("Name is empty") 18 | } 19 | 20 | if p.APIToken == "" { 21 | return fmt.Errorf("API token is empty") 22 | } 23 | 24 | if p.Host == "" { 25 | return fmt.Errorf("Host is empty") 26 | } 27 | 28 | return nil 29 | } 30 | -------------------------------------------------------------------------------- /rc/profile_test.go: -------------------------------------------------------------------------------- 1 | package rc_test 2 | 3 | import ( 4 | . "github.com/onsi/ginkgo" 5 | . "github.com/onsi/gomega" 6 | "github.com/pivotal-cf/pivnet-cli/v3/rc" 7 | ) 8 | 9 | var _ = Describe("PivnetProfile", func() { 10 | var ( 11 | profile rc.PivnetProfile 12 | ) 13 | 14 | BeforeEach(func() { 15 | profile = rc.PivnetProfile{ 16 | Name: "some-name", 17 | APIToken: "some-api-token", 18 | Host: "some-host", 19 | } 20 | }) 21 | 22 | Describe("Validate", func() { 23 | It("returns nil when validation is successful", func() { 24 | err := profile.Validate() 25 | Expect(err).NotTo(HaveOccurred()) 26 | }) 27 | 28 | Context("when name is empty", func() { 29 | BeforeEach(func() { 30 | profile.Name = "" 31 | }) 32 | 33 | It("returns an error", func() { 34 | err := profile.Validate() 35 | Expect(err).To(HaveOccurred()) 36 | 37 | Expect(err.Error()).To(ContainSubstring("Name")) 38 | }) 39 | }) 40 | 41 | Context("when API token is empty", func() { 42 | BeforeEach(func() { 43 | profile.APIToken = "" 44 | }) 45 | 46 | It("returns an error", func() { 47 | err := profile.Validate() 48 | Expect(err).To(HaveOccurred()) 49 | 50 | Expect(err.Error()).To(ContainSubstring("API token")) 51 | }) 52 | }) 53 | 54 | Context("when host is empty", func() { 55 | BeforeEach(func() { 56 | profile.Host = "" 57 | }) 58 | 59 | It("returns an error", func() { 60 | err := profile.Validate() 61 | Expect(err).To(HaveOccurred()) 62 | 63 | Expect(err.Error()).To(ContainSubstring("Host")) 64 | }) 65 | }) 66 | }) 67 | }) 68 | -------------------------------------------------------------------------------- /semver/init_test.go: -------------------------------------------------------------------------------- 1 | package semver_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/onsi/ginkgo" 7 | . "github.com/onsi/gomega" 8 | ) 9 | 10 | const () 11 | 12 | func TestSemver(t *testing.T) { 13 | RegisterFailHandler(Fail) 14 | RunSpecs(t, "Semver Suite") 15 | } 16 | -------------------------------------------------------------------------------- /semver/semver.go: -------------------------------------------------------------------------------- 1 | package semver 2 | 3 | import ( 4 | "regexp" 5 | "strconv" 6 | "strings" 7 | ) 8 | 9 | func Compare(s1, s2 string) (result int, err error) { 10 | if s1 == s2 { 11 | return 0, nil 12 | } 13 | 14 | if len(s1) == 0 && len(s2) > 0 { 15 | return -1, nil 16 | } 17 | 18 | if len(s1) > 0 && len(s2) == 0 { 19 | return 1, nil 20 | } 21 | 22 | s1Segments, s2Segments, err := parseArguments(s1, s2) 23 | if err != nil { 24 | return 0, err 25 | } 26 | 27 | semverLength := min(len(s1Segments), len(s2Segments)) 28 | for i := 0; i < semverLength; i++ { 29 | v1, err := strconv.Atoi(s1Segments[i]) 30 | if err != nil { 31 | return 0, err 32 | } 33 | 34 | v2, err := strconv.Atoi(s2Segments[i]) 35 | if err != nil { 36 | return 0, err 37 | } 38 | 39 | if v1 > v2 { 40 | return 1, nil 41 | } 42 | 43 | if v1 < v2 { 44 | return -1, nil 45 | } 46 | } 47 | 48 | return compareBySegmentLengths(s1Segments, s2Segments), nil 49 | } 50 | 51 | func min(a, b int) int { 52 | if a < b { 53 | return a 54 | } 55 | return b 56 | } 57 | 58 | func parseArguments(s1, s2 string) (s1Segments []string, s2Segments []string, err error) { 59 | l1 := findAndReplace("\\pL", s1, "") // matches all unicode letters 60 | r1 := findAndReplace("\\pL", s2, "") // matches all unicode letters 61 | l2 := findAndReplace("\\.+", l1, ".") 62 | r2 := findAndReplace("\\.+", r1, ".") 63 | return strings.Split(l2, "."), strings.Split(r2, "."), nil 64 | } 65 | 66 | func findAndReplace(pattern string, src string, replace string) string { 67 | re, _ := regexp.Compile(pattern) 68 | return re.ReplaceAllString(src, replace) 69 | } 70 | 71 | func compareBySegmentLengths(s1Segments []string, s2Segments []string) int { 72 | if len(s1Segments) > len(s2Segments) { 73 | return 1 74 | } 75 | 76 | if len(s1Segments) < len(s2Segments) { 77 | return -1 78 | } 79 | 80 | return 0 81 | } 82 | -------------------------------------------------------------------------------- /semver/semver_test.go: -------------------------------------------------------------------------------- 1 | package semver_test 2 | 3 | import ( 4 | . "github.com/onsi/ginkgo" 5 | . "github.com/onsi/ginkgo/extensions/table" 6 | . "github.com/onsi/gomega" 7 | 8 | "github.com/pivotal-cf/pivnet-cli/v3/semver" 9 | ) 10 | 11 | var _ = Describe("semantic versioning comparison", func() { 12 | DescribeTable("", func(s1, s2 string, expected int){ 13 | Expect(semver.Compare(s1, s2)).To(Equal(expected)) 14 | }, 15 | Entry("when equal", "1.2.3", "1.2.3", 0), 16 | Entry("when greater", "1.2.4", "1.2.3", 1), 17 | Entry("when smaller", "1.2.2", "1.2.3", -1), 18 | Entry("when both empty", "", "", 0), 19 | Entry("when left side empty", "", "1.2.3", -1), 20 | Entry("when right side empty", "1.2.3", "", 1), 21 | Entry("when both zero", "0", "0", 0), 22 | Entry("when left side zero", "0", "1.2.3", -1), 23 | Entry("when right side zero", "1.2.3", "0", 1), 24 | Entry("when letters on both sides", "v1.2.3", "v1.2.3", 0), 25 | Entry("when letter on right side", "v1.2.3", "1.2.3", 0), 26 | Entry("when letter on left side", "1.2.3", "v1.2.3", 0), 27 | Entry("when consecutive dots on the both sides", "1..2", "1..2", 0), 28 | Entry("when consecutive dots on the left side", "1..2", "1.2", 0), 29 | Entry("when consecutive dots on the right side", "1.2", "1..2", 0), 30 | ) 31 | }) 32 | -------------------------------------------------------------------------------- /ui/color.go: -------------------------------------------------------------------------------- 1 | package ui 2 | 3 | import "github.com/fatih/color" 4 | 5 | var ( 6 | ErrorColor = color.New(color.FgRed) 7 | SuccessColor = color.New(color.FgGreen) 8 | ) 9 | -------------------------------------------------------------------------------- /version/version.go: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | var ( 4 | Version string 5 | ) 6 | --------------------------------------------------------------------------------