mirror of
https://github.com/argoproj/argo-cd.git
synced 2026-02-20 09:38:49 +01:00
Compare commits
17 Commits
hydrator-c
...
v2.12.0-rc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0704aa6506 | ||
|
|
511d6e371c | ||
|
|
065f8494cf | ||
|
|
beacacc43d | ||
|
|
81d454215d | ||
|
|
1237d4ea17 | ||
|
|
b211d3e038 | ||
|
|
50c32b53f0 | ||
|
|
444d332d0a | ||
|
|
573c771d2b | ||
|
|
e616dff2d1 | ||
|
|
e36e19de4e | ||
|
|
bbfa79ad9e | ||
|
|
00fc93b8b2 | ||
|
|
16c20a84b8 | ||
|
|
2a9a62eeb7 | ||
|
|
fe60670885 |
@@ -129,20 +129,18 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
|
||||
// Log a warning if there are unrecognized generators
|
||||
_ = utils.CheckInvalidGenerators(&applicationSetInfo)
|
||||
// desiredApplications is the main list of all expected Applications from all generators in this appset.
|
||||
desiredApplications, applicationSetReason, generatorsErr := r.generateApplications(logCtx, applicationSetInfo)
|
||||
if generatorsErr != nil {
|
||||
desiredApplications, applicationSetReason, err := r.generateApplications(logCtx, applicationSetInfo)
|
||||
if err != nil {
|
||||
_ = r.setApplicationSetStatusCondition(ctx,
|
||||
&applicationSetInfo,
|
||||
argov1alpha1.ApplicationSetCondition{
|
||||
Type: argov1alpha1.ApplicationSetConditionErrorOccurred,
|
||||
Message: generatorsErr.Error(),
|
||||
Message: err.Error(),
|
||||
Reason: string(applicationSetReason),
|
||||
Status: argov1alpha1.ApplicationSetConditionStatusTrue,
|
||||
}, parametersGenerated,
|
||||
)
|
||||
if len(desiredApplications) < 1 {
|
||||
return ctrl.Result{}, generatorsErr
|
||||
}
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
parametersGenerated = true
|
||||
@@ -320,7 +318,7 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
|
||||
|
||||
requeueAfter := r.getMinRequeueAfter(&applicationSetInfo)
|
||||
|
||||
if len(validateErrors) == 0 && generatorsErr == nil {
|
||||
if len(validateErrors) == 0 {
|
||||
if err := r.setApplicationSetStatusCondition(ctx,
|
||||
&applicationSetInfo,
|
||||
argov1alpha1.ApplicationSetCondition{
|
||||
|
||||
@@ -2471,90 +2471,6 @@ func TestReconcilerValidationProjectErrorBehaviour(t *testing.T) {
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestReconcilerCreateAppsRecoveringRenderError(t *testing.T) {
|
||||
scheme := runtime.NewScheme()
|
||||
err := v1alpha1.AddToScheme(scheme)
|
||||
require.NoError(t, err)
|
||||
err = v1alpha1.AddToScheme(scheme)
|
||||
require.NoError(t, err)
|
||||
|
||||
project := v1alpha1.AppProject{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: "argocd"},
|
||||
}
|
||||
appSet := v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "name",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
GoTemplate: true,
|
||||
Generators: []v1alpha1.ApplicationSetGenerator{
|
||||
{
|
||||
List: &v1alpha1.ListGenerator{
|
||||
Elements: []apiextensionsv1.JSON{{
|
||||
Raw: []byte(`{"name": "very-good-app"}`),
|
||||
}, {
|
||||
Raw: []byte(`{"name": "bad-app"}`),
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
Template: v1alpha1.ApplicationSetTemplate{
|
||||
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{
|
||||
Name: "{{ index (splitList \"-\" .name ) 2 }}",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSpec{
|
||||
Source: &v1alpha1.ApplicationSource{RepoURL: "https://github.com/argoproj/argocd-example-apps", Path: "guestbook"},
|
||||
Project: "default",
|
||||
Destination: v1alpha1.ApplicationDestination{Server: "https://kubernetes.default.svc"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
kubeclientset := kubefake.NewSimpleClientset()
|
||||
argoDBMock := dbmocks.ArgoDB{}
|
||||
argoObjs := []runtime.Object{&project}
|
||||
|
||||
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appSet).WithStatusSubresource(&appSet).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).Build()
|
||||
|
||||
r := ApplicationSetReconciler{
|
||||
Client: client,
|
||||
Scheme: scheme,
|
||||
Renderer: &utils.Render{},
|
||||
Recorder: record.NewFakeRecorder(1),
|
||||
Cache: &fakeCache{},
|
||||
Generators: map[string]generators.Generator{
|
||||
"List": generators.NewListGenerator(),
|
||||
},
|
||||
ArgoDB: &argoDBMock,
|
||||
ArgoAppClientset: appclientset.NewSimpleClientset(argoObjs...),
|
||||
KubeClientset: kubeclientset,
|
||||
Policy: v1alpha1.ApplicationsSyncPolicySync,
|
||||
ArgoCDNamespace: "argocd",
|
||||
}
|
||||
|
||||
req := ctrl.Request{
|
||||
NamespacedName: types.NamespacedName{
|
||||
Namespace: "argocd",
|
||||
Name: "name",
|
||||
},
|
||||
}
|
||||
|
||||
// Verify that on generatorsError, no error is returned, but the object is requeued
|
||||
res, err := r.Reconcile(context.Background(), req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, ReconcileRequeueOnValidationError, res.RequeueAfter)
|
||||
|
||||
var app v1alpha1.Application
|
||||
|
||||
// make sure good app got created
|
||||
err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "app"}, &app)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "app", app.Name)
|
||||
}
|
||||
|
||||
func TestSetApplicationSetStatusCondition(t *testing.T) {
|
||||
scheme := runtime.NewScheme()
|
||||
err := v1alpha1.AddToScheme(scheme)
|
||||
|
||||
@@ -104,7 +104,17 @@ func loadClusters(ctx context.Context, kubeClient *kubernetes.Clientset, appClie
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client := redis.NewClient(&redis.Options{Addr: fmt.Sprintf("localhost:%d", port)})
|
||||
|
||||
redisOptions := &redis.Options{Addr: fmt.Sprintf("localhost:%d", port)}
|
||||
|
||||
secret, err := kubeClient.CoreV1().Secrets(namespace).Get(context.Background(), defaulRedisInitialPasswordSecretName, v1.GetOptions{})
|
||||
if err == nil {
|
||||
if _, ok := secret.Data[defaultResisInitialPasswordKey]; ok {
|
||||
redisOptions.Password = string(secret.Data[defaultResisInitialPasswordKey])
|
||||
}
|
||||
}
|
||||
|
||||
client := redis.NewClient(redisOptions)
|
||||
compressionType, err := cacheutil.CompressionTypeFromString(redisCompressionStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -776,8 +776,6 @@ func NewApplicationSetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Com
|
||||
}
|
||||
}
|
||||
|
||||
// sourcePosition startes with 1, thus, it needs to be decreased by 1 to find the correct index in the list of sources
|
||||
sourcePosition = sourcePosition - 1
|
||||
visited := cmdutil.SetAppSpecOptions(c.Flags(), &app.Spec, &appOpts, sourcePosition)
|
||||
if visited == 0 {
|
||||
log.Error("Please set at least one option to update")
|
||||
|
||||
@@ -374,8 +374,8 @@ data:
|
||||
|
||||
var fakePostDeleteHook = `
|
||||
{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Pod",
|
||||
"apiVersion": "batch/v1",
|
||||
"kind": "Job",
|
||||
"metadata": {
|
||||
"name": "post-delete-hook",
|
||||
"namespace": "default",
|
||||
@@ -388,22 +388,93 @@ var fakePostDeleteHook = `
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"containers": [
|
||||
{
|
||||
"name": "post-delete-hook",
|
||||
"image": "busybox",
|
||||
"restartPolicy": "Never",
|
||||
"command": [
|
||||
"/bin/sh",
|
||||
"-c",
|
||||
"sleep 5 && echo hello from the post-delete-hook pod"
|
||||
]
|
||||
"template": {
|
||||
"metadata": {
|
||||
"name": "post-delete-hook"
|
||||
},
|
||||
"spec": {
|
||||
"containers": [
|
||||
{
|
||||
"name": "post-delete-hook",
|
||||
"image": "busybox",
|
||||
"command": [
|
||||
"/bin/sh",
|
||||
"-c",
|
||||
"sleep 5 && echo hello from the post-delete-hook job"
|
||||
]
|
||||
}
|
||||
],
|
||||
"restartPolicy": "Never"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
var fakeServiceAccount = `
|
||||
{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ServiceAccount",
|
||||
"metadata": {
|
||||
"name": "hook-serviceaccount",
|
||||
"namespace": "default",
|
||||
"annotations": {
|
||||
"argocd.argoproj.io/hook": "PostDelete",
|
||||
"argocd.argoproj.io/hook-delete-policy": "BeforeHookCreation,HookSucceeded"
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
var fakeRole = `
|
||||
{
|
||||
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||
"kind": "Role",
|
||||
"metadata": {
|
||||
"name": "hook-role",
|
||||
"namespace": "default",
|
||||
"annotations": {
|
||||
"argocd.argoproj.io/hook": "PostDelete",
|
||||
"argocd.argoproj.io/hook-delete-policy": "BeforeHookCreation,HookSucceeded"
|
||||
}
|
||||
},
|
||||
"rules": [
|
||||
{
|
||||
"apiGroups": [""],
|
||||
"resources": ["secrets"],
|
||||
"verbs": ["get", "delete", "list"]
|
||||
}
|
||||
]
|
||||
}
|
||||
`
|
||||
|
||||
var fakeRoleBinding = `
|
||||
{
|
||||
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||
"kind": "RoleBinding",
|
||||
"metadata": {
|
||||
"name": "hook-rolebinding",
|
||||
"namespace": "default",
|
||||
"annotations": {
|
||||
"argocd.argoproj.io/hook": "PostDelete",
|
||||
"argocd.argoproj.io/hook-delete-policy": "BeforeHookCreation,HookSucceeded"
|
||||
}
|
||||
},
|
||||
"roleRef": {
|
||||
"apiGroup": "rbac.authorization.k8s.io",
|
||||
"kind": "Role",
|
||||
"name": "hook-role"
|
||||
},
|
||||
"subjects": [
|
||||
{
|
||||
"kind": "ServiceAccount",
|
||||
"name": "hook-serviceaccount",
|
||||
"namespace": "default"
|
||||
}
|
||||
]
|
||||
}
|
||||
`
|
||||
|
||||
func newFakeApp() *v1alpha1.Application {
|
||||
return createFakeApp(fakeApp)
|
||||
}
|
||||
@@ -439,12 +510,39 @@ func newFakeCM() map[string]interface{} {
|
||||
}
|
||||
|
||||
func newFakePostDeleteHook() map[string]interface{} {
|
||||
var cm map[string]interface{}
|
||||
err := yaml.Unmarshal([]byte(fakePostDeleteHook), &cm)
|
||||
var hook map[string]interface{}
|
||||
err := yaml.Unmarshal([]byte(fakePostDeleteHook), &hook)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return cm
|
||||
return hook
|
||||
}
|
||||
|
||||
func newFakeRoleBinding() map[string]interface{} {
|
||||
var roleBinding map[string]interface{}
|
||||
err := yaml.Unmarshal([]byte(fakeRoleBinding), &roleBinding)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return roleBinding
|
||||
}
|
||||
|
||||
func newFakeRole() map[string]interface{} {
|
||||
var role map[string]interface{}
|
||||
err := yaml.Unmarshal([]byte(fakeRole), &role)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return role
|
||||
}
|
||||
|
||||
func newFakeServiceAccount() map[string]interface{} {
|
||||
var serviceAccount map[string]interface{}
|
||||
err := yaml.Unmarshal([]byte(fakeServiceAccount), &serviceAccount)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return serviceAccount
|
||||
}
|
||||
|
||||
func TestAutoSync(t *testing.T) {
|
||||
@@ -721,7 +819,7 @@ func TestFinalizeAppDeletion(t *testing.T) {
|
||||
|
||||
// Ensure any stray resources irregularly labeled with instance label of app are not deleted upon deleting,
|
||||
// when app project restriction is in place
|
||||
t.Run("ProjectRestrictionEnforced", func(*testing.T) {
|
||||
t.Run("ProjectRestrictionEnforced", func(t *testing.T) {
|
||||
restrictedProj := v1alpha1.AppProject{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "restricted",
|
||||
@@ -882,7 +980,13 @@ func TestFinalizeAppDeletion(t *testing.T) {
|
||||
app.SetPostDeleteFinalizer()
|
||||
app.Spec.Destination.Namespace = test.FakeArgoCDNamespace
|
||||
liveHook := &unstructured.Unstructured{Object: newFakePostDeleteHook()}
|
||||
require.NoError(t, unstructured.SetNestedField(liveHook.Object, "Succeeded", "status", "phase"))
|
||||
conditions := []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "Complete",
|
||||
"status": "True",
|
||||
},
|
||||
}
|
||||
require.NoError(t, unstructured.SetNestedField(liveHook.Object, conditions, "status", "conditions"))
|
||||
ctrl := newFakeController(&fakeData{
|
||||
manifestResponses: []*apiclient.ManifestResponse{{
|
||||
Manifests: []string{fakePostDeleteHook},
|
||||
@@ -916,15 +1020,27 @@ func TestFinalizeAppDeletion(t *testing.T) {
|
||||
app := newFakeApp()
|
||||
app.SetPostDeleteFinalizer("cleanup")
|
||||
app.Spec.Destination.Namespace = test.FakeArgoCDNamespace
|
||||
liveRoleBinding := &unstructured.Unstructured{Object: newFakeRoleBinding()}
|
||||
liveRole := &unstructured.Unstructured{Object: newFakeRole()}
|
||||
liveServiceAccount := &unstructured.Unstructured{Object: newFakeServiceAccount()}
|
||||
liveHook := &unstructured.Unstructured{Object: newFakePostDeleteHook()}
|
||||
require.NoError(t, unstructured.SetNestedField(liveHook.Object, "Succeeded", "status", "phase"))
|
||||
conditions := []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "Complete",
|
||||
"status": "True",
|
||||
},
|
||||
}
|
||||
require.NoError(t, unstructured.SetNestedField(liveHook.Object, conditions, "status", "conditions"))
|
||||
ctrl := newFakeController(&fakeData{
|
||||
manifestResponses: []*apiclient.ManifestResponse{{
|
||||
Manifests: []string{fakePostDeleteHook},
|
||||
Manifests: []string{fakeRoleBinding, fakeRole, fakeServiceAccount, fakePostDeleteHook},
|
||||
}},
|
||||
apps: []runtime.Object{app, &defaultProj},
|
||||
managedLiveObjs: map[kube.ResourceKey]*unstructured.Unstructured{
|
||||
kube.GetResourceKey(liveHook): liveHook,
|
||||
kube.GetResourceKey(liveRoleBinding): liveRoleBinding,
|
||||
kube.GetResourceKey(liveRole): liveRole,
|
||||
kube.GetResourceKey(liveServiceAccount): liveServiceAccount,
|
||||
kube.GetResourceKey(liveHook): liveHook,
|
||||
},
|
||||
}, nil)
|
||||
|
||||
@@ -943,9 +1059,14 @@ func TestFinalizeAppDeletion(t *testing.T) {
|
||||
return []*v1alpha1.Cluster{}, nil
|
||||
})
|
||||
require.NoError(t, err)
|
||||
// post-delete hook is deleted
|
||||
require.Len(t, ctrl.kubectl.(*MockKubectl).DeletedResources, 1)
|
||||
require.Equal(t, "post-delete-hook", ctrl.kubectl.(*MockKubectl).DeletedResources[0].Name)
|
||||
// post-delete hooks are deleted
|
||||
require.Len(t, ctrl.kubectl.(*MockKubectl).DeletedResources, 4)
|
||||
deletedResources := []string{}
|
||||
for _, res := range ctrl.kubectl.(*MockKubectl).DeletedResources {
|
||||
deletedResources = append(deletedResources, res.Name)
|
||||
}
|
||||
expectedNames := []string{"hook-rolebinding", "hook-role", "hook-serviceaccount", "post-delete-hook"}
|
||||
require.ElementsMatch(t, expectedNames, deletedResources, "Deleted resources should match expected names")
|
||||
// finalizer is not removed
|
||||
assert.False(t, patched)
|
||||
})
|
||||
|
||||
@@ -98,6 +98,18 @@ func (ctrl *ApplicationController) executePostDeleteHooks(app *v1alpha1.Applicat
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if hookHealth == nil {
|
||||
logCtx.WithFields(log.Fields{
|
||||
"group": obj.GroupVersionKind().Group,
|
||||
"version": obj.GroupVersionKind().Version,
|
||||
"kind": obj.GetKind(),
|
||||
"name": obj.GetName(),
|
||||
"namespace": obj.GetNamespace(),
|
||||
}).Info("No health check defined for resource, considering it healthy")
|
||||
hookHealth = &health.HealthStatus{
|
||||
Status: health.HealthStatusHealthy,
|
||||
}
|
||||
}
|
||||
if hookHealth.Status == health.HealthStatusProgressing {
|
||||
progressingHooksCnt++
|
||||
}
|
||||
@@ -128,6 +140,11 @@ func (ctrl *ApplicationController) cleanupPostDeleteHooks(liveObjs map[kube.Reso
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if hookHealth == nil {
|
||||
hookHealth = &health.HealthStatus{
|
||||
Status: health.HealthStatusHealthy,
|
||||
}
|
||||
}
|
||||
if health.IsWorse(aggregatedHealth, hookHealth.Status) {
|
||||
aggregatedHealth = hookHealth.Status
|
||||
}
|
||||
|
||||
@@ -326,7 +326,7 @@ As with other generators, clusters *must* already be defined within Argo CD, in
|
||||
In addition to the flattened key/value pairs from the configuration file, the following generator parameters are provided:
|
||||
|
||||
- `{{.path.path}}`: The path to the directory containing matching configuration file within the Git repository. Example: `/clusters/clusterA`, if the config file was `/clusters/clusterA/config.json`
|
||||
- `{{index .path n}}`: The path to the matching configuration file within the Git repository, split into array elements (`n` - array index). Example: `index .path 0: clusters`, `index .path 1: clusterA`
|
||||
- `{{index .path.segments n}}`: The path to the matching configuration file within the Git repository, split into array elements (`n` - array index). Example: `index .path.segments 0: clusters`, `index .path.segments 1: clusterA`
|
||||
- `{{.path.basename}}`: Basename of the path to the directory containing the configuration file (e.g. `clusterA`, with the above example.)
|
||||
- `{{.path.basenameNormalized}}`: This field is the same as `.path.basename` with unsupported characters replaced with `-` (e.g. a `path` of `/directory/directory_2`, and `.path.basename` of `directory_2` would produce `directory-2` here).
|
||||
- `{{.path.filename}}`: The matched filename. e.g., `config.json` in the above example.
|
||||
@@ -360,7 +360,7 @@ spec:
|
||||
files:
|
||||
- path: "applicationset/examples/git-generator-files-discovery/cluster-config/**/config.json"
|
||||
values:
|
||||
base_dir: "{{index .path 0}}/{{index .path 1}}/{{index .path 2}}"
|
||||
base_dir: "{{index .path.segments 0}}/{{index .path.segments 1}}/{{index .path.segments 2}}"
|
||||
template:
|
||||
metadata:
|
||||
name: '{{.cluster.name}}-guestbook'
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
| Argo CD version | Kubernetes versions |
|
||||
|-----------------|---------------------|
|
||||
| 2.7 | v1.26, v1.25, v1.24, v1.23 |
|
||||
| 2.6 | v1.24, v1.23, v1.22 |
|
||||
| 2.5 | v1.24, v1.23, v1.22 |
|
||||
|
||||
| 2.12 | |
|
||||
| 2.11 | v1.29, v1.28, v1.27, v1.26, v1.25 |
|
||||
| 2.10 | v1.28, v1.27, v1.26, v1.25 |
|
||||
|
||||
6
go.mod
6
go.mod
@@ -11,7 +11,7 @@ require (
|
||||
github.com/TomOnTime/utfutil v0.0.0-20180511104225-09c41003ee1d
|
||||
github.com/alicebob/miniredis/v2 v2.30.4
|
||||
github.com/antonmedv/expr v1.15.2
|
||||
github.com/argoproj/gitops-engine v0.7.1-0.20240615185936-83ce6ca8cedc
|
||||
github.com/argoproj/gitops-engine v0.7.1-0.20240714153147-adb68bcaab73
|
||||
github.com/argoproj/notifications-engine v0.4.1-0.20240606074338-0802cd427621
|
||||
github.com/argoproj/pkg v0.13.7-0.20230626144333-d56162821bd1
|
||||
github.com/aws/aws-sdk-go v1.50.8
|
||||
@@ -52,14 +52,14 @@ require (
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0
|
||||
github.com/hashicorp/go-retryablehttp v0.7.4
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7
|
||||
github.com/imdario/mergo v0.3.16
|
||||
github.com/improbable-eng/grpc-web v0.15.0
|
||||
github.com/itchyny/gojq v0.12.13
|
||||
github.com/jeremywohl/flatten v1.0.1
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
||||
github.com/ktrysmt/go-bitbucket v0.9.67
|
||||
github.com/mattn/go-isatty v0.0.19
|
||||
github.com/mattn/go-isatty v0.0.20
|
||||
github.com/mattn/go-zglob v0.0.4
|
||||
github.com/microsoft/azure-devops-go-api/azuredevops v1.0.0-b5
|
||||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1
|
||||
|
||||
20
go.sum
20
go.sum
@@ -695,8 +695,8 @@ github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb
|
||||
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU=
|
||||
github.com/appscode/go v0.0.0-20191119085241-0887d8ec2ecc/go.mod h1:OawnOmAL4ZX3YaPdN+8HTNwBveT1jMsqP74moa9XUbE=
|
||||
github.com/argoproj/gitops-engine v0.7.1-0.20240615185936-83ce6ca8cedc h1:J7LJp2Gh9A9/eQN7Lg74JW+YOVO5NEjq5/cudGAiOwk=
|
||||
github.com/argoproj/gitops-engine v0.7.1-0.20240615185936-83ce6ca8cedc/go.mod h1:ByLmH5B1Gs361tgI5x5f8oSFuBEXDYENYpG3zFDWtHU=
|
||||
github.com/argoproj/gitops-engine v0.7.1-0.20240714153147-adb68bcaab73 h1:7kyTgFsPjvb6noafslp2pr7fBCS9s8OJ759LdLzrOro=
|
||||
github.com/argoproj/gitops-engine v0.7.1-0.20240714153147-adb68bcaab73/go.mod h1:xMIbuLg9Qj2e0egTy+8NcukbhRaVmWwK9vm3aAQZoi4=
|
||||
github.com/argoproj/notifications-engine v0.4.1-0.20240606074338-0802cd427621 h1:Yg1nt+D2uDK1SL2jSlfukA4yc7db184TTN7iWy3voRE=
|
||||
github.com/argoproj/notifications-engine v0.4.1-0.20240606074338-0802cd427621/go.mod h1:N0A4sEws2soZjEpY4hgZpQS8mRIEw6otzwfkgc3g9uQ=
|
||||
github.com/argoproj/pkg v0.13.7-0.20230626144333-d56162821bd1 h1:qsHwwOJ21K2Ao0xPju1sNuqphyMnMYkyB3ZLoLtxWpo=
|
||||
@@ -892,6 +892,8 @@ github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+ne
|
||||
github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8=
|
||||
github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
||||
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
||||
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
|
||||
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
@@ -1242,14 +1244,14 @@ github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
|
||||
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
|
||||
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-retryablehttp v0.5.1/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
@@ -1383,13 +1385,15 @@ github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsI
|
||||
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
|
||||
@@ -27,6 +27,8 @@ rules:
|
||||
- appprojects
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- argoproj.io
|
||||
resources:
|
||||
@@ -62,4 +64,4 @@ rules:
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- watch
|
||||
|
||||
@@ -5,7 +5,7 @@ kind: Kustomization
|
||||
images:
|
||||
- name: quay.io/argoproj/argocd
|
||||
newName: quay.io/argoproj/argocd
|
||||
newTag: latest
|
||||
newTag: v2.12.0-rc4
|
||||
resources:
|
||||
- ./application-controller
|
||||
- ./dex
|
||||
|
||||
@@ -20822,6 +20822,8 @@ rules:
|
||||
- appprojects
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- argoproj.io
|
||||
resources:
|
||||
@@ -21268,7 +21270,7 @@ spec:
|
||||
key: applicationsetcontroller.enable.scm.providers
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -21386,7 +21388,7 @@ spec:
|
||||
- argocd
|
||||
- admin
|
||||
- redis-initial-password
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: secret-init
|
||||
securityContext:
|
||||
@@ -21639,7 +21641,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -21691,7 +21693,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -21963,7 +21965,7 @@ spec:
|
||||
key: controller.ignore.normalizer.jq.timeout
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
|
||||
@@ -12,4 +12,4 @@ resources:
|
||||
images:
|
||||
- name: quay.io/argoproj/argocd
|
||||
newName: quay.io/argoproj/argocd
|
||||
newTag: latest
|
||||
newTag: v2.12.0-rc4
|
||||
|
||||
@@ -12,7 +12,7 @@ patches:
|
||||
images:
|
||||
- name: quay.io/argoproj/argocd
|
||||
newName: quay.io/argoproj/argocd
|
||||
newTag: latest
|
||||
newTag: v2.12.0-rc4
|
||||
resources:
|
||||
- ../../base/application-controller
|
||||
- ../../base/applicationset-controller
|
||||
|
||||
@@ -20860,6 +20860,8 @@ rules:
|
||||
- appprojects
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- argoproj.io
|
||||
resources:
|
||||
@@ -22609,7 +22611,7 @@ spec:
|
||||
key: applicationsetcontroller.enable.scm.providers
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -22732,7 +22734,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -22814,7 +22816,7 @@ spec:
|
||||
key: notificationscontroller.selfservice.enabled
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -22933,7 +22935,7 @@ spec:
|
||||
- argocd
|
||||
- admin
|
||||
- redis-initial-password
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: secret-init
|
||||
securityContext:
|
||||
@@ -23214,7 +23216,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -23266,7 +23268,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -23590,7 +23592,7 @@ spec:
|
||||
key: server.api.content.types
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -23889,7 +23891,7 @@ spec:
|
||||
key: controller.ignore.normalizer.jq.timeout
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
|
||||
@@ -149,6 +149,8 @@ rules:
|
||||
- appprojects
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- argoproj.io
|
||||
resources:
|
||||
@@ -1686,7 +1688,7 @@ spec:
|
||||
key: applicationsetcontroller.enable.scm.providers
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -1809,7 +1811,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -1891,7 +1893,7 @@ spec:
|
||||
key: notificationscontroller.selfservice.enabled
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -2010,7 +2012,7 @@ spec:
|
||||
- argocd
|
||||
- admin
|
||||
- redis-initial-password
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: secret-init
|
||||
securityContext:
|
||||
@@ -2291,7 +2293,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -2343,7 +2345,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -2667,7 +2669,7 @@ spec:
|
||||
key: server.api.content.types
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -2966,7 +2968,7 @@ spec:
|
||||
key: controller.ignore.normalizer.jq.timeout
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
|
||||
@@ -20849,6 +20849,8 @@ rules:
|
||||
- appprojects
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- argoproj.io
|
||||
resources:
|
||||
@@ -21726,7 +21728,7 @@ spec:
|
||||
key: applicationsetcontroller.enable.scm.providers
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -21849,7 +21851,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -21931,7 +21933,7 @@ spec:
|
||||
key: notificationscontroller.selfservice.enabled
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -22031,7 +22033,7 @@ spec:
|
||||
- argocd
|
||||
- admin
|
||||
- redis-initial-password
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: secret-init
|
||||
securityContext:
|
||||
@@ -22284,7 +22286,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -22336,7 +22338,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -22658,7 +22660,7 @@ spec:
|
||||
key: server.api.content.types
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -22957,7 +22959,7 @@ spec:
|
||||
key: controller.ignore.normalizer.jq.timeout
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
|
||||
@@ -138,6 +138,8 @@ rules:
|
||||
- appprojects
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- argoproj.io
|
||||
resources:
|
||||
@@ -803,7 +805,7 @@ spec:
|
||||
key: applicationsetcontroller.enable.scm.providers
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -926,7 +928,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -1008,7 +1010,7 @@ spec:
|
||||
key: notificationscontroller.selfservice.enabled
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -1108,7 +1110,7 @@ spec:
|
||||
- argocd
|
||||
- admin
|
||||
- redis-initial-password
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: secret-init
|
||||
securityContext:
|
||||
@@ -1361,7 +1363,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -1413,7 +1415,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -1735,7 +1737,7 @@ spec:
|
||||
key: server.api.content.types
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -2034,7 +2036,7 @@ spec:
|
||||
key: controller.ignore.normalizer.jq.timeout
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc4
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
|
||||
@@ -2769,7 +2769,10 @@ func (s *Service) UpdateRevisionForPaths(_ context.Context, request *apiclient.U
|
||||
return nil, status.Errorf(codes.Internal, "unable to get changed files for repo %s with revision %s: %v", repo.Repo, revision, err)
|
||||
}
|
||||
|
||||
changed := apppathutil.AppFilesHaveChanged(refreshPaths, files)
|
||||
changed := false
|
||||
if len(files) != 0 {
|
||||
changed = apppathutil.AppFilesHaveChanged(refreshPaths, files)
|
||||
}
|
||||
|
||||
if !changed {
|
||||
logCtx.Debugf("no changes found for application %s in repo %s from revision %s to revision %s", request.AppName, repo.Repo, syncedRevision, revision)
|
||||
|
||||
@@ -1495,71 +1495,9 @@ func (s *Server) RevisionMetadata(ctx context.Context, q *application.RevisionMe
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var versionId int64 = 0
|
||||
if q.VersionId != nil {
|
||||
versionId = int64(*q.VersionId)
|
||||
}
|
||||
|
||||
var source *v1alpha1.ApplicationSource
|
||||
|
||||
// To support changes between single source and multi source revisions
|
||||
// we have to calculate if the operation has to be done as multisource or not.
|
||||
// There are 2 different scenarios, checking current revision and historic revision
|
||||
// - Current revision (VersionId is nil or 0):
|
||||
// - The application is multi source and required version too -> multi source
|
||||
// - The application is single source and the required version too -> single source
|
||||
// - The application is multi source and the required version is single source -> single source
|
||||
// - The application is single source and the required version is multi source -> multi source
|
||||
// - Historic revision:
|
||||
// - The application is multi source and the previous one too -> multi source
|
||||
// - The application is single source and the previous one too -> single source
|
||||
// - The application is multi source and the previous one is single source -> multi source
|
||||
// - The application is single source and the previous one is multi source -> single source
|
||||
isRevisionMultiSource := a.Spec.HasMultipleSources()
|
||||
emptyHistory := len(a.Status.History) == 0
|
||||
if !emptyHistory {
|
||||
for _, h := range a.Status.History {
|
||||
if h.ID == versionId {
|
||||
isRevisionMultiSource = len(h.Revisions) > 0
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the historical data is empty (because the app hasn't been synced yet)
|
||||
// we can use the source, if not (the app has been synced at least once)
|
||||
// we have to use the history because sources can be added/removed
|
||||
if emptyHistory {
|
||||
if isRevisionMultiSource {
|
||||
source = &a.Spec.Sources[*q.SourceIndex]
|
||||
} else {
|
||||
s := a.Spec.GetSource()
|
||||
source = &s
|
||||
}
|
||||
} else {
|
||||
// the source count can change during the time, we cannot just trust in .status.sync
|
||||
// because if a source has been added/removed, the revisions there won't match
|
||||
// as this is only used for the UI and not internally, we can use the historical data
|
||||
// using the specific revisionId
|
||||
for _, h := range a.Status.History {
|
||||
if h.ID == versionId {
|
||||
// The iteration values are assigned to the respective iteration variables as in an assignment statement.
|
||||
// The iteration variables may be declared by the “range” clause using a form of short variable declaration (:=).
|
||||
// In this case their types are set to the types of the respective iteration values and their scope is the block of the "for" statement;
|
||||
// they are re-used in each iteration. If the iteration variables are declared outside the "for" statement,
|
||||
// after execution their values will be those of the last iteration.
|
||||
// https://golang.org/ref/spec#For_statements
|
||||
h := h
|
||||
if isRevisionMultiSource {
|
||||
source = &h.Sources[*q.SourceIndex]
|
||||
} else {
|
||||
source = &h.Source
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if source == nil {
|
||||
return nil, fmt.Errorf("revision not found: %w", err)
|
||||
source, err := getAppSourceBySourceIndexAndVersionId(a, q.SourceIndex, q.VersionId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting app source by source index and version ID: %w", err)
|
||||
}
|
||||
|
||||
repo, err := s.db.GetRepository(ctx, source.RepoURL, proj.Name)
|
||||
@@ -1585,22 +1523,9 @@ func (s *Server) RevisionChartDetails(ctx context.Context, q *application.Revisi
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var source *v1alpha1.ApplicationSource
|
||||
if a.Spec.HasMultipleSources() {
|
||||
// the source count can change during the time, we cannot just trust in .status.sync
|
||||
// because if a source has been added/removed, the revisions there won't match
|
||||
// as this is only used for the UI and not internally, we can use the historical data
|
||||
// using the specific revisionId
|
||||
for _, h := range a.Status.History {
|
||||
if h.ID == int64(*q.VersionId) {
|
||||
source = &h.Sources[*q.SourceIndex]
|
||||
}
|
||||
}
|
||||
if source == nil {
|
||||
return nil, fmt.Errorf("revision not found: %w", err)
|
||||
}
|
||||
} else {
|
||||
source = a.Spec.Source
|
||||
source, err := getAppSourceBySourceIndexAndVersionId(a, q.SourceIndex, q.VersionId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting app source by source index and version ID: %w", err)
|
||||
}
|
||||
|
||||
if source.Chart == "" {
|
||||
@@ -1622,6 +1547,76 @@ func (s *Server) RevisionChartDetails(ctx context.Context, q *application.Revisi
|
||||
})
|
||||
}
|
||||
|
||||
// getAppSourceBySourceIndexAndVersionId returns the source for a specific source index and version ID. Source index and
|
||||
// version ID are optional. If the source index is not specified, it defaults to 0. If the version ID is not specified,
|
||||
// we use the source(s) currently configured for the app. If the version ID is specified, we find the source for that
|
||||
// version ID. If the version ID is not found, we return an error. If the source index is out of bounds for whichever
|
||||
// source we choose (configured sources or sources for a specific version), we return an error.
|
||||
func getAppSourceBySourceIndexAndVersionId(a *appv1.Application, sourceIndexMaybe *int32, versionIdMaybe *int32) (appv1.ApplicationSource, error) {
|
||||
// Start with all the app's configured sources.
|
||||
sources := a.Spec.GetSources()
|
||||
|
||||
// If the user specified a version, get the sources for that version. If the version is not found, return an error.
|
||||
if versionIdMaybe != nil {
|
||||
versionId := int64(*versionIdMaybe)
|
||||
var err error
|
||||
sources, err = getSourcesByVersionId(a, versionId)
|
||||
if err != nil {
|
||||
return appv1.ApplicationSource{}, fmt.Errorf("error getting source by version ID: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Start by assuming we want the first source.
|
||||
sourceIndex := 0
|
||||
|
||||
// If the user specified a source index, use that instead.
|
||||
if sourceIndexMaybe != nil {
|
||||
sourceIndex = int(*sourceIndexMaybe)
|
||||
if sourceIndex >= len(sources) {
|
||||
if len(sources) == 1 {
|
||||
return appv1.ApplicationSource{}, fmt.Errorf("source index %d not found because there is only 1 source", sourceIndex)
|
||||
}
|
||||
return appv1.ApplicationSource{}, fmt.Errorf("source index %d not found because there are only %d sources", sourceIndex, len(sources))
|
||||
}
|
||||
}
|
||||
|
||||
source := sources[sourceIndex]
|
||||
|
||||
return source, nil
|
||||
}
|
||||
|
||||
// getRevisionHistoryByVersionId returns the revision history for a specific version ID.
|
||||
// If the version ID is not found, it returns an empty revision history and false.
|
||||
func getRevisionHistoryByVersionId(histories v1alpha1.RevisionHistories, versionId int64) (appv1.RevisionHistory, bool) {
|
||||
for _, h := range histories {
|
||||
if h.ID == versionId {
|
||||
return h, true
|
||||
}
|
||||
}
|
||||
return appv1.RevisionHistory{}, false
|
||||
}
|
||||
|
||||
// getSourcesByVersionId returns the sources for a specific version ID. If there is no history, it returns an error.
|
||||
// If the version ID is not found, it returns an error. If the version ID is found, and there are multiple sources,
|
||||
// it returns the sources for that version ID. If the version ID is found, and there is only one source, it returns
|
||||
// a slice with just the single source.
|
||||
func getSourcesByVersionId(a *appv1.Application, versionId int64) ([]appv1.ApplicationSource, error) {
|
||||
if len(a.Status.History) == 0 {
|
||||
return nil, fmt.Errorf("version ID %d not found because the app has no history", versionId)
|
||||
}
|
||||
|
||||
h, ok := getRevisionHistoryByVersionId(a.Status.History, versionId)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("revision history not found for version ID %d", versionId)
|
||||
}
|
||||
|
||||
if len(h.Sources) > 0 {
|
||||
return h.Sources, nil
|
||||
}
|
||||
|
||||
return []v1alpha1.ApplicationSource{h.Source}, nil
|
||||
}
|
||||
|
||||
func isMatchingResource(q *application.ResourcesQuery, key kube.ResourceKey) bool {
|
||||
return (q.GetName() == "" || q.GetName() == key.Name) &&
|
||||
(q.GetNamespace() == "" || q.GetNamespace() == key.Namespace) &&
|
||||
|
||||
@@ -10,6 +10,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"k8s.io/utils/pointer"
|
||||
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
|
||||
"github.com/argoproj/gitops-engine/pkg/health"
|
||||
@@ -3025,3 +3027,265 @@ func TestServer_ResolveSourceRevisions_SingleSource(t *testing.T) {
|
||||
assert.Equal(t, ([]string)(nil), sourceRevisions)
|
||||
assert.Equal(t, ([]string)(nil), displayRevisions)
|
||||
}
|
||||
|
||||
func Test_RevisionMetadata(t *testing.T) {
|
||||
singleSourceApp := newTestApp()
|
||||
singleSourceApp.Name = "single-source-app"
|
||||
singleSourceApp.Spec = appv1.ApplicationSpec{
|
||||
Source: &appv1.ApplicationSource{
|
||||
RepoURL: "https://github.com/argoproj/argocd-example-apps.git",
|
||||
Path: "helm-guestbook",
|
||||
TargetRevision: "HEAD",
|
||||
},
|
||||
}
|
||||
|
||||
multiSourceApp := newTestApp()
|
||||
multiSourceApp.Name = "multi-source-app"
|
||||
multiSourceApp.Spec = appv1.ApplicationSpec{
|
||||
Sources: []appv1.ApplicationSource{
|
||||
{
|
||||
RepoURL: "https://github.com/argoproj/argocd-example-apps.git",
|
||||
Path: "helm-guestbook",
|
||||
TargetRevision: "HEAD",
|
||||
},
|
||||
{
|
||||
RepoURL: "https://github.com/argoproj/argocd-example-apps.git",
|
||||
Path: "kustomize-guestbook",
|
||||
TargetRevision: "HEAD",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
singleSourceHistory := []appv1.RevisionHistory{
|
||||
{
|
||||
ID: 1,
|
||||
Source: singleSourceApp.Spec.GetSource(),
|
||||
Revision: "a",
|
||||
},
|
||||
}
|
||||
multiSourceHistory := []appv1.RevisionHistory{
|
||||
{
|
||||
ID: 1,
|
||||
Sources: multiSourceApp.Spec.GetSources(),
|
||||
Revisions: []string{"a", "b"},
|
||||
},
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
multiSource bool
|
||||
history *struct {
|
||||
matchesSourceType bool
|
||||
}
|
||||
sourceIndex *int32
|
||||
versionId *int32
|
||||
expectErrorContains *string
|
||||
}{
|
||||
{
|
||||
name: "single-source app without history, no source index, no version ID",
|
||||
multiSource: false,
|
||||
},
|
||||
{
|
||||
name: "single-source app without history, no source index, missing version ID",
|
||||
multiSource: false,
|
||||
versionId: pointer.Int32(999),
|
||||
expectErrorContains: pointer.String("the app has no history"),
|
||||
},
|
||||
{
|
||||
name: "single source app without history, present source index, no version ID",
|
||||
multiSource: false,
|
||||
sourceIndex: pointer.Int32(0),
|
||||
},
|
||||
{
|
||||
name: "single source app without history, invalid source index, no version ID",
|
||||
multiSource: false,
|
||||
sourceIndex: pointer.Int32(999),
|
||||
expectErrorContains: pointer.String("source index 999 not found"),
|
||||
},
|
||||
{
|
||||
name: "single source app with matching history, no source index, no version ID",
|
||||
multiSource: false,
|
||||
history: &struct{ matchesSourceType bool }{true},
|
||||
},
|
||||
{
|
||||
name: "single source app with matching history, no source index, missing version ID",
|
||||
multiSource: false,
|
||||
history: &struct{ matchesSourceType bool }{true},
|
||||
versionId: pointer.Int32(999),
|
||||
expectErrorContains: pointer.String("history not found for version ID 999"),
|
||||
},
|
||||
{
|
||||
name: "single source app with matching history, no source index, present version ID",
|
||||
multiSource: false,
|
||||
history: &struct{ matchesSourceType bool }{true},
|
||||
versionId: pointer.Int32(1),
|
||||
},
|
||||
{
|
||||
name: "single source app with multi-source history, no source index, no version ID",
|
||||
multiSource: false,
|
||||
history: &struct{ matchesSourceType bool }{false},
|
||||
},
|
||||
{
|
||||
name: "single source app with multi-source history, no source index, missing version ID",
|
||||
multiSource: false,
|
||||
history: &struct{ matchesSourceType bool }{false},
|
||||
versionId: pointer.Int32(999),
|
||||
expectErrorContains: pointer.String("history not found for version ID 999"),
|
||||
},
|
||||
{
|
||||
name: "single source app with multi-source history, no source index, present version ID",
|
||||
multiSource: false,
|
||||
history: &struct{ matchesSourceType bool }{false},
|
||||
versionId: pointer.Int32(1),
|
||||
},
|
||||
{
|
||||
name: "single-source app with multi-source history, source index 1, no version ID",
|
||||
multiSource: false,
|
||||
sourceIndex: pointer.Int32(1),
|
||||
history: &struct{ matchesSourceType bool }{false},
|
||||
// Since the user requested source index 1, but no version ID, we'll get an error when looking at the live
|
||||
// source, because the live source is single-source.
|
||||
expectErrorContains: pointer.String("there is only 1 source"),
|
||||
},
|
||||
{
|
||||
name: "single-source app with multi-source history, invalid source index, no version ID",
|
||||
multiSource: false,
|
||||
sourceIndex: pointer.Int32(999),
|
||||
history: &struct{ matchesSourceType bool }{false},
|
||||
expectErrorContains: pointer.String("source index 999 not found"),
|
||||
},
|
||||
{
|
||||
name: "single-source app with multi-source history, valid source index, present version ID",
|
||||
multiSource: false,
|
||||
sourceIndex: pointer.Int32(1),
|
||||
history: &struct{ matchesSourceType bool }{false},
|
||||
versionId: pointer.Int32(1),
|
||||
},
|
||||
{
|
||||
name: "multi-source app without history, no source index, no version ID",
|
||||
multiSource: true,
|
||||
},
|
||||
{
|
||||
name: "multi-source app without history, no source index, missing version ID",
|
||||
multiSource: true,
|
||||
versionId: pointer.Int32(999),
|
||||
expectErrorContains: pointer.String("the app has no history"),
|
||||
},
|
||||
{
|
||||
name: "multi-source app without history, present source index, no version ID",
|
||||
multiSource: true,
|
||||
sourceIndex: pointer.Int32(1),
|
||||
},
|
||||
{
|
||||
name: "multi-source app without history, invalid source index, no version ID",
|
||||
multiSource: true,
|
||||
sourceIndex: pointer.Int32(999),
|
||||
expectErrorContains: pointer.String("source index 999 not found"),
|
||||
},
|
||||
{
|
||||
name: "multi-source app with matching history, no source index, no version ID",
|
||||
multiSource: true,
|
||||
history: &struct{ matchesSourceType bool }{true},
|
||||
},
|
||||
{
|
||||
name: "multi-source app with matching history, no source index, missing version ID",
|
||||
multiSource: true,
|
||||
history: &struct{ matchesSourceType bool }{true},
|
||||
versionId: pointer.Int32(999),
|
||||
expectErrorContains: pointer.String("history not found for version ID 999"),
|
||||
},
|
||||
{
|
||||
name: "multi-source app with matching history, no source index, present version ID",
|
||||
multiSource: true,
|
||||
history: &struct{ matchesSourceType bool }{true},
|
||||
versionId: pointer.Int32(1),
|
||||
},
|
||||
{
|
||||
name: "multi-source app with single-source history, no source index, no version ID",
|
||||
multiSource: true,
|
||||
history: &struct{ matchesSourceType bool }{false},
|
||||
},
|
||||
{
|
||||
name: "multi-source app with single-source history, no source index, missing version ID",
|
||||
multiSource: true,
|
||||
history: &struct{ matchesSourceType bool }{false},
|
||||
versionId: pointer.Int32(999),
|
||||
expectErrorContains: pointer.String("history not found for version ID 999"),
|
||||
},
|
||||
{
|
||||
name: "multi-source app with single-source history, no source index, present version ID",
|
||||
multiSource: true,
|
||||
history: &struct{ matchesSourceType bool }{false},
|
||||
versionId: pointer.Int32(1),
|
||||
},
|
||||
{
|
||||
name: "multi-source app with single-source history, source index 1, no version ID",
|
||||
multiSource: true,
|
||||
sourceIndex: pointer.Int32(1),
|
||||
history: &struct{ matchesSourceType bool }{false},
|
||||
},
|
||||
{
|
||||
name: "multi-source app with single-source history, invalid source index, no version ID",
|
||||
multiSource: true,
|
||||
sourceIndex: pointer.Int32(999),
|
||||
history: &struct{ matchesSourceType bool }{false},
|
||||
expectErrorContains: pointer.String("source index 999 not found"),
|
||||
},
|
||||
{
|
||||
name: "multi-source app with single-source history, valid source index, present version ID",
|
||||
multiSource: true,
|
||||
sourceIndex: pointer.Int32(0),
|
||||
history: &struct{ matchesSourceType bool }{false},
|
||||
versionId: pointer.Int32(1),
|
||||
},
|
||||
{
|
||||
name: "multi-source app with single-source history, source index 1, present version ID",
|
||||
multiSource: true,
|
||||
sourceIndex: pointer.Int32(1),
|
||||
history: &struct{ matchesSourceType bool }{false},
|
||||
versionId: pointer.Int32(1),
|
||||
expectErrorContains: pointer.String("source index 1 not found"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tcc := tc
|
||||
t.Run(tcc.name, func(t *testing.T) {
|
||||
app := singleSourceApp
|
||||
if tcc.multiSource {
|
||||
app = multiSourceApp
|
||||
}
|
||||
if tcc.history != nil {
|
||||
if tcc.history.matchesSourceType {
|
||||
if tcc.multiSource {
|
||||
app.Status.History = multiSourceHistory
|
||||
} else {
|
||||
app.Status.History = singleSourceHistory
|
||||
}
|
||||
} else {
|
||||
if tcc.multiSource {
|
||||
app.Status.History = singleSourceHistory
|
||||
} else {
|
||||
app.Status.History = multiSourceHistory
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s := newTestAppServer(t, app)
|
||||
|
||||
request := &application.RevisionMetadataQuery{
|
||||
Name: pointer.String(app.Name),
|
||||
Revision: pointer.String("HEAD"),
|
||||
SourceIndex: tcc.sourceIndex,
|
||||
VersionId: tcc.versionId,
|
||||
}
|
||||
|
||||
_, err := s.RevisionMetadata(context.Background(), request)
|
||||
if tcc.expectErrorContains != nil {
|
||||
require.ErrorContains(t, err, *tcc.expectErrorContains)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,101 +522,6 @@ func TestSimpleListGeneratorGoTemplate(t *testing.T) {
|
||||
Delete().Then().Expect(ApplicationsDoNotExist([]argov1alpha1.Application{*expectedAppNewMetadata}))
|
||||
}
|
||||
|
||||
func TestCreateApplicationDespiteParamsError(t *testing.T) {
|
||||
expectedErrorMessage := `failed to execute go template {{.cluster}}-guestbook: template: :1:2: executing "" at <.cluster>: map has no entry for key "cluster"`
|
||||
expectedConditionsParamsError := []v1alpha1.ApplicationSetCondition{
|
||||
{
|
||||
Type: v1alpha1.ApplicationSetConditionErrorOccurred,
|
||||
Status: v1alpha1.ApplicationSetConditionStatusTrue,
|
||||
Message: expectedErrorMessage,
|
||||
Reason: v1alpha1.ApplicationSetReasonRenderTemplateParamsError,
|
||||
},
|
||||
{
|
||||
Type: v1alpha1.ApplicationSetConditionParametersGenerated,
|
||||
Status: v1alpha1.ApplicationSetConditionStatusFalse,
|
||||
Message: expectedErrorMessage,
|
||||
Reason: v1alpha1.ApplicationSetReasonErrorOccurred,
|
||||
},
|
||||
{
|
||||
Type: v1alpha1.ApplicationSetConditionResourcesUpToDate,
|
||||
Status: v1alpha1.ApplicationSetConditionStatusFalse,
|
||||
Message: expectedErrorMessage,
|
||||
Reason: v1alpha1.ApplicationSetReasonRenderTemplateParamsError,
|
||||
},
|
||||
}
|
||||
expectedApp := argov1alpha1.Application{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: application.ApplicationKind,
|
||||
APIVersion: "argoproj.io/v1alpha1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "my-cluster-guestbook",
|
||||
Namespace: fixture.TestNamespace(),
|
||||
Finalizers: []string{"resources-finalizer.argocd.argoproj.io"},
|
||||
},
|
||||
Spec: argov1alpha1.ApplicationSpec{
|
||||
Project: "default",
|
||||
Source: &argov1alpha1.ApplicationSource{
|
||||
RepoURL: "https://github.com/argoproj/argocd-example-apps.git",
|
||||
TargetRevision: "HEAD",
|
||||
Path: "guestbook",
|
||||
},
|
||||
Destination: argov1alpha1.ApplicationDestination{
|
||||
Server: "https://kubernetes.default.svc",
|
||||
Namespace: "guestbook",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
Given(t).
|
||||
// Create a ListGenerator-based ApplicationSet
|
||||
When().Create(v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "simple-list-generator",
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
GoTemplate: true,
|
||||
GoTemplateOptions: []string{"missingkey=error"},
|
||||
Template: v1alpha1.ApplicationSetTemplate{
|
||||
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{.cluster}}-guestbook"},
|
||||
Spec: argov1alpha1.ApplicationSpec{
|
||||
Project: "default",
|
||||
Source: &argov1alpha1.ApplicationSource{
|
||||
RepoURL: "https://github.com/argoproj/argocd-example-apps.git",
|
||||
TargetRevision: "HEAD",
|
||||
Path: "guestbook",
|
||||
},
|
||||
Destination: argov1alpha1.ApplicationDestination{
|
||||
Server: "{{.url}}",
|
||||
Namespace: "guestbook",
|
||||
},
|
||||
},
|
||||
},
|
||||
Generators: []v1alpha1.ApplicationSetGenerator{
|
||||
{
|
||||
List: &v1alpha1.ListGenerator{
|
||||
Elements: []apiextensionsv1.JSON{
|
||||
{
|
||||
Raw: []byte(`{"cluster": "my-cluster","url": "https://kubernetes.default.svc"}`),
|
||||
},
|
||||
{
|
||||
Raw: []byte(`{"invalidCluster": "invalid-cluster","url": "https://kubernetes.default.svc"}`),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}).Then().Expect(ApplicationsExist([]argov1alpha1.Application{expectedApp})).
|
||||
|
||||
// verify the ApplicationSet status conditions were set correctly
|
||||
Expect(ApplicationSetHasConditions("simple-list-generator", expectedConditionsParamsError)).
|
||||
|
||||
// Delete the ApplicationSet, and verify it deletes the Applications
|
||||
When().
|
||||
Delete().Then().Expect(ApplicationsDoNotExist([]argov1alpha1.Application{expectedApp}))
|
||||
}
|
||||
|
||||
func TestRenderHelmValuesObject(t *testing.T) {
|
||||
expectedApp := argov1alpha1.Application{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
|
||||
@@ -153,7 +153,9 @@ export const ApplicationDeploymentHistory = ({
|
||||
</React.Fragment>
|
||||
))
|
||||
)
|
||||
) : null}
|
||||
) : (
|
||||
<p>Click to see source details.</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -192,7 +192,14 @@ export class ApplicationDetails extends React.Component<RouteComponentProps<{app
|
||||
)
|
||||
);
|
||||
|
||||
const getContentForChart = (aRevision: string, aSourceIndex: number, aVersionId: number, indx: number, aSource: models.ApplicationSource, sourceHeader?: JSX.Element) => {
|
||||
const getContentForChart = (
|
||||
aRevision: string,
|
||||
aSourceIndex: number | null,
|
||||
aVersionId: number | null,
|
||||
indx: number,
|
||||
aSource: models.ApplicationSource,
|
||||
sourceHeader?: JSX.Element
|
||||
) => {
|
||||
const showChartNonMetadataInfo = (aRevision: string, aRepoUrl: string) => {
|
||||
return (
|
||||
<>
|
||||
@@ -366,9 +373,9 @@ export class ApplicationDetails extends React.Component<RouteComponentProps<{app
|
||||
return <>{cont}</>;
|
||||
} else if (application.spec.source) {
|
||||
if (source.chart) {
|
||||
cont.push(getContentForChart(revision, 0, 0, 0, source));
|
||||
cont.push(getContentForChart(revision, null, null, 0, source));
|
||||
} else {
|
||||
cont.push(getContentForNonChart(revision, 0, getAppCurrentVersion(application), 0, source));
|
||||
cont.push(getContentForNonChart(revision, null, getAppCurrentVersion(application), 0, source));
|
||||
}
|
||||
return <>{cont}</>;
|
||||
} else {
|
||||
|
||||
@@ -247,7 +247,7 @@ export const ApplicationParameters = (props: {
|
||||
</div>
|
||||
</React.Fragment>
|
||||
)}
|
||||
<DataLoader input={app} load={application => getSourceFromSources(application, index)}>
|
||||
<DataLoader input={app.spec.sources[index]} load={src => getSourceFromAppSources(src, app.metadata.name, app.spec.project, index, 0)}>
|
||||
{(details: models.RepoAppDetails) => getEditablePanelForOneSource(details, index, source)}
|
||||
</DataLoader>
|
||||
</div>
|
||||
@@ -986,17 +986,12 @@ function gatherDetails(
|
||||
}
|
||||
|
||||
// For Sources field. Get one source with index i from the list
|
||||
async function getSourceFromSources(app: models.Application, i: number) {
|
||||
const sources: models.ApplicationSource[] = app.spec.sources;
|
||||
if (sources && i < sources.length) {
|
||||
const aSource = sources[i];
|
||||
const repoDetail = await services.repos.appDetails(aSource, app.metadata.name, app.spec.project, i, 0).catch(() => ({
|
||||
type: 'Directory' as models.AppSourceType,
|
||||
path: aSource.path
|
||||
}));
|
||||
return repoDetail;
|
||||
}
|
||||
return null;
|
||||
async function getSourceFromAppSources(aSource: models.ApplicationSource, name: string, project: string, index: number, version: number) {
|
||||
const repoDetail = await services.repos.appDetails(aSource, name, project, index, version).catch(() => ({
|
||||
type: 'Directory' as models.AppSourceType,
|
||||
path: aSource.path
|
||||
}));
|
||||
return repoDetail;
|
||||
}
|
||||
|
||||
// Delete when source field is removed
|
||||
|
||||
@@ -1131,9 +1131,9 @@ export function getAppDefaultOperationSyncRevision(app?: appModels.Application)
|
||||
|
||||
// getAppCurrentVersion gets the first app revisions from `status.sync.revisions` or, if that list is missing or empty, the `revision`
|
||||
// field.
|
||||
export function getAppCurrentVersion(app?: appModels.Application) {
|
||||
if (!app || !app.status || !app.status.history) {
|
||||
return 0;
|
||||
export function getAppCurrentVersion(app?: appModels.Application): number | null {
|
||||
if (!app || !app.status || !app.status.history || app.status.history.length === 0) {
|
||||
return null;
|
||||
}
|
||||
return app.status.history[app.status.history.length - 1].id;
|
||||
}
|
||||
|
||||
@@ -857,7 +857,7 @@ export class ReposList extends React.Component<
|
||||
const confirmed = await this.appContext.apis.popup.confirm('Disconnect repository', `Are you sure you want to disconnect '${repo}'?`);
|
||||
if (confirmed) {
|
||||
try {
|
||||
await services.repos.delete(repo, project);
|
||||
await services.repos.delete(repo, project || '');
|
||||
this.repoLoader.reload();
|
||||
} catch (e) {
|
||||
this.appContext.apis.notifications.show({
|
||||
|
||||
@@ -53,22 +53,26 @@ export class ApplicationsService {
|
||||
.then(res => res.body as models.ApplicationSyncWindowState);
|
||||
}
|
||||
|
||||
public revisionMetadata(name: string, appNamespace: string, revision: string, sourceIndex: number, versionId: number): Promise<models.RevisionMetadata> {
|
||||
return requests
|
||||
.get(`/applications/${name}/revisions/${revision || 'HEAD'}/metadata`)
|
||||
.query({appNamespace})
|
||||
.query({sourceIndex})
|
||||
.query({versionId})
|
||||
.then(res => res.body as models.RevisionMetadata);
|
||||
public revisionMetadata(name: string, appNamespace: string, revision: string, sourceIndex: number | null, versionId: number | null): Promise<models.RevisionMetadata> {
|
||||
let r = requests.get(`/applications/${name}/revisions/${revision || 'HEAD'}/metadata`).query({appNamespace});
|
||||
if (sourceIndex !== null) {
|
||||
r = r.query({sourceIndex});
|
||||
}
|
||||
if (versionId !== null) {
|
||||
r = r.query({versionId});
|
||||
}
|
||||
return r.then(res => res.body as models.RevisionMetadata);
|
||||
}
|
||||
|
||||
public revisionChartDetails(name: string, appNamespace: string, revision: string, sourceIndex: number, versionId: number): Promise<models.ChartDetails> {
|
||||
return requests
|
||||
.get(`/applications/${name}/revisions/${revision || 'HEAD'}/chartdetails`)
|
||||
.query({appNamespace})
|
||||
.query({sourceIndex})
|
||||
.query({versionId})
|
||||
.then(res => res.body as models.ChartDetails);
|
||||
let r = requests.get(`/applications/${name}/revisions/${revision || 'HEAD'}/chartdetails`).query({appNamespace});
|
||||
if (sourceIndex !== null) {
|
||||
r = r.query({sourceIndex});
|
||||
}
|
||||
if (versionId !== null) {
|
||||
r = r.query({versionId});
|
||||
}
|
||||
return r.then(res => res.body as models.ChartDetails);
|
||||
}
|
||||
|
||||
public resourceTree(name: string, appNamespace: string): Promise<models.ApplicationTree> {
|
||||
|
||||
@@ -112,12 +112,12 @@ func GetAppRefreshPaths(app *v1alpha1.Application) []string {
|
||||
}
|
||||
|
||||
// AppFilesHaveChanged returns true if any of the changed files are under the given refresh paths
|
||||
// If refreshPaths is empty, it will always return true
|
||||
// If refreshPaths or changedFiles are empty, it will always return true
|
||||
func AppFilesHaveChanged(refreshPaths []string, changedFiles []string) bool {
|
||||
// empty slice means there was no changes to any files
|
||||
// so we should not refresh
|
||||
// an empty slice of changed files means that the payload didn't include a list
|
||||
// of changed files and we have to assume that a refresh is required
|
||||
if len(changedFiles) == 0 {
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
if len(refreshPaths) == 0 {
|
||||
|
||||
@@ -134,7 +134,7 @@ func Test_AppFilesHaveChanged(t *testing.T) {
|
||||
changeExpected bool
|
||||
}{
|
||||
{"default no path", &v1alpha1.Application{}, []string{"README.md"}, true},
|
||||
{"no files changed", getApp(".", "source/path"), []string{}, false},
|
||||
{"no files changed", getApp(".", "source/path"), []string{}, true},
|
||||
{"relative path - matching", getApp(".", "source/path"), []string{"source/path/my-deployment.yaml"}, true},
|
||||
{"relative path, multi source - matching #1", getMultiSourceApp(".", "source/path", "other/path"), []string{"source/path/my-deployment.yaml"}, true},
|
||||
{"relative path, multi source - matching #2", getMultiSourceApp(".", "other/path", "source/path"), []string{"source/path/my-deployment.yaml"}, true},
|
||||
|
||||
Reference in New Issue
Block a user