mirror of
https://github.com/argoproj/argo-cd.git
synced 2026-02-23 19:18:47 +01:00
Compare commits
5 Commits
appsetdocs
...
v2.12.0-rc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bbfa79ad9e | ||
|
|
00fc93b8b2 | ||
|
|
16c20a84b8 | ||
|
|
2a9a62eeb7 | ||
|
|
fe60670885 |
@@ -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 |
|
||||
|
||||
@@ -5,7 +5,7 @@ kind: Kustomization
|
||||
images:
|
||||
- name: quay.io/argoproj/argocd
|
||||
newName: quay.io/argoproj/argocd
|
||||
newTag: latest
|
||||
newTag: v2.12.0-rc2
|
||||
resources:
|
||||
- ./application-controller
|
||||
- ./dex
|
||||
|
||||
@@ -21268,7 +21268,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-rc2
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -21386,7 +21386,7 @@ spec:
|
||||
- argocd
|
||||
- admin
|
||||
- redis-initial-password
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc2
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: secret-init
|
||||
securityContext:
|
||||
@@ -21639,7 +21639,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-rc2
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -21691,7 +21691,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-rc2
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -21963,7 +21963,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-rc2
|
||||
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-rc2
|
||||
|
||||
@@ -12,7 +12,7 @@ patches:
|
||||
images:
|
||||
- name: quay.io/argoproj/argocd
|
||||
newName: quay.io/argoproj/argocd
|
||||
newTag: latest
|
||||
newTag: v2.12.0-rc2
|
||||
resources:
|
||||
- ../../base/application-controller
|
||||
- ../../base/applicationset-controller
|
||||
|
||||
@@ -22609,7 +22609,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-rc2
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -22732,7 +22732,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc2
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -22814,7 +22814,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-rc2
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -22933,7 +22933,7 @@ spec:
|
||||
- argocd
|
||||
- admin
|
||||
- redis-initial-password
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc2
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: secret-init
|
||||
securityContext:
|
||||
@@ -23214,7 +23214,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-rc2
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -23266,7 +23266,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-rc2
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -23590,7 +23590,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-rc2
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -23889,7 +23889,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-rc2
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
|
||||
@@ -1686,7 +1686,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-rc2
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -1809,7 +1809,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc2
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -1891,7 +1891,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-rc2
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -2010,7 +2010,7 @@ spec:
|
||||
- argocd
|
||||
- admin
|
||||
- redis-initial-password
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc2
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: secret-init
|
||||
securityContext:
|
||||
@@ -2291,7 +2291,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-rc2
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -2343,7 +2343,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-rc2
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -2667,7 +2667,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-rc2
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -2966,7 +2966,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-rc2
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
|
||||
@@ -21726,7 +21726,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-rc2
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -21849,7 +21849,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc2
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -21931,7 +21931,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-rc2
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -22031,7 +22031,7 @@ spec:
|
||||
- argocd
|
||||
- admin
|
||||
- redis-initial-password
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc2
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: secret-init
|
||||
securityContext:
|
||||
@@ -22284,7 +22284,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-rc2
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -22336,7 +22336,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-rc2
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -22658,7 +22658,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-rc2
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -22957,7 +22957,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-rc2
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
|
||||
@@ -803,7 +803,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-rc2
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -926,7 +926,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc2
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -1008,7 +1008,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-rc2
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -1108,7 +1108,7 @@ spec:
|
||||
- argocd
|
||||
- admin
|
||||
- redis-initial-password
|
||||
image: quay.io/argoproj/argocd:latest
|
||||
image: quay.io/argoproj/argocd:v2.12.0-rc2
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: secret-init
|
||||
securityContext:
|
||||
@@ -1361,7 +1361,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-rc2
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -1413,7 +1413,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-rc2
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -1735,7 +1735,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-rc2
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -2034,7 +2034,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-rc2
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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> {
|
||||
|
||||
Reference in New Issue
Block a user