diff --git a/Makefile b/Makefile index 6d1a2569950a7..ec22c096c652a 100644 --- a/Makefile +++ b/Makefile @@ -146,7 +146,8 @@ override LDFLAGS += \ -X ${PACKAGE}.buildDate=${BUILD_DATE} \ -X ${PACKAGE}.gitCommit=${GIT_COMMIT} \ -X ${PACKAGE}.gitTreeState=${GIT_TREE_STATE}\ - -X ${PACKAGE}.kubectlVersion=${KUBECTL_VERSION} + -X ${PACKAGE}.kubectlVersion=${KUBECTL_VERSION}\ + -X "${PACKAGE}.extraBuildInfo=${EXTRA_BUILD_INFO}" ifeq (${STATIC_BUILD}, true) override LDFLAGS += -extldflags "-static" diff --git a/Procfile b/Procfile index d8557c81ea19a..68b725ba9e920 100644 --- a/Procfile +++ b/Procfile @@ -8,5 +8,5 @@ ui: sh -c 'cd ui && ${ARGOCD_E2E_YARN_CMD:-yarn} start' git-server: test/fixture/testrepos/start-git.sh helm-registry: test/fixture/testrepos/start-helm-registry.sh dev-mounter: [[ "$ARGOCD_E2E_TEST" != "true" ]] && go run hack/dev-mounter/main.go --configmap argocd-ssh-known-hosts-cm=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} --configmap argocd-tls-certs-cm=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} --configmap argocd-gpg-keys-cm=${ARGOCD_GPG_DATA_PATH:-/tmp/argocd-local/gpg/source} -applicationset-controller: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=4 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_ASK_PASS_SOCK=/tmp/applicationset-ask-pass.sock ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-applicationset-controller $COMMAND --loglevel debug --metrics-addr localhost:12345 --probe-addr localhost:12346 --argocd-repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081}" -notification: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=4 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_BINARY_NAME=argocd-notifications $COMMAND --loglevel debug" +applicationset-controller: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=4 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-applicationset-controller $COMMAND --loglevel debug --metrics-addr localhost:12345 --probe-addr localhost:12346 --argocd-repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081}" +notification: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=4 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_BINARY_NAME=argocd-notifications $COMMAND --loglevel debug" \ No newline at end of file diff --git a/USERS.md b/USERS.md index 205d5f0194b73..03030f90d49e1 100644 --- a/USERS.md +++ b/USERS.md @@ -14,6 +14,7 @@ Currently, the following organizations are **officially** using Argo CD: 1. [Adyen](https://www.adyen.com) 1. [AirQo](https://airqo.net/) 1. [Akuity](https://akuity.io/) +1. [Albert Heijn](https://ah.nl/) 1. [Alibaba Group](https://www.alibabagroup.com/) 1. [Allianz Direct](https://www.allianzdirect.de/) 1. [Amadeus IT Group](https://amadeus.com/) @@ -195,6 +196,7 @@ Currently, the following organizations are **officially** using Argo CD: 1. [Polarpoint.io](https://polarpoint.io) 1. [PostFinance](https://github.com/postfinance) 1. [Preferred Networks](https://preferred.jp/en/) +1. [Previder BV](https://previder.nl) 1. [Productboard](https://www.productboard.com/) 1. [Prudential](https://prudential.com.sg) 1. [PUBG](https://www.pubg.com) diff --git a/applicationset/controllers/applicationset_controller.go b/applicationset/controllers/applicationset_controller.go index 3cd58d58d68a1..a5de3d49e69b1 100644 --- a/applicationset/controllers/applicationset_controller.go +++ b/applicationset/controllers/applicationset_controller.go @@ -1341,7 +1341,7 @@ func getOwnsHandlerPredicates(enableProgressiveSyncs bool) predicate.Funcs { return false } requeue := shouldRequeueApplicationSet(appOld, appNew, enableProgressiveSyncs) - log.Debugf("requeue: %t caused by application %s\n", requeue, appNew.Name) + log.Debugf("requeue: %t caused by application %s", requeue, appNew.Name) return requeue }, GenericFunc: func(e event.GenericEvent) bool { diff --git a/applicationset/controllers/requeue_after_test.go b/applicationset/controllers/requeue_after_test.go index 16983a8340fbb..7a95c4d60b738 100644 --- a/applicationset/controllers/requeue_after_test.go +++ b/applicationset/controllers/requeue_after_test.go @@ -6,9 +6,9 @@ import ( "time" "github.com/argoproj/argo-cd/v2/applicationset/generators" + "github.com/argoproj/argo-cd/v2/applicationset/services/mocks" argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" @@ -20,7 +20,7 @@ import ( ) func TestRequeueAfter(t *testing.T) { - mockServer := argoCDServiceMock{} + mockServer := &mocks.Repos{} ctx := context.Background() scheme := runtime.NewScheme() err := argov1alpha1.AddToScheme(scheme) @@ -150,30 +150,3 @@ func TestRequeueAfter(t *testing.T) { }) } } - -type argoCDServiceMock struct { - mock *mock.Mock -} - -func (a argoCDServiceMock) GetApps(ctx context.Context, repoURL string, revision string) ([]string, error) { - args := a.mock.Called(ctx, repoURL, revision) - - return args.Get(0).([]string), args.Error(1) -} - -func (a argoCDServiceMock) GetFiles(ctx context.Context, repoURL string, revision string, pattern string) (map[string][]byte, error) { - args := a.mock.Called(ctx, repoURL, revision, pattern) - - return args.Get(0).(map[string][]byte), args.Error(1) -} - -func (a argoCDServiceMock) GetFileContent(ctx context.Context, repoURL string, revision string, path string) ([]byte, error) { - args := a.mock.Called(ctx, repoURL, revision, path) - - return args.Get(0).([]byte), args.Error(1) -} - -func (a argoCDServiceMock) GetDirectories(ctx context.Context, repoURL string, revision string) ([]string, error) { - args := a.mock.Called(ctx, repoURL, revision) - return args.Get(0).([]string), args.Error(1) -} diff --git a/applicationset/generators/generator_spec_processor_test.go b/applicationset/generators/generator_spec_processor_test.go index 36a1495c02af4..8590837b2302e 100644 --- a/applicationset/generators/generator_spec_processor_test.go +++ b/applicationset/generators/generator_spec_processor_test.go @@ -4,13 +4,13 @@ import ( "context" "testing" + "github.com/argoproj/argo-cd/v2/applicationset/services/mocks" log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - testutils "github.com/argoproj/argo-cd/v2/applicationset/utils/test" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" "github.com/stretchr/testify/mock" corev1 "k8s.io/api/core/v1" @@ -150,9 +150,9 @@ func getMockClusterGenerator() Generator { } func getMockGitGenerator() Generator { - argoCDServiceMock := testutils.ArgoCDServiceMock{Mock: &mock.Mock{}} - argoCDServiceMock.Mock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything).Return([]string{"app1", "app2", "app_3", "p1/app4"}, nil) - var gitGenerator = NewGitGenerator(argoCDServiceMock) + argoCDServiceMock := mocks.Repos{} + argoCDServiceMock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything).Return([]string{"app1", "app2", "app_3", "p1/app4"}, nil) + var gitGenerator = NewGitGenerator(&argoCDServiceMock) return gitGenerator } diff --git a/applicationset/generators/git_test.go b/applicationset/generators/git_test.go index e428cfd3141e3..dadb7ec29c0b5 100644 --- a/applicationset/generators/git_test.go +++ b/applicationset/generators/git_test.go @@ -4,21 +4,14 @@ import ( "fmt" "testing" + "github.com/argoproj/argo-cd/v2/applicationset/services/mocks" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - testutils "github.com/argoproj/argo-cd/v2/applicationset/utils/test" argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" ) -// type clientSet struct { -// RepoServerServiceClient apiclient.RepoServerServiceClient -// } - -// func (c *clientSet) NewRepoServerClient() (io.Closer, apiclient.RepoServerServiceClient, error) { -// return io.NewCloser(func() error { return nil }), c.RepoServerServiceClient, nil -// } func Test_generateParamsFromGitFile(t *testing.T) { params, err := (*GitGenerator)(nil).generateParamsFromGitFile("path/dir/file_name.yaml", []byte(` @@ -244,11 +237,11 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) { t.Run(testCaseCopy.name, func(t *testing.T) { t.Parallel() - argoCDServiceMock := testutils.ArgoCDServiceMock{Mock: &mock.Mock{}} + argoCDServiceMock := mocks.Repos{} - argoCDServiceMock.Mock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError) + argoCDServiceMock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError) - var gitGenerator = NewGitGenerator(argoCDServiceMock) + var gitGenerator = NewGitGenerator(&argoCDServiceMock) applicationSetInfo := argoprojiov1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "set", @@ -274,7 +267,7 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) { assert.Equal(t, testCaseCopy.expected, got) } - argoCDServiceMock.Mock.AssertExpectations(t) + argoCDServiceMock.AssertExpectations(t) }) } } @@ -539,11 +532,11 @@ func TestGitGenerateParamsFromDirectoriesGoTemplate(t *testing.T) { t.Run(testCaseCopy.name, func(t *testing.T) { t.Parallel() - argoCDServiceMock := testutils.ArgoCDServiceMock{Mock: &mock.Mock{}} + argoCDServiceMock := mocks.Repos{} - argoCDServiceMock.Mock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError) + argoCDServiceMock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError) - var gitGenerator = NewGitGenerator(argoCDServiceMock) + var gitGenerator = NewGitGenerator(&argoCDServiceMock) applicationSetInfo := argoprojiov1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "set", @@ -570,7 +563,7 @@ func TestGitGenerateParamsFromDirectoriesGoTemplate(t *testing.T) { assert.Equal(t, testCaseCopy.expected, got) } - argoCDServiceMock.Mock.AssertExpectations(t) + argoCDServiceMock.AssertExpectations(t) }) } @@ -830,11 +823,11 @@ cluster: t.Run(testCaseCopy.name, func(t *testing.T) { t.Parallel() - argoCDServiceMock := testutils.ArgoCDServiceMock{Mock: &mock.Mock{}} - argoCDServiceMock.Mock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything). + argoCDServiceMock := mocks.Repos{} + argoCDServiceMock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(testCaseCopy.repoFileContents, testCaseCopy.repoPathsError) - var gitGenerator = NewGitGenerator(argoCDServiceMock) + var gitGenerator = NewGitGenerator(&argoCDServiceMock) applicationSetInfo := argoprojiov1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "set", @@ -860,7 +853,7 @@ cluster: assert.ElementsMatch(t, testCaseCopy.expected, got) } - argoCDServiceMock.Mock.AssertExpectations(t) + argoCDServiceMock.AssertExpectations(t) }) } } @@ -1179,11 +1172,11 @@ cluster: t.Run(testCaseCopy.name, func(t *testing.T) { t.Parallel() - argoCDServiceMock := testutils.ArgoCDServiceMock{Mock: &mock.Mock{}} - argoCDServiceMock.Mock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything). + argoCDServiceMock := mocks.Repos{} + argoCDServiceMock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(testCaseCopy.repoFileContents, testCaseCopy.repoPathsError) - var gitGenerator = NewGitGenerator(argoCDServiceMock) + var gitGenerator = NewGitGenerator(&argoCDServiceMock) applicationSetInfo := argoprojiov1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "set", @@ -1210,7 +1203,7 @@ cluster: assert.ElementsMatch(t, testCaseCopy.expected, got) } - argoCDServiceMock.Mock.AssertExpectations(t) + argoCDServiceMock.AssertExpectations(t) }) } } diff --git a/applicationset/generators/matrix_test.go b/applicationset/generators/matrix_test.go index f80c055c23c60..1053fef046e1e 100644 --- a/applicationset/generators/matrix_test.go +++ b/applicationset/generators/matrix_test.go @@ -5,6 +5,7 @@ import ( "testing" "time" + "github.com/argoproj/argo-cd/v2/applicationset/services/mocks" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -17,7 +18,6 @@ import ( "github.com/stretchr/testify/mock" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - testutils "github.com/argoproj/argo-cd/v2/applicationset/utils/test" argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" ) @@ -1052,8 +1052,8 @@ func TestGitGenerator_GenerateParams_list_x_git_matrix_generator(t *testing.T) { }, } - repoServiceMock := testutils.ArgoCDServiceMock{Mock: &mock.Mock{}} - repoServiceMock.Mock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(map[string][]byte{ + repoServiceMock := &mocks.Repos{} + repoServiceMock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(map[string][]byte{ "some/path.json": []byte("test: content"), }, nil) gitGenerator := NewGitGenerator(repoServiceMock) diff --git a/applicationset/services/mocks/Repos.go b/applicationset/services/mocks/Repos.go new file mode 100644 index 0000000000000..776b104cae284 --- /dev/null +++ b/applicationset/services/mocks/Repos.go @@ -0,0 +1,81 @@ +// Code generated by mockery v2.25.1. DO NOT EDIT. + +package mocks + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" +) + +// Repos is an autogenerated mock type for the Repos type +type Repos struct { + mock.Mock +} + +// GetDirectories provides a mock function with given fields: ctx, repoURL, revision +func (_m *Repos) GetDirectories(ctx context.Context, repoURL string, revision string) ([]string, error) { + ret := _m.Called(ctx, repoURL, revision) + + var r0 []string + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) ([]string, error)); ok { + return rf(ctx, repoURL, revision) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string) []string); ok { + r0 = rf(ctx, repoURL, revision) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { + r1 = rf(ctx, repoURL, revision) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetFiles provides a mock function with given fields: ctx, repoURL, revision, pattern +func (_m *Repos) GetFiles(ctx context.Context, repoURL string, revision string, pattern string) (map[string][]byte, error) { + ret := _m.Called(ctx, repoURL, revision, pattern) + + var r0 map[string][]byte + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, string) (map[string][]byte, error)); ok { + return rf(ctx, repoURL, revision, pattern) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string, string) map[string][]byte); ok { + r0 = rf(ctx, repoURL, revision, pattern) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(map[string][]byte) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string, string) error); ok { + r1 = rf(ctx, repoURL, revision, pattern) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +type mockConstructorTestingTNewRepos interface { + mock.TestingT + Cleanup(func()) +} + +// NewRepos creates a new instance of Repos. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewRepos(t mockConstructorTestingTNewRepos) *Repos { + mock := &Repos{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/applicationset/services/mocks/RepositoryDB.go b/applicationset/services/mocks/RepositoryDB.go new file mode 100644 index 0000000000000..9d6240d342776 --- /dev/null +++ b/applicationset/services/mocks/RepositoryDB.go @@ -0,0 +1,57 @@ +// Code generated by mockery v2.21.1. DO NOT EDIT. + +package mocks + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" + + v1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" +) + +// RepositoryDB is an autogenerated mock type for the RepositoryDB type +type RepositoryDB struct { + mock.Mock +} + +// GetRepository provides a mock function with given fields: ctx, url +func (_m *RepositoryDB) GetRepository(ctx context.Context, url string) (*v1alpha1.Repository, error) { + ret := _m.Called(ctx, url) + + var r0 *v1alpha1.Repository + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (*v1alpha1.Repository, error)); ok { + return rf(ctx, url) + } + if rf, ok := ret.Get(0).(func(context.Context, string) *v1alpha1.Repository); ok { + r0 = rf(ctx, url) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*v1alpha1.Repository) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, url) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +type mockConstructorTestingTNewRepositoryDB interface { + mock.TestingT + Cleanup(func()) +} + +// NewRepositoryDB creates a new instance of RepositoryDB. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewRepositoryDB(t mockConstructorTestingTNewRepositoryDB) *RepositoryDB { + mock := &RepositoryDB{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/applicationset/services/repo_service.go b/applicationset/services/repo_service.go index 571f497433de8..731355196283f 100644 --- a/applicationset/services/repo_service.go +++ b/applicationset/services/repo_service.go @@ -3,25 +3,26 @@ package services import ( "context" "fmt" - "os" - "path/filepath" - "strings" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "github.com/argoproj/argo-cd/v2/reposerver/apiclient" + repoapiclient "github.com/argoproj/argo-cd/v2/reposerver/apiclient" "github.com/argoproj/argo-cd/v2/util/db" "github.com/argoproj/argo-cd/v2/util/git" + "github.com/argoproj/argo-cd/v2/util/io" ) // RepositoryDB Is a lean facade for ArgoDB, -// Using a lean interface makes it more easy to test the functionality the git generator uses +// Using a lean interface makes it easier to test the functionality of the git generator type RepositoryDB interface { GetRepository(ctx context.Context, url string) (*v1alpha1.Repository, error) } type argoCDService struct { - repositoriesDB RepositoryDB - storecreds git.CredsStore - submoduleEnabled bool + repositoriesDB RepositoryDB + storecreds git.CredsStore + submoduleEnabled bool + repoServerClientSet repoapiclient.Clientset } type Repos interface { @@ -33,121 +34,61 @@ type Repos interface { GetDirectories(ctx context.Context, repoURL string, revision string) ([]string, error) } -func NewArgoCDService(db db.ArgoDB, gitCredStore git.CredsStore, submoduleEnabled bool) Repos { - +func NewArgoCDService(db db.ArgoDB, submoduleEnabled bool, repoClientset repoapiclient.Clientset) (Repos, error) { return &argoCDService{ - repositoriesDB: db.(RepositoryDB), - storecreds: gitCredStore, - submoduleEnabled: submoduleEnabled, - } + repositoriesDB: db.(RepositoryDB), + submoduleEnabled: submoduleEnabled, + repoServerClientSet: repoClientset, + }, nil } func (a *argoCDService) GetFiles(ctx context.Context, repoURL string, revision string, pattern string) (map[string][]byte, error) { repo, err := a.repositoriesDB.GetRepository(ctx, repoURL) if err != nil { - return nil, fmt.Errorf("Error in GetRepository: %w", err) + return nil, fmt.Errorf("error in GetRepository: %w", err) } - gitRepoClient, err := git.NewClient(repo.Repo, repo.GetGitCreds(a.storecreds), repo.IsInsecure(), repo.IsLFSEnabled(), repo.Proxy) - - if err != nil { - return nil, err + fileRequest := &apiclient.GitFilesRequest{ + Repo: repo, + SubmoduleEnabled: a.submoduleEnabled, + Revision: revision, + Path: pattern, } - - err = checkoutRepo(gitRepoClient, revision, a.submoduleEnabled) + closer, client, err := a.repoServerClientSet.NewRepoServerClient() if err != nil { return nil, err } + defer io.Close(closer) - paths, err := gitRepoClient.LsFiles(pattern) + fileResponse, err := client.GetGitFiles(ctx, fileRequest) if err != nil { - return nil, fmt.Errorf("Error during listing files of local repo: %w", err) - } - - res := map[string][]byte{} - for _, filePath := range paths { - bytes, err := os.ReadFile(filepath.Join(gitRepoClient.Root(), filePath)) - if err != nil { - return nil, err - } - res[filePath] = bytes + return nil, err } - - return res, nil + return fileResponse.GetMap(), nil } func (a *argoCDService) GetDirectories(ctx context.Context, repoURL string, revision string) ([]string, error) { - repo, err := a.repositoriesDB.GetRepository(ctx, repoURL) if err != nil { - return nil, fmt.Errorf("Error in GetRepository: %w", err) + return nil, fmt.Errorf("error in GetRepository: %w", err) } - gitRepoClient, err := git.NewClient(repo.Repo, repo.GetGitCreds(a.storecreds), repo.IsInsecure(), repo.IsLFSEnabled(), repo.Proxy) - if err != nil { - return nil, fmt.Errorf("error creating a new git client: %w", err) + dirRequest := &apiclient.GitDirectoriesRequest{ + Repo: repo, + SubmoduleEnabled: a.submoduleEnabled, + Revision: revision, } - err = checkoutRepo(gitRepoClient, revision, a.submoduleEnabled) + closer, client, err := a.repoServerClientSet.NewRepoServerClient() if err != nil { - return nil, fmt.Errorf("error while checking out repo: %w", err) - } - - filteredPaths := []string{} - - repoRoot := gitRepoClient.Root() - - if err := filepath.Walk(repoRoot, func(path string, info os.FileInfo, fnErr error) error { - if fnErr != nil { - return fmt.Errorf("error walking the file tree: %w", fnErr) - } - if !info.IsDir() { // Skip files: directories only - return nil - } - - fname := info.Name() - if strings.HasPrefix(fname, ".") { // Skip all folders starts with "." - return filepath.SkipDir - } - - relativePath, err := filepath.Rel(repoRoot, path) - if err != nil { - return fmt.Errorf("error constructing relative repo path: %w", err) - } - - if relativePath == "." { // Exclude '.' from results - return nil - } - - filteredPaths = append(filteredPaths, relativePath) - - return nil - }); err != nil { return nil, err } + defer io.Close(closer) - return filteredPaths, nil - -} - -func checkoutRepo(gitRepoClient git.Client, revision string, submoduleEnabled bool) error { - err := gitRepoClient.Init() - if err != nil { - return fmt.Errorf("Error during initializing repo: %w", err) - } - - err = gitRepoClient.Fetch(revision) + dirResponse, err := client.GetGitDirectories(ctx, dirRequest) if err != nil { - return fmt.Errorf("Error during fetching repo: %w", err) + return nil, err } + return dirResponse.GetPaths(), nil - commitSHA, err := gitRepoClient.LsRemote(revision) - if err != nil { - return fmt.Errorf("Error during fetching commitSHA: %w", err) - } - err = gitRepoClient.Checkout(commitSHA, submoduleEnabled) - if err != nil { - return fmt.Errorf("Error during repo checkout: %w", err) - } - return nil } diff --git a/applicationset/services/repo_service_test.go b/applicationset/services/repo_service_test.go index bc0238b2eacc7..7df653a6e04ea 100644 --- a/applicationset/services/repo_service_test.go +++ b/applicationset/services/repo_service_test.go @@ -3,231 +3,189 @@ package services import ( "context" "fmt" - "sort" "testing" + "github.com/argoproj/argo-cd/v2/applicationset/services/mocks" + "github.com/argoproj/argo-cd/v2/reposerver/apiclient" + repo_mocks "github.com/argoproj/argo-cd/v2/reposerver/apiclient/mocks" + db_mocks "github.com/argoproj/argo-cd/v2/util/db/mocks" + "github.com/argoproj/argo-cd/v2/util/git" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" ) -type ArgocdRepositoryMock struct { - mock *mock.Mock -} - -func (a ArgocdRepositoryMock) GetRepository(ctx context.Context, url string) (*v1alpha1.Repository, error) { - args := a.mock.Called(ctx, url) - - return args.Get(0).(*v1alpha1.Repository), args.Error(1) - -} - func TestGetDirectories(t *testing.T) { - // Hardcode a specific revision to changes to argocd-example-apps from regressing this test: - // Author: Alexander Matyushentsev - // Date: Sun Jan 31 09:54:53 2021 -0800 - // chore: downgrade kustomize guestbook image tag (#73) - exampleRepoRevision := "08f72e2a309beab929d9fd14626071b1a61a47f9" - - for _, c := range []struct { - name string - repoURL string - revision string - repoRes *v1alpha1.Repository - repoErr error - expected []string - expectedError error + type fields struct { + repositoriesDBFuncs []func(*mocks.RepositoryDB) + storecreds git.CredsStore + submoduleEnabled bool + repoServerClientFuncs []func(*repo_mocks.RepoServerServiceClient) + } + type args struct { + ctx context.Context + repoURL string + revision string + } + tests := []struct { + name string + fields fields + args args + want []string + wantErr assert.ErrorAssertionFunc }{ - { - name: "All child folders should be returned", - repoURL: "https://github.com/argoproj/argocd-example-apps/", - revision: exampleRepoRevision, - repoRes: &v1alpha1.Repository{ - Repo: "https://github.com/argoproj/argocd-example-apps/", + {name: "ErrorGettingRepos", fields: fields{ + repositoriesDBFuncs: []func(*mocks.RepositoryDB){ + func(db *mocks.RepositoryDB) { + db.On("GetRepository", mock.Anything, mock.Anything).Return(nil, fmt.Errorf("unable to get repos")) + }, }, - repoErr: nil, - expected: []string{"apps", "apps/templates", "blue-green", "blue-green/templates", "guestbook", "helm-dependency", - "helm-guestbook", "helm-guestbook/templates", "helm-hooks", "jsonnet-guestbook", "jsonnet-guestbook-tla", - "ksonnet-guestbook", "ksonnet-guestbook/components", "ksonnet-guestbook/environments", "ksonnet-guestbook/environments/default", - "ksonnet-guestbook/environments/dev", "ksonnet-guestbook/environments/prod", "kustomize-guestbook", "plugins", "plugins/kasane", - "plugins/kustomized-helm", "plugins/kustomized-helm/overlays", "pre-post-sync", "sock-shop", "sock-shop/base", "sync-waves"}, - }, - { - name: "If GetRepository returns an error, it should pass back to caller", - repoURL: "https://github.com/argoproj/argocd-example-apps/", - revision: exampleRepoRevision, - repoRes: &v1alpha1.Repository{ - Repo: "https://github.com/argoproj/argocd-example-apps/", + }, args: args{}, want: nil, wantErr: assert.Error}, + {name: "ErrorGettingDirs", fields: fields{ + repositoriesDBFuncs: []func(*mocks.RepositoryDB){ + func(db *mocks.RepositoryDB) { + db.On("GetRepository", mock.Anything, mock.Anything).Return(&v1alpha1.Repository{}, nil) + }, }, - repoErr: fmt.Errorf("Simulated error from GetRepository"), - expected: nil, - expectedError: fmt.Errorf("Error in GetRepository: Simulated error from GetRepository"), - }, - { - name: "Test against repository containing no directories", - // Here I picked an arbitrary repository in argoproj-labs, with a commit containing no folders. - repoURL: "https://github.com/argoproj-labs/argo-workflows-operator/", - revision: "5f50933a576833b73b7a172909d8545a108685f4", - repoRes: &v1alpha1.Repository{ - Repo: "https://github.com/argoproj-labs/argo-workflows-operator/", + repoServerClientFuncs: []func(*repo_mocks.RepoServerServiceClient){ + func(client *repo_mocks.RepoServerServiceClient) { + client.On("GetGitDirectories", mock.Anything, mock.Anything).Return(nil, fmt.Errorf("unable to get dirs")) + }, }, - repoErr: nil, - expected: []string{}, - }, - } { - cc := c - t.Run(cc.name, func(t *testing.T) { - argocdRepositoryMock := ArgocdRepositoryMock{mock: &mock.Mock{}} - - argocdRepositoryMock.mock.On("GetRepository", mock.Anything, cc.repoURL).Return(cc.repoRes, cc.repoErr) - - argocd := argoCDService{ - repositoriesDB: argocdRepositoryMock, + }, args: args{}, want: nil, wantErr: assert.Error}, + {name: "HappyCase", fields: fields{ + repositoriesDBFuncs: []func(*mocks.RepositoryDB){ + func(db *mocks.RepositoryDB) { + db.On("GetRepository", mock.Anything, mock.Anything).Return(&v1alpha1.Repository{}, nil) + }, + }, + repoServerClientFuncs: []func(*repo_mocks.RepoServerServiceClient){ + func(client *repo_mocks.RepoServerServiceClient) { + client.On("GetGitDirectories", mock.Anything, mock.Anything).Return(&apiclient.GitDirectoriesResponse{ + Paths: []string{"foo", "foo/bar", "bar/foo"}, + }, nil) + }, + }, + }, args: args{}, want: []string{"foo", "foo/bar", "bar/foo"}, wantErr: assert.NoError}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mockDb := &mocks.RepositoryDB{} + mockRepoClient := &repo_mocks.RepoServerServiceClient{} + // decorate the mocks + for i := range tt.fields.repositoriesDBFuncs { + tt.fields.repositoriesDBFuncs[i](mockDb) + } + for i := range tt.fields.repoServerClientFuncs { + tt.fields.repoServerClientFuncs[i](mockRepoClient) } - got, err := argocd.GetDirectories(context.TODO(), cc.repoURL, cc.revision) - - if cc.expectedError != nil { - assert.EqualError(t, err, cc.expectedError.Error()) - } else { - sort.Strings(got) - sort.Strings(cc.expected) - - assert.Equal(t, got, cc.expected) - assert.NoError(t, err) + a := &argoCDService{ + repositoriesDB: mockDb, + storecreds: tt.fields.storecreds, + submoduleEnabled: tt.fields.submoduleEnabled, + repoServerClientSet: &repo_mocks.Clientset{RepoServerServiceClient: mockRepoClient}, + } + got, err := a.GetDirectories(tt.args.ctx, tt.args.repoURL, tt.args.revision) + if !tt.wantErr(t, err, fmt.Sprintf("GetDirectories(%v, %v, %v)", tt.args.ctx, tt.args.repoURL, tt.args.revision)) { + return } + assert.Equalf(t, tt.want, got, "GetDirectories(%v, %v, %v)", tt.args.ctx, tt.args.repoURL, tt.args.revision) }) } } func TestGetFiles(t *testing.T) { - - // Hardcode a specific commit, so that changes to argoproj/argocd-example-apps/ don't break our tests - // "chore: downgrade kustomize guestbook image tag (#73)" - commitID := "08f72e2a309beab929d9fd14626071b1a61a47f9" - - tests := []struct { - name string + type fields struct { + repositoriesDBFuncs []func(*mocks.RepositoryDB) + storecreds git.CredsStore + submoduleEnabled bool + repoServerClientFuncs []func(*repo_mocks.RepoServerServiceClient) + } + type args struct { + ctx context.Context repoURL string revision string pattern string - repoRes *v1alpha1.Repository - repoErr error - - expectSubsetOfPaths []string - doesNotContainPaths []string - expectedError error + } + tests := []struct { + name string + fields fields + args args + want map[string][]byte + wantErr assert.ErrorAssertionFunc }{ - { - name: "pull a specific revision of example apps and verify the list is expected", - repoRes: &v1alpha1.Repository{ - Insecure: true, - InsecureIgnoreHostKey: true, - Repo: "https://github.com/argoproj/argocd-example-apps/", - }, - repoURL: "https://github.com/argoproj/argocd-example-apps/", - revision: commitID, - pattern: "*", - expectSubsetOfPaths: []string{ - "apps/Chart.yaml", - "apps/templates/helm-guestbook.yaml", - "apps/templates/helm-hooks.yaml", - "apps/templates/kustomize-guestbook.yaml", - "apps/templates/namespaces.yaml", - "apps/templates/sync-waves.yaml", - "apps/values.yaml", - "blue-green/.helmignore", - "blue-green/Chart.yaml", - "blue-green/README.md", - "blue-green/templates/NOTES.txt", - "blue-green/templates/rollout.yaml", - "blue-green/templates/services.yaml", - "blue-green/values.yaml", - "guestbook/guestbook-ui-deployment.yaml", - "guestbook/guestbook-ui-svc.yaml", - "kustomize-guestbook/guestbook-ui-deployment.yaml", - "kustomize-guestbook/guestbook-ui-svc.yaml", - "kustomize-guestbook/kustomization.yaml", + {name: "ErrorGettingRepos", fields: fields{ + repositoriesDBFuncs: []func(*mocks.RepositoryDB){ + func(db *mocks.RepositoryDB) { + db.On("GetRepository", mock.Anything, mock.Anything).Return(nil, fmt.Errorf("unable to get repos")) + }, }, - }, - { - name: "pull an invalid revision, and confirm an error is returned", - repoRes: &v1alpha1.Repository{ - Insecure: true, - InsecureIgnoreHostKey: true, - Repo: "https://github.com/argoproj/argocd-example-apps/", + }, args: args{}, want: nil, wantErr: assert.Error}, + {name: "ErrorGettingFiles", fields: fields{ + repositoriesDBFuncs: []func(*mocks.RepositoryDB){ + func(db *mocks.RepositoryDB) { + db.On("GetRepository", mock.Anything, mock.Anything).Return(&v1alpha1.Repository{}, nil) + }, }, - repoURL: "https://github.com/argoproj/argocd-example-apps/", - revision: "this-tag-does-not-exist", - pattern: "*", - expectSubsetOfPaths: []string{}, - expectedError: fmt.Errorf("Error during fetching repo: `git fetch origin this-tag-does-not-exist --tags --force --prune` failed exit status 128: fatal: couldn't find remote ref this-tag-does-not-exist"), - }, - { - name: "pull a specific revision of example apps, and use a ** pattern", - repoRes: &v1alpha1.Repository{ - Insecure: true, - InsecureIgnoreHostKey: true, - Repo: "https://github.com/argoproj/argocd-example-apps/", + repoServerClientFuncs: []func(*repo_mocks.RepoServerServiceClient){ + func(client *repo_mocks.RepoServerServiceClient) { + client.On("GetGitFiles", mock.Anything, mock.Anything).Return(nil, fmt.Errorf("unable to get files")) + }, }, - repoURL: "https://github.com/argoproj/argocd-example-apps/", - revision: commitID, - pattern: "**/*.yaml", - expectSubsetOfPaths: []string{ - "apps/Chart.yaml", - "apps/templates/helm-guestbook.yaml", - "apps/templates/helm-hooks.yaml", - "apps/templates/kustomize-guestbook.yaml", - "apps/templates/namespaces.yaml", - "apps/templates/sync-waves.yaml", - "apps/values.yaml", - "blue-green/templates/rollout.yaml", - "blue-green/templates/services.yaml", - "blue-green/values.yaml", - "guestbook/guestbook-ui-deployment.yaml", - "guestbook/guestbook-ui-svc.yaml", - "kustomize-guestbook/guestbook-ui-deployment.yaml", - "kustomize-guestbook/guestbook-ui-svc.yaml", - "kustomize-guestbook/kustomization.yaml", + }, args: args{}, want: nil, wantErr: assert.Error}, + {name: "HappyCase", fields: fields{ + repositoriesDBFuncs: []func(*mocks.RepositoryDB){ + func(db *mocks.RepositoryDB) { + db.On("GetRepository", mock.Anything, mock.Anything).Return(&v1alpha1.Repository{}, nil) + }, }, - doesNotContainPaths: []string{ - "blue-green/.helmignore", - "blue-green/README.md", - "blue-green/templates/NOTES.txt", + repoServerClientFuncs: []func(*repo_mocks.RepoServerServiceClient){ + func(client *repo_mocks.RepoServerServiceClient) { + client.On("GetGitFiles", mock.Anything, mock.Anything).Return(&apiclient.GitFilesResponse{ + Map: map[string][]byte{ + "foo.json": []byte("hello: world!"), + "bar.yaml": []byte("yay: appsets"), + }, + }, nil) + }, }, - }, + }, args: args{}, want: map[string][]byte{ + "foo.json": []byte("hello: world!"), + "bar.yaml": []byte("yay: appsets"), + }, wantErr: assert.NoError}, } - - for _, cc := range tests { - - // Get all the paths for a repository, and confirm that the expected subset of paths is found (or the expected error is returned) - t.Run(cc.name, func(t *testing.T) { - argocdRepositoryMock := ArgocdRepositoryMock{mock: &mock.Mock{}} - - argocdRepositoryMock.mock.On("GetRepository", mock.Anything, cc.repoURL).Return(cc.repoRes, cc.repoErr) - - argocd := argoCDService{ - repositoriesDB: argocdRepositoryMock, + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mockDb := &mocks.RepositoryDB{} + mockRepoClient := &repo_mocks.RepoServerServiceClient{} + // decorate the mocks + for i := range tt.fields.repositoriesDBFuncs { + tt.fields.repositoriesDBFuncs[i](mockDb) + } + for i := range tt.fields.repoServerClientFuncs { + tt.fields.repoServerClientFuncs[i](mockRepoClient) } - getPathsRes, err := argocd.GetFiles(context.Background(), cc.repoURL, cc.revision, cc.pattern) - - if cc.expectedError == nil { - - assert.NoError(t, err) - for _, path := range cc.expectSubsetOfPaths { - assert.Contains(t, getPathsRes, path, "Unable to locate path: %s", path) - } - - for _, shouldNotContain := range cc.doesNotContainPaths { - assert.NotContains(t, getPathsRes, shouldNotContain, "GetPaths should not contain %s", shouldNotContain) - } - - } else { - assert.EqualError(t, err, cc.expectedError.Error()) + a := &argoCDService{ + repositoriesDB: mockDb, + storecreds: tt.fields.storecreds, + submoduleEnabled: tt.fields.submoduleEnabled, + repoServerClientSet: &repo_mocks.Clientset{RepoServerServiceClient: mockRepoClient}, + } + got, err := a.GetFiles(tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.pattern) + if !tt.wantErr(t, err, fmt.Sprintf("GetFiles(%v, %v, %v, %v)", tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.pattern)) { + return } + assert.Equalf(t, tt.want, got, "GetFiles(%v, %v, %v, %v)", tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.pattern) }) } } + +func TestNewArgoCDService(t *testing.T) { + service, err := NewArgoCDService(&db_mocks.ArgoDB{}, false, &repo_mocks.Clientset{}) + assert.NoError(t, err, err) + assert.NotNil(t, service) +} diff --git a/applicationset/utils/test/testutils.go b/applicationset/utils/test/testutils.go deleted file mode 100644 index 896ac75e274d3..0000000000000 --- a/applicationset/utils/test/testutils.go +++ /dev/null @@ -1,34 +0,0 @@ -package test - -import ( - "context" - - "github.com/stretchr/testify/mock" -) - -type ArgoCDServiceMock struct { - Mock *mock.Mock -} - -func (a ArgoCDServiceMock) GetApps(ctx context.Context, repoURL string, revision string) ([]string, error) { - args := a.Mock.Called(ctx, repoURL, revision) - - return args.Get(0).([]string), args.Error(1) -} - -func (a ArgoCDServiceMock) GetFiles(ctx context.Context, repoURL string, revision string, pattern string) (map[string][]byte, error) { - args := a.Mock.Called(ctx, repoURL, revision, pattern) - - return args.Get(0).(map[string][]byte), args.Error(1) -} - -func (a ArgoCDServiceMock) GetFileContent(ctx context.Context, repoURL string, revision string, path string) ([]byte, error) { - args := a.Mock.Called(ctx, repoURL, revision, path) - - return args.Get(0).([]byte), args.Error(1) -} - -func (a ArgoCDServiceMock) GetDirectories(ctx context.Context, repoURL string, revision string) ([]string, error) { - args := a.Mock.Called(ctx, repoURL, revision) - return args.Get(0).([]string), args.Error(1) -} diff --git a/assets/swagger.json b/assets/swagger.json index b59e0c9a3732d..faead17c68718 100644 --- a/assets/swagger.json +++ b/assets/swagger.json @@ -8611,6 +8611,9 @@ "Compiler": { "type": "string" }, + "ExtraBuildInfo": { + "type": "string" + }, "GitCommit": { "type": "string" }, diff --git a/cmd/argocd-applicationset-controller/commands/applicationset_controller.go b/cmd/argocd-applicationset-controller/commands/applicationset_controller.go index 6067a3d52aa48..68befdfa61d92 100644 --- a/cmd/argocd-applicationset-controller/commands/applicationset_controller.go +++ b/cmd/argocd-applicationset-controller/commands/applicationset_controller.go @@ -2,10 +2,13 @@ package command import ( "fmt" + "math" "net/http" "os" "time" + "github.com/argoproj/argo-cd/v2/reposerver/apiclient" + "github.com/argoproj/argo-cd/v2/util/tls" "github.com/argoproj/pkg/stats" "k8s.io/apimachinery/pkg/runtime" ctrl "sigs.k8s.io/controller-runtime" @@ -17,7 +20,6 @@ import ( "github.com/argoproj/argo-cd/v2/applicationset/webhook" cmdutil "github.com/argoproj/argo-cd/v2/cmd/util" "github.com/argoproj/argo-cd/v2/common" - "github.com/argoproj/argo-cd/v2/reposerver/askpass" "github.com/argoproj/argo-cd/v2/util/env" "github.com/argoproj/argo-cd/v2/util/github_app" @@ -45,17 +47,20 @@ func getSubmoduleEnabled() bool { func NewCommand() *cobra.Command { var ( - clientConfig clientcmd.ClientConfig - metricsAddr string - probeBindAddr string - webhookAddr string - enableLeaderElection bool - namespace string - argocdRepoServer string - policy string - debugLog bool - dryRun bool - enableProgressiveSyncs bool + clientConfig clientcmd.ClientConfig + metricsAddr string + probeBindAddr string + webhookAddr string + enableLeaderElection bool + namespace string + argocdRepoServer string + policy string + debugLog bool + dryRun bool + enableProgressiveSyncs bool + repoServerPlaintext bool + repoServerStrictTLS bool + repoServerTimeoutSeconds int ) scheme := runtime.NewScheme() _ = clientgoscheme.AddToScheme(scheme) @@ -80,9 +85,7 @@ func NewCommand() *cobra.Command { cli.SetLogLevel(cmdutil.LogLevel) restConfig, err := clientConfig.ClientConfig() - if err != nil { - return err - } + errors.CheckError(err) restConfig.UserAgent = fmt.Sprintf("argocd-applicationset-controller/%s (%s)", vers.Version, vers.Platform) @@ -110,25 +113,40 @@ func NewCommand() *cobra.Command { os.Exit(1) } dynamicClient, err := dynamic.NewForConfig(mgr.GetConfig()) - if err != nil { - return err - } + errors.CheckError(err) k8sClient, err := kubernetes.NewForConfig(mgr.GetConfig()) - if err != nil { - return err - } + errors.CheckError(err) + argoSettingsMgr := argosettings.NewSettingsManager(ctx, k8sClient, namespace) appSetConfig := appclientset.NewForConfigOrDie(mgr.GetConfig()) argoCDDB := db.NewDB(namespace, argoSettingsMgr, k8sClient) - askPassServer := askpass.NewServer() scmAuth := generators.SCMAuthProviders{ GitHubApps: github_app.NewAuthCredentials(argoCDDB.(db.RepoCredsDB)), } + + tlsConfig := apiclient.TLSConfiguration{ + DisableTLS: repoServerPlaintext, + StrictValidation: repoServerPlaintext, + } + + if !repoServerPlaintext && repoServerStrictTLS { + pool, err := tls.LoadX509CertPool( + fmt.Sprintf("%s/reposerver/tls/tls.crt", env.StringFromEnv(common.EnvAppConfigPath, common.DefaultAppConfigPath)), + fmt.Sprintf("%s/reposerver/tls/ca.crt", env.StringFromEnv(common.EnvAppConfigPath, common.DefaultAppConfigPath)), + ) + errors.CheckError(err) + tlsConfig.Certificates = pool + } + + repoClientset := apiclient.NewRepoServerClientset(argocdRepoServer, repoServerTimeoutSeconds, tlsConfig) + argoCDService, err := services.NewArgoCDService(argoCDDB, getSubmoduleEnabled(), repoClientset) + errors.CheckError(err) + terminalGenerators := map[string]generators.Generator{ "List": generators.NewListGenerator(), "Clusters": generators.NewClusterGenerator(mgr.GetClient(), ctx, k8sClient, namespace), - "Git": generators.NewGitGenerator(services.NewArgoCDService(argoCDDB, askPassServer, getSubmoduleEnabled())), + "Git": generators.NewGitGenerator(argoCDService), "SCMProvider": generators.NewSCMProviderGenerator(mgr.GetClient(), scmAuth), "ClusterDecisionResource": generators.NewDuckTypeGenerator(ctx, dynamicClient, k8sClient, namespace), "PullRequest": generators.NewPullRequestGenerator(mgr.GetClient(), scmAuth), @@ -165,7 +183,6 @@ func NewCommand() *cobra.Command { startWebhookServer(webhookHandler, webhookAddr) } - go func() { errors.CheckError(askPassServer.Run(askpass.SocketPath)) }() if err = (&controllers.ApplicationSetReconciler{ Generators: topLevelGenerators, Client: mgr.GetClient(), @@ -206,6 +223,9 @@ func NewCommand() *cobra.Command { command.Flags().StringVar(&cmdutil.LogLevel, "loglevel", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_LOGLEVEL", "info"), "Set the logging level. One of: debug|info|warn|error") command.Flags().BoolVar(&dryRun, "dry-run", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_DRY_RUN", false), "Enable dry run mode") command.Flags().BoolVar(&enableProgressiveSyncs, "enable-progressive-syncs", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_SYNCS", false), "Enable use of the experimental progressive syncs feature.") + command.Flags().BoolVar(&repoServerPlaintext, "repo-server-plaintext", env.ParseBoolFromEnv("ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_PLAINTEXT", false), "Disable TLS on connections to repo server") + command.Flags().BoolVar(&repoServerStrictTLS, "repo-server-strict-tls", env.ParseBoolFromEnv("ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_STRICT_TLS", false), "Whether to use strict validation of the TLS cert presented by the repo server") + command.Flags().IntVar(&repoServerTimeoutSeconds, "repo-server-timeout-seconds", env.ParseNumFromEnv("ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_TIMEOUT_SECONDS", 60, 0, math.MaxInt64), "Repo server RPC call timeout seconds.") return &command } diff --git a/cmd/argocd/commands/version.go b/cmd/argocd/commands/version.go index 8f3d5b1abfe11..8c69c4195c3ad 100644 --- a/cmd/argocd/commands/version.go +++ b/cmd/argocd/commands/version.go @@ -116,6 +116,9 @@ func printClientVersion(version *common.Version, short bool) string { output += fmt.Sprintf(" GoVersion: %s\n", version.GoVersion) output += fmt.Sprintf(" Compiler: %s\n", version.Compiler) output += fmt.Sprintf(" Platform: %s\n", version.Platform) + if version.ExtraBuildInfo != "" { + output += fmt.Sprintf(" ExtraBuildInfo: %s\n", version.ExtraBuildInfo) + } return output } @@ -147,6 +150,9 @@ func printServerVersion(version *version.VersionMessage, short bool) string { if version.Platform != "" { output += fmt.Sprintf(" Platform: %s\n", version.Platform) } + if version.ExtraBuildInfo != "" { + output += fmt.Sprintf(" ExtraBuildInfo: %s\n", version.ExtraBuildInfo) + } if version.KustomizeVersion != "" { output += fmt.Sprintf(" Kustomize Version: %s\n", version.KustomizeVersion) } diff --git a/cmpserver/plugin/config.go b/cmpserver/plugin/config.go index c772abb7f7f30..faa718ff9fd2e 100644 --- a/cmpserver/plugin/config.go +++ b/cmpserver/plugin/config.go @@ -37,7 +37,7 @@ type Discover struct { } func (d Discover) IsDefined() bool { - return d.FileName != "" || d.Find.Glob == "" || len(d.Find.Command.Command) > 0 + return d.FileName != "" || d.Find.Glob != "" || len(d.Find.Command.Command) > 0 } // Command holds binary path and arguments list diff --git a/cmpserver/plugin/plugin.go b/cmpserver/plugin/plugin.go index 379616260cff5..08be235315dde 100644 --- a/cmpserver/plugin/plugin.go +++ b/cmpserver/plugin/plugin.go @@ -113,7 +113,7 @@ func runCommand(ctx context.Context, command Command, path string, env []string) } if len(output) == 0 { log.WithFields(log.Fields{ - "stderr": stderr, + "stderr": stderr.String(), "command": command, }).Warn("Plugin command returned zero output") } diff --git a/common/version.go b/common/version.go index 8598f98c3171d..e8caf37a30601 100644 --- a/common/version.go +++ b/common/version.go @@ -16,6 +16,7 @@ var ( gitTag = "" // output from `git describe --exact-match --tags HEAD` (if clean tree state) gitTreeState = "" // determined from `git status --porcelain`. either 'clean' or 'dirty' kubectlVersion = "" // determined from go.mod file + extraBuildInfo = "" // extra build information for vendors to populate during build ) // Version contains Argo version information @@ -29,6 +30,7 @@ type Version struct { Compiler string Platform string KubectlVersion string + ExtraBuildInfo string } func (v Version) String() string { @@ -66,6 +68,7 @@ func GetVersion() Version { versionStr += "+unknown" } } + return Version{ Version: versionStr, BuildDate: buildDate, @@ -76,5 +79,6 @@ func GetVersion() Version { Compiler: runtime.Compiler, Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH), KubectlVersion: kubectlVersion, + ExtraBuildInfo: extraBuildInfo, } } diff --git a/controller/appcontroller.go b/controller/appcontroller.go index d48dfe29d8adf..052dd35d094cc 100644 --- a/controller/appcontroller.go +++ b/controller/appcontroller.go @@ -53,6 +53,7 @@ import ( "github.com/argoproj/argo-cd/v2/util/db" "github.com/argoproj/argo-cd/v2/util/errors" "github.com/argoproj/argo-cd/v2/util/glob" + "github.com/argoproj/argo-cd/v2/util/helm" logutils "github.com/argoproj/argo-cd/v2/util/log" settings_util "github.com/argoproj/argo-cd/v2/util/settings" ) @@ -943,7 +944,9 @@ func (ctrl *ApplicationController) removeProjectFinalizer(proj *appv1.AppProject // shouldBeDeleted returns whether a given resource obj should be deleted on cascade delete of application app func (ctrl *ApplicationController) shouldBeDeleted(app *appv1.Application, obj *unstructured.Unstructured) bool { - return !kube.IsCRD(obj) && !isSelfReferencedApp(app, kube.GetObjectRef(obj)) && !resourceutil.HasAnnotationOption(obj, synccommon.AnnotationSyncOptions, synccommon.SyncOptionDisableDeletion) + return !kube.IsCRD(obj) && !isSelfReferencedApp(app, kube.GetObjectRef(obj)) && + !resourceutil.HasAnnotationOption(obj, synccommon.AnnotationSyncOptions, synccommon.SyncOptionDisableDeletion) && + !resourceutil.HasAnnotationOption(obj, helm.ResourcePolicyAnnotation, helm.ResourcePolicyKeep) } func (ctrl *ApplicationController) getPermittedAppLiveObjects(app *appv1.Application, proj *appv1.AppProject, projectClusters func(project string) ([]*appv1.Cluster, error)) (map[kube.ResourceKey]*unstructured.Unstructured, error) { diff --git a/controller/appcontroller_test.go b/controller/appcontroller_test.go index 9e107b4e791fe..6f8a163e4e4bf 100644 --- a/controller/appcontroller_test.go +++ b/controller/appcontroller_test.go @@ -1528,4 +1528,10 @@ func Test_syncDeleteOption(t *testing.T) { delete := ctrl.shouldBeDeleted(app, cmObj) assert.False(t, delete) }) + t.Run("with delete set to false object is retained", func(t *testing.T) { + cmObj := kube.MustToUnstructured(&cm) + cmObj.SetAnnotations(map[string]string{"helm.sh/resource-policy": "keep"}) + delete := ctrl.shouldBeDeleted(app, cmObj) + assert.False(t, delete) + }) } diff --git a/docs/assets/argocd-components.png b/docs/assets/argocd-components.png new file mode 100644 index 0000000000000..35e214a10ca7f Binary files /dev/null and b/docs/assets/argocd-components.png differ diff --git a/docs/assets/extra_info-1.png b/docs/assets/extra_info-1.png new file mode 100644 index 0000000000000..8ccf597c0879e Binary files /dev/null and b/docs/assets/extra_info-1.png differ diff --git a/docs/assets/extra_info-2.png b/docs/assets/extra_info-2.png new file mode 100644 index 0000000000000..3dde4e61fa4e0 Binary files /dev/null and b/docs/assets/extra_info-2.png differ diff --git a/docs/assets/extra_info.png b/docs/assets/extra_info.png new file mode 100644 index 0000000000000..c5064762e5138 Binary files /dev/null and b/docs/assets/extra_info.png differ diff --git a/docs/developer-guide/architecture/components.md b/docs/developer-guide/architecture/components.md new file mode 100644 index 0000000000000..eb2904b531ccb --- /dev/null +++ b/docs/developer-guide/architecture/components.md @@ -0,0 +1,118 @@ +# Component Architecture + +Argo CD is designed with a component based architecture. The goal is +to separate the responsibility in different deployable units in order +to have the following benefits: + +- **Modularity**: Provides great level of flexibility. Components + interact with each other via an interface. This means that as long + as the interface contract is respected, a given component can be + replaced without requiring the rest of the system to adapt. It is + also possible to run the system without certain components if a + specific group of functionality isn't desired. +- **Single responsibility**: Helps to determine where the different + types of functionality should be implemented which drives for + better system cohesiveness. +- **Reusability**: Clearly defined interfaces helps in functionality + discoverability which benefits reusability of services. + +The default Argo CD installation is composed by different components +and different Kubernetes controllers. The controllers aren't +categorized as components as they have proprietary interfaces (CRDs) +and therefore, miss the modular nature. There are more resources +created while installing Argo CD (ConfigMaps, Services, etc), but for +simplicity we are covering just the ones directly related with the +componentized architecture. + +## Dependencies + +The diagram below has represented all dependencies between the +different components used by the default Argo CD installation: + +![Components Diagram](../../assets/argocd-components.png) + +There are 4 logical layers represented in the diagram: + +- **UI**: This is the presentation layer. Users interact with Argo CD + mainly by components from this layer. +- **Application**: The capabilities required to support the components + from the UI layer. +- **Core**: The main Argo CD gitops functionality is implemented by + components and Kubernetes controllers from the Core layer. +- **Infra**: Represent the tools that Argo CD depends on as part of + its infrastructure. + +The logical layers also help making the diagram easier to follow as +dependencies are represented in a top-down relationship. This means +that components from the top layers will be allowed to depend on any +component from any of the bottom layers. However components from the +bottom layers will never depend on any ones from upper layers. + +## Responsibility + +Below you can refer to a brief description of Argo CD components and +its main responsibilities. + +### Webapp + +Argo CD ships with a powerful web interface that allows managing +applications deployed in a given Kubernetes cluster. + +### CLI + +Argo CD provides a CLI that can be used by users to interact with Argo +CD API. The CLI can also be used for automation and scripting. + +### API Server + +Defines the proprietary API exposed by Argo CD that powers the Webapp +and the CLI functionalities. + +### Application Controller + +The Application Controller is responsible for reconciling the +Application resource in Kubernetes syncronizing the desired +application state (provided in Git) with the live state (in +Kubernetes). The Application Controller is also responsible for +reconciling the Project resource. + +### ApplicationSet Controller + +The ApplicationSet Controller is responsible for reconciling the +ApplicationSet resource. + +### Repo Server + +Repo Server plays an important role in Argo CD architecture as it is +responsible for interacting with the Git repository to generate the +desired state for all Kubernetes resources that belongs to a given +application. + +### Redis + +Redis is used by Argo CD to provide a cache layer reducing requests +sent to the Kube API as well as to the Git provider. It also supports +a few UI operations. + +### Kube API + +Argo CD controllers will connect to the Kubernetes API in order to run +the reconciliation loop. + +### Git + +As a gitops tool Argo CD requires that the desired state of the +Kubernetes resources to be provided in a Git repository. + +We use "git" here to stand in for an actual git repo, a Helm repo, +or an OCI artifact repo. Argo CD supports all those options. + +### Dex + +Argo CD relies on Dex to provide authentication with external OIDC +providers. However other tools can be used instead of Dex. Check the +[user management +documentation](../../operator-manual/user-management/index.md) for +more details. + + diff --git a/docs/operator-manual/application.yaml b/docs/operator-manual/application.yaml index 1d15b8ba109cc..299da7eba4b95 100644 --- a/docs/operator-manual/application.yaml +++ b/docs/operator-manual/application.yaml @@ -152,7 +152,12 @@ spec: # name: in-cluster # The namespace will only be set for namespace-scoped resources that have not set a value for .metadata.namespace namespace: guestbook - + + # Extra information to show in the Argo CD Application details tab + info: + - name: 'Example:' + value: 'https://example.com' + # Sync policy syncPolicy: automated: # automated sync by default retries failed attempts 5 times with following delays between attempts ( 5s, 10s, 20s, 40s, 80s ); retry controlled using `retry` field. diff --git a/docs/operator-manual/upgrading/2.6-2.7.md b/docs/operator-manual/upgrading/2.6-2.7.md index c0f89de2d53ee..8ff1158728314 100644 --- a/docs/operator-manual/upgrading/2.6-2.7.md +++ b/docs/operator-manual/upgrading/2.6-2.7.md @@ -58,7 +58,7 @@ The manifests are now using [`tini` as entrypoint][3], instead of `entrypoint.sh ## Deep Links template updates -Deep Links now allow you to access other values like `cluster`, `project`, `application` and `resource` in the url and condition templates for specific categories of links. +Deep Links now allow you to access other values like `cluster`, `project`, `application` and `resource` in the url and condition templates for specific categories of links. The templating syntax has also been updated to be prefixed with the type of resource you want to access for example previously if you had a `resource.links` config like : ```yaml resource.links: | @@ -75,3 +75,9 @@ This would become : ``` Read the full [documentation](../deep_links.md) to see all possible combinations of values accessible fo each category of links. + +## Support of `helm.sh/resource-policy` annotation + +Argo CD now supports the `helm.sh/resource-policy` annotation to control the deletion of resources. The behavior is the same as the behavior of +`argocd.argoproj.io/sync-options: Delete=false` annotation: if the annotation is present and set to `keep`, the resource will not be deleted +when the application is deleted. diff --git a/docs/user-guide/extra_info.md b/docs/user-guide/extra_info.md new file mode 100644 index 0000000000000..0a27e497ec46d --- /dev/null +++ b/docs/user-guide/extra_info.md @@ -0,0 +1,28 @@ +# Add extra Application info + +You can add additional information to an Application on your ArgoCD dashboard. +If you wish to add clickable links, see [Add external URL](https://argo-cd.readthedocs.io/en/stable/user-guide/external-url/). + +This is done by providing the 'info' field a key-value in your Application manifest. + +Example: +```yaml +project: argo-demo +source: + repoURL: 'https://demo' + path: argo-demo +destination: + server: https://demo + namespace: argo-demo +info: + - name: Example: + value: >- + https://example.com +``` +![External link](../assets/extra_info-1.png) + +The additional information will be visible on the ArgoCD Application details page. + +![External link](../assets/extra_info.png) + +![External link](../assets/extra_info-2.png) diff --git a/docs/user-guide/helm.md b/docs/user-guide/helm.md index c5d16f4fc4b3b..d65316b71d0bd 100644 --- a/docs/user-guide/helm.md +++ b/docs/user-guide/helm.md @@ -119,6 +119,7 @@ Argo CD supports many (most?) Helm hooks by mapping the Helm annotations onto Ar | `helm.sh/hook-delete-policy` | Supported. See also `argocd.argoproj.io/hook-delete-policy`). | | `helm.sh/hook-delete-timeout` | Not supported. Never used in Helm stable | | `helm.sh/hook-weight` | Supported as equivalent to `argocd.argoproj.io/sync-wave`. | +| `helm.sh/resource-policy: keep` | Supported as equivalent to `argocd.argoproj.io/sync-options: Delete=false`. | Unsupported hooks are ignored. In Argo CD, hooks are created by using `kubectl apply`, rather than `kubectl create`. This means that if the hook is named and already exists, it will not change unless you have annotated it with `before-hook-creation`. diff --git a/manifests/base/applicationset-controller/argocd-applicationset-controller-deployment.yaml b/manifests/base/applicationset-controller/argocd-applicationset-controller-deployment.yaml index de42229ba5df6..f7d5b6f2efd10 100644 --- a/manifests/base/applicationset-controller/argocd-applicationset-controller-deployment.yaml +++ b/manifests/base/applicationset-controller/argocd-applicationset-controller-deployment.yaml @@ -22,107 +22,132 @@ spec: imagePullPolicy: Always name: argocd-applicationset-controller ports: - - containerPort: 7000 - name: webhook - - containerPort: 8080 - name: metrics + - containerPort: 7000 + name: webhook + - containerPort: 8080 + name: metrics env: - - name: NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_LEADER_ELECTION - valueFrom: - configMapKeyRef: - key: applicationsetcontroller.enable.leader.election - name: argocd-cmd-params-cm - optional: true - - name: ARGOCD_APPLICATIONSET_CONTROLLER_NAMESPACE - valueFrom: - configMapKeyRef: - key: applicationsetcontroller.namespace - name: argocd-cmd-params-cm - optional: true - - name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER - valueFrom: - configMapKeyRef: - key: repo.server - name: argocd-cmd-params-cm - optional: true - - name: ARGOCD_APPLICATIONSET_CONTROLLER_POLICY - valueFrom: - configMapKeyRef: - key: applicationsetcontroller.policy - name: argocd-cmd-params-cm - optional: true - - name: ARGOCD_APPLICATIONSET_CONTROLLER_DEBUG - valueFrom: - configMapKeyRef: - key: applicationsetcontroller.debug - name: argocd-cmd-params-cm - optional: true - - name: ARGOCD_APPLICATIONSET_CONTROLLER_LOGFORMAT - valueFrom: - configMapKeyRef: - key: applicationsetcontroller.log.format - name: argocd-cmd-params-cm - optional: true - - name: ARGOCD_APPLICATIONSET_CONTROLLER_LOGLEVEL - valueFrom: - configMapKeyRef: - key: applicationsetcontroller.log.level - name: argocd-cmd-params-cm - optional: true - - name: ARGOCD_APPLICATIONSET_CONTROLLER_DRY_RUN - valueFrom: - configMapKeyRef: - key: applicationsetcontroller.dryrun - name: argocd-cmd-params-cm - optional: true - - name: ARGOCD_GIT_MODULES_ENABLED - valueFrom: - configMapKeyRef: - key: applicationsetcontroller.enable.git.submodule - name: argocd-cmd-params-cm - optional: true - - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_SYNCS - valueFrom: - configMapKeyRef: - key: applicationsetcontroller.enable.progressive.syncs - name: argocd-cmd-params-cm - optional: true + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_LEADER_ELECTION + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.enable.leader.election + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_NAMESPACE + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.namespace + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER + valueFrom: + configMapKeyRef: + key: repo.server + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_POLICY + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.policy + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_DEBUG + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.debug + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_LOGFORMAT + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.log.format + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_LOGLEVEL + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.log.level + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_DRY_RUN + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.dryrun + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_GIT_MODULES_ENABLED + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.enable.git.submodule + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_SYNCS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.enable.progressive.syncs + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_PLAINTEXT + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: controller.repo.server.plaintext + optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_STRICT_TLS + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: controller.repo.server.strict.tls + optional: true volumeMounts: - - mountPath: /app/config/ssh - name: ssh-known-hosts - - mountPath: /app/config/tls - name: tls-certs - - mountPath: /app/config/gpg/source - name: gpg-keys - - mountPath: /app/config/gpg/keys - name: gpg-keyring - - mountPath: /tmp - name: tmp + - mountPath: /app/config/ssh + name: ssh-known-hosts + - mountPath: /app/config/tls + name: tls-certs + - mountPath: /app/config/gpg/source + name: gpg-keys + - mountPath: /app/config/gpg/keys + name: gpg-keyring + - mountPath: /tmp + name: tmp + - name: argocd-repo-server-tls + mountPath: /app/config/reposerver/tls securityContext: capabilities: drop: - - ALL + - ALL allowPrivilegeEscalation: false - readOnlyRootFilesystem: true + readOnlyRootFilesystem: true runAsNonRoot: true seccompProfile: type: RuntimeDefault serviceAccountName: argocd-applicationset-controller volumes: - - configMap: - name: argocd-ssh-known-hosts-cm - name: ssh-known-hosts - - configMap: - name: argocd-tls-certs-cm - name: tls-certs - - configMap: - name: argocd-gpg-keys-cm - name: gpg-keys - - emptyDir: {} - name: gpg-keyring - - emptyDir: {} - name: tmp + - configMap: + name: argocd-ssh-known-hosts-cm + name: ssh-known-hosts + - configMap: + name: argocd-tls-certs-cm + name: tls-certs + - configMap: + name: argocd-gpg-keys-cm + name: gpg-keys + - emptyDir: { } + name: gpg-keyring + - emptyDir: { } + name: tmp + - name: argocd-repo-server-tls + secret: + secretName: argocd-repo-server-tls + optional: true + items: + - key: tls.crt + path: tls.crt + - key: tls.key + path: tls.key + - key: ca.crt + path: ca.crt \ No newline at end of file diff --git a/manifests/base/repo-server/argocd-repo-server-network-policy.yaml b/manifests/base/repo-server/argocd-repo-server-network-policy.yaml index 2b3fb72b557b5..267dfa81adc49 100644 --- a/manifests/base/repo-server/argocd-repo-server-network-policy.yaml +++ b/manifests/base/repo-server/argocd-repo-server-network-policy.yaml @@ -7,18 +7,21 @@ spec: matchLabels: app.kubernetes.io/name: argocd-repo-server policyTypes: - - Ingress + - Ingress ingress: - from: - - podSelector: - matchLabels: - app.kubernetes.io/name: argocd-server - - podSelector: - matchLabels: - app.kubernetes.io/name: argocd-application-controller - - podSelector: - matchLabels: - app.kubernetes.io/name: argocd-notifications-controller + - podSelector: + matchLabels: + app.kubernetes.io/name: argocd-server + - podSelector: + matchLabels: + app.kubernetes.io/name: argocd-application-controller + - podSelector: + matchLabels: + app.kubernetes.io/name: argocd-notifications-controller + - podSelector: + matchLabels: + app.kubernetes.io/name: argocd-applicationset-controller ports: - protocol: TCP port: 8081 diff --git a/manifests/core-install.yaml b/manifests/core-install.yaml index c7f025baccf43..3769b9411b682 100644 --- a/manifests/core-install.yaml +++ b/manifests/core-install.yaml @@ -6641,6 +6641,18 @@ spec: key: applicationsetcontroller.enable.progressive.syncs name: argocd-cmd-params-cm optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_PLAINTEXT + valueFrom: + configMapKeyRef: + key: controller.repo.server.plaintext + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_STRICT_TLS + valueFrom: + configMapKeyRef: + key: controller.repo.server.strict.tls + name: argocd-cmd-params-cm + optional: true image: quay.io/argoproj/argocd:latest imagePullPolicy: Always name: argocd-applicationset-controller @@ -6669,6 +6681,8 @@ spec: name: gpg-keyring - mountPath: /tmp name: tmp + - mountPath: /app/config/reposerver/tls + name: argocd-repo-server-tls serviceAccountName: argocd-applicationset-controller volumes: - configMap: @@ -6684,6 +6698,17 @@ spec: name: gpg-keyring - emptyDir: {} name: tmp + - name: argocd-repo-server-tls + secret: + items: + - key: tls.crt + path: tls.crt + - key: tls.key + path: tls.key + - key: ca.crt + path: ca.crt + optional: true + secretName: argocd-repo-server-tls --- apiVersion: apps/v1 kind: Deployment @@ -7298,6 +7323,9 @@ spec: - podSelector: matchLabels: app.kubernetes.io/name: argocd-notifications-controller + - podSelector: + matchLabels: + app.kubernetes.io/name: argocd-applicationset-controller ports: - port: 8081 protocol: TCP diff --git a/manifests/ha/install.yaml b/manifests/ha/install.yaml index 1029f807a2010..31f9651b84d3c 100644 --- a/manifests/ha/install.yaml +++ b/manifests/ha/install.yaml @@ -7860,6 +7860,18 @@ spec: key: applicationsetcontroller.enable.progressive.syncs name: argocd-cmd-params-cm optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_PLAINTEXT + valueFrom: + configMapKeyRef: + key: controller.repo.server.plaintext + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_STRICT_TLS + valueFrom: + configMapKeyRef: + key: controller.repo.server.strict.tls + name: argocd-cmd-params-cm + optional: true image: quay.io/argoproj/argocd:latest imagePullPolicy: Always name: argocd-applicationset-controller @@ -7888,6 +7900,8 @@ spec: name: gpg-keyring - mountPath: /tmp name: tmp + - mountPath: /app/config/reposerver/tls + name: argocd-repo-server-tls serviceAccountName: argocd-applicationset-controller volumes: - configMap: @@ -7903,6 +7917,17 @@ spec: name: gpg-keyring - emptyDir: {} name: tmp + - name: argocd-repo-server-tls + secret: + items: + - key: tls.crt + path: tls.crt + - key: tls.key + path: tls.key + - key: ca.crt + path: ca.crt + optional: true + secretName: argocd-repo-server-tls --- apiVersion: apps/v1 kind: Deployment @@ -9329,6 +9354,9 @@ spec: - podSelector: matchLabels: app.kubernetes.io/name: argocd-notifications-controller + - podSelector: + matchLabels: + app.kubernetes.io/name: argocd-applicationset-controller ports: - port: 8081 protocol: TCP diff --git a/manifests/ha/namespace-install.yaml b/manifests/ha/namespace-install.yaml index 4dd87d5aada63..362096b0b51f5 100644 --- a/manifests/ha/namespace-install.yaml +++ b/manifests/ha/namespace-install.yaml @@ -1579,6 +1579,18 @@ spec: key: applicationsetcontroller.enable.progressive.syncs name: argocd-cmd-params-cm optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_PLAINTEXT + valueFrom: + configMapKeyRef: + key: controller.repo.server.plaintext + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_STRICT_TLS + valueFrom: + configMapKeyRef: + key: controller.repo.server.strict.tls + name: argocd-cmd-params-cm + optional: true image: quay.io/argoproj/argocd:latest imagePullPolicy: Always name: argocd-applicationset-controller @@ -1607,6 +1619,8 @@ spec: name: gpg-keyring - mountPath: /tmp name: tmp + - mountPath: /app/config/reposerver/tls + name: argocd-repo-server-tls serviceAccountName: argocd-applicationset-controller volumes: - configMap: @@ -1622,6 +1636,17 @@ spec: name: gpg-keyring - emptyDir: {} name: tmp + - name: argocd-repo-server-tls + secret: + items: + - key: tls.crt + path: tls.crt + - key: tls.key + path: tls.key + - key: ca.crt + path: ca.crt + optional: true + secretName: argocd-repo-server-tls --- apiVersion: apps/v1 kind: Deployment @@ -3048,6 +3073,9 @@ spec: - podSelector: matchLabels: app.kubernetes.io/name: argocd-notifications-controller + - podSelector: + matchLabels: + app.kubernetes.io/name: argocd-applicationset-controller ports: - port: 8081 protocol: TCP diff --git a/manifests/install.yaml b/manifests/install.yaml index f06e9580d55ff..4e16b9f15fc34 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -6979,6 +6979,18 @@ spec: key: applicationsetcontroller.enable.progressive.syncs name: argocd-cmd-params-cm optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_PLAINTEXT + valueFrom: + configMapKeyRef: + key: controller.repo.server.plaintext + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_STRICT_TLS + valueFrom: + configMapKeyRef: + key: controller.repo.server.strict.tls + name: argocd-cmd-params-cm + optional: true image: quay.io/argoproj/argocd:latest imagePullPolicy: Always name: argocd-applicationset-controller @@ -7007,6 +7019,8 @@ spec: name: gpg-keyring - mountPath: /tmp name: tmp + - mountPath: /app/config/reposerver/tls + name: argocd-repo-server-tls serviceAccountName: argocd-applicationset-controller volumes: - configMap: @@ -7022,6 +7036,17 @@ spec: name: gpg-keyring - emptyDir: {} name: tmp + - name: argocd-repo-server-tls + secret: + items: + - key: tls.crt + path: tls.crt + - key: tls.key + path: tls.key + - key: ca.crt + path: ca.crt + optional: true + secretName: argocd-repo-server-tls --- apiVersion: apps/v1 kind: Deployment @@ -8147,6 +8172,9 @@ spec: - podSelector: matchLabels: app.kubernetes.io/name: argocd-notifications-controller + - podSelector: + matchLabels: + app.kubernetes.io/name: argocd-applicationset-controller ports: - port: 8081 protocol: TCP diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index 70769e75a9dc7..101c3c1953e7d 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -698,6 +698,18 @@ spec: key: applicationsetcontroller.enable.progressive.syncs name: argocd-cmd-params-cm optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_PLAINTEXT + valueFrom: + configMapKeyRef: + key: controller.repo.server.plaintext + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_STRICT_TLS + valueFrom: + configMapKeyRef: + key: controller.repo.server.strict.tls + name: argocd-cmd-params-cm + optional: true image: quay.io/argoproj/argocd:latest imagePullPolicy: Always name: argocd-applicationset-controller @@ -726,6 +738,8 @@ spec: name: gpg-keyring - mountPath: /tmp name: tmp + - mountPath: /app/config/reposerver/tls + name: argocd-repo-server-tls serviceAccountName: argocd-applicationset-controller volumes: - configMap: @@ -741,6 +755,17 @@ spec: name: gpg-keyring - emptyDir: {} name: tmp + - name: argocd-repo-server-tls + secret: + items: + - key: tls.crt + path: tls.crt + - key: tls.key + path: tls.key + - key: ca.crt + path: ca.crt + optional: true + secretName: argocd-repo-server-tls --- apiVersion: apps/v1 kind: Deployment @@ -1866,6 +1891,9 @@ spec: - podSelector: matchLabels: app.kubernetes.io/name: argocd-notifications-controller + - podSelector: + matchLabels: + app.kubernetes.io/name: argocd-applicationset-controller ports: - port: 8081 protocol: TCP diff --git a/mkdocs.yml b/mkdocs.yml index 71d4086fe1d89..7d0da86dd10da 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -165,12 +165,14 @@ nav: - user-guide/best_practices.md - user-guide/status-badge.md - user-guide/external-url.md + - user-guide/extra_info.md - Notification subscriptions: user-guide/subscriptions.md - Command Reference: user-guide/commands/argocd.md - Developer Guide: - developer-guide/index.md - Architecture: - developer-guide/architecture/authz-authn.md + - developer-guide/architecture/components.md - Code Contribution Guide: developer-guide/code-contributions.md - Toolchain Guide: developer-guide/toolchain-guide.md - developer-guide/contributors-quickstart.md diff --git a/notification_controller/controller/controller_test.go b/notification_controller/controller/controller_test.go new file mode 100644 index 0000000000000..fdbd683722279 --- /dev/null +++ b/notification_controller/controller/controller_test.go @@ -0,0 +1,166 @@ +package controller + +import ( + "context" + "testing" + "time" + + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "github.com/sirupsen/logrus/hooks/test" + "github.com/stretchr/testify/assert" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/dynamic/fake" + k8sfake "k8s.io/client-go/kubernetes/fake" + "k8s.io/client-go/tools/cache" +) + +func TestIsAppSyncStatusRefreshed(t *testing.T) { + logger, _ := test.NewNullLogger() + logEntry := logger.WithField("", "") + + tests := []struct { + name string + app *unstructured.Unstructured + expectedValue bool + }{ + { + name: "No OperationState", + app: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "status": map[string]interface{}{}, + }, + }, + expectedValue: true, + }, + { + name: "No FinishedAt, Completed Phase", + app: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "status": map[string]interface{}{ + "operationState": map[string]interface{}{ + "phase": "Succeeded", + }, + }, + }, + }, + expectedValue: false, + }, + { + name: "FinishedAt After ReconciledAt & ObservedAt", + app: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "status": map[string]interface{}{ + "operationState": map[string]interface{}{ + "finishedAt": "2021-01-01T01:05:00Z", + "phase": "Succeeded", + }, + "reconciledAt": "2021-01-01T01:02:00Z", + "observedAt": "2021-01-01T01:04:00Z", + }, + }, + }, + expectedValue: false, + }, + { + name: "FinishedAt Before ReconciledAt & ObservedAt", + app: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "status": map[string]interface{}{ + "operationState": map[string]interface{}{ + "finishedAt": "2021-01-01T01:02:00Z", + "phase": "Succeeded", + }, + "reconciledAt": "2021-01-01T01:04:00Z", + "observedAt": "2021-01-01T01:06:00Z", + }, + }, + }, + expectedValue: true, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + actualValue := isAppSyncStatusRefreshed(test.app, logEntry) + assert.Equal(t, test.expectedValue, actualValue) + }) + } +} + +func TestGetAppProj_invalidProjectNestedString(t *testing.T) { + app := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "spec": map[string]interface{}{}, + }, + } + informer := cache.NewSharedIndexInformer(nil, nil, 0, nil) + proj := getAppProj(app, informer) + + assert.Nil(t, proj) +} + +func TestInit(t *testing.T) { + scheme := runtime.NewScheme() + err := v1alpha1.SchemeBuilder.AddToScheme(scheme) + if err != nil { + t.Fatalf("Error registering the resource: %v", err) + } + dynamicClient := fake.NewSimpleDynamicClient(scheme) + k8sClient := k8sfake.NewSimpleClientset() + appLabelSelector := "app=test" + + nc := NewController( + k8sClient, + dynamicClient, + nil, + "default", + appLabelSelector, + nil, + "my-secret", + "my-configmap", + ) + + assert.NotNil(t, nc) + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + err = nc.Init(ctx) + + assert.NoError(t, err) +} + +func TestInitTimeout(t *testing.T) { + scheme := runtime.NewScheme() + err := v1alpha1.SchemeBuilder.AddToScheme(scheme) + if err != nil { + t.Fatalf("Error registering the resource: %v", err) + } + dynamicClient := fake.NewSimpleDynamicClient(scheme) + k8sClient := k8sfake.NewSimpleClientset() + appLabelSelector := "app=test" + + nc := NewController( + k8sClient, + dynamicClient, + nil, + "default", + appLabelSelector, + nil, + "my-secret", + "my-configmap", + ) + + assert.NotNil(t, nc) + + // Use a short timeout to simulate a timeout during cache synchronization + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Millisecond) + defer cancel() + + err = nc.Init(ctx) + + // Expect an error & add assertion for the error message + assert.Error(t, err) + assert.Equal(t, "Timed out waiting for caches to sync", err.Error()) +} diff --git a/pkg/apiclient/version/version.pb.go b/pkg/apiclient/version/version.pb.go index 35474d63124ed..0b58bf4a6cede 100644 --- a/pkg/apiclient/version/version.pb.go +++ b/pkg/apiclient/version/version.pb.go @@ -46,6 +46,7 @@ type VersionMessage struct { HelmVersion string `protobuf:"bytes,11,opt,name=HelmVersion,proto3" json:"HelmVersion,omitempty"` KubectlVersion string `protobuf:"bytes,12,opt,name=KubectlVersion,proto3" json:"KubectlVersion,omitempty"` JsonnetVersion string `protobuf:"bytes,13,opt,name=JsonnetVersion,proto3" json:"JsonnetVersion,omitempty"` + ExtraBuildInfo string `protobuf:"bytes,14,opt,name=ExtraBuildInfo,proto3" json:"ExtraBuildInfo,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -168,6 +169,13 @@ func (m *VersionMessage) GetJsonnetVersion() string { return "" } +func (m *VersionMessage) GetExtraBuildInfo() string { + if m != nil { + return m.ExtraBuildInfo + } + return "" +} + func init() { proto.RegisterType((*VersionMessage)(nil), "version.VersionMessage") } @@ -175,32 +183,33 @@ func init() { func init() { proto.RegisterFile("server/version/version.proto", fileDescriptor_8be80977d07a4107) } var fileDescriptor_8be80977d07a4107 = []byte{ - // 399 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x92, 0xdf, 0x6a, 0xdb, 0x30, - 0x18, 0xc5, 0x71, 0xb2, 0xe5, 0x8f, 0x92, 0x85, 0x21, 0x46, 0x66, 0xbc, 0x10, 0x42, 0x2e, 0xc6, - 0x18, 0xcc, 0x86, 0x6c, 0x4f, 0x90, 0x6c, 0x64, 0x2c, 0x0c, 0xc2, 0x32, 0x7a, 0xd1, 0x3b, 0xd9, - 0xf9, 0xe2, 0xaa, 0xb5, 0xfc, 0x19, 0x59, 0x36, 0xb4, 0x97, 0x7d, 0x85, 0x42, 0x9f, 0xa9, 0x97, - 0x85, 0xbe, 0x40, 0x09, 0x7d, 0x90, 0x62, 0xd9, 0x72, 0x9b, 0xf6, 0xca, 0x3a, 0xe7, 0xfc, 0x7c, - 0x10, 0x1c, 0x91, 0x51, 0x0a, 0x32, 0x07, 0xe9, 0xe5, 0x20, 0x53, 0x8e, 0xb1, 0xf9, 0xba, 0x89, - 0x44, 0x85, 0xb4, 0x5d, 0x49, 0x67, 0x14, 0x22, 0x86, 0x11, 0x78, 0x2c, 0xe1, 0x1e, 0x8b, 0x63, - 0x54, 0x4c, 0x71, 0x8c, 0xd3, 0x12, 0x73, 0x3e, 0x55, 0xa9, 0x56, 0x7e, 0xb6, 0xf3, 0x40, 0x24, - 0xea, 0xbc, 0x0c, 0xa7, 0xd7, 0x4d, 0x32, 0x38, 0x2a, 0x6b, 0xfe, 0x42, 0x9a, 0xb2, 0x10, 0xa8, - 0x4d, 0xda, 0x95, 0x63, 0x5b, 0x13, 0xeb, 0x4b, 0xf7, 0x9f, 0x91, 0x74, 0x44, 0xba, 0xf3, 0x8c, - 0x47, 0xdb, 0x9f, 0x4c, 0x81, 0xdd, 0xd0, 0xd9, 0x93, 0x51, 0xa4, 0x4b, 0xae, 0x16, 0x28, 0x04, - 0x57, 0x76, 0xb3, 0x4c, 0x6b, 0x83, 0x0e, 0x49, 0x6b, 0xc9, 0xd5, 0x7f, 0x16, 0xda, 0x6f, 0x74, - 0x54, 0x29, 0x3a, 0x25, 0xfd, 0xe2, 0x24, 0x01, 0x36, 0xaa, 0xa8, 0x7d, 0xab, 0xd3, 0x03, 0x4f, - 0x37, 0xa3, 0xb9, 0x53, 0xab, 0x6a, 0x36, 0x06, 0x75, 0x48, 0x67, 0x81, 0x22, 0xe1, 0x11, 0x48, - 0xbb, 0xad, 0xc3, 0x5a, 0x17, 0xd9, 0x3a, 0x62, 0x6a, 0x87, 0x52, 0xd8, 0x9d, 0x32, 0x33, 0x9a, - 0x7e, 0x25, 0xef, 0x57, 0x59, 0xaa, 0x50, 0xf0, 0x0b, 0x30, 0xe5, 0x44, 0x33, 0xaf, 0x7c, 0x3a, - 0x21, 0xbd, 0xdf, 0x10, 0x09, 0x83, 0xf5, 0x34, 0xf6, 0xdc, 0xa2, 0x9f, 0xc9, 0x60, 0x95, 0xf9, - 0x10, 0xa8, 0xc8, 0x40, 0x7d, 0x0d, 0xbd, 0x70, 0x0b, 0xee, 0x4f, 0x8a, 0x71, 0x0c, 0xca, 0x70, - 0xef, 0x4a, 0xee, 0xd0, 0x9d, 0xf9, 0xf5, 0x2e, 0x1b, 0x90, 0x39, 0x0f, 0x80, 0xae, 0xeb, 0x5d, - 0xe8, 0xd0, 0x2d, 0x37, 0x75, 0xcd, 0xa6, 0xee, 0xaf, 0x62, 0x53, 0xe7, 0xa3, 0x6b, 0x5e, 0xc8, - 0xe1, 0xa6, 0xd3, 0x0f, 0x97, 0x77, 0x0f, 0x57, 0x8d, 0x01, 0xed, 0xeb, 0x37, 0x52, 0x41, 0xf3, - 0xf9, 0xcd, 0x7e, 0x6c, 0xdd, 0xee, 0xc7, 0xd6, 0xfd, 0x7e, 0x6c, 0x1d, 0xff, 0x08, 0xb9, 0x3a, - 0xc9, 0x7c, 0x37, 0x40, 0xe1, 0x31, 0x19, 0x62, 0x22, 0xf1, 0x54, 0x1f, 0xbe, 0x05, 0x5b, 0x2f, - 0x9f, 0x79, 0xc9, 0x59, 0x58, 0xfc, 0x1d, 0x44, 0x1c, 0x62, 0x65, 0x3a, 0xfc, 0x96, 0xbe, 0xc2, - 0xf7, 0xc7, 0x00, 0x00, 0x00, 0xff, 0xff, 0x9e, 0x97, 0xec, 0x06, 0xab, 0x02, 0x00, 0x00, + // 415 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x92, 0xd1, 0x6a, 0x14, 0x31, + 0x18, 0x85, 0x99, 0x56, 0x77, 0xdb, 0x74, 0x5d, 0x24, 0x48, 0x0d, 0xeb, 0xb2, 0x94, 0xbd, 0x10, + 0x11, 0x9c, 0x81, 0xea, 0x13, 0x6c, 0x2d, 0x55, 0x8b, 0x50, 0xac, 0x78, 0xe1, 0x5d, 0x66, 0xfa, + 0xef, 0x18, 0x9d, 0xe4, 0x1f, 0x32, 0xff, 0x2c, 0xea, 0xa5, 0xaf, 0xe0, 0xfb, 0x78, 0xed, 0xa5, + 0xe0, 0x0b, 0xc8, 0xe2, 0x83, 0x48, 0x92, 0xc9, 0xe8, 0xd8, 0xab, 0xcd, 0x39, 0xe7, 0xdb, 0x43, + 0x98, 0x13, 0x36, 0x6f, 0xc0, 0x6e, 0xc0, 0x66, 0x1b, 0xb0, 0x8d, 0x42, 0x13, 0x7f, 0xd3, 0xda, + 0x22, 0x21, 0x1f, 0x77, 0x72, 0x36, 0x2f, 0x11, 0xcb, 0x0a, 0x32, 0x59, 0xab, 0x4c, 0x1a, 0x83, + 0x24, 0x49, 0xa1, 0x69, 0x02, 0x36, 0xbb, 0xd7, 0xa5, 0x5e, 0xe5, 0xed, 0x3a, 0x03, 0x5d, 0xd3, + 0xa7, 0x10, 0x2e, 0xbf, 0xed, 0xb2, 0xe9, 0x9b, 0x50, 0xf3, 0x12, 0x9a, 0x46, 0x96, 0xc0, 0x05, + 0x1b, 0x77, 0x8e, 0x48, 0x8e, 0x92, 0x07, 0xfb, 0xaf, 0xa2, 0xe4, 0x73, 0xb6, 0xbf, 0x6a, 0x55, + 0x75, 0xf5, 0x54, 0x12, 0x88, 0x1d, 0x9f, 0xfd, 0x35, 0x5c, 0x7a, 0xa6, 0xe8, 0x04, 0xb5, 0x56, + 0x24, 0x76, 0x43, 0xda, 0x1b, 0xfc, 0x90, 0x8d, 0xce, 0x14, 0xbd, 0x96, 0xa5, 0xb8, 0xe1, 0xa3, + 0x4e, 0xf1, 0x25, 0x9b, 0xb8, 0x93, 0x05, 0xb8, 0x24, 0x57, 0x7b, 0xd3, 0xa7, 0x03, 0xcf, 0x37, + 0x63, 0xbc, 0xd3, 0xa8, 0x6b, 0x8e, 0x06, 0x9f, 0xb1, 0xbd, 0x13, 0xd4, 0xb5, 0xaa, 0xc0, 0x8a, + 0xb1, 0x0f, 0x7b, 0xed, 0xb2, 0x8b, 0x4a, 0xd2, 0x1a, 0xad, 0x16, 0x7b, 0x21, 0x8b, 0x9a, 0x3f, + 0x64, 0xb7, 0xcf, 0xdb, 0x86, 0x50, 0xab, 0xcf, 0x10, 0xcb, 0x99, 0x67, 0xae, 0xf9, 0xfc, 0x88, + 0x1d, 0x3c, 0x83, 0x4a, 0x47, 0xec, 0xc0, 0x63, 0xff, 0x5a, 0xfc, 0x3e, 0x9b, 0x9e, 0xb7, 0x39, + 0x14, 0x54, 0x45, 0x68, 0xe2, 0xa1, 0xff, 0x5c, 0xc7, 0xbd, 0x68, 0xd0, 0x18, 0xa0, 0xc8, 0xdd, + 0x0a, 0xdc, 0xd0, 0x75, 0xdc, 0xe9, 0x47, 0xb2, 0xd2, 0x7f, 0xdf, 0xe7, 0x66, 0x8d, 0x62, 0x1a, + 0xb8, 0xa1, 0x7b, 0x9c, 0xf7, 0xfb, 0x5d, 0x82, 0xdd, 0xa8, 0x02, 0xf8, 0x45, 0xbf, 0x1f, 0x3f, + 0x4c, 0xc3, 0xf6, 0x69, 0xdc, 0x3e, 0x3d, 0x75, 0xdb, 0xcf, 0xee, 0xa6, 0xf1, 0x25, 0x0d, 0xb7, + 0x5f, 0xde, 0xf9, 0xf2, 0xf3, 0xf7, 0xd7, 0x9d, 0x29, 0x9f, 0xf8, 0xb7, 0xd4, 0x41, 0xab, 0xd5, + 0xf7, 0xed, 0x22, 0xf9, 0xb1, 0x5d, 0x24, 0xbf, 0xb6, 0x8b, 0xe4, 0xed, 0x93, 0x52, 0xd1, 0xbb, + 0x36, 0x4f, 0x0b, 0xd4, 0x99, 0xb4, 0x25, 0xd6, 0x16, 0xdf, 0xfb, 0xc3, 0xa3, 0xe2, 0x2a, 0xdb, + 0x1c, 0x67, 0xf5, 0x87, 0xd2, 0xfd, 0xbb, 0xa8, 0x14, 0x18, 0x8a, 0x1d, 0xf9, 0xc8, 0x5f, 0xe1, + 0xf1, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd2, 0x21, 0xc0, 0xd1, 0xd3, 0x02, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -309,6 +318,13 @@ func (m *VersionMessage) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if len(m.ExtraBuildInfo) > 0 { + i -= len(m.ExtraBuildInfo) + copy(dAtA[i:], m.ExtraBuildInfo) + i = encodeVarintVersion(dAtA, i, uint64(len(m.ExtraBuildInfo))) + i-- + dAtA[i] = 0x72 + } if len(m.JsonnetVersion) > 0 { i -= len(m.JsonnetVersion) copy(dAtA[i:], m.JsonnetVersion) @@ -461,6 +477,10 @@ func (m *VersionMessage) Size() (n int) { if l > 0 { n += 1 + l + sovVersion(uint64(l)) } + l = len(m.ExtraBuildInfo) + if l > 0 { + n += 1 + l + sovVersion(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -886,6 +906,38 @@ func (m *VersionMessage) Unmarshal(dAtA []byte) error { } m.JsonnetVersion = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 14: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ExtraBuildInfo", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowVersion + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthVersion + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthVersion + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ExtraBuildInfo = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipVersion(dAtA[iNdEx:]) diff --git a/reposerver/apiclient/mocks/RepoServerServiceClient.go b/reposerver/apiclient/mocks/RepoServerServiceClient.go index d5aa772a02384..25337c53a6373 100644 --- a/reposerver/apiclient/mocks/RepoServerServiceClient.go +++ b/reposerver/apiclient/mocks/RepoServerServiceClient.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.14.1. DO NOT EDIT. +// Code generated by mockery v2.21.1. DO NOT EDIT. package mocks @@ -33,6 +33,10 @@ func (_m *RepoServerServiceClient) GenerateManifest(ctx context.Context, in *api ret := _m.Called(_ca...) var r0 *apiclient.ManifestResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *apiclient.ManifestRequest, ...grpc.CallOption) (*apiclient.ManifestResponse, error)); ok { + return rf(ctx, in, opts...) + } if rf, ok := ret.Get(0).(func(context.Context, *apiclient.ManifestRequest, ...grpc.CallOption) *apiclient.ManifestResponse); ok { r0 = rf(ctx, in, opts...) } else { @@ -41,7 +45,6 @@ func (_m *RepoServerServiceClient) GenerateManifest(ctx context.Context, in *api } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *apiclient.ManifestRequest, ...grpc.CallOption) error); ok { r1 = rf(ctx, in, opts...) } else { @@ -63,6 +66,10 @@ func (_m *RepoServerServiceClient) GenerateManifestWithFiles(ctx context.Context ret := _m.Called(_ca...) var r0 apiclient.RepoServerService_GenerateManifestWithFilesClient + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, ...grpc.CallOption) (apiclient.RepoServerService_GenerateManifestWithFilesClient, error)); ok { + return rf(ctx, opts...) + } if rf, ok := ret.Get(0).(func(context.Context, ...grpc.CallOption) apiclient.RepoServerService_GenerateManifestWithFilesClient); ok { r0 = rf(ctx, opts...) } else { @@ -71,7 +78,6 @@ func (_m *RepoServerServiceClient) GenerateManifestWithFiles(ctx context.Context } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, ...grpc.CallOption) error); ok { r1 = rf(ctx, opts...) } else { @@ -93,6 +99,10 @@ func (_m *RepoServerServiceClient) GetAppDetails(ctx context.Context, in *apicli ret := _m.Called(_ca...) var r0 *apiclient.RepoAppDetailsResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *apiclient.RepoServerAppDetailsQuery, ...grpc.CallOption) (*apiclient.RepoAppDetailsResponse, error)); ok { + return rf(ctx, in, opts...) + } if rf, ok := ret.Get(0).(func(context.Context, *apiclient.RepoServerAppDetailsQuery, ...grpc.CallOption) *apiclient.RepoAppDetailsResponse); ok { r0 = rf(ctx, in, opts...) } else { @@ -101,7 +111,6 @@ func (_m *RepoServerServiceClient) GetAppDetails(ctx context.Context, in *apicli } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *apiclient.RepoServerAppDetailsQuery, ...grpc.CallOption) error); ok { r1 = rf(ctx, in, opts...) } else { @@ -111,6 +120,72 @@ func (_m *RepoServerServiceClient) GetAppDetails(ctx context.Context, in *apicli return r0, r1 } +// GetGitDirectories provides a mock function with given fields: ctx, in, opts +func (_m *RepoServerServiceClient) GetGitDirectories(ctx context.Context, in *apiclient.GitDirectoriesRequest, opts ...grpc.CallOption) (*apiclient.GitDirectoriesResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *apiclient.GitDirectoriesResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *apiclient.GitDirectoriesRequest, ...grpc.CallOption) (*apiclient.GitDirectoriesResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *apiclient.GitDirectoriesRequest, ...grpc.CallOption) *apiclient.GitDirectoriesResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*apiclient.GitDirectoriesResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *apiclient.GitDirectoriesRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetGitFiles provides a mock function with given fields: ctx, in, opts +func (_m *RepoServerServiceClient) GetGitFiles(ctx context.Context, in *apiclient.GitFilesRequest, opts ...grpc.CallOption) (*apiclient.GitFilesResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *apiclient.GitFilesResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *apiclient.GitFilesRequest, ...grpc.CallOption) (*apiclient.GitFilesResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *apiclient.GitFilesRequest, ...grpc.CallOption) *apiclient.GitFilesResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*apiclient.GitFilesResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *apiclient.GitFilesRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // GetHelmCharts provides a mock function with given fields: ctx, in, opts func (_m *RepoServerServiceClient) GetHelmCharts(ctx context.Context, in *apiclient.HelmChartsRequest, opts ...grpc.CallOption) (*apiclient.HelmChartsResponse, error) { _va := make([]interface{}, len(opts)) @@ -123,6 +198,10 @@ func (_m *RepoServerServiceClient) GetHelmCharts(ctx context.Context, in *apicli ret := _m.Called(_ca...) var r0 *apiclient.HelmChartsResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *apiclient.HelmChartsRequest, ...grpc.CallOption) (*apiclient.HelmChartsResponse, error)); ok { + return rf(ctx, in, opts...) + } if rf, ok := ret.Get(0).(func(context.Context, *apiclient.HelmChartsRequest, ...grpc.CallOption) *apiclient.HelmChartsResponse); ok { r0 = rf(ctx, in, opts...) } else { @@ -131,7 +210,6 @@ func (_m *RepoServerServiceClient) GetHelmCharts(ctx context.Context, in *apicli } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *apiclient.HelmChartsRequest, ...grpc.CallOption) error); ok { r1 = rf(ctx, in, opts...) } else { @@ -183,6 +261,10 @@ func (_m *RepoServerServiceClient) GetRevisionMetadata(ctx context.Context, in * ret := _m.Called(_ca...) var r0 *v1alpha1.RevisionMetadata + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *apiclient.RepoServerRevisionMetadataRequest, ...grpc.CallOption) (*v1alpha1.RevisionMetadata, error)); ok { + return rf(ctx, in, opts...) + } if rf, ok := ret.Get(0).(func(context.Context, *apiclient.RepoServerRevisionMetadataRequest, ...grpc.CallOption) *v1alpha1.RevisionMetadata); ok { r0 = rf(ctx, in, opts...) } else { @@ -191,7 +273,6 @@ func (_m *RepoServerServiceClient) GetRevisionMetadata(ctx context.Context, in * } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *apiclient.RepoServerRevisionMetadataRequest, ...grpc.CallOption) error); ok { r1 = rf(ctx, in, opts...) } else { @@ -213,6 +294,10 @@ func (_m *RepoServerServiceClient) ListApps(ctx context.Context, in *apiclient.L ret := _m.Called(_ca...) var r0 *apiclient.AppList + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *apiclient.ListAppsRequest, ...grpc.CallOption) (*apiclient.AppList, error)); ok { + return rf(ctx, in, opts...) + } if rf, ok := ret.Get(0).(func(context.Context, *apiclient.ListAppsRequest, ...grpc.CallOption) *apiclient.AppList); ok { r0 = rf(ctx, in, opts...) } else { @@ -221,7 +306,6 @@ func (_m *RepoServerServiceClient) ListApps(ctx context.Context, in *apiclient.L } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *apiclient.ListAppsRequest, ...grpc.CallOption) error); ok { r1 = rf(ctx, in, opts...) } else { @@ -243,6 +327,10 @@ func (_m *RepoServerServiceClient) ListPlugins(ctx context.Context, in *emptypb. ret := _m.Called(_ca...) var r0 *apiclient.PluginList + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *emptypb.Empty, ...grpc.CallOption) (*apiclient.PluginList, error)); ok { + return rf(ctx, in, opts...) + } if rf, ok := ret.Get(0).(func(context.Context, *emptypb.Empty, ...grpc.CallOption) *apiclient.PluginList); ok { r0 = rf(ctx, in, opts...) } else { @@ -251,7 +339,6 @@ func (_m *RepoServerServiceClient) ListPlugins(ctx context.Context, in *emptypb. } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *emptypb.Empty, ...grpc.CallOption) error); ok { r1 = rf(ctx, in, opts...) } else { @@ -273,6 +360,10 @@ func (_m *RepoServerServiceClient) ListRefs(ctx context.Context, in *apiclient.L ret := _m.Called(_ca...) var r0 *apiclient.Refs + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *apiclient.ListRefsRequest, ...grpc.CallOption) (*apiclient.Refs, error)); ok { + return rf(ctx, in, opts...) + } if rf, ok := ret.Get(0).(func(context.Context, *apiclient.ListRefsRequest, ...grpc.CallOption) *apiclient.Refs); ok { r0 = rf(ctx, in, opts...) } else { @@ -281,7 +372,6 @@ func (_m *RepoServerServiceClient) ListRefs(ctx context.Context, in *apiclient.L } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *apiclient.ListRefsRequest, ...grpc.CallOption) error); ok { r1 = rf(ctx, in, opts...) } else { @@ -303,6 +393,10 @@ func (_m *RepoServerServiceClient) ResolveRevision(ctx context.Context, in *apic ret := _m.Called(_ca...) var r0 *apiclient.ResolveRevisionResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *apiclient.ResolveRevisionRequest, ...grpc.CallOption) (*apiclient.ResolveRevisionResponse, error)); ok { + return rf(ctx, in, opts...) + } if rf, ok := ret.Get(0).(func(context.Context, *apiclient.ResolveRevisionRequest, ...grpc.CallOption) *apiclient.ResolveRevisionResponse); ok { r0 = rf(ctx, in, opts...) } else { @@ -311,7 +405,6 @@ func (_m *RepoServerServiceClient) ResolveRevision(ctx context.Context, in *apic } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *apiclient.ResolveRevisionRequest, ...grpc.CallOption) error); ok { r1 = rf(ctx, in, opts...) } else { @@ -333,6 +426,10 @@ func (_m *RepoServerServiceClient) TestRepository(ctx context.Context, in *apicl ret := _m.Called(_ca...) var r0 *apiclient.TestRepositoryResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *apiclient.TestRepositoryRequest, ...grpc.CallOption) (*apiclient.TestRepositoryResponse, error)); ok { + return rf(ctx, in, opts...) + } if rf, ok := ret.Get(0).(func(context.Context, *apiclient.TestRepositoryRequest, ...grpc.CallOption) *apiclient.TestRepositoryResponse); ok { r0 = rf(ctx, in, opts...) } else { @@ -341,7 +438,6 @@ func (_m *RepoServerServiceClient) TestRepository(ctx context.Context, in *apicl } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *apiclient.TestRepositoryRequest, ...grpc.CallOption) error); ok { r1 = rf(ctx, in, opts...) } else { diff --git a/reposerver/apiclient/repository.pb.go b/reposerver/apiclient/repository.pb.go index 00ee36ba97347..3e9eab42178c2 100644 --- a/reposerver/apiclient/repository.pb.go +++ b/reposerver/apiclient/repository.pb.go @@ -1885,6 +1885,236 @@ func (m *HelmChartsResponse) GetItems() []*HelmChart { return nil } +type GitFilesRequest struct { + Repo *v1alpha1.Repository `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"` + SubmoduleEnabled bool `protobuf:"varint,2,opt,name=submoduleEnabled,proto3" json:"submoduleEnabled,omitempty"` + Revision string `protobuf:"bytes,3,opt,name=revision,proto3" json:"revision,omitempty"` + Path string `protobuf:"bytes,4,opt,name=path,proto3" json:"path,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GitFilesRequest) Reset() { *m = GitFilesRequest{} } +func (m *GitFilesRequest) String() string { return proto.CompactTextString(m) } +func (*GitFilesRequest) ProtoMessage() {} +func (*GitFilesRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_dd8723cfcc820480, []int{27} +} +func (m *GitFilesRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GitFilesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GitFilesRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GitFilesRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GitFilesRequest.Merge(m, src) +} +func (m *GitFilesRequest) XXX_Size() int { + return m.Size() +} +func (m *GitFilesRequest) XXX_DiscardUnknown() { + xxx_messageInfo_GitFilesRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_GitFilesRequest proto.InternalMessageInfo + +func (m *GitFilesRequest) GetRepo() *v1alpha1.Repository { + if m != nil { + return m.Repo + } + return nil +} + +func (m *GitFilesRequest) GetSubmoduleEnabled() bool { + if m != nil { + return m.SubmoduleEnabled + } + return false +} + +func (m *GitFilesRequest) GetRevision() string { + if m != nil { + return m.Revision + } + return "" +} + +func (m *GitFilesRequest) GetPath() string { + if m != nil { + return m.Path + } + return "" +} + +type GitFilesResponse struct { + // Map consisting of path of the path to its contents in bytes + Map map[string][]byte `protobuf:"bytes,1,rep,name=map,proto3" json:"map,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GitFilesResponse) Reset() { *m = GitFilesResponse{} } +func (m *GitFilesResponse) String() string { return proto.CompactTextString(m) } +func (*GitFilesResponse) ProtoMessage() {} +func (*GitFilesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_dd8723cfcc820480, []int{28} +} +func (m *GitFilesResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GitFilesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GitFilesResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GitFilesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GitFilesResponse.Merge(m, src) +} +func (m *GitFilesResponse) XXX_Size() int { + return m.Size() +} +func (m *GitFilesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_GitFilesResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_GitFilesResponse proto.InternalMessageInfo + +func (m *GitFilesResponse) GetMap() map[string][]byte { + if m != nil { + return m.Map + } + return nil +} + +type GitDirectoriesRequest struct { + Repo *v1alpha1.Repository `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"` + SubmoduleEnabled bool `protobuf:"varint,2,opt,name=submoduleEnabled,proto3" json:"submoduleEnabled,omitempty"` + Revision string `protobuf:"bytes,3,opt,name=revision,proto3" json:"revision,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GitDirectoriesRequest) Reset() { *m = GitDirectoriesRequest{} } +func (m *GitDirectoriesRequest) String() string { return proto.CompactTextString(m) } +func (*GitDirectoriesRequest) ProtoMessage() {} +func (*GitDirectoriesRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_dd8723cfcc820480, []int{29} +} +func (m *GitDirectoriesRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GitDirectoriesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GitDirectoriesRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GitDirectoriesRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GitDirectoriesRequest.Merge(m, src) +} +func (m *GitDirectoriesRequest) XXX_Size() int { + return m.Size() +} +func (m *GitDirectoriesRequest) XXX_DiscardUnknown() { + xxx_messageInfo_GitDirectoriesRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_GitDirectoriesRequest proto.InternalMessageInfo + +func (m *GitDirectoriesRequest) GetRepo() *v1alpha1.Repository { + if m != nil { + return m.Repo + } + return nil +} + +func (m *GitDirectoriesRequest) GetSubmoduleEnabled() bool { + if m != nil { + return m.SubmoduleEnabled + } + return false +} + +func (m *GitDirectoriesRequest) GetRevision() string { + if m != nil { + return m.Revision + } + return "" +} + +type GitDirectoriesResponse struct { + // A set of directory paths + Paths []string `protobuf:"bytes,1,rep,name=paths,proto3" json:"paths,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GitDirectoriesResponse) Reset() { *m = GitDirectoriesResponse{} } +func (m *GitDirectoriesResponse) String() string { return proto.CompactTextString(m) } +func (*GitDirectoriesResponse) ProtoMessage() {} +func (*GitDirectoriesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_dd8723cfcc820480, []int{30} +} +func (m *GitDirectoriesResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GitDirectoriesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GitDirectoriesResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GitDirectoriesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GitDirectoriesResponse.Merge(m, src) +} +func (m *GitDirectoriesResponse) XXX_Size() int { + return m.Size() +} +func (m *GitDirectoriesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_GitDirectoriesResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_GitDirectoriesResponse proto.InternalMessageInfo + +func (m *GitDirectoriesResponse) GetPaths() []string { + if m != nil { + return m.Paths + } + return nil +} + func init() { proto.RegisterType((*ManifestRequest)(nil), "repository.ManifestRequest") proto.RegisterMapType((map[string]bool)(nil), "repository.ManifestRequest.EnabledSourceTypesEntry") @@ -1920,6 +2150,11 @@ func init() { proto.RegisterType((*HelmChartsRequest)(nil), "repository.HelmChartsRequest") proto.RegisterType((*HelmChart)(nil), "repository.HelmChart") proto.RegisterType((*HelmChartsResponse)(nil), "repository.HelmChartsResponse") + proto.RegisterType((*GitFilesRequest)(nil), "repository.GitFilesRequest") + proto.RegisterType((*GitFilesResponse)(nil), "repository.GitFilesResponse") + proto.RegisterMapType((map[string][]byte)(nil), "repository.GitFilesResponse.MapEntry") + proto.RegisterType((*GitDirectoriesRequest)(nil), "repository.GitDirectoriesRequest") + proto.RegisterType((*GitDirectoriesResponse)(nil), "repository.GitDirectoriesResponse") } func init() { @@ -1927,128 +2162,136 @@ func init() { } var fileDescriptor_dd8723cfcc820480 = []byte{ - // 1929 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x59, 0xdd, 0x6e, 0x1b, 0xc7, - 0x15, 0xe6, 0x92, 0x94, 0x44, 0x1e, 0xd9, 0x96, 0x34, 0xb6, 0xa5, 0x35, 0xe3, 0x08, 0xca, 0xb6, - 0x31, 0xd4, 0x38, 0x59, 0x42, 0x32, 0x92, 0x14, 0x4e, 0x9b, 0x42, 0x51, 0x6c, 0xcb, 0xb5, 0x65, - 0xab, 0x6b, 0xb7, 0x45, 0x5a, 0xb7, 0xc5, 0x68, 0x39, 0x5c, 0x4e, 0xb8, 0x3f, 0xe3, 0xdd, 0x59, - 0x16, 0x34, 0xd0, 0x8b, 0x02, 0x45, 0x1f, 0xa1, 0x28, 0xfa, 0x00, 0x7d, 0x83, 0xa2, 0x97, 0xbd, - 0xea, 0xcf, 0x65, 0xd1, 0x17, 0x68, 0xe1, 0x27, 0x29, 0x66, 0x76, 0xf6, 0x97, 0x2b, 0xd9, 0x01, - 0x65, 0xe5, 0x22, 0x37, 0xd2, 0xce, 0xcc, 0xf9, 0x9b, 0x33, 0x67, 0xce, 0xf9, 0xce, 0x10, 0x6e, - 0x84, 0x84, 0x05, 0x11, 0x09, 0x27, 0x24, 0xec, 0xcb, 0x4f, 0xca, 0x83, 0x70, 0x5a, 0xf8, 0x34, - 0x59, 0x18, 0xf0, 0x00, 0x41, 0x3e, 0xd3, 0x7b, 0xe8, 0x50, 0x3e, 0x8a, 0x8f, 0x4d, 0x3b, 0xf0, - 0xfa, 0x38, 0x74, 0x02, 0x16, 0x06, 0x5f, 0xca, 0x8f, 0x0f, 0xec, 0x41, 0x7f, 0xb2, 0xdb, 0x67, - 0x63, 0xa7, 0x8f, 0x19, 0x8d, 0xfa, 0x98, 0x31, 0x97, 0xda, 0x98, 0xd3, 0xc0, 0xef, 0x4f, 0x76, - 0xb0, 0xcb, 0x46, 0x78, 0xa7, 0xef, 0x10, 0x9f, 0x84, 0x98, 0x93, 0x41, 0x22, 0xb9, 0xf7, 0x96, - 0x13, 0x04, 0x8e, 0x4b, 0xfa, 0x72, 0x74, 0x1c, 0x0f, 0xfb, 0xc4, 0x63, 0x5c, 0xa9, 0x35, 0xfe, - 0x78, 0x01, 0x56, 0x0e, 0xb1, 0x4f, 0x87, 0x24, 0xe2, 0x16, 0x79, 0x1e, 0x93, 0x88, 0xa3, 0x67, - 0xd0, 0x16, 0xc6, 0xe8, 0xda, 0x96, 0xb6, 0xbd, 0xbc, 0x7b, 0x60, 0xe6, 0xd6, 0x98, 0xa9, 0x35, - 0xf2, 0xe3, 0x57, 0xf6, 0xc0, 0x9c, 0xec, 0x9a, 0x6c, 0xec, 0x98, 0xc2, 0x1a, 0xb3, 0x60, 0x8d, - 0x99, 0x5a, 0x63, 0x5a, 0xd9, 0xb6, 0x2c, 0x29, 0x15, 0xf5, 0xa0, 0x13, 0x92, 0x09, 0x8d, 0x68, - 0xe0, 0xeb, 0xcd, 0x2d, 0x6d, 0xbb, 0x6b, 0x65, 0x63, 0xa4, 0xc3, 0x92, 0x1f, 0xec, 0x63, 0x7b, - 0x44, 0xf4, 0xd6, 0x96, 0xb6, 0xdd, 0xb1, 0xd2, 0x21, 0xda, 0x82, 0x65, 0xcc, 0xd8, 0x43, 0x7c, - 0x4c, 0xdc, 0x07, 0x64, 0xaa, 0xb7, 0x25, 0x63, 0x71, 0x4a, 0xf0, 0x62, 0xc6, 0x1e, 0x61, 0x8f, - 0xe8, 0x0b, 0x72, 0x35, 0x1d, 0xa2, 0xeb, 0xd0, 0xf5, 0xb1, 0x47, 0x22, 0x86, 0x6d, 0xa2, 0x77, - 0xe4, 0x5a, 0x3e, 0x81, 0x7e, 0x03, 0x6b, 0x05, 0xc3, 0x9f, 0x04, 0x71, 0x68, 0x13, 0x1d, 0xe4, - 0xd6, 0x1f, 0xcf, 0xb7, 0xf5, 0xbd, 0xaa, 0x58, 0x6b, 0x56, 0x13, 0xfa, 0x25, 0x2c, 0xc8, 0x93, - 0xd7, 0x97, 0xb7, 0x5a, 0x67, 0xea, 0xed, 0x44, 0x2c, 0xf2, 0x61, 0x89, 0xb9, 0xb1, 0x43, 0xfd, - 0x48, 0xbf, 0x20, 0x35, 0x3c, 0x9d, 0x4f, 0xc3, 0x7e, 0xe0, 0x0f, 0xa9, 0x73, 0x88, 0x7d, 0xec, - 0x10, 0x8f, 0xf8, 0xfc, 0x48, 0x0a, 0xb7, 0x52, 0x25, 0xe8, 0x05, 0xac, 0x8e, 0xe3, 0x88, 0x07, - 0x1e, 0x7d, 0x41, 0x1e, 0x33, 0xc1, 0x1b, 0xe9, 0x17, 0xa5, 0x37, 0x1f, 0xcd, 0xa7, 0xf8, 0x41, - 0x45, 0xaa, 0x35, 0xa3, 0x47, 0x04, 0xc9, 0x38, 0x3e, 0x26, 0x3f, 0x21, 0xa1, 0x8c, 0xae, 0x4b, - 0x49, 0x90, 0x14, 0xa6, 0x92, 0x30, 0xa2, 0x6a, 0x14, 0xe9, 0x2b, 0x5b, 0xad, 0x24, 0x8c, 0xb2, - 0x29, 0xb4, 0x0d, 0x2b, 0x13, 0x12, 0xd2, 0xe1, 0xf4, 0x09, 0x75, 0x7c, 0xcc, 0xe3, 0x90, 0xe8, - 0xab, 0x32, 0x14, 0xab, 0xd3, 0xc8, 0x83, 0x8b, 0x23, 0xe2, 0x7a, 0xc2, 0xe5, 0xfb, 0x21, 0x19, - 0x44, 0xfa, 0x9a, 0xf4, 0xef, 0xbd, 0xf9, 0x4f, 0x50, 0x8a, 0xb3, 0xca, 0xd2, 0x85, 0x61, 0x7e, - 0x60, 0xa9, 0x9b, 0x92, 0xdc, 0x11, 0x94, 0x18, 0x56, 0x99, 0x46, 0x37, 0xe0, 0x12, 0x0f, 0xb1, - 0x3d, 0xa6, 0xbe, 0x73, 0x48, 0xf8, 0x28, 0x18, 0xe8, 0x97, 0xa5, 0x27, 0x2a, 0xb3, 0xc8, 0x06, - 0x44, 0x7c, 0x7c, 0xec, 0x92, 0x41, 0x12, 0x8b, 0x4f, 0xa7, 0x8c, 0x44, 0xfa, 0x15, 0xb9, 0x8b, - 0x5b, 0x66, 0x21, 0x43, 0x55, 0x12, 0x84, 0x79, 0x67, 0x86, 0xeb, 0x8e, 0xcf, 0xc3, 0xa9, 0x55, - 0x23, 0x0e, 0x8d, 0x61, 0x59, 0xec, 0x23, 0x0d, 0x85, 0xab, 0x32, 0x14, 0xee, 0xcf, 0xe7, 0xa3, - 0x83, 0x5c, 0xa0, 0x55, 0x94, 0x8e, 0x4c, 0x40, 0x23, 0x1c, 0x1d, 0xc6, 0x2e, 0xa7, 0xcc, 0x25, - 0x89, 0x19, 0x91, 0xbe, 0x2e, 0xdd, 0x54, 0xb3, 0x82, 0x1e, 0x00, 0x84, 0x64, 0x98, 0xd2, 0x6d, - 0xc8, 0x9d, 0xdf, 0x3c, 0x6d, 0xe7, 0x56, 0x46, 0x9d, 0xec, 0xb8, 0xc0, 0xde, 0xbb, 0x03, 0x1b, - 0x27, 0x38, 0x06, 0xad, 0x42, 0x6b, 0x4c, 0xa6, 0x32, 0xa1, 0x76, 0x2d, 0xf1, 0x89, 0xae, 0xc0, - 0xc2, 0x04, 0xbb, 0x31, 0x91, 0x29, 0xb0, 0x63, 0x25, 0x83, 0xdb, 0xcd, 0xef, 0x6a, 0xbd, 0xdf, - 0x6b, 0xb0, 0x52, 0x51, 0x53, 0xc3, 0xff, 0x8b, 0x22, 0xff, 0x19, 0x04, 0xdd, 0xf0, 0x29, 0x0e, - 0x1d, 0xc2, 0x0b, 0x86, 0x18, 0xff, 0xd1, 0x40, 0xaf, 0xec, 0xff, 0xa7, 0x94, 0x8f, 0xee, 0x52, - 0x97, 0x44, 0xe8, 0x63, 0x58, 0x0a, 0x93, 0x39, 0x55, 0x26, 0xde, 0x3a, 0xc5, 0x6d, 0x07, 0x0d, - 0x2b, 0xa5, 0x46, 0x9f, 0x42, 0xc7, 0x23, 0x1c, 0x0f, 0x30, 0xc7, 0xca, 0xf6, 0xad, 0x3a, 0x4e, - 0xa1, 0xe5, 0x50, 0xd1, 0x1d, 0x34, 0xac, 0x8c, 0x07, 0x7d, 0x08, 0x0b, 0xf6, 0x28, 0xf6, 0xc7, - 0xb2, 0x40, 0x2c, 0xef, 0xbe, 0x7d, 0x12, 0xf3, 0xbe, 0x20, 0x3a, 0x68, 0x58, 0x09, 0xf5, 0x67, - 0x8b, 0xd0, 0x66, 0x38, 0xe4, 0xc6, 0x5d, 0xb8, 0x52, 0xa7, 0x42, 0x54, 0x25, 0x7b, 0x44, 0xec, - 0x71, 0x14, 0x7b, 0xca, 0xcd, 0xd9, 0x18, 0x21, 0x68, 0x47, 0xf4, 0x45, 0xe2, 0xea, 0x96, 0x25, - 0xbf, 0x8d, 0xef, 0xc0, 0xda, 0x8c, 0x36, 0x71, 0xa8, 0x89, 0x6d, 0x42, 0xc2, 0x05, 0xa5, 0xda, - 0x88, 0xe1, 0xea, 0x53, 0xe9, 0x8b, 0x2c, 0x35, 0x9f, 0x47, 0x9d, 0x35, 0x0e, 0x60, 0xbd, 0xaa, - 0x36, 0x62, 0x81, 0x1f, 0x11, 0x71, 0x4b, 0x64, 0x2e, 0xa3, 0x64, 0x90, 0xaf, 0x4a, 0x2b, 0x3a, - 0x56, 0xcd, 0x8a, 0xf1, 0xdb, 0x26, 0xac, 0x5b, 0x24, 0x0a, 0xdc, 0x09, 0x49, 0x13, 0xcd, 0xf9, - 0x40, 0x85, 0x9f, 0x43, 0x0b, 0x33, 0xa6, 0xc2, 0xe4, 0xfe, 0x99, 0x15, 0x63, 0x4b, 0x48, 0x45, - 0xef, 0xc3, 0x1a, 0xf6, 0x8e, 0xa9, 0x13, 0x07, 0x71, 0x94, 0x6e, 0x4b, 0x06, 0x55, 0xd7, 0x9a, - 0x5d, 0x30, 0x6c, 0xd8, 0x98, 0x71, 0x81, 0x72, 0x67, 0x11, 0xd0, 0x68, 0x15, 0x40, 0x53, 0xab, - 0xa4, 0x79, 0x92, 0x92, 0x7f, 0x68, 0xb0, 0x9a, 0x5f, 0x1d, 0x25, 0xfe, 0x3a, 0x74, 0x3d, 0x35, - 0x17, 0xe9, 0x9a, 0x2c, 0x58, 0xf9, 0x44, 0x19, 0xdb, 0x34, 0xab, 0xd8, 0x66, 0x1d, 0x16, 0x13, - 0xe8, 0xa9, 0x36, 0xa6, 0x46, 0x25, 0x93, 0xdb, 0x15, 0x93, 0x37, 0x01, 0xa2, 0x2c, 0x7f, 0xe9, - 0x8b, 0x72, 0xb5, 0x30, 0x83, 0x0c, 0xb8, 0x90, 0x54, 0x42, 0x8b, 0x44, 0xb1, 0xcb, 0xf5, 0x25, - 0x49, 0x51, 0x9a, 0x33, 0x02, 0x58, 0x79, 0x48, 0xc5, 0x1e, 0x86, 0xd1, 0xf9, 0x04, 0xfb, 0x47, - 0xd0, 0x16, 0xca, 0xc4, 0xc6, 0x8e, 0x43, 0xec, 0xdb, 0x23, 0x92, 0xfa, 0x2a, 0x1b, 0x8b, 0x6b, - 0xcc, 0xb1, 0x13, 0xe9, 0x4d, 0x39, 0x2f, 0xbf, 0x8d, 0xbf, 0x36, 0x13, 0x4b, 0xf7, 0x18, 0x8b, - 0xbe, 0x7e, 0xf8, 0x5b, 0x5f, 0x90, 0x5b, 0xb3, 0x05, 0xb9, 0x62, 0xf2, 0x57, 0x29, 0xc8, 0x67, - 0x54, 0xa6, 0x8c, 0x18, 0x96, 0xf6, 0x18, 0x13, 0x86, 0xa0, 0x1d, 0x68, 0x63, 0xc6, 0x12, 0x87, - 0x57, 0x32, 0xb2, 0x22, 0x11, 0xff, 0x95, 0x49, 0x92, 0xb4, 0xf7, 0x31, 0x74, 0xb3, 0xa9, 0x57, - 0xa9, 0xed, 0x16, 0xd5, 0x6e, 0x01, 0x24, 0x88, 0xf3, 0xbe, 0x3f, 0x0c, 0xc4, 0x91, 0x8a, 0x60, - 0x57, 0xac, 0xf2, 0xdb, 0xb8, 0x9d, 0x52, 0x48, 0xdb, 0xde, 0x87, 0x05, 0xca, 0x89, 0x97, 0x1a, - 0xb7, 0x5e, 0x34, 0x2e, 0x17, 0x64, 0x25, 0x44, 0xc6, 0x3f, 0x3b, 0x70, 0x4d, 0x9c, 0xd8, 0x13, - 0x79, 0x4d, 0xf6, 0x18, 0xfb, 0x9c, 0x70, 0x4c, 0xdd, 0xe8, 0x47, 0x31, 0x09, 0xa7, 0x6f, 0x38, - 0x30, 0x1c, 0x58, 0x4c, 0x6e, 0x99, 0xca, 0x77, 0x67, 0xde, 0x7c, 0x28, 0xf1, 0x79, 0xc7, 0xd1, - 0x7a, 0x33, 0x1d, 0x47, 0x5d, 0x07, 0xd0, 0x3e, 0xa7, 0x0e, 0xe0, 0xe4, 0x26, 0xb0, 0xd0, 0x5a, - 0x2e, 0x96, 0x5b, 0xcb, 0x1a, 0x60, 0xbd, 0xf4, 0xba, 0xc0, 0xba, 0x53, 0x0b, 0xac, 0xbd, 0xda, - 0x7b, 0xdc, 0x95, 0xee, 0xfe, 0x7e, 0x31, 0x02, 0x4f, 0x8c, 0xb5, 0x79, 0x20, 0x36, 0xbc, 0x51, - 0x88, 0xfd, 0xe3, 0x12, 0x64, 0x4e, 0x9a, 0xd6, 0x0f, 0x5f, 0x6f, 0x4f, 0xdf, 0x24, 0xf0, 0xfc, - 0x3b, 0x89, 0x99, 0x58, 0x90, 0xfb, 0x20, 0x2b, 0xe8, 0xa2, 0x0e, 0x89, 0xd2, 0xaa, 0x92, 0x96, - 0xf8, 0x46, 0x37, 0xa1, 0x2d, 0x9c, 0xac, 0x40, 0xed, 0x46, 0xd1, 0x9f, 0xe2, 0x24, 0xf6, 0x18, - 0x7b, 0xc2, 0x88, 0x6d, 0x49, 0x22, 0x74, 0x1b, 0xba, 0x59, 0xe0, 0xab, 0x9b, 0x75, 0xbd, 0xc8, - 0x91, 0xdd, 0x93, 0x94, 0x2d, 0x27, 0x17, 0xbc, 0x03, 0x1a, 0x12, 0x5b, 0x42, 0xbe, 0x85, 0x59, - 0xde, 0xcf, 0xd3, 0xc5, 0x8c, 0x37, 0x23, 0x47, 0x3b, 0xb0, 0x98, 0x74, 0xf9, 0xf2, 0x06, 0x2d, - 0xef, 0x5e, 0x9b, 0x4d, 0xa6, 0x29, 0x97, 0x22, 0x34, 0xfe, 0xae, 0xc1, 0x3b, 0x79, 0x40, 0xa4, - 0xb7, 0x29, 0x45, 0xdd, 0x5f, 0x7f, 0xc5, 0xbd, 0x01, 0x97, 0x24, 0xcc, 0xcf, 0x9b, 0xfd, 0xe4, - 0xdd, 0xa9, 0x32, 0x6b, 0xfc, 0x45, 0x83, 0x77, 0x67, 0xf7, 0xb1, 0x3f, 0xc2, 0x21, 0xcf, 0x8e, - 0xf7, 0x3c, 0xf6, 0x92, 0x16, 0xbc, 0x66, 0x5e, 0xf0, 0x4a, 0xfb, 0x6b, 0x95, 0xf7, 0x67, 0xfc, - 0xad, 0x09, 0xcb, 0x85, 0x00, 0xaa, 0x2b, 0x98, 0x02, 0xf0, 0xc9, 0xb8, 0x95, 0x8d, 0x9d, 0x2c, - 0x0a, 0x5d, 0xab, 0x30, 0x83, 0xc6, 0x00, 0x0c, 0x87, 0xd8, 0x23, 0x9c, 0x84, 0x22, 0x93, 0x8b, - 0x1b, 0xff, 0x60, 0xfe, 0xec, 0x72, 0x94, 0xca, 0xb4, 0x0a, 0xe2, 0x05, 0x62, 0x95, 0xaa, 0x23, - 0x95, 0xbf, 0xd5, 0x08, 0xfd, 0x1a, 0x2e, 0x0d, 0xa9, 0x4b, 0x8e, 0x72, 0x43, 0x16, 0xa5, 0x21, - 0x8f, 0xe7, 0x37, 0xe4, 0x6e, 0x51, 0xae, 0x55, 0x51, 0x63, 0xbc, 0x07, 0xab, 0xd5, 0xfb, 0x24, - 0x8c, 0xa4, 0x1e, 0x76, 0x32, 0x6f, 0xa9, 0x91, 0x81, 0x60, 0xb5, 0x7a, 0x7f, 0x8c, 0xff, 0x36, - 0xe1, 0x6a, 0x26, 0x6e, 0xcf, 0xf7, 0x83, 0xd8, 0xb7, 0xe5, 0xc3, 0x59, 0xed, 0x59, 0x5c, 0x81, - 0x05, 0x4e, 0xb9, 0x9b, 0x01, 0x1f, 0x39, 0x10, 0xb5, 0x8b, 0x07, 0x81, 0xcb, 0x29, 0x53, 0x07, - 0x9c, 0x0e, 0x93, 0xb3, 0x7f, 0x1e, 0xd3, 0x90, 0x0c, 0x64, 0x26, 0xe8, 0x58, 0xd9, 0x58, 0xac, - 0x09, 0x54, 0x23, 0x61, 0x7c, 0xe2, 0xcc, 0x6c, 0x2c, 0xe3, 0x3e, 0x70, 0x5d, 0x62, 0x0b, 0x77, - 0x14, 0x80, 0x7e, 0x65, 0x56, 0x36, 0x10, 0x3c, 0xa4, 0xbe, 0xa3, 0x60, 0xbe, 0x1a, 0x09, 0x3b, - 0x71, 0x18, 0xe2, 0xa9, 0xde, 0x91, 0x0e, 0x48, 0x06, 0xe8, 0x7b, 0xd0, 0xf2, 0x30, 0x53, 0x85, - 0xee, 0xbd, 0x52, 0x76, 0xa8, 0xf3, 0x80, 0x79, 0x88, 0x59, 0x52, 0x09, 0x04, 0x5b, 0xef, 0x23, - 0xe8, 0xa4, 0x13, 0x5f, 0x09, 0x12, 0x7e, 0x09, 0x17, 0x4b, 0xc9, 0x07, 0x7d, 0x01, 0xeb, 0x79, - 0x44, 0x15, 0x15, 0x2a, 0x10, 0xf8, 0xce, 0x2b, 0x2d, 0xb3, 0x4e, 0x10, 0x60, 0x3c, 0x87, 0x35, - 0x11, 0x32, 0xf2, 0xe2, 0x9f, 0x53, 0x6b, 0xf3, 0x09, 0x74, 0x33, 0x95, 0xb5, 0x31, 0xd3, 0x83, - 0xce, 0x24, 0x7d, 0xd0, 0x4c, 0x7a, 0x9b, 0x6c, 0x6c, 0xec, 0x01, 0x2a, 0xda, 0xab, 0x2a, 0xd0, - 0xcd, 0x32, 0x28, 0xbe, 0x5a, 0x2d, 0x37, 0x92, 0x5c, 0x61, 0xe2, 0xdd, 0x3f, 0x77, 0x60, 0x2d, - 0x4f, 0x7d, 0xe2, 0x2f, 0xb5, 0x09, 0x7a, 0x0c, 0xab, 0xf7, 0xd4, 0xef, 0x0c, 0x69, 0xc7, 0x8a, - 0x4e, 0x7b, 0x02, 0xea, 0x5d, 0xaf, 0x5f, 0x4c, 0x2c, 0x32, 0x1a, 0xc8, 0x86, 0x6b, 0x55, 0x81, - 0xf9, 0x6b, 0xd3, 0xb7, 0x4f, 0x91, 0x9c, 0x51, 0xbd, 0x4a, 0xc5, 0xb6, 0x86, 0xbe, 0x80, 0x4b, - 0xe5, 0x37, 0x11, 0x54, 0x8a, 0x85, 0xda, 0x67, 0x9a, 0x9e, 0x71, 0x1a, 0x49, 0x66, 0xff, 0x33, - 0x01, 0x3c, 0x4a, 0x0f, 0x04, 0xc8, 0x28, 0xc3, 0xa2, 0xba, 0x07, 0x94, 0xde, 0xb7, 0x4e, 0xa5, - 0xc9, 0xa4, 0x7f, 0x02, 0x9d, 0xb4, 0xa1, 0x2e, 0xbb, 0xb9, 0xd2, 0x66, 0xf7, 0x56, 0xcb, 0xf2, - 0x86, 0x91, 0xd1, 0x40, 0x9f, 0x26, 0xcc, 0xa2, 0xe1, 0x9a, 0x65, 0x2e, 0xb4, 0x91, 0xbd, 0xcb, - 0x35, 0xad, 0x9b, 0xd1, 0x40, 0x3f, 0x80, 0x65, 0xf1, 0x75, 0xa4, 0x5e, 0xf8, 0xd7, 0xcd, 0xe4, - 0x07, 0x25, 0x33, 0xfd, 0x41, 0xc9, 0xbc, 0xe3, 0x31, 0x3e, 0xed, 0xd5, 0xf4, 0x56, 0x4a, 0xc0, - 0x33, 0xb8, 0x78, 0x8f, 0xf0, 0x1c, 0x0a, 0xa1, 0x77, 0x5f, 0x0b, 0x30, 0xf6, 0x8c, 0x2a, 0xd9, - 0x2c, 0x9a, 0x32, 0x1a, 0xe8, 0x0f, 0x1a, 0x5c, 0xbe, 0x47, 0x78, 0x15, 0x5c, 0xa0, 0x0f, 0xea, - 0x95, 0x9c, 0x00, 0x42, 0x7a, 0x8f, 0xe6, 0xbd, 0xb7, 0x65, 0xb1, 0x46, 0x03, 0xfd, 0x49, 0x83, - 0x8d, 0x82, 0x61, 0x45, 0xb4, 0x80, 0x76, 0x4e, 0x37, 0xae, 0x06, 0x59, 0xf4, 0x7e, 0x38, 0xe7, - 0x0f, 0x37, 0x05, 0x91, 0x46, 0x03, 0x1d, 0xc9, 0x33, 0xc9, 0x93, 0x03, 0x7a, 0xbb, 0x36, 0x0b, - 0x64, 0xda, 0x37, 0x4f, 0x5a, 0x4e, 0xcf, 0xe1, 0xb3, 0xbd, 0x7f, 0xbd, 0xdc, 0xd4, 0xfe, 0xfd, - 0x72, 0x53, 0xfb, 0xdf, 0xcb, 0x4d, 0xed, 0x67, 0xb7, 0x5e, 0xf1, 0x1b, 0x66, 0xe1, 0x67, 0x51, - 0xcc, 0xa8, 0xed, 0x52, 0xe2, 0xf3, 0xe3, 0x45, 0x19, 0x52, 0xb7, 0xfe, 0x1f, 0x00, 0x00, 0xff, - 0xff, 0xe1, 0xc0, 0x48, 0x2d, 0x35, 0x1d, 0x00, 0x00, + // 2061 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x5a, 0x5b, 0x6f, 0x1c, 0x49, + 0x15, 0x9e, 0x9e, 0xf1, 0x65, 0xe6, 0xd8, 0xb1, 0xc7, 0x15, 0x5f, 0x3a, 0xb3, 0x59, 0xcb, 0xdb, + 0x90, 0xc8, 0x24, 0xbb, 0x33, 0xb2, 0xa3, 0xdd, 0xa0, 0x2c, 0x2c, 0xf2, 0x7a, 0x13, 0x3b, 0x9b, + 0x38, 0x31, 0x9d, 0x00, 0x5a, 0x08, 0xa0, 0x72, 0x4f, 0xcd, 0x4c, 0xed, 0xf4, 0x74, 0x57, 0xba, + 0xab, 0x8d, 0x1c, 0x89, 0x07, 0x04, 0xe2, 0x27, 0x20, 0xc4, 0xff, 0x40, 0x3c, 0x21, 0x9e, 0xb8, + 0x48, 0xbc, 0xac, 0xf8, 0x03, 0xa0, 0xfc, 0x12, 0x54, 0x97, 0xbe, 0x4e, 0xdb, 0xc9, 0x32, 0x8e, + 0x57, 0x68, 0x5f, 0x92, 0xae, 0xaa, 0x73, 0xab, 0x53, 0xa7, 0xce, 0xf9, 0x4e, 0x8d, 0xe1, 0x7a, + 0x40, 0x98, 0x1f, 0x92, 0xe0, 0x98, 0x04, 0x1d, 0xf9, 0x49, 0xb9, 0x1f, 0x9c, 0x64, 0x3e, 0xdb, + 0x2c, 0xf0, 0xb9, 0x8f, 0x20, 0x9d, 0x69, 0x3d, 0xec, 0x53, 0x3e, 0x88, 0x8e, 0xda, 0x8e, 0x3f, + 0xea, 0xe0, 0xa0, 0xef, 0xb3, 0xc0, 0xff, 0x5c, 0x7e, 0xbc, 0xe7, 0x74, 0x3b, 0xc7, 0xdb, 0x1d, + 0x36, 0xec, 0x77, 0x30, 0xa3, 0x61, 0x07, 0x33, 0xe6, 0x52, 0x07, 0x73, 0xea, 0x7b, 0x9d, 0xe3, + 0x2d, 0xec, 0xb2, 0x01, 0xde, 0xea, 0xf4, 0x89, 0x47, 0x02, 0xcc, 0x49, 0x57, 0x49, 0x6e, 0xbd, + 0xd5, 0xf7, 0xfd, 0xbe, 0x4b, 0x3a, 0x72, 0x74, 0x14, 0xf5, 0x3a, 0x64, 0xc4, 0xb8, 0x56, 0x6b, + 0xfd, 0x7e, 0x1e, 0x16, 0x0f, 0xb0, 0x47, 0x7b, 0x24, 0xe4, 0x36, 0x79, 0x1e, 0x91, 0x90, 0xa3, + 0x67, 0x30, 0x25, 0x8c, 0x31, 0x8d, 0x0d, 0x63, 0x73, 0x6e, 0x7b, 0xbf, 0x9d, 0x5a, 0xd3, 0x8e, + 0xad, 0x91, 0x1f, 0x3f, 0x77, 0xba, 0xed, 0xe3, 0xed, 0x36, 0x1b, 0xf6, 0xdb, 0xc2, 0x9a, 0x76, + 0xc6, 0x9a, 0x76, 0x6c, 0x4d, 0xdb, 0x4e, 0xb6, 0x65, 0x4b, 0xa9, 0xa8, 0x05, 0xf5, 0x80, 0x1c, + 0xd3, 0x90, 0xfa, 0x9e, 0x59, 0xdd, 0x30, 0x36, 0x1b, 0x76, 0x32, 0x46, 0x26, 0xcc, 0x7a, 0xfe, + 0x2e, 0x76, 0x06, 0xc4, 0xac, 0x6d, 0x18, 0x9b, 0x75, 0x3b, 0x1e, 0xa2, 0x0d, 0x98, 0xc3, 0x8c, + 0x3d, 0xc4, 0x47, 0xc4, 0x7d, 0x40, 0x4e, 0xcc, 0x29, 0xc9, 0x98, 0x9d, 0x12, 0xbc, 0x98, 0xb1, + 0x47, 0x78, 0x44, 0xcc, 0x69, 0xb9, 0x1a, 0x0f, 0xd1, 0x55, 0x68, 0x78, 0x78, 0x44, 0x42, 0x86, + 0x1d, 0x62, 0xd6, 0xe5, 0x5a, 0x3a, 0x81, 0x7e, 0x09, 0x4b, 0x19, 0xc3, 0x9f, 0xf8, 0x51, 0xe0, + 0x10, 0x13, 0xe4, 0xd6, 0x1f, 0x4f, 0xb6, 0xf5, 0x9d, 0xa2, 0x58, 0x7b, 0x5c, 0x13, 0xfa, 0x19, + 0x4c, 0xcb, 0x93, 0x37, 0xe7, 0x36, 0x6a, 0xe7, 0xea, 0x6d, 0x25, 0x16, 0x79, 0x30, 0xcb, 0xdc, + 0xa8, 0x4f, 0xbd, 0xd0, 0x9c, 0x97, 0x1a, 0x9e, 0x4e, 0xa6, 0x61, 0xd7, 0xf7, 0x7a, 0xb4, 0x7f, + 0x80, 0x3d, 0xdc, 0x27, 0x23, 0xe2, 0xf1, 0x43, 0x29, 0xdc, 0x8e, 0x95, 0xa0, 0x17, 0xd0, 0x1c, + 0x46, 0x21, 0xf7, 0x47, 0xf4, 0x05, 0x79, 0xcc, 0x04, 0x6f, 0x68, 0x5e, 0x92, 0xde, 0x7c, 0x34, + 0x99, 0xe2, 0x07, 0x05, 0xa9, 0xf6, 0x98, 0x1e, 0x11, 0x24, 0xc3, 0xe8, 0x88, 0xfc, 0x90, 0x04, + 0x32, 0xba, 0x16, 0x54, 0x90, 0x64, 0xa6, 0x54, 0x18, 0x51, 0x3d, 0x0a, 0xcd, 0xc5, 0x8d, 0x9a, + 0x0a, 0xa3, 0x64, 0x0a, 0x6d, 0xc2, 0xe2, 0x31, 0x09, 0x68, 0xef, 0xe4, 0x09, 0xed, 0x7b, 0x98, + 0x47, 0x01, 0x31, 0x9b, 0x32, 0x14, 0x8b, 0xd3, 0x68, 0x04, 0x97, 0x06, 0xc4, 0x1d, 0x09, 0x97, + 0xef, 0x06, 0xa4, 0x1b, 0x9a, 0x4b, 0xd2, 0xbf, 0x7b, 0x93, 0x9f, 0xa0, 0x14, 0x67, 0xe7, 0xa5, + 0x0b, 0xc3, 0x3c, 0xdf, 0xd6, 0x37, 0x45, 0xdd, 0x11, 0xa4, 0x0c, 0x2b, 0x4c, 0xa3, 0xeb, 0xb0, + 0xc0, 0x03, 0xec, 0x0c, 0xa9, 0xd7, 0x3f, 0x20, 0x7c, 0xe0, 0x77, 0xcd, 0xcb, 0xd2, 0x13, 0x85, + 0x59, 0xe4, 0x00, 0x22, 0x1e, 0x3e, 0x72, 0x49, 0x57, 0xc5, 0xe2, 0xd3, 0x13, 0x46, 0x42, 0x73, + 0x59, 0xee, 0xe2, 0x56, 0x3b, 0x93, 0xa1, 0x0a, 0x09, 0xa2, 0x7d, 0x77, 0x8c, 0xeb, 0xae, 0xc7, + 0x83, 0x13, 0xbb, 0x44, 0x1c, 0x1a, 0xc2, 0x9c, 0xd8, 0x47, 0x1c, 0x0a, 0x2b, 0x32, 0x14, 0xee, + 0x4f, 0xe6, 0xa3, 0xfd, 0x54, 0xa0, 0x9d, 0x95, 0x8e, 0xda, 0x80, 0x06, 0x38, 0x3c, 0x88, 0x5c, + 0x4e, 0x99, 0x4b, 0x94, 0x19, 0xa1, 0xb9, 0x2a, 0xdd, 0x54, 0xb2, 0x82, 0x1e, 0x00, 0x04, 0xa4, + 0x17, 0xd3, 0xad, 0xc9, 0x9d, 0xdf, 0x3c, 0x6b, 0xe7, 0x76, 0x42, 0xad, 0x76, 0x9c, 0x61, 0x6f, + 0xdd, 0x85, 0xb5, 0x53, 0x1c, 0x83, 0x9a, 0x50, 0x1b, 0x92, 0x13, 0x99, 0x50, 0x1b, 0xb6, 0xf8, + 0x44, 0xcb, 0x30, 0x7d, 0x8c, 0xdd, 0x88, 0xc8, 0x14, 0x58, 0xb7, 0xd5, 0xe0, 0x4e, 0xf5, 0xdb, + 0x46, 0xeb, 0xb7, 0x06, 0x2c, 0x16, 0xd4, 0x94, 0xf0, 0xff, 0x34, 0xcb, 0x7f, 0x0e, 0x41, 0xd7, + 0x7b, 0x8a, 0x83, 0x3e, 0xe1, 0x19, 0x43, 0xac, 0x7f, 0x19, 0x60, 0x16, 0xf6, 0xff, 0x23, 0xca, + 0x07, 0xf7, 0xa8, 0x4b, 0x42, 0x74, 0x1b, 0x66, 0x03, 0x35, 0xa7, 0xcb, 0xc4, 0x5b, 0x67, 0xb8, + 0x6d, 0xbf, 0x62, 0xc7, 0xd4, 0xe8, 0x23, 0xa8, 0x8f, 0x08, 0xc7, 0x5d, 0xcc, 0xb1, 0xb6, 0x7d, + 0xa3, 0x8c, 0x53, 0x68, 0x39, 0xd0, 0x74, 0xfb, 0x15, 0x3b, 0xe1, 0x41, 0xef, 0xc3, 0xb4, 0x33, + 0x88, 0xbc, 0xa1, 0x2c, 0x10, 0x73, 0xdb, 0x6f, 0x9f, 0xc6, 0xbc, 0x2b, 0x88, 0xf6, 0x2b, 0xb6, + 0xa2, 0xfe, 0x78, 0x06, 0xa6, 0x18, 0x0e, 0xb8, 0x75, 0x0f, 0x96, 0xcb, 0x54, 0x88, 0xaa, 0xe4, + 0x0c, 0x88, 0x33, 0x0c, 0xa3, 0x91, 0x76, 0x73, 0x32, 0x46, 0x08, 0xa6, 0x42, 0xfa, 0x42, 0xb9, + 0xba, 0x66, 0xcb, 0x6f, 0xeb, 0x5b, 0xb0, 0x34, 0xa6, 0x4d, 0x1c, 0xaa, 0xb2, 0x4d, 0x48, 0x98, + 0xd7, 0xaa, 0xad, 0x08, 0x56, 0x9e, 0x4a, 0x5f, 0x24, 0xa9, 0xf9, 0x22, 0xea, 0xac, 0xb5, 0x0f, + 0xab, 0x45, 0xb5, 0x21, 0xf3, 0xbd, 0x90, 0x88, 0x5b, 0x22, 0x73, 0x19, 0x25, 0xdd, 0x74, 0x55, + 0x5a, 0x51, 0xb7, 0x4b, 0x56, 0xac, 0x5f, 0x55, 0x61, 0xd5, 0x26, 0xa1, 0xef, 0x1e, 0x93, 0x38, + 0xd1, 0x5c, 0x0c, 0x54, 0xf8, 0x09, 0xd4, 0x30, 0x63, 0x3a, 0x4c, 0xee, 0x9f, 0x5b, 0x31, 0xb6, + 0x85, 0x54, 0xf4, 0x2e, 0x2c, 0xe1, 0xd1, 0x11, 0xed, 0x47, 0x7e, 0x14, 0xc6, 0xdb, 0x92, 0x41, + 0xd5, 0xb0, 0xc7, 0x17, 0x2c, 0x07, 0xd6, 0xc6, 0x5c, 0xa0, 0xdd, 0x99, 0x05, 0x34, 0x46, 0x01, + 0xd0, 0x94, 0x2a, 0xa9, 0x9e, 0xa6, 0xe4, 0x6f, 0x06, 0x34, 0xd3, 0xab, 0xa3, 0xc5, 0x5f, 0x85, + 0xc6, 0x48, 0xcf, 0x85, 0xa6, 0x21, 0x0b, 0x56, 0x3a, 0x91, 0xc7, 0x36, 0xd5, 0x22, 0xb6, 0x59, + 0x85, 0x19, 0x05, 0x3d, 0xf5, 0xc6, 0xf4, 0x28, 0x67, 0xf2, 0x54, 0xc1, 0xe4, 0x75, 0x80, 0x30, + 0xc9, 0x5f, 0xe6, 0x8c, 0x5c, 0xcd, 0xcc, 0x20, 0x0b, 0xe6, 0x55, 0x25, 0xb4, 0x49, 0x18, 0xb9, + 0xdc, 0x9c, 0x95, 0x14, 0xb9, 0x39, 0xcb, 0x87, 0xc5, 0x87, 0x54, 0xec, 0xa1, 0x17, 0x5e, 0x4c, + 0xb0, 0x7f, 0x00, 0x53, 0x42, 0x99, 0xd8, 0xd8, 0x51, 0x80, 0x3d, 0x67, 0x40, 0x62, 0x5f, 0x25, + 0x63, 0x71, 0x8d, 0x39, 0xee, 0x87, 0x66, 0x55, 0xce, 0xcb, 0x6f, 0xeb, 0x4f, 0x55, 0x65, 0xe9, + 0x0e, 0x63, 0xe1, 0x57, 0x0f, 0x7f, 0xcb, 0x0b, 0x72, 0x6d, 0xbc, 0x20, 0x17, 0x4c, 0xfe, 0x32, + 0x05, 0xf9, 0x9c, 0xca, 0x94, 0x15, 0xc1, 0xec, 0x0e, 0x63, 0xc2, 0x10, 0xb4, 0x05, 0x53, 0x98, + 0x31, 0xe5, 0xf0, 0x42, 0x46, 0xd6, 0x24, 0xe2, 0x7f, 0x6d, 0x92, 0x24, 0x6d, 0xdd, 0x86, 0x46, + 0x32, 0xf5, 0x2a, 0xb5, 0x8d, 0xac, 0xda, 0x0d, 0x00, 0x85, 0x38, 0xef, 0x7b, 0x3d, 0x5f, 0x1c, + 0xa9, 0x08, 0x76, 0xcd, 0x2a, 0xbf, 0xad, 0x3b, 0x31, 0x85, 0xb4, 0xed, 0x5d, 0x98, 0xa6, 0x9c, + 0x8c, 0x62, 0xe3, 0x56, 0xb3, 0xc6, 0xa5, 0x82, 0x6c, 0x45, 0x64, 0xfd, 0xbd, 0x0e, 0x57, 0xc4, + 0x89, 0x3d, 0x91, 0xd7, 0x64, 0x87, 0xb1, 0x4f, 0x08, 0xc7, 0xd4, 0x0d, 0xbf, 0x1f, 0x91, 0xe0, + 0xe4, 0x0d, 0x07, 0x46, 0x1f, 0x66, 0xd4, 0x2d, 0xd3, 0xf9, 0xee, 0xdc, 0x9b, 0x0f, 0x2d, 0x3e, + 0xed, 0x38, 0x6a, 0x6f, 0xa6, 0xe3, 0x28, 0xeb, 0x00, 0xa6, 0x2e, 0xa8, 0x03, 0x38, 0xbd, 0x09, + 0xcc, 0xb4, 0x96, 0x33, 0xf9, 0xd6, 0xb2, 0x04, 0x58, 0xcf, 0xbe, 0x2e, 0xb0, 0xae, 0x97, 0x02, + 0xeb, 0x51, 0xe9, 0x3d, 0x6e, 0x48, 0x77, 0x7f, 0x37, 0x1b, 0x81, 0xa7, 0xc6, 0xda, 0x24, 0x10, + 0x1b, 0xde, 0x28, 0xc4, 0xfe, 0x41, 0x0e, 0x32, 0xab, 0xa6, 0xf5, 0xfd, 0xd7, 0xdb, 0xd3, 0xd7, + 0x09, 0x3c, 0xff, 0x46, 0x62, 0x26, 0xe6, 0xa7, 0x3e, 0x48, 0x0a, 0xba, 0xa8, 0x43, 0xa2, 0xb4, + 0xea, 0xa4, 0x25, 0xbe, 0xd1, 0x4d, 0x98, 0x12, 0x4e, 0xd6, 0xa0, 0x76, 0x2d, 0xeb, 0x4f, 0x71, + 0x12, 0x3b, 0x8c, 0x3d, 0x61, 0xc4, 0xb1, 0x25, 0x11, 0xba, 0x03, 0x8d, 0x24, 0xf0, 0xf5, 0xcd, + 0xba, 0x9a, 0xe5, 0x48, 0xee, 0x49, 0xcc, 0x96, 0x92, 0x0b, 0xde, 0x2e, 0x0d, 0x88, 0x23, 0x21, + 0xdf, 0xf4, 0x38, 0xef, 0x27, 0xf1, 0x62, 0xc2, 0x9b, 0x90, 0xa3, 0x2d, 0x98, 0x51, 0x5d, 0xbe, + 0xbc, 0x41, 0x73, 0xdb, 0x57, 0xc6, 0x93, 0x69, 0xcc, 0xa5, 0x09, 0xad, 0xbf, 0x1a, 0xf0, 0x4e, + 0x1a, 0x10, 0xf1, 0x6d, 0x8a, 0x51, 0xf7, 0x57, 0x5f, 0x71, 0xaf, 0xc3, 0x82, 0x84, 0xf9, 0x69, + 0xb3, 0xaf, 0xde, 0x9d, 0x0a, 0xb3, 0xd6, 0x1f, 0x0d, 0xb8, 0x36, 0xbe, 0x8f, 0xdd, 0x01, 0x0e, + 0x78, 0x72, 0xbc, 0x17, 0xb1, 0x97, 0xb8, 0xe0, 0x55, 0xd3, 0x82, 0x97, 0xdb, 0x5f, 0x2d, 0xbf, + 0x3f, 0xeb, 0x2f, 0x55, 0x98, 0xcb, 0x04, 0x50, 0x59, 0xc1, 0x14, 0x80, 0x4f, 0xc6, 0xad, 0x6c, + 0xec, 0x64, 0x51, 0x68, 0xd8, 0x99, 0x19, 0x34, 0x04, 0x60, 0x38, 0xc0, 0x23, 0xc2, 0x49, 0x20, + 0x32, 0xb9, 0xb8, 0xf1, 0x0f, 0x26, 0xcf, 0x2e, 0x87, 0xb1, 0x4c, 0x3b, 0x23, 0x5e, 0x20, 0x56, + 0xa9, 0x3a, 0xd4, 0xf9, 0x5b, 0x8f, 0xd0, 0x2f, 0x60, 0xa1, 0x47, 0x5d, 0x72, 0x98, 0x1a, 0x32, + 0x23, 0x0d, 0x79, 0x3c, 0xb9, 0x21, 0xf7, 0xb2, 0x72, 0xed, 0x82, 0x1a, 0xeb, 0x06, 0x34, 0x8b, + 0xf7, 0x49, 0x18, 0x49, 0x47, 0xb8, 0x9f, 0x78, 0x4b, 0x8f, 0x2c, 0x04, 0xcd, 0xe2, 0xfd, 0xb1, + 0xfe, 0x5d, 0x85, 0x95, 0x44, 0xdc, 0x8e, 0xe7, 0xf9, 0x91, 0xe7, 0xc8, 0x87, 0xb3, 0xd2, 0xb3, + 0x58, 0x86, 0x69, 0x4e, 0xb9, 0x9b, 0x00, 0x1f, 0x39, 0x10, 0xb5, 0x8b, 0xfb, 0xbe, 0xcb, 0x29, + 0xd3, 0x07, 0x1c, 0x0f, 0xd5, 0xd9, 0x3f, 0x8f, 0x68, 0x40, 0xba, 0x32, 0x13, 0xd4, 0xed, 0x64, + 0x2c, 0xd6, 0x04, 0xaa, 0x91, 0x30, 0x5e, 0x39, 0x33, 0x19, 0xcb, 0xb8, 0xf7, 0x5d, 0x97, 0x38, + 0xc2, 0x1d, 0x19, 0xa0, 0x5f, 0x98, 0x95, 0x0d, 0x04, 0x0f, 0xa8, 0xd7, 0xd7, 0x30, 0x5f, 0x8f, + 0x84, 0x9d, 0x38, 0x08, 0xf0, 0x89, 0x59, 0x97, 0x0e, 0x50, 0x03, 0xf4, 0x1d, 0xa8, 0x8d, 0x30, + 0xd3, 0x85, 0xee, 0x46, 0x2e, 0x3b, 0x94, 0x79, 0xa0, 0x7d, 0x80, 0x99, 0xaa, 0x04, 0x82, 0xad, + 0xf5, 0x01, 0xd4, 0xe3, 0x89, 0x2f, 0x05, 0x09, 0x3f, 0x87, 0x4b, 0xb9, 0xe4, 0x83, 0x3e, 0x83, + 0xd5, 0x34, 0xa2, 0xb2, 0x0a, 0x35, 0x08, 0x7c, 0xe7, 0x95, 0x96, 0xd9, 0xa7, 0x08, 0xb0, 0x9e, + 0xc3, 0x92, 0x08, 0x19, 0x79, 0xf1, 0x2f, 0xa8, 0xb5, 0xf9, 0x10, 0x1a, 0x89, 0xca, 0xd2, 0x98, + 0x69, 0x41, 0xfd, 0x38, 0x7e, 0xd0, 0x54, 0xbd, 0x4d, 0x32, 0xb6, 0x76, 0x00, 0x65, 0xed, 0xd5, + 0x15, 0xe8, 0x66, 0x1e, 0x14, 0xaf, 0x14, 0xcb, 0x8d, 0x24, 0x8f, 0x31, 0xf1, 0x3f, 0x0d, 0x58, + 0xdc, 0xa3, 0xf2, 0x95, 0xe3, 0x82, 0x92, 0xdc, 0x0d, 0x68, 0x86, 0xd1, 0xd1, 0xc8, 0xef, 0x46, + 0x2e, 0xd1, 0xa0, 0x40, 0x57, 0xfa, 0xb1, 0xf9, 0xb3, 0x92, 0x9f, 0x70, 0x16, 0xc3, 0x7c, 0xa0, + 0x3b, 0x5c, 0xf9, 0x6d, 0xfd, 0xda, 0x80, 0x66, 0xba, 0x1b, 0xed, 0x8f, 0xdb, 0x2a, 0x6e, 0x95, + 0x37, 0xae, 0x65, 0xbd, 0x51, 0x24, 0xfd, 0xdf, 0x43, 0x76, 0x3e, 0x1b, 0xb2, 0x7f, 0x36, 0x60, + 0x65, 0x8f, 0xf2, 0x38, 0x59, 0xd0, 0xff, 0x33, 0xcf, 0x5a, 0x6d, 0x58, 0x2d, 0x9a, 0xaf, 0x5d, + 0xb9, 0x0c, 0xd3, 0xc2, 0xcf, 0x71, 0xf7, 0xad, 0x06, 0xdb, 0x5f, 0x34, 0x60, 0x29, 0x2d, 0x9f, + 0xe2, 0x5f, 0xea, 0x10, 0xf4, 0x18, 0x9a, 0x7b, 0xfa, 0xb7, 0xaa, 0xf8, 0xd5, 0x03, 0x9d, 0xf5, + 0x8c, 0xd8, 0xba, 0x5a, 0xbe, 0xa8, 0x54, 0x5b, 0x15, 0xe4, 0xc0, 0x95, 0xa2, 0xc0, 0xf4, 0xc5, + 0xf2, 0x9b, 0x67, 0x48, 0x4e, 0xa8, 0x5e, 0xa5, 0x62, 0xd3, 0x40, 0x9f, 0xc1, 0x42, 0xfe, 0x5d, + 0x0d, 0xe5, 0xf2, 0x49, 0xe9, 0x53, 0x5f, 0xcb, 0x3a, 0x8b, 0x24, 0xb1, 0xff, 0x99, 0x00, 0xaf, + 0xb9, 0x47, 0x26, 0x64, 0xe5, 0xa1, 0x75, 0xd9, 0x23, 0x5c, 0xeb, 0x1b, 0x67, 0xd2, 0x24, 0xd2, + 0x3f, 0x84, 0x7a, 0xfc, 0x28, 0x93, 0x77, 0x73, 0xe1, 0xa9, 0xa6, 0xd5, 0xcc, 0xcb, 0xeb, 0x85, + 0x56, 0x05, 0x7d, 0xa4, 0x98, 0x45, 0xd3, 0x3e, 0xce, 0x9c, 0x79, 0x8a, 0x68, 0x5d, 0x2e, 0x69, + 0xff, 0xad, 0x0a, 0xfa, 0x1e, 0xcc, 0x89, 0xaf, 0x43, 0xfd, 0x2b, 0xd1, 0x6a, 0x5b, 0xfd, 0x28, + 0xd9, 0x8e, 0x7f, 0x94, 0x6c, 0xdf, 0x1d, 0x31, 0x7e, 0xd2, 0x2a, 0xe9, 0xcf, 0xb5, 0x80, 0x67, + 0x70, 0x69, 0x8f, 0xf0, 0x14, 0x4e, 0xa3, 0x6b, 0xaf, 0xd5, 0x74, 0xb4, 0xac, 0x22, 0xd9, 0x38, + 0x22, 0xb7, 0x2a, 0xe8, 0x77, 0x06, 0x5c, 0xde, 0x23, 0xbc, 0x08, 0x50, 0xd1, 0x7b, 0xe5, 0x4a, + 0x4e, 0x01, 0xb2, 0xad, 0x47, 0x93, 0xde, 0xd7, 0xbc, 0x58, 0xab, 0x82, 0xfe, 0x60, 0xc0, 0x5a, + 0xc6, 0xb0, 0x2c, 0xe2, 0x44, 0x5b, 0x67, 0x1b, 0x57, 0x82, 0x4e, 0x5b, 0x9f, 0x4e, 0xf8, 0xe3, + 0x5f, 0x46, 0xa4, 0x55, 0x41, 0x87, 0xf2, 0x4c, 0xd2, 0x02, 0x83, 0xde, 0x2e, 0xad, 0x24, 0x89, + 0xf6, 0xf5, 0xd3, 0x96, 0x93, 0x73, 0xf8, 0x14, 0xe6, 0xf6, 0x08, 0x8f, 0xb3, 0x6e, 0x3e, 0xd2, + 0x0a, 0x45, 0x28, 0x7f, 0x55, 0x8b, 0x89, 0x5a, 0x46, 0xcc, 0x92, 0x92, 0x95, 0xc9, 0x53, 0xf9, + 0xbb, 0x5a, 0x9a, 0x82, 0xf3, 0x11, 0x53, 0x9e, 0xe6, 0xac, 0xca, 0xc7, 0x3b, 0xff, 0x78, 0xb9, + 0x6e, 0x7c, 0xf1, 0x72, 0xdd, 0xf8, 0xcf, 0xcb, 0x75, 0xe3, 0xc7, 0xb7, 0x5e, 0xf1, 0x8b, 0x7d, + 0xe6, 0x8f, 0x00, 0x30, 0xa3, 0x8e, 0x4b, 0x89, 0xc7, 0x8f, 0x66, 0x64, 0xf0, 0xdf, 0xfa, 0x6f, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xfb, 0xa8, 0x48, 0x92, 0x23, 0x20, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -2085,6 +2328,10 @@ type RepoServerServiceClient interface { GetRevisionChartDetails(ctx context.Context, in *RepoServerRevisionChartDetailsRequest, opts ...grpc.CallOption) (*v1alpha1.ChartDetails, error) // GetHelmCharts returns list of helm charts in the specified repository GetHelmCharts(ctx context.Context, in *HelmChartsRequest, opts ...grpc.CallOption) (*HelmChartsResponse, error) + // GetGitFiles returns a set of file paths and their contents for the given repo + GetGitFiles(ctx context.Context, in *GitFilesRequest, opts ...grpc.CallOption) (*GitFilesResponse, error) + // GetGitDirectories returns a set of directory paths for the given repo + GetGitDirectories(ctx context.Context, in *GitDirectoriesRequest, opts ...grpc.CallOption) (*GitDirectoriesResponse, error) } type repoServerServiceClient struct { @@ -2219,6 +2466,24 @@ func (c *repoServerServiceClient) GetHelmCharts(ctx context.Context, in *HelmCha return out, nil } +func (c *repoServerServiceClient) GetGitFiles(ctx context.Context, in *GitFilesRequest, opts ...grpc.CallOption) (*GitFilesResponse, error) { + out := new(GitFilesResponse) + err := c.cc.Invoke(ctx, "/repository.RepoServerService/GetGitFiles", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *repoServerServiceClient) GetGitDirectories(ctx context.Context, in *GitDirectoriesRequest, opts ...grpc.CallOption) (*GitDirectoriesResponse, error) { + out := new(GitDirectoriesResponse) + err := c.cc.Invoke(ctx, "/repository.RepoServerService/GetGitDirectories", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // RepoServerServiceServer is the server API for RepoServerService service. type RepoServerServiceServer interface { // GenerateManifest generates manifest for application in specified repo name and revision @@ -2243,6 +2508,10 @@ type RepoServerServiceServer interface { GetRevisionChartDetails(context.Context, *RepoServerRevisionChartDetailsRequest) (*v1alpha1.ChartDetails, error) // GetHelmCharts returns list of helm charts in the specified repository GetHelmCharts(context.Context, *HelmChartsRequest) (*HelmChartsResponse, error) + // GetGitFiles returns a set of file paths and their contents for the given repo + GetGitFiles(context.Context, *GitFilesRequest) (*GitFilesResponse, error) + // GetGitDirectories returns a set of directory paths for the given repo + GetGitDirectories(context.Context, *GitDirectoriesRequest) (*GitDirectoriesResponse, error) } // UnimplementedRepoServerServiceServer can be embedded to have forward compatible implementations. @@ -2282,6 +2551,12 @@ func (*UnimplementedRepoServerServiceServer) GetRevisionChartDetails(ctx context func (*UnimplementedRepoServerServiceServer) GetHelmCharts(ctx context.Context, req *HelmChartsRequest) (*HelmChartsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetHelmCharts not implemented") } +func (*UnimplementedRepoServerServiceServer) GetGitFiles(ctx context.Context, req *GitFilesRequest) (*GitFilesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetGitFiles not implemented") +} +func (*UnimplementedRepoServerServiceServer) GetGitDirectories(ctx context.Context, req *GitDirectoriesRequest) (*GitDirectoriesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetGitDirectories not implemented") +} func RegisterRepoServerServiceServer(s *grpc.Server, srv RepoServerServiceServer) { s.RegisterService(&_RepoServerService_serviceDesc, srv) @@ -2493,6 +2768,42 @@ func _RepoServerService_GetHelmCharts_Handler(srv interface{}, ctx context.Conte return interceptor(ctx, in, info, handler) } +func _RepoServerService_GetGitFiles_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GitFilesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RepoServerServiceServer).GetGitFiles(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/repository.RepoServerService/GetGitFiles", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RepoServerServiceServer).GetGitFiles(ctx, req.(*GitFilesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _RepoServerService_GetGitDirectories_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GitDirectoriesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RepoServerServiceServer).GetGitDirectories(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/repository.RepoServerService/GetGitDirectories", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RepoServerServiceServer).GetGitDirectories(ctx, req.(*GitDirectoriesRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _RepoServerService_serviceDesc = grpc.ServiceDesc{ ServiceName: "repository.RepoServerService", HandlerType: (*RepoServerServiceServer)(nil), @@ -2537,6 +2848,14 @@ var _RepoServerService_serviceDesc = grpc.ServiceDesc{ MethodName: "GetHelmCharts", Handler: _RepoServerService_GetHelmCharts_Handler, }, + { + MethodName: "GetGitFiles", + Handler: _RepoServerService_GetGitFiles_Handler, + }, + { + MethodName: "GetGitDirectories", + Handler: _RepoServerService_GetGitDirectories_Handler, + }, }, Streams: []grpc.StreamDesc{ { @@ -4285,47 +4604,250 @@ func (m *HelmChartsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func encodeVarintRepository(dAtA []byte, offset int, v uint64) int { - offset -= sovRepository(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ +func (m *GitFilesRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } - dAtA[offset] = uint8(v) - return base + return dAtA[:n], nil } -func (m *ManifestRequest) Size() (n int) { - if m == nil { - return 0 - } + +func (m *GitFilesRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GitFilesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - if m.Repo != nil { - l = m.Repo.Size() - n += 1 + l + sovRepository(uint64(l)) - } - l = len(m.Revision) - if l > 0 { - n += 1 + l + sovRepository(uint64(l)) - } - if m.NoCache { - n += 2 + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - l = len(m.AppLabelKey) - if l > 0 { - n += 1 + l + sovRepository(uint64(l)) + if len(m.Path) > 0 { + i -= len(m.Path) + copy(dAtA[i:], m.Path) + i = encodeVarintRepository(dAtA, i, uint64(len(m.Path))) + i-- + dAtA[i] = 0x22 } - l = len(m.AppName) - if l > 0 { - n += 1 + l + sovRepository(uint64(l)) + if len(m.Revision) > 0 { + i -= len(m.Revision) + copy(dAtA[i:], m.Revision) + i = encodeVarintRepository(dAtA, i, uint64(len(m.Revision))) + i-- + dAtA[i] = 0x1a } - l = len(m.Namespace) - if l > 0 { - n += 1 + l + sovRepository(uint64(l)) + if m.SubmoduleEnabled { + i-- + if m.SubmoduleEnabled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x10 } - if m.ApplicationSource != nil { + if m.Repo != nil { + { + size, err := m.Repo.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRepository(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *GitFilesResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GitFilesResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GitFilesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Map) > 0 { + for k := range m.Map { + v := m.Map[k] + baseI := i + if len(v) > 0 { + i -= len(v) + copy(dAtA[i:], v) + i = encodeVarintRepository(dAtA, i, uint64(len(v))) + i-- + dAtA[i] = 0x12 + } + i -= len(k) + copy(dAtA[i:], k) + i = encodeVarintRepository(dAtA, i, uint64(len(k))) + i-- + dAtA[i] = 0xa + i = encodeVarintRepository(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *GitDirectoriesRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GitDirectoriesRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GitDirectoriesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Revision) > 0 { + i -= len(m.Revision) + copy(dAtA[i:], m.Revision) + i = encodeVarintRepository(dAtA, i, uint64(len(m.Revision))) + i-- + dAtA[i] = 0x1a + } + if m.SubmoduleEnabled { + i-- + if m.SubmoduleEnabled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x10 + } + if m.Repo != nil { + { + size, err := m.Repo.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRepository(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *GitDirectoriesResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GitDirectoriesResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GitDirectoriesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Paths) > 0 { + for iNdEx := len(m.Paths) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Paths[iNdEx]) + copy(dAtA[i:], m.Paths[iNdEx]) + i = encodeVarintRepository(dAtA, i, uint64(len(m.Paths[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintRepository(dAtA []byte, offset int, v uint64) int { + offset -= sovRepository(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *ManifestRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Repo != nil { + l = m.Repo.Size() + n += 1 + l + sovRepository(uint64(l)) + } + l = len(m.Revision) + if l > 0 { + n += 1 + l + sovRepository(uint64(l)) + } + if m.NoCache { + n += 2 + } + l = len(m.AppLabelKey) + if l > 0 { + n += 1 + l + sovRepository(uint64(l)) + } + l = len(m.AppName) + if l > 0 { + n += 1 + l + sovRepository(uint64(l)) + } + l = len(m.Namespace) + if l > 0 { + n += 1 + l + sovRepository(uint64(l)) + } + if m.ApplicationSource != nil { l = m.ApplicationSource.Size() n += 1 + l + sovRepository(uint64(l)) } @@ -5069,54 +5591,146 @@ func (m *HelmChartsResponse) Size() (n int) { return n } -func sovRepository(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozRepository(x uint64) (n int) { - return sovRepository(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +func (m *GitFilesRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Repo != nil { + l = m.Repo.Size() + n += 1 + l + sovRepository(uint64(l)) + } + if m.SubmoduleEnabled { + n += 2 + } + l = len(m.Revision) + if l > 0 { + n += 1 + l + sovRepository(uint64(l)) + } + l = len(m.Path) + if l > 0 { + n += 1 + l + sovRepository(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n } -func (m *ManifestRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRepository - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break + +func (m *GitFilesResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Map) > 0 { + for k, v := range m.Map { + _ = k + _ = v + l = 0 + if len(v) > 0 { + l = 1 + len(v) + sovRepository(uint64(len(v))) } + mapEntrySize := 1 + len(k) + sovRepository(uint64(len(k))) + l + n += mapEntrySize + 1 + sovRepository(uint64(mapEntrySize)) } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: ManifestRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: ManifestRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Repo", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRepository - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *GitDirectoriesRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Repo != nil { + l = m.Repo.Size() + n += 1 + l + sovRepository(uint64(l)) + } + if m.SubmoduleEnabled { + n += 2 + } + l = len(m.Revision) + if l > 0 { + n += 1 + l + sovRepository(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *GitDirectoriesResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Paths) > 0 { + for _, s := range m.Paths { + l = len(s) + n += 1 + l + sovRepository(uint64(l)) + } + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func sovRepository(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozRepository(x uint64) (n int) { + return sovRepository(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *ManifestRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ManifestRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ManifestRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Repo", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] iNdEx++ msglen |= int(b&0x7F) << shift if b < 0x80 { @@ -9953,6 +10567,578 @@ func (m *HelmChartsResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *GitFilesRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GitFilesRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GitFilesRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Repo", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRepository + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRepository + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Repo == nil { + m.Repo = &v1alpha1.Repository{} + } + if err := m.Repo.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SubmoduleEnabled", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.SubmoduleEnabled = bool(v != 0) + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Revision", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRepository + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRepository + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Revision = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Path", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRepository + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRepository + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Path = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRepository(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRepository + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GitFilesResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GitFilesResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GitFilesResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Map", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRepository + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRepository + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Map == nil { + m.Map = make(map[string][]byte) + } + var mapkey string + mapvalue := []byte{} + for iNdEx < postIndex { + entryPreIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + if fieldNum == 1 { + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapkey |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthRepository + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthRepository + } + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + } else if fieldNum == 2 { + var mapbyteLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + mapbyteLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intMapbyteLen := int(mapbyteLen) + if intMapbyteLen < 0 { + return ErrInvalidLengthRepository + } + postbytesIndex := iNdEx + intMapbyteLen + if postbytesIndex < 0 { + return ErrInvalidLengthRepository + } + if postbytesIndex > l { + return io.ErrUnexpectedEOF + } + mapvalue = make([]byte, mapbyteLen) + copy(mapvalue, dAtA[iNdEx:postbytesIndex]) + iNdEx = postbytesIndex + } else { + iNdEx = entryPreIndex + skippy, err := skipRepository(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRepository + } + if (iNdEx + skippy) > postIndex { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + m.Map[mapkey] = mapvalue + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRepository(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRepository + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GitDirectoriesRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GitDirectoriesRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GitDirectoriesRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Repo", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRepository + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRepository + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Repo == nil { + m.Repo = &v1alpha1.Repository{} + } + if err := m.Repo.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SubmoduleEnabled", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.SubmoduleEnabled = bool(v != 0) + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Revision", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRepository + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRepository + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Revision = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRepository(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRepository + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GitDirectoriesResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GitDirectoriesResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GitDirectoriesResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Paths", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRepository + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRepository + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Paths = append(m.Paths, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRepository(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRepository + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipRepository(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/reposerver/cache/cache.go b/reposerver/cache/cache.go index c91123d45ee29..0d1a60d5a9584 100644 --- a/reposerver/cache/cache.go +++ b/reposerver/cache/cache.go @@ -317,6 +317,28 @@ func (c *Cache) SetRevisionChartDetails(repoURL, chart, revision string, item *a return c.cache.SetItem(revisionChartDetailsKey(repoURL, chart, revision), item, c.repoCacheExpiration, false) } +func gitDataKey(gitObject, repoURL, revision string) string { + return fmt.Sprintf("%s|%s|%s", gitObject, repoURL, revision) +} + +func (c *Cache) SetGitFiles(repoURL, revision string, files map[string][]byte) error { + return c.cache.SetItem(gitDataKey(gitfiles, repoURL, revision), &files, c.repoCacheExpiration, false) +} + +func (c *Cache) GetGitFiles(repoURL, revision string) (map[string][]byte, error) { + var item map[string][]byte + return item, c.cache.GetItem(gitDataKey(gitfiles, repoURL, revision), &item) +} + +func (c *Cache) SetGitDirectories(repoURL, revision string, directories []string) error { + return c.cache.SetItem(gitDataKey(gitdir, repoURL, revision), &directories, c.repoCacheExpiration, false) +} + +func (c *Cache) GetGitDirectories(repoURL, revision string) ([]string, error) { + var item []string + return item, c.cache.GetItem(gitDataKey(gitdir, repoURL, revision), &item) +} + func (cmr *CachedManifestResponse) shallowCopy() *CachedManifestResponse { if cmr == nil { return nil diff --git a/reposerver/cache/types.go b/reposerver/cache/types.go new file mode 100644 index 0000000000000..777c0759d599e --- /dev/null +++ b/reposerver/cache/types.go @@ -0,0 +1,6 @@ +package cache + +const ( + gitdir = "gitdirs" + gitfiles = "gitfiles" +) diff --git a/reposerver/repository/repository.go b/reposerver/repository/repository.go index ba1f669a0ecaa..b28c61e4e1c43 100644 --- a/reposerver/repository/repository.go +++ b/reposerver/repository/repository.go @@ -295,7 +295,7 @@ func (s *Service) runRepoOperation( if sanitizer, ok := grpc.SanitizerFromContext(ctx); ok { // make sure randomized path replaced with '.' in the error message - sanitizer.AddRegexReplacement(regexp.MustCompile(`(`+regexp.QuoteMeta(s.rootDir)+`/.*?)/`), ".") + sanitizer.AddRegexReplacement(getRepoSanitizerRegex(s.rootDir), "") } var gitClient git.Client @@ -441,6 +441,15 @@ func (s *Service) runRepoOperation( } } +func getRepoSanitizerRegex(rootDir string) *regexp.Regexp { + // This regex assumes that the sensitive part of the path (the component immediately after "rootDir") contains no + // spaces. This assumption allows us to avoid sanitizing "more info" in "/tmp/_argocd-repo/SENSITIVE more info". + // + // The no-spaces assumption holds for our actual use case, which is "/tmp/_argocd-repo/{random UUID}". The UUID will + // only ever contain digits and hyphens. + return regexp.MustCompile(regexp.QuoteMeta(rootDir) + `/[^ /]*`) +} + type gitClientGetter func(repo *v1alpha1.Repository, revision string, opts ...git.ClientOpts) (git.Client, string, error) // resolveReferencedSources resolves the revisions for the given referenced sources. This lets us invalidate the cached @@ -2517,3 +2526,134 @@ func (s *Service) ResolveRevision(ctx context.Context, q *apiclient.ResolveRevis }, nil } } + +func (s *Service) GetGitFiles(_ context.Context, request *apiclient.GitFilesRequest) (*apiclient.GitFilesResponse, error) { + repo := request.GetRepo() + revision := request.GetRevision() + gitPath := request.GetPath() + if gitPath == "" { + gitPath = "." + } + + if repo == nil { + return nil, status.Error(codes.InvalidArgument, "must pass a valid repo") + } + + gitClient, revision, err := s.newClientResolveRevision(repo, revision, git.WithCache(s.cache, true)) + if err != nil { + return nil, status.Errorf(codes.Internal, "unable to resolve git revision %s: %v", revision, err) + } + + // check the cache and return the results if present + if cachedFiles, err := s.cache.GetGitFiles(repo.Repo, revision); err == nil { + log.Debugf("cache hit for repo: %s revision: %s", repo.Repo, revision) + return &apiclient.GitFilesResponse{ + Map: cachedFiles, + }, nil + } + + // cache miss, generate the results + closer, err := s.repoLock.Lock(gitClient.Root(), revision, true, func() (goio.Closer, error) { + return s.checkoutRevision(gitClient, revision, request.GetSubmoduleEnabled()) + }) + if err != nil { + return nil, status.Errorf(codes.Internal, "unable to checkout git repo %s with revision %s: %v", repo.Repo, revision, err) + } + defer io.Close(closer) + + gitFiles, err := gitClient.LsFiles(gitPath) + if err != nil { + return nil, status.Errorf(codes.Internal, "unable to list files. repo %s with revision %s: %v", repo.Repo, revision, err) + } + log.Debugf("listed %d git files from %s under %s", len(gitFiles), repo.Repo, gitPath) + + res := make(map[string][]byte) + for _, filePath := range gitFiles { + fileContents, err := os.ReadFile(filepath.Join(gitClient.Root(), filePath)) + if err != nil { + return nil, status.Errorf(codes.Internal, "unable to read files. repo %s with revision %s: %v", repo.Repo, revision, err) + } + res[filePath] = fileContents + } + + err = s.cache.SetGitFiles(repo.Repo, revision, res) + if err != nil { + log.Warnf("error caching git files for repo %s with revision %s: %v", repo.Repo, revision, err) + } + + return &apiclient.GitFilesResponse{ + Map: res, + }, nil +} + +func (s *Service) GetGitDirectories(_ context.Context, request *apiclient.GitDirectoriesRequest) (*apiclient.GitDirectoriesResponse, error) { + repo := request.GetRepo() + revision := request.GetRevision() + + if repo == nil { + return nil, status.Error(codes.InvalidArgument, "must pass a valid repo") + } + + gitClient, revision, err := s.newClientResolveRevision(repo, revision, git.WithCache(s.cache, true)) + if err != nil { + return nil, status.Errorf(codes.Internal, "unable to resolve git revision %s: %v", revision, err) + } + + // check the cache and return the results if present + if cachedPaths, err := s.cache.GetGitDirectories(repo.Repo, revision); err == nil { + log.Debugf("cache hit for repo: %s revision: %s", repo.Repo, revision) + return &apiclient.GitDirectoriesResponse{ + Paths: cachedPaths, + }, nil + } + + // cache miss, generate the results + closer, err := s.repoLock.Lock(gitClient.Root(), revision, true, func() (goio.Closer, error) { + return s.checkoutRevision(gitClient, revision, request.GetSubmoduleEnabled()) + }) + if err != nil { + return nil, status.Errorf(codes.Internal, "unable to checkout git repo %s with revision %s: %v", repo.Repo, revision, err) + } + defer io.Close(closer) + + repoRoot := gitClient.Root() + var paths []string + if err := filepath.WalkDir(repoRoot, func(path string, entry fs.DirEntry, fnErr error) error { + if fnErr != nil { + return fmt.Errorf("error walking the file tree: %w", fnErr) + } + if !entry.IsDir() { // Skip files: directories only + return nil + } + + fname := entry.Name() + if strings.HasPrefix(fname, ".") { // Skip all folders starts with "." + return filepath.SkipDir + } + + relativePath, err := filepath.Rel(repoRoot, path) + if err != nil { + return fmt.Errorf("error constructing relative repo path: %w", err) + } + + if relativePath == "." { // Exclude '.' from results + return nil + } + + paths = append(paths, relativePath) + + return nil + }); err != nil { + return nil, err + } + + log.Debugf("found %d git paths from %s", len(paths), repo.Repo) + err = s.cache.SetGitDirectories(repo.Repo, revision, paths) + if err != nil { + log.Warnf("error caching git directories for repo %s with revision %s: %v", repo.Repo, revision, err) + } + + return &apiclient.GitDirectoriesResponse{ + Paths: paths, + }, nil +} diff --git a/reposerver/repository/repository.proto b/reposerver/repository/repository.proto index fddb75c5aa7ed..685526a5b08af 100644 --- a/reposerver/repository/repository.proto +++ b/reposerver/repository/repository.proto @@ -89,13 +89,13 @@ message ManifestResponse { } message ListRefsRequest { - github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.Repository repo = 1; + github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.Repository repo = 1; } // A subset of the repository's named refs message Refs { - repeated string branches = 1; - repeated string tags = 2; + repeated string branches = 1; + repeated string tags = 2; } // ListAppsRequest requests a repository directory structure @@ -136,11 +136,11 @@ message RepoServerAppDetailsQuery { // RepoAppDetailsResponse application details message RepoAppDetailsResponse { - string type = 1; - HelmAppSpec helm = 3; - KustomizeAppSpec kustomize = 4; - DirectoryAppSpec directory = 5; - PluginAppSpec plugin = 6; + string type = 1; + HelmAppSpec helm = 3; + KustomizeAppSpec kustomize = 4; + DirectoryAppSpec directory = 5; + PluginAppSpec plugin = 6; } message RepoServerRevisionMetadataRequest { @@ -163,20 +163,20 @@ message RepoServerRevisionChartDetailsRequest { // HelmAppSpec contains helm app name in source repo message HelmAppSpec { - string name = 1; - repeated string valueFiles = 3; - // the output of `helm inspect values` - repeated github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.HelmParameter parameters = 4; - // the contents of values.yaml - string values = 5; + string name = 1; + repeated string valueFiles = 3; + // the output of `helm inspect values` + repeated github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.HelmParameter parameters = 4; + // the contents of values.yaml + string values = 5; // helm file parameters repeated github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.HelmFileParameter fileParameters = 6; } // KustomizeAppSpec contains kustomize images message KustomizeAppSpec { - // images is a list of available images. - repeated string images = 3; + // images is a list of available images. + repeated string images = 3; } // DirectoryAppSpec contains directory @@ -225,6 +225,29 @@ message HelmChartsResponse { repeated HelmChart items = 1; } +message GitFilesRequest { + github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.Repository repo = 1; + bool submoduleEnabled = 2; + string revision = 3; + string path = 4; +} + +message GitFilesResponse { + // Map consisting of path of the path to its contents in bytes + map map = 1; +} + +message GitDirectoriesRequest { + github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.Repository repo = 1; + bool submoduleEnabled = 2; + string revision = 3; +} + +message GitDirectoriesResponse { + // A set of directory paths + repeated string paths = 1; +} + // ManifestService service RepoServerService { @@ -243,7 +266,7 @@ service RepoServerService { // Returns a valid revision rpc ResolveRevision(ResolveRevisionRequest) returns (ResolveRevisionResponse) { } - + // Returns a list of refs (e.g. branches and tags) in the repo rpc ListRefs(ListRefsRequest) returns (Refs) { } @@ -271,4 +294,12 @@ service RepoServerService { // GetHelmCharts returns list of helm charts in the specified repository rpc GetHelmCharts(HelmChartsRequest) returns (HelmChartsResponse) { } + + // GetGitFiles returns a set of file paths and their contents for the given repo + rpc GetGitFiles(GitFilesRequest) returns (GitFilesResponse) { + } + + // GetGitDirectories returns a set of directory paths for the given repo + rpc GetGitDirectories(GitDirectoriesRequest) returns (GitDirectoriesResponse) { + } } diff --git a/reposerver/repository/repository_test.go b/reposerver/repository/repository_test.go index 46f2958a6395d..b0c827422cb45 100644 --- a/reposerver/repository/repository_test.go +++ b/reposerver/repository/repository_test.go @@ -2772,3 +2772,182 @@ func Test_getResolvedValueFiles(t *testing.T) { }) } } +func TestErrorGetGitDirectories(t *testing.T) { + type fields struct { + service *Service + } + type args struct { + ctx context.Context + request *apiclient.GitDirectoriesRequest + } + tests := []struct { + name string + fields fields + args args + want *apiclient.GitDirectoriesResponse + wantErr assert.ErrorAssertionFunc + }{ + {name: "InvalidRepo", fields: fields{service: newService(".")}, args: args{ + ctx: context.TODO(), + request: &apiclient.GitDirectoriesRequest{ + Repo: nil, + SubmoduleEnabled: false, + Revision: "HEAD", + }, + }, want: nil, wantErr: assert.Error}, + {name: "InvalidResolveRevision", fields: fields{service: func() *Service { + s, _ := newServiceWithOpt(func(gitClient *gitmocks.Client, helmClient *helmmocks.Client, paths *iomocks.TempPaths) { + gitClient.On("Checkout", mock.Anything, mock.Anything).Return(nil) + gitClient.On("LsRemote", mock.Anything).Return("", fmt.Errorf("ah error")) + paths.On("GetPath", mock.Anything).Return(".", nil) + paths.On("GetPathIfExists", mock.Anything).Return(".", nil) + }, ".") + return s + }()}, args: args{ + ctx: context.TODO(), + request: &apiclient.GitDirectoriesRequest{ + Repo: &argoappv1.Repository{Repo: "not-a-valid-url"}, + SubmoduleEnabled: false, + Revision: "sadfsadf", + }, + }, want: nil, wantErr: assert.Error}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := tt.fields.service + got, err := s.GetGitDirectories(tt.args.ctx, tt.args.request) + if !tt.wantErr(t, err, fmt.Sprintf("GetGitDirectories(%v, %v)", tt.args.ctx, tt.args.request)) { + return + } + assert.Equalf(t, tt.want, got, "GetGitDirectories(%v, %v)", tt.args.ctx, tt.args.request) + }) + } +} + +func TestGetGitDirectories(t *testing.T) { + // test not using the cache + root := "./testdata/git-files-dirs" + s, _ := newServiceWithOpt(func(gitClient *gitmocks.Client, helmClient *helmmocks.Client, paths *iomocks.TempPaths) { + gitClient.On("Init").Return(nil) + gitClient.On("Fetch", mock.Anything).Return(nil) + gitClient.On("Checkout", mock.Anything, mock.Anything).Once().Return(nil) + gitClient.On("LsRemote", "HEAD").Return("632039659e542ed7de0c170a4fcc1c571b288fc0", nil) + gitClient.On("Root").Return(root) + paths.On("GetPath", mock.Anything).Return(root, nil) + paths.On("GetPathIfExists", mock.Anything).Return(root, nil) + }, root) + dirRequest := &apiclient.GitDirectoriesRequest{ + Repo: &argoappv1.Repository{Repo: "a-url.com"}, + SubmoduleEnabled: false, + Revision: "HEAD", + } + directories, err := s.GetGitDirectories(context.TODO(), dirRequest) + assert.Nil(t, err) + assert.ElementsMatch(t, directories.GetPaths(), []string{"app", "app/bar", "app/foo/bar", "somedir", "app/foo"}) + + // do the same request again to use the cache + // we only allow CheckOut to be called once in the mock + directories, err = s.GetGitDirectories(context.TODO(), dirRequest) + assert.Nil(t, err) + assert.ElementsMatch(t, []string{"app", "app/bar", "app/foo/bar", "somedir", "app/foo"}, directories.GetPaths()) +} + +func TestErrorGetGitFiles(t *testing.T) { + type fields struct { + service *Service + } + type args struct { + ctx context.Context + request *apiclient.GitFilesRequest + } + tests := []struct { + name string + fields fields + args args + want *apiclient.GitFilesResponse + wantErr assert.ErrorAssertionFunc + }{ + {name: "InvalidRepo", fields: fields{service: newService(".")}, args: args{ + ctx: context.TODO(), + request: &apiclient.GitFilesRequest{ + Repo: nil, + SubmoduleEnabled: false, + Revision: "HEAD", + }, + }, want: nil, wantErr: assert.Error}, + {name: "InvalidResolveRevision", fields: fields{service: func() *Service { + s, _ := newServiceWithOpt(func(gitClient *gitmocks.Client, helmClient *helmmocks.Client, paths *iomocks.TempPaths) { + gitClient.On("Checkout", mock.Anything, mock.Anything).Return(nil) + gitClient.On("LsRemote", mock.Anything).Return("", fmt.Errorf("ah error")) + paths.On("GetPath", mock.Anything).Return(".", nil) + paths.On("GetPathIfExists", mock.Anything).Return(".", nil) + }, ".") + return s + }()}, args: args{ + ctx: context.TODO(), + request: &apiclient.GitFilesRequest{ + Repo: &argoappv1.Repository{Repo: "not-a-valid-url"}, + SubmoduleEnabled: false, + Revision: "sadfsadf", + }, + }, want: nil, wantErr: assert.Error}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := tt.fields.service + got, err := s.GetGitFiles(tt.args.ctx, tt.args.request) + if !tt.wantErr(t, err, fmt.Sprintf("GetGitFiles(%v, %v)", tt.args.ctx, tt.args.request)) { + return + } + assert.Equalf(t, tt.want, got, "GetGitFiles(%v, %v)", tt.args.ctx, tt.args.request) + }) + } +} + +func TestGetGitFiles(t *testing.T) { + // test not using the cache + files := []string{"./testdata/git-files-dirs/somedir/config.yaml", + "./testdata/git-files-dirs/config.yaml", "./testdata/git-files-dirs/config.yaml", "./testdata/git-files-dirs/app/foo/bar/config.yaml"} + root := "" + s, _ := newServiceWithOpt(func(gitClient *gitmocks.Client, helmClient *helmmocks.Client, paths *iomocks.TempPaths) { + gitClient.On("Init").Return(nil) + gitClient.On("Fetch", mock.Anything).Return(nil) + gitClient.On("Checkout", mock.Anything, mock.Anything).Once().Return(nil) + gitClient.On("LsRemote", "HEAD").Return("632039659e542ed7de0c170a4fcc1c571b288fc0", nil) + gitClient.On("Root").Return(root) + gitClient.On("LsFiles", mock.Anything).Once().Return(files, nil) + paths.On("GetPath", mock.Anything).Return(root, nil) + paths.On("GetPathIfExists", mock.Anything).Return(root, nil) + }, root) + filesRequest := &apiclient.GitFilesRequest{ + Repo: &argoappv1.Repository{Repo: "a-url.com"}, + SubmoduleEnabled: false, + Revision: "HEAD", + } + + // expected map + expected := make(map[string][]byte) + for _, filePath := range files { + fileContents, err := os.ReadFile(filePath) + assert.Nil(t, err) + expected[filePath] = fileContents + } + + fileResponse, err := s.GetGitFiles(context.TODO(), filesRequest) + assert.Nil(t, err) + assert.Equal(t, fileResponse.GetMap(), expected) + + // do the same request again to use the cache + // we only allow LsFiles to be called once in the mock + fileResponse, err = s.GetGitFiles(context.TODO(), filesRequest) + assert.Nil(t, err) + assert.Equal(t, expected, fileResponse.GetMap()) +} + +func Test_getRepoSanitizerRegex(t *testing.T) { + r := getRepoSanitizerRegex("/tmp/_argocd-repo") + msg := r.ReplaceAllString("error message containing /tmp/_argocd-repo/SENSITIVE and other stuff", "") + assert.Equal(t, "error message containing and other stuff", msg) + msg = r.ReplaceAllString("error message containing /tmp/_argocd-repo/SENSITIVE/with/trailing/path and other stuff", "") + assert.Equal(t, "error message containing /with/trailing/path and other stuff", msg) +} diff --git a/reposerver/repository/testdata/git-files-dirs/app/bar/.hidden/.keep b/reposerver/repository/testdata/git-files-dirs/app/bar/.hidden/.keep new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/reposerver/repository/testdata/git-files-dirs/app/bar/.keep b/reposerver/repository/testdata/git-files-dirs/app/bar/.keep new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/reposerver/repository/testdata/git-files-dirs/app/foo/bar/config.yaml b/reposerver/repository/testdata/git-files-dirs/app/foo/bar/config.yaml new file mode 100644 index 0000000000000..433c6b94dc0cf --- /dev/null +++ b/reposerver/repository/testdata/git-files-dirs/app/foo/bar/config.yaml @@ -0,0 +1,2 @@ +version: 4.2.1a +name: fooaaaa \ No newline at end of file diff --git a/reposerver/repository/testdata/git-files-dirs/app/foo/config.yaml b/reposerver/repository/testdata/git-files-dirs/app/foo/config.yaml new file mode 100644 index 0000000000000..096b2f1a35b87 --- /dev/null +++ b/reposerver/repository/testdata/git-files-dirs/app/foo/config.yaml @@ -0,0 +1,2 @@ +version: 4.2.1 +name: foo \ No newline at end of file diff --git a/reposerver/repository/testdata/git-files-dirs/config.yaml b/reposerver/repository/testdata/git-files-dirs/config.yaml new file mode 100644 index 0000000000000..5c0feb3c03c8a --- /dev/null +++ b/reposerver/repository/testdata/git-files-dirs/config.yaml @@ -0,0 +1,2 @@ +version: 4.2.1.5 +name: foooooo \ No newline at end of file diff --git a/reposerver/repository/testdata/git-files-dirs/somedir/config.yaml b/reposerver/repository/testdata/git-files-dirs/somedir/config.yaml new file mode 100644 index 0000000000000..c66361bb14a46 --- /dev/null +++ b/reposerver/repository/testdata/git-files-dirs/somedir/config.yaml @@ -0,0 +1,2 @@ +version: 2.1 +name: fo \ No newline at end of file diff --git a/server/version/version.go b/server/version/version.go index e899a7ab590d5..cc4eeb24152a6 100644 --- a/server/version/version.go +++ b/server/version/version.go @@ -2,6 +2,7 @@ package version import ( "context" + "github.com/golang/protobuf/ptypes/empty" "github.com/google/go-jsonnet" @@ -67,6 +68,7 @@ func (s *Server) Version(ctx context.Context, _ *empty.Empty) (*version.VersionM HelmVersion: s.helmVersion, JsonnetVersion: s.jsonnetVersion, KubectlVersion: vers.KubectlVersion, + ExtraBuildInfo: vers.ExtraBuildInfo, }, nil } diff --git a/server/version/version.proto b/server/version/version.proto index a2bc1d685661f..f5b887aa29f00 100644 --- a/server/version/version.proto +++ b/server/version/version.proto @@ -23,6 +23,7 @@ message VersionMessage { string HelmVersion = 11; string KubectlVersion = 12; string JsonnetVersion = 13; + string ExtraBuildInfo = 14; } // VersionService returns the version of the API server. diff --git a/test/container/Procfile b/test/container/Procfile index 3eb8edefffd07..7f0637e80d675 100644 --- a/test/container/Procfile +++ b/test/container/Procfile @@ -10,5 +10,5 @@ fcgiwrap: sudo sh -c "test $ARGOCD_E2E_TEST = true && (fcgiwrap -s unix:/var/run nginx: sudo sh -c "test $ARGOCD_E2E_TEST = true && nginx -g 'daemon off;' -c $(pwd)/test/fixture/testrepos/nginx.conf" helm-registry: sudo sh -c "registry serve /etc/docker/registry/config.yml" dev-mounter: test "$ARGOCD_E2E_TEST" != "true" && go run hack/dev-mounter/main.go --configmap argocd-ssh-known-hosts-cm=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} --configmap argocd-tls-certs-cm=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} --configmap argocd-gpg-keys-cm=${ARGOCD_GPG_DATA_PATH:-/tmp/argocd-local/gpg/source} -applicationset-controller: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=4 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_ASK_PASS_SOCK=/tmp/applicationset-ask-pass.sock ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-applicationset-controller $COMMAND --loglevel debug --metrics-addr localhost:12345 --probe-addr localhost:12346 --argocd-repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081}" +applicationset-controller: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=4 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-applicationset-controller $COMMAND --loglevel debug --metrics-addr localhost:12345 --probe-addr localhost:12346 --argocd-repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081}" notification: sh -c "FORCE_LOG_COLORS=4 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_BINARY_NAME=argocd-notifications go run ./cmd/main.go --loglevel debug" diff --git a/ui/src/app/applications/components/application-details/application-details.scss b/ui/src/app/applications/components/application-details/application-details.scss index 9390e4534034b..6eac2b2f57097 100644 --- a/ui/src/app/applications/components/application-details/application-details.scss +++ b/ui/src/app/applications/components/application-details/application-details.scss @@ -213,8 +213,7 @@ $header: 120px; display: inline-block; background-color: $argo-color-gray-1; box-shadow: 1px 1px 3px $argo-color-gray-5; - position: fixed; - + position: absolute; a { padding: 5px; margin: 2px; @@ -227,7 +226,6 @@ $header: 120px; position: relative; display: inline-block; vertical-align: middle; - font-size: 13px; font-weight: 500; line-height: 1.4; text-align: center; @@ -246,9 +244,13 @@ $header: 120px; &.group-nodes-button-on { color: $argo-color-gray-1; background-color: $argo-color-gray-6; + border: 3px solid $argo-color-teal-4; + font-size: 14px; + outline-style: solid; &:hover { background-color: $argo-color-gray-5; } + } } @@ -260,7 +262,7 @@ $header: 120px; .zoom-value { user-select: none; - margin-top: 3px; + margin-top: 5px; margin-right: 6px; margin-left: 4px; font-size: 14px; @@ -344,4 +346,32 @@ $header: 120px; .sb-page-wrapper .top-bar.row { display: none !important; } -} \ No newline at end of file +} + +.resource-parent-node-info-title { + flex-direction: column; + color: $argo-color-gray-6; + + &__label { + display: flex; + margin-bottom: 0.25em; + flex-shrink: 1; + div:first-child { + margin-right: 10px; + width: 60px; + text-align: right; + } + div:last-child { + font-weight: 500; + width: 100%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + text-align: left; + + } + } +} + + + diff --git a/ui/src/app/applications/components/application-details/application-details.tsx b/ui/src/app/applications/components/application-details/application-details.tsx index 9504219af4755..75eabc52b3caa 100644 --- a/ui/src/app/applications/components/application-details/application-details.tsx +++ b/ui/src/app/applications/components/application-details/application-details.tsx @@ -87,8 +87,16 @@ export class ApplicationDetails extends React.Component { extensionsMap[ext.title] = ext; }); - - this.state = {page: 0, groupedResources: [], slidingPanelPage: 0, filteredGraph: [], truncateNameOnRight: false, collapsedNodes: [], extensions, extensionsMap}; + this.state = { + page: 0, + groupedResources: [], + slidingPanelPage: 0, + filteredGraph: [], + truncateNameOnRight: false, + collapsedNodes: [], + extensions, + extensionsMap + }; if (typeof this.props.match.params.appnamespace === 'undefined') { this.appNamespace = ''; } else { @@ -285,6 +293,9 @@ export class ApplicationDetails extends React.Component { this.setState({filteredGraph: filterGraph}); }; + const setShowCompactNodes = (showCompactView: boolean) => { + services.viewPreferences.updatePreferences({appDetails: {...pref, groupNodes: showCompactView}}); + }; const toggleNameDirection = () => { this.setState({truncateNameOnRight: !this.state.truncateNameOnRight}); }; @@ -333,7 +344,7 @@ export class ApplicationDetails extends React.Component + this.filterTreeNode(node, treeFilter)} @@ -475,10 +488,12 @@ export class ApplicationDetails extends React.Component openGroupNodeDetails(groupdedNodeIds)} zoom={pref.zoom} + podGroupCount={pref.podGroupCount} appContext={this.appContext} nameDirection={this.state.truncateNameOnRight} filters={pref.resourceFilter} setTreeFilterGraph={setFilterGraph} + setShowCompactNodes={setShowCompactNodes} setNodeExpansion={(node, isExpanded) => this.setNodeExpansion(node, isExpanded)} getNodeExpansion={node => this.getNodeExpansion(node)} /> @@ -533,6 +548,7 @@ export class ApplicationDetails extends React.Component this.getApplicationActionMenu(application, false) ) } + tree={tree} /> )} @@ -561,6 +577,7 @@ export class ApplicationDetails extends React.Component )} diff --git a/ui/src/app/applications/components/application-details/application-resource-list.tsx b/ui/src/app/applications/components/application-details/application-resource-list.tsx index 30c4531b6eeaf..dba61c5135492 100644 --- a/ui/src/app/applications/components/application-details/application-resource-list.tsx +++ b/ui/src/app/applications/components/application-details/application-resource-list.tsx @@ -1,102 +1,157 @@ import {DropDown} from 'argo-ui'; -import * as classNames from 'classnames'; import * as React from 'react'; - +import * as classNames from 'classnames'; import * as models from '../../../shared/models'; import {ResourceIcon} from '../resource-icon'; import {ResourceLabel} from '../resource-label'; import {ComparisonStatusIcon, HealthStatusIcon, nodeKey, createdOrNodeKey} from '../utils'; import {Consumer} from '../../../shared/context'; import * as _ from 'lodash'; +import Moment from 'react-moment'; +import {format} from 'date-fns'; +import {ResourceNode, ResourceRef} from '../../../shared/models'; export const ApplicationResourceList = ({ resources, onNodeClick, - nodeMenu + nodeMenu, + tree }: { resources: models.ResourceStatus[]; onNodeClick?: (fullName: string) => any; nodeMenu?: (node: models.ResourceNode) => React.ReactNode; -}) => ( -
-
-
-
-
NAME
-
GROUP/KIND
-
SYNC ORDER
-
NAMESPACE
-
CREATED AT
-
STATUS
+ tree?: models.ApplicationTree; +}) => { + function getResNode(nodes: ResourceNode[], nodeId: string): models.ResourceNode { + for (const node of nodes) { + if (nodeKey(node) === nodeId) { + return node; + } + } + return null; + } + const parentNode = ((resources || []).length > 0 && (getResNode(tree.nodes, nodeKey(resources[0])) as ResourceNode)?.parentRefs?.[0]) || ({} as ResourceRef); + + return ( +
+
+ {Object.keys(parentNode).length > 0 && ( +
+
Parent Node Info
+
+
Name:
+
{parentNode?.name}
+
+
+
Kind:
+
{parentNode?.kind}
+
+
+ )}
-
- {resources - .sort((first, second) => -createdOrNodeKey(first).localeCompare(createdOrNodeKey(second))) - .map(res => ( -
onNodeClick(nodeKey(res))}> +
+
-
-
- -
-
{ResourceLabel({kind: res.kind})}
-
-
-
- {res.name} - {res.kind === 'Application' && ( - - {ctx => ( - - - - +
+
NAME
+
GROUP/KIND
+
SYNC ORDER
+
NAMESPACE
+ {(parentNode.kind === 'Rollout' || parentNode.kind === 'Deployment') &&
REVISION
} +
CREATED AT
+
STATUS
+
+
+ {resources + .sort((first, second) => -createdOrNodeKey(first).localeCompare(createdOrNodeKey(second))) + .map(res => ( +
onNodeClick(nodeKey(res))}> +
+
+
+ +
+
{ResourceLabel({kind: res.kind})}
+
+
+
+ {res.name} + {res.kind === 'Application' && ( + + {ctx => ( + + + + + + )} + + )} +
+
{[res.group, res.kind].filter(item => !!item).join('/')}
+
{res.syncWave || '-'}
+
{res.namespace}
+ {res.kind === 'ReplicaSet' && + ((getResNode(tree.nodes, nodeKey(res)) as ResourceNode).info || []) + .filter(tag => !tag.name.includes('Node')) + .slice(0, 4) + .map((tag, i) => { + return ( +
+ {tag?.value?.split(':')[1] || '-'} +
+ ); + })} + +
+ {res.createdAt && ( + + + {res.createdAt} + +  ago   {format(new Date(res.createdAt), 'MM/dd/yy')} )} - - )} -
-
{[res.group, res.kind].filter(item => !!item).join('/')}
-
{res.syncWave || '-'}
-
{res.namespace}
-
{res.createdAt}
-
- {res.health && ( - - {res.health.status}   - - )} - {res.status && } - {res.hook && } -
- ( - - )}> - {nodeMenu({ - name: res.name, - version: res.version, - kind: res.kind, - namespace: res.namespace, - group: res.group, - info: null, - uid: '', - resourceVersion: null, - parentRefs: [] - })} - +
+
+ {res.health && ( + + {res.health.status}   + + )} + {res.status && } + {res.hook && } +
+ ( + + )}> + {nodeMenu({ + name: res.name, + version: res.version, + kind: res.kind, + namespace: res.namespace, + group: res.group, + info: null, + uid: '', + resourceVersion: null, + parentRefs: [] + })} + +
+
-
-
- ))} -
-); + ))} +
+
+ ); +}; diff --git a/ui/src/app/applications/components/application-parameters/application-parameters.tsx b/ui/src/app/applications/components/application-parameters/application-parameters.tsx index 16c2ea5c5c909..819f063d31d4a 100644 --- a/ui/src/app/applications/components/application-parameters/application-parameters.tsx +++ b/ui/src/app/applications/components/application-parameters/application-parameters.tsx @@ -319,7 +319,7 @@ export const ApplicationParameters = (props: { const liveParam = app.spec.source.plugin?.parameters?.find(param => param.name === name); const pluginIcon = announcement && liveParam ? 'This parameter has been provided by plugin, but is overridden in application manifest.' : 'This parameter is provided by the plugin.'; - const isPluginPar = announcement ? true : false; + const isPluginPar = !!announcement; if ((announcement?.collectionType === undefined && liveParam?.map) || announcement?.collectionType === 'map') { let liveParamMap; if (liveParam) { @@ -351,7 +351,7 @@ export const ApplicationParameters = (props: { &--fill { background-color: $argo-color-teal-8; } - + &:hover &--neighbors { background-color: $argo-color-gray-7; } @@ -365,6 +375,7 @@ margin-right: 1px; } + &__node-kind { font-size: 0.7em; color: $argo-color-gray-6; @@ -398,5 +409,11 @@ &__direction-right { direction: rtl; } - -} + &__direction-center-left { + overflow: hidden; + padding-top: 15px; + padding-left: 15px; + + } + +} \ No newline at end of file diff --git a/ui/src/app/applications/components/application-resource-tree/application-resource-tree.tsx b/ui/src/app/applications/components/application-resource-tree/application-resource-tree.tsx index 29707816b7e05..5343e2f256ca9 100644 --- a/ui/src/app/applications/components/application-resource-tree/application-resource-tree.tsx +++ b/ui/src/app/applications/components/application-resource-tree/application-resource-tree.tsx @@ -1,4 +1,4 @@ -import {DropDown, DropDownMenu, Tooltip} from 'argo-ui'; +import {DropDown, DropDownMenu, NotificationType, Tooltip} from 'argo-ui'; import * as classNames from 'classnames'; import * as dagre from 'dagre'; import * as React from 'react'; @@ -26,8 +26,8 @@ import { } from '../utils'; import {NodeUpdateAnimation} from './node-update-animation'; import {PodGroup} from '../application-pod-view/pod-view'; -import {ArrowConnector} from './arrow-connector'; import './application-resource-tree.scss'; +import {ArrowConnector} from './arrow-connector'; function treeNodeKey(node: NodeId & {uid?: string}) { return node.uid || nodeKey(node); @@ -59,7 +59,9 @@ export interface ApplicationResourceTreeProps { appContext?: AppContext; showOrphanedResources: boolean; showCompactNodes: boolean; + setShowCompactNodes: (showCompactNodes: boolean) => void; zoom: number; + podGroupCount: number; filters?: string[]; setTreeFilterGraph?: (filterGraph: any[]) => void; nameDirection: boolean; @@ -88,7 +90,6 @@ const NODE_TYPES = { groupedNodes: 'grouped_nodes', podGroup: 'pod_group' }; - // generate lots of colors with different darkness const TRAFFIC_COLORS = [0, 0.25, 0.4, 0.6] .map(darken => @@ -292,10 +293,22 @@ function renderGroupedNodes(props: ApplicationResourceTreeProps, node: {count: n
{ResourceLabel({kind: node.kind})}
-
- props.onGroupdNodeClick && props.onGroupdNodeClick(node.groupedNodeIds)}> - click to show details of {node.count} collapsed {node.kind} - +
props.onGroupdNodeClick && props.onGroupdNodeClick(node.groupedNodeIds)} + title={`Click to see details of ${node.count} collapsed ${node.kind} and doesn't contains any active pods`}> + {node.kind} + + {node.kind === 'ReplicaSet' ? ( + + ) : ( + + )} +
{indicators.map(i => ( @@ -408,21 +421,47 @@ function renderPodGroup(props: ApplicationResourceTreeProps, id: string, node: R const margin = 8; let topExtra = 0; const podGroup = node.podGroup; + const podGroupHealthy = []; + const podGroupDegraded = []; + const podGroupInProgress = []; + + for (const pod of podGroup?.pods || []) { + switch (pod.health) { + case 'Healthy': + podGroupHealthy.push(pod); + break; + case 'Degraded': + podGroupDegraded.push(pod); + break; + case 'Progressing': + podGroupInProgress.push(pod); + } + } + + const showPodGroupByStatus = props.tree.nodes.filter((rNode: ResourceTreeNode) => rNode.kind === 'Pod').length >= props.podGroupCount; + const numberOfRows = showPodGroupByStatus + ? [podGroupHealthy, podGroupDegraded, podGroupInProgress].reduce((total, podGroupByStatus) => total + (podGroupByStatus.filter(pod => pod).length > 0 ? 1 : 0), 0) + : Math.ceil(podGroup?.pods.length / 8); + if (podGroup) { - const numberOfRows = Math.ceil(podGroup.pods.length / 8); topExtra = margin + (POD_NODE_HEIGHT / 2 + 30 * numberOfRows) / 2; } + return (
props.onNodeClick && props.onNodeClick(fullName)} className={classNames('application-resource-tree__node', { 'active': fullName === props.selectedNodeFullName, 'application-resource-tree__node--orphaned': node.orphaned })} title={describeNode(node)} - style={{left: node.x, top: node.y - topExtra, width: node.width, height: node.height}}> + style={{ + left: node.x, + top: node.y - topExtra, + width: node.width, + height: showPodGroupByStatus ? POD_NODE_HEIGHT + 20 * numberOfRows : node.height + }}> -
+
props.onNodeClick && props.onNodeClick(fullName)} className={`application-resource-tree__node__top-part`}>
+ })} + onClick={() => props.onGroupdNodeClick && props.onGroupdNodeClick(node.groupedNodeIds)}> {node.name} (
- {podGroup && ( -
-
-
- {podGroup.pods.map(pod => ( - ( - - {pod.metadata.name} -
Health: {pod.health}
- {pod.createdAt && ( - - Created: - - {pod.createdAt} - - ago ({{pod.createdAt}}) - - )} -
- } - popperOptions={{ - modifiers: { - preventOverflow: { - enabled: true - }, - hide: { - enabled: false - }, - flip: { - enabled: false - } - } - }} - key={pod.metadata.name}> -
- {isYoungerThanXMinutes(pod, 30) && ( - - )} -
- -
-
- - )} - items={[ - { - title: ( - - Info - - ), - action: () => props.onNodeClick(pod.fullName) - }, - { - title: ( - - Logs - - ), - action: () => { - props.appContext.apis.navigation.goto('.', {node: pod.fullName, tab: 'logs'}, {replace: true}); - } - }, - { - title: ( - - Delete - - ), - action: () => { - deletePodAction(pod, props.appContext, props.app.metadata.name, props.app.metadata.namespace); - } - } - ]} - /> - ))} -
-
PODS
+ {[podGroupHealthy, podGroupDegraded, podGroupInProgress].map((pods, index) => { + return ( +
+ {renderPodGroupByStatus(props, node, pods, showPodGroupByStatus)}
-
- )} + ); + })}
); } +function renderPodGroupByStatus(props: ApplicationResourceTreeProps, node: any, pods: models.Pod[], showPodGroupByStatus: boolean) { + return ( +
+ {pods.length !== 0 && showPodGroupByStatus ? ( + +
+ +
+ + +
+ ) : ( + pods.map(pod => ( + ( + + {pod.metadata.name} +
Health: {pod.health}
+ {pod.createdAt && ( + + Created: + + {pod.createdAt} + + ago ({{pod.createdAt}}) + + )} +
+ } + popperOptions={{ + modifiers: { + preventOverflow: { + enabled: true + }, + hide: { + enabled: false + }, + flip: { + enabled: false + } + } + }} + key={pod.metadata.name}> +
+ {isYoungerThanXMinutes(pod, 30) && ( + + )} +
+ +
+
+ + )} + items={[ + { + title: ( + + Info + + ), + action: () => props.onNodeClick(pod.fullName) + }, + { + title: ( + + Logs + + ), + action: () => { + props.appContext.apis.navigation.goto('.', {node: pod.fullName, tab: 'logs'}, {replace: true}); + } + }, + { + title: ( + + Delete + + ), + action: () => { + deletePodAction(pod, props.appContext, props.app.metadata.name, props.app.metadata.namespace); + } + } + ]} + /> + )) + )} +
+ ); +} + function expandCollapse(node: ResourceTreeNode, props: ApplicationResourceTreeProps) { const isExpanded = !props.getNodeExpansion(node.uid); node.isExpanded = isExpanded; @@ -860,6 +927,23 @@ export const ApplicationResourceTree = (props: ApplicationResourceTreeProps) => } }, [props.filters]); + const [defaultCompactView, setDefaultCompactView] = React.useState(false); + React.useEffect(() => { + const {podGroupCount, setShowCompactNodes, appContext} = props; + const podCount = nodes.filter(node => node.kind === 'Pod').length; + + if (!defaultCompactView && podCount > podGroupCount) { + setShowCompactNodes(true); + setDefaultCompactView(true); + + appContext.apis.notifications.show({ + content: `Since the number of pods has surpassed the threshold pod count of ${podGroupCount}, you will now be switched to the group node view. + If you prefer the tree view, you can simply click on the Group Nodes toolbar button to deselect the current view.`, + type: NotificationType.Success + }); + } + }, [props.setShowCompactNodes, props.showCompactNodes, defaultCompactView]); + function filterGraph(app: models.Application, filteredIndicatorParent: string, graphNodesFilter: dagre.graphlib.Graph, predicate: (node: ResourceTreeNode) => boolean) { const appKey = appNodeKey(app); let filtered = 0; diff --git a/ui/src/app/applications/components/applications-list/applications-tiles.tsx b/ui/src/app/applications/components/applications-list/applications-tiles.tsx index c07f3b156b133..7665c472e80b1 100644 --- a/ui/src/app/applications/components/applications-list/applications-tiles.tsx +++ b/ui/src/app/applications/components/applications-list/applications-tiles.tsx @@ -258,6 +258,16 @@ export const ApplicationTiles = ({applications, syncApplication, refreshApplicat
{AppUtils.formatCreationTimestamp(app.metadata.creationTimestamp)}
+ {app.status.operationState && ( +
+
+ Last Sync: +
+
+ {AppUtils.formatCreationTimestamp(app.status.operationState.finishedAt || app.status.operationState.startedAt)} +
+
+ )}
(
-
{props.children}
+
+ {props.children} +
); diff --git a/ui/src/app/shared/services/view-preferences-service.ts b/ui/src/app/shared/services/view-preferences-service.ts index f2321fc6677f1..314170dba0404 100644 --- a/ui/src/app/shared/services/view-preferences-service.ts +++ b/ui/src/app/shared/services/view-preferences-service.ts @@ -27,6 +27,7 @@ export interface AppDetailsPreferences { wrapLines: boolean; groupNodes?: boolean; zoom: number; + podGroupCount: number; } export interface PodViewPreferences { @@ -120,7 +121,8 @@ const DEFAULT_PREFERENCES: ViewPreferences = { darkMode: false, followLogs: false, wrapLines: false, - zoom: 1.0 + zoom: 1.0, + podGroupCount: 15.0 }, appList: { view: 'tiles' as AppsListViewType, diff --git a/util/cli/cli.go b/util/cli/cli.go index a91a6fdd7e21b..d6baf1395dc64 100644 --- a/util/cli/cli.go +++ b/util/cli/cli.go @@ -52,6 +52,9 @@ func NewVersionCmd(cliName string) *cobra.Command { fmt.Printf(" GoVersion: %s\n", version.GoVersion) fmt.Printf(" Compiler: %s\n", version.Compiler) fmt.Printf(" Platform: %s\n", version.Platform) + if version.ExtraBuildInfo != "" { + fmt.Printf(" ExtraBuildInfo: %s\n", version.ExtraBuildInfo) + } }, } versionCmd.Flags().BoolVar(&short, "short", false, "print just the version number") diff --git a/util/helm/helm.go b/util/helm/helm.go index e997d9f6116f1..edb0f3b672b35 100644 --- a/util/helm/helm.go +++ b/util/helm/helm.go @@ -16,6 +16,11 @@ import ( pathutil "github.com/argoproj/argo-cd/v2/util/io/path" ) +const ( + ResourcePolicyAnnotation = "helm.sh/resource-policy" + ResourcePolicyKeep = "keep" +) + type HelmRepository struct { Creds Name string