mirror of
https://github.com/argoproj/argo-cd.git
synced 2026-03-27 19:08:47 +01:00
Compare commits
201 Commits
temp-cherr
...
appsetdocs
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
37efa1880b | ||
|
|
83257a9e73 | ||
|
|
cae840bb13 | ||
|
|
8d12e352f4 | ||
|
|
d54ae98b20 | ||
|
|
12928cbdcc | ||
|
|
9c443b6501 | ||
|
|
a45f715763 | ||
|
|
335b65baf8 | ||
|
|
f27515783a | ||
|
|
2afcb6f107 | ||
|
|
05a9171b42 | ||
|
|
ac50d8e1c1 | ||
|
|
f775e7bf28 | ||
|
|
fa0b5f56ab | ||
|
|
43e5941042 | ||
|
|
2168221092 | ||
|
|
64569e61a1 | ||
|
|
cca7485917 | ||
|
|
74b35322a2 | ||
|
|
0ed7c5618f | ||
|
|
42219fd7b7 | ||
|
|
111cf2ce9f | ||
|
|
d301b40c6b | ||
|
|
e3bd56972d | ||
|
|
922d080ae5 | ||
|
|
bd1018af5e | ||
|
|
76dbaaa3e0 | ||
|
|
376e8d5260 | ||
|
|
627da11384 | ||
|
|
75cb7fc42d | ||
|
|
a8f646e430 | ||
|
|
4202168c44 | ||
|
|
e3b333a860 | ||
|
|
cb135fdd0d | ||
|
|
3c3410cf5d | ||
|
|
5e9fc55783 | ||
|
|
9d66e89d14 | ||
|
|
14a09be652 | ||
|
|
fbd7f29056 | ||
|
|
2cefcc5a36 | ||
|
|
683e4e0d95 | ||
|
|
8d1aeb58a2 | ||
|
|
4c27f73559 | ||
|
|
dc3286730a | ||
|
|
62ec9fef36 | ||
|
|
a8b76f2951 | ||
|
|
8a752a56d6 | ||
|
|
4f179a192d | ||
|
|
270b352cbd | ||
|
|
2d994038be | ||
|
|
753f7b6e72 | ||
|
|
6959e54f06 | ||
|
|
7327093b66 | ||
|
|
74582e9965 | ||
|
|
29c69b3601 | ||
|
|
546383a8e5 | ||
|
|
0444fcdf37 | ||
|
|
527ef92c30 | ||
|
|
2731c3f18d | ||
|
|
9783c5ea24 | ||
|
|
db82e23ebb | ||
|
|
04a1608643 | ||
|
|
6b002a5106 | ||
|
|
5223ce546a | ||
|
|
95a43e0416 | ||
|
|
c6b00007f2 | ||
|
|
eb6732ec9e | ||
|
|
0b0c737af0 | ||
|
|
c0b278738c | ||
|
|
029927b25e | ||
|
|
f2490fccdd | ||
|
|
898a126f10 | ||
|
|
bfb04ddf3e | ||
|
|
416b7d0c32 | ||
|
|
561cbef5cc | ||
|
|
2bcaa19894 | ||
|
|
228b86d3b5 | ||
|
|
f542ae5158 | ||
|
|
c71dd1a9e6 | ||
|
|
f2c5093013 | ||
|
|
21ea59d600 | ||
|
|
e2e6faa3b5 | ||
|
|
42fa72d499 | ||
|
|
6f9389c2ea | ||
|
|
98cd061ac9 | ||
|
|
b9131c1802 | ||
|
|
e6f94f227c | ||
|
|
74244323f8 | ||
|
|
e38c7ae00f | ||
|
|
261137df9d | ||
|
|
c47152d017 | ||
|
|
7c7dda0e93 | ||
|
|
806c5f6b6d | ||
|
|
795bda5dd8 | ||
|
|
499f74dc27 | ||
|
|
c4183aad76 | ||
|
|
3f74b24c0a | ||
|
|
1905d127a5 | ||
|
|
07da3d41da | ||
|
|
cbef55e566 | ||
|
|
c6757573ae | ||
|
|
2b1220c600 | ||
|
|
edbce2a524 | ||
|
|
55f8a434d0 | ||
|
|
8a97c1d138 | ||
|
|
35009a7d1c | ||
|
|
94b34f88ec | ||
|
|
ce819128f9 | ||
|
|
e6e9255216 | ||
|
|
c09e6fa6ad | ||
|
|
3baca9b696 | ||
|
|
961147d387 | ||
|
|
686964daaa | ||
|
|
b88ad57986 | ||
|
|
975e966e26 | ||
|
|
49a4b7f14f | ||
|
|
644af54a7c | ||
|
|
c897e944db | ||
|
|
94d3899038 | ||
|
|
1823d8fcd2 | ||
|
|
402802b089 | ||
|
|
e784c47667 | ||
|
|
e44ae96c07 | ||
|
|
be293fe9ed | ||
|
|
e18b4d7ac8 | ||
|
|
f32f69f7d2 | ||
|
|
846503bb0e | ||
|
|
f63f5f954e | ||
|
|
8044d68492 | ||
|
|
33ad0a7ba7 | ||
|
|
0dddb9e6c8 | ||
|
|
562fa065c6 | ||
|
|
ecee599640 | ||
|
|
38b0fd5cd4 | ||
|
|
87671f55c5 | ||
|
|
1f1c33983b | ||
|
|
ee83eea784 | ||
|
|
9e6b28b8a2 | ||
|
|
84b49c84ca | ||
|
|
6c64d5ff55 | ||
|
|
7b1ed5218a | ||
|
|
079341c65c | ||
|
|
9f81cd4798 | ||
|
|
37aaeb3dd9 | ||
|
|
7870200461 | ||
|
|
167e122eba | ||
|
|
a1431bef4c | ||
|
|
073ccf7c35 | ||
|
|
feb7097fc9 | ||
|
|
976a8498d4 | ||
|
|
36d563a3c2 | ||
|
|
944f9f7b68 | ||
|
|
f78c7ee2ba | ||
|
|
c1b2f78f46 | ||
|
|
38c2b34da0 | ||
|
|
2e1db11ad9 | ||
|
|
ab05f35507 | ||
|
|
b3bf182a65 | ||
|
|
563ccb20c7 | ||
|
|
ca9da799d8 | ||
|
|
50fb7bcd21 | ||
|
|
eb6dd46e19 | ||
|
|
e14d6b7bf9 | ||
|
|
6daaac5924 | ||
|
|
65664ce5f3 | ||
|
|
8a447d9ae0 | ||
|
|
951d9d3f17 | ||
|
|
967126860c | ||
|
|
d19b02dcd0 | ||
|
|
d183d9c614 | ||
|
|
b600c5ec7d | ||
|
|
8e91ce9b2b | ||
|
|
8507a87bfa | ||
|
|
4e2902d972 | ||
|
|
928fd19593 | ||
|
|
5b79c34c72 | ||
|
|
0973409273 | ||
|
|
922dd771e3 | ||
|
|
4a1d0f3af5 | ||
|
|
d1574c204f | ||
|
|
4dcabb933e | ||
|
|
fa747f987c | ||
|
|
71c7700f2e | ||
|
|
7efd2fe2eb | ||
|
|
43822815f7 | ||
|
|
911a9c6776 | ||
|
|
73c3935031 | ||
|
|
4641e802a4 | ||
|
|
4b087089fb | ||
|
|
7d0c10e0d2 | ||
|
|
9843bfbdf8 | ||
|
|
5d147a3ae6 | ||
|
|
68d60cd092 | ||
|
|
99cd3c7650 | ||
|
|
622847bcb5 | ||
|
|
ad09b9c744 | ||
|
|
47bec8b438 | ||
|
|
95b8a4ab0b | ||
|
|
c32afb4ee2 | ||
|
|
c9c40684b7 |
41
.github/workflows/ci-build.yaml
vendored
41
.github/workflows/ci-build.yaml
vendored
@@ -14,7 +14,7 @@ on:
|
||||
env:
|
||||
# Golang version to use across CI steps
|
||||
# renovate: datasource=golang-version packageName=golang
|
||||
GOLANG_VERSION: '1.23.3'
|
||||
GOLANG_VERSION: '1.24.1'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
files_yaml: |
|
||||
backend:
|
||||
- '!ui/**'
|
||||
- '!**.md'
|
||||
- '!**.md'
|
||||
- '!**/*.md'
|
||||
- '!docs/**'
|
||||
frontend:
|
||||
@@ -94,8 +94,8 @@ jobs:
|
||||
|
||||
lint-go:
|
||||
permissions:
|
||||
contents: read # for actions/checkout to fetch code
|
||||
pull-requests: read # for golangci/golangci-lint-action to fetch pull requests
|
||||
contents: read # for actions/checkout to fetch code
|
||||
pull-requests: read # for golangci/golangci-lint-action to fetch pull requests
|
||||
name: Lint Go code
|
||||
if: ${{ needs.changes.outputs.backend == 'true' }}
|
||||
runs-on: ubuntu-22.04
|
||||
@@ -112,7 +112,7 @@ jobs:
|
||||
uses: golangci/golangci-lint-action@971e284b6050e8a5849b72094c50ab08da042db8 # v6.1.1
|
||||
with:
|
||||
# renovate: datasource=go packageName=github.com/golangci/golangci-lint versioning=regex:^v(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)?$
|
||||
version: v1.63.4
|
||||
version: v1.64.7
|
||||
args: --verbose
|
||||
|
||||
test-go:
|
||||
@@ -402,30 +402,31 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# latest: true means that this version mush upload the coverage report to codecov.io
|
||||
# We designate the latest version because we only collect code coverage for that version.
|
||||
k3s:
|
||||
- version: v1.31.0
|
||||
# We designate the latest version because we only collect code coverage for that version.
|
||||
- version: v1.32.1
|
||||
latest: true
|
||||
- version: v1.31.0
|
||||
latest: false
|
||||
- version: v1.30.4
|
||||
latest: false
|
||||
- version: v1.29.8
|
||||
latest: false
|
||||
- version: v1.28.13
|
||||
latest: false
|
||||
needs:
|
||||
- build-go
|
||||
- changes
|
||||
env:
|
||||
GOPATH: /home/runner/go
|
||||
ARGOCD_FAKE_IN_CLUSTER: "true"
|
||||
ARGOCD_SSH_DATA_PATH: "/tmp/argo-e2e/app/config/ssh"
|
||||
ARGOCD_TLS_DATA_PATH: "/tmp/argo-e2e/app/config/tls"
|
||||
ARGOCD_E2E_SSH_KNOWN_HOSTS: "../fixture/certs/ssh_known_hosts"
|
||||
ARGOCD_E2E_K3S: "true"
|
||||
ARGOCD_IN_CI: "true"
|
||||
ARGOCD_E2E_APISERVER_PORT: "8088"
|
||||
ARGOCD_APPLICATION_NAMESPACES: "argocd-e2e-external,argocd-e2e-external-2"
|
||||
ARGOCD_SERVER: "127.0.0.1:8088"
|
||||
ARGOCD_FAKE_IN_CLUSTER: 'true'
|
||||
ARGOCD_SSH_DATA_PATH: '/tmp/argo-e2e/app/config/ssh'
|
||||
ARGOCD_TLS_DATA_PATH: '/tmp/argo-e2e/app/config/tls'
|
||||
ARGOCD_E2E_SSH_KNOWN_HOSTS: '../fixture/certs/ssh_known_hosts'
|
||||
ARGOCD_E2E_K3S: 'true'
|
||||
ARGOCD_IN_CI: 'true'
|
||||
ARGOCD_E2E_APISERVER_PORT: '8088'
|
||||
ARGOCD_APPLICATION_NAMESPACES: 'argocd-e2e-external,argocd-e2e-external-2'
|
||||
ARGOCD_SERVER: '127.0.0.1:8088'
|
||||
GITHUB_TOKEN: ${{ secrets.E2E_TEST_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
|
||||
GITLAB_TOKEN: ${{ secrets.E2E_TEST_GITLAB_TOKEN }}
|
||||
steps:
|
||||
@@ -486,7 +487,7 @@ jobs:
|
||||
run: |
|
||||
docker pull ghcr.io/dexidp/dex:v2.41.1
|
||||
docker pull argoproj/argo-cd-ci-builder:v1.0.0
|
||||
docker pull redis:7.0.15-alpine
|
||||
docker pull redis:7.2.7-alpine
|
||||
- name: Create target directory for binaries in the build-process
|
||||
run: |
|
||||
mkdir -p dist
|
||||
@@ -549,4 +550,4 @@ jobs:
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
15
.github/workflows/image.yaml
vendored
15
.github/workflows/image.yaml
vendored
@@ -7,7 +7,7 @@ on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
types: [ labeled, unlabeled, opened, synchronize, reopened ]
|
||||
types: [labeled, unlabeled, opened, synchronize, reopened]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
@@ -46,14 +46,14 @@ jobs:
|
||||
needs: [set-vars]
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write # for pushing packages to GHCR, which is used by cd.apps.argoproj.io to avoid polluting Quay with tags
|
||||
packages: write # for pushing packages to GHCR, which is used by cd.apps.argoproj.io to avoid polluting Quay with tags
|
||||
id-token: write # for creating OIDC tokens for signing.
|
||||
if: ${{ github.repository == 'argoproj/argo-cd' && github.event_name != 'push' }}
|
||||
uses: ./.github/workflows/image-reuse.yaml
|
||||
with:
|
||||
# Note: cannot use env variables to set go-version (https://docs.github.com/en/actions/using-workflows/reusing-workflows#limitations)
|
||||
# renovate: datasource=golang-version packageName=golang
|
||||
go-version: 1.23.3
|
||||
go-version: 1.24.1
|
||||
platforms: ${{ needs.set-vars.outputs.platforms }}
|
||||
push: false
|
||||
|
||||
@@ -61,7 +61,7 @@ jobs:
|
||||
needs: [set-vars]
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write # for pushing packages to GHCR, which is used by cd.apps.argoproj.io to avoid polluting Quay with tags
|
||||
packages: write # for pushing packages to GHCR, which is used by cd.apps.argoproj.io to avoid polluting Quay with tags
|
||||
id-token: write # for creating OIDC tokens for signing.
|
||||
if: ${{ github.repository == 'argoproj/argo-cd' && github.event_name == 'push' }}
|
||||
uses: ./.github/workflows/image-reuse.yaml
|
||||
@@ -70,7 +70,7 @@ jobs:
|
||||
ghcr_image_name: ghcr.io/argoproj/argo-cd/argocd:${{ needs.set-vars.outputs.image-tag }}
|
||||
# Note: cannot use env variables to set go-version (https://docs.github.com/en/actions/using-workflows/reusing-workflows#limitations)
|
||||
# renovate: datasource=golang-version packageName=golang
|
||||
go-version: 1.23.3
|
||||
go-version: 1.24.1
|
||||
platforms: ${{ needs.set-vars.outputs.platforms }}
|
||||
push: true
|
||||
secrets:
|
||||
@@ -101,8 +101,8 @@ jobs:
|
||||
- build-and-publish
|
||||
- set-vars
|
||||
permissions:
|
||||
contents: write # for git to push upgrade commit if not already deployed
|
||||
packages: write # for pushing packages to GHCR, which is used by cd.apps.argoproj.io to avoid polluting Quay with tags
|
||||
contents: write # for git to push upgrade commit if not already deployed
|
||||
packages: write # for pushing packages to GHCR, which is used by cd.apps.argoproj.io to avoid polluting Quay with tags
|
||||
if: ${{ github.repository == 'argoproj/argo-cd' && github.event_name == 'push' }}
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
@@ -116,4 +116,3 @@ jobs:
|
||||
git config --global user.name 'CI'
|
||||
git diff --exit-code && echo 'Already deployed' || (git commit -am 'Upgrade argocd to ${{ needs.set-vars.outputs.image-tag }}' && git push)
|
||||
working-directory: argoproj-deployments/argocd
|
||||
|
||||
|
||||
4
.github/workflows/pr-title-check.yml
vendored
4
.github/workflows/pr-title-check.yml
vendored
@@ -12,8 +12,8 @@ permissions: {}
|
||||
# workflow being trigger a number of times. This limits it
|
||||
# to one run per PR.
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
group: ${{ github.workflow }}-${{ github.head_ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
validate:
|
||||
|
||||
46
.github/workflows/release.yaml
vendored
46
.github/workflows/release.yaml
vendored
@@ -11,7 +11,7 @@ permissions: {}
|
||||
|
||||
env:
|
||||
# renovate: datasource=golang-version packageName=golang
|
||||
GOLANG_VERSION: '1.23.3' # Note: go-version must also be set in job argocd-image.with.go-version
|
||||
GOLANG_VERSION: '1.24.1' # Note: go-version must also be set in job argocd-image.with.go-version
|
||||
|
||||
jobs:
|
||||
argocd-image:
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
quay_image_name: quay.io/argoproj/argocd:${{ github.ref_name }}
|
||||
# Note: cannot use env variables to set go-version (https://docs.github.com/en/actions/using-workflows/reusing-workflows#limitations)
|
||||
# renovate: datasource=golang-version packageName=golang
|
||||
go-version: 1.23.3
|
||||
go-version: 1.24.1
|
||||
platforms: linux/amd64,linux/arm64,linux/s390x,linux/ppc64le
|
||||
push: true
|
||||
secrets:
|
||||
@@ -33,20 +33,20 @@ jobs:
|
||||
quay_password: ${{ secrets.RELEASE_QUAY_TOKEN }}
|
||||
|
||||
argocd-image-provenance:
|
||||
needs: [argocd-image]
|
||||
permissions:
|
||||
actions: read # for detecting the Github Actions environment.
|
||||
id-token: write # for creating OIDC tokens for signing.
|
||||
packages: write # for uploading attestations. (https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#known-issues)
|
||||
# Must be refernced by a tag. https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#referencing-the-slsa-generator
|
||||
if: github.repository == 'argoproj/argo-cd'
|
||||
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.0.0
|
||||
with:
|
||||
image: quay.io/argoproj/argocd
|
||||
digest: ${{ needs.argocd-image.outputs.image-digest }}
|
||||
secrets:
|
||||
registry-username: ${{ secrets.RELEASE_QUAY_USERNAME }}
|
||||
registry-password: ${{ secrets.RELEASE_QUAY_TOKEN }}
|
||||
needs: [argocd-image]
|
||||
permissions:
|
||||
actions: read # for detecting the Github Actions environment.
|
||||
id-token: write # for creating OIDC tokens for signing.
|
||||
packages: write # for uploading attestations. (https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#known-issues)
|
||||
# Must be refernced by a tag. https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#referencing-the-slsa-generator
|
||||
if: github.repository == 'argoproj/argo-cd'
|
||||
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.0.0
|
||||
with:
|
||||
image: quay.io/argoproj/argocd
|
||||
digest: ${{ needs.argocd-image.outputs.image-digest }}
|
||||
secrets:
|
||||
registry-username: ${{ secrets.RELEASE_QUAY_USERNAME }}
|
||||
registry-password: ${{ secrets.RELEASE_QUAY_TOKEN }}
|
||||
|
||||
goreleaser:
|
||||
needs:
|
||||
@@ -107,7 +107,7 @@ jobs:
|
||||
- name: Generate subject for provenance
|
||||
id: hash
|
||||
env:
|
||||
ARTIFACTS: "${{ steps.run-goreleaser.outputs.artifacts }}"
|
||||
ARTIFACTS: '${{ steps.run-goreleaser.outputs.artifacts }}'
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
@@ -128,8 +128,8 @@ jobs:
|
||||
# Must be refernced by a tag. https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#referencing-the-slsa-generator
|
||||
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0
|
||||
with:
|
||||
base64-subjects: "${{ needs.goreleaser.outputs.hashes }}"
|
||||
provenance-name: "argocd-cli.intoto.jsonl"
|
||||
base64-subjects: '${{ needs.goreleaser.outputs.hashes }}'
|
||||
provenance-name: 'argocd-cli.intoto.jsonl'
|
||||
upload-assets: true
|
||||
|
||||
generate-sbom:
|
||||
@@ -164,7 +164,7 @@ jobs:
|
||||
SIGS_BOM_VERSION: v0.2.1
|
||||
# comma delimited list of project relative folders to inspect for package
|
||||
# managers (gomod, yarn, npm).
|
||||
PROJECT_FOLDERS: ".,./ui"
|
||||
PROJECT_FOLDERS: '.,./ui'
|
||||
# full qualified name of the docker image to be inspected
|
||||
DOCKER_IMAGE: quay.io/argoproj/argocd:${{ github.ref_name }}
|
||||
run: |
|
||||
@@ -212,8 +212,8 @@ jobs:
|
||||
# Must be referenced by a tag. https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#referencing-the-slsa-generator
|
||||
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0
|
||||
with:
|
||||
base64-subjects: "${{ needs.generate-sbom.outputs.hashes }}"
|
||||
provenance-name: "argocd-sbom.intoto.jsonl"
|
||||
base64-subjects: '${{ needs.generate-sbom.outputs.hashes }}'
|
||||
provenance-name: 'argocd-sbom.intoto.jsonl'
|
||||
upload-assets: true
|
||||
|
||||
post-release:
|
||||
@@ -296,7 +296,7 @@ jobs:
|
||||
uses: peter-evans/create-pull-request@5e914681df9dc83aa4e4905692ca88beb2f9e91f # v7.0.5
|
||||
with:
|
||||
commit-message: Bump version in master
|
||||
title: "chore: Bump version in master"
|
||||
title: 'chore: Bump version in master'
|
||||
body: All images built from master should indicate which version we are on track for.
|
||||
signoff: true
|
||||
branch: update-version
|
||||
|
||||
2
.gitpod.Dockerfile
vendored
2
.gitpod.Dockerfile
vendored
@@ -1,4 +1,4 @@
|
||||
FROM gitpod/workspace-full@sha256:bec45ebdcc9b9c5ec28d5c61c16bf599200aa0d2dc1e69e2ed8ab0a424bae6db
|
||||
FROM gitpod/workspace-full@sha256:a47a68ee7f9da10cd889ccce4661bc73f2c0d5a98d3d087e8bdfc0230b27964c
|
||||
|
||||
USER root
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ linters:
|
||||
- unparam
|
||||
- unused
|
||||
- usestdlibvars
|
||||
- usetesting
|
||||
- whitespace
|
||||
linters-settings:
|
||||
gocritic:
|
||||
@@ -66,6 +67,8 @@ linters-settings:
|
||||
pkg: k8s.io/api/rbac/v1
|
||||
- alias: apierrors
|
||||
pkg: k8s.io/apimachinery/pkg/api/errors
|
||||
- alias: apiextensionsv1
|
||||
pkg: k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1
|
||||
- alias: metav1
|
||||
pkg: k8s.io/apimachinery/pkg/apis/meta/v1
|
||||
- alias: informersv1
|
||||
@@ -138,10 +141,16 @@ linters-settings:
|
||||
- name: useless-break
|
||||
- name: var-declaration
|
||||
- name: var-naming
|
||||
disabled: true
|
||||
arguments:
|
||||
- ["ID"]
|
||||
- ["VM"]
|
||||
- - skipPackageNameChecks: true
|
||||
upperCaseConst: true
|
||||
testifylint:
|
||||
enable-all: true
|
||||
disable:
|
||||
- go-require
|
||||
usetesting:
|
||||
os-mkdir-temp: false
|
||||
run:
|
||||
timeout: 50m
|
||||
|
||||
@@ -76,4 +76,7 @@ packages:
|
||||
SessionServiceClient:
|
||||
github.com/argoproj/argo-cd/v3/pkg/apiclient/cluster:
|
||||
interfaces:
|
||||
ClusterServiceServer:
|
||||
ClusterServiceServer:
|
||||
github.com/argoproj/argo-cd/v3/pkg/client/clientset/versioned/typed/application/v1alpha1:
|
||||
interfaces:
|
||||
AppProjectInterface:
|
||||
|
||||
@@ -4,7 +4,7 @@ ARG BASE_IMAGE=docker.io/library/ubuntu:24.04@sha256:80dd3c3b9c6cecb9f1667e9290b
|
||||
# Initial stage which pulls prepares build dependencies and CLI tooling we need for our final image
|
||||
# Also used as the image in CI jobs so needs all dependencies
|
||||
####################################################################################################
|
||||
FROM docker.io/library/golang:1.23.3@sha256:d56c3e08fe5b27729ee3834854ae8f7015af48fd651cd25d1e3bcf3c19830174 AS builder
|
||||
FROM docker.io/library/golang:1.24.1@sha256:c5adecdb7b3f8c5ca3c88648a861882849cc8b02fed68ece31e25de88ad13418 AS builder
|
||||
|
||||
RUN echo 'deb http://archive.debian.org/debian buster-backports main' >> /etc/apt/sources.list
|
||||
|
||||
@@ -101,7 +101,7 @@ RUN HOST_ARCH=$TARGETARCH NODE_ENV='production' NODE_ONLINE_ENV='online' NODE_OP
|
||||
####################################################################################################
|
||||
# Argo CD Build stage which performs the actual build of Argo CD binaries
|
||||
####################################################################################################
|
||||
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.23.3@sha256:d56c3e08fe5b27729ee3834854ae8f7015af48fd651cd25d1e3bcf3c19830174 AS argocd-build
|
||||
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.24.1@sha256:c5adecdb7b3f8c5ca3c88648a861882849cc8b02fed68ece31e25de88ad13418 AS argocd-build
|
||||
|
||||
WORKDIR /go/src/github.com/argoproj/argo-cd
|
||||
|
||||
|
||||
6
USERS.md
6
USERS.md
@@ -30,7 +30,7 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [Ant Group](https://www.antgroup.com/)
|
||||
1. [AppDirect](https://www.appdirect.com)
|
||||
1. [Arctiq Inc.](https://www.arctiq.ca)
|
||||
2. [Arturia](https://www.arturia.com)
|
||||
1. [Arturia](https://www.arturia.com)
|
||||
1. [ARZ Allgemeines Rechenzentrum GmbH](https://www.arz.at/)
|
||||
1. [Augury](https://www.augury.com/)
|
||||
1. [Autodesk](https://www.autodesk.com)
|
||||
@@ -147,6 +147,7 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [Hazelcast](https://hazelcast.com/)
|
||||
1. [Healy](https://www.healyworld.net)
|
||||
1. [Helio](https://helio.exchange)
|
||||
1. [hetao101](https://www.hetao101.com/)
|
||||
1. [Hetki](https://hetki.ai)
|
||||
1. [hipages](https://hipages.com.au/)
|
||||
1. [Hiya](https://hiya.com)
|
||||
@@ -376,6 +377,7 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [Vinted](https://vinted.com/)
|
||||
1. [Virtuo](https://www.govirtuo.com/)
|
||||
1. [VISITS Technologies](https://visits.world/en)
|
||||
1. [Viya](https://viya.me)
|
||||
1. [Volvo Cars](https://www.volvocars.com/)
|
||||
1. [Voyager Digital](https://www.investvoyager.com/)
|
||||
1. [VSHN - The DevOps Company](https://vshn.ch/)
|
||||
@@ -390,6 +392,7 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [WooliesX](https://wooliesx.com.au/)
|
||||
1. [Woolworths Group](https://www.woolworthsgroup.com.au/)
|
||||
1. [WSpot](https://www.wspot.com.br/)
|
||||
1. [X3M ads](https://x3mads.com)
|
||||
1. [Yieldlab](https://www.yieldlab.de/)
|
||||
1. [Youverify](https://youverify.co/)
|
||||
1. [Yubo](https://www.yubo.live/)
|
||||
@@ -397,3 +400,4 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [Zimpler](https://www.zimpler.com/)
|
||||
1. [ZipRecuiter](https://www.ziprecruiter.com/)
|
||||
1. [ZOZO](https://corp.zozo.com/)
|
||||
|
||||
|
||||
@@ -155,6 +155,7 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
|
||||
// desiredApplications is the main list of all expected Applications from all generators in this appset.
|
||||
desiredApplications, applicationSetReason, err := template.GenerateApplications(logCtx, applicationSetInfo, r.Generators, r.Renderer, r.Client)
|
||||
if err != nil {
|
||||
logCtx.Errorf("unable to generate applications: %v", err)
|
||||
_ = r.setApplicationSetStatusCondition(ctx,
|
||||
&applicationSetInfo,
|
||||
argov1alpha1.ApplicationSetCondition{
|
||||
@@ -164,7 +165,8 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
|
||||
Status: argov1alpha1.ApplicationSetConditionStatusTrue,
|
||||
}, parametersGenerated,
|
||||
)
|
||||
return ctrl.Result{RequeueAfter: ReconcileRequeueOnValidationError}, err
|
||||
// In order for the controller SDK to respect RequeueAfter, the error must be nil
|
||||
return ctrl.Result{RequeueAfter: ReconcileRequeueOnValidationError}, nil
|
||||
}
|
||||
|
||||
parametersGenerated = true
|
||||
@@ -768,7 +770,7 @@ func (r *ApplicationSetReconciler) deleteInCluster(ctx context.Context, logCtx *
|
||||
}
|
||||
|
||||
// removeFinalizerOnInvalidDestination removes the Argo CD resources finalizer if the application contains an invalid target (eg missing cluster)
|
||||
func (r *ApplicationSetReconciler) removeFinalizerOnInvalidDestination(ctx context.Context, applicationSet argov1alpha1.ApplicationSet, app *argov1alpha1.Application, clusterList *argov1alpha1.ClusterList, appLog *log.Entry) error {
|
||||
func (r *ApplicationSetReconciler) removeFinalizerOnInvalidDestination(ctx context.Context, applicationSet argov1alpha1.ApplicationSet, app *argov1alpha1.Application, clusterList []utils.ClusterSpecifier, appLog *log.Entry) error {
|
||||
// Only check if the finalizers need to be removed IF there are finalizers to remove
|
||||
if len(app.Finalizers) == 0 {
|
||||
return nil
|
||||
@@ -783,7 +785,7 @@ func (r *ApplicationSetReconciler) removeFinalizerOnInvalidDestination(ctx conte
|
||||
} else {
|
||||
// Detect if the destination's server field does not match an existing cluster
|
||||
matchingCluster := false
|
||||
for _, cluster := range clusterList.Items {
|
||||
for _, cluster := range clusterList {
|
||||
if destCluster.Server != cluster.Server {
|
||||
continue
|
||||
}
|
||||
@@ -1052,19 +1054,20 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatus(ctx con
|
||||
Message: "No Application status found, defaulting status to Waiting.",
|
||||
Status: "Waiting",
|
||||
Step: strconv.Itoa(getAppStep(app.Name, appStepMap)),
|
||||
TargetRevisions: app.Status.GetRevisions(),
|
||||
}
|
||||
} else {
|
||||
// we have an existing AppStatus
|
||||
currentAppStatus = applicationSet.Status.ApplicationStatus[idx]
|
||||
|
||||
// upgrade any existing AppStatus that might have been set by an older argo-cd version
|
||||
// note: currentAppStatus.TargetRevisions may be set to empty list earlier during migrations,
|
||||
// to prevent other usage of r.Client.Status().Update to fail before reaching here.
|
||||
if len(currentAppStatus.TargetRevisions) == 0 {
|
||||
currentAppStatus.TargetRevisions = app.Status.GetRevisions()
|
||||
if !reflect.DeepEqual(currentAppStatus.TargetRevisions, app.Status.GetRevisions()) {
|
||||
currentAppStatus.Message = "Application has pending changes, setting status to Waiting."
|
||||
}
|
||||
}
|
||||
if !reflect.DeepEqual(currentAppStatus.TargetRevisions, app.Status.GetRevisions()) {
|
||||
currentAppStatus.TargetRevisions = app.Status.GetRevisions()
|
||||
currentAppStatus.Status = "Waiting"
|
||||
currentAppStatus.LastTransitionTime = &now
|
||||
currentAppStatus.Step = strconv.Itoa(getAppStep(currentAppStatus.Application, appStepMap))
|
||||
}
|
||||
|
||||
appOutdated := false
|
||||
if progressiveSyncsRollingSyncStrategyEnabled(applicationSet) {
|
||||
@@ -1077,25 +1080,15 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatus(ctx con
|
||||
currentAppStatus.Status = "Waiting"
|
||||
currentAppStatus.Message = "Application has pending changes, setting status to Waiting."
|
||||
currentAppStatus.Step = strconv.Itoa(getAppStep(currentAppStatus.Application, appStepMap))
|
||||
currentAppStatus.TargetRevisions = app.Status.GetRevisions()
|
||||
}
|
||||
|
||||
if currentAppStatus.Status == "Pending" {
|
||||
if operationPhaseString == "Succeeded" {
|
||||
revisions := []string{}
|
||||
if len(app.Status.OperationState.SyncResult.Revisions) > 0 {
|
||||
revisions = app.Status.OperationState.SyncResult.Revisions
|
||||
} else if app.Status.OperationState.SyncResult.Revision != "" {
|
||||
revisions = append(revisions, app.Status.OperationState.SyncResult.Revision)
|
||||
}
|
||||
|
||||
if reflect.DeepEqual(currentAppStatus.TargetRevisions, revisions) {
|
||||
logCtx.Infof("Application %v has completed a sync successfully, updating its ApplicationSet status to Progressing", app.Name)
|
||||
currentAppStatus.LastTransitionTime = &now
|
||||
currentAppStatus.Status = "Progressing"
|
||||
currentAppStatus.Message = "Application resource completed a sync successfully, updating status from Pending to Progressing."
|
||||
currentAppStatus.Step = strconv.Itoa(getAppStep(currentAppStatus.Application, appStepMap))
|
||||
}
|
||||
if !appOutdated && operationPhaseString == "Succeeded" {
|
||||
logCtx.Infof("Application %v has completed a sync successfully, updating its ApplicationSet status to Progressing", app.Name)
|
||||
currentAppStatus.LastTransitionTime = &now
|
||||
currentAppStatus.Status = "Progressing"
|
||||
currentAppStatus.Message = "Application resource completed a sync successfully, updating status from Pending to Progressing."
|
||||
currentAppStatus.Step = strconv.Itoa(getAppStep(currentAppStatus.Application, appStepMap))
|
||||
} else if operationPhaseString == "Running" || healthStatusString == "Progressing" {
|
||||
logCtx.Infof("Application %v has entered Progressing status, updating its ApplicationSet status to Progressing", app.Name)
|
||||
currentAppStatus.LastTransitionTime = &now
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -1097,12 +1096,12 @@ func TestCreateOrUpdateInCluster(t *testing.T) {
|
||||
Metrics: metrics,
|
||||
}
|
||||
|
||||
err = r.createOrUpdateInCluster(context.TODO(), log.NewEntry(log.StandardLogger()), c.appSet, c.desiredApps)
|
||||
err = r.createOrUpdateInCluster(t.Context(), log.NewEntry(log.StandardLogger()), c.appSet, c.desiredApps)
|
||||
require.NoError(t, err)
|
||||
|
||||
for _, obj := range c.expected {
|
||||
got := &v1alpha1.Application{}
|
||||
_ = client.Get(context.Background(), crtclient.ObjectKey{
|
||||
_ = client.Get(t.Context(), crtclient.ObjectKey{
|
||||
Namespace: obj.Namespace,
|
||||
Name: obj.Name,
|
||||
}, got)
|
||||
@@ -1198,7 +1197,7 @@ func TestRemoveFinalizerOnInvalidDestination_FinalizerTypes(t *testing.T) {
|
||||
kubeclientset := kubefake.NewSimpleClientset(objects...)
|
||||
metrics := appsetmetrics.NewFakeAppsetMetrics()
|
||||
|
||||
argodb := db.NewDB("argocd", settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd"), kubeclientset)
|
||||
argodb := db.NewDB("argocd", settings.NewSettingsManager(t.Context(), kubeclientset, "argocd"), kubeclientset)
|
||||
|
||||
r := ApplicationSetReconciler{
|
||||
Client: client,
|
||||
@@ -1208,18 +1207,18 @@ func TestRemoveFinalizerOnInvalidDestination_FinalizerTypes(t *testing.T) {
|
||||
Metrics: metrics,
|
||||
ArgoDB: argodb,
|
||||
}
|
||||
clusterList, err := utils.ListClusters(context.Background(), kubeclientset, "namespace")
|
||||
clusterList, err := utils.ListClusters(t.Context(), kubeclientset, "namespace")
|
||||
require.NoError(t, err)
|
||||
|
||||
appLog := log.WithFields(log.Fields{"app": app.Name, "appSet": ""})
|
||||
|
||||
appInputParam := app.DeepCopy()
|
||||
|
||||
err = r.removeFinalizerOnInvalidDestination(context.Background(), appSet, appInputParam, clusterList, appLog)
|
||||
err = r.removeFinalizerOnInvalidDestination(t.Context(), appSet, appInputParam, clusterList, appLog)
|
||||
require.NoError(t, err)
|
||||
|
||||
retrievedApp := v1alpha1.Application{}
|
||||
err = client.Get(context.Background(), crtclient.ObjectKeyFromObject(&app), &retrievedApp)
|
||||
err = client.Get(t.Context(), crtclient.ObjectKeyFromObject(&app), &retrievedApp)
|
||||
require.NoError(t, err)
|
||||
|
||||
// App on the cluster should have the expected finalizers
|
||||
@@ -1353,7 +1352,7 @@ func TestRemoveFinalizerOnInvalidDestination_DestinationTypes(t *testing.T) {
|
||||
kubeclientset := getDefaultTestClientSet(secret)
|
||||
metrics := appsetmetrics.NewFakeAppsetMetrics()
|
||||
|
||||
argodb := db.NewDB("argocd", settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd"), kubeclientset)
|
||||
argodb := db.NewDB("argocd", settings.NewSettingsManager(t.Context(), kubeclientset, "argocd"), kubeclientset)
|
||||
|
||||
r := ApplicationSetReconciler{
|
||||
Client: client,
|
||||
@@ -1364,18 +1363,18 @@ func TestRemoveFinalizerOnInvalidDestination_DestinationTypes(t *testing.T) {
|
||||
ArgoDB: argodb,
|
||||
}
|
||||
|
||||
clusterList, err := utils.ListClusters(context.Background(), kubeclientset, "argocd")
|
||||
clusterList, err := utils.ListClusters(t.Context(), kubeclientset, "argocd")
|
||||
require.NoError(t, err)
|
||||
|
||||
appLog := log.WithFields(log.Fields{"app": app.Name, "appSet": ""})
|
||||
|
||||
appInputParam := app.DeepCopy()
|
||||
|
||||
err = r.removeFinalizerOnInvalidDestination(context.Background(), appSet, appInputParam, clusterList, appLog)
|
||||
err = r.removeFinalizerOnInvalidDestination(t.Context(), appSet, appInputParam, clusterList, appLog)
|
||||
require.NoError(t, err)
|
||||
|
||||
retrievedApp := v1alpha1.Application{}
|
||||
err = client.Get(context.Background(), crtclient.ObjectKeyFromObject(&app), &retrievedApp)
|
||||
err = client.Get(t.Context(), crtclient.ObjectKeyFromObject(&app), &retrievedApp)
|
||||
require.NoError(t, err)
|
||||
|
||||
finalizerRemoved := len(retrievedApp.Finalizers) == 0
|
||||
@@ -1448,11 +1447,11 @@ func TestRemoveOwnerReferencesOnDeleteAppSet(t *testing.T) {
|
||||
Metrics: metrics,
|
||||
}
|
||||
|
||||
err = r.removeOwnerReferencesOnDeleteAppSet(context.Background(), appSet)
|
||||
err = r.removeOwnerReferencesOnDeleteAppSet(t.Context(), appSet)
|
||||
require.NoError(t, err)
|
||||
|
||||
retrievedApp := v1alpha1.Application{}
|
||||
err = client.Get(context.Background(), crtclient.ObjectKeyFromObject(&app), &retrievedApp)
|
||||
err = client.Get(t.Context(), crtclient.ObjectKeyFromObject(&app), &retrievedApp)
|
||||
require.NoError(t, err)
|
||||
|
||||
ownerReferencesRemoved := len(retrievedApp.OwnerReferences) == 0
|
||||
@@ -1646,12 +1645,12 @@ func TestCreateApplications(t *testing.T) {
|
||||
Metrics: metrics,
|
||||
}
|
||||
|
||||
err = r.createInCluster(context.TODO(), log.NewEntry(log.StandardLogger()), c.appSet, c.apps)
|
||||
err = r.createInCluster(t.Context(), log.NewEntry(log.StandardLogger()), c.appSet, c.apps)
|
||||
require.NoError(t, err)
|
||||
|
||||
for _, obj := range c.expected {
|
||||
got := &v1alpha1.Application{}
|
||||
_ = client.Get(context.Background(), crtclient.ObjectKey{
|
||||
_ = client.Get(t.Context(), crtclient.ObjectKey{
|
||||
Namespace: obj.Namespace,
|
||||
Name: obj.Name,
|
||||
}, got)
|
||||
@@ -1789,13 +1788,13 @@ func TestDeleteInCluster(t *testing.T) {
|
||||
Metrics: metrics,
|
||||
}
|
||||
|
||||
err = r.deleteInCluster(context.TODO(), log.NewEntry(log.StandardLogger()), c.appSet, c.desiredApps)
|
||||
err = r.deleteInCluster(t.Context(), log.NewEntry(log.StandardLogger()), c.appSet, c.desiredApps)
|
||||
require.NoError(t, err)
|
||||
|
||||
// For each of the expected objects, verify they exist on the cluster
|
||||
for _, obj := range c.expected {
|
||||
got := &v1alpha1.Application{}
|
||||
_ = client.Get(context.Background(), crtclient.ObjectKey{
|
||||
_ = client.Get(t.Context(), crtclient.ObjectKey{
|
||||
Namespace: obj.Namespace,
|
||||
Name: obj.Name,
|
||||
}, got)
|
||||
@@ -1809,7 +1808,7 @@ func TestDeleteInCluster(t *testing.T) {
|
||||
// Verify each of the unexpected objs cannot be found
|
||||
for _, obj := range c.notExpected {
|
||||
got := &v1alpha1.Application{}
|
||||
err := client.Get(context.Background(), crtclient.ObjectKey{
|
||||
err := client.Get(t.Context(), crtclient.ObjectKey{
|
||||
Namespace: obj.Namespace,
|
||||
Name: obj.Name,
|
||||
}, got)
|
||||
@@ -1915,8 +1914,8 @@ func TestRequeueGeneratorFails(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
res, err := r.Reconcile(context.Background(), req)
|
||||
require.Error(t, err)
|
||||
res, err := r.Reconcile(t.Context(), req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, ReconcileRequeueOnValidationError, res.RequeueAfter)
|
||||
}
|
||||
|
||||
@@ -2088,7 +2087,7 @@ func TestValidateGeneratedApplications(t *testing.T) {
|
||||
|
||||
kubeclientset := getDefaultTestClientSet(secret)
|
||||
|
||||
argodb := db.NewDB("argocd", settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd"), kubeclientset)
|
||||
argodb := db.NewDB("argocd", settings.NewSettingsManager(t.Context(), kubeclientset, "argocd"), kubeclientset)
|
||||
|
||||
r := ApplicationSetReconciler{
|
||||
Client: client,
|
||||
@@ -2102,7 +2101,7 @@ func TestValidateGeneratedApplications(t *testing.T) {
|
||||
}
|
||||
|
||||
appSetInfo := v1alpha1.ApplicationSet{}
|
||||
validationErrors, _ := r.validateGeneratedApplications(context.TODO(), cc.apps, appSetInfo)
|
||||
validationErrors, _ := r.validateGeneratedApplications(t.Context(), cc.apps, appSetInfo)
|
||||
assert.Equal(t, cc.validationErrors, validationErrors)
|
||||
})
|
||||
}
|
||||
@@ -2153,7 +2152,7 @@ func TestReconcilerValidationProjectErrorBehaviour(t *testing.T) {
|
||||
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appSet, &project).WithStatusSubresource(&appSet).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).Build()
|
||||
metrics := appsetmetrics.NewFakeAppsetMetrics()
|
||||
|
||||
argodb := db.NewDB("argocd", settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd"), kubeclientset)
|
||||
argodb := db.NewDB("argocd", settings.NewSettingsManager(t.Context(), kubeclientset, "argocd"), kubeclientset)
|
||||
|
||||
r := ApplicationSetReconciler{
|
||||
Client: client,
|
||||
@@ -2178,19 +2177,19 @@ func TestReconcilerValidationProjectErrorBehaviour(t *testing.T) {
|
||||
}
|
||||
|
||||
// Verify that on validation error, no error is returned, but the object is requeued
|
||||
res, err := r.Reconcile(context.Background(), req)
|
||||
res, err := r.Reconcile(t.Context(), 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: "good-project"}, &app)
|
||||
err = r.Client.Get(t.Context(), crtclient.ObjectKey{Namespace: "argocd", Name: "good-project"}, &app)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "good-project", app.Name)
|
||||
|
||||
// make sure bad app was not created
|
||||
err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "bad-project"}, &app)
|
||||
err = r.Client.Get(t.Context(), crtclient.ObjectKey{Namespace: "argocd", Name: "bad-project"}, &app)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
@@ -2352,7 +2351,7 @@ func TestSetApplicationSetStatusCondition(t *testing.T) {
|
||||
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&testCase.appset).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).WithStatusSubresource(&testCase.appset).Build()
|
||||
metrics := appsetmetrics.NewFakeAppsetMetrics()
|
||||
|
||||
argodb := db.NewDB("argocd", settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd"), kubeclientset)
|
||||
argodb := db.NewDB("argocd", settings.NewSettingsManager(t.Context(), kubeclientset, "argocd"), kubeclientset)
|
||||
|
||||
r := ApplicationSetReconciler{
|
||||
Client: client,
|
||||
@@ -2368,7 +2367,7 @@ func TestSetApplicationSetStatusCondition(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, condition := range testCase.conditions {
|
||||
err = r.setApplicationSetStatusCondition(context.TODO(), &testCase.appset, condition, true)
|
||||
err = r.setApplicationSetStatusCondition(t.Context(), &testCase.appset, condition, true)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
@@ -2440,7 +2439,7 @@ func applicationsUpdateSyncPolicyTest(t *testing.T, applicationsSyncPolicy v1alp
|
||||
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appSet, &defaultProject).WithStatusSubresource(&appSet).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).Build()
|
||||
metrics := appsetmetrics.NewFakeAppsetMetrics()
|
||||
|
||||
argodb := db.NewDB("argocd", settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd"), kubeclientset)
|
||||
argodb := db.NewDB("argocd", settings.NewSettingsManager(t.Context(), kubeclientset, "argocd"), kubeclientset)
|
||||
|
||||
r := ApplicationSetReconciler{
|
||||
Client: client,
|
||||
@@ -2466,20 +2465,20 @@ func applicationsUpdateSyncPolicyTest(t *testing.T, applicationsSyncPolicy v1alp
|
||||
}
|
||||
|
||||
// Verify that on validation error, no error is returned, but the object is requeued
|
||||
resCreate, err := r.Reconcile(context.Background(), req)
|
||||
resCreate, err := r.Reconcile(t.Context(), req)
|
||||
require.NoErrorf(t, err, "Reconcile failed with error: %v", err)
|
||||
assert.Equal(t, time.Duration(0), resCreate.RequeueAfter)
|
||||
|
||||
var app v1alpha1.Application
|
||||
|
||||
// make sure good app got created
|
||||
err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "good-cluster"}, &app)
|
||||
err = r.Client.Get(t.Context(), crtclient.ObjectKey{Namespace: "argocd", Name: "good-cluster"}, &app)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "good-cluster", app.Name)
|
||||
|
||||
// Update resource
|
||||
var retrievedApplicationSet v1alpha1.ApplicationSet
|
||||
err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "name"}, &retrievedApplicationSet)
|
||||
err = r.Client.Get(t.Context(), crtclient.ObjectKey{Namespace: "argocd", Name: "name"}, &retrievedApplicationSet)
|
||||
require.NoError(t, err)
|
||||
|
||||
retrievedApplicationSet.Spec.Template.Annotations = map[string]string{"annotation-key": "annotation-value"}
|
||||
@@ -2489,13 +2488,13 @@ func applicationsUpdateSyncPolicyTest(t *testing.T, applicationsSyncPolicy v1alp
|
||||
Values: "global.test: test",
|
||||
}
|
||||
|
||||
err = r.Client.Update(context.TODO(), &retrievedApplicationSet)
|
||||
err = r.Client.Update(t.Context(), &retrievedApplicationSet)
|
||||
require.NoError(t, err)
|
||||
|
||||
resUpdate, err := r.Reconcile(context.Background(), req)
|
||||
resUpdate, err := r.Reconcile(t.Context(), req)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "good-cluster"}, &app)
|
||||
err = r.Client.Get(t.Context(), crtclient.ObjectKey{Namespace: "argocd", Name: "good-cluster"}, &app)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, time.Duration(0), resUpdate.RequeueAfter)
|
||||
assert.Equal(t, "good-cluster", app.Name)
|
||||
@@ -2615,7 +2614,7 @@ func applicationsDeleteSyncPolicyTest(t *testing.T, applicationsSyncPolicy v1alp
|
||||
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appSet, &defaultProject).WithStatusSubresource(&appSet).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).Build()
|
||||
metrics := appsetmetrics.NewFakeAppsetMetrics()
|
||||
|
||||
argodb := db.NewDB("argocd", settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd"), kubeclientset)
|
||||
argodb := db.NewDB("argocd", settings.NewSettingsManager(t.Context(), kubeclientset, "argocd"), kubeclientset)
|
||||
|
||||
r := ApplicationSetReconciler{
|
||||
Client: client,
|
||||
@@ -2641,20 +2640,20 @@ func applicationsDeleteSyncPolicyTest(t *testing.T, applicationsSyncPolicy v1alp
|
||||
}
|
||||
|
||||
// Verify that on validation error, no error is returned, but the object is requeued
|
||||
resCreate, err := r.Reconcile(context.Background(), req)
|
||||
resCreate, err := r.Reconcile(t.Context(), req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, time.Duration(0), resCreate.RequeueAfter)
|
||||
|
||||
var app v1alpha1.Application
|
||||
|
||||
// make sure good app got created
|
||||
err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "good-cluster"}, &app)
|
||||
err = r.Client.Get(t.Context(), crtclient.ObjectKey{Namespace: "argocd", Name: "good-cluster"}, &app)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "good-cluster", app.Name)
|
||||
|
||||
// Update resource
|
||||
var retrievedApplicationSet v1alpha1.ApplicationSet
|
||||
err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "name"}, &retrievedApplicationSet)
|
||||
err = r.Client.Get(t.Context(), crtclient.ObjectKey{Namespace: "argocd", Name: "name"}, &retrievedApplicationSet)
|
||||
require.NoError(t, err)
|
||||
retrievedApplicationSet.Spec.Generators = []v1alpha1.ApplicationSetGenerator{
|
||||
{
|
||||
@@ -2664,15 +2663,15 @@ func applicationsDeleteSyncPolicyTest(t *testing.T, applicationsSyncPolicy v1alp
|
||||
},
|
||||
}
|
||||
|
||||
err = r.Client.Update(context.TODO(), &retrievedApplicationSet)
|
||||
err = r.Client.Update(t.Context(), &retrievedApplicationSet)
|
||||
require.NoError(t, err)
|
||||
|
||||
resUpdate, err := r.Reconcile(context.Background(), req)
|
||||
resUpdate, err := r.Reconcile(t.Context(), req)
|
||||
require.NoError(t, err)
|
||||
|
||||
var apps v1alpha1.ApplicationList
|
||||
|
||||
err = r.Client.List(context.TODO(), &apps)
|
||||
err = r.Client.List(t.Context(), &apps)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, time.Duration(0), resUpdate.RequeueAfter)
|
||||
|
||||
@@ -2804,7 +2803,7 @@ func TestPolicies(t *testing.T) {
|
||||
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appSet, &defaultProject).WithStatusSubresource(&appSet).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).Build()
|
||||
metrics := appsetmetrics.NewFakeAppsetMetrics()
|
||||
|
||||
argodb := db.NewDB("argocd", settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd"), kubeclientset)
|
||||
argodb := db.NewDB("argocd", settings.NewSettingsManager(t.Context(), kubeclientset, "argocd"), kubeclientset)
|
||||
|
||||
r := ApplicationSetReconciler{
|
||||
Client: client,
|
||||
@@ -2829,25 +2828,25 @@ func TestPolicies(t *testing.T) {
|
||||
}
|
||||
|
||||
// Check if Application is created
|
||||
res, err := r.Reconcile(context.Background(), req)
|
||||
res, err := r.Reconcile(t.Context(), req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, time.Duration(0), res.RequeueAfter)
|
||||
|
||||
var app v1alpha1.Application
|
||||
err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "my-app"}, &app)
|
||||
err = r.Client.Get(t.Context(), crtclient.ObjectKey{Namespace: "argocd", Name: "my-app"}, &app)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "value", app.Annotations["key"])
|
||||
|
||||
// Check if Application is updated
|
||||
app.Annotations["key"] = "edited"
|
||||
err = r.Client.Update(context.TODO(), &app)
|
||||
err = r.Client.Update(t.Context(), &app)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, err = r.Reconcile(context.Background(), req)
|
||||
res, err = r.Reconcile(t.Context(), req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, time.Duration(0), res.RequeueAfter)
|
||||
|
||||
err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "my-app"}, &app)
|
||||
err = r.Client.Get(t.Context(), crtclient.ObjectKey{Namespace: "argocd", Name: "my-app"}, &app)
|
||||
require.NoError(t, err)
|
||||
|
||||
if c.allowedUpdate {
|
||||
@@ -2857,21 +2856,21 @@ func TestPolicies(t *testing.T) {
|
||||
}
|
||||
|
||||
// Check if Application is deleted
|
||||
err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "name"}, &appSet)
|
||||
err = r.Client.Get(t.Context(), crtclient.ObjectKey{Namespace: "argocd", Name: "name"}, &appSet)
|
||||
require.NoError(t, err)
|
||||
appSet.Spec.Generators[0] = v1alpha1.ApplicationSetGenerator{
|
||||
List: &v1alpha1.ListGenerator{
|
||||
Elements: []apiextensionsv1.JSON{},
|
||||
},
|
||||
}
|
||||
err = r.Client.Update(context.TODO(), &appSet)
|
||||
err = r.Client.Update(t.Context(), &appSet)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, err = r.Reconcile(context.Background(), req)
|
||||
res, err = r.Reconcile(t.Context(), req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, time.Duration(0), res.RequeueAfter)
|
||||
|
||||
err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "my-app"}, &app)
|
||||
err = r.Client.Get(t.Context(), crtclient.ObjectKey{Namespace: "argocd", Name: "my-app"}, &app)
|
||||
require.NoError(t, err)
|
||||
if c.allowedDelete {
|
||||
assert.NotNil(t, app.DeletionTimestamp)
|
||||
@@ -2963,7 +2962,7 @@ func TestSetApplicationSetApplicationStatus(t *testing.T) {
|
||||
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&cc.appSet).WithStatusSubresource(&cc.appSet).Build()
|
||||
metrics := appsetmetrics.NewFakeAppsetMetrics()
|
||||
|
||||
argodb := db.NewDB("argocd", settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd"), kubeclientset)
|
||||
argodb := db.NewDB("argocd", settings.NewSettingsManager(t.Context(), kubeclientset, "argocd"), kubeclientset)
|
||||
|
||||
r := ApplicationSetReconciler{
|
||||
Client: client,
|
||||
@@ -2978,7 +2977,7 @@ func TestSetApplicationSetApplicationStatus(t *testing.T) {
|
||||
Metrics: metrics,
|
||||
}
|
||||
|
||||
err = r.setAppSetApplicationStatus(context.TODO(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.appStatuses)
|
||||
err = r.setAppSetApplicationStatus(t.Context(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.appStatuses)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, cc.expectedAppStatuses, cc.appSet.Status.ApplicationStatus)
|
||||
@@ -3723,7 +3722,7 @@ func TestBuildAppDependencyList(t *testing.T) {
|
||||
t.Run(cc.name, func(t *testing.T) {
|
||||
kubeclientset := kubefake.NewSimpleClientset([]runtime.Object{}...)
|
||||
|
||||
argodb := db.NewDB("argocd", settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd"), kubeclientset)
|
||||
argodb := db.NewDB("argocd", settings.NewSettingsManager(t.Context(), kubeclientset, "argocd"), kubeclientset)
|
||||
|
||||
r := ApplicationSetReconciler{
|
||||
Client: client,
|
||||
@@ -4391,7 +4390,7 @@ func TestBuildAppSyncMap(t *testing.T) {
|
||||
t.Run(cc.name, func(t *testing.T) {
|
||||
kubeclientset := kubefake.NewSimpleClientset([]runtime.Object{}...)
|
||||
|
||||
argodb := db.NewDB("argocd", settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd"), kubeclientset)
|
||||
argodb := db.NewDB("argocd", settings.NewSettingsManager(t.Context(), kubeclientset, "argocd"), kubeclientset)
|
||||
|
||||
r := ApplicationSetReconciler{
|
||||
Client: client,
|
||||
@@ -4749,6 +4748,9 @@ func TestUpdateApplicationSetApplicationStatus(t *testing.T) {
|
||||
Health: v1alpha1.HealthStatus{
|
||||
Status: health.HealthStatusProgressing,
|
||||
},
|
||||
Sync: v1alpha1.SyncStatus{
|
||||
Revision: "Next",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -4812,7 +4814,8 @@ func TestUpdateApplicationSetApplicationStatus(t *testing.T) {
|
||||
Phase: common.OperationRunning,
|
||||
},
|
||||
Sync: v1alpha1.SyncStatus{
|
||||
Status: v1alpha1.SyncStatusCodeSynced,
|
||||
Status: v1alpha1.SyncStatusCodeSynced,
|
||||
Revision: "Current",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -4877,7 +4880,8 @@ func TestUpdateApplicationSetApplicationStatus(t *testing.T) {
|
||||
Phase: common.OperationSucceeded,
|
||||
},
|
||||
Sync: v1alpha1.SyncStatus{
|
||||
Status: v1alpha1.SyncStatusCodeSynced,
|
||||
Status: v1alpha1.SyncStatusCodeSynced,
|
||||
Revision: "Next",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -4942,7 +4946,8 @@ func TestUpdateApplicationSetApplicationStatus(t *testing.T) {
|
||||
Phase: common.OperationSucceeded,
|
||||
},
|
||||
Sync: v1alpha1.SyncStatus{
|
||||
Status: v1alpha1.SyncStatusCodeSynced,
|
||||
Revision: "Current",
|
||||
Status: v1alpha1.SyncStatusCodeSynced,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -5181,86 +5186,6 @@ func TestUpdateApplicationSetApplicationStatus(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "does not progresses a pending application with a successful sync triggered by controller with invalid revision to progressing",
|
||||
appSet: v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "name",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
Strategy: &v1alpha1.ApplicationSetStrategy{
|
||||
Type: "RollingSync",
|
||||
RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{
|
||||
Steps: []v1alpha1.ApplicationSetRolloutStep{
|
||||
{
|
||||
MatchExpressions: []v1alpha1.ApplicationMatchExpression{},
|
||||
},
|
||||
{
|
||||
MatchExpressions: []v1alpha1.ApplicationMatchExpression{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: v1alpha1.ApplicationSetStatus{
|
||||
ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{
|
||||
{
|
||||
Application: "app1",
|
||||
LastTransitionTime: &metav1.Time{
|
||||
Time: time.Now().Add(time.Duration(-1) * time.Minute),
|
||||
},
|
||||
Message: "",
|
||||
Status: "Pending",
|
||||
Step: "1",
|
||||
TargetRevisions: []string{"Next"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
apps: []v1alpha1.Application{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "app1",
|
||||
},
|
||||
Status: v1alpha1.ApplicationStatus{
|
||||
Health: v1alpha1.HealthStatus{
|
||||
Status: health.HealthStatusDegraded,
|
||||
},
|
||||
OperationState: &v1alpha1.OperationState{
|
||||
Phase: common.OperationSucceeded,
|
||||
StartedAt: metav1.Time{
|
||||
Time: time.Now(),
|
||||
},
|
||||
Operation: v1alpha1.Operation{
|
||||
InitiatedBy: v1alpha1.OperationInitiator{
|
||||
Username: "applicationset-controller",
|
||||
Automated: true,
|
||||
},
|
||||
},
|
||||
SyncResult: &v1alpha1.SyncOperationResult{
|
||||
Revision: "Previous",
|
||||
},
|
||||
},
|
||||
Sync: v1alpha1.SyncStatus{
|
||||
Status: v1alpha1.SyncStatusCodeSynced,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
appStepMap: map[string]int{
|
||||
"app1": 0,
|
||||
},
|
||||
expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{
|
||||
{
|
||||
Application: "app1",
|
||||
Message: "",
|
||||
Status: "Pending",
|
||||
Step: "1",
|
||||
TargetRevisions: []string{"Next"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "removes the appStatus for applications that no longer exist",
|
||||
appSet: v1alpha1.ApplicationSet{
|
||||
@@ -5315,7 +5240,77 @@ func TestUpdateApplicationSetApplicationStatus(t *testing.T) {
|
||||
Phase: common.OperationSucceeded,
|
||||
},
|
||||
Sync: v1alpha1.SyncStatus{
|
||||
Status: v1alpha1.SyncStatusCodeSynced,
|
||||
Status: v1alpha1.SyncStatusCodeSynced,
|
||||
Revision: "Current",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
appStepMap: map[string]int{
|
||||
"app1": 0,
|
||||
},
|
||||
expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{
|
||||
{
|
||||
Application: "app1",
|
||||
Message: "Application resource is already Healthy, updating status from Waiting to Healthy.",
|
||||
Status: "Healthy",
|
||||
Step: "1",
|
||||
TargetRevisions: []string{"Current"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "progresses a pending synced application with an old revision to progressing with the Current one",
|
||||
appSet: v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "name",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
Strategy: &v1alpha1.ApplicationSetStrategy{
|
||||
Type: "RollingSync",
|
||||
RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{
|
||||
Steps: []v1alpha1.ApplicationSetRolloutStep{
|
||||
{
|
||||
MatchExpressions: []v1alpha1.ApplicationMatchExpression{},
|
||||
},
|
||||
{
|
||||
MatchExpressions: []v1alpha1.ApplicationMatchExpression{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: v1alpha1.ApplicationSetStatus{
|
||||
ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{
|
||||
{
|
||||
Application: "app1",
|
||||
Message: "",
|
||||
Status: "Pending",
|
||||
Step: "1",
|
||||
TargetRevisions: []string{"Old"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
apps: []v1alpha1.Application{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "app1",
|
||||
},
|
||||
Status: v1alpha1.ApplicationStatus{
|
||||
Health: v1alpha1.HealthStatus{
|
||||
Status: health.HealthStatusHealthy,
|
||||
},
|
||||
OperationState: &v1alpha1.OperationState{
|
||||
Phase: common.OperationSucceeded,
|
||||
SyncResult: &v1alpha1.SyncOperationResult{
|
||||
Revision: "Current",
|
||||
},
|
||||
},
|
||||
Sync: v1alpha1.SyncStatus{
|
||||
Status: v1alpha1.SyncStatusCodeSynced,
|
||||
Revisions: []string{"Current"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -5340,7 +5335,7 @@ func TestUpdateApplicationSetApplicationStatus(t *testing.T) {
|
||||
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&cc.appSet).WithStatusSubresource(&cc.appSet).Build()
|
||||
metrics := appsetmetrics.NewFakeAppsetMetrics()
|
||||
|
||||
argodb := db.NewDB("argocd", settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd"), kubeclientset)
|
||||
argodb := db.NewDB("argocd", settings.NewSettingsManager(t.Context(), kubeclientset, "argocd"), kubeclientset)
|
||||
|
||||
r := ApplicationSetReconciler{
|
||||
Client: client,
|
||||
@@ -5352,7 +5347,7 @@ func TestUpdateApplicationSetApplicationStatus(t *testing.T) {
|
||||
Metrics: metrics,
|
||||
}
|
||||
|
||||
appStatuses, err := r.updateApplicationSetApplicationStatus(context.TODO(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.apps, cc.appStepMap)
|
||||
appStatuses, err := r.updateApplicationSetApplicationStatus(t.Context(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.apps, cc.appStepMap)
|
||||
|
||||
// opt out of testing the LastTransitionTime is accurate
|
||||
for i := range appStatuses {
|
||||
@@ -6090,7 +6085,7 @@ func TestUpdateApplicationSetApplicationStatusProgress(t *testing.T) {
|
||||
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&cc.appSet).WithStatusSubresource(&cc.appSet).Build()
|
||||
metrics := appsetmetrics.NewFakeAppsetMetrics()
|
||||
|
||||
argodb := db.NewDB("argocd", settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd"), kubeclientset)
|
||||
argodb := db.NewDB("argocd", settings.NewSettingsManager(t.Context(), kubeclientset, "argocd"), kubeclientset)
|
||||
|
||||
r := ApplicationSetReconciler{
|
||||
Client: client,
|
||||
@@ -6102,7 +6097,7 @@ func TestUpdateApplicationSetApplicationStatusProgress(t *testing.T) {
|
||||
Metrics: metrics,
|
||||
}
|
||||
|
||||
appStatuses, err := r.updateApplicationSetApplicationStatusProgress(context.TODO(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.appSyncMap, cc.appStepMap)
|
||||
appStatuses, err := r.updateApplicationSetApplicationStatusProgress(t.Context(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.appSyncMap, cc.appStepMap)
|
||||
|
||||
// opt out of testing the LastTransitionTime is accurate
|
||||
for i := range appStatuses {
|
||||
@@ -6302,7 +6297,7 @@ func TestUpdateResourceStatus(t *testing.T) {
|
||||
client := fake.NewClientBuilder().WithScheme(scheme).WithStatusSubresource(&cc.appSet).WithObjects(&cc.appSet).Build()
|
||||
metrics := appsetmetrics.NewFakeAppsetMetrics()
|
||||
|
||||
argodb := db.NewDB("argocd", settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd"), kubeclientset)
|
||||
argodb := db.NewDB("argocd", settings.NewSettingsManager(t.Context(), kubeclientset, "argocd"), kubeclientset)
|
||||
|
||||
r := ApplicationSetReconciler{
|
||||
Client: client,
|
||||
@@ -6314,7 +6309,7 @@ func TestUpdateResourceStatus(t *testing.T) {
|
||||
Metrics: metrics,
|
||||
}
|
||||
|
||||
err := r.updateResourcesStatus(context.TODO(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.apps)
|
||||
err := r.updateResourcesStatus(t.Context(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.apps)
|
||||
|
||||
require.NoError(t, err, "expected no errors, but errors occurred")
|
||||
assert.Equal(t, cc.expectedResources, cc.appSet.Status.Resources, "expected resources did not match actual")
|
||||
@@ -6393,7 +6388,7 @@ func TestResourceStatusAreOrdered(t *testing.T) {
|
||||
client := fake.NewClientBuilder().WithScheme(scheme).WithStatusSubresource(&cc.appSet).WithObjects(&cc.appSet).Build()
|
||||
metrics := appsetmetrics.NewFakeAppsetMetrics()
|
||||
|
||||
argodb := db.NewDB("argocd", settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd"), kubeclientset)
|
||||
argodb := db.NewDB("argocd", settings.NewSettingsManager(t.Context(), kubeclientset, "argocd"), kubeclientset)
|
||||
|
||||
r := ApplicationSetReconciler{
|
||||
Client: client,
|
||||
@@ -6405,13 +6400,13 @@ func TestResourceStatusAreOrdered(t *testing.T) {
|
||||
Metrics: metrics,
|
||||
}
|
||||
|
||||
err := r.updateResourcesStatus(context.TODO(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.apps)
|
||||
err := r.updateResourcesStatus(t.Context(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.apps)
|
||||
require.NoError(t, err, "expected no errors, but errors occurred")
|
||||
|
||||
err = r.updateResourcesStatus(context.TODO(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.apps)
|
||||
err = r.updateResourcesStatus(t.Context(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.apps)
|
||||
require.NoError(t, err, "expected no errors, but errors occurred")
|
||||
|
||||
err = r.updateResourcesStatus(context.TODO(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.apps)
|
||||
err = r.updateResourcesStatus(t.Context(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.apps)
|
||||
require.NoError(t, err, "expected no errors, but errors occurred")
|
||||
|
||||
assert.Equal(t, cc.expectedResources, cc.appSet.Status.Resources, "expected resources did not match actual")
|
||||
@@ -6675,7 +6670,7 @@ func TestMigrateStatus(t *testing.T) {
|
||||
Client: client,
|
||||
}
|
||||
|
||||
err := r.migrateStatus(context.Background(), &tc.appset)
|
||||
err := r.migrateStatus(t.Context(), &tc.appset)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tc.expectedStatus, tc.appset.Status)
|
||||
})
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
argocommon "github.com/argoproj/argo-cd/v3/common"
|
||||
@@ -550,7 +549,7 @@ func TestClusterEventHandler(t *testing.T) {
|
||||
|
||||
mockAddRateLimitingInterface := mockAddRateLimitingInterface{}
|
||||
|
||||
handler.queueRelatedAppGenerators(context.Background(), &mockAddRateLimitingInterface, &test.secret)
|
||||
handler.queueRelatedAppGenerators(t.Context(), &mockAddRateLimitingInterface, &test.secret)
|
||||
|
||||
assert.ElementsMatch(t, mockAddRateLimitingInterface.addedItems, test.expectedRequests)
|
||||
})
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -24,7 +23,7 @@ import (
|
||||
|
||||
func TestRequeueAfter(t *testing.T) {
|
||||
mockServer := &mocks.Repos{}
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
scheme := runtime.NewScheme()
|
||||
err := argov1alpha1.AddToScheme(scheme)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -70,7 +70,7 @@ func (g *ClusterGenerator) GenerateParams(appSetGenerator *argoappsetv1alpha1.Ap
|
||||
// - Since local clusters do not have secrets, they do not have labels to match against
|
||||
ignoreLocalClusters := len(appSetGenerator.Clusters.Selector.MatchExpressions) > 0 || len(appSetGenerator.Clusters.Selector.MatchLabels) > 0
|
||||
|
||||
// ListCluster from Argo CD's util/db package will include the local cluster in the list of clusters
|
||||
// ListCluster will include the local cluster in the list of clusters
|
||||
clustersFromArgoCD, err := utils.ListClusters(g.ctx, g.clientset, g.namespace)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error listing clusters: %w", err)
|
||||
@@ -93,7 +93,7 @@ func (g *ClusterGenerator) GenerateParams(appSetGenerator *argoappsetv1alpha1.Ap
|
||||
logCtx.Debugf("Using flat mode = %t for cluster generator", isFlatMode)
|
||||
clustersParams := make([]map[string]any, 0)
|
||||
|
||||
for _, cluster := range clustersFromArgoCD.Items {
|
||||
for _, cluster := range clustersFromArgoCD {
|
||||
// If there is a secret for this cluster, then it's a non-local cluster, so it will be
|
||||
// handled by the next step.
|
||||
if secretForCluster, exists := clusterSecrets[cluster.Name]; exists {
|
||||
|
||||
@@ -315,7 +315,7 @@ func TestGenerateParams(t *testing.T) {
|
||||
testCase.clientError,
|
||||
}
|
||||
|
||||
clusterGenerator := NewClusterGenerator(context.Background(), cl, appClientset, "namespace")
|
||||
clusterGenerator := NewClusterGenerator(t.Context(), cl, appClientset, "namespace")
|
||||
|
||||
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
@@ -853,7 +853,7 @@ func TestGenerateParamsGoTemplate(t *testing.T) {
|
||||
testCase.clientError,
|
||||
}
|
||||
|
||||
clusterGenerator := NewClusterGenerator(context.Background(), cl, appClientset, "namespace")
|
||||
clusterGenerator := NewClusterGenerator(t.Context(), cl, appClientset, "namespace")
|
||||
|
||||
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
|
||||
@@ -165,9 +165,6 @@ func (g *DuckTypeGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.A
|
||||
}
|
||||
log.Infof("Number of decisions found: %v", len(clusterDecisions))
|
||||
|
||||
// Read this outside the loop to improve performance
|
||||
argoClusters := clustersFromArgoCD.Items
|
||||
|
||||
if len(clusterDecisions) == 0 {
|
||||
log.Warningf("clusterDecisionResource status.%s missing", statusListKey)
|
||||
return nil, nil
|
||||
@@ -188,7 +185,7 @@ func (g *DuckTypeGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.A
|
||||
|
||||
found := false
|
||||
|
||||
for _, argoCluster := range argoClusters {
|
||||
for _, argoCluster := range clustersFromArgoCD {
|
||||
if argoCluster.Name == strMatchValue {
|
||||
log.WithField(matchKey, argoCluster.Name).Info("matched cluster in ArgoCD")
|
||||
params["name"] = argoCluster.Name
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package generators
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
@@ -20,7 +19,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
resourceApiVersion = "mallard.io/v1"
|
||||
resourceAPIVersion = "mallard.io/v1"
|
||||
resourceKind = "ducks"
|
||||
resourceName = "quak"
|
||||
)
|
||||
@@ -79,7 +78,7 @@ func TestGenerateParamsForDuckType(t *testing.T) {
|
||||
|
||||
duckType := &unstructured.Unstructured{
|
||||
Object: map[string]any{
|
||||
"apiVersion": resourceApiVersion,
|
||||
"apiVersion": resourceAPIVersion,
|
||||
"kind": "Duck",
|
||||
"metadata": map[string]any{
|
||||
"name": resourceName,
|
||||
@@ -101,7 +100,7 @@ func TestGenerateParamsForDuckType(t *testing.T) {
|
||||
|
||||
duckTypeProdOnly := &unstructured.Unstructured{
|
||||
Object: map[string]any{
|
||||
"apiVersion": resourceApiVersion,
|
||||
"apiVersion": resourceAPIVersion,
|
||||
"kind": "Duck",
|
||||
"metadata": map[string]any{
|
||||
"name": resourceName,
|
||||
@@ -120,7 +119,7 @@ func TestGenerateParamsForDuckType(t *testing.T) {
|
||||
|
||||
duckTypeEmpty := &unstructured.Unstructured{
|
||||
Object: map[string]any{
|
||||
"apiVersion": resourceApiVersion,
|
||||
"apiVersion": resourceAPIVersion,
|
||||
"kind": "Duck",
|
||||
"metadata": map[string]any{
|
||||
"name": resourceName,
|
||||
@@ -137,7 +136,7 @@ func TestGenerateParamsForDuckType(t *testing.T) {
|
||||
Namespace: "namespace",
|
||||
},
|
||||
Data: map[string]string{
|
||||
"apiVersion": resourceApiVersion,
|
||||
"apiVersion": resourceAPIVersion,
|
||||
"kind": resourceKind,
|
||||
"statusListKey": "decisions",
|
||||
"matchKey": "clusterName",
|
||||
@@ -293,7 +292,7 @@ func TestGenerateParamsForDuckType(t *testing.T) {
|
||||
|
||||
fakeDynClient := dynfake.NewSimpleDynamicClientWithCustomListKinds(runtime.NewScheme(), gvrToListKind, testCase.resource)
|
||||
|
||||
duckTypeGenerator := NewDuckTypeGenerator(context.Background(), fakeDynClient, appClientset, "namespace")
|
||||
duckTypeGenerator := NewDuckTypeGenerator(t.Context(), fakeDynClient, appClientset, "namespace")
|
||||
|
||||
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
@@ -375,7 +374,7 @@ func TestGenerateParamsForDuckTypeGoTemplate(t *testing.T) {
|
||||
|
||||
duckType := &unstructured.Unstructured{
|
||||
Object: map[string]any{
|
||||
"apiVersion": resourceApiVersion,
|
||||
"apiVersion": resourceAPIVersion,
|
||||
"kind": "Duck",
|
||||
"metadata": map[string]any{
|
||||
"name": resourceName,
|
||||
@@ -397,7 +396,7 @@ func TestGenerateParamsForDuckTypeGoTemplate(t *testing.T) {
|
||||
|
||||
duckTypeProdOnly := &unstructured.Unstructured{
|
||||
Object: map[string]any{
|
||||
"apiVersion": resourceApiVersion,
|
||||
"apiVersion": resourceAPIVersion,
|
||||
"kind": "Duck",
|
||||
"metadata": map[string]any{
|
||||
"name": resourceName,
|
||||
@@ -416,7 +415,7 @@ func TestGenerateParamsForDuckTypeGoTemplate(t *testing.T) {
|
||||
|
||||
duckTypeEmpty := &unstructured.Unstructured{
|
||||
Object: map[string]any{
|
||||
"apiVersion": resourceApiVersion,
|
||||
"apiVersion": resourceAPIVersion,
|
||||
"kind": "Duck",
|
||||
"metadata": map[string]any{
|
||||
"name": resourceName,
|
||||
@@ -433,7 +432,7 @@ func TestGenerateParamsForDuckTypeGoTemplate(t *testing.T) {
|
||||
Namespace: "namespace",
|
||||
},
|
||||
Data: map[string]string{
|
||||
"apiVersion": resourceApiVersion,
|
||||
"apiVersion": resourceAPIVersion,
|
||||
"kind": resourceKind,
|
||||
"statusListKey": "decisions",
|
||||
"matchKey": "clusterName",
|
||||
@@ -589,7 +588,7 @@ func TestGenerateParamsForDuckTypeGoTemplate(t *testing.T) {
|
||||
|
||||
fakeDynClient := dynfake.NewSimpleDynamicClientWithCustomListKinds(runtime.NewScheme(), gvrToListKind, testCase.resource)
|
||||
|
||||
duckTypeGenerator := NewDuckTypeGenerator(context.Background(), fakeDynClient, appClientset, "namespace")
|
||||
duckTypeGenerator := NewDuckTypeGenerator(t.Context(), fakeDynClient, appClientset, "namespace")
|
||||
|
||||
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
|
||||
@@ -159,16 +159,3 @@ func InterpolateGenerator(requestedGenerator *argoprojiov1alpha1.ApplicationSetG
|
||||
|
||||
return *interpolatedGenerator, nil
|
||||
}
|
||||
|
||||
// Fixes https://github.com/argoproj/argo-cd/issues/11982 while ensuring backwards compatibility.
|
||||
// This is only a short-term solution and should be removed in a future major version.
|
||||
func dropDisabledNestedSelectors(generators []argoprojiov1alpha1.ApplicationSetNestedGenerator) bool {
|
||||
var foundSelector bool
|
||||
for i := range generators {
|
||||
if generators[i].Selector != nil {
|
||||
foundSelector = true
|
||||
generators[i].Selector = nil
|
||||
}
|
||||
}
|
||||
return foundSelector
|
||||
}
|
||||
|
||||
@@ -81,13 +81,17 @@ func (g *GitGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.Applic
|
||||
verifyCommit = len(appProject.Spec.SignatureKeys) > 0 && gpg.IsGPGEnabled()
|
||||
}
|
||||
|
||||
// If the project field is templated, we cannot resolve the project name, so we pass an empty string to the repo-server.
|
||||
// This means only "globally-scoped" repo credentials can be used for such appsets.
|
||||
project := resolveProjectName(appSet.Spec.Template.Spec.Project)
|
||||
|
||||
var err error
|
||||
var res []map[string]any
|
||||
switch {
|
||||
case len(appSetGenerator.Git.Directories) != 0:
|
||||
res, err = g.generateParamsForGitDirectories(appSetGenerator, noRevisionCache, verifyCommit, appSet.Spec.GoTemplate, appSet.Spec.GoTemplateOptions)
|
||||
res, err = g.generateParamsForGitDirectories(appSetGenerator, noRevisionCache, verifyCommit, appSet.Spec.GoTemplate, project, appSet.Spec.GoTemplateOptions)
|
||||
case len(appSetGenerator.Git.Files) != 0:
|
||||
res, err = g.generateParamsForGitFiles(appSetGenerator, noRevisionCache, verifyCommit, appSet.Spec.GoTemplate, appSet.Spec.GoTemplateOptions)
|
||||
res, err = g.generateParamsForGitFiles(appSetGenerator, noRevisionCache, verifyCommit, appSet.Spec.GoTemplate, project, appSet.Spec.GoTemplateOptions)
|
||||
default:
|
||||
return nil, EmptyAppSetGeneratorError
|
||||
}
|
||||
@@ -98,9 +102,9 @@ func (g *GitGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.Applic
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (g *GitGenerator) generateParamsForGitDirectories(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, noRevisionCache, verifyCommit bool, useGoTemplate bool, goTemplateOptions []string) ([]map[string]any, error) {
|
||||
func (g *GitGenerator) generateParamsForGitDirectories(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, noRevisionCache, verifyCommit, useGoTemplate bool, project string, goTemplateOptions []string) ([]map[string]any, error) {
|
||||
// Directories, not files
|
||||
allPaths, err := g.repos.GetDirectories(context.TODO(), appSetGenerator.Git.RepoURL, appSetGenerator.Git.Revision, noRevisionCache, verifyCommit)
|
||||
allPaths, err := g.repos.GetDirectories(context.TODO(), appSetGenerator.Git.RepoURL, appSetGenerator.Git.Revision, project, noRevisionCache, verifyCommit)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting directories from repo: %w", err)
|
||||
}
|
||||
@@ -123,11 +127,11 @@ func (g *GitGenerator) generateParamsForGitDirectories(appSetGenerator *argoproj
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (g *GitGenerator) generateParamsForGitFiles(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, noRevisionCache, verifyCommit bool, useGoTemplate bool, goTemplateOptions []string) ([]map[string]any, error) {
|
||||
func (g *GitGenerator) generateParamsForGitFiles(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, noRevisionCache, verifyCommit, useGoTemplate bool, project string, goTemplateOptions []string) ([]map[string]any, error) {
|
||||
// Get all files that match the requested path string, removing duplicates
|
||||
allFiles := make(map[string][]byte)
|
||||
for _, requestedPath := range appSetGenerator.Git.Files {
|
||||
files, err := g.repos.GetFiles(context.TODO(), appSetGenerator.Git.RepoURL, appSetGenerator.Git.Revision, requestedPath.Path, noRevisionCache, verifyCommit)
|
||||
files, err := g.repos.GetFiles(context.TODO(), appSetGenerator.Git.RepoURL, appSetGenerator.Git.Revision, project, requestedPath.Path, noRevisionCache, verifyCommit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -303,3 +307,11 @@ func (g *GitGenerator) generateParamsFromApps(requestedApps []string, appSetGene
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func resolveProjectName(project string) string {
|
||||
if strings.Contains(project, "{{") {
|
||||
return ""
|
||||
}
|
||||
|
||||
return project
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/utils/ptr"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/services/mocks"
|
||||
@@ -169,11 +170,12 @@ foo:
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
params, err := (*GitGenerator)(nil).generateParamsFromGitFile(tt.args.filePath, tt.args.fileContent, tt.args.values, tt.args.useGoTemplate, tt.args.goTemplateOptions, tt.args.pathParamPrefix)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("GitGenerator.generateParamsFromGitFile() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err, "GitGenerator.generateParamsFromGitFile()")
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.want, params)
|
||||
}
|
||||
assert.Equal(t, tt.want, params)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -198,7 +200,6 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) {
|
||||
"app_3",
|
||||
"p1/app4",
|
||||
},
|
||||
repoError: nil,
|
||||
expected: []map[string]any{
|
||||
{"path": "app1", "path.basename": "app1", "path.basenameNormalized": "app1", "path[0]": "app1"},
|
||||
{"path": "app2", "path.basename": "app2", "path.basenameNormalized": "app2", "path[0]": "app2"},
|
||||
@@ -233,7 +234,6 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) {
|
||||
"p1/p2/app3",
|
||||
"p1/p2/p3/app4",
|
||||
},
|
||||
repoError: nil,
|
||||
expected: []map[string]any{
|
||||
{"path": "p1/app2", "path.basename": "app2", "path[0]": "p1", "path[1]": "app2", "path.basenameNormalized": "app2"},
|
||||
{"path": "p1/p2/app3", "path.basename": "app3", "path[0]": "p1", "path[1]": "p2", "path[2]": "app3", "path.basenameNormalized": "app3"},
|
||||
@@ -321,7 +321,7 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) {
|
||||
|
||||
argoCDServiceMock := mocks.Repos{}
|
||||
|
||||
argoCDServiceMock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError)
|
||||
argoCDServiceMock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError)
|
||||
|
||||
gitGenerator := NewGitGenerator(&argoCDServiceMock, "")
|
||||
applicationSetInfo := v1alpha1.ApplicationSet{
|
||||
@@ -622,7 +622,7 @@ func TestGitGenerateParamsFromDirectoriesGoTemplate(t *testing.T) {
|
||||
|
||||
argoCDServiceMock := mocks.Repos{}
|
||||
|
||||
argoCDServiceMock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError)
|
||||
argoCDServiceMock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError)
|
||||
|
||||
gitGenerator := NewGitGenerator(&argoCDServiceMock, "")
|
||||
applicationSetInfo := v1alpha1.ApplicationSet{
|
||||
@@ -986,7 +986,7 @@ cluster:
|
||||
t.Parallel()
|
||||
|
||||
argoCDServiceMock := mocks.Repos{}
|
||||
argoCDServiceMock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).
|
||||
argoCDServiceMock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).
|
||||
Return(testCaseCopy.repoFileContents, testCaseCopy.repoPathsError)
|
||||
|
||||
gitGenerator := NewGitGenerator(&argoCDServiceMock, "")
|
||||
@@ -1342,7 +1342,7 @@ cluster:
|
||||
t.Parallel()
|
||||
|
||||
argoCDServiceMock := mocks.Repos{}
|
||||
argoCDServiceMock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).
|
||||
argoCDServiceMock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).
|
||||
Return(testCaseCopy.repoFileContents, testCaseCopy.repoPathsError)
|
||||
|
||||
gitGenerator := NewGitGenerator(&argoCDServiceMock, "")
|
||||
@@ -1387,6 +1387,7 @@ cluster:
|
||||
func TestGitGenerator_GenerateParams(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
appProject v1alpha1.AppProject
|
||||
directories []v1alpha1.GitDirectoryGeneratorItem
|
||||
pathParamPrefix string
|
||||
repoApps []string
|
||||
@@ -1395,6 +1396,7 @@ func TestGitGenerator_GenerateParams(t *testing.T) {
|
||||
values map[string]string
|
||||
expected []map[string]any
|
||||
expectedError error
|
||||
expectedProject *string
|
||||
appset v1alpha1.ApplicationSet
|
||||
callGetDirectories bool
|
||||
}{
|
||||
@@ -1466,21 +1468,102 @@ func TestGitGenerator_GenerateParams(t *testing.T) {
|
||||
expected: []map[string]any{{"path": "app1", "path.basename": "app1", "path.basenameNormalized": "app1", "path[0]": "app1", "values.foo": "bar"}},
|
||||
expectedError: errors.New("error getting project project: appprojects.argoproj.io \"project\" not found"),
|
||||
},
|
||||
{
|
||||
name: "Project field is not templated - verify that project is passed through to repo-server as-is",
|
||||
repoApps: []string{
|
||||
"app1",
|
||||
},
|
||||
callGetDirectories: true,
|
||||
appProject: v1alpha1.AppProject{
|
||||
TypeMeta: metav1.TypeMeta{},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "project",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
},
|
||||
appset: v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "set",
|
||||
Namespace: "namespace",
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
Generators: []v1alpha1.ApplicationSetGenerator{{
|
||||
Git: &v1alpha1.GitGenerator{
|
||||
RepoURL: "RepoURL",
|
||||
Revision: "Revision",
|
||||
Directories: []v1alpha1.GitDirectoryGeneratorItem{{Path: "*"}},
|
||||
PathParamPrefix: "",
|
||||
Values: map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
},
|
||||
}},
|
||||
Template: v1alpha1.ApplicationSetTemplate{
|
||||
Spec: v1alpha1.ApplicationSpec{
|
||||
Project: "project",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []map[string]any{{"path": "app1", "path.basename": "app1", "path.basenameNormalized": "app1", "path[0]": "app1", "values.foo": "bar"}},
|
||||
expectedProject: ptr.To("project"),
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Project field is templated - verify that project is passed through to repo-server as empty string",
|
||||
repoApps: []string{
|
||||
"app1",
|
||||
},
|
||||
callGetDirectories: true,
|
||||
appset: v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "set",
|
||||
Namespace: "namespace",
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
Generators: []v1alpha1.ApplicationSetGenerator{{
|
||||
Git: &v1alpha1.GitGenerator{
|
||||
RepoURL: "RepoURL",
|
||||
Revision: "Revision",
|
||||
Directories: []v1alpha1.GitDirectoryGeneratorItem{{Path: "*"}},
|
||||
PathParamPrefix: "",
|
||||
Values: map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
},
|
||||
}},
|
||||
Template: v1alpha1.ApplicationSetTemplate{
|
||||
Spec: v1alpha1.ApplicationSpec{
|
||||
Project: "{{.project}}",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []map[string]any{{"path": "app1", "path.basename": "app1", "path.basenameNormalized": "app1", "path[0]": "app1", "values.foo": "bar"}},
|
||||
expectedProject: ptr.To(""),
|
||||
expectedError: nil,
|
||||
},
|
||||
}
|
||||
for _, testCase := range cases {
|
||||
argoCDServiceMock := mocks.Repos{}
|
||||
|
||||
if testCase.callGetDirectories {
|
||||
argoCDServiceMock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(testCase.repoApps, testCase.repoPathsError)
|
||||
var project any
|
||||
if testCase.expectedProject != nil {
|
||||
project = *testCase.expectedProject
|
||||
} else {
|
||||
project = mock.Anything
|
||||
}
|
||||
|
||||
argoCDServiceMock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything, project, mock.Anything, mock.Anything).Return(testCase.repoApps, testCase.repoPathsError)
|
||||
}
|
||||
gitGenerator := NewGitGenerator(&argoCDServiceMock, "namespace")
|
||||
gitGenerator := NewGitGenerator(&argoCDServiceMock, "argocd")
|
||||
|
||||
scheme := runtime.NewScheme()
|
||||
err := v1alpha1.AddToScheme(scheme)
|
||||
require.NoError(t, err)
|
||||
appProject := v1alpha1.AppProject{}
|
||||
|
||||
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appProject).Build()
|
||||
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&testCase.appProject).Build()
|
||||
|
||||
got, err := gitGenerator.GenerateParams(&testCase.appset.Spec.Generators[0], &testCase.appset, client)
|
||||
|
||||
|
||||
@@ -10,8 +10,6 @@ import (
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/utils"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var _ Generator = (*MatrixGenerator)(nil)
|
||||
@@ -86,22 +84,10 @@ func (m *MatrixGenerator) getParams(appSetBaseGenerator argoprojiov1alpha1.Appli
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if matrixGen != nil && !appSet.Spec.ApplyNestedSelectors {
|
||||
foundSelector := dropDisabledNestedSelectors(matrixGen.Generators)
|
||||
if foundSelector {
|
||||
log.Warnf("AppSet '%v' defines selector on nested matrix generator's generator without enabling them via 'spec.applyNestedSelectors', ignoring nested selectors", appSet.Name)
|
||||
}
|
||||
}
|
||||
mergeGen, err := getMergeGenerator(appSetBaseGenerator)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error retrieving merge generator: %w", err)
|
||||
}
|
||||
if mergeGen != nil && !appSet.Spec.ApplyNestedSelectors {
|
||||
foundSelector := dropDisabledNestedSelectors(mergeGen.Generators)
|
||||
if foundSelector {
|
||||
log.Warnf("AppSet '%v' defines selector on nested merge generator's generator without enabling them via 'spec.applyNestedSelectors', ignoring nested selectors", appSet.Name)
|
||||
}
|
||||
}
|
||||
|
||||
t, err := Transform(
|
||||
argoprojiov1alpha1.ApplicationSetGenerator{
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package generators
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -644,7 +643,7 @@ func TestInterpolatedMatrixGenerate(t *testing.T) {
|
||||
fakeClient,
|
||||
testCase.clientError,
|
||||
}
|
||||
clusterGenerator := NewClusterGenerator(context.Background(), cl, appClientset, "namespace")
|
||||
clusterGenerator := NewClusterGenerator(t.Context(), cl, appClientset, "namespace")
|
||||
|
||||
for _, g := range testCaseCopy.baseGenerators {
|
||||
gitGeneratorSpec := v1alpha1.ApplicationSetGenerator{
|
||||
@@ -827,7 +826,7 @@ func TestInterpolatedMatrixGenerateGoTemplate(t *testing.T) {
|
||||
fakeClient,
|
||||
testCase.clientError,
|
||||
}
|
||||
clusterGenerator := NewClusterGenerator(context.Background(), cl, appClientset, "namespace")
|
||||
clusterGenerator := NewClusterGenerator(t.Context(), cl, appClientset, "namespace")
|
||||
|
||||
for _, g := range testCaseCopy.baseGenerators {
|
||||
gitGeneratorSpec := v1alpha1.ApplicationSetGenerator{
|
||||
@@ -1087,7 +1086,7 @@ func TestGitGenerator_GenerateParams_list_x_git_matrix_generator(t *testing.T) {
|
||||
}
|
||||
|
||||
repoServiceMock := &mocks.Repos{}
|
||||
repoServiceMock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(map[string][]byte{
|
||||
repoServiceMock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(map[string][]byte{
|
||||
"some/path.json": []byte("test: content"),
|
||||
}, nil)
|
||||
gitGenerator := NewGitGenerator(repoServiceMock, "")
|
||||
|
||||
@@ -11,8 +11,6 @@ import (
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/utils"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var _ Generator = (*MergeGenerator)(nil)
|
||||
@@ -124,11 +122,11 @@ func getParamSetsByMergeKey(mergeKeys []string, paramSets []map[string]any) (map
|
||||
for mergeKey := range deDuplicatedMergeKeys {
|
||||
paramSetKey[mergeKey] = paramSet[mergeKey]
|
||||
}
|
||||
paramSetKeyJson, err := json.Marshal(paramSetKey)
|
||||
paramSetKeyJSON, err := json.Marshal(paramSetKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error marshalling param set key json: %w", err)
|
||||
}
|
||||
paramSetKeyString := string(paramSetKeyJson)
|
||||
paramSetKeyString := string(paramSetKeyJSON)
|
||||
if _, exists := paramSetsByMergeKey[paramSetKeyString]; exists {
|
||||
return nil, fmt.Errorf("%w. Duplicate key was %s", ErrNonUniqueParamSets, paramSetKeyString)
|
||||
}
|
||||
@@ -144,22 +142,10 @@ func (m *MergeGenerator) getParams(appSetBaseGenerator argoprojiov1alpha1.Applic
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if matrixGen != nil && !appSet.Spec.ApplyNestedSelectors {
|
||||
foundSelector := dropDisabledNestedSelectors(matrixGen.Generators)
|
||||
if foundSelector {
|
||||
log.Warnf("AppSet '%v' defines selector on nested matrix generator's generator without enabling them via 'spec.applyNestedSelectors', ignoring nested selector", appSet.Name)
|
||||
}
|
||||
}
|
||||
mergeGen, err := getMergeGenerator(appSetBaseGenerator)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if mergeGen != nil && !appSet.Spec.ApplyNestedSelectors {
|
||||
foundSelector := dropDisabledNestedSelectors(mergeGen.Generators)
|
||||
if foundSelector {
|
||||
log.Warnf("AppSet '%v' defines selector on nested merge generator's generator without enabling them via 'spec.applyNestedSelectors', ignoring nested selector", appSet.Name)
|
||||
}
|
||||
}
|
||||
|
||||
t, err := Transform(
|
||||
argoprojiov1alpha1.ApplicationSetGenerator{
|
||||
|
||||
@@ -39,12 +39,12 @@ func getTerminalListGeneratorMultiple(jsons []string) argoprojiov1alpha1.Applica
|
||||
func listOfMapsToSet(maps []map[string]any) (map[string]bool, error) {
|
||||
set := make(map[string]bool, len(maps))
|
||||
for _, paramMap := range maps {
|
||||
paramMapAsJson, err := json.Marshal(paramMap)
|
||||
paramMapAsJSON, err := json.Marshal(paramMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
set[string(paramMapAsJson)] = false
|
||||
set[string(paramMapAsJSON)] = false
|
||||
}
|
||||
return set, nil
|
||||
}
|
||||
|
||||
2
applicationset/generators/mocks/Generator.go
generated
2
applicationset/generators/mocks/Generator.go
generated
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
// Code generated by mockery v2.52.4. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
|
||||
@@ -193,8 +193,8 @@ func (g *PluginGenerator) getConfigMap(ctx context.Context, configMapRef string)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
baseUrl, ok := cm.Data["baseUrl"]
|
||||
if !ok || baseUrl == "" {
|
||||
baseURL, ok := cm.Data["baseUrl"]
|
||||
if !ok || baseURL == "" {
|
||||
return nil, errors.New("baseUrl not found in ConfigMap")
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package generators
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -629,7 +628,7 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
@@ -691,11 +690,11 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
require.EqualError(t, err, testCase.expectedError.Error())
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
expectedJson, err := json.Marshal(testCase.expected)
|
||||
expectedJSON, err := json.Marshal(testCase.expected)
|
||||
require.NoError(t, err)
|
||||
gotJson, err := json.Marshal(got)
|
||||
gotJSON, err := json.Marshal(got)
|
||||
require.NoError(t, err)
|
||||
assert.JSONEq(t, string(expectedJson), string(gotJson))
|
||||
assert.JSONEq(t, string(expectedJSON), string(gotJSON))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -109,6 +109,11 @@ func (g *PullRequestGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha
|
||||
"author": pull.Author,
|
||||
}
|
||||
|
||||
err := appendTemplatedValues(appSetGenerator.PullRequest.Values, paramMap, applicationSetInfo.Spec.GoTemplate, applicationSetInfo.Spec.GoTemplateOptions)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to append templated values: %w", err)
|
||||
}
|
||||
|
||||
// PR lables will only be supported for Go Template appsets, since fasttemplate will be deprecated.
|
||||
if applicationSetInfo != nil && applicationSetInfo.Spec.GoTemplate {
|
||||
paramMap["labels"] = pull.Labels
|
||||
|
||||
@@ -14,9 +14,10 @@ import (
|
||||
)
|
||||
|
||||
func TestPullRequestGithubGenerateParams(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
cases := []struct {
|
||||
selectFunc func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error)
|
||||
values map[string]string
|
||||
expected []map[string]any
|
||||
expectedErr error
|
||||
applicationSet argoprojiov1alpha1.ApplicationSet
|
||||
@@ -120,6 +121,45 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
|
||||
},
|
||||
expectedErr: nil,
|
||||
},
|
||||
{
|
||||
selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) {
|
||||
return pullrequest.NewFakeService(
|
||||
ctx,
|
||||
[]*pullrequest.PullRequest{
|
||||
{
|
||||
Number: 1,
|
||||
Title: "title1",
|
||||
Branch: "my_branch",
|
||||
TargetBranch: "master",
|
||||
HeadSHA: "abcd",
|
||||
Author: "testName",
|
||||
},
|
||||
},
|
||||
nil,
|
||||
)
|
||||
},
|
||||
values: map[string]string{
|
||||
"foo": "bar",
|
||||
"pr_branch": "{{ branch }}",
|
||||
},
|
||||
expected: []map[string]any{
|
||||
{
|
||||
"number": "1",
|
||||
"title": "title1",
|
||||
"branch": "my_branch",
|
||||
"branch_slug": "my-branch",
|
||||
"target_branch": "master",
|
||||
"target_branch_slug": "master",
|
||||
"head_sha": "abcd",
|
||||
"head_short_sha": "abcd",
|
||||
"head_short_sha_7": "abcd",
|
||||
"author": "testName",
|
||||
"values.foo": "bar",
|
||||
"values.pr_branch": "my_branch",
|
||||
},
|
||||
},
|
||||
expectedErr: nil,
|
||||
},
|
||||
{
|
||||
selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) {
|
||||
return pullrequest.NewFakeService(
|
||||
@@ -219,12 +259,14 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
|
||||
selectServiceProviderFunc: c.selectFunc,
|
||||
}
|
||||
generatorConfig := argoprojiov1alpha1.ApplicationSetGenerator{
|
||||
PullRequest: &argoprojiov1alpha1.PullRequestGenerator{},
|
||||
PullRequest: &argoprojiov1alpha1.PullRequestGenerator{
|
||||
Values: c.values,
|
||||
},
|
||||
}
|
||||
|
||||
got, gotErr := gen.GenerateParams(&generatorConfig, &c.applicationSet, nil)
|
||||
if c.expectedErr != nil {
|
||||
assert.Equal(t, c.expectedErr.Error(), gotErr.Error())
|
||||
require.EqualError(t, gotErr, c.expectedErr.Error())
|
||||
} else {
|
||||
require.NoError(t, gotErr)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
package generators
|
||||
|
||||
type SCMGeneratorWithCustomApiUrl interface {
|
||||
type SCMGeneratorWithCustomApiUrl interface { //nolint:revive //FIXME(var-naming)
|
||||
CustomApiUrl() string
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
argoappv1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
applisters "github.com/argoproj/argo-cd/v3/pkg/client/listers/application/v1alpha1"
|
||||
metricsutil "github.com/argoproj/argo-cd/v3/util/metrics"
|
||||
"github.com/argoproj/argo-cd/v3/util/metrics/kubectl"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -57,6 +58,10 @@ func NewApplicationsetMetrics(appsetLister applisters.ApplicationSetLister, apps
|
||||
metrics.Registry.MustRegister(reconcileHistogram)
|
||||
metrics.Registry.MustRegister(appsetCollector)
|
||||
|
||||
kubectlMetricsServer := kubectl.NewKubectlMetrics()
|
||||
kubectlMetricsServer.RegisterWithClientGo()
|
||||
kubectl.RegisterWithPrometheus(metrics.Registry)
|
||||
|
||||
return ApplicationsetMetrics{
|
||||
reconcileHistogram: reconcileHistogram,
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package http
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -118,7 +117,7 @@ func TestClientDo(t *testing.T) {
|
||||
client, err := NewClient(cc.fakeServer.URL, cc.clientOptionFns...)
|
||||
require.NoError(t, err, "NewClient returned unexpected error")
|
||||
|
||||
req, err := client.NewRequestWithContext(context.Background(), http.MethodPost, "", cc.params)
|
||||
req, err := client.NewRequestWithContext(t.Context(), http.MethodPost, "", cc.params)
|
||||
require.NoError(t, err, "NewRequest returned unexpected error")
|
||||
|
||||
var data []map[string]any
|
||||
|
||||
38
applicationset/services/mocks/Repos.go
generated
38
applicationset/services/mocks/Repos.go
generated
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
// Code generated by mockery v2.52.4. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
@@ -13,9 +13,9 @@ type Repos struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// GetDirectories provides a mock function with given fields: ctx, repoURL, revision, noRevisionCache, verifyCommit
|
||||
func (_m *Repos) GetDirectories(ctx context.Context, repoURL string, revision string, noRevisionCache bool, verifyCommit bool) ([]string, error) {
|
||||
ret := _m.Called(ctx, repoURL, revision, noRevisionCache, verifyCommit)
|
||||
// GetDirectories provides a mock function with given fields: ctx, repoURL, revision, project, noRevisionCache, verifyCommit
|
||||
func (_m *Repos) GetDirectories(ctx context.Context, repoURL string, revision string, project string, noRevisionCache bool, verifyCommit bool) ([]string, error) {
|
||||
ret := _m.Called(ctx, repoURL, revision, project, noRevisionCache, verifyCommit)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetDirectories")
|
||||
@@ -23,19 +23,19 @@ func (_m *Repos) GetDirectories(ctx context.Context, repoURL string, revision st
|
||||
|
||||
var r0 []string
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, bool, bool) ([]string, error)); ok {
|
||||
return rf(ctx, repoURL, revision, noRevisionCache, verifyCommit)
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, string, bool, bool) ([]string, error)); ok {
|
||||
return rf(ctx, repoURL, revision, project, noRevisionCache, verifyCommit)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, bool, bool) []string); ok {
|
||||
r0 = rf(ctx, repoURL, revision, noRevisionCache, verifyCommit)
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, string, bool, bool) []string); ok {
|
||||
r0 = rf(ctx, repoURL, revision, project, noRevisionCache, verifyCommit)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]string)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, string, bool, bool) error); ok {
|
||||
r1 = rf(ctx, repoURL, revision, noRevisionCache, verifyCommit)
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, string, string, bool, bool) error); ok {
|
||||
r1 = rf(ctx, repoURL, revision, project, noRevisionCache, verifyCommit)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
@@ -43,9 +43,9 @@ func (_m *Repos) GetDirectories(ctx context.Context, repoURL string, revision st
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetFiles provides a mock function with given fields: ctx, repoURL, revision, pattern, noRevisionCache, verifyCommit
|
||||
func (_m *Repos) GetFiles(ctx context.Context, repoURL string, revision string, pattern string, noRevisionCache bool, verifyCommit bool) (map[string][]byte, error) {
|
||||
ret := _m.Called(ctx, repoURL, revision, pattern, noRevisionCache, verifyCommit)
|
||||
// GetFiles provides a mock function with given fields: ctx, repoURL, revision, project, pattern, noRevisionCache, verifyCommit
|
||||
func (_m *Repos) GetFiles(ctx context.Context, repoURL string, revision string, project string, pattern string, noRevisionCache bool, verifyCommit bool) (map[string][]byte, error) {
|
||||
ret := _m.Called(ctx, repoURL, revision, project, pattern, noRevisionCache, verifyCommit)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetFiles")
|
||||
@@ -53,19 +53,19 @@ func (_m *Repos) GetFiles(ctx context.Context, repoURL string, revision string,
|
||||
|
||||
var r0 map[string][]byte
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, string, bool, bool) (map[string][]byte, error)); ok {
|
||||
return rf(ctx, repoURL, revision, pattern, noRevisionCache, verifyCommit)
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, bool, bool) (map[string][]byte, error)); ok {
|
||||
return rf(ctx, repoURL, revision, project, pattern, noRevisionCache, verifyCommit)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, string, bool, bool) map[string][]byte); ok {
|
||||
r0 = rf(ctx, repoURL, revision, pattern, noRevisionCache, verifyCommit)
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, bool, bool) map[string][]byte); ok {
|
||||
r0 = rf(ctx, repoURL, revision, project, pattern, noRevisionCache, verifyCommit)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(map[string][]byte)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, string, string, bool, bool) error); ok {
|
||||
r1 = rf(ctx, repoURL, revision, pattern, noRevisionCache, verifyCommit)
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, string, string, string, bool, bool) error); ok {
|
||||
r1 = rf(ctx, repoURL, revision, project, pattern, noRevisionCache, verifyCommit)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
@@ -34,7 +33,7 @@ func TestPlugin(t *testing.T) {
|
||||
client, err := NewPluginService("plugin-test", ts.URL, token, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
data, err := client.List(context.Background(), nil)
|
||||
data, err := client.List(t.Context(), nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
var expectedData ServiceResponse
|
||||
|
||||
@@ -42,13 +42,13 @@ var (
|
||||
)
|
||||
|
||||
func NewAzureDevOpsService(token, url, organization, project, repo string, labels []string) (PullRequestService, error) {
|
||||
organizationUrl := buildURL(url, organization)
|
||||
organizationURL := buildURL(url, organization)
|
||||
|
||||
var connection *azuredevops.Connection
|
||||
if token == "" {
|
||||
connection = azuredevops.NewAnonymousConnection(organizationUrl)
|
||||
connection = azuredevops.NewAnonymousConnection(organizationURL)
|
||||
} else {
|
||||
connection = azuredevops.NewPatConnection(organizationUrl, token)
|
||||
connection = azuredevops.NewPatConnection(organizationURL, token)
|
||||
}
|
||||
|
||||
return &AzureDevOpsService{
|
||||
|
||||
@@ -61,20 +61,20 @@ func (m *AzureClientFactoryMock) GetClient(ctx context.Context) (git.Client, err
|
||||
func TestListPullRequest(t *testing.T) {
|
||||
teamProject := "myorg_project"
|
||||
repoName := "myorg_project_repo"
|
||||
pr_id := 123
|
||||
pr_title := "feat(123)"
|
||||
pr_head_sha := "cd4973d9d14a08ffe6b641a89a68891d6aac8056"
|
||||
ctx := context.Background()
|
||||
prID := 123
|
||||
prTitle := "feat(123)"
|
||||
prHeadSha := "cd4973d9d14a08ffe6b641a89a68891d6aac8056"
|
||||
ctx := t.Context()
|
||||
uniqueName := "testName"
|
||||
|
||||
pullRequestMock := []git.GitPullRequest{
|
||||
{
|
||||
PullRequestId: createIntPtr(pr_id),
|
||||
Title: createStringPtr(pr_title),
|
||||
PullRequestId: createIntPtr(prID),
|
||||
Title: createStringPtr(prTitle),
|
||||
SourceRefName: createStringPtr("refs/heads/feature-branch"),
|
||||
TargetRefName: createStringPtr("refs/heads/main"),
|
||||
LastMergeSourceCommit: &git.GitCommitRef{
|
||||
CommitId: createStringPtr(pr_head_sha),
|
||||
CommitId: createStringPtr(prHeadSha),
|
||||
},
|
||||
Labels: &[]core.WebApiTagDefinition{},
|
||||
Repository: &git.GitRepository{
|
||||
@@ -108,9 +108,9 @@ func TestListPullRequest(t *testing.T) {
|
||||
assert.Len(t, list, 1)
|
||||
assert.Equal(t, "feature-branch", list[0].Branch)
|
||||
assert.Equal(t, "main", list[0].TargetBranch)
|
||||
assert.Equal(t, pr_head_sha, list[0].HeadSHA)
|
||||
assert.Equal(t, prHeadSha, list[0].HeadSHA)
|
||||
assert.Equal(t, "feat(123)", list[0].Title)
|
||||
assert.Equal(t, pr_id, list[0].Number)
|
||||
assert.Equal(t, prID, list[0].Number)
|
||||
assert.Equal(t, uniqueName, list[0].Author)
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ type PullRequestResponse struct {
|
||||
|
||||
var _ PullRequestService = (*BitbucketCloudService)(nil)
|
||||
|
||||
func parseUrl(uri string) (*url.URL, error) {
|
||||
func parseURL(uri string) (*url.URL, error) {
|
||||
if uri == "" {
|
||||
uri = "https://api.bitbucket.org/2.0"
|
||||
}
|
||||
@@ -65,10 +65,10 @@ func parseUrl(uri string) (*url.URL, error) {
|
||||
return url, nil
|
||||
}
|
||||
|
||||
func NewBitbucketCloudServiceBasicAuth(baseUrl, username, password, owner, repositorySlug string) (PullRequestService, error) {
|
||||
url, err := parseUrl(baseUrl)
|
||||
func NewBitbucketCloudServiceBasicAuth(baseURL, username, password, owner, repositorySlug string) (PullRequestService, error) {
|
||||
url, err := parseURL(baseURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing base url of %s for %s/%s: %w", baseUrl, owner, repositorySlug, err)
|
||||
return nil, fmt.Errorf("error parsing base url of %s for %s/%s: %w", baseURL, owner, repositorySlug, err)
|
||||
}
|
||||
|
||||
bitbucketClient := bitbucket.NewBasicAuth(username, password)
|
||||
@@ -81,10 +81,10 @@ func NewBitbucketCloudServiceBasicAuth(baseUrl, username, password, owner, repos
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewBitbucketCloudServiceBearerToken(baseUrl, bearerToken, owner, repositorySlug string) (PullRequestService, error) {
|
||||
url, err := parseUrl(baseUrl)
|
||||
func NewBitbucketCloudServiceBearerToken(baseURL, bearerToken, owner, repositorySlug string) (PullRequestService, error) {
|
||||
url, err := parseURL(baseURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing base url of %s for %s/%s: %w", baseUrl, owner, repositorySlug, err)
|
||||
return nil, fmt.Errorf("error parsing base url of %s for %s/%s: %w", baseURL, owner, repositorySlug, err)
|
||||
}
|
||||
|
||||
bitbucketClient := bitbucket.NewOAuthbearerToken(bearerToken)
|
||||
@@ -97,9 +97,9 @@ func NewBitbucketCloudServiceBearerToken(baseUrl, bearerToken, owner, repository
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewBitbucketCloudServiceNoAuth(baseUrl, owner, repositorySlug string) (PullRequestService, error) {
|
||||
func NewBitbucketCloudServiceNoAuth(baseURL, owner, repositorySlug string) (PullRequestService, error) {
|
||||
// There is currently no method to explicitly not require auth
|
||||
return NewBitbucketCloudServiceBearerToken(baseUrl, "", owner, repositorySlug)
|
||||
return NewBitbucketCloudServiceBearerToken(baseURL, "", owner, repositorySlug)
|
||||
}
|
||||
|
||||
func (b *BitbucketCloudService) List(_ context.Context) ([]*PullRequest, error) {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package pull_request
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
@@ -54,11 +53,11 @@ func defaultHandlerCloud(t *testing.T) func(http.ResponseWriter, *http.Request)
|
||||
}
|
||||
|
||||
func TestParseUrlEmptyUrl(t *testing.T) {
|
||||
url, err := parseUrl("")
|
||||
bitbucketUrl, _ := url.Parse("https://api.bitbucket.org/2.0")
|
||||
url, err := parseURL("")
|
||||
bitbucketURL, _ := url.Parse("https://api.bitbucket.org/2.0")
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, bitbucketUrl, url)
|
||||
assert.Equal(t, bitbucketURL, url)
|
||||
}
|
||||
|
||||
func TestInvalidBaseUrlBasicAuthCloud(t *testing.T) {
|
||||
@@ -87,7 +86,7 @@ func TestListPullRequestBearerTokenCloud(t *testing.T) {
|
||||
defer ts.Close()
|
||||
svc, err := NewBitbucketCloudServiceBearerToken(ts.URL, "TOKEN", "OWNER", "REPO")
|
||||
require.NoError(t, err)
|
||||
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 1)
|
||||
assert.Equal(t, 101, pullRequests[0].Number)
|
||||
@@ -105,7 +104,7 @@ func TestListPullRequestNoAuthCloud(t *testing.T) {
|
||||
defer ts.Close()
|
||||
svc, err := NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO")
|
||||
require.NoError(t, err)
|
||||
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 1)
|
||||
assert.Equal(t, 101, pullRequests[0].Number)
|
||||
@@ -123,7 +122,7 @@ func TestListPullRequestBasicAuthCloud(t *testing.T) {
|
||||
defer ts.Close()
|
||||
svc, err := NewBitbucketCloudServiceBasicAuth(ts.URL, "user", "password", "OWNER", "REPO")
|
||||
require.NoError(t, err)
|
||||
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 1)
|
||||
assert.Equal(t, 101, pullRequests[0].Number)
|
||||
@@ -214,7 +213,7 @@ func TestListPullRequestPaginationCloud(t *testing.T) {
|
||||
defer ts.Close()
|
||||
svc, err := NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO")
|
||||
require.NoError(t, err)
|
||||
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 3)
|
||||
assert.Equal(t, PullRequest{
|
||||
@@ -246,7 +245,7 @@ func TestListResponseErrorCloud(t *testing.T) {
|
||||
}))
|
||||
defer ts.Close()
|
||||
svc, _ := NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO")
|
||||
_, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
_, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
@@ -270,7 +269,7 @@ func TestListResponseMalformedCloud(t *testing.T) {
|
||||
}))
|
||||
defer ts.Close()
|
||||
svc, _ := NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO")
|
||||
_, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
_, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
@@ -294,7 +293,7 @@ func TestListResponseMalformedValuesCloud(t *testing.T) {
|
||||
}))
|
||||
defer ts.Close()
|
||||
svc, _ := NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO")
|
||||
_, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
_, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
@@ -319,7 +318,7 @@ func TestListResponseEmptyCloud(t *testing.T) {
|
||||
defer ts.Close()
|
||||
svc, err := NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO")
|
||||
require.NoError(t, err)
|
||||
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.NoError(t, err)
|
||||
assert.Empty(t, pullRequests)
|
||||
}
|
||||
@@ -406,7 +405,7 @@ func TestListPullRequestBranchMatchCloud(t *testing.T) {
|
||||
regexp := `feature-1[\d]{2}`
|
||||
svc, err := NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO")
|
||||
require.NoError(t, err)
|
||||
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{
|
||||
pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{
|
||||
{
|
||||
BranchMatch: ®exp,
|
||||
},
|
||||
@@ -431,7 +430,7 @@ func TestListPullRequestBranchMatchCloud(t *testing.T) {
|
||||
regexp = `.*2$`
|
||||
svc, err = NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO")
|
||||
require.NoError(t, err)
|
||||
pullRequests, err = ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{
|
||||
pullRequests, err = ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{
|
||||
{
|
||||
BranchMatch: ®exp,
|
||||
},
|
||||
@@ -449,7 +448,7 @@ func TestListPullRequestBranchMatchCloud(t *testing.T) {
|
||||
regexp = `[\d{2}`
|
||||
svc, err = NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO")
|
||||
require.NoError(t, err)
|
||||
_, err = ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{
|
||||
_, err = ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{
|
||||
{
|
||||
BranchMatch: ®exp,
|
||||
},
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package pull_request
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"io"
|
||||
@@ -64,9 +63,9 @@ func TestListPullRequestNoAuth(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
svc, err := NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
svc, err := NewBitbucketServiceNoAuth(t.Context(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 1)
|
||||
assert.Equal(t, 101, pullRequests[0].Number)
|
||||
@@ -165,9 +164,9 @@ func TestListPullRequestPagination(t *testing.T) {
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
svc, err := NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
svc, err := NewBitbucketServiceNoAuth(t.Context(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 3)
|
||||
assert.Equal(t, PullRequest{
|
||||
@@ -207,9 +206,9 @@ func TestListPullRequestBasicAuth(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
svc, err := NewBitbucketServiceBasicAuth(context.Background(), "user", "password", ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
svc, err := NewBitbucketServiceBasicAuth(t.Context(), "user", "password", ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 1)
|
||||
assert.Equal(t, 101, pullRequests[0].Number)
|
||||
@@ -224,9 +223,9 @@ func TestListPullRequestBearerAuth(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
svc, err := NewBitbucketServiceBearerToken(context.Background(), "tolkien", ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
svc, err := NewBitbucketServiceBearerToken(t.Context(), "tolkien", ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 1)
|
||||
assert.Equal(t, 101, pullRequests[0].Number)
|
||||
@@ -290,9 +289,9 @@ func TestListPullRequestTLS(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
svc, err := NewBitbucketServiceBasicAuth(context.Background(), "user", "password", ts.URL, "PROJECT", "REPO", "", test.tlsInsecure, certs)
|
||||
svc, err := NewBitbucketServiceBasicAuth(t.Context(), "user", "password", ts.URL, "PROJECT", "REPO", "", test.tlsInsecure, certs)
|
||||
require.NoError(t, err)
|
||||
_, err = ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
_, err = ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
if test.requireErr {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
@@ -307,8 +306,8 @@ func TestListResponseError(t *testing.T) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}))
|
||||
defer ts.Close()
|
||||
svc, _ := NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
_, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
svc, _ := NewBitbucketServiceNoAuth(t.Context(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
_, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
@@ -332,8 +331,8 @@ func TestListResponseMalformed(t *testing.T) {
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
svc, _ := NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
_, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
svc, _ := NewBitbucketServiceNoAuth(t.Context(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
_, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
@@ -357,9 +356,9 @@ func TestListResponseEmpty(t *testing.T) {
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
svc, err := NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
svc, err := NewBitbucketServiceNoAuth(t.Context(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.NoError(t, err)
|
||||
assert.Empty(t, pullRequests)
|
||||
}
|
||||
@@ -453,9 +452,9 @@ func TestListPullRequestBranchMatch(t *testing.T) {
|
||||
}))
|
||||
defer ts.Close()
|
||||
regexp := `feature-1[\d]{2}`
|
||||
svc, err := NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
svc, err := NewBitbucketServiceNoAuth(t.Context(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{
|
||||
pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{
|
||||
{
|
||||
BranchMatch: ®exp,
|
||||
},
|
||||
@@ -482,9 +481,9 @@ func TestListPullRequestBranchMatch(t *testing.T) {
|
||||
}, *pullRequests[1])
|
||||
|
||||
regexp = `.*2$`
|
||||
svc, err = NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
svc, err = NewBitbucketServiceNoAuth(t.Context(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
pullRequests, err = ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{
|
||||
pullRequests, err = ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{
|
||||
{
|
||||
BranchMatch: ®exp,
|
||||
},
|
||||
@@ -502,9 +501,9 @@ func TestListPullRequestBranchMatch(t *testing.T) {
|
||||
}, *pullRequests[0])
|
||||
|
||||
regexp = `[\d{2}`
|
||||
svc, err = NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
svc, err = NewBitbucketServiceNoAuth(t.Context(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
_, err = ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{
|
||||
_, err = ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{
|
||||
{
|
||||
BranchMatch: ®exp,
|
||||
},
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package pull_request
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
@@ -253,7 +252,7 @@ func TestGiteaList(t *testing.T) {
|
||||
}))
|
||||
host, err := NewGiteaService("", ts.URL, "test-argocd", "pr-test", false)
|
||||
require.NoError(t, err)
|
||||
prs, err := host.List(context.Background())
|
||||
prs, err := host.List(t.Context())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, prs, 1)
|
||||
assert.Equal(t, 1, prs[0].Number)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package pull_request
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"io"
|
||||
@@ -38,7 +37,7 @@ func TestGitLabServiceCustomBaseURL(t *testing.T) {
|
||||
svc, err := NewGitLabService("", server.URL, "278964", nil, "", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = svc.List(context.Background())
|
||||
_, err = svc.List(t.Context())
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
@@ -57,7 +56,7 @@ func TestGitLabServiceToken(t *testing.T) {
|
||||
svc, err := NewGitLabService("token-123", server.URL, "278964", nil, "", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = svc.List(context.Background())
|
||||
_, err = svc.List(t.Context())
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
@@ -76,7 +75,7 @@ func TestList(t *testing.T) {
|
||||
svc, err := NewGitLabService("", server.URL, "278964", []string{}, "", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
prs, err := svc.List(context.Background())
|
||||
prs, err := svc.List(t.Context())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, prs, 1)
|
||||
assert.Equal(t, 15442, prs[0].Number)
|
||||
@@ -102,7 +101,7 @@ func TestListWithLabels(t *testing.T) {
|
||||
svc, err := NewGitLabService("", server.URL, "278964", []string{"feature", "ready"}, "", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = svc.List(context.Background())
|
||||
_, err = svc.List(t.Context())
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
@@ -121,7 +120,7 @@ func TestListWithState(t *testing.T) {
|
||||
svc, err := NewGitLabService("", server.URL, "278964", []string{}, "opened", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = svc.List(context.Background())
|
||||
_, err = svc.List(t.Context())
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
@@ -183,7 +182,7 @@ func TestListWithStateTLS(t *testing.T) {
|
||||
svc, err := NewGitLabService("", ts.URL, "278964", []string{}, "opened", "", test.tlsInsecure, certs)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = svc.List(context.Background())
|
||||
_, err = svc.List(t.Context())
|
||||
if test.requireErr {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package pull_request
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -16,7 +15,7 @@ func strp(s string) *string {
|
||||
|
||||
func TestFilterBranchMatchBadRegexp(t *testing.T) {
|
||||
provider, _ := NewFakeService(
|
||||
context.Background(),
|
||||
t.Context(),
|
||||
[]*PullRequest{
|
||||
{
|
||||
Number: 1,
|
||||
@@ -34,13 +33,13 @@ func TestFilterBranchMatchBadRegexp(t *testing.T) {
|
||||
BranchMatch: strp("("),
|
||||
},
|
||||
}
|
||||
_, err := ListPullRequests(context.Background(), provider, filters)
|
||||
_, err := ListPullRequests(t.Context(), provider, filters)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestFilterBranchMatch(t *testing.T) {
|
||||
provider, _ := NewFakeService(
|
||||
context.Background(),
|
||||
t.Context(),
|
||||
[]*PullRequest{
|
||||
{
|
||||
Number: 1,
|
||||
@@ -82,7 +81,7 @@ func TestFilterBranchMatch(t *testing.T) {
|
||||
BranchMatch: strp("w"),
|
||||
},
|
||||
}
|
||||
pullRequests, err := ListPullRequests(context.Background(), provider, filters)
|
||||
pullRequests, err := ListPullRequests(t.Context(), provider, filters)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 1)
|
||||
assert.Equal(t, "two", pullRequests[0].Branch)
|
||||
@@ -90,7 +89,7 @@ func TestFilterBranchMatch(t *testing.T) {
|
||||
|
||||
func TestFilterTargetBranchMatch(t *testing.T) {
|
||||
provider, _ := NewFakeService(
|
||||
context.Background(),
|
||||
t.Context(),
|
||||
[]*PullRequest{
|
||||
{
|
||||
Number: 1,
|
||||
@@ -132,7 +131,7 @@ func TestFilterTargetBranchMatch(t *testing.T) {
|
||||
TargetBranchMatch: strp("1"),
|
||||
},
|
||||
}
|
||||
pullRequests, err := ListPullRequests(context.Background(), provider, filters)
|
||||
pullRequests, err := ListPullRequests(t.Context(), provider, filters)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 1)
|
||||
assert.Equal(t, "two", pullRequests[0].Branch)
|
||||
@@ -140,7 +139,7 @@ func TestFilterTargetBranchMatch(t *testing.T) {
|
||||
|
||||
func TestMultiFilterOr(t *testing.T) {
|
||||
provider, _ := NewFakeService(
|
||||
context.Background(),
|
||||
t.Context(),
|
||||
[]*PullRequest{
|
||||
{
|
||||
Number: 1,
|
||||
@@ -185,7 +184,7 @@ func TestMultiFilterOr(t *testing.T) {
|
||||
BranchMatch: strp("r"),
|
||||
},
|
||||
}
|
||||
pullRequests, err := ListPullRequests(context.Background(), provider, filters)
|
||||
pullRequests, err := ListPullRequests(t.Context(), provider, filters)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 3)
|
||||
assert.Equal(t, "two", pullRequests[0].Branch)
|
||||
@@ -195,7 +194,7 @@ func TestMultiFilterOr(t *testing.T) {
|
||||
|
||||
func TestMultiFilterOrWithTargetBranchFilter(t *testing.T) {
|
||||
provider, _ := NewFakeService(
|
||||
context.Background(),
|
||||
t.Context(),
|
||||
[]*PullRequest{
|
||||
{
|
||||
Number: 1,
|
||||
@@ -242,7 +241,7 @@ func TestMultiFilterOrWithTargetBranchFilter(t *testing.T) {
|
||||
TargetBranchMatch: strp("3"),
|
||||
},
|
||||
}
|
||||
pullRequests, err := ListPullRequests(context.Background(), provider, filters)
|
||||
pullRequests, err := ListPullRequests(t.Context(), provider, filters)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 2)
|
||||
assert.Equal(t, "two", pullRequests[0].Branch)
|
||||
@@ -251,7 +250,7 @@ func TestMultiFilterOrWithTargetBranchFilter(t *testing.T) {
|
||||
|
||||
func TestNoFilters(t *testing.T) {
|
||||
provider, _ := NewFakeService(
|
||||
context.Background(),
|
||||
t.Context(),
|
||||
[]*PullRequest{
|
||||
{
|
||||
Number: 1,
|
||||
@@ -273,7 +272,7 @@ func TestNoFilters(t *testing.T) {
|
||||
nil,
|
||||
)
|
||||
filters := []argoprojiov1alpha1.PullRequestGeneratorFilter{}
|
||||
repos, err := ListPullRequests(context.Background(), provider, filters)
|
||||
repos, err := ListPullRequests(t.Context(), provider, filters)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, repos, 2)
|
||||
assert.Equal(t, "one", repos[0].Branch)
|
||||
|
||||
@@ -6,37 +6,52 @@ import (
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v3/reposerver/apiclient"
|
||||
"github.com/argoproj/argo-cd/v3/util/git"
|
||||
"github.com/argoproj/argo-cd/v3/util/db"
|
||||
"github.com/argoproj/argo-cd/v3/util/io"
|
||||
)
|
||||
|
||||
type argoCDService struct {
|
||||
getRepository func(ctx context.Context, url, project string) (*v1alpha1.Repository, error)
|
||||
storecreds git.CredsStore
|
||||
submoduleEnabled bool
|
||||
repoServerClientSet apiclient.Clientset
|
||||
newFileGlobbingEnabled bool
|
||||
getRepository func(ctx context.Context, url, project string) (*v1alpha1.Repository, error)
|
||||
submoduleEnabled bool
|
||||
newFileGlobbingEnabled bool
|
||||
getGitFilesFromRepoServer func(ctx context.Context, req *apiclient.GitFilesRequest) (*apiclient.GitFilesResponse, error)
|
||||
getGitDirectoriesFromRepoServer func(ctx context.Context, req *apiclient.GitDirectoriesRequest) (*apiclient.GitDirectoriesResponse, error)
|
||||
}
|
||||
|
||||
type Repos interface {
|
||||
// GetFiles returns content of files (not directories) within the target repo
|
||||
GetFiles(ctx context.Context, repoURL string, revision string, pattern string, noRevisionCache, verifyCommit bool) (map[string][]byte, error)
|
||||
GetFiles(ctx context.Context, repoURL, revision, project, pattern string, noRevisionCache, verifyCommit bool) (map[string][]byte, error)
|
||||
|
||||
// GetDirectories returns a list of directories (not files) within the target repo
|
||||
GetDirectories(ctx context.Context, repoURL string, revision string, noRevisionCache, verifyCommit bool) ([]string, error)
|
||||
GetDirectories(ctx context.Context, repoURL, revision, project string, noRevisionCache, verifyCommit bool) ([]string, error)
|
||||
}
|
||||
|
||||
func NewArgoCDService(getRepository func(ctx context.Context, url, project string) (*v1alpha1.Repository, error), submoduleEnabled bool, repoClientset apiclient.Clientset, newFileGlobbingEnabled bool) (Repos, error) {
|
||||
func NewArgoCDService(db db.ArgoDB, submoduleEnabled bool, repoClientset apiclient.Clientset, newFileGlobbingEnabled bool) Repos {
|
||||
return &argoCDService{
|
||||
getRepository: getRepository,
|
||||
getRepository: db.GetRepository,
|
||||
submoduleEnabled: submoduleEnabled,
|
||||
repoServerClientSet: repoClientset,
|
||||
newFileGlobbingEnabled: newFileGlobbingEnabled,
|
||||
}, nil
|
||||
getGitFilesFromRepoServer: func(ctx context.Context, fileRequest *apiclient.GitFilesRequest) (*apiclient.GitFilesResponse, error) {
|
||||
closer, client, err := repoClientset.NewRepoServerClient()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error initializing new repo server client: %w", err)
|
||||
}
|
||||
defer io.Close(closer)
|
||||
return client.GetGitFiles(ctx, fileRequest)
|
||||
},
|
||||
getGitDirectoriesFromRepoServer: func(ctx context.Context, dirRequest *apiclient.GitDirectoriesRequest) (*apiclient.GitDirectoriesResponse, error) {
|
||||
closer, client, err := repoClientset.NewRepoServerClient()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error initialising new repo server client: %w", err)
|
||||
}
|
||||
defer io.Close(closer)
|
||||
return client.GetGitDirectories(ctx, dirRequest)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (a *argoCDService) GetFiles(ctx context.Context, repoURL string, revision string, pattern string, noRevisionCache, verifyCommit bool) (map[string][]byte, error) {
|
||||
repo, err := a.getRepository(ctx, repoURL, "")
|
||||
func (a *argoCDService) GetFiles(ctx context.Context, repoURL, revision, project, pattern string, noRevisionCache, verifyCommit bool) (map[string][]byte, error) {
|
||||
repo, err := a.getRepository(ctx, repoURL, project)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error in GetRepository: %w", err)
|
||||
}
|
||||
@@ -50,21 +65,15 @@ func (a *argoCDService) GetFiles(ctx context.Context, repoURL string, revision s
|
||||
NoRevisionCache: noRevisionCache,
|
||||
VerifyCommit: verifyCommit,
|
||||
}
|
||||
closer, client, err := a.repoServerClientSet.NewRepoServerClient()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error initialising new repo server client: %w", err)
|
||||
}
|
||||
defer io.Close(closer)
|
||||
|
||||
fileResponse, err := client.GetGitFiles(ctx, fileRequest)
|
||||
fileResponse, err := a.getGitFilesFromRepoServer(ctx, fileRequest)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error retrieving Git files: %w", err)
|
||||
}
|
||||
return fileResponse.GetMap(), nil
|
||||
}
|
||||
|
||||
func (a *argoCDService) GetDirectories(ctx context.Context, repoURL string, revision string, noRevisionCache, verifyCommit bool) ([]string, error) {
|
||||
repo, err := a.getRepository(ctx, repoURL, "")
|
||||
func (a *argoCDService) GetDirectories(ctx context.Context, repoURL, revision, project string, noRevisionCache, verifyCommit bool) ([]string, error) {
|
||||
repo, err := a.getRepository(ctx, repoURL, project)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error in GetRepository: %w", err)
|
||||
}
|
||||
@@ -77,13 +86,7 @@ func (a *argoCDService) GetDirectories(ctx context.Context, repoURL string, revi
|
||||
VerifyCommit: verifyCommit,
|
||||
}
|
||||
|
||||
closer, client, err := a.repoServerClientSet.NewRepoServerClient()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error initialising new repo server client: %w", err)
|
||||
}
|
||||
defer io.Close(closer)
|
||||
|
||||
dirResponse, err := client.GetGitDirectories(ctx, dirRequest)
|
||||
dirResponse, err := a.getGitDirectoriesFromRepoServer(ctx, dirRequest)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error retrieving Git Directories: %w", err)
|
||||
}
|
||||
|
||||
@@ -7,22 +7,21 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/reposerver/apiclient"
|
||||
repo_mocks "github.com/argoproj/argo-cd/v3/reposerver/apiclient/mocks"
|
||||
"github.com/argoproj/argo-cd/v3/util/git"
|
||||
"github.com/argoproj/argo-cd/v3/util/db"
|
||||
"github.com/argoproj/argo-cd/v3/util/settings"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
func TestGetDirectories(t *testing.T) {
|
||||
type fields struct {
|
||||
storecreds git.CredsStore
|
||||
submoduleEnabled bool
|
||||
getRepository func(ctx context.Context, url, project string) (*v1alpha1.Repository, error)
|
||||
repoServerClientFuncs []func(*repo_mocks.RepoServerServiceClient)
|
||||
submoduleEnabled bool
|
||||
getRepository func(ctx context.Context, url, project string) (*v1alpha1.Repository, error)
|
||||
getGitDirectories func(ctx context.Context, req *apiclient.GitDirectoriesRequest) (*apiclient.GitDirectoriesResponse, error)
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
@@ -47,50 +46,41 @@ func TestGetDirectories(t *testing.T) {
|
||||
getRepository: func(_ context.Context, _, _ string) (*v1alpha1.Repository, error) {
|
||||
return &v1alpha1.Repository{}, nil
|
||||
},
|
||||
repoServerClientFuncs: []func(*repo_mocks.RepoServerServiceClient){
|
||||
func(client *repo_mocks.RepoServerServiceClient) {
|
||||
client.On("GetGitDirectories", mock.Anything, mock.Anything).Return(nil, errors.New("unable to get dirs"))
|
||||
},
|
||||
getGitDirectories: func(_ context.Context, _ *apiclient.GitDirectoriesRequest) (*apiclient.GitDirectoriesResponse, error) {
|
||||
return nil, errors.New("unable to get dirs")
|
||||
},
|
||||
}, args: args{}, want: nil, wantErr: assert.Error},
|
||||
{name: "HappyCase", fields: fields{
|
||||
getRepository: func(_ context.Context, _, _ string) (*v1alpha1.Repository, error) {
|
||||
return &v1alpha1.Repository{}, nil
|
||||
return &v1alpha1.Repository{
|
||||
Repo: "foo",
|
||||
}, nil
|
||||
},
|
||||
repoServerClientFuncs: []func(*repo_mocks.RepoServerServiceClient){
|
||||
func(client *repo_mocks.RepoServerServiceClient) {
|
||||
client.On("GetGitDirectories", mock.Anything, mock.Anything).Return(&apiclient.GitDirectoriesResponse{
|
||||
Paths: []string{"foo", "foo/bar", "bar/foo"},
|
||||
}, nil)
|
||||
},
|
||||
getGitDirectories: func(_ context.Context, _ *apiclient.GitDirectoriesRequest) (*apiclient.GitDirectoriesResponse, error) {
|
||||
return &apiclient.GitDirectoriesResponse{
|
||||
Paths: []string{"foo", "foo/bar", "bar/foo"},
|
||||
}, nil
|
||||
},
|
||||
}, args: args{}, want: []string{"foo", "foo/bar", "bar/foo"}, wantErr: assert.NoError},
|
||||
}, args: args{
|
||||
repoURL: "foo",
|
||||
}, want: []string{"foo", "foo/bar", "bar/foo"}, wantErr: assert.NoError},
|
||||
{name: "ErrorVerifyingCommit", fields: fields{
|
||||
getRepository: func(_ context.Context, _, _ string) (*v1alpha1.Repository, error) {
|
||||
return &v1alpha1.Repository{}, nil
|
||||
},
|
||||
repoServerClientFuncs: []func(*repo_mocks.RepoServerServiceClient){
|
||||
func(client *repo_mocks.RepoServerServiceClient) {
|
||||
client.On("GetGitDirectories", mock.Anything, mock.Anything).Return(nil, errors.New("revision HEAD is not signed"))
|
||||
},
|
||||
getGitDirectories: func(_ context.Context, _ *apiclient.GitDirectoriesRequest) (*apiclient.GitDirectoriesResponse, error) {
|
||||
return nil, errors.New("revision HEAD is not signed")
|
||||
},
|
||||
}, args: args{}, want: nil, wantErr: assert.Error},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mockRepoClient := &repo_mocks.RepoServerServiceClient{}
|
||||
// decorate the mocks
|
||||
for i := range tt.fields.repoServerClientFuncs {
|
||||
tt.fields.repoServerClientFuncs[i](mockRepoClient)
|
||||
}
|
||||
|
||||
a := &argoCDService{
|
||||
getRepository: tt.fields.getRepository,
|
||||
storecreds: tt.fields.storecreds,
|
||||
submoduleEnabled: tt.fields.submoduleEnabled,
|
||||
repoServerClientSet: &repo_mocks.Clientset{RepoServerServiceClient: mockRepoClient},
|
||||
getRepository: tt.fields.getRepository,
|
||||
submoduleEnabled: tt.fields.submoduleEnabled,
|
||||
getGitDirectoriesFromRepoServer: tt.fields.getGitDirectories,
|
||||
}
|
||||
got, err := a.GetDirectories(tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.noRevisionCache, tt.args.verifyCommit)
|
||||
got, err := a.GetDirectories(tt.args.ctx, tt.args.repoURL, tt.args.revision, "", tt.args.noRevisionCache, tt.args.verifyCommit)
|
||||
if !tt.wantErr(t, err, fmt.Sprintf("GetDirectories(%v, %v, %v, %v)", tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.noRevisionCache)) {
|
||||
return
|
||||
}
|
||||
@@ -101,10 +91,9 @@ func TestGetDirectories(t *testing.T) {
|
||||
|
||||
func TestGetFiles(t *testing.T) {
|
||||
type fields struct {
|
||||
storecreds git.CredsStore
|
||||
submoduleEnabled bool
|
||||
repoServerClientFuncs []func(*repo_mocks.RepoServerServiceClient)
|
||||
getRepository func(ctx context.Context, url, project string) (*v1alpha1.Repository, error)
|
||||
submoduleEnabled bool
|
||||
getRepository func(ctx context.Context, url, project string) (*v1alpha1.Repository, error)
|
||||
getGitFiles func(ctx context.Context, req *apiclient.GitFilesRequest) (*apiclient.GitFilesResponse, error)
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
@@ -130,27 +119,27 @@ func TestGetFiles(t *testing.T) {
|
||||
getRepository: func(_ context.Context, _, _ string) (*v1alpha1.Repository, error) {
|
||||
return &v1alpha1.Repository{}, nil
|
||||
},
|
||||
repoServerClientFuncs: []func(*repo_mocks.RepoServerServiceClient){
|
||||
func(client *repo_mocks.RepoServerServiceClient) {
|
||||
client.On("GetGitFiles", mock.Anything, mock.Anything).Return(nil, errors.New("unable to get files"))
|
||||
},
|
||||
getGitFiles: func(_ context.Context, _ *apiclient.GitFilesRequest) (*apiclient.GitFilesResponse, error) {
|
||||
return nil, errors.New("unable to get files")
|
||||
},
|
||||
}, args: args{}, want: nil, wantErr: assert.Error},
|
||||
{name: "HappyCase", fields: fields{
|
||||
getRepository: func(_ context.Context, _, _ string) (*v1alpha1.Repository, error) {
|
||||
return &v1alpha1.Repository{}, nil
|
||||
return &v1alpha1.Repository{
|
||||
Repo: "foo",
|
||||
}, nil
|
||||
},
|
||||
repoServerClientFuncs: []func(*repo_mocks.RepoServerServiceClient){
|
||||
func(client *repo_mocks.RepoServerServiceClient) {
|
||||
client.On("GetGitFiles", mock.Anything, mock.Anything).Return(&apiclient.GitFilesResponse{
|
||||
Map: map[string][]byte{
|
||||
"foo.json": []byte("hello: world!"),
|
||||
"bar.yaml": []byte("yay: appsets"),
|
||||
},
|
||||
}, nil)
|
||||
},
|
||||
getGitFiles: func(_ context.Context, _ *apiclient.GitFilesRequest) (*apiclient.GitFilesResponse, error) {
|
||||
return &apiclient.GitFilesResponse{
|
||||
Map: map[string][]byte{
|
||||
"foo.json": []byte("hello: world!"),
|
||||
"bar.yaml": []byte("yay: appsets"),
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
}, args: args{}, want: map[string][]byte{
|
||||
}, args: args{
|
||||
repoURL: "foo",
|
||||
}, want: map[string][]byte{
|
||||
"foo.json": []byte("hello: world!"),
|
||||
"bar.yaml": []byte("yay: appsets"),
|
||||
}, wantErr: assert.NoError},
|
||||
@@ -158,28 +147,19 @@ func TestGetFiles(t *testing.T) {
|
||||
getRepository: func(_ context.Context, _, _ string) (*v1alpha1.Repository, error) {
|
||||
return &v1alpha1.Repository{}, nil
|
||||
},
|
||||
repoServerClientFuncs: []func(*repo_mocks.RepoServerServiceClient){
|
||||
func(client *repo_mocks.RepoServerServiceClient) {
|
||||
client.On("GetGitFiles", mock.Anything, mock.Anything).Return(nil, errors.New("revision HEAD is not signed"))
|
||||
},
|
||||
getGitFiles: func(_ context.Context, _ *apiclient.GitFilesRequest) (*apiclient.GitFilesResponse, error) {
|
||||
return nil, errors.New("revision HEAD is not signed")
|
||||
},
|
||||
}, args: args{}, want: nil, wantErr: assert.Error},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mockRepoClient := &repo_mocks.RepoServerServiceClient{}
|
||||
// decorate the mocks
|
||||
for i := range tt.fields.repoServerClientFuncs {
|
||||
tt.fields.repoServerClientFuncs[i](mockRepoClient)
|
||||
}
|
||||
|
||||
a := &argoCDService{
|
||||
getRepository: tt.fields.getRepository,
|
||||
storecreds: tt.fields.storecreds,
|
||||
submoduleEnabled: tt.fields.submoduleEnabled,
|
||||
repoServerClientSet: &repo_mocks.Clientset{RepoServerServiceClient: mockRepoClient},
|
||||
getRepository: tt.fields.getRepository,
|
||||
submoduleEnabled: tt.fields.submoduleEnabled,
|
||||
getGitFilesFromRepoServer: tt.fields.getGitFiles,
|
||||
}
|
||||
got, err := a.GetFiles(tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.pattern, tt.args.noRevisionCache, tt.args.verifyCommit)
|
||||
got, err := a.GetFiles(tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.pattern, "", tt.args.noRevisionCache, tt.args.verifyCommit)
|
||||
if !tt.wantErr(t, err, fmt.Sprintf("GetFiles(%v, %v, %v, %v, %v)", tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.pattern, tt.args.noRevisionCache)) {
|
||||
return
|
||||
}
|
||||
@@ -189,9 +169,9 @@ func TestGetFiles(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNewArgoCDService(t *testing.T) {
|
||||
service, err := NewArgoCDService(func(_ context.Context, _, _ string) (*v1alpha1.Repository, error) {
|
||||
return &v1alpha1.Repository{}, nil
|
||||
}, false, &repo_mocks.Clientset{}, false)
|
||||
require.NoError(t, err)
|
||||
testNamespace := "test"
|
||||
clientset := fake.NewClientset()
|
||||
testDB := db.NewDB(testNamespace, settings.NewSettingsManager(t.Context(), clientset, testNamespace), clientset)
|
||||
service := NewArgoCDService(testDB, false, &repo_mocks.Clientset{}, false)
|
||||
assert.NotNil(t, service)
|
||||
}
|
||||
|
||||
@@ -26,8 +26,8 @@ import (
|
||||
|
||||
const (
|
||||
resourceTypeCodeCommitRepository = "codecommit:repository"
|
||||
prefixGitUrlHttps = "https://git-codecommit."
|
||||
prefixGitUrlHttpsFIPS = "https://git-codecommit-fips."
|
||||
prefixGitURLHTTPS = "https://git-codecommit."
|
||||
prefixGitURLHTTPSFIPS = "https://git-codecommit-fips."
|
||||
)
|
||||
|
||||
// AWSCodeCommitClient is a lean facade to the codecommitiface.CodeCommitAPI
|
||||
@@ -315,16 +315,16 @@ func getCodeCommitRepoName(repoArn string) (string, error) {
|
||||
// getCodeCommitFIPSEndpoint transforms provided https:// codecommit URL to a FIPS-compliant endpoint.
|
||||
// note that the specified region must support FIPS, otherwise the returned URL won't be reachable
|
||||
// see: https://docs.aws.amazon.com/codecommit/latest/userguide/regions.html#regions-git
|
||||
func getCodeCommitFIPSEndpoint(repoUrl string) (string, error) {
|
||||
if strings.HasPrefix(repoUrl, prefixGitUrlHttpsFIPS) {
|
||||
log.Debugf("provided repoUrl %s is already a fips endpoint", repoUrl)
|
||||
return repoUrl, nil
|
||||
func getCodeCommitFIPSEndpoint(repoURL string) (string, error) {
|
||||
if strings.HasPrefix(repoURL, prefixGitURLHTTPSFIPS) {
|
||||
log.Debugf("provided repoUrl %s is already a fips endpoint", repoURL)
|
||||
return repoURL, nil
|
||||
}
|
||||
if !strings.HasPrefix(repoUrl, prefixGitUrlHttps) {
|
||||
return "", fmt.Errorf("the provided https endpoint isn't recognized, cannot be transformed to FIPS endpoint: %s", repoUrl)
|
||||
if !strings.HasPrefix(repoURL, prefixGitURLHTTPS) {
|
||||
return "", fmt.Errorf("the provided https endpoint isn't recognized, cannot be transformed to FIPS endpoint: %s", repoURL)
|
||||
}
|
||||
// we already have the prefix, so we guarantee to replace exactly the prefix only.
|
||||
return strings.Replace(repoUrl, prefixGitUrlHttps, prefixGitUrlHttpsFIPS, 1), nil
|
||||
return strings.Replace(repoURL, prefixGitURLHTTPS, prefixGitURLHTTPSFIPS, 1), nil
|
||||
}
|
||||
|
||||
func hasAwsError(err error, codes ...string) bool {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
// Code generated by mockery v2.52.4. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
// Code generated by mockery v2.52.4. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package scm_provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sort"
|
||||
"testing"
|
||||
@@ -23,7 +22,7 @@ type awsCodeCommitTestRepository struct {
|
||||
arn string
|
||||
accountId string
|
||||
defaultBranch string
|
||||
expectedCloneUrl string
|
||||
expectedCloneURL string
|
||||
getRepositoryError error
|
||||
getRepositoryNilMetadata bool
|
||||
valid bool
|
||||
@@ -49,7 +48,7 @@ func TestAWSCodeCommitListRepos(t *testing.T) {
|
||||
id: "8235624d-d248-4df9-a983-2558b01dbe83",
|
||||
arn: "arn:aws:codecommit:us-east-1:111111111111:repo1",
|
||||
defaultBranch: "main",
|
||||
expectedCloneUrl: "https://git-codecommit.us-east-1.amazonaws.com/v1/repos/repo1",
|
||||
expectedCloneURL: "https://git-codecommit.us-east-1.amazonaws.com/v1/repos/repo1",
|
||||
valid: true,
|
||||
},
|
||||
},
|
||||
@@ -74,7 +73,7 @@ func TestAWSCodeCommitListRepos(t *testing.T) {
|
||||
id: "8235624d-d248-4df9-a983-2558b01dbe83",
|
||||
arn: "arn:aws:codecommit:us-east-1:111111111111:repo1",
|
||||
defaultBranch: "main",
|
||||
expectedCloneUrl: "https://git-codecommit-fips.us-east-1.amazonaws.com/v1/repos/repo1",
|
||||
expectedCloneURL: "https://git-codecommit-fips.us-east-1.amazonaws.com/v1/repos/repo1",
|
||||
valid: true,
|
||||
},
|
||||
},
|
||||
@@ -96,7 +95,7 @@ func TestAWSCodeCommitListRepos(t *testing.T) {
|
||||
id: "8235624d-d248-4df9-a983-2558b01dbe83",
|
||||
arn: "arn:aws:codecommit:us-east-1:111111111111:repo1",
|
||||
defaultBranch: "main",
|
||||
expectedCloneUrl: "ssh://git-codecommit.us-east-1.amazonaws.com/v1/repos/repo1",
|
||||
expectedCloneURL: "ssh://git-codecommit.us-east-1.amazonaws.com/v1/repos/repo1",
|
||||
valid: true,
|
||||
},
|
||||
{
|
||||
@@ -160,7 +159,7 @@ func TestAWSCodeCommitListRepos(t *testing.T) {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
codeCommitClient := mocks.NewAWSCodeCommitClient(t)
|
||||
taggingClient := mocks.NewAWSTaggingClient(t)
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
codecommitRepoNameIdPairs := make([]*codecommit.RepositoryNameIdPair, 0)
|
||||
resourceTaggings := make([]*resourcegroupstaggingapi.ResourceTagMapping, 0)
|
||||
validRepositories := make([]*awsCodeCommitTestRepository, 0)
|
||||
@@ -226,7 +225,7 @@ func TestAWSCodeCommitListRepos(t *testing.T) {
|
||||
assert.Equal(t, originRepo.name, repo.Repository)
|
||||
assert.Equal(t, originRepo.id, repo.RepositoryId)
|
||||
assert.Equal(t, originRepo.defaultBranch, repo.Branch)
|
||||
assert.Equal(t, originRepo.expectedCloneUrl, repo.URL)
|
||||
assert.Equal(t, originRepo.expectedCloneURL, repo.URL)
|
||||
assert.Empty(t, repo.SHA, "SHA is always empty")
|
||||
}
|
||||
}
|
||||
@@ -349,7 +348,7 @@ func TestAWSCodeCommitRepoHasPath(t *testing.T) {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
codeCommitClient := mocks.NewAWSCodeCommitClient(t)
|
||||
taggingClient := mocks.NewAWSTaggingClient(t)
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
if testCase.expectedGetFolderPath != "" {
|
||||
codeCommitClient.
|
||||
On("GetFolderWithContext", ctx, &codecommit.GetFolderInput{
|
||||
@@ -382,7 +381,7 @@ func TestAWSCodeCommitGetBranches(t *testing.T) {
|
||||
id := "1a64adc4-2fb5-4abd-afe7-127984ba83c0"
|
||||
defaultBranch := "main"
|
||||
organization := "111111111111"
|
||||
cloneUrl := "https://git-codecommit.us-east-1.amazonaws.com/v1/repos/repo1"
|
||||
cloneURL := "https://git-codecommit.us-east-1.amazonaws.com/v1/repos/repo1"
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
@@ -422,7 +421,7 @@ func TestAWSCodeCommitGetBranches(t *testing.T) {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
codeCommitClient := mocks.NewAWSCodeCommitClient(t)
|
||||
taggingClient := mocks.NewAWSTaggingClient(t)
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
if testCase.allBranches {
|
||||
codeCommitClient.
|
||||
On("ListBranchesWithContext", ctx, &codecommit.ListBranchesInput{
|
||||
@@ -445,7 +444,7 @@ func TestAWSCodeCommitGetBranches(t *testing.T) {
|
||||
actual, err := provider.GetBranches(ctx, &Repository{
|
||||
Organization: organization,
|
||||
Repository: name,
|
||||
URL: cloneUrl,
|
||||
URL: cloneURL,
|
||||
RepositoryId: id,
|
||||
})
|
||||
if testCase.expectOverallError {
|
||||
@@ -454,7 +453,7 @@ func TestAWSCodeCommitGetBranches(t *testing.T) {
|
||||
assertCopiedProperties := func(repo *Repository) {
|
||||
assert.Equal(t, id, repo.RepositoryId)
|
||||
assert.Equal(t, name, repo.Repository)
|
||||
assert.Equal(t, cloneUrl, repo.URL)
|
||||
assert.Equal(t, cloneURL, repo.URL)
|
||||
assert.Equal(t, organization, repo.Organization)
|
||||
assert.Empty(t, repo.SHA)
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ func (g *AzureDevOpsProvider) RepoHasPath(ctx context.Context, repo *Repository,
|
||||
}
|
||||
|
||||
var repoId string
|
||||
if uuid, isUuid := repo.RepositoryId.(uuid.UUID); isUuid { // most likely an UUID, but do type-safe check anyway. Do %v fallback if not expected type.
|
||||
if uuid, isUUID := repo.RepositoryId.(uuid.UUID); isUUID { // most likely an UUID, but do type-safe check anyway. Do %v fallback if not expected type.
|
||||
repoId = uuid.String()
|
||||
} else {
|
||||
repoId = fmt.Sprintf("%v", repo.RepositoryId)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
// Code generated by mockery v2.52.4. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ func TestAzureDevopsRepoHasPath(t *testing.T) {
|
||||
path := "dir/subdir/item.yaml"
|
||||
branchName := "my/featurebranch"
|
||||
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
uuid := uuid.New().String()
|
||||
|
||||
testCases := []struct {
|
||||
@@ -115,7 +115,7 @@ func TestGetDefaultBranchOnDisabledRepo(t *testing.T) {
|
||||
repoName := "myorg_project_repo"
|
||||
defaultBranch := "main"
|
||||
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
@@ -174,7 +174,7 @@ func TestGetAllBranchesOnDisabledRepo(t *testing.T) {
|
||||
repoName := "myorg_project_repo"
|
||||
defaultBranch := "main"
|
||||
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
@@ -233,7 +233,7 @@ func TestAzureDevOpsGetDefaultBranchStripsRefsName(t *testing.T) {
|
||||
teamProject := "myorg_project"
|
||||
repoName := "myorg_project_repo"
|
||||
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
uuid := uuid.New().String()
|
||||
strippedBranchName := "somebranch"
|
||||
defaultBranch := fmt.Sprintf("refs/heads/%v", strippedBranchName)
|
||||
@@ -264,7 +264,7 @@ func TestAzureDevOpsGetBranchesDefultBranchOnly(t *testing.T) {
|
||||
teamProject := "myorg_project"
|
||||
repoName := "myorg_project_repo"
|
||||
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
uuid := uuid.New().String()
|
||||
|
||||
defaultBranch := "main"
|
||||
@@ -272,7 +272,7 @@ func TestAzureDevOpsGetBranchesDefultBranchOnly(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
expectedBranch *azureGit.GitBranchStats
|
||||
getBranchesApiError error
|
||||
getBranchesAPIError error
|
||||
clientError error
|
||||
}{
|
||||
{
|
||||
@@ -281,7 +281,7 @@ func TestAzureDevOpsGetBranchesDefultBranchOnly(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "GetBranches AllBranches false when request fails returns error and empty result",
|
||||
getBranchesApiError: errors.New("Remote Azure Devops GetBranches error"),
|
||||
getBranchesAPIError: errors.New("Remote Azure Devops GetBranches error"),
|
||||
},
|
||||
{
|
||||
name: "GetBranches AllBranches false when Azure DevOps client fails returns error",
|
||||
@@ -300,7 +300,7 @@ func TestAzureDevOpsGetBranchesDefultBranchOnly(t *testing.T) {
|
||||
clientFactoryMock := &AzureClientFactoryMock{mock: &mock.Mock{}}
|
||||
clientFactoryMock.mock.On("GetClient", mock.Anything).Return(&gitClientMock, testCase.clientError)
|
||||
|
||||
gitClientMock.On("GetBranch", ctx, azureGit.GetBranchArgs{RepositoryId: &repoName, Project: &teamProject, Name: &defaultBranch}).Return(testCase.expectedBranch, testCase.getBranchesApiError)
|
||||
gitClientMock.On("GetBranch", ctx, azureGit.GetBranchArgs{RepositoryId: &repoName, Project: &teamProject, Name: &defaultBranch}).Return(testCase.expectedBranch, testCase.getBranchesAPIError)
|
||||
|
||||
repo := &Repository{Organization: organization, Repository: repoName, RepositoryId: uuid, Branch: defaultBranch}
|
||||
|
||||
@@ -314,9 +314,9 @@ func TestAzureDevOpsGetBranchesDefultBranchOnly(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
if testCase.getBranchesApiError != nil {
|
||||
if testCase.getBranchesAPIError != nil {
|
||||
assert.Empty(t, branches)
|
||||
require.ErrorContains(t, err, testCase.getBranchesApiError.Error())
|
||||
require.ErrorContains(t, err, testCase.getBranchesAPIError.Error())
|
||||
} else {
|
||||
if testCase.expectedBranch != nil {
|
||||
assert.NotEmpty(t, branches)
|
||||
@@ -335,13 +335,13 @@ func TestAzureDevopsGetBranches(t *testing.T) {
|
||||
teamProject := "myorg_project"
|
||||
repoName := "myorg_project_repo"
|
||||
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
uuid := uuid.New().String()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
expectedBranches *[]azureGit.GitBranchStats
|
||||
getBranchesApiError error
|
||||
getBranchesAPIError error
|
||||
clientError error
|
||||
allBranches bool
|
||||
expectedProcessingErrorMsg string
|
||||
@@ -353,7 +353,7 @@ func TestAzureDevopsGetBranches(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "GetBranches when Azure DevOps request fails returns error and empty result",
|
||||
getBranchesApiError: errors.New("Remote Azure Devops GetBranches error"),
|
||||
getBranchesAPIError: errors.New("Remote Azure Devops GetBranches error"),
|
||||
allBranches: true,
|
||||
},
|
||||
{
|
||||
@@ -384,7 +384,7 @@ func TestAzureDevopsGetBranches(t *testing.T) {
|
||||
clientFactoryMock := &AzureClientFactoryMock{mock: &mock.Mock{}}
|
||||
clientFactoryMock.mock.On("GetClient", mock.Anything).Return(&gitClientMock, testCase.clientError)
|
||||
|
||||
gitClientMock.On("GetBranches", ctx, azureGit.GetBranchesArgs{RepositoryId: &repoName, Project: &teamProject}).Return(testCase.expectedBranches, testCase.getBranchesApiError)
|
||||
gitClientMock.On("GetBranches", ctx, azureGit.GetBranchesArgs{RepositoryId: &repoName, Project: &teamProject}).Return(testCase.expectedBranches, testCase.getBranchesAPIError)
|
||||
|
||||
repo := &Repository{Organization: organization, Repository: repoName, RepositoryId: uuid}
|
||||
|
||||
@@ -403,9 +403,9 @@ func TestAzureDevopsGetBranches(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
if testCase.getBranchesApiError != nil {
|
||||
if testCase.getBranchesAPIError != nil {
|
||||
assert.Empty(t, branches)
|
||||
require.ErrorContains(t, err, testCase.getBranchesApiError.Error())
|
||||
require.ErrorContains(t, err, testCase.getBranchesAPIError.Error())
|
||||
} else {
|
||||
if len(*testCase.expectedBranches) > 0 {
|
||||
assert.NotEmpty(t, branches)
|
||||
@@ -427,7 +427,7 @@ func TestGetAzureDevopsRepositories(t *testing.T) {
|
||||
teamProject := "myorg_project"
|
||||
|
||||
uuid := uuid.New()
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
|
||||
repoId := &uuid
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ func (g *BitBucketCloudProvider) ListRepos(_ context.Context, cloneProtocol stri
|
||||
return nil, fmt.Errorf("error listing repositories for %s: %w", g.owner, err)
|
||||
}
|
||||
for _, bitBucketRepo := range accountReposResp.Items {
|
||||
cloneUrl, err := findCloneURL(cloneProtocol, &bitBucketRepo)
|
||||
cloneURL, err := findCloneURL(cloneProtocol, &bitBucketRepo)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error fetching clone url for repo %s: %w", bitBucketRepo.Slug, err)
|
||||
}
|
||||
@@ -109,7 +109,7 @@ func (g *BitBucketCloudProvider) ListRepos(_ context.Context, cloneProtocol stri
|
||||
Organization: g.owner,
|
||||
Repository: bitBucketRepo.Slug,
|
||||
Branch: bitBucketRepo.Mainbranch.Name,
|
||||
URL: *cloneUrl,
|
||||
URL: *cloneURL,
|
||||
Labels: []string{},
|
||||
RepositoryId: bitBucketRepo.Uuid,
|
||||
})
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package scm_provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@@ -94,7 +93,7 @@ func TestBitbucketHasRepo(t *testing.T) {
|
||||
SHA: c.sha,
|
||||
Branch: "main",
|
||||
}
|
||||
hasPath, err := provider.RepoHasPath(context.Background(), repo, c.path)
|
||||
hasPath, err := provider.RepoHasPath(t.Context(), repo, c.path)
|
||||
if err != nil {
|
||||
require.Error(t, fmt.Errorf("Error in test %w", err))
|
||||
}
|
||||
@@ -488,7 +487,7 @@ func TestBitbucketListRepos(t *testing.T) {
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
provider, _ := NewBitBucketCloudProvider(c.owner, "user", "password", c.allBranches)
|
||||
rawRepos, err := ListRepos(context.Background(), provider, c.filters, c.proto)
|
||||
rawRepos, err := ListRepos(t.Context(), provider, c.filters, c.proto)
|
||||
if c.hasError {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package scm_provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"io"
|
||||
@@ -103,9 +102,9 @@ func TestListReposNoAuth(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true, "", false, nil)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", true, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.ListRepos(context.Background(), "ssh")
|
||||
repos, err := provider.ListRepos(t.Context(), "ssh")
|
||||
verifyDefaultRepo(t, err, repos)
|
||||
}
|
||||
|
||||
@@ -195,9 +194,9 @@ func TestListReposPagination(t *testing.T) {
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true, "", false, nil)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", true, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.ListRepos(context.Background(), "ssh")
|
||||
repos, err := provider.ListRepos(t.Context(), "ssh")
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, repos, 2)
|
||||
assert.Equal(t, Repository{
|
||||
@@ -272,9 +271,9 @@ func TestGetBranchesBranchPagination(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true, "", false, nil)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", true, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.GetBranches(context.Background(), &Repository{
|
||||
repos, err := provider.GetBranches(t.Context(), &Repository{
|
||||
Organization: "PROJECT",
|
||||
Repository: "REPO",
|
||||
URL: "ssh://git@mycompany.bitbucket.org/PROJECT/REPO.git",
|
||||
@@ -324,9 +323,9 @@ func TestGetBranchesDefaultOnly(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.GetBranches(context.Background(), &Repository{
|
||||
repos, err := provider.GetBranches(t.Context(), &Repository{
|
||||
Organization: "PROJECT",
|
||||
Repository: "REPO",
|
||||
URL: "ssh://git@mycompany.bitbucket.org/PROJECT/REPO.git",
|
||||
@@ -355,9 +354,9 @@ func TestGetBranchesMissingDefault(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.GetBranches(context.Background(), &Repository{
|
||||
repos, err := provider.GetBranches(t.Context(), &Repository{
|
||||
Organization: "PROJECT",
|
||||
Repository: "REPO",
|
||||
URL: "ssh://git@mycompany.bitbucket.org/PROJECT/REPO.git",
|
||||
@@ -376,9 +375,9 @@ func TestGetBranchesEmptyRepo(t *testing.T) {
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.GetBranches(context.Background(), &Repository{
|
||||
repos, err := provider.GetBranches(t.Context(), &Repository{
|
||||
Organization: "PROJECT",
|
||||
Repository: "REPO",
|
||||
URL: "ssh://git@mycompany.bitbucket.org/PROJECT/REPO.git",
|
||||
@@ -398,9 +397,9 @@ func TestGetBranchesErrorDefaultBranch(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
_, err = provider.GetBranches(context.Background(), &Repository{
|
||||
_, err = provider.GetBranches(t.Context(), &Repository{
|
||||
Organization: "PROJECT",
|
||||
Repository: "REPO",
|
||||
URL: "ssh://git@mycompany.bitbucket.org/PROJECT/REPO.git",
|
||||
@@ -465,9 +464,9 @@ func TestListReposTLS(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
provider, err := NewBitbucketServerProviderBasicAuth(context.Background(), "user", "password", ts.URL, "PROJECT", true, "", test.tlsInsecure, certs)
|
||||
provider, err := NewBitbucketServerProviderBasicAuth(t.Context(), "user", "password", ts.URL, "PROJECT", true, "", test.tlsInsecure, certs)
|
||||
require.NoError(t, err)
|
||||
_, err = provider.ListRepos(context.Background(), "ssh")
|
||||
_, err = provider.ListRepos(t.Context(), "ssh")
|
||||
if test.requireErr {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
@@ -484,9 +483,9 @@ func TestListReposBasicAuth(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderBasicAuth(context.Background(), "user", "password", ts.URL, "PROJECT", true, "", false, nil)
|
||||
provider, err := NewBitbucketServerProviderBasicAuth(t.Context(), "user", "password", ts.URL, "PROJECT", true, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.ListRepos(context.Background(), "ssh")
|
||||
repos, err := provider.ListRepos(t.Context(), "ssh")
|
||||
verifyDefaultRepo(t, err, repos)
|
||||
}
|
||||
|
||||
@@ -497,9 +496,9 @@ func TestListReposBearerAuth(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderBearerToken(context.Background(), "tolkien", ts.URL, "PROJECT", true, "", false, nil)
|
||||
provider, err := NewBitbucketServerProviderBearerToken(t.Context(), "tolkien", ts.URL, "PROJECT", true, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.ListRepos(context.Background(), "ssh")
|
||||
repos, err := provider.ListRepos(t.Context(), "ssh")
|
||||
verifyDefaultRepo(t, err, repos)
|
||||
}
|
||||
|
||||
@@ -523,9 +522,9 @@ func TestListReposDefaultBranch(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.ListRepos(context.Background(), "ssh")
|
||||
repos, err := provider.ListRepos(t.Context(), "ssh")
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, repos, 1)
|
||||
assert.Equal(t, Repository{
|
||||
@@ -548,9 +547,9 @@ func TestListReposMissingDefaultBranch(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.ListRepos(context.Background(), "ssh")
|
||||
repos, err := provider.ListRepos(t.Context(), "ssh")
|
||||
require.NoError(t, err)
|
||||
assert.Empty(t, repos)
|
||||
}
|
||||
@@ -564,9 +563,9 @@ func TestListReposErrorDefaultBranch(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
_, err = provider.ListRepos(context.Background(), "ssh")
|
||||
_, err = provider.ListRepos(t.Context(), "ssh")
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
@@ -576,9 +575,9 @@ func TestListReposCloneProtocol(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true, "", false, nil)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", true, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.ListRepos(context.Background(), "https")
|
||||
repos, err := provider.ListRepos(t.Context(), "https")
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, repos, 1)
|
||||
assert.Equal(t, Repository{
|
||||
@@ -598,9 +597,9 @@ func TestListReposUnknownProtocol(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true, "", false, nil)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", true, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
_, errProtocol := provider.ListRepos(context.Background(), "http")
|
||||
_, errProtocol := provider.ListRepos(t.Context(), "http")
|
||||
require.Error(t, errProtocol)
|
||||
}
|
||||
|
||||
@@ -636,37 +635,37 @@ func TestBitbucketServerHasPath(t *testing.T) {
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true, "", false, nil)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", true, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repo := &Repository{
|
||||
Organization: "PROJECT",
|
||||
Repository: "REPO",
|
||||
Branch: "main",
|
||||
}
|
||||
ok, err := provider.RepoHasPath(context.Background(), repo, "pkg")
|
||||
ok, err := provider.RepoHasPath(t.Context(), repo, "pkg")
|
||||
require.NoError(t, err)
|
||||
assert.True(t, ok)
|
||||
|
||||
ok, err = provider.RepoHasPath(context.Background(), repo, "pkg/")
|
||||
ok, err = provider.RepoHasPath(t.Context(), repo, "pkg/")
|
||||
require.NoError(t, err)
|
||||
assert.True(t, ok)
|
||||
|
||||
ok, err = provider.RepoHasPath(context.Background(), repo, "anotherpkg/file.txt")
|
||||
ok, err = provider.RepoHasPath(t.Context(), repo, "anotherpkg/file.txt")
|
||||
require.NoError(t, err)
|
||||
assert.True(t, ok)
|
||||
|
||||
ok, err = provider.RepoHasPath(context.Background(), repo, "anotherpkg/missing.txt")
|
||||
ok, err = provider.RepoHasPath(t.Context(), repo, "anotherpkg/missing.txt")
|
||||
require.NoError(t, err)
|
||||
assert.False(t, ok)
|
||||
|
||||
ok, err = provider.RepoHasPath(context.Background(), repo, "notathing")
|
||||
ok, err = provider.RepoHasPath(t.Context(), repo, "notathing")
|
||||
require.NoError(t, err)
|
||||
assert.False(t, ok)
|
||||
|
||||
ok, err = provider.RepoHasPath(context.Background(), repo, "return-redirect")
|
||||
ok, err = provider.RepoHasPath(t.Context(), repo, "return-redirect")
|
||||
require.NoError(t, err)
|
||||
assert.True(t, ok)
|
||||
|
||||
_, err = provider.RepoHasPath(context.Background(), repo, "unauthorized-response")
|
||||
_, err = provider.RepoHasPath(t.Context(), repo, "unauthorized-response")
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package scm_provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@@ -305,7 +304,7 @@ func TestGiteaListRepos(t *testing.T) {
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
provider, _ := NewGiteaProvider("test-argocd", "", ts.URL, c.allBranches, false)
|
||||
rawRepos, err := ListRepos(context.Background(), provider, c.filters, c.proto)
|
||||
rawRepos, err := ListRepos(t.Context(), provider, c.filters, c.proto)
|
||||
if c.hasError {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
@@ -342,19 +341,19 @@ func TestGiteaHasPath(t *testing.T) {
|
||||
}
|
||||
|
||||
t.Run("file exists", func(t *testing.T) {
|
||||
ok, err := host.RepoHasPath(context.Background(), repo, "README.md")
|
||||
ok, err := host.RepoHasPath(t.Context(), repo, "README.md")
|
||||
require.NoError(t, err)
|
||||
assert.True(t, ok)
|
||||
})
|
||||
|
||||
t.Run("directory exists", func(t *testing.T) {
|
||||
ok, err := host.RepoHasPath(context.Background(), repo, "gitea")
|
||||
ok, err := host.RepoHasPath(t.Context(), repo, "gitea")
|
||||
require.NoError(t, err)
|
||||
assert.True(t, ok)
|
||||
})
|
||||
|
||||
t.Run("does not exists", func(t *testing.T) {
|
||||
ok, err := host.RepoHasPath(context.Background(), repo, "notathing")
|
||||
ok, err := host.RepoHasPath(t.Context(), repo, "notathing")
|
||||
require.NoError(t, err)
|
||||
assert.False(t, ok)
|
||||
})
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package scm_provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@@ -244,7 +243,7 @@ func TestGithubListRepos(t *testing.T) {
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
provider, _ := NewGithubProvider("argoproj", "", ts.URL, c.allBranches)
|
||||
rawRepos, err := ListRepos(context.Background(), provider, c.filters, c.proto)
|
||||
rawRepos, err := ListRepos(t.Context(), provider, c.filters, c.proto)
|
||||
if c.hasError {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
@@ -279,11 +278,11 @@ func TestGithubHasPath(t *testing.T) {
|
||||
Repository: "argo-cd",
|
||||
Branch: "master",
|
||||
}
|
||||
ok, err := host.RepoHasPath(context.Background(), repo, "pkg/")
|
||||
ok, err := host.RepoHasPath(t.Context(), repo, "pkg/")
|
||||
require.NoError(t, err)
|
||||
assert.True(t, ok)
|
||||
|
||||
ok, err = host.RepoHasPath(context.Background(), repo, "notathing/")
|
||||
ok, err = host.RepoHasPath(t.Context(), repo, "notathing/")
|
||||
require.NoError(t, err)
|
||||
assert.False(t, ok)
|
||||
}
|
||||
@@ -299,7 +298,7 @@ func TestGithubGetBranches(t *testing.T) {
|
||||
Repository: "argo-cd",
|
||||
Branch: "master",
|
||||
}
|
||||
repos, err := host.GetBranches(context.Background(), repo)
|
||||
repos, err := host.GetBranches(t.Context(), repo)
|
||||
if err != nil {
|
||||
require.NoError(t, err)
|
||||
} else {
|
||||
@@ -311,12 +310,12 @@ func TestGithubGetBranches(t *testing.T) {
|
||||
Repository: "applicationset",
|
||||
Branch: "main",
|
||||
}
|
||||
_, err = host.GetBranches(context.Background(), repo2)
|
||||
_, err = host.GetBranches(t.Context(), repo2)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Get all branches
|
||||
host.allBranches = true
|
||||
repos, err = host.GetBranches(context.Background(), repo)
|
||||
repos, err = host.GetBranches(t.Context(), repo)
|
||||
if err != nil {
|
||||
require.NoError(t, err)
|
||||
} else {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package scm_provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
@@ -1152,7 +1151,7 @@ func TestGitlabListRepos(t *testing.T) {
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
provider, _ := NewGitlabProvider("test-argocd-proton", "", ts.URL, c.allBranches, c.includeSubgroups, c.includeSharedProjects, c.insecure, "", c.topic, nil)
|
||||
rawRepos, err := ListRepos(context.Background(), provider, c.filters, c.proto)
|
||||
rawRepos, err := ListRepos(t.Context(), provider, c.filters, c.proto)
|
||||
if c.hasError {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
@@ -1235,7 +1234,7 @@ func TestGitlabHasPath(t *testing.T) {
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
ok, err := host.RepoHasPath(context.Background(), repo, c.path)
|
||||
ok, err := host.RepoHasPath(t.Context(), repo, c.path)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, c.exists, ok)
|
||||
})
|
||||
@@ -1253,7 +1252,7 @@ func TestGitlabGetBranches(t *testing.T) {
|
||||
Branch: "master",
|
||||
}
|
||||
t.Run("branch exists", func(t *testing.T) {
|
||||
repos, err := host.GetBranches(context.Background(), repo)
|
||||
repos, err := host.GetBranches(t.Context(), repo)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "master", repos[0].Branch)
|
||||
})
|
||||
@@ -1263,7 +1262,7 @@ func TestGitlabGetBranches(t *testing.T) {
|
||||
Branch: "foo",
|
||||
}
|
||||
t.Run("unknown branch", func(t *testing.T) {
|
||||
_, err := host.GetBranches(context.Background(), repo2)
|
||||
_, err := host.GetBranches(t.Context(), repo2)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
@@ -1329,7 +1328,7 @@ func TestGetBranchesTLS(t *testing.T) {
|
||||
RepositoryId: 27084533,
|
||||
Branch: "master",
|
||||
}
|
||||
_, err = host.GetBranches(context.Background(), repo)
|
||||
_, err = host.GetBranches(t.Context(), repo)
|
||||
if test.requireErr {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package scm_provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
@@ -37,7 +36,7 @@ func TestFilterRepoMatch(t *testing.T) {
|
||||
RepositoryMatch: strp("n|hr"),
|
||||
},
|
||||
}
|
||||
repos, err := ListRepos(context.Background(), provider, filters, "")
|
||||
repos, err := ListRepos(t.Context(), provider, filters, "")
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, repos, 2)
|
||||
assert.Equal(t, "one", repos[0].Repository)
|
||||
@@ -66,7 +65,7 @@ func TestFilterLabelMatch(t *testing.T) {
|
||||
LabelMatch: strp("^prod-.*$"),
|
||||
},
|
||||
}
|
||||
repos, err := ListRepos(context.Background(), provider, filters, "")
|
||||
repos, err := ListRepos(t.Context(), provider, filters, "")
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, repos, 2)
|
||||
assert.Equal(t, "one", repos[0].Repository)
|
||||
@@ -92,7 +91,7 @@ func TestFilterPathExists(t *testing.T) {
|
||||
PathsExist: []string{"two"},
|
||||
},
|
||||
}
|
||||
repos, err := ListRepos(context.Background(), provider, filters, "")
|
||||
repos, err := ListRepos(t.Context(), provider, filters, "")
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, repos, 1)
|
||||
assert.Equal(t, "two", repos[0].Repository)
|
||||
@@ -117,7 +116,7 @@ func TestFilterPathDoesntExists(t *testing.T) {
|
||||
PathsDoNotExist: []string{"two"},
|
||||
},
|
||||
}
|
||||
repos, err := ListRepos(context.Background(), provider, filters, "")
|
||||
repos, err := ListRepos(t.Context(), provider, filters, "")
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, repos, 2)
|
||||
}
|
||||
@@ -135,7 +134,7 @@ func TestFilterRepoMatchBadRegexp(t *testing.T) {
|
||||
RepositoryMatch: strp("("),
|
||||
},
|
||||
}
|
||||
_, err := ListRepos(context.Background(), provider, filters, "")
|
||||
_, err := ListRepos(t.Context(), provider, filters, "")
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
@@ -152,7 +151,7 @@ func TestFilterLabelMatchBadRegexp(t *testing.T) {
|
||||
LabelMatch: strp("("),
|
||||
},
|
||||
}
|
||||
_, err := ListRepos(context.Background(), provider, filters, "")
|
||||
_, err := ListRepos(t.Context(), provider, filters, "")
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
@@ -186,7 +185,7 @@ func TestFilterBranchMatch(t *testing.T) {
|
||||
BranchMatch: strp("w"),
|
||||
},
|
||||
}
|
||||
repos, err := ListRepos(context.Background(), provider, filters, "")
|
||||
repos, err := ListRepos(t.Context(), provider, filters, "")
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, repos, 2)
|
||||
assert.Equal(t, "one", repos[0].Repository)
|
||||
@@ -218,7 +217,7 @@ func TestMultiFilterAnd(t *testing.T) {
|
||||
LabelMatch: strp("^prod-.*$"),
|
||||
},
|
||||
}
|
||||
repos, err := ListRepos(context.Background(), provider, filters, "")
|
||||
repos, err := ListRepos(t.Context(), provider, filters, "")
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, repos, 1)
|
||||
assert.Equal(t, "two", repos[0].Repository)
|
||||
@@ -249,7 +248,7 @@ func TestMultiFilterOr(t *testing.T) {
|
||||
LabelMatch: strp("^prod-.*$"),
|
||||
},
|
||||
}
|
||||
repos, err := ListRepos(context.Background(), provider, filters, "")
|
||||
repos, err := ListRepos(t.Context(), provider, filters, "")
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, repos, 3)
|
||||
assert.Equal(t, "one", repos[0].Repository)
|
||||
@@ -275,7 +274,7 @@ func TestNoFilters(t *testing.T) {
|
||||
},
|
||||
}
|
||||
filters := []argoprojiov1alpha1.SCMProviderGeneratorFilter{}
|
||||
repos, err := ListRepos(context.Background(), provider, filters, "")
|
||||
repos, err := ListRepos(t.Context(), provider, filters, "")
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, repos, 3)
|
||||
assert.Equal(t, "one", repos[0].Repository)
|
||||
|
||||
@@ -7,31 +7,17 @@ import (
|
||||
func BuildResourceStatus(statusMap map[string]argov1alpha1.ResourceStatus, apps []argov1alpha1.Application) map[string]argov1alpha1.ResourceStatus {
|
||||
appMap := map[string]argov1alpha1.Application{}
|
||||
for _, app := range apps {
|
||||
appCopy := app
|
||||
appMap[app.Name] = app
|
||||
|
||||
gvk := app.GroupVersionKind()
|
||||
// Create status if it does not exist
|
||||
status, ok := statusMap[app.Name]
|
||||
if !ok {
|
||||
status = argov1alpha1.ResourceStatus{
|
||||
Group: gvk.Group,
|
||||
Version: gvk.Version,
|
||||
Kind: gvk.Kind,
|
||||
Name: app.Name,
|
||||
Namespace: app.Namespace,
|
||||
Status: app.Status.Sync.Status,
|
||||
Health: &appCopy.Status.Health,
|
||||
}
|
||||
}
|
||||
|
||||
var status argov1alpha1.ResourceStatus
|
||||
status.Group = gvk.Group
|
||||
status.Version = gvk.Version
|
||||
status.Kind = gvk.Kind
|
||||
status.Name = app.Name
|
||||
status.Namespace = app.Namespace
|
||||
status.Status = app.Status.Sync.Status
|
||||
status.Health = &appCopy.Status.Health
|
||||
status.Health = app.Status.Health.DeepCopy()
|
||||
|
||||
statusMap[app.Name] = status
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package utils
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/common"
|
||||
appv1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
@@ -13,16 +12,14 @@ import (
|
||||
"k8s.io/client-go/kubernetes"
|
||||
)
|
||||
|
||||
var (
|
||||
localCluster = appv1.Cluster{
|
||||
Name: "in-cluster",
|
||||
Server: appv1.KubernetesInternalAPIServerAddr,
|
||||
ConnectionState: appv1.ConnectionState{Status: appv1.ConnectionStatusSuccessful},
|
||||
}
|
||||
initLocalCluster sync.Once
|
||||
)
|
||||
// ClusterSpecifier contains only the name and server URL of a cluster. We use this struct to avoid partially-populating
|
||||
// the full Cluster struct, which would be misleading.
|
||||
type ClusterSpecifier struct {
|
||||
Name string
|
||||
Server string
|
||||
}
|
||||
|
||||
func ListClusters(ctx context.Context, clientset kubernetes.Interface, namespace string) (*appv1.ClusterList, error) {
|
||||
func ListClusters(ctx context.Context, clientset kubernetes.Interface, namespace string) ([]ClusterSpecifier, error) {
|
||||
clusterSecretsList, err := clientset.CoreV1().Secrets(namespace).List(ctx,
|
||||
metav1.ListOptions{LabelSelector: common.LabelKeySecretType + "=" + common.LabelValueSecretTypeCluster})
|
||||
if err != nil {
|
||||
@@ -35,54 +32,29 @@ func ListClusters(ctx context.Context, clientset kubernetes.Interface, namespace
|
||||
|
||||
clusterSecrets := clusterSecretsList.Items
|
||||
|
||||
clusterList := appv1.ClusterList{
|
||||
Items: make([]appv1.Cluster, len(clusterSecrets)),
|
||||
}
|
||||
clusterList := make([]ClusterSpecifier, len(clusterSecrets))
|
||||
|
||||
hasInClusterCredentials := false
|
||||
for i, clusterSecret := range clusterSecrets {
|
||||
// This line has changed from the original Argo CD code: now receives an error, and handles it
|
||||
cluster, err := db.SecretToCluster(&clusterSecret)
|
||||
if err != nil || cluster == nil {
|
||||
return nil, fmt.Errorf("unable to convert cluster secret to cluster object '%s': %w", clusterSecret.Name, err)
|
||||
}
|
||||
|
||||
// db.SecretToCluster populates these, but they're not meant to be available to the caller.
|
||||
cluster.Labels = nil
|
||||
cluster.Annotations = nil
|
||||
|
||||
clusterList.Items[i] = *cluster
|
||||
clusterList[i] = ClusterSpecifier{
|
||||
Name: cluster.Name,
|
||||
Server: cluster.Server,
|
||||
}
|
||||
if cluster.Server == appv1.KubernetesInternalAPIServerAddr {
|
||||
hasInClusterCredentials = true
|
||||
}
|
||||
}
|
||||
if !hasInClusterCredentials {
|
||||
localCluster := getLocalCluster(clientset)
|
||||
if localCluster != nil {
|
||||
clusterList.Items = append(clusterList.Items, *localCluster)
|
||||
}
|
||||
// There was no secret for the in-cluster config, so we add it here. We don't fully-populate the Cluster struct,
|
||||
// since only the name and server fields are used by the generator.
|
||||
clusterList = append(clusterList, ClusterSpecifier{
|
||||
Name: "in-cluster",
|
||||
Server: appv1.KubernetesInternalAPIServerAddr,
|
||||
})
|
||||
}
|
||||
return &clusterList, nil
|
||||
}
|
||||
|
||||
func getLocalCluster(clientset kubernetes.Interface) *appv1.Cluster {
|
||||
initLocalCluster.Do(func() {
|
||||
info, err := clientset.Discovery().ServerVersion()
|
||||
if err == nil {
|
||||
//nolint:staticcheck
|
||||
localCluster.ServerVersion = fmt.Sprintf("%s.%s", info.Major, info.Minor)
|
||||
//nolint:staticcheck
|
||||
localCluster.ConnectionState = appv1.ConnectionState{Status: appv1.ConnectionStatusSuccessful}
|
||||
} else {
|
||||
//nolint:staticcheck
|
||||
localCluster.ConnectionState = appv1.ConnectionState{
|
||||
Status: appv1.ConnectionStatusFailed,
|
||||
Message: err.Error(),
|
||||
}
|
||||
}
|
||||
})
|
||||
cluster := localCluster.DeepCopy()
|
||||
now := metav1.Now()
|
||||
//nolint:staticcheck
|
||||
cluster.ConnectionState.ModifiedAt = &now
|
||||
return cluster
|
||||
return clusterList, nil
|
||||
}
|
||||
|
||||
@@ -163,12 +163,12 @@ func applyIgnoreDifferences(applicationSetIgnoreDifferences argov1alpha1.Applica
|
||||
if len(result.Lives) != 1 {
|
||||
return fmt.Errorf("expected 1 normalized application, got %d", len(result.Lives))
|
||||
}
|
||||
foundJsonNormalized, err := json.Marshal(result.Lives[0].Object)
|
||||
foundJSONNormalized, err := json.Marshal(result.Lives[0].Object)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal normalized app to json: %w", err)
|
||||
}
|
||||
foundNormalized := &argov1alpha1.Application{}
|
||||
err = json.Unmarshal(foundJsonNormalized, &foundNormalized)
|
||||
err = json.Unmarshal(foundJSONNormalized, &foundNormalized)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to unmarshal normalized app to json: %w", err)
|
||||
}
|
||||
@@ -176,12 +176,12 @@ func applyIgnoreDifferences(applicationSetIgnoreDifferences argov1alpha1.Applica
|
||||
return fmt.Errorf("expected 1 normalized application, got %d", len(result.Targets))
|
||||
}
|
||||
foundNormalized.DeepCopyInto(found)
|
||||
generatedJsonNormalized, err := json.Marshal(result.Targets[0].Object)
|
||||
generatedJSONNormalized, err := json.Marshal(result.Targets[0].Object)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal normalized app to json: %w", err)
|
||||
}
|
||||
generatedAppNormalized := &argov1alpha1.Application{}
|
||||
err = json.Unmarshal(generatedJsonNormalized, &generatedAppNormalized)
|
||||
err = json.Unmarshal(generatedJSONNormalized, &generatedAppNormalized)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to unmarshal normalized app json to structured app: %w", err)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -21,7 +20,7 @@ func TestGetSecretRef(t *testing.T) {
|
||||
},
|
||||
}
|
||||
client := fake.NewClientBuilder().WithObjects(secret).Build()
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
|
||||
cases := []struct {
|
||||
name, namespace, token string
|
||||
@@ -86,7 +85,7 @@ func TestGetConfigMapData(t *testing.T) {
|
||||
},
|
||||
}
|
||||
client := fake.NewClientBuilder().WithObjects(configMap).Build()
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
|
||||
cases := []struct {
|
||||
name, namespace, data string
|
||||
|
||||
2
applicationset/utils/mocks/Renderer.go
generated
2
applicationset/utils/mocks/Renderer.go
generated
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
// Code generated by mockery v2.52.4. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
|
||||
@@ -139,11 +139,11 @@ func (r *Render) deeplyReplace(copy, original reflect.Value, replaceMap map[stri
|
||||
} else if currentType == "Raw.k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" || currentType == "Raw.k8s.io/apimachinery/pkg/runtime" {
|
||||
var unmarshaled any
|
||||
originalBytes := original.Field(i).Bytes()
|
||||
convertedToJson, err := ConvertYAMLToJSON(string(originalBytes))
|
||||
convertedToJSON, err := ConvertYAMLToJSON(string(originalBytes))
|
||||
if err != nil {
|
||||
return fmt.Errorf("error while converting template to json %q: %w", convertedToJson, err)
|
||||
return fmt.Errorf("error while converting template to json %q: %w", convertedToJSON, err)
|
||||
}
|
||||
err = json.Unmarshal([]byte(convertedToJson), &unmarshaled)
|
||||
err = json.Unmarshal([]byte(convertedToJSON), &unmarshaled)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to unmarshal JSON field: %w", err)
|
||||
}
|
||||
@@ -489,7 +489,7 @@ func SlugifyName(args ...any) string {
|
||||
return urlSlug
|
||||
}
|
||||
|
||||
func getTlsConfigWithCACert(scmRootCAPath string, caCerts []byte) *tls.Config {
|
||||
func getTLSConfigWithCACert(scmRootCAPath string, caCerts []byte) *tls.Config {
|
||||
tlsConfig := &tls.Config{}
|
||||
|
||||
if scmRootCAPath != "" {
|
||||
@@ -518,8 +518,8 @@ func getTlsConfigWithCACert(scmRootCAPath string, caCerts []byte) *tls.Config {
|
||||
return tlsConfig
|
||||
}
|
||||
|
||||
func GetTlsConfig(scmRootCAPath string, insecure bool, caCerts []byte) *tls.Config {
|
||||
tlsConfig := getTlsConfigWithCACert(scmRootCAPath, caCerts)
|
||||
func GetTlsConfig(scmRootCAPath string, insecure bool, caCerts []byte) *tls.Config { //nolint:revive //FIXME(var-naming)
|
||||
tlsConfig := getTLSConfigWithCACert(scmRootCAPath, caCerts)
|
||||
|
||||
if insecure {
|
||||
tlsConfig.InsecureSkipVerify = true
|
||||
|
||||
@@ -1331,42 +1331,42 @@ WkBKOclmOV2xlTVuPw==
|
||||
scmRootCAPath string
|
||||
insecure bool
|
||||
caCerts []byte
|
||||
validateCertInTlsConfig bool
|
||||
validateCertInTLSConfig bool
|
||||
}{
|
||||
{
|
||||
name: "Insecure mode configured, SCM Root CA Path not set",
|
||||
scmRootCAPath: "",
|
||||
insecure: true,
|
||||
caCerts: nil,
|
||||
validateCertInTlsConfig: false,
|
||||
validateCertInTLSConfig: false,
|
||||
},
|
||||
{
|
||||
name: "SCM Root CA Path set, Insecure mode set to false",
|
||||
scmRootCAPath: rootCAPath,
|
||||
insecure: false,
|
||||
caCerts: nil,
|
||||
validateCertInTlsConfig: true,
|
||||
validateCertInTLSConfig: true,
|
||||
},
|
||||
{
|
||||
name: "SCM Root CA Path set, Insecure mode set to true",
|
||||
scmRootCAPath: rootCAPath,
|
||||
insecure: true,
|
||||
caCerts: nil,
|
||||
validateCertInTlsConfig: true,
|
||||
validateCertInTLSConfig: true,
|
||||
},
|
||||
{
|
||||
name: "Cert passed, Insecure mode set to false",
|
||||
scmRootCAPath: "",
|
||||
insecure: false,
|
||||
caCerts: []byte(certFromCM),
|
||||
validateCertInTlsConfig: true,
|
||||
validateCertInTLSConfig: true,
|
||||
},
|
||||
{
|
||||
name: "SCM Root CA Path set, cert passed, Insecure mode set to false",
|
||||
scmRootCAPath: rootCAPath,
|
||||
insecure: false,
|
||||
caCerts: []byte(certFromCM),
|
||||
validateCertInTlsConfig: true,
|
||||
validateCertInTLSConfig: true,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1384,7 +1384,7 @@ WkBKOclmOV2xlTVuPw==
|
||||
assert.True(t, ok)
|
||||
}
|
||||
assert.NotNil(t, tlsConfig)
|
||||
if testCase.validateCertInTlsConfig {
|
||||
if testCase.validateCertInTLSConfig {
|
||||
assert.True(t, tlsConfig.RootCAs.Equal(certPool))
|
||||
}
|
||||
})
|
||||
|
||||
126
applicationset/webhook/testdata/gitlab-event.json
vendored
126
applicationset/webhook/testdata/gitlab-event.json
vendored
@@ -1,65 +1,65 @@
|
||||
{
|
||||
"object_kind": "push",
|
||||
"event_name": "push",
|
||||
"before": "e5ba5f6c13b64670048daa88e4c053d60b0e115a",
|
||||
"after": "bb0748feaa336d841c251017e4e374c22d0c8a98",
|
||||
"ref": "refs/heads/master",
|
||||
"checkout_sha": "bb0748feaa336d841c251017e4e374c22d0c8a98",
|
||||
"message": null,
|
||||
"user_id": 1,
|
||||
"user_name": "name",
|
||||
"user_username": "username",
|
||||
"user_email": "",
|
||||
"user_avatar": "",
|
||||
"project_id": 1,
|
||||
"project": {
|
||||
"id": 1,
|
||||
"name": "project",
|
||||
"description": "",
|
||||
"web_url": "https://gitlab/group/name",
|
||||
"avatar_url": null,
|
||||
"git_ssh_url": "ssh://git@gitlab:2222/group/name.git",
|
||||
"git_http_url": "https://gitlab/group/name.git",
|
||||
"namespace": "group",
|
||||
"visibility_level": 1,
|
||||
"path_with_namespace": "group/name",
|
||||
"default_branch": "master",
|
||||
"ci_config_path": null,
|
||||
"homepage": "https://gitlab/group/name",
|
||||
"url": "ssh://git@gitlab:2222/group/name.git",
|
||||
"ssh_url": "ssh://git@gitlab:2222/group/name.git",
|
||||
"http_url": "https://gitlab/group/name.git"
|
||||
},
|
||||
"commits": [
|
||||
{
|
||||
"id": "bb0748feaa336d841c251017e4e374c22d0c8a98",
|
||||
"message": "Test commit message\n",
|
||||
"timestamp": "2020-01-06T03:47:55Z",
|
||||
"url": "https://gitlab/group/name/commit/bb0748feaa336d841c251017e4e374c22d0c8a98",
|
||||
"author": {
|
||||
"name": "User",
|
||||
"email": "user@example.com"
|
||||
},
|
||||
"added": [
|
||||
"file.yaml"
|
||||
],
|
||||
"modified": [
|
||||
],
|
||||
"removed": [
|
||||
|
||||
]
|
||||
}
|
||||
],
|
||||
"total_commits_count": 1,
|
||||
"push_options": {
|
||||
},
|
||||
"repository": {
|
||||
"name": "name",
|
||||
"url": "ssh://git@gitlab:2222/group/name.git",
|
||||
"description": "",
|
||||
"homepage": "https://gitlab/group/name",
|
||||
"git_http_url": "https://gitlab/group/name.git",
|
||||
"git_ssh_url": "ssh://git@gitlab:2222/group/name.git",
|
||||
"visibility_level": 10
|
||||
"object_kind": "push",
|
||||
"event_name": "push",
|
||||
"before": "e5ba5f6c13b64670048daa88e4c053d60b0e115a",
|
||||
"after": "bb0748feaa336d841c251017e4e374c22d0c8a98",
|
||||
"ref": "refs/heads/master",
|
||||
"checkout_sha": "bb0748feaa336d841c251017e4e374c22d0c8a98",
|
||||
"message": null,
|
||||
"user_id": 1,
|
||||
"user_name": "name",
|
||||
"user_username": "username",
|
||||
"user_email": "",
|
||||
"user_avatar": "",
|
||||
"project_id": 1,
|
||||
"project": {
|
||||
"id": 1,
|
||||
"name": "project",
|
||||
"description": "",
|
||||
"web_url": "https://gitlab.com/group/name",
|
||||
"avatar_url": null,
|
||||
"git_ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
|
||||
"git_http_url": "https://gitlab.com/group/name.git",
|
||||
"namespace": "group",
|
||||
"visibility_level": 1,
|
||||
"path_with_namespace": "group/name",
|
||||
"default_branch": "master",
|
||||
"ci_config_path": null,
|
||||
"homepage": "https://gitlab.com/group/name",
|
||||
"url": "ssh://git@gitlab.com:2222/group/name.git",
|
||||
"ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
|
||||
"http_url": "https://gitlab.com/group/name.git"
|
||||
},
|
||||
"commits": [
|
||||
{
|
||||
"id": "bb0748feaa336d841c251017e4e374c22d0c8a98",
|
||||
"message": "Test commit message\n",
|
||||
"timestamp": "2020-01-06T03:47:55Z",
|
||||
"url": "https://gitlab.com/group/name/commit/bb0748feaa336d841c251017e4e374c22d0c8a98",
|
||||
"author": {
|
||||
"name": "User",
|
||||
"email": "user@example.com"
|
||||
},
|
||||
"added": [
|
||||
"file.yaml"
|
||||
],
|
||||
"modified": [
|
||||
],
|
||||
"removed": [
|
||||
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"total_commits_count": 1,
|
||||
"push_options": {
|
||||
},
|
||||
"repository": {
|
||||
"name": "name",
|
||||
"url": "ssh://git@gitlab.com:2222/group/name.git",
|
||||
"description": "",
|
||||
"homepage": "https://gitlab.com/group/name",
|
||||
"git_http_url": "https://gitlab.com/group/name.git",
|
||||
"git_ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
|
||||
"visibility_level": 10
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"description": "",
|
||||
"web_url": "https://gitlab.com/group/name",
|
||||
"avatar_url": null,
|
||||
"git_ssh_url": "ssh://git@gitlab:2222/group/name.git",
|
||||
"git_ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
|
||||
"git_http_url": "https://gitlab.com/group/name.git",
|
||||
"namespace": "group",
|
||||
"visibility_level": 1,
|
||||
@@ -22,17 +22,17 @@
|
||||
"default_branch": "master",
|
||||
"ci_config_path": null,
|
||||
"homepage": "https://gitlab.com/group/name",
|
||||
"url": "ssh://git@gitlab:2222/group/name.git",
|
||||
"ssh_url": "ssh://git@gitlab:2222/group/name.git",
|
||||
"url": "ssh://git@gitlab.com:2222/group/name.git",
|
||||
"ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
|
||||
"http_url": "https://gitlab.com/group/name.git"
|
||||
},
|
||||
"repository": {
|
||||
"name": "name",
|
||||
"url": "ssh://git@gitlab:2222/group/name.git",
|
||||
"url": "ssh://git@gitlab.com:2222/group/name.git",
|
||||
"description": "",
|
||||
"homepage": "https://gitlab.com/group/name",
|
||||
"git_http_url": "https://gitlab.com/group/name.git",
|
||||
"git_ssh_url": "ssh://git@gitlab:2222/group/name.git",
|
||||
"git_ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
|
||||
"visibility_level": 10
|
||||
},
|
||||
"object_attributes": {
|
||||
@@ -60,7 +60,7 @@
|
||||
"description": "Aut reprehenderit ut est.",
|
||||
"web_url": "https://gitlab.com/group/name",
|
||||
"avatar_url": null,
|
||||
"git_ssh_url": "ssh://git@gitlab:2222/group/name.git",
|
||||
"git_ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
|
||||
"git_http_url": "https://gitlab.com/group/name.git",
|
||||
"namespace": "Awesome Space",
|
||||
"visibility_level": 20,
|
||||
@@ -68,7 +68,7 @@
|
||||
"default_branch": "master",
|
||||
"homepage": "https://gitlab.com/group/name",
|
||||
"url": "https://gitlab.com/group/name.git",
|
||||
"ssh_url": "ssh://git@gitlab:2222/group/name.git",
|
||||
"ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
|
||||
"http_url": "https://gitlab.com/group/name.git"
|
||||
},
|
||||
"target": {
|
||||
@@ -76,7 +76,7 @@
|
||||
"description": "Aut reprehenderit ut est.",
|
||||
"web_url": "https://gitlab.com/group/name",
|
||||
"avatar_url": null,
|
||||
"git_ssh_url": "ssh://git@gitlab:2222/group/name.git",
|
||||
"git_ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
|
||||
"git_http_url": "https://gitlab.com/group/name.git",
|
||||
"namespace": "Awesome Space",
|
||||
"visibility_level": 20,
|
||||
@@ -84,7 +84,7 @@
|
||||
"default_branch": "master",
|
||||
"homepage": "https://gitlab.com/group/name",
|
||||
"url": "https://gitlab.com/group/name.git",
|
||||
"ssh_url": "ssh://git@gitlab:2222/group/name.git",
|
||||
"ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
|
||||
"http_url": "https://gitlab.com/group/name.git"
|
||||
},
|
||||
"last_commit": {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"description": "",
|
||||
"web_url": "https://gitlab.com/group/name",
|
||||
"avatar_url": null,
|
||||
"git_ssh_url": "ssh://git@gitlab:2222/group/name.git",
|
||||
"git_ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
|
||||
"git_http_url": "https://gitlab.com/group/name.git",
|
||||
"namespace": "group",
|
||||
"visibility_level": 1,
|
||||
@@ -22,17 +22,17 @@
|
||||
"default_branch": "master",
|
||||
"ci_config_path": null,
|
||||
"homepage": "https://gitlab.com/group/name",
|
||||
"url": "ssh://git@gitlab:2222/group/name.git",
|
||||
"ssh_url": "ssh://git@gitlab:2222/group/name.git",
|
||||
"url": "ssh://git@gitlab.com:2222/group/name.git",
|
||||
"ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
|
||||
"http_url": "https://gitlab.com/group/name.git"
|
||||
},
|
||||
"repository": {
|
||||
"name": "name",
|
||||
"url": "ssh://git@gitlab:2222/group/name.git",
|
||||
"url": "ssh://git@gitlab.com:2222/group/name.git",
|
||||
"description": "",
|
||||
"homepage": "https://gitlab.com/group/name",
|
||||
"git_http_url": "https://gitlab.com/group/name.git",
|
||||
"git_ssh_url": "ssh://git@gitlab:2222/group/name.git",
|
||||
"git_ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
|
||||
"visibility_level": 10
|
||||
},
|
||||
"object_attributes": {
|
||||
@@ -60,7 +60,7 @@
|
||||
"description": "Aut reprehenderit ut est.",
|
||||
"web_url": "https://gitlab.com/group/name",
|
||||
"avatar_url": null,
|
||||
"git_ssh_url": "ssh://git@gitlab:2222/group/name.git",
|
||||
"git_ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
|
||||
"git_http_url": "https://gitlab.com/group/name.git",
|
||||
"namespace": "Awesome Space",
|
||||
"visibility_level": 20,
|
||||
@@ -68,7 +68,7 @@
|
||||
"default_branch": "master",
|
||||
"homepage": "https://gitlab.com/group/name",
|
||||
"url": "https://gitlab.com/group/name.git",
|
||||
"ssh_url": "ssh://git@gitlab:2222/group/name.git",
|
||||
"ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
|
||||
"http_url": "https://gitlab.com/group/name.git"
|
||||
},
|
||||
"target": {
|
||||
@@ -76,7 +76,7 @@
|
||||
"description": "Aut reprehenderit ut est.",
|
||||
"web_url": "https://gitlab.com/group/name",
|
||||
"avatar_url": null,
|
||||
"git_ssh_url": "ssh://git@gitlab:2222/group/name.git",
|
||||
"git_ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
|
||||
"git_http_url": "https://gitlab.com/group/name.git",
|
||||
"namespace": "Awesome Space",
|
||||
"visibility_level": 20,
|
||||
@@ -84,7 +84,7 @@
|
||||
"default_branch": "master",
|
||||
"homepage": "https://gitlab.com/group/name",
|
||||
"url": "https://gitlab.com/group/name.git",
|
||||
"ssh_url": "ssh://git@gitlab:2222/group/name.git",
|
||||
"ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
|
||||
"http_url": "https://gitlab.com/group/name.git"
|
||||
},
|
||||
"last_commit": {
|
||||
|
||||
@@ -217,13 +217,7 @@ func getGitGeneratorInfo(payload any) *gitGeneratorInfo {
|
||||
}
|
||||
|
||||
log.Infof("Received push event repo: %s, revision: %s, touchedHead: %v", webURL, revision, touchedHead)
|
||||
urlObj, err := url.Parse(webURL)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to parse repoURL '%s'", webURL)
|
||||
return nil
|
||||
}
|
||||
regexpStr := `(?i)(http://|https://|\w+@|ssh://(\w+@)?)` + urlObj.Hostname() + "(:[0-9]+|)[:/]" + urlObj.Path[1:] + "(\\.git)?$"
|
||||
repoRegexp, err := regexp.Compile(regexpStr)
|
||||
repoRegexp, err := webhook.GetWebURLRegex(webURL)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to compile regexp for repoURL '%s'", webURL)
|
||||
return nil
|
||||
@@ -245,13 +239,7 @@ func getPRGeneratorInfo(payload any) *prGeneratorInfo {
|
||||
}
|
||||
|
||||
apiURL := payload.Repository.URL
|
||||
urlObj, err := url.Parse(apiURL)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to parse repoURL '%s'", apiURL)
|
||||
return nil
|
||||
}
|
||||
regexpStr := `(?i)(http://|https://|\w+@|ssh://(\w+@)?)` + urlObj.Hostname() + "(:[0-9]+|)[:/]"
|
||||
apiRegexp, err := regexp.Compile(regexpStr)
|
||||
apiRegexp, err := webhook.GetAPIURLRegex(apiURL)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to compile regexp for repoURL '%s'", apiURL)
|
||||
return nil
|
||||
|
||||
@@ -2,7 +2,6 @@ package webhook
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
@@ -63,7 +62,7 @@ func TestWebhookHandler(t *testing.T) {
|
||||
headerKey: "X-GitHub-Event",
|
||||
headerValue: "push",
|
||||
payloadFile: "github-commit-event.json",
|
||||
effectedAppSets: []string{"git-github", "matrix-git-github", "merge-git-github", "matrix-scm-git-github", "matrix-nested-git-github", "merge-nested-git-github", "plugin", "matrix-pull-request-github-plugin"},
|
||||
effectedAppSets: []string{"git-github", "git-github-ssh", "git-github-alt-ssh", "matrix-git-github", "merge-git-github", "matrix-scm-git-github", "matrix-nested-git-github", "merge-nested-git-github", "plugin", "matrix-pull-request-github-plugin"},
|
||||
expectedStatusCode: http.StatusOK,
|
||||
expectedRefresh: true,
|
||||
},
|
||||
@@ -81,7 +80,7 @@ func TestWebhookHandler(t *testing.T) {
|
||||
headerKey: "X-GitHub-Event",
|
||||
headerValue: "push",
|
||||
payloadFile: "github-commit-branch-event.json",
|
||||
effectedAppSets: []string{"git-github", "plugin", "matrix-pull-request-github-plugin"},
|
||||
effectedAppSets: []string{"git-github", "git-github-ssh", "git-github-alt-ssh", "plugin", "matrix-pull-request-github-plugin"},
|
||||
expectedStatusCode: http.StatusOK,
|
||||
expectedRefresh: true,
|
||||
},
|
||||
@@ -90,7 +89,7 @@ func TestWebhookHandler(t *testing.T) {
|
||||
headerKey: "X-GitHub-Event",
|
||||
headerValue: "ping",
|
||||
payloadFile: "github-ping-event.json",
|
||||
effectedAppSets: []string{"git-github", "plugin"},
|
||||
effectedAppSets: []string{"git-github", "git-github-ssh", "git-github-alt-ssh", "plugin"},
|
||||
expectedStatusCode: http.StatusOK,
|
||||
expectedRefresh: false,
|
||||
},
|
||||
@@ -99,7 +98,7 @@ func TestWebhookHandler(t *testing.T) {
|
||||
headerKey: "X-Gitlab-Event",
|
||||
headerValue: "Push Hook",
|
||||
payloadFile: "gitlab-event.json",
|
||||
effectedAppSets: []string{"git-gitlab", "plugin", "matrix-pull-request-github-plugin"},
|
||||
effectedAppSets: []string{"git-gitlab", "git-gitlab-ssh", "git-gitlab-alt-ssh", "plugin", "matrix-pull-request-github-plugin"},
|
||||
expectedStatusCode: http.StatusOK,
|
||||
expectedRefresh: true,
|
||||
},
|
||||
@@ -108,7 +107,7 @@ func TestWebhookHandler(t *testing.T) {
|
||||
headerKey: "X-Gitlab-Event",
|
||||
headerValue: "System Hook",
|
||||
payloadFile: "gitlab-event.json",
|
||||
effectedAppSets: []string{"git-gitlab", "plugin", "matrix-pull-request-github-plugin"},
|
||||
effectedAppSets: []string{"git-gitlab", "git-gitlab-ssh", "git-gitlab-alt-ssh", "plugin", "matrix-pull-request-github-plugin"},
|
||||
expectedStatusCode: http.StatusOK,
|
||||
expectedRefresh: true,
|
||||
},
|
||||
@@ -117,7 +116,7 @@ func TestWebhookHandler(t *testing.T) {
|
||||
headerKey: "X-Random-Event",
|
||||
headerValue: "Push Hook",
|
||||
payloadFile: "gitlab-event.json",
|
||||
effectedAppSets: []string{"git-gitlab", "plugin"},
|
||||
effectedAppSets: []string{"git-gitlab", "git-gitlab-ssh", "git-gitlab-alt-ssh", "plugin"},
|
||||
expectedStatusCode: http.StatusBadRequest,
|
||||
expectedRefresh: false,
|
||||
},
|
||||
@@ -126,7 +125,7 @@ func TestWebhookHandler(t *testing.T) {
|
||||
headerKey: "X-Random-Event",
|
||||
headerValue: "Push Hook",
|
||||
payloadFile: "invalid-event.json",
|
||||
effectedAppSets: []string{"git-gitlab", "plugin"},
|
||||
effectedAppSets: []string{"git-gitlab", "git-gitlab-ssh", "git-gitlab-alt-ssh", "plugin"},
|
||||
expectedStatusCode: http.StatusBadRequest,
|
||||
expectedRefresh: false,
|
||||
},
|
||||
@@ -209,7 +208,11 @@ func TestWebhookHandler(t *testing.T) {
|
||||
fc := fake.NewClientBuilder().WithScheme(scheme).WithObjects(
|
||||
fakeAppWithGitGenerator("git-github", namespace, "https://github.com/org/repo"),
|
||||
fakeAppWithGitGenerator("git-github-copy", namespace, "https://github.com/org/repo-copy"),
|
||||
fakeAppWithGitGenerator("git-gitlab", namespace, "https://gitlab/group/name"),
|
||||
fakeAppWithGitGenerator("git-github-ssh", namespace, "ssh://git@github.com/org/repo"),
|
||||
fakeAppWithGitGenerator("git-github-alt-ssh", namespace, "ssh://git@ssh.github.com:443/org/repo"),
|
||||
fakeAppWithGitGenerator("git-gitlab", namespace, "https://gitlab.com/group/name"),
|
||||
fakeAppWithGitGenerator("git-gitlab-ssh", namespace, "ssh://git@gitlab.com/group/name"),
|
||||
fakeAppWithGitGenerator("git-gitlab-alt-ssh", namespace, "ssh://git@altssh.gitlab.com:443/group/name"),
|
||||
fakeAppWithGitGenerator("git-azure-devops", namespace, "https://dev.azure.com/fabrikam-fiber-inc/DefaultCollection/_git/Fabrikam-Fiber-Git"),
|
||||
fakeAppWithGitGeneratorWithRevision("github-shorthand", namespace, "https://github.com/org/repo", "env/dev"),
|
||||
fakeAppWithGithubPullRequestGenerator("pull-request-github", namespace, "CodErTOcat", "Hello-World"),
|
||||
@@ -226,7 +229,7 @@ func TestWebhookHandler(t *testing.T) {
|
||||
fakeAppWithMergeAndPullRequestGenerator("merge-pull-request-github", namespace, "Codertocat", "Hello-World"),
|
||||
fakeAppWithMergeAndNestedGitGenerator("merge-nested-git-github", namespace, "https://github.com/org/repo"),
|
||||
).Build()
|
||||
set := argosettings.NewSettingsManager(context.TODO(), fakeClient, namespace)
|
||||
set := argosettings.NewSettingsManager(t.Context(), fakeClient, namespace)
|
||||
h, err := NewWebhookHandler(namespace, webhookParallelism, set, fc, mockGenerators())
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -243,7 +246,7 @@ func TestWebhookHandler(t *testing.T) {
|
||||
assert.Equal(t, test.expectedStatusCode, w.Code)
|
||||
|
||||
list := &v1alpha1.ApplicationSetList{}
|
||||
err = fc.List(context.TODO(), list)
|
||||
err = fc.List(t.Context(), list)
|
||||
require.NoError(t, err)
|
||||
effectedAppSetsAsExpected := make(map[string]bool)
|
||||
for _, appSetName := range test.effectedAppSets {
|
||||
|
||||
156
assets/swagger.json
generated
156
assets/swagger.json
generated
@@ -920,6 +920,11 @@
|
||||
"type": "string",
|
||||
"name": "project",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"name": "matchCase",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -1153,6 +1158,11 @@
|
||||
"type": "string",
|
||||
"name": "project",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"name": "matchCase",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -3777,6 +3787,12 @@
|
||||
"description": "Whether to use azure workload identity for authentication.",
|
||||
"name": "useAzureWorkloadIdentity",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "BearerToken contains the bearer token used for Git auth at the repo server.",
|
||||
"name": "bearerToken",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -4609,6 +4625,12 @@
|
||||
"description": "Whether to use azure workload identity for authentication.",
|
||||
"name": "useAzureWorkloadIdentity",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "BearerToken contains the bearer token used for Git auth at the repo server.",
|
||||
"name": "bearerToken",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -5079,41 +5101,51 @@
|
||||
}
|
||||
},
|
||||
"applicationv1alpha1ResourceStatus": {
|
||||
"description": "ResourceStatus holds the current synchronization and health status of a Kubernetes resource.",
|
||||
"type": "object",
|
||||
"title": "ResourceStatus holds the current sync and health status of a resource\nTODO: describe members of this type",
|
||||
"properties": {
|
||||
"group": {
|
||||
"description": "Group represents the API group of the resource (e.g., \"apps\" for Deployments).",
|
||||
"type": "string"
|
||||
},
|
||||
"health": {
|
||||
"$ref": "#/definitions/v1alpha1HealthStatus"
|
||||
},
|
||||
"hook": {
|
||||
"description": "Hook is true if the resource is used as a lifecycle hook in an Argo CD application.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"kind": {
|
||||
"description": "Kind specifies the type of the resource (e.g., \"Deployment\", \"Service\").",
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"description": "Name is the unique name of the resource within the namespace.",
|
||||
"type": "string"
|
||||
},
|
||||
"namespace": {
|
||||
"description": "Namespace defines the Kubernetes namespace where the resource is located.",
|
||||
"type": "string"
|
||||
},
|
||||
"requiresDeletionConfirmation": {
|
||||
"description": "RequiresDeletionConfirmation is true if the resource requires explicit user confirmation before deletion.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"requiresPruning": {
|
||||
"description": "RequiresPruning is true if the resource needs to be pruned (deleted) as part of synchronization.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"status": {
|
||||
"description": "Status represents the synchronization state of the resource (e.g., Synced, OutOfSync).",
|
||||
"type": "string"
|
||||
},
|
||||
"syncWave": {
|
||||
"description": "SyncWave determines the order in which resources are applied during a sync operation.\nLower values are applied first.",
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"version": {
|
||||
"description": "Version indicates the API version of the resource (e.g., \"v1\", \"v1beta1\").",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
@@ -6407,6 +6439,7 @@
|
||||
},
|
||||
"v1PortStatus": {
|
||||
"type": "object",
|
||||
"title": "PortStatus represents the error condition of a service port",
|
||||
"properties": {
|
||||
"error": {
|
||||
"type": "string",
|
||||
@@ -6916,8 +6949,8 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"applyNestedSelectors": {
|
||||
"type": "boolean",
|
||||
"title": "ApplyNestedSelectors enables selectors defined within the generators of two level-nested matrix or merge generators"
|
||||
"description": "ApplyNestedSelectors enables selectors defined within the generators of two level-nested matrix or merge generators\nDeprecated: This field is ignored, and the behavior is always enabled. The field will be removed in a future\nversion of the ApplicationSet CRD.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"generators": {
|
||||
"type": "array",
|
||||
@@ -7275,6 +7308,10 @@
|
||||
"type": "boolean",
|
||||
"title": "ForceCommonLabels specifies whether to force applying common labels to resources for Kustomize apps"
|
||||
},
|
||||
"ignoreMissingComponents": {
|
||||
"type": "boolean",
|
||||
"title": "IgnoreMissingComponents prevents kustomize from failing when components do not exist locally by not appending them to kustomization file"
|
||||
},
|
||||
"images": {
|
||||
"type": "array",
|
||||
"title": "Images is a list of Kustomize image override specifications",
|
||||
@@ -7286,6 +7323,10 @@
|
||||
"description": "KubeVersion specifies the Kubernetes API version to pass to Helm when templating manifests. By default, Argo CD\nuses the Kubernetes version of the target cluster.",
|
||||
"type": "string"
|
||||
},
|
||||
"labelIncludeTemplates": {
|
||||
"type": "boolean",
|
||||
"title": "LabelIncludeTemplates specifies whether to apply common labels to resource templates or not"
|
||||
},
|
||||
"labelWithoutSelector": {
|
||||
"type": "boolean",
|
||||
"title": "LabelWithoutSelector specifies whether to apply common labels to resource selectors or not"
|
||||
@@ -7506,34 +7547,34 @@
|
||||
}
|
||||
},
|
||||
"v1alpha1ApplicationTree": {
|
||||
"description": "ApplicationTree represents the hierarchical structure of resources associated with an Argo CD application.",
|
||||
"type": "object",
|
||||
"title": "ApplicationTree holds nodes which belongs to the application\nTODO: describe purpose of this type",
|
||||
"properties": {
|
||||
"hosts": {
|
||||
"description": "Hosts provides a list of Kubernetes nodes that are running pods related to the application.",
|
||||
"type": "array",
|
||||
"title": "Hosts holds list of Kubernetes nodes that run application related pods",
|
||||
"items": {
|
||||
"$ref": "#/definitions/v1alpha1HostInfo"
|
||||
}
|
||||
},
|
||||
"nodes": {
|
||||
"description": "Nodes contains list of nodes which either directly managed by the application and children of directly managed nodes.",
|
||||
"description": "Nodes contains a list of resources that are either directly managed by the application\nor are children of directly managed resources.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/v1alpha1ResourceNode"
|
||||
}
|
||||
},
|
||||
"orphanedNodes": {
|
||||
"description": "OrphanedNodes contains if or orphaned nodes: nodes which are not managed by the app but in the same namespace. List is populated only if orphaned resources enabled in app project.",
|
||||
"description": "OrphanedNodes contains resources that exist in the same namespace as the application\nbut are not managed by it. This list is populated only if orphaned resource tracking\nis enabled in the application's project settings.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/v1alpha1ResourceNode"
|
||||
}
|
||||
},
|
||||
"shardsCount": {
|
||||
"description": "ShardsCount represents the total number of shards the application tree is split into.\nThis is used to distribute resource processing across multiple shards.",
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"title": "ShardsCount contains total number of shards the application tree is split into"
|
||||
"format": "int64"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -8127,13 +8168,15 @@
|
||||
}
|
||||
},
|
||||
"v1alpha1HostInfo": {
|
||||
"description": "HostInfo holds metadata and resource usage metrics for a specific host in the cluster.",
|
||||
"type": "object",
|
||||
"title": "HostInfo holds host name and resources metrics\nTODO: describe purpose of this type\nTODO: describe members of this type",
|
||||
"properties": {
|
||||
"name": {
|
||||
"description": "Name is the hostname or node name in the Kubernetes cluster.",
|
||||
"type": "string"
|
||||
},
|
||||
"resourcesInfo": {
|
||||
"description": "ResourcesInfo provides a list of resource usage details for different resource types on this host.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/v1alpha1HostResourceInfo"
|
||||
@@ -8145,22 +8188,26 @@
|
||||
}
|
||||
},
|
||||
"v1alpha1HostResourceInfo": {
|
||||
"description": "HostResourceInfo represents resource usage details for a specific resource type on a host.",
|
||||
"type": "object",
|
||||
"title": "TODO: describe this type",
|
||||
"properties": {
|
||||
"capacity": {
|
||||
"description": "Capacity represents the total available capacity of this resource on the host.",
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"requestedByApp": {
|
||||
"description": "RequestedByApp indicates the total amount of this resource requested by the application running on the host.",
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"requestedByNeighbors": {
|
||||
"description": "RequestedByNeighbors indicates the total amount of this resource requested by other workloads on the same host.",
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"resourceName": {
|
||||
"description": "ResourceName specifies the type of resource (e.g., CPU, memory, storage).",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
@@ -8276,13 +8323,15 @@
|
||||
}
|
||||
},
|
||||
"v1alpha1KnownTypeField": {
|
||||
"description": "KnownTypeField contains a mapping between a Custom Resource Definition (CRD) field\nand a well-known Kubernetes type. This mapping is primarily used for unit conversions\nin resources where the type is not explicitly defined (e.g., converting \"0.1\" to \"100m\" for CPU requests).",
|
||||
"type": "object",
|
||||
"title": "KnownTypeField contains mapping between CRD field and known Kubernetes type.\nThis is mainly used for unit conversion in unknown resources (e.g. 0.1 == 100mi)\nTODO: Describe the members of this type",
|
||||
"properties": {
|
||||
"field": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"title": "Field represents the JSON path to the specific field in the CRD that requires type conversion.\nExample: \"spec.resources.requests.cpu\""
|
||||
},
|
||||
"type": {
|
||||
"description": "Type specifies the expected Kubernetes type for the field, such as \"cpu\" or \"memory\".\nThis helps in converting values between different formats (e.g., \"0.1\" to \"100m\" for CPU).",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
@@ -8692,6 +8741,13 @@
|
||||
},
|
||||
"template": {
|
||||
"$ref": "#/definitions/v1alpha1ApplicationSetTemplate"
|
||||
},
|
||||
"values": {
|
||||
"type": "object",
|
||||
"title": "Values contains key/value pairs which are passed directly as parameters to the template",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -8890,6 +8946,10 @@
|
||||
"type": "object",
|
||||
"title": "RepoCreds holds the definition for repository credentials",
|
||||
"properties": {
|
||||
"bearerToken": {
|
||||
"type": "string",
|
||||
"title": "BearerToken contains the bearer token used for Git BitBucket Data Center auth at the repo server"
|
||||
},
|
||||
"enableOCI": {
|
||||
"type": "boolean",
|
||||
"title": "EnableOCI specifies whether helm-oci support should be enabled for this repo"
|
||||
@@ -8981,6 +9041,10 @@
|
||||
"type": "object",
|
||||
"title": "Repository is a repository holding application configurations",
|
||||
"properties": {
|
||||
"bearerToken": {
|
||||
"type": "string",
|
||||
"title": "BearerToken contains the bearer token used for Git BitBucket Data Center auth at the repo server"
|
||||
},
|
||||
"connectionState": {
|
||||
"$ref": "#/definitions/v1alpha1ConnectionState"
|
||||
},
|
||||
@@ -9139,22 +9203,27 @@
|
||||
}
|
||||
},
|
||||
"v1alpha1ResourceAction": {
|
||||
"description": "ResourceAction represents an individual action that can be performed on a resource.\nIt includes parameters, an optional disabled flag, an icon for display, and a name for the action.",
|
||||
"type": "object",
|
||||
"title": "TODO: describe this type\nTODO: describe members of this type",
|
||||
"properties": {
|
||||
"disabled": {
|
||||
"description": "Disabled indicates whether the action is disabled.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"displayName": {
|
||||
"description": "DisplayName provides a user-friendly name for the action.",
|
||||
"type": "string"
|
||||
},
|
||||
"iconClass": {
|
||||
"description": "IconClass specifies the CSS class for the action's icon.",
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"description": "Name is the name or identifier for the action.",
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"description": "Params contains the parameters required to execute the action.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/v1alpha1ResourceActionParam"
|
||||
@@ -9163,67 +9232,78 @@
|
||||
}
|
||||
},
|
||||
"v1alpha1ResourceActionParam": {
|
||||
"description": "ResourceActionParam represents a parameter for a resource action.\nIt includes a name, value, type, and an optional default value for the parameter.",
|
||||
"type": "object",
|
||||
"title": "TODO: describe this type\nTODO: describe members of this type",
|
||||
"properties": {
|
||||
"default": {
|
||||
"description": "Default is the default value of the parameter, if any.",
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"description": "Name is the name of the parameter.",
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"description": "Type is the type of the parameter (e.g., string, integer).",
|
||||
"type": "string"
|
||||
},
|
||||
"value": {
|
||||
"description": "Value is the value of the parameter.",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1alpha1ResourceDiff": {
|
||||
"description": "ResourceDiff holds the diff between a live and target resource object in Argo CD.\nIt is used to compare the desired state (from Git/Helm) with the actual state in the cluster.",
|
||||
"type": "object",
|
||||
"title": "ResourceDiff holds the diff of a live and target resource object\nTODO: describe members of this type",
|
||||
"properties": {
|
||||
"diff": {
|
||||
"type": "string",
|
||||
"title": "Diff contains the JSON patch between target and live resource\nDeprecated: use NormalizedLiveState and PredictedLiveState to render the difference"
|
||||
"description": "Diff contains the JSON patch representing the difference between the live and target resource.\nDeprecated: Use NormalizedLiveState and PredictedLiveState instead to compute differences.",
|
||||
"type": "string"
|
||||
},
|
||||
"group": {
|
||||
"description": "Group represents the API group of the resource (e.g., \"apps\" for Deployments).",
|
||||
"type": "string"
|
||||
},
|
||||
"hook": {
|
||||
"description": "Hook indicates whether this resource is a hook resource (e.g., pre-sync or post-sync hooks).",
|
||||
"type": "boolean"
|
||||
},
|
||||
"kind": {
|
||||
"description": "Kind represents the Kubernetes resource kind (e.g., \"Deployment\", \"Service\").",
|
||||
"type": "string"
|
||||
},
|
||||
"liveState": {
|
||||
"type": "string",
|
||||
"title": "TargetState contains the JSON live resource manifest"
|
||||
"description": "LiveState contains the JSON-serialized resource manifest of the resource currently running in the cluster.",
|
||||
"type": "string"
|
||||
},
|
||||
"modified": {
|
||||
"description": "Modified indicates whether the live resource has changes compared to the target resource.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"name": {
|
||||
"description": "Name is the name of the resource.",
|
||||
"type": "string"
|
||||
},
|
||||
"namespace": {
|
||||
"description": "Namespace specifies the namespace where the resource exists.",
|
||||
"type": "string"
|
||||
},
|
||||
"normalizedLiveState": {
|
||||
"type": "string",
|
||||
"title": "NormalizedLiveState contains JSON serialized live resource state with applied normalizations"
|
||||
"description": "NormalizedLiveState contains the JSON-serialized live resource state after applying normalizations.\nNormalizations may include ignoring irrelevant fields like timestamps or defaults applied by Kubernetes.",
|
||||
"type": "string"
|
||||
},
|
||||
"predictedLiveState": {
|
||||
"type": "string",
|
||||
"title": "PredictedLiveState contains JSON serialized resource state that is calculated based on normalized and target resource state"
|
||||
"description": "PredictedLiveState contains the JSON-serialized resource state that Argo CD predicts based on the\ncombination of the normalized live state and the desired target state.",
|
||||
"type": "string"
|
||||
},
|
||||
"resourceVersion": {
|
||||
"description": "ResourceVersion is the Kubernetes resource version, which helps in tracking changes.",
|
||||
"type": "string"
|
||||
},
|
||||
"targetState": {
|
||||
"type": "string",
|
||||
"title": "TargetState contains the JSON serialized resource manifest defined in the Git/Helm"
|
||||
"description": "TargetState contains the JSON-serialized resource manifest as defined in the Git/Helm repository.",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -9265,35 +9345,39 @@
|
||||
}
|
||||
},
|
||||
"v1alpha1ResourceNetworkingInfo": {
|
||||
"description": "ResourceNetworkingInfo holds networking-related information for a resource.",
|
||||
"type": "object",
|
||||
"title": "ResourceNetworkingInfo holds networking resource related information\nTODO: describe members of this type",
|
||||
"properties": {
|
||||
"externalURLs": {
|
||||
"description": "ExternalURLs holds list of URLs which should be available externally. List is populated for ingress resources using rules hostnames.",
|
||||
"description": "ExternalURLs holds a list of URLs that should be accessible externally.\nThis field is typically populated for Ingress resources based on their hostname rules.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"ingress": {
|
||||
"description": "Ingress provides information about external access points (e.g., load balancer ingress) for this resource.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/v1LoadBalancerIngress"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"description": "Labels holds the labels associated with this networking resource.",
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"targetLabels": {
|
||||
"description": "TargetLabels represents labels associated with the target resources that this resource communicates with.",
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"targetRefs": {
|
||||
"description": "TargetRefs contains references to other resources that this resource interacts with, such as Services or Pods.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/v1alpha1ResourceRef"
|
||||
@@ -9302,8 +9386,8 @@
|
||||
}
|
||||
},
|
||||
"v1alpha1ResourceNode": {
|
||||
"description": "ResourceNode contains information about a live Kubernetes resource and its relationships with other resources.",
|
||||
"type": "object",
|
||||
"title": "ResourceNode contains information about live resource and its children\nTODO: describe members of this type",
|
||||
"properties": {
|
||||
"createdAt": {
|
||||
"$ref": "#/definitions/v1Time"
|
||||
@@ -9312,12 +9396,14 @@
|
||||
"$ref": "#/definitions/v1alpha1HealthStatus"
|
||||
},
|
||||
"images": {
|
||||
"description": "Images lists container images associated with the resource.\nThis is primarily useful for pods and other workload resources.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"info": {
|
||||
"description": "Info provides additional metadata or annotations about the resource.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/v1alpha1InfoItem"
|
||||
@@ -9327,12 +9413,14 @@
|
||||
"$ref": "#/definitions/v1alpha1ResourceNetworkingInfo"
|
||||
},
|
||||
"parentRefs": {
|
||||
"description": "ParentRefs lists the parent resources that reference this resource.\nThis helps in understanding ownership and hierarchical relationships.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/v1alpha1ResourceRef"
|
||||
}
|
||||
},
|
||||
"resourceVersion": {
|
||||
"description": "ResourceVersion indicates the version of the resource, used to track changes.",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
@@ -9344,12 +9432,14 @@
|
||||
},
|
||||
"v1alpha1ResourceOverride": {
|
||||
"type": "object",
|
||||
"title": "ResourceOverride holds configuration to customize resource diffing and health assessment\nTODO: describe the members of this type",
|
||||
"title": "ResourceOverride holds configuration to customize resource diffing and health assessment",
|
||||
"properties": {
|
||||
"actions": {
|
||||
"description": "Actions defines the set of actions that can be performed on the resource, as a Lua script.",
|
||||
"type": "string"
|
||||
},
|
||||
"healthLua": {
|
||||
"description": "HealthLua contains a Lua script that defines custom health checks for the resource.",
|
||||
"type": "string"
|
||||
},
|
||||
"ignoreDifferences": {
|
||||
@@ -9359,12 +9449,14 @@
|
||||
"$ref": "#/definitions/v1alpha1OverrideIgnoreDiff"
|
||||
},
|
||||
"knownTypeFields": {
|
||||
"description": "KnownTypeFields lists fields for which unit conversions should be applied.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/v1alpha1KnownTypeField"
|
||||
}
|
||||
},
|
||||
"useOpenLibs": {
|
||||
"description": "UseOpenLibs indicates whether to use open-source libraries for the resource.",
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
@@ -10097,6 +10189,10 @@
|
||||
"type": "object",
|
||||
"title": "SyncWindow contains the kind, time, duration and attributes that are used to assign the syncWindows to apps",
|
||||
"properties": {
|
||||
"andOperator": {
|
||||
"type": "boolean",
|
||||
"title": "UseAndOperator use AND operator for matching applications, namespaces and clusters instead of the default OR operator"
|
||||
},
|
||||
"applications": {
|
||||
"type": "array",
|
||||
"title": "Applications contains a list of applications that the window will apply to",
|
||||
|
||||
@@ -259,7 +259,7 @@ func NewCommand() *cobra.Command {
|
||||
command.Flags().StringVar(&commitServerAddress, "commit-server", env.StringFromEnv("ARGOCD_APPLICATION_CONTROLLER_COMMIT_SERVER", common.DefaultCommitServerAddr), "Commit server address.")
|
||||
command.Flags().IntVar(&statusProcessors, "status-processors", env.ParseNumFromEnv("ARGOCD_APPLICATION_CONTROLLER_STATUS_PROCESSORS", 20, 0, math.MaxInt32), "Number of application status processors")
|
||||
command.Flags().IntVar(&operationProcessors, "operation-processors", env.ParseNumFromEnv("ARGOCD_APPLICATION_CONTROLLER_OPERATION_PROCESSORS", 10, 0, math.MaxInt32), "Number of application operation processors")
|
||||
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_APPLICATION_CONTROLLER_LOGFORMAT", "text"), "Set the logging format. One of: text|json")
|
||||
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_APPLICATION_CONTROLLER_LOGFORMAT", "json"), "Set the logging format. One of: json|text")
|
||||
command.Flags().StringVar(&cmdutil.LogLevel, "loglevel", env.StringFromEnv("ARGOCD_APPLICATION_CONTROLLER_LOGLEVEL", "info"), "Set the logging level. One of: debug|info|warn|error")
|
||||
command.Flags().IntVar(&glogLevel, "gloglevel", 0, "Set the glog logging level")
|
||||
command.Flags().IntVar(&metricsPort, "metrics-port", common.DefaultPortArgoCDMetrics, "Start metrics server on given port")
|
||||
@@ -280,7 +280,7 @@ func NewCommand() *cobra.Command {
|
||||
command.Flags().StringToStringVar(&otlpHeaders, "otlp-headers", env.ParseStringToStringFromEnv("ARGOCD_APPLICATION_CONTROLLER_OTLP_HEADERS", map[string]string{}, ","), "List of OpenTelemetry collector extra headers sent with traces, headers are comma-separated key-value pairs(e.g. key1=value1,key2=value2)")
|
||||
command.Flags().StringSliceVar(&otlpAttrs, "otlp-attrs", env.StringsFromEnv("ARGOCD_APPLICATION_CONTROLLER_OTLP_ATTRS", []string{}, ","), "List of OpenTelemetry collector extra attrs when send traces, each attribute is separated by a colon(e.g. key:value)")
|
||||
command.Flags().StringSliceVar(&applicationNamespaces, "application-namespaces", env.StringsFromEnv("ARGOCD_APPLICATION_NAMESPACES", []string{}, ","), "List of additional namespaces that applications are allowed to be reconciled from")
|
||||
command.Flags().BoolVar(&persistResourceHealth, "persist-resource-health", env.ParseBoolFromEnv("ARGOCD_APPLICATION_CONTROLLER_PERSIST_RESOURCE_HEALTH", true), "Enables storing the managed resources health in the Application CRD")
|
||||
command.Flags().BoolVar(&persistResourceHealth, "persist-resource-health", env.ParseBoolFromEnv("ARGOCD_APPLICATION_CONTROLLER_PERSIST_RESOURCE_HEALTH", false), "Enables storing the managed resources health in the Application CRD")
|
||||
command.Flags().StringVar(&shardingAlgorithm, "sharding-method", env.StringFromEnv(common.EnvControllerShardingAlgorithm, common.DefaultShardingAlgorithm), "Enables choice of sharding method. Supported sharding methods are : [legacy, round-robin, consistent-hashing] ")
|
||||
// global queue rate limit config
|
||||
command.Flags().Int64Var(&workqueueRateLimit.BucketSize, "wq-bucket-size", env.ParseInt64FromEnv("WORKQUEUE_BUCKET_SIZE", 500, 1, math.MaxInt64), "Set Workqueue Rate Limiter Bucket Size, default 500")
|
||||
|
||||
@@ -188,8 +188,7 @@ func NewCommand() *cobra.Command {
|
||||
}
|
||||
|
||||
repoClientset := apiclient.NewRepoServerClientset(argocdRepoServer, repoServerTimeoutSeconds, tlsConfig)
|
||||
argoCDService, err := services.NewArgoCDService(argoCDDB.GetRepository, gitSubmoduleEnabled, repoClientset, enableNewGitFileGlobbing)
|
||||
errors.CheckError(err)
|
||||
argoCDService := services.NewArgoCDService(argoCDDB, gitSubmoduleEnabled, repoClientset, enableNewGitFileGlobbing)
|
||||
|
||||
topLevelGenerators := generators.GetGenerators(ctx, mgr.GetClient(), k8sClient, namespace, argoCDService, dynamicClient, scmConfig)
|
||||
|
||||
@@ -252,7 +251,7 @@ func NewCommand() *cobra.Command {
|
||||
command.Flags().StringVar(&policy, "policy", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_POLICY", ""), "Modify how application is synced between the generator and the cluster. Default is '' (empty), which means AppSets default to 'sync', but they may override that default. Setting an explicit value prevents AppSet-level overrides, unless --allow-policy-override is enabled. Explicit options are: 'sync' (create & update & delete), 'create-only', 'create-update' (no deletion), 'create-delete' (no update)")
|
||||
command.Flags().BoolVar(&enablePolicyOverride, "enable-policy-override", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_POLICY_OVERRIDE", policy == ""), "For security reason if 'policy' is set, it is not possible to override it at applicationSet level. 'allow-policy-override' allows user to define their own policy")
|
||||
command.Flags().BoolVar(&debugLog, "debug", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_DEBUG", false), "Print debug logs. Takes precedence over loglevel")
|
||||
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_LOGFORMAT", "text"), "Set the logging format. One of: text|json")
|
||||
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_LOGFORMAT", "json"), "Set the logging format. One of: json|text")
|
||||
command.Flags().StringVar(&cmdutil.LogLevel, "loglevel", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_LOGLEVEL", "info"), "Set the logging level. One of: debug|info|warn|error")
|
||||
command.Flags().StringSliceVar(&allowedScmProviders, "allowed-scm-providers", env.StringsFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_ALLOWED_SCM_PROVIDERS", []string{}, ","), "The list of allowed custom SCM provider API URLs. This restriction does not apply to SCM or PR generators which do not accept a custom API URL. (Default: Empty = all)")
|
||||
command.Flags().BoolVar(&enableScmProviders, "enable-scm-providers", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_SCM_PROVIDERS", true), "Enable retrieving information from SCM providers, used by the SCM and PR generators (Default: true)")
|
||||
|
||||
@@ -89,7 +89,7 @@ func NewCommand() *cobra.Command {
|
||||
},
|
||||
}
|
||||
|
||||
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_CMP_SERVER_LOGFORMAT", "text"), "Set the logging format. One of: text|json")
|
||||
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_CMP_SERVER_LOGFORMAT", "json"), "Set the logging format. One of: json|text")
|
||||
command.Flags().StringVar(&cmdutil.LogLevel, "loglevel", env.StringFromEnv("ARGOCD_CMP_SERVER_LOGLEVEL", "info"), "Set the logging level. One of: trace|debug|info|warn|error")
|
||||
command.Flags().StringVar(&configFilePath, "config-dir-path", common.DefaultPluginConfigFilePath, "Config management plugin configuration file location, Default is '/home/argocd/cmp-server/config/'")
|
||||
command.Flags().StringVar(&otlpAddress, "otlp-address", env.StringFromEnv("ARGOCD_CMP_SERVER_OTLP_ADDRESS", ""), "OpenTelemetry collector address to send traces to")
|
||||
|
||||
@@ -106,7 +106,7 @@ func NewCommand() *cobra.Command {
|
||||
return nil
|
||||
},
|
||||
}
|
||||
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_COMMIT_SERVER_LOGFORMAT", "text"), "Set the logging format. One of: text|json")
|
||||
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_COMMIT_SERVER_LOGFORMAT", "json"), "Set the logging format. One of: json|text")
|
||||
command.Flags().StringVar(&cmdutil.LogLevel, "loglevel", env.StringFromEnv("ARGOCD_COMMIT_SERVER_LOGLEVEL", "info"), "Set the logging level. One of: debug|info|warn|error")
|
||||
command.Flags().StringVar(&listenHost, "address", env.StringFromEnv("ARGOCD_COMMIT_SERVER_LISTEN_ADDRESS", common.DefaultAddressCommitServer), "Listen on given address for incoming connections")
|
||||
command.Flags().IntVar(&listenPort, "port", common.DefaultPortCommitServer, "Listen on given port for incoming connections")
|
||||
|
||||
@@ -144,7 +144,7 @@ func NewRunDexCommand() *cobra.Command {
|
||||
}
|
||||
|
||||
clientConfig = cli.AddKubectlFlagsToCmd(&command)
|
||||
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_DEX_SERVER_LOGFORMAT", "text"), "Set the logging format. One of: text|json")
|
||||
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_DEX_SERVER_LOGFORMAT", "json"), "Set the logging format. One of: json|text")
|
||||
command.Flags().StringVar(&cmdutil.LogLevel, "loglevel", env.StringFromEnv("ARGOCD_DEX_SERVER_LOGLEVEL", "info"), "Set the logging level. One of: debug|info|warn|error")
|
||||
command.Flags().BoolVar(&disableTLS, "disable-tls", env.ParseBoolFromEnv("ARGOCD_DEX_SERVER_DISABLE_TLS", false), "Disable TLS on the HTTP endpoint")
|
||||
return &command
|
||||
@@ -212,7 +212,7 @@ func NewGenDexConfigCommand() *cobra.Command {
|
||||
}
|
||||
|
||||
clientConfig = cli.AddKubectlFlagsToCmd(&command)
|
||||
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_DEX_SERVER_LOGFORMAT", "text"), "Set the logging format. One of: text|json")
|
||||
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_DEX_SERVER_LOGFORMAT", "json"), "Set the logging format. One of: json|text")
|
||||
command.Flags().StringVar(&cmdutil.LogLevel, "loglevel", env.StringFromEnv("ARGOCD_DEX_SERVER_LOGLEVEL", "info"), "Set the logging level. One of: debug|info|warn|error")
|
||||
command.Flags().StringVarP(&out, "out", "o", "", "Output to the specified file instead of stdout")
|
||||
command.Flags().BoolVar(&disableTLS, "disable-tls", env.ParseBoolFromEnv("ARGOCD_DEX_SERVER_DISABLE_TLS", false), "Disable TLS on the HTTP endpoint")
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -11,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func TestGetSignedRequestWithRetry(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
|
||||
t.Run("will return signed request on first attempt", func(t *testing.T) {
|
||||
// given
|
||||
|
||||
@@ -180,7 +180,7 @@ func NewCommand() *cobra.Command {
|
||||
command.Flags().StringVar(&appLabelSelector, "app-label-selector", "", "App label selector.")
|
||||
command.Flags().StringVar(&namespace, "namespace", "", "Namespace which controller handles. Current namespace if empty.")
|
||||
command.Flags().StringVar(&logLevel, "loglevel", env.StringFromEnv("ARGOCD_NOTIFICATIONS_CONTROLLER_LOGLEVEL", "info"), "Set the logging level. One of: debug|info|warn|error")
|
||||
command.Flags().StringVar(&logFormat, "logformat", env.StringFromEnv("ARGOCD_NOTIFICATIONS_CONTROLLER_LOGFORMAT", "text"), "Set the logging format. One of: text|json")
|
||||
command.Flags().StringVar(&logFormat, "logformat", env.StringFromEnv("ARGOCD_NOTIFICATIONS_CONTROLLER_LOGFORMAT", "json"), "Set the logging format. One of: json|text")
|
||||
command.Flags().IntVar(&metricsPort, "metrics-port", defaultMetricsPort, "Metrics port")
|
||||
command.Flags().StringVar(&argocdRepoServer, "argocd-repo-server", common.DefaultRepoServerAddr, "Argo CD repo server address")
|
||||
command.Flags().BoolVar(&argocdRepoServerPlaintext, "argocd-repo-server-plaintext", env.ParseBoolFromEnv("ARGOCD_NOTIFICATION_CONTROLLER_REPO_SERVER_PLAINTEXT", false), "Use a plaintext client (non-TLS) to connect to repository server")
|
||||
|
||||
@@ -230,7 +230,7 @@ func NewCommand() *cobra.Command {
|
||||
return nil
|
||||
},
|
||||
}
|
||||
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_REPO_SERVER_LOGFORMAT", "text"), "Set the logging format. One of: text|json")
|
||||
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_REPO_SERVER_LOGFORMAT", "json"), "Set the logging format. One of: json|text")
|
||||
command.Flags().StringVar(&cmdutil.LogLevel, "loglevel", env.StringFromEnv("ARGOCD_REPO_SERVER_LOGLEVEL", "info"), "Set the logging level. One of: debug|info|warn|error")
|
||||
command.Flags().Int64Var(¶llelismLimit, "parallelismlimit", int64(env.ParseNumFromEnv("ARGOCD_REPO_SERVER_PARALLELISM_LIMIT", 0, 0, math.MaxInt32)), "Limit on number of concurrent manifests generate requests. Any value less the 1 means no limit.")
|
||||
command.Flags().StringVar(&listenHost, "address", env.StringFromEnv("ARGOCD_REPO_SERVER_LISTEN_ADDRESS", common.DefaultAddressRepoServer), "Listen on given address for incoming connections")
|
||||
|
||||
@@ -88,6 +88,7 @@ func NewCommand() *cobra.Command {
|
||||
enableProxyExtension bool
|
||||
webhookParallelism int
|
||||
hydratorEnabled bool
|
||||
syncWithReplaceAllowed bool
|
||||
|
||||
// ApplicationSet
|
||||
enableNewGitFileGlobbing bool
|
||||
@@ -179,7 +180,7 @@ func NewCommand() *cobra.Command {
|
||||
tlsConfig.Certificates = pool
|
||||
}
|
||||
|
||||
dexTlsConfig := &dex.DexTLSConfig{
|
||||
dexTLSConfig := &dex.DexTLSConfig{
|
||||
DisableTLS: dexServerPlaintext,
|
||||
StrictValidation: dexServerStrictTLS,
|
||||
}
|
||||
@@ -191,14 +192,14 @@ func NewCommand() *cobra.Command {
|
||||
if err != nil {
|
||||
log.Fatalf("%v", err)
|
||||
}
|
||||
dexTlsConfig.RootCAs = pool
|
||||
dexTLSConfig.RootCAs = pool
|
||||
cert, err := tls.LoadX509Cert(
|
||||
env.StringFromEnv(common.EnvAppConfigPath, common.DefaultAppConfigPath) + "/dex/tls/tls.crt",
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatalf("%v", err)
|
||||
}
|
||||
dexTlsConfig.Certificate = cert.Raw
|
||||
dexTLSConfig.Certificate = cert.Raw
|
||||
}
|
||||
|
||||
repoclientset := apiclient.NewRepoServerClientset(repoServerAddress, repoServerTimeoutSeconds, tlsConfig)
|
||||
@@ -229,7 +230,7 @@ func NewCommand() *cobra.Command {
|
||||
AppClientset: appClientSet,
|
||||
RepoClientset: repoclientset,
|
||||
DexServerAddr: dexServerAddress,
|
||||
DexTLSConfig: dexTlsConfig,
|
||||
DexTLSConfig: dexTLSConfig,
|
||||
DisableAuth: disableAuth,
|
||||
ContentTypes: contentTypesList,
|
||||
EnableGZip: enableGZip,
|
||||
@@ -245,6 +246,7 @@ func NewCommand() *cobra.Command {
|
||||
WebhookParallelism: webhookParallelism,
|
||||
EnableK8sEvent: enableK8sEvent,
|
||||
HydratorEnabled: hydratorEnabled,
|
||||
SyncWithReplaceAllowed: syncWithReplaceAllowed,
|
||||
}
|
||||
|
||||
appsetOpts := server.ApplicationSetOpts{
|
||||
@@ -295,7 +297,7 @@ func NewCommand() *cobra.Command {
|
||||
command.Flags().StringVar(&staticAssetsDir, "staticassets", env.StringFromEnv("ARGOCD_SERVER_STATIC_ASSETS", "/shared/app"), "Directory path that contains additional static assets")
|
||||
command.Flags().StringVar(&baseHRef, "basehref", env.StringFromEnv("ARGOCD_SERVER_BASEHREF", "/"), "Value for base href in index.html. Used if Argo CD is running behind reverse proxy under subpath different from /")
|
||||
command.Flags().StringVar(&rootPath, "rootpath", env.StringFromEnv("ARGOCD_SERVER_ROOTPATH", ""), "Used if Argo CD is running behind reverse proxy under subpath different from /")
|
||||
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_SERVER_LOGFORMAT", "text"), "Set the logging format. One of: text|json")
|
||||
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_SERVER_LOGFORMAT", "json"), "Set the logging format. One of: json|text")
|
||||
command.Flags().StringVar(&cmdutil.LogLevel, "loglevel", env.StringFromEnv("ARGOCD_SERVER_LOG_LEVEL", "info"), "Set the logging level. One of: debug|info|warn|error")
|
||||
command.Flags().IntVar(&glogLevel, "gloglevel", 0, "Set the glog logging level")
|
||||
command.Flags().StringVar(&repoServerAddress, "repo-server", env.StringFromEnv("ARGOCD_SERVER_REPO_SERVER", common.DefaultRepoServerAddr), "Repo server address")
|
||||
@@ -324,6 +326,7 @@ func NewCommand() *cobra.Command {
|
||||
command.Flags().IntVar(&webhookParallelism, "webhook-parallelism-limit", env.ParseNumFromEnv("ARGOCD_SERVER_WEBHOOK_PARALLELISM_LIMIT", 50, 1, 1000), "Number of webhook requests processed concurrently")
|
||||
command.Flags().StringSliceVar(&enableK8sEvent, "enable-k8s-event", env.StringsFromEnv("ARGOCD_ENABLE_K8S_EVENT", argo.DefaultEnableEventList(), ","), "Enable ArgoCD to use k8s event. For disabling all events, set the value as `none`. (e.g --enable-k8s-event=none), For enabling specific events, set the value as `event reason`. (e.g --enable-k8s-event=StatusRefreshed,ResourceCreated)")
|
||||
command.Flags().BoolVar(&hydratorEnabled, "hydrator-enabled", env.ParseBoolFromEnv("ARGOCD_HYDRATOR_ENABLED", false), "Feature flag to enable Hydrator. Default (\"false\")")
|
||||
command.Flags().BoolVar(&syncWithReplaceAllowed, "sync-with-replace-allowed", env.ParseBoolFromEnv("ARGOCD_SYNC_WITH_REPLACE_ALLOWED", true), "Whether to allow users to select replace for syncs from UI/CLI")
|
||||
|
||||
// Flags related to the applicationSet component.
|
||||
command.Flags().StringVar(&scmRootCAPath, "appset-scm-root-ca-path", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_SCM_ROOT_CA_PATH", ""), "Provide Root CA Path for self-signed TLS Certificates")
|
||||
|
||||
@@ -16,12 +16,13 @@ import (
|
||||
"golang.org/x/term"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/util/rbac"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/cmd/argocd/commands/headless"
|
||||
"github.com/argoproj/argo-cd/v3/cmd/argocd/commands/utils"
|
||||
argocdclient "github.com/argoproj/argo-cd/v3/pkg/apiclient"
|
||||
accountpkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/account"
|
||||
"github.com/argoproj/argo-cd/v3/pkg/apiclient/session"
|
||||
"github.com/argoproj/argo-cd/v3/server/rbacpolicy"
|
||||
"github.com/argoproj/argo-cd/v3/util/cli"
|
||||
"github.com/argoproj/argo-cd/v3/util/errors"
|
||||
"github.com/argoproj/argo-cd/v3/util/io"
|
||||
@@ -218,7 +219,7 @@ argocd account can-i create clusters '*'
|
||||
|
||||
Actions: %v
|
||||
Resources: %v
|
||||
`, rbacpolicy.Actions, rbacpolicy.Resources),
|
||||
`, rbac.Actions, rbac.Resources),
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
ctx := c.Context()
|
||||
|
||||
|
||||
@@ -14,20 +14,20 @@ import (
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
cmdutil "github.com/argoproj/argo-cd/v3/cmd/util"
|
||||
"github.com/argoproj/argo-cd/v3/common"
|
||||
argocdclient "github.com/argoproj/argo-cd/v3/pkg/apiclient"
|
||||
"github.com/argoproj/argo-cd/v3/util/errors"
|
||||
"github.com/argoproj/argo-cd/v3/util/settings"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/pkg/apis/application"
|
||||
"github.com/argoproj/argo-cd/v3/util/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
// YamlSeparator separates sections of a YAML file
|
||||
yamlSeparator = "---\n"
|
||||
|
||||
applicationsetNamespacesCmdParamsKey = "applicationsetcontroller.namespaces"
|
||||
applicationNamespacesCmdParamsKey = "application.namespaces"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -38,6 +38,19 @@ var (
|
||||
appplicationSetResource = schema.GroupVersionResource{Group: application.Group, Version: "v1alpha1", Resource: application.ApplicationSetPlural}
|
||||
)
|
||||
|
||||
type argocdAdditionalNamespaces struct {
|
||||
applicationNamespaces []string
|
||||
applicationsetNamespaces []string
|
||||
}
|
||||
|
||||
type argoCDClientsets struct {
|
||||
configMaps dynamic.ResourceInterface
|
||||
secrets dynamic.ResourceInterface
|
||||
applications dynamic.ResourceInterface
|
||||
projects dynamic.ResourceInterface
|
||||
applicationSets dynamic.ResourceInterface
|
||||
}
|
||||
|
||||
// NewAdminCommand returns a new instance of an argocd command
|
||||
func NewAdminCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
pathOpts := clientcmd.NewDefaultPathOptions()
|
||||
@@ -69,102 +82,31 @@ $ argocd admin initial-password reset
|
||||
command.AddCommand(NewInitialPasswordCommand())
|
||||
command.AddCommand(NewRedisInitialPasswordCommand())
|
||||
|
||||
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", "text", "Set the logging format. One of: text|json")
|
||||
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", "json", "Set the logging format. One of: json|text")
|
||||
command.Flags().StringVar(&cmdutil.LogLevel, "loglevel", "info", "Set the logging level. One of: debug|info|warn|error")
|
||||
return command
|
||||
}
|
||||
|
||||
type argoCDClientsets struct {
|
||||
configMaps dynamic.ResourceInterface
|
||||
secrets dynamic.ResourceInterface
|
||||
applications dynamic.ResourceInterface
|
||||
projects dynamic.ResourceInterface
|
||||
applicationSets dynamic.ResourceInterface
|
||||
}
|
||||
|
||||
func newArgoCDClientsets(config *rest.Config, namespace string) *argoCDClientsets {
|
||||
dynamicIf, err := dynamic.NewForConfig(config)
|
||||
errors.CheckError(err)
|
||||
|
||||
return &argoCDClientsets{
|
||||
configMaps: dynamicIf.Resource(configMapResource).Namespace(namespace),
|
||||
secrets: dynamicIf.Resource(secretResource).Namespace(namespace),
|
||||
// To support applications and applicationsets in any namespace we will watch all namespaces and filter them afterwards
|
||||
applications: dynamicIf.Resource(applicationsResource),
|
||||
configMaps: dynamicIf.Resource(configMapResource).Namespace(namespace),
|
||||
secrets: dynamicIf.Resource(secretResource).Namespace(namespace),
|
||||
applications: dynamicIf.Resource(applicationsResource).Namespace(namespace),
|
||||
projects: dynamicIf.Resource(appprojectsResource).Namespace(namespace),
|
||||
applicationSets: dynamicIf.Resource(appplicationSetResource),
|
||||
applicationSets: dynamicIf.Resource(appplicationSetResource).Namespace(namespace),
|
||||
}
|
||||
}
|
||||
|
||||
// getReferencedSecrets examines the argocd-cm config for any referenced repo secrets and returns a
|
||||
// map of all referenced secrets.
|
||||
func getReferencedSecrets(un unstructured.Unstructured) map[string]bool {
|
||||
var cm corev1.ConfigMap
|
||||
err := runtime.DefaultUnstructuredConverter.FromUnstructured(un.Object, &cm)
|
||||
errors.CheckError(err)
|
||||
referencedSecrets := make(map[string]bool)
|
||||
|
||||
// Referenced repository secrets
|
||||
if reposRAW, ok := cm.Data["repositories"]; ok {
|
||||
repos := make([]settings.Repository, 0)
|
||||
err := yaml.Unmarshal([]byte(reposRAW), &repos)
|
||||
errors.CheckError(err)
|
||||
for _, cred := range repos {
|
||||
if cred.PasswordSecret != nil {
|
||||
referencedSecrets[cred.PasswordSecret.Name] = true
|
||||
}
|
||||
if cred.SSHPrivateKeySecret != nil {
|
||||
referencedSecrets[cred.SSHPrivateKeySecret.Name] = true
|
||||
}
|
||||
if cred.UsernameSecret != nil {
|
||||
referencedSecrets[cred.UsernameSecret.Name] = true
|
||||
}
|
||||
if cred.TLSClientCertDataSecret != nil {
|
||||
referencedSecrets[cred.TLSClientCertDataSecret.Name] = true
|
||||
}
|
||||
if cred.TLSClientCertKeySecret != nil {
|
||||
referencedSecrets[cred.TLSClientCertKeySecret.Name] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Referenced repository credentials secrets
|
||||
if reposRAW, ok := cm.Data["repository.credentials"]; ok {
|
||||
creds := make([]settings.RepositoryCredentials, 0)
|
||||
err := yaml.Unmarshal([]byte(reposRAW), &creds)
|
||||
errors.CheckError(err)
|
||||
for _, cred := range creds {
|
||||
if cred.PasswordSecret != nil {
|
||||
referencedSecrets[cred.PasswordSecret.Name] = true
|
||||
}
|
||||
if cred.SSHPrivateKeySecret != nil {
|
||||
referencedSecrets[cred.SSHPrivateKeySecret.Name] = true
|
||||
}
|
||||
if cred.UsernameSecret != nil {
|
||||
referencedSecrets[cred.UsernameSecret.Name] = true
|
||||
}
|
||||
if cred.TLSClientCertDataSecret != nil {
|
||||
referencedSecrets[cred.TLSClientCertDataSecret.Name] = true
|
||||
}
|
||||
if cred.TLSClientCertKeySecret != nil {
|
||||
referencedSecrets[cred.TLSClientCertKeySecret.Name] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return referencedSecrets
|
||||
}
|
||||
|
||||
// isArgoCDSecret returns whether or not the given secret is a part of Argo CD configuration
|
||||
// (e.g. argocd-secret, repo credentials, or cluster credentials)
|
||||
func isArgoCDSecret(repoSecretRefs map[string]bool, un unstructured.Unstructured) bool {
|
||||
func isArgoCDSecret(un unstructured.Unstructured) bool {
|
||||
secretName := un.GetName()
|
||||
if secretName == common.ArgoCDSecretName {
|
||||
return true
|
||||
}
|
||||
if repoSecretRefs != nil {
|
||||
if _, ok := repoSecretRefs[secretName]; ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if labels := un.GetLabels(); labels != nil {
|
||||
if _, ok := labels[common.LabelKeySecretType]; ok {
|
||||
return true
|
||||
@@ -227,22 +169,12 @@ func specsEqual(left, right unstructured.Unstructured) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type argocdAdditonalNamespaces struct {
|
||||
applicationNamespaces []string
|
||||
applicationsetNamespaces []string
|
||||
}
|
||||
|
||||
const (
|
||||
applicationsetNamespacesCmdParamsKey = "applicationsetcontroller.namespaces"
|
||||
applicationNamespacesCmdParamsKey = "application.namespaces"
|
||||
)
|
||||
|
||||
// Get additional namespaces from argocd-cmd-params
|
||||
func getAdditionalNamespaces(ctx context.Context, argocdClientsets *argoCDClientsets) *argocdAdditonalNamespaces {
|
||||
func getAdditionalNamespaces(ctx context.Context, configMapsClient dynamic.ResourceInterface) *argocdAdditionalNamespaces {
|
||||
applicationNamespaces := make([]string, 0)
|
||||
applicationsetNamespaces := make([]string, 0)
|
||||
|
||||
un, err := argocdClientsets.configMaps.Get(ctx, common.ArgoCDCmdParamsConfigMapName, metav1.GetOptions{})
|
||||
un, err := configMapsClient.Get(ctx, common.ArgoCDCmdParamsConfigMapName, metav1.GetOptions{})
|
||||
errors.CheckError(err)
|
||||
var cm corev1.ConfigMap
|
||||
err = runtime.DefaultUnstructuredConverter.FromUnstructured(un.Object, &cm)
|
||||
@@ -270,7 +202,7 @@ func getAdditionalNamespaces(ctx context.Context, argocdClientsets *argoCDClient
|
||||
applicationsetNamespaces = namespacesListFromString(strNamespaces)
|
||||
}
|
||||
|
||||
return &argocdAdditonalNamespaces{
|
||||
return &argocdAdditionalNamespaces{
|
||||
applicationNamespaces: applicationNamespaces,
|
||||
applicationsetNamespaces: applicationsetNamespaces,
|
||||
}
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
dynfake "k8s.io/client-go/dynamic/fake"
|
||||
)
|
||||
|
||||
@@ -28,33 +26,33 @@ func TestGetAdditionalNamespaces(t *testing.T) {
|
||||
|
||||
testCases := []struct {
|
||||
CmdParamsKeys map[string]any
|
||||
expected argocdAdditonalNamespaces
|
||||
expected argocdAdditionalNamespaces
|
||||
description string
|
||||
}{
|
||||
{
|
||||
description: "empty configmap should return no additional namespaces",
|
||||
CmdParamsKeys: map[string]any{},
|
||||
expected: argocdAdditonalNamespaces{applicationNamespaces: []string{}, applicationsetNamespaces: []string{}},
|
||||
expected: argocdAdditionalNamespaces{applicationNamespaces: []string{}, applicationsetNamespaces: []string{}},
|
||||
},
|
||||
{
|
||||
description: "empty strings in respective keys in cm shoud return empty namespace list",
|
||||
CmdParamsKeys: map[string]any{applicationsetNamespacesCmdParamsKey: "", applicationNamespacesCmdParamsKey: ""},
|
||||
expected: argocdAdditonalNamespaces{applicationNamespaces: []string{}, applicationsetNamespaces: []string{}},
|
||||
expected: argocdAdditionalNamespaces{applicationNamespaces: []string{}, applicationsetNamespaces: []string{}},
|
||||
},
|
||||
{
|
||||
description: "when only one of the keys in the cm is set only correct respective list of namespaces should be returned",
|
||||
CmdParamsKeys: map[string]any{applicationNamespacesCmdParamsKey: "foo, bar*"},
|
||||
expected: argocdAdditonalNamespaces{applicationsetNamespaces: []string{}, applicationNamespaces: []string{"foo", "bar*"}},
|
||||
expected: argocdAdditionalNamespaces{applicationsetNamespaces: []string{}, applicationNamespaces: []string{"foo", "bar*"}},
|
||||
},
|
||||
{
|
||||
description: "when only one of the keys in the cm is set only correct respective list of namespaces should be returned",
|
||||
CmdParamsKeys: map[string]any{applicationsetNamespacesCmdParamsKey: "foo, bar*"},
|
||||
expected: argocdAdditonalNamespaces{applicationNamespaces: []string{}, applicationsetNamespaces: []string{"foo", "bar*"}},
|
||||
expected: argocdAdditionalNamespaces{applicationNamespaces: []string{}, applicationsetNamespaces: []string{"foo", "bar*"}},
|
||||
},
|
||||
{
|
||||
description: "whitespaces are removed for both multiple and single namespace",
|
||||
CmdParamsKeys: map[string]any{applicationNamespacesCmdParamsKey: " bar ", applicationsetNamespacesCmdParamsKey: " foo , bar* "},
|
||||
expected: argocdAdditonalNamespaces{applicationNamespaces: []string{"bar"}, applicationsetNamespaces: []string{"foo", "bar*"}},
|
||||
expected: argocdAdditionalNamespaces{applicationNamespaces: []string{"bar"}, applicationsetNamespaces: []string{"foo", "bar*"}},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -62,14 +60,10 @@ func TestGetAdditionalNamespaces(t *testing.T) {
|
||||
fakeDynClient := dynfake.NewSimpleDynamicClient(runtime.NewScheme(), createArgoCDCmdCMWithKeys(c.CmdParamsKeys))
|
||||
|
||||
argoCDClientsets := &argoCDClientsets{
|
||||
configMaps: fakeDynClient.Resource(configMapResource).Namespace("argocd"),
|
||||
applications: fakeDynClient.Resource(schema.GroupVersionResource{}),
|
||||
applicationSets: fakeDynClient.Resource(schema.GroupVersionResource{}),
|
||||
secrets: fakeDynClient.Resource(schema.GroupVersionResource{}),
|
||||
projects: fakeDynClient.Resource(schema.GroupVersionResource{}),
|
||||
configMaps: fakeDynClient.Resource(configMapResource).Namespace("argocd"),
|
||||
}
|
||||
|
||||
result := getAdditionalNamespaces(context.TODO(), argoCDClientsets)
|
||||
result := getAdditionalNamespaces(t.Context(), argoCDClientsets.configMaps)
|
||||
assert.Equal(t, c.expected, *result)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/argoproj/gitops-engine/pkg/utils/kube"
|
||||
"github.com/spf13/cobra"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -403,7 +404,26 @@ func reconcileApplications(
|
||||
)
|
||||
|
||||
appStateManager := controller.NewAppStateManager(
|
||||
argoDB, appClientset, repoServerClient, namespace, kubeutil.NewKubectl(), settingsMgr, stateCache, projInformer, server, cache, time.Second, argo.NewResourceTracking(), false, 0, serverSideDiff, ignoreNormalizerOpts)
|
||||
argoDB,
|
||||
appClientset,
|
||||
repoServerClient,
|
||||
namespace,
|
||||
kubeutil.NewKubectl(),
|
||||
func(_ string) (kube.CleanupFunc, error) {
|
||||
return func() {}, nil
|
||||
},
|
||||
settingsMgr,
|
||||
stateCache,
|
||||
projInformer,
|
||||
server,
|
||||
cache,
|
||||
time.Second,
|
||||
argo.NewResourceTracking(),
|
||||
false,
|
||||
0,
|
||||
serverSideDiff,
|
||||
ignoreNormalizerOpts,
|
||||
)
|
||||
|
||||
appsList, err := appClientset.ArgoprojV1alpha1().Applications(namespace).List(ctx, metav1.ListOptions{LabelSelector: selector})
|
||||
if err != nil {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
clustermocks "github.com/argoproj/gitops-engine/pkg/cache/mocks"
|
||||
@@ -31,7 +30,7 @@ import (
|
||||
)
|
||||
|
||||
func TestGetReconcileResults(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
|
||||
appClientset := appfake.NewSimpleClientset(&v1alpha1.Application{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
@@ -56,7 +55,7 @@ func TestGetReconcileResults(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetReconcileResults_Refresh(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
|
||||
argoCM := &corev1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/argoproj/gitops-engine/pkg/utils/kube"
|
||||
log "github.com/sirupsen/logrus"
|
||||
@@ -14,6 +16,8 @@ import (
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
|
||||
"k8s.io/client-go/util/retry"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/cmd/argocd/commands/utils"
|
||||
@@ -41,8 +45,11 @@ func NewExportCommand() *cobra.Command {
|
||||
|
||||
config, err := clientConfig.ClientConfig()
|
||||
errors.CheckError(err)
|
||||
client, err := dynamic.NewForConfig(config)
|
||||
errors.CheckError(err)
|
||||
namespace, _, err := clientConfig.Namespace()
|
||||
errors.CheckError(err)
|
||||
acdClients := newArgoCDClientsets(config, namespace)
|
||||
|
||||
var writer io.Writer
|
||||
if out == "-" {
|
||||
@@ -60,7 +67,23 @@ func NewExportCommand() *cobra.Command {
|
||||
}()
|
||||
}
|
||||
|
||||
acdClients := newArgoCDClientsets(config, namespace)
|
||||
if len(applicationNamespaces) == 0 || len(applicationsetNamespaces) == 0 {
|
||||
defaultNs := getAdditionalNamespaces(ctx, acdClients.configMaps)
|
||||
if len(applicationNamespaces) == 0 {
|
||||
applicationNamespaces = defaultNs.applicationNamespaces
|
||||
}
|
||||
if len(applicationsetNamespaces) == 0 {
|
||||
applicationsetNamespaces = defaultNs.applicationsetNamespaces
|
||||
}
|
||||
}
|
||||
// To support applications and applicationsets in any namespace, we must list ALL namespaces and filter them afterwards
|
||||
if len(applicationNamespaces) > 0 {
|
||||
acdClients.applications = client.Resource(applicationsResource)
|
||||
}
|
||||
if len(applicationsetNamespaces) > 0 {
|
||||
acdClients.applicationSets = client.Resource(appplicationSetResource)
|
||||
}
|
||||
|
||||
acdConfigMap, err := acdClients.configMaps.Get(ctx, common.ArgoCDConfigMapName, metav1.GetOptions{})
|
||||
errors.CheckError(err)
|
||||
export(writer, *acdConfigMap, namespace)
|
||||
@@ -74,29 +97,20 @@ func NewExportCommand() *cobra.Command {
|
||||
errors.CheckError(err)
|
||||
export(writer, *acdTLSCertsConfigMap, namespace)
|
||||
|
||||
referencedSecrets := getReferencedSecrets(*acdConfigMap)
|
||||
secrets, err := acdClients.secrets.List(ctx, metav1.ListOptions{})
|
||||
errors.CheckError(err)
|
||||
for _, secret := range secrets.Items {
|
||||
if isArgoCDSecret(referencedSecrets, secret) {
|
||||
if isArgoCDSecret(secret) {
|
||||
export(writer, secret, namespace)
|
||||
}
|
||||
}
|
||||
|
||||
projects, err := acdClients.projects.List(ctx, metav1.ListOptions{})
|
||||
errors.CheckError(err)
|
||||
for _, proj := range projects.Items {
|
||||
export(writer, proj, namespace)
|
||||
}
|
||||
|
||||
additionalNamespaces := getAdditionalNamespaces(ctx, acdClients)
|
||||
|
||||
if len(applicationNamespaces) == 0 {
|
||||
applicationNamespaces = additionalNamespaces.applicationNamespaces
|
||||
}
|
||||
if len(applicationsetNamespaces) == 0 {
|
||||
applicationsetNamespaces = additionalNamespaces.applicationsetNamespaces
|
||||
}
|
||||
|
||||
applications, err := acdClients.applications.List(ctx, metav1.ListOptions{})
|
||||
errors.CheckError(err)
|
||||
for _, app := range applications.Items {
|
||||
@@ -125,8 +139,8 @@ func NewExportCommand() *cobra.Command {
|
||||
|
||||
clientConfig = cli.AddKubectlFlagsToCmd(&command)
|
||||
command.Flags().StringVarP(&out, "out", "o", "-", "Output to the specified file instead of stdout")
|
||||
command.Flags().StringSliceVarP(&applicationNamespaces, "application-namespaces", "", []string{}, fmt.Sprintf("Comma separated list of namespace globs to export applications from. If not provided value from '%s' in %s will be used,if it's not defined only applications from Argo CD namespace will be exported", applicationNamespacesCmdParamsKey, common.ArgoCDCmdParamsConfigMapName))
|
||||
command.Flags().StringSliceVarP(&applicationsetNamespaces, "applicationset-namespaces", "", []string{}, fmt.Sprintf("Comma separated list of namespace globs to export applicationsets from. If not provided value from '%s' in %s will be used,if it's not defined only applicationsets from Argo CD namespace will be exported", applicationsetNamespacesCmdParamsKey, common.ArgoCDCmdParamsConfigMapName))
|
||||
command.Flags().StringSliceVarP(&applicationNamespaces, "application-namespaces", "", []string{}, fmt.Sprintf("Comma separated list of namespace globs to export applications from. If not provided value from '%s' in %s will be used. If it's not defined, only applications from Argo CD namespace will be exported", applicationNamespacesCmdParamsKey, common.ArgoCDCmdParamsConfigMapName))
|
||||
command.Flags().StringSliceVarP(&applicationsetNamespaces, "applicationset-namespaces", "", []string{}, fmt.Sprintf("Comma separated list of namespace globs to export applicationsets from. If not provided value from '%s' in %s will be used. If it's not defined, only applicationsets from Argo CD namespace will be exported", applicationsetNamespacesCmdParamsKey, common.ArgoCDCmdParamsConfigMapName))
|
||||
return &command
|
||||
}
|
||||
|
||||
@@ -139,7 +153,9 @@ func NewImportCommand() *cobra.Command {
|
||||
verbose bool
|
||||
stopOperation bool
|
||||
ignoreTracking bool
|
||||
overrideOnConflict bool
|
||||
promptsEnabled bool
|
||||
skipResourcesWithLabel string
|
||||
applicationNamespaces []string
|
||||
applicationsetNamespaces []string
|
||||
)
|
||||
@@ -162,7 +178,8 @@ func NewImportCommand() *cobra.Command {
|
||||
acdClients := newArgoCDClientsets(config, namespace)
|
||||
client, err := dynamic.NewForConfig(config)
|
||||
errors.CheckError(err)
|
||||
|
||||
fmt.Printf("import process started %s\n", namespace)
|
||||
tt := time.Now()
|
||||
var input []byte
|
||||
if in := args[0]; in == "-" {
|
||||
input, err = io.ReadAll(os.Stdin)
|
||||
@@ -175,37 +192,40 @@ func NewImportCommand() *cobra.Command {
|
||||
dryRunMsg = " (dry run)"
|
||||
}
|
||||
|
||||
additionalNamespaces := getAdditionalNamespaces(ctx, acdClients)
|
||||
|
||||
if len(applicationNamespaces) == 0 {
|
||||
applicationNamespaces = additionalNamespaces.applicationNamespaces
|
||||
if len(applicationNamespaces) == 0 || len(applicationsetNamespaces) == 0 {
|
||||
defaultNs := getAdditionalNamespaces(ctx, acdClients.configMaps)
|
||||
if len(applicationNamespaces) == 0 {
|
||||
applicationNamespaces = defaultNs.applicationNamespaces
|
||||
}
|
||||
if len(applicationsetNamespaces) == 0 {
|
||||
applicationsetNamespaces = defaultNs.applicationsetNamespaces
|
||||
}
|
||||
}
|
||||
if len(applicationsetNamespaces) == 0 {
|
||||
applicationsetNamespaces = additionalNamespaces.applicationsetNamespaces
|
||||
// To support applications and applicationsets in any namespace, we must list ALL namespaces and filter them afterwards
|
||||
if len(applicationNamespaces) > 0 {
|
||||
acdClients.applications = client.Resource(applicationsResource)
|
||||
}
|
||||
if len(applicationsetNamespaces) > 0 {
|
||||
acdClients.applicationSets = client.Resource(appplicationSetResource)
|
||||
}
|
||||
|
||||
// pruneObjects tracks live objects and it's current resource version. any remaining
|
||||
// pruneObjects tracks live objects, and it's current resource version. any remaining
|
||||
// items in this map indicates the resource should be pruned since it no longer appears
|
||||
// in the backup
|
||||
pruneObjects := make(map[kube.ResourceKey]unstructured.Unstructured)
|
||||
configMaps, err := acdClients.configMaps.List(ctx, metav1.ListOptions{})
|
||||
|
||||
errors.CheckError(err)
|
||||
// referencedSecrets holds any secrets referenced in the argocd-cm configmap. These
|
||||
// secrets need to be imported too
|
||||
var referencedSecrets map[string]bool
|
||||
for _, cm := range configMaps.Items {
|
||||
if isArgoCDConfigMap(cm.GetName()) {
|
||||
pruneObjects[kube.ResourceKey{Group: "", Kind: "ConfigMap", Name: cm.GetName(), Namespace: cm.GetNamespace()}] = cm
|
||||
}
|
||||
if cm.GetName() == common.ArgoCDConfigMapName {
|
||||
referencedSecrets = getReferencedSecrets(cm)
|
||||
}
|
||||
}
|
||||
|
||||
secrets, err := acdClients.secrets.List(ctx, metav1.ListOptions{})
|
||||
errors.CheckError(err)
|
||||
for _, secret := range secrets.Items {
|
||||
if isArgoCDSecret(referencedSecrets, secret) {
|
||||
if isArgoCDSecret(secret) {
|
||||
pruneObjects[kube.ResourceKey{Group: "", Kind: "Secret", Name: secret.GetName(), Namespace: secret.GetNamespace()}] = secret
|
||||
}
|
||||
}
|
||||
@@ -234,9 +254,9 @@ func NewImportCommand() *cobra.Command {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create or replace existing object
|
||||
backupObjects, err := kube.SplitYAML(input)
|
||||
|
||||
errors.CheckError(err)
|
||||
for _, bakObj := range backupObjects {
|
||||
gvk := bakObj.GroupVersionKind()
|
||||
@@ -247,6 +267,13 @@ func NewImportCommand() *cobra.Command {
|
||||
key := kube.ResourceKey{Group: gvk.Group, Kind: gvk.Kind, Name: bakObj.GetName(), Namespace: bakObj.GetNamespace()}
|
||||
liveObj, exists := pruneObjects[key]
|
||||
delete(pruneObjects, key)
|
||||
|
||||
// If the resource in backup matches the skip label, do not import it
|
||||
if isSkipLabelMatches(bakObj, skipResourcesWithLabel) {
|
||||
fmt.Printf("Skipping %s/%s %s in namespace %s\n", bakObj.GroupVersionKind().Group, bakObj.GroupVersionKind().Kind, bakObj.GetName(), bakObj.GetNamespace())
|
||||
continue
|
||||
}
|
||||
|
||||
var dynClient dynamic.ResourceInterface
|
||||
switch bakObj.GetKind() {
|
||||
case "Secret":
|
||||
@@ -256,17 +283,17 @@ func NewImportCommand() *cobra.Command {
|
||||
case application.AppProjectKind:
|
||||
dynClient = client.Resource(appprojectsResource).Namespace(bakObj.GetNamespace())
|
||||
case application.ApplicationKind:
|
||||
dynClient = client.Resource(applicationsResource).Namespace(bakObj.GetNamespace())
|
||||
// If application is not in one of the allowed namespaces do not import it
|
||||
if !secutil.IsNamespaceEnabled(bakObj.GetNamespace(), namespace, applicationNamespaces) {
|
||||
continue
|
||||
}
|
||||
dynClient = client.Resource(applicationsResource).Namespace(bakObj.GetNamespace())
|
||||
case application.ApplicationSetKind:
|
||||
dynClient = client.Resource(appplicationSetResource).Namespace(bakObj.GetNamespace())
|
||||
// If applicationset is not in one of the allowed namespaces do not import it
|
||||
if !secutil.IsNamespaceEnabled(bakObj.GetNamespace(), namespace, applicationsetNamespaces) {
|
||||
continue
|
||||
}
|
||||
dynClient = client.Resource(appplicationSetResource).Namespace(bakObj.GetNamespace())
|
||||
}
|
||||
|
||||
// If there is a live object, remove the tracking annotations/label that might conflict
|
||||
@@ -299,6 +326,21 @@ func NewImportCommand() *cobra.Command {
|
||||
if !dryRun {
|
||||
newLive := updateLive(bakObj, &liveObj, stopOperation)
|
||||
_, err = dynClient.Update(ctx, newLive, metav1.UpdateOptions{})
|
||||
if apierrors.IsConflict(err) {
|
||||
fmt.Printf("Failed to update %s/%s %s in namespace %s: %v\n", gvk.Group, gvk.Kind, bakObj.GetName(), bakObj.GetNamespace(), err)
|
||||
if overrideOnConflict {
|
||||
err = retry.RetryOnConflict(retry.DefaultRetry, func() error {
|
||||
fmt.Printf("Resource conflict: retrying update for Group: %s, Kind: %s, Name: %s, Namespace: %s\n", gvk.Group, gvk.Kind, bakObj.GetName(), bakObj.GetNamespace())
|
||||
liveObj, getErr := dynClient.Get(ctx, newLive.GetName(), metav1.GetOptions{})
|
||||
if getErr != nil {
|
||||
errors.CheckError(getErr)
|
||||
}
|
||||
newLive.SetResourceVersion(liveObj.GetResourceVersion())
|
||||
_, err = dynClient.Update(ctx, newLive, metav1.UpdateOptions{})
|
||||
return err
|
||||
})
|
||||
}
|
||||
}
|
||||
if apierrors.IsForbidden(err) || apierrors.IsNotFound(err) {
|
||||
isForbidden = true
|
||||
log.Warnf("%s/%s %s: %v", gvk.Group, gvk.Kind, bakObj.GetName(), err)
|
||||
@@ -316,6 +358,12 @@ func NewImportCommand() *cobra.Command {
|
||||
|
||||
// Delete objects not in backup
|
||||
for key, liveObj := range pruneObjects {
|
||||
// If a live resource has a label to skip the import, it should never be pruned
|
||||
if isSkipLabelMatches(&liveObj, skipResourcesWithLabel) {
|
||||
fmt.Printf("Skipping pruning of %s/%s %s in namespace %s\n", key.Group, key.Kind, liveObj.GetName(), liveObj.GetNamespace())
|
||||
continue
|
||||
}
|
||||
|
||||
if prune {
|
||||
var dynClient dynamic.ResourceInterface
|
||||
switch key.Kind {
|
||||
@@ -363,6 +411,8 @@ func NewImportCommand() *cobra.Command {
|
||||
fmt.Printf("%s/%s %s needs pruning\n", key.Group, key.Kind, key.Name)
|
||||
}
|
||||
}
|
||||
duration := time.Since(tt)
|
||||
fmt.Printf("Import process completed successfully in namespace %s at %s, duration: %s\n", namespace, time.Now().Format(time.RFC3339), duration)
|
||||
},
|
||||
}
|
||||
|
||||
@@ -370,12 +420,13 @@ func NewImportCommand() *cobra.Command {
|
||||
command.Flags().BoolVar(&dryRun, "dry-run", false, "Print what will be performed")
|
||||
command.Flags().BoolVar(&prune, "prune", false, "Prune secrets, applications and projects which do not appear in the backup")
|
||||
command.Flags().BoolVar(&ignoreTracking, "ignore-tracking", false, "Do not update the tracking annotation if the resource is already tracked")
|
||||
command.Flags().BoolVar(&overrideOnConflict, "override-on-conflict", false, "Override the resource on conflict when updating resources")
|
||||
command.Flags().BoolVar(&verbose, "verbose", false, "Verbose output (versus only changed output)")
|
||||
command.Flags().BoolVar(&stopOperation, "stop-operation", false, "Stop any existing operations")
|
||||
command.Flags().StringSliceVarP(&applicationNamespaces, "application-namespaces", "", []string{}, fmt.Sprintf("Comma separated list of namespace globs to which import of applications is allowed. If not provided value from '%s' in %s will be used,if it's not defined only applications without an explicit namespace will be imported to the Argo CD namespace", applicationNamespacesCmdParamsKey, common.ArgoCDCmdParamsConfigMapName))
|
||||
command.Flags().StringSliceVarP(&applicationsetNamespaces, "applicationset-namespaces", "", []string{}, fmt.Sprintf("Comma separated list of namespace globs which import of applicationsets is allowed. If not provided value from '%s' in %s will be used,if it's not defined only applicationsets without an explicit namespace will be imported to the Argo CD namespace", applicationsetNamespacesCmdParamsKey, common.ArgoCDCmdParamsConfigMapName))
|
||||
command.Flags().StringVarP(&skipResourcesWithLabel, "skip-resources-with-label", "", "", "Skip importing resources based on the label e.g. '--skip-resources-with-label my-label/example.io=true'")
|
||||
command.Flags().StringSliceVarP(&applicationNamespaces, "application-namespaces", "", []string{}, fmt.Sprintf("Comma separated list of namespace globs to which import of applications is allowed. If not provided, value from '%s' in %s will be used. If it's not defined, only applications without an explicit namespace will be imported to the Argo CD namespace", applicationNamespacesCmdParamsKey, common.ArgoCDCmdParamsConfigMapName))
|
||||
command.Flags().StringSliceVarP(&applicationsetNamespaces, "applicationset-namespaces", "", []string{}, fmt.Sprintf("Comma separated list of namespace globs which import of applicationsets is allowed. If not provided, value from '%s' in %s will be used. If it's not defined, only applicationsets without an explicit namespace will be imported to the Argo CD namespace", applicationsetNamespacesCmdParamsKey, common.ArgoCDCmdParamsConfigMapName))
|
||||
command.PersistentFlags().BoolVar(&promptsEnabled, "prompts-enabled", localconfig.GetPromptsEnabled(true), "Force optional interactive prompts to be enabled or disabled, overriding local configuration. If not specified, the local configuration value will be used, which is false by default.")
|
||||
|
||||
return &command
|
||||
}
|
||||
|
||||
@@ -407,6 +458,7 @@ func export(w io.Writer, un unstructured.Unstructured, argocdNamespace string) {
|
||||
un.SetLabels(labels)
|
||||
un.SetAnnotations(annotations)
|
||||
if namespace != argocdNamespace {
|
||||
// Explicitly add the namespace for appset and apps in any namespace
|
||||
un.SetNamespace(namespace)
|
||||
}
|
||||
data, err := yaml.Marshal(un.Object)
|
||||
@@ -472,3 +524,19 @@ func updateTracking(bak, live *unstructured.Unstructured) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// isSkipLabelMatches return if the resource should be skipped based on the labels
|
||||
func isSkipLabelMatches(obj *unstructured.Unstructured, skipResourcesWithLabel string) bool {
|
||||
if skipResourcesWithLabel == "" {
|
||||
return false
|
||||
}
|
||||
parts := strings.SplitN(skipResourcesWithLabel, "=", 2)
|
||||
if len(parts) != 2 || parts[0] == "" || parts[1] == "" {
|
||||
return false
|
||||
}
|
||||
key, value := parts[0], parts[1]
|
||||
if val, ok := obj.GetLabels()[key]; ok && val == value {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -85,3 +85,76 @@ func Test_updateTracking(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsSkipLabelMatches(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
obj *unstructured.Unstructured
|
||||
skipLabels string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "Label matches",
|
||||
obj: &unstructured.Unstructured{
|
||||
Object: map[string]any{
|
||||
"metadata": map[string]any{
|
||||
"labels": map[string]any{
|
||||
"test-label": "value",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
skipLabels: "test-label=value",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "Label does not match",
|
||||
obj: &unstructured.Unstructured{
|
||||
Object: map[string]any{
|
||||
"metadata": map[string]any{
|
||||
"labels": map[string]any{
|
||||
"different-label": "value",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
skipLabels: "test-label=value",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "Empty skip labels",
|
||||
obj: &unstructured.Unstructured{
|
||||
Object: map[string]any{
|
||||
"metadata": map[string]any{
|
||||
"labels": map[string]any{
|
||||
"test-label": "value",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
skipLabels: "",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "No labels value",
|
||||
obj: &unstructured.Unstructured{
|
||||
Object: map[string]any{
|
||||
"metadata": map[string]any{
|
||||
"labels": map[string]any{
|
||||
"test-label": "value",
|
||||
"another-label": "value2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
skipLabels: "test-label",
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := isSkipLabelMatches(tt.obj, tt.skipLabels)
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,13 +180,12 @@ func getControllerReplicas(ctx context.Context, kubeClient *kubernetes.Clientset
|
||||
|
||||
func NewClusterShardsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
var (
|
||||
shard int
|
||||
replicas int
|
||||
shardingAlgorithm string
|
||||
clientConfig clientcmd.ClientConfig
|
||||
cacheSrc func() (*appstatecache.Cache, error)
|
||||
portForwardRedis bool
|
||||
redisCompressionStr string
|
||||
shard int
|
||||
replicas int
|
||||
shardingAlgorithm string
|
||||
clientConfig clientcmd.ClientConfig
|
||||
cacheSrc func() (*appstatecache.Cache, error)
|
||||
portForwardRedis bool
|
||||
)
|
||||
command := cobra.Command{
|
||||
Use: "shards",
|
||||
@@ -210,7 +209,7 @@ func NewClusterShardsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comm
|
||||
if replicas == 0 {
|
||||
return
|
||||
}
|
||||
clusters, err := loadClusters(ctx, kubeClient, appClient, replicas, shardingAlgorithm, namespace, portForwardRedis, cacheSrc, shard, clientOpts.RedisName, clientOpts.RedisHaProxyName, redisCompressionStr)
|
||||
clusters, err := loadClusters(ctx, kubeClient, appClient, replicas, shardingAlgorithm, namespace, portForwardRedis, cacheSrc, shard, clientOpts.RedisName, clientOpts.RedisHaProxyName, clientOpts.RedisCompression)
|
||||
errors.CheckError(err)
|
||||
if len(clusters) == 0 {
|
||||
return
|
||||
@@ -231,7 +230,6 @@ func NewClusterShardsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comm
|
||||
// we can ignore unchecked error here as the command will be parsed again and checked when command.Execute() is run later
|
||||
//nolint:errcheck
|
||||
command.ParseFlags(os.Args[1:])
|
||||
redisCompressionStr, _ = command.Flags().GetString(cacheutil.CLIFlagRedisCompress)
|
||||
return &command
|
||||
}
|
||||
|
||||
@@ -461,13 +459,12 @@ func NewClusterDisableNamespacedMode() *cobra.Command {
|
||||
|
||||
func NewClusterStatsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
var (
|
||||
shard int
|
||||
replicas int
|
||||
shardingAlgorithm string
|
||||
clientConfig clientcmd.ClientConfig
|
||||
cacheSrc func() (*appstatecache.Cache, error)
|
||||
portForwardRedis bool
|
||||
redisCompressionStr string
|
||||
shard int
|
||||
replicas int
|
||||
shardingAlgorithm string
|
||||
clientConfig clientcmd.ClientConfig
|
||||
cacheSrc func() (*appstatecache.Cache, error)
|
||||
portForwardRedis bool
|
||||
)
|
||||
command := cobra.Command{
|
||||
Use: "stats",
|
||||
@@ -497,7 +494,7 @@ argocd admin cluster stats target-cluster`,
|
||||
replicas, err = getControllerReplicas(ctx, kubeClient, namespace, clientOpts.AppControllerName)
|
||||
errors.CheckError(err)
|
||||
}
|
||||
clusters, err := loadClusters(ctx, kubeClient, appClient, replicas, shardingAlgorithm, namespace, portForwardRedis, cacheSrc, shard, clientOpts.RedisName, clientOpts.RedisHaProxyName, redisCompressionStr)
|
||||
clusters, err := loadClusters(ctx, kubeClient, appClient, replicas, shardingAlgorithm, namespace, portForwardRedis, cacheSrc, shard, clientOpts.RedisName, clientOpts.RedisHaProxyName, clientOpts.RedisCompression)
|
||||
errors.CheckError(err)
|
||||
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
@@ -519,7 +516,6 @@ argocd admin cluster stats target-cluster`,
|
||||
// we can ignore unchecked error here as the command will be parsed again and checked when command.Execute() is run later
|
||||
//nolint:errcheck
|
||||
command.ParseFlags(os.Args[1:])
|
||||
redisCompressionStr, _ = command.Flags().GetString(cacheutil.CLIFlagRedisCompress)
|
||||
return &command
|
||||
}
|
||||
|
||||
@@ -549,7 +545,7 @@ argocd admin cluster kubeconfig https://cluster-api-url:6443 /path/to/output/kub
|
||||
c.HelpFunc()(c, args)
|
||||
os.Exit(1)
|
||||
}
|
||||
serverUrl := args[0]
|
||||
serverURL := args[0]
|
||||
output := args[1]
|
||||
conf, err := clientConfig.ClientConfig()
|
||||
errors.CheckError(err)
|
||||
@@ -558,7 +554,7 @@ argocd admin cluster kubeconfig https://cluster-api-url:6443 /path/to/output/kub
|
||||
kubeclientset, err := kubernetes.NewForConfig(conf)
|
||||
errors.CheckError(err)
|
||||
|
||||
cluster, err := db.NewDB(namespace, settings.NewSettingsManager(ctx, kubeclientset, namespace), kubeclientset).GetCluster(ctx, serverUrl)
|
||||
cluster, err := db.NewDB(namespace, settings.NewSettingsManager(ctx, kubeclientset, namespace), kubeclientset).GetCluster(ctx, serverURL)
|
||||
errors.CheckError(err)
|
||||
rawConfig, err := cluster.RawRestConfig()
|
||||
errors.CheckError(err)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -51,7 +50,7 @@ func Test_loadClusters(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
kubeClient := fake.NewClientset(argoCDCM, argoCDSecret)
|
||||
appClient := fakeapps.NewSimpleClientset(app)
|
||||
cacheSrc := func() (*appstate.Cache, error) {
|
||||
|
||||
@@ -12,17 +12,14 @@ import (
|
||||
"github.com/argoproj/argo-cd/v3/cmd/argocd/commands/initialize"
|
||||
"github.com/argoproj/argo-cd/v3/common"
|
||||
argocdclient "github.com/argoproj/argo-cd/v3/pkg/apiclient"
|
||||
"github.com/argoproj/argo-cd/v3/util/cache"
|
||||
"github.com/argoproj/argo-cd/v3/util/env"
|
||||
"github.com/argoproj/argo-cd/v3/util/errors"
|
||||
)
|
||||
|
||||
func NewDashboardCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
var (
|
||||
port int
|
||||
address string
|
||||
compressionStr string
|
||||
clientConfig clientcmd.ClientConfig
|
||||
port int
|
||||
address string
|
||||
clientConfig clientcmd.ClientConfig
|
||||
)
|
||||
cmd := &cobra.Command{
|
||||
Use: "dashboard",
|
||||
@@ -30,10 +27,8 @@ func NewDashboardCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command
|
||||
Run: func(cmd *cobra.Command, _ []string) {
|
||||
ctx := cmd.Context()
|
||||
|
||||
compression, err := cache.CompressionTypeFromString(compressionStr)
|
||||
errors.CheckError(err)
|
||||
clientOpts.Core = true
|
||||
errors.CheckError(headless.MaybeStartLocalServer(ctx, clientOpts, initialize.RetrieveContextIfChanged(cmd.Flag("context")), &port, &address, compression, clientConfig))
|
||||
errors.CheckError(headless.MaybeStartLocalServer(ctx, clientOpts, initialize.RetrieveContextIfChanged(cmd.Flag("context")), &port, &address, clientConfig))
|
||||
println(fmt.Sprintf("Argo CD UI is available at http://%s:%d", address, port))
|
||||
<-ctx.Done()
|
||||
},
|
||||
@@ -50,6 +45,5 @@ $ argocd admin dashboard --redis-compress gzip
|
||||
clientConfig = cli.AddKubectlFlagsToSet(cmd.Flags())
|
||||
cmd.Flags().IntVar(&port, "port", common.DefaultPortAPIServer, "Listen on given port")
|
||||
cmd.Flags().StringVar(&address, "address", common.DefaultAddressAdminDashboard, "Listen on given address")
|
||||
cmd.Flags().StringVar(&compressionStr, "redis-compress", env.StringFromEnv("REDIS_COMPRESSION", string(cache.RedisCompressionGZip)), "Enable this if the application controller is configured with redis compression enabled. (possible values: gzip, none)")
|
||||
return cmd
|
||||
}
|
||||
|
||||
@@ -136,17 +136,17 @@ func generateProjectAllowList(serverResources []*metav1.APIResourceList, cluster
|
||||
continue
|
||||
}
|
||||
|
||||
ruleApiGroup := rule.APIGroups[0]
|
||||
ruleAPIGroup := rule.APIGroups[0]
|
||||
for _, ruleResource := range rule.Resources {
|
||||
for _, apiResourcesList := range serverResources {
|
||||
gv, err := schema.ParseGroupVersion(apiResourcesList.GroupVersion)
|
||||
if err != nil {
|
||||
gv = schema.GroupVersion{}
|
||||
}
|
||||
if ruleApiGroup == gv.Group {
|
||||
if ruleAPIGroup == gv.Group {
|
||||
for _, apiResource := range apiResourcesList.APIResources {
|
||||
if apiResource.Name == ruleResource {
|
||||
resourceList = append(resourceList, metav1.GroupKind{Group: ruleApiGroup, Kind: apiResource.Kind})
|
||||
resourceList = append(resourceList, metav1.GroupKind{Group: ruleAPIGroup, Kind: apiResource.Kind})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -30,7 +29,7 @@ func newProj(name string, roleNames ...string) *v1alpha1.AppProject {
|
||||
}
|
||||
|
||||
func TestUpdateProjects_FindMatchingProject(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
|
||||
clientset := fake.NewSimpleClientset(newProj("foo", "test"), newProj("bar", "test"))
|
||||
|
||||
@@ -49,7 +48,7 @@ func TestUpdateProjects_FindMatchingProject(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestUpdateProjects_FindMatchingRole(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
|
||||
clientset := fake.NewSimpleClientset(newProj("proj", "foo", "bar"))
|
||||
|
||||
|
||||
@@ -54,6 +54,9 @@ func NewGenRepoSpecCommand() *cobra.Command {
|
||||
# Add a private Git repository via HTTPS using username/password and TLS client certificates:
|
||||
argocd admin repo generate-spec https://git.example.com/repos/repo --username git --password secret --tls-client-cert-path ~/mycert.crt --tls-client-cert-key-path ~/mycert.key
|
||||
|
||||
# Add a private Git BitBucket Data Center repository via HTTPS using bearer token:
|
||||
argocd admin repo generate-spec https://bitbucket.example.com/scm/proj/repo --bearer-token secret-token
|
||||
|
||||
# Add a private Git repository via HTTPS using username/password without verifying the server's TLS certificate
|
||||
argocd admin repo generate-spec https://git.example.com/repos/repo --username git --password secret --insecure-skip-server-verification
|
||||
|
||||
@@ -138,6 +141,13 @@ func NewGenRepoSpecCommand() *cobra.Command {
|
||||
repoOpts.Repo.Password = cli.PromptPassword(repoOpts.Repo.Password)
|
||||
}
|
||||
|
||||
err := cmdutil.ValidateBearerTokenAndPasswordCombo(repoOpts.Repo.BearerToken, repoOpts.Repo.Password)
|
||||
errors.CheckError(err)
|
||||
err = cmdutil.ValidateBearerTokenForHTTPSRepoOnly(repoOpts.Repo.BearerToken, git.IsHTTPSURL(repoOpts.Repo.Repo))
|
||||
errors.CheckError(err)
|
||||
err = cmdutil.ValidateBearerTokenForGitOnly(repoOpts.Repo.BearerToken, repoOpts.Repo.Type)
|
||||
errors.CheckError(err)
|
||||
|
||||
argoCDCM := &corev1.ConfigMap{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "ConfigMap",
|
||||
@@ -155,7 +165,7 @@ func NewGenRepoSpecCommand() *cobra.Command {
|
||||
settingsMgr := settings.NewSettingsManager(ctx, kubeClientset, ArgoCDNamespace)
|
||||
argoDB := db.NewDB(ArgoCDNamespace, settingsMgr, kubeClientset)
|
||||
|
||||
_, err := argoDB.CreateRepository(ctx, &repoOpts.Repo)
|
||||
_, err = argoDB.CreateRepository(ctx, &repoOpts.Repo)
|
||||
errors.CheckError(err)
|
||||
|
||||
secret, err := kubeClientset.CoreV1().Secrets(ArgoCDNamespace).Get(ctx, db.RepoURLToSecretName(repoSecretPrefix, repoOpts.Repo.Repo, repoOpts.Repo.Project), metav1.GetOptions{})
|
||||
|
||||
@@ -162,7 +162,7 @@ func NewSettingsCommand() *cobra.Command {
|
||||
|
||||
command.AddCommand(NewValidateSettingsCommand(&opts))
|
||||
command.AddCommand(NewResourceOverridesCommand(&opts))
|
||||
command.AddCommand(NewRBACCommand(&opts))
|
||||
command.AddCommand(NewRBACCommand())
|
||||
|
||||
opts.clientConfig = cli.AddKubectlFlagsToCmd(command)
|
||||
command.PersistentFlags().StringVar(&opts.argocdCMPath, "argocd-cm-path", "", "Path to local argocd-cm.yaml file")
|
||||
@@ -247,19 +247,6 @@ var validatorsByGroup = map[string]settingValidator{
|
||||
}
|
||||
return summary, err
|
||||
},
|
||||
"repositories": joinValidators(func(manager *settings.SettingsManager) (string, error) {
|
||||
repos, err := manager.GetRepositories()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("%d repositories", len(repos)), nil
|
||||
}, func(manager *settings.SettingsManager) (string, error) {
|
||||
creds, err := manager.GetRepositoryCredentials()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("%d repository credentials", len(creds)), nil
|
||||
}),
|
||||
"accounts": func(manager *settings.SettingsManager) (string, error) {
|
||||
accounts, err := manager.GetAccounts()
|
||||
if err != nil {
|
||||
|
||||
@@ -15,10 +15,8 @@ import (
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/common"
|
||||
"github.com/argoproj/argo-cd/v3/server/rbacpolicy"
|
||||
"github.com/argoproj/argo-cd/v3/util/assets"
|
||||
"github.com/argoproj/argo-cd/v3/util/cli"
|
||||
"github.com/argoproj/argo-cd/v3/util/errors"
|
||||
"github.com/argoproj/argo-cd/v3/util/rbac"
|
||||
)
|
||||
|
||||
@@ -28,98 +26,89 @@ type rbacTrait struct {
|
||||
allowPath bool
|
||||
}
|
||||
|
||||
// Provide a mapping of short-hand resource names to their RBAC counterparts
|
||||
// Provide a mapping of shorthand resource names to their RBAC counterparts
|
||||
var resourceMap = map[string]string{
|
||||
"account": rbacpolicy.ResourceAccounts,
|
||||
"app": rbacpolicy.ResourceApplications,
|
||||
"apps": rbacpolicy.ResourceApplications,
|
||||
"application": rbacpolicy.ResourceApplications,
|
||||
"applicationsets": rbacpolicy.ResourceApplicationSets,
|
||||
"cert": rbacpolicy.ResourceCertificates,
|
||||
"certs": rbacpolicy.ResourceCertificates,
|
||||
"certificate": rbacpolicy.ResourceCertificates,
|
||||
"cluster": rbacpolicy.ResourceClusters,
|
||||
"extension": rbacpolicy.ResourceExtensions,
|
||||
"gpgkey": rbacpolicy.ResourceGPGKeys,
|
||||
"key": rbacpolicy.ResourceGPGKeys,
|
||||
"log": rbacpolicy.ResourceLogs,
|
||||
"logs": rbacpolicy.ResourceLogs,
|
||||
"exec": rbacpolicy.ResourceExec,
|
||||
"proj": rbacpolicy.ResourceProjects,
|
||||
"projs": rbacpolicy.ResourceProjects,
|
||||
"project": rbacpolicy.ResourceProjects,
|
||||
"repo": rbacpolicy.ResourceRepositories,
|
||||
"repos": rbacpolicy.ResourceRepositories,
|
||||
"repository": rbacpolicy.ResourceRepositories,
|
||||
}
|
||||
|
||||
var projectScoped = map[string]bool{
|
||||
rbacpolicy.ResourceApplications: true,
|
||||
rbacpolicy.ResourceApplicationSets: true,
|
||||
rbacpolicy.ResourceLogs: true,
|
||||
rbacpolicy.ResourceExec: true,
|
||||
rbacpolicy.ResourceClusters: true,
|
||||
rbacpolicy.ResourceRepositories: true,
|
||||
"account": rbac.ResourceAccounts,
|
||||
"app": rbac.ResourceApplications,
|
||||
"apps": rbac.ResourceApplications,
|
||||
"application": rbac.ResourceApplications,
|
||||
"applicationsets": rbac.ResourceApplicationSets,
|
||||
"cert": rbac.ResourceCertificates,
|
||||
"certs": rbac.ResourceCertificates,
|
||||
"certificate": rbac.ResourceCertificates,
|
||||
"cluster": rbac.ResourceClusters,
|
||||
"extension": rbac.ResourceExtensions,
|
||||
"gpgkey": rbac.ResourceGPGKeys,
|
||||
"key": rbac.ResourceGPGKeys,
|
||||
"log": rbac.ResourceLogs,
|
||||
"logs": rbac.ResourceLogs,
|
||||
"exec": rbac.ResourceExec,
|
||||
"proj": rbac.ResourceProjects,
|
||||
"projs": rbac.ResourceProjects,
|
||||
"project": rbac.ResourceProjects,
|
||||
"repo": rbac.ResourceRepositories,
|
||||
"repos": rbac.ResourceRepositories,
|
||||
"repository": rbac.ResourceRepositories,
|
||||
}
|
||||
|
||||
// List of allowed RBAC resources
|
||||
var validRBACResourcesActions = map[string]actionTraitMap{
|
||||
rbacpolicy.ResourceAccounts: accountsActions,
|
||||
rbacpolicy.ResourceApplications: applicationsActions,
|
||||
rbacpolicy.ResourceApplicationSets: defaultCRUDActions,
|
||||
rbacpolicy.ResourceCertificates: defaultCRDActions,
|
||||
rbacpolicy.ResourceClusters: defaultCRUDActions,
|
||||
rbacpolicy.ResourceExtensions: extensionActions,
|
||||
rbacpolicy.ResourceGPGKeys: defaultCRDActions,
|
||||
rbacpolicy.ResourceLogs: logsActions,
|
||||
rbacpolicy.ResourceExec: execActions,
|
||||
rbacpolicy.ResourceProjects: defaultCRUDActions,
|
||||
rbacpolicy.ResourceRepositories: defaultCRUDActions,
|
||||
rbac.ResourceAccounts: accountsActions,
|
||||
rbac.ResourceApplications: applicationsActions,
|
||||
rbac.ResourceApplicationSets: defaultCRUDActions,
|
||||
rbac.ResourceCertificates: defaultCRDActions,
|
||||
rbac.ResourceClusters: defaultCRUDActions,
|
||||
rbac.ResourceExtensions: extensionActions,
|
||||
rbac.ResourceGPGKeys: defaultCRDActions,
|
||||
rbac.ResourceLogs: logsActions,
|
||||
rbac.ResourceExec: execActions,
|
||||
rbac.ResourceProjects: defaultCRUDActions,
|
||||
rbac.ResourceRepositories: defaultCRUDActions,
|
||||
}
|
||||
|
||||
// List of allowed RBAC actions
|
||||
var defaultCRUDActions = actionTraitMap{
|
||||
rbacpolicy.ActionCreate: rbacTrait{},
|
||||
rbacpolicy.ActionGet: rbacTrait{},
|
||||
rbacpolicy.ActionUpdate: rbacTrait{},
|
||||
rbacpolicy.ActionDelete: rbacTrait{},
|
||||
rbac.ActionCreate: rbacTrait{},
|
||||
rbac.ActionGet: rbacTrait{},
|
||||
rbac.ActionUpdate: rbacTrait{},
|
||||
rbac.ActionDelete: rbacTrait{},
|
||||
}
|
||||
|
||||
var defaultCRDActions = actionTraitMap{
|
||||
rbacpolicy.ActionCreate: rbacTrait{},
|
||||
rbacpolicy.ActionGet: rbacTrait{},
|
||||
rbacpolicy.ActionDelete: rbacTrait{},
|
||||
rbac.ActionCreate: rbacTrait{},
|
||||
rbac.ActionGet: rbacTrait{},
|
||||
rbac.ActionDelete: rbacTrait{},
|
||||
}
|
||||
|
||||
var applicationsActions = actionTraitMap{
|
||||
rbacpolicy.ActionCreate: rbacTrait{},
|
||||
rbacpolicy.ActionGet: rbacTrait{},
|
||||
rbacpolicy.ActionUpdate: rbacTrait{allowPath: true},
|
||||
rbacpolicy.ActionDelete: rbacTrait{allowPath: true},
|
||||
rbacpolicy.ActionAction: rbacTrait{allowPath: true},
|
||||
rbacpolicy.ActionOverride: rbacTrait{},
|
||||
rbacpolicy.ActionSync: rbacTrait{},
|
||||
rbac.ActionCreate: rbacTrait{},
|
||||
rbac.ActionGet: rbacTrait{},
|
||||
rbac.ActionUpdate: rbacTrait{allowPath: true},
|
||||
rbac.ActionDelete: rbacTrait{allowPath: true},
|
||||
rbac.ActionAction: rbacTrait{allowPath: true},
|
||||
rbac.ActionOverride: rbacTrait{},
|
||||
rbac.ActionSync: rbacTrait{},
|
||||
}
|
||||
|
||||
var accountsActions = actionTraitMap{
|
||||
rbacpolicy.ActionCreate: rbacTrait{},
|
||||
rbacpolicy.ActionUpdate: rbacTrait{},
|
||||
rbac.ActionCreate: rbacTrait{},
|
||||
rbac.ActionUpdate: rbacTrait{},
|
||||
}
|
||||
|
||||
var execActions = actionTraitMap{
|
||||
rbacpolicy.ActionCreate: rbacTrait{},
|
||||
rbac.ActionCreate: rbacTrait{},
|
||||
}
|
||||
|
||||
var logsActions = actionTraitMap{
|
||||
rbacpolicy.ActionGet: rbacTrait{},
|
||||
rbac.ActionGet: rbacTrait{},
|
||||
}
|
||||
|
||||
var extensionActions = actionTraitMap{
|
||||
rbacpolicy.ActionInvoke: rbacTrait{},
|
||||
rbac.ActionInvoke: rbacTrait{},
|
||||
}
|
||||
|
||||
// NewRBACCommand is the command for 'rbac'
|
||||
func NewRBACCommand(cmdCtx commandContext) *cobra.Command {
|
||||
func NewRBACCommand() *cobra.Command {
|
||||
command := &cobra.Command{
|
||||
Use: "rbac",
|
||||
Short: "Validate and test RBAC configuration",
|
||||
@@ -127,13 +116,13 @@ func NewRBACCommand(cmdCtx commandContext) *cobra.Command {
|
||||
c.HelpFunc()(c, args)
|
||||
},
|
||||
}
|
||||
command.AddCommand(NewRBACCanCommand(cmdCtx))
|
||||
command.AddCommand(NewRBACCanCommand())
|
||||
command.AddCommand(NewRBACValidateCommand())
|
||||
return command
|
||||
}
|
||||
|
||||
// NewRBACCanCommand is the command for 'rbac can'
|
||||
func NewRBACCanCommand(cmdCtx commandContext) *cobra.Command {
|
||||
func NewRBACCanCommand() *cobra.Command {
|
||||
var (
|
||||
policyFile string
|
||||
defaultRole string
|
||||
@@ -219,30 +208,7 @@ argocd admin settings rbac can someuser create application 'default/app' --defau
|
||||
defaultRole = newDefaultRole
|
||||
}
|
||||
|
||||
// Logs RBAC will be enforced only if an internal var serverRBACLogEnforceEnable
|
||||
// (representing server.rbac.log.enforce.enable env var in argocd-cm)
|
||||
// is defined and has a "true" value
|
||||
// Otherwise, no RBAC enforcement for logs will take place (meaning, 'can' request on a logs resource will result in "yes",
|
||||
// even if there is no explicit RBAC allow, or if there is an explicit RBAC deny)
|
||||
var isLogRbacEnforced func() bool
|
||||
if nsOverride && policyFile == "" {
|
||||
if resolveRBACResourceName(resource) == rbacpolicy.ResourceLogs {
|
||||
isLogRbacEnforced = func() bool {
|
||||
if opts, ok := cmdCtx.(*settingsOpts); ok {
|
||||
opts.loadClusterSettings = true
|
||||
opts.clientConfig = clientConfig
|
||||
settingsMgr, err := opts.createSettingsManager(ctx)
|
||||
errors.CheckError(err)
|
||||
logEnforceEnable, err := settingsMgr.GetServerRBACLogEnforceEnable()
|
||||
errors.CheckError(err)
|
||||
return logEnforceEnable
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
res := checkPolicy(subject, action, resource, subResource, builtinPolicy, userPolicy, defaultRole, matchMode, strict, isLogRbacEnforced)
|
||||
|
||||
res := checkPolicy(subject, action, resource, subResource, builtinPolicy, userPolicy, defaultRole, matchMode, strict)
|
||||
if res {
|
||||
if !quiet {
|
||||
fmt.Println("Yes")
|
||||
@@ -408,7 +374,7 @@ func getPolicyConfigMap(ctx context.Context, client kubernetes.Interface, namesp
|
||||
|
||||
// checkPolicy checks whether given subject is allowed to execute specified
|
||||
// action against specified resource
|
||||
func checkPolicy(subject, action, resource, subResource, builtinPolicy, userPolicy, defaultRole, matchMode string, strict bool, isLogRbacEnforced func() bool) bool {
|
||||
func checkPolicy(subject, action, resource, subResource, builtinPolicy, userPolicy, defaultRole, matchMode string, strict bool) bool {
|
||||
enf := rbac.NewEnforcer(nil, "argocd", "argocd-rbac-cm", nil)
|
||||
enf.SetDefaultRole(defaultRole)
|
||||
enf.SetMatchMode(matchMode)
|
||||
@@ -445,16 +411,11 @@ func checkPolicy(subject, action, resource, subResource, builtinPolicy, userPoli
|
||||
// Some project scoped resources have a special notation - for simplicity's sake,
|
||||
// if user gives no sub-resource (or specifies simple '*'), we construct
|
||||
// the required notation by setting subresource to '*/*'.
|
||||
if projectScoped[realResource] {
|
||||
if rbac.ProjectScoped[realResource] {
|
||||
if subResource == "*" || subResource == "" {
|
||||
subResource = "*/*"
|
||||
}
|
||||
}
|
||||
if realResource == rbacpolicy.ResourceLogs {
|
||||
if isLogRbacEnforced != nil && !isLogRbacEnforced() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return enf.Enforce(subject, realResource, action, subResource)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
@@ -14,7 +13,8 @@ import (
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/server/rbacpolicy"
|
||||
"github.com/argoproj/argo-cd/v3/util/rbac"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/util/assets"
|
||||
)
|
||||
|
||||
@@ -56,8 +56,8 @@ func Test_validateRBACResourceAction(t *testing.T) {
|
||||
{
|
||||
name: "Test valid resource and action",
|
||||
args: args{
|
||||
resource: rbacpolicy.ResourceApplications,
|
||||
action: rbacpolicy.ActionCreate,
|
||||
resource: rbac.ResourceApplications,
|
||||
action: rbac.ActionCreate,
|
||||
},
|
||||
valid: true,
|
||||
},
|
||||
@@ -71,7 +71,7 @@ func Test_validateRBACResourceAction(t *testing.T) {
|
||||
{
|
||||
name: "Test invalid action",
|
||||
args: args{
|
||||
resource: rbacpolicy.ResourceApplications,
|
||||
resource: rbac.ResourceApplications,
|
||||
action: "invalid",
|
||||
},
|
||||
valid: false,
|
||||
@@ -79,24 +79,24 @@ func Test_validateRBACResourceAction(t *testing.T) {
|
||||
{
|
||||
name: "Test invalid action for resource",
|
||||
args: args{
|
||||
resource: rbacpolicy.ResourceLogs,
|
||||
action: rbacpolicy.ActionCreate,
|
||||
resource: rbac.ResourceLogs,
|
||||
action: rbac.ActionCreate,
|
||||
},
|
||||
valid: false,
|
||||
},
|
||||
{
|
||||
name: "Test valid action with path",
|
||||
args: args{
|
||||
resource: rbacpolicy.ResourceApplications,
|
||||
action: rbacpolicy.ActionAction + "/apps/Deployment/restart",
|
||||
resource: rbac.ResourceApplications,
|
||||
action: rbac.ActionAction + "/apps/Deployment/restart",
|
||||
},
|
||||
valid: true,
|
||||
},
|
||||
{
|
||||
name: "Test invalid action with path",
|
||||
args: args{
|
||||
resource: rbacpolicy.ResourceApplications,
|
||||
action: rbacpolicy.ActionGet + "/apps/Deployment/restart",
|
||||
resource: rbac.ResourceApplications,
|
||||
action: rbac.ActionGet + "/apps/Deployment/restart",
|
||||
},
|
||||
valid: false,
|
||||
},
|
||||
@@ -115,7 +115,7 @@ func Test_validateRBACResourceAction(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_PolicyFromCSV(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
|
||||
uPol, dRole, matchMode := getPolicy(ctx, "testdata/rbac/policy.csv", nil, "")
|
||||
require.NotEmpty(t, uPol)
|
||||
@@ -124,27 +124,19 @@ func Test_PolicyFromCSV(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_PolicyFromYAML(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
|
||||
uPol, dRole, matchMode := getPolicy(ctx, "testdata/rbac/argocd-rbac-cm.yaml", nil, "")
|
||||
require.NotEmpty(t, uPol)
|
||||
require.Equal(t, "role:unknown", dRole)
|
||||
require.Empty(t, matchMode)
|
||||
require.True(t, checkPolicy("my-org:team-qa", "update", "project", "foo",
|
||||
"", uPol, dRole, matchMode, true, nil))
|
||||
}
|
||||
|
||||
func trueLogRbacEnforce() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func falseLogRbacEnforce() bool {
|
||||
return false
|
||||
"", uPol, dRole, matchMode, true))
|
||||
}
|
||||
|
||||
func Test_PolicyFromK8s(t *testing.T) {
|
||||
data, err := os.ReadFile("testdata/rbac/policy.csv")
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
|
||||
require.NoError(t, err)
|
||||
kubeclientset := fake.NewClientset(&corev1.ConfigMap{
|
||||
@@ -163,111 +155,69 @@ func Test_PolicyFromK8s(t *testing.T) {
|
||||
require.Equal(t, "", matchMode)
|
||||
|
||||
t.Run("get applications", func(t *testing.T) {
|
||||
ok := checkPolicy("role:user", "get", "applications", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, nil)
|
||||
ok := checkPolicy("role:user", "get", "applications", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true)
|
||||
require.True(t, ok)
|
||||
})
|
||||
t.Run("get clusters", func(t *testing.T) {
|
||||
ok := checkPolicy("role:user", "get", "clusters", "*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, nil)
|
||||
ok := checkPolicy("role:user", "get", "clusters", "*", assets.BuiltinPolicyCSV, uPol, dRole, "", true)
|
||||
require.True(t, ok)
|
||||
})
|
||||
t.Run("get certificates", func(t *testing.T) {
|
||||
ok := checkPolicy("role:user", "get", "certificates", "*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, nil)
|
||||
ok := checkPolicy("role:user", "get", "certificates", "*", assets.BuiltinPolicyCSV, uPol, dRole, "", true)
|
||||
require.False(t, ok)
|
||||
})
|
||||
t.Run("get certificates by default role", func(t *testing.T) {
|
||||
ok := checkPolicy("role:user", "get", "certificates", "*", assets.BuiltinPolicyCSV, uPol, "role:readonly", "glob", true, nil)
|
||||
ok := checkPolicy("role:user", "get", "certificates", "*", assets.BuiltinPolicyCSV, uPol, "role:readonly", "glob", true)
|
||||
require.True(t, ok)
|
||||
})
|
||||
t.Run("get certificates by default role without builtin policy", func(t *testing.T) {
|
||||
ok := checkPolicy("role:user", "get", "certificates", "*", "", uPol, "role:readonly", "glob", true, nil)
|
||||
ok := checkPolicy("role:user", "get", "certificates", "*", "", uPol, "role:readonly", "glob", true)
|
||||
require.False(t, ok)
|
||||
})
|
||||
t.Run("use regex match mode instead of glob", func(t *testing.T) {
|
||||
ok := checkPolicy("role:user", "get", "certificates", ".*", assets.BuiltinPolicyCSV, uPol, "role:readonly", "regex", true, nil)
|
||||
ok := checkPolicy("role:user", "get", "certificates", ".*", assets.BuiltinPolicyCSV, uPol, "role:readonly", "regex", true)
|
||||
require.False(t, ok)
|
||||
})
|
||||
t.Run("get logs", func(t *testing.T) {
|
||||
ok := checkPolicy("role:test", "get", "logs", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, nil)
|
||||
ok := checkPolicy("role:test", "get", "logs", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true)
|
||||
require.True(t, ok)
|
||||
})
|
||||
// no function is provided to check if logs rbac is enforced or not, so the policy permissions are queried to determine if no-such-user can get logs
|
||||
t.Run("no-such-user get logs", func(t *testing.T) {
|
||||
ok := checkPolicy("no-such-user", "get", "logs", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, nil)
|
||||
ok := checkPolicy("no-such-user", "get", "logs", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true)
|
||||
require.False(t, ok)
|
||||
})
|
||||
// logs rbac policy is enforced, and no-such-user is not granted logs permission in user policy, so the result should be false (cannot get logs)
|
||||
t.Run("no-such-user get logs rbac enforced", func(t *testing.T) {
|
||||
ok := checkPolicy("no-such-user", "get", "logs", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, trueLogRbacEnforce)
|
||||
require.False(t, ok)
|
||||
})
|
||||
// no-such-user is not granted logs permission in user policy, but logs rbac policy is not enforced, so logs permission is open to all
|
||||
t.Run("no-such-user get logs rbac not enforced", func(t *testing.T) {
|
||||
ok := checkPolicy("no-such-user", "get", "logs", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, falseLogRbacEnforce)
|
||||
require.True(t, ok)
|
||||
})
|
||||
// no function is provided to check if logs rbac is enforced or not, so the policy permissions are queried to determine if log-deny-user can get logs
|
||||
t.Run("log-deny-user get logs", func(t *testing.T) {
|
||||
ok := checkPolicy("log-deny-user", "get", "logs", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, nil)
|
||||
ok := checkPolicy("log-deny-user", "get", "logs", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true)
|
||||
require.False(t, ok)
|
||||
})
|
||||
// logs rbac policy is enforced, and log-deny-user is denied logs permission in user policy, so the result should be false (cannot get logs)
|
||||
t.Run("log-deny-user get logs rbac enforced", func(t *testing.T) {
|
||||
ok := checkPolicy("log-deny-user", "get", "logs", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, trueLogRbacEnforce)
|
||||
require.False(t, ok)
|
||||
})
|
||||
// log-deny-user is denied logs permission in user policy, but logs rbac policy is not enforced, so logs permission is open to all
|
||||
t.Run("log-deny-user get logs rbac not enforced", func(t *testing.T) {
|
||||
ok := checkPolicy("log-deny-user", "get", "logs", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, falseLogRbacEnforce)
|
||||
require.True(t, ok)
|
||||
})
|
||||
// no function is provided to check if logs rbac is enforced or not, so the policy permissions are queried to determine if log-allow-user can get logs
|
||||
t.Run("log-allow-user get logs", func(t *testing.T) {
|
||||
ok := checkPolicy("log-allow-user", "get", "logs", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, nil)
|
||||
require.True(t, ok)
|
||||
})
|
||||
// logs rbac policy is enforced, and log-allow-user is granted logs permission in user policy, so the result should be true (can get logs)
|
||||
t.Run("log-allow-user get logs rbac enforced", func(t *testing.T) {
|
||||
ok := checkPolicy("log-allow-user", "get", "logs", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, trueLogRbacEnforce)
|
||||
require.True(t, ok)
|
||||
})
|
||||
// log-allow-user is granted logs permission in user policy, and logs rbac policy is not enforced, so logs permission is open to all
|
||||
t.Run("log-allow-user get logs rbac not enforced", func(t *testing.T) {
|
||||
ok := checkPolicy("log-allow-user", "get", "logs", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, falseLogRbacEnforce)
|
||||
ok := checkPolicy("log-allow-user", "get", "logs", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true)
|
||||
require.True(t, ok)
|
||||
})
|
||||
t.Run("get logs", func(t *testing.T) {
|
||||
ok := checkPolicy("role:test", "get", "logs", "*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, nil)
|
||||
ok := checkPolicy("role:test", "get", "logs", "*", assets.BuiltinPolicyCSV, uPol, dRole, "", true)
|
||||
require.True(t, ok)
|
||||
})
|
||||
t.Run("get logs", func(t *testing.T) {
|
||||
ok := checkPolicy("role:test", "get", "logs", "", assets.BuiltinPolicyCSV, uPol, dRole, "", true, nil)
|
||||
ok := checkPolicy("role:test", "get", "logs", "", assets.BuiltinPolicyCSV, uPol, dRole, "", true)
|
||||
require.True(t, ok)
|
||||
})
|
||||
t.Run("create exec", func(t *testing.T) {
|
||||
ok := checkPolicy("role:test", "create", "exec", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, nil)
|
||||
ok := checkPolicy("role:test", "create", "exec", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true)
|
||||
require.True(t, ok)
|
||||
})
|
||||
t.Run("create applicationsets", func(t *testing.T) {
|
||||
ok := checkPolicy("role:user", "create", "applicationsets", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, nil)
|
||||
require.True(t, ok)
|
||||
})
|
||||
// trueLogRbacEnforce or falseLogRbacEnforce should not affect non-logs resources
|
||||
t.Run("create applicationsets with trueLogRbacEnforce", func(t *testing.T) {
|
||||
ok := checkPolicy("role:user", "create", "applicationsets", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, trueLogRbacEnforce)
|
||||
require.True(t, ok)
|
||||
})
|
||||
t.Run("create applicationsets with falseLogRbacEnforce", func(t *testing.T) {
|
||||
ok := checkPolicy("role:user", "create", "applicationsets", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, trueLogRbacEnforce)
|
||||
ok := checkPolicy("role:user", "create", "applicationsets", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true)
|
||||
require.True(t, ok)
|
||||
})
|
||||
t.Run("delete applicationsets", func(t *testing.T) {
|
||||
ok := checkPolicy("role:user", "delete", "applicationsets", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, nil)
|
||||
ok := checkPolicy("role:user", "delete", "applicationsets", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true)
|
||||
require.True(t, ok)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_PolicyFromK8sUsingRegex(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
|
||||
policy := `
|
||||
p, role:user, clusters, get, .+, allow
|
||||
@@ -301,49 +251,49 @@ p, role:readonly, certificates, get, .*, allow
|
||||
p, role:, certificates, get, .*, allow`
|
||||
|
||||
t.Run("get applications", func(t *testing.T) {
|
||||
ok := checkPolicy("role:user", "get", "applications", ".*/.*", builtInPolicy, uPol, dRole, "regex", true, nil)
|
||||
ok := checkPolicy("role:user", "get", "applications", ".*/.*", builtInPolicy, uPol, dRole, "regex", true)
|
||||
require.True(t, ok)
|
||||
})
|
||||
t.Run("get clusters", func(t *testing.T) {
|
||||
ok := checkPolicy("role:user", "get", "clusters", ".*", builtInPolicy, uPol, dRole, "regex", true, nil)
|
||||
ok := checkPolicy("role:user", "get", "clusters", ".*", builtInPolicy, uPol, dRole, "regex", true)
|
||||
require.True(t, ok)
|
||||
})
|
||||
t.Run("get certificates", func(t *testing.T) {
|
||||
ok := checkPolicy("role:user", "get", "certificates", ".*", builtInPolicy, uPol, dRole, "regex", true, nil)
|
||||
ok := checkPolicy("role:user", "get", "certificates", ".*", builtInPolicy, uPol, dRole, "regex", true)
|
||||
require.False(t, ok)
|
||||
})
|
||||
t.Run("get certificates by default role", func(t *testing.T) {
|
||||
ok := checkPolicy("role:user", "get", "certificates", ".*", builtInPolicy, uPol, "role:readonly", "regex", true, nil)
|
||||
ok := checkPolicy("role:user", "get", "certificates", ".*", builtInPolicy, uPol, "role:readonly", "regex", true)
|
||||
require.True(t, ok)
|
||||
})
|
||||
t.Run("get certificates by default role without builtin policy", func(t *testing.T) {
|
||||
ok := checkPolicy("role:user", "get", "certificates", ".*", "", uPol, "role:readonly", "regex", true, nil)
|
||||
ok := checkPolicy("role:user", "get", "certificates", ".*", "", uPol, "role:readonly", "regex", true)
|
||||
require.False(t, ok)
|
||||
})
|
||||
t.Run("use glob match mode instead of regex", func(t *testing.T) {
|
||||
ok := checkPolicy("role:user", "get", "certificates", ".+", builtInPolicy, uPol, dRole, "glob", true, nil)
|
||||
ok := checkPolicy("role:user", "get", "certificates", ".+", builtInPolicy, uPol, dRole, "glob", true)
|
||||
require.False(t, ok)
|
||||
})
|
||||
t.Run("get logs via glob match mode", func(t *testing.T) {
|
||||
ok := checkPolicy("role:user", "get", "logs", ".*/.*", builtInPolicy, uPol, dRole, "glob", true, nil)
|
||||
ok := checkPolicy("role:user", "get", "logs", ".*/.*", builtInPolicy, uPol, dRole, "glob", true)
|
||||
require.True(t, ok)
|
||||
})
|
||||
t.Run("create exec", func(t *testing.T) {
|
||||
ok := checkPolicy("role:user", "create", "exec", ".*/.*", builtInPolicy, uPol, dRole, "regex", true, nil)
|
||||
ok := checkPolicy("role:user", "create", "exec", ".*/.*", builtInPolicy, uPol, dRole, "regex", true)
|
||||
require.True(t, ok)
|
||||
})
|
||||
t.Run("create applicationsets", func(t *testing.T) {
|
||||
ok := checkPolicy("role:user", "create", "applicationsets", ".*/.*", builtInPolicy, uPol, dRole, "regex", true, nil)
|
||||
ok := checkPolicy("role:user", "create", "applicationsets", ".*/.*", builtInPolicy, uPol, dRole, "regex", true)
|
||||
require.True(t, ok)
|
||||
})
|
||||
t.Run("delete applicationsets", func(t *testing.T) {
|
||||
ok := checkPolicy("role:user", "delete", "applicationsets", ".*/.*", builtInPolicy, uPol, dRole, "regex", true, nil)
|
||||
ok := checkPolicy("role:user", "delete", "applicationsets", ".*/.*", builtInPolicy, uPol, dRole, "regex", true)
|
||||
require.True(t, ok)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNewRBACCanCommand(t *testing.T) {
|
||||
command := NewRBACCanCommand(&settingsOpts{})
|
||||
command := NewRBACCanCommand()
|
||||
|
||||
require.NotNil(t, command)
|
||||
assert.Equal(t, "can", command.Name())
|
||||
|
||||
@@ -88,7 +88,7 @@ type validatorTestCase struct {
|
||||
}
|
||||
|
||||
func TestCreateSettingsManager(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
|
||||
f, closer, err := tempFile(`apiVersion: v1
|
||||
kind: ConfigMap
|
||||
@@ -157,15 +157,6 @@ clientSecret: aaaabbbbccccddddeee`,
|
||||
},
|
||||
containsSummary: "updated-options",
|
||||
},
|
||||
"Repositories": {
|
||||
validator: "repositories",
|
||||
data: map[string]string{
|
||||
"repositories": `
|
||||
- url: https://github.com/argoproj/my-private-repository1
|
||||
- url: https://github.com/argoproj/my-private-repository2`,
|
||||
},
|
||||
containsSummary: "2 repositories",
|
||||
},
|
||||
"Accounts": {
|
||||
validator: "accounts",
|
||||
data: map[string]string{
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
"github.com/argoproj/gitops-engine/pkg/sync/hook"
|
||||
"github.com/argoproj/gitops-engine/pkg/sync/ignore"
|
||||
"github.com/argoproj/gitops-engine/pkg/utils/kube"
|
||||
grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/retry"
|
||||
grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/retry"
|
||||
"github.com/mattn/go-isatty"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -276,7 +276,7 @@ func hasAppChanged(appReq, appRes *argoappv1.Application, upsert bool) bool {
|
||||
}
|
||||
|
||||
func parentChildDetails(ctx context.Context, appIf application.ApplicationServiceClient, appName string, appNs string) (map[string]argoappv1.ResourceNode, map[string][]string, map[string]struct{}) {
|
||||
mapUidToNode := make(map[string]argoappv1.ResourceNode)
|
||||
mapUIDToNode := make(map[string]argoappv1.ResourceNode)
|
||||
mapParentToChild := make(map[string][]string)
|
||||
parentNode := make(map[string]struct{})
|
||||
|
||||
@@ -284,7 +284,7 @@ func parentChildDetails(ctx context.Context, appIf application.ApplicationServic
|
||||
errors.CheckError(err)
|
||||
|
||||
for _, node := range resourceTree.Nodes {
|
||||
mapUidToNode[node.UID] = node
|
||||
mapUIDToNode[node.UID] = node
|
||||
|
||||
if len(node.ParentRefs) > 0 {
|
||||
_, ok := mapParentToChild[node.ParentRefs[0].UID]
|
||||
@@ -297,7 +297,7 @@ func parentChildDetails(ctx context.Context, appIf application.ApplicationServic
|
||||
parentNode[node.UID] = struct{}{}
|
||||
}
|
||||
}
|
||||
return mapUidToNode, mapParentToChild, parentNode
|
||||
return mapUIDToNode, mapParentToChild, parentNode
|
||||
}
|
||||
|
||||
func printHeader(ctx context.Context, acdClient argocdclient.Client, app *argoappv1.Application, windows *argoappv1.SyncWindows, showOperation bool, showParams bool, sourcePosition int) {
|
||||
@@ -444,17 +444,17 @@ func NewApplicationGetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Com
|
||||
}
|
||||
case "tree":
|
||||
printHeader(ctx, acdClient, app, windows, showOperation, showParams, sourcePosition)
|
||||
mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState := resourceParentChild(ctx, acdClient, appName, appNs)
|
||||
if len(mapUidToNode) > 0 {
|
||||
mapUIDToNode, mapParentToChild, parentNode, mapNodeNameToResourceState := resourceParentChild(ctx, acdClient, appName, appNs)
|
||||
if len(mapUIDToNode) > 0 {
|
||||
fmt.Println()
|
||||
printTreeView(mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState)
|
||||
printTreeView(mapUIDToNode, mapParentToChild, parentNode, mapNodeNameToResourceState)
|
||||
}
|
||||
case "tree=detailed":
|
||||
printHeader(ctx, acdClient, app, windows, showOperation, showParams, sourcePosition)
|
||||
mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState := resourceParentChild(ctx, acdClient, appName, appNs)
|
||||
if len(mapUidToNode) > 0 {
|
||||
mapUIDToNode, mapParentToChild, parentNode, mapNodeNameToResourceState := resourceParentChild(ctx, acdClient, appName, appNs)
|
||||
if len(mapUIDToNode) > 0 {
|
||||
fmt.Println()
|
||||
printTreeViewDetailed(mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState)
|
||||
printTreeViewDetailed(mapUIDToNode, mapParentToChild, parentNode, mapNodeNameToResourceState)
|
||||
}
|
||||
default:
|
||||
errors.CheckError(fmt.Errorf("unknown output format: %s", output))
|
||||
@@ -486,6 +486,7 @@ func NewApplicationLogsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
||||
filter string
|
||||
container string
|
||||
previous bool
|
||||
matchCase bool
|
||||
)
|
||||
command := &cobra.Command{
|
||||
Use: "logs APPNAME",
|
||||
@@ -521,6 +522,9 @@ func NewApplicationLogsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
||||
# Filter logs to show only those containing a specific string
|
||||
argocd app logs my-app --filter "error"
|
||||
|
||||
# Filter logs to show only those containing a specific string and match case
|
||||
argocd app logs my-app --filter "error" --match-case
|
||||
|
||||
# Get logs for a specific container within the pods
|
||||
argocd app logs my-app -c my-container
|
||||
|
||||
@@ -554,6 +558,7 @@ func NewApplicationLogsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
||||
SinceSeconds: ptr.To(sinceSeconds),
|
||||
UntilTime: &untilTime,
|
||||
Filter: &filter,
|
||||
MatchCase: ptr.To(matchCase),
|
||||
Container: ptr.To(container),
|
||||
Previous: ptr.To(previous),
|
||||
AppNamespace: &appNs,
|
||||
@@ -598,6 +603,7 @@ func NewApplicationLogsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
||||
command.Flags().StringVar(&filter, "filter", "", "Show logs contain this string")
|
||||
command.Flags().StringVarP(&container, "container", "c", "", "Optional container name")
|
||||
command.Flags().BoolVarP(&previous, "previous", "p", false, "Specify if the previously terminated container logs should be returned")
|
||||
command.Flags().BoolVarP(&matchCase, "match-case", "m", false, "Specify if the filter should be case-sensitive")
|
||||
|
||||
return command
|
||||
}
|
||||
@@ -887,6 +893,7 @@ type unsetOpts struct {
|
||||
kustomizeNamespace bool
|
||||
kustomizeImages []string
|
||||
kustomizeReplicas []string
|
||||
ignoreMissingComponents bool
|
||||
parameters []string
|
||||
valuesFiles []string
|
||||
valuesLiteral bool
|
||||
@@ -903,6 +910,7 @@ func (o *unsetOpts) KustomizeIsZero() bool {
|
||||
!o.nameSuffix &&
|
||||
!o.kustomizeVersion &&
|
||||
!o.kustomizeNamespace &&
|
||||
!o.ignoreMissingComponents &&
|
||||
len(o.kustomizeImages) == 0 &&
|
||||
len(o.kustomizeReplicas) == 0
|
||||
}
|
||||
@@ -1008,6 +1016,7 @@ func NewApplicationUnsetCommand(clientOpts *argocdclient.ClientOptions) *cobra.C
|
||||
command.Flags().BoolVar(&opts.kustomizeNamespace, "kustomize-namespace", false, "Kustomize namespace")
|
||||
command.Flags().StringArrayVar(&opts.kustomizeImages, "kustomize-image", []string{}, "Kustomize images name (e.g. --kustomize-image node --kustomize-image mysql)")
|
||||
command.Flags().StringArrayVar(&opts.kustomizeReplicas, "kustomize-replica", []string{}, "Kustomize replicas name (e.g. --kustomize-replica my-deployment --kustomize-replica my-statefulset)")
|
||||
command.Flags().BoolVar(&opts.ignoreMissingComponents, "ignore-missing-components", false, "Unset the kustomize ignore-missing-components option (revert to false)")
|
||||
command.Flags().StringArrayVar(&opts.pluginEnvs, "plugin-env", []string{}, "Unset plugin env variables (e.g --plugin-env name)")
|
||||
command.Flags().BoolVar(&opts.passCredentials, "pass-credentials", false, "Unset passCredentials")
|
||||
command.Flags().BoolVar(&opts.ref, "ref", false, "Unset ref on the source")
|
||||
@@ -1048,6 +1057,11 @@ func unset(source *argoappv1.ApplicationSource, opts unsetOpts) (updated bool, n
|
||||
source.Kustomize.Namespace = ""
|
||||
}
|
||||
|
||||
if opts.ignoreMissingComponents && source.Kustomize.IgnoreMissingComponents {
|
||||
source.Kustomize.IgnoreMissingComponents = false
|
||||
updated = true
|
||||
}
|
||||
|
||||
for _, kustomizeImage := range opts.kustomizeImages {
|
||||
for i, item := range source.Kustomize.Images {
|
||||
if argoappv1.KustomizeImage(kustomizeImage).Match(item) {
|
||||
@@ -2492,14 +2506,14 @@ func checkResourceStatus(watch watchOpts, healthStatus string, syncStatus string
|
||||
// constructs the necessary data structures to print the app as a tree.
|
||||
func resourceParentChild(ctx context.Context, acdClient argocdclient.Client, appName string, appNs string) (map[string]argoappv1.ResourceNode, map[string][]string, map[string]struct{}, map[string]*resourceState) {
|
||||
_, appIf := acdClient.NewApplicationClientOrDie()
|
||||
mapUidToNode, mapParentToChild, parentNode := parentChildDetails(ctx, appIf, appName, appNs)
|
||||
mapUIDToNode, mapParentToChild, parentNode := parentChildDetails(ctx, appIf, appName, appNs)
|
||||
app, err := appIf.Get(ctx, &application.ApplicationQuery{Name: ptr.To(appName), AppNamespace: ptr.To(appNs)})
|
||||
errors.CheckError(err)
|
||||
mapNodeNameToResourceState := make(map[string]*resourceState)
|
||||
for _, res := range getResourceStates(app, nil) {
|
||||
mapNodeNameToResourceState[res.Kind+"/"+res.Name] = res
|
||||
}
|
||||
return mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState
|
||||
return mapUIDToNode, mapParentToChild, parentNode, mapNodeNameToResourceState
|
||||
}
|
||||
|
||||
const waitFormatString = "%s\t%5s\t%10s\t%10s\t%20s\t%8s\t%7s\t%10s\t%s\n"
|
||||
@@ -2557,16 +2571,17 @@ func waitOnApplicationStatus(ctx context.Context, acdClient argocdclient.Client,
|
||||
_ = w.Flush()
|
||||
}
|
||||
case "tree":
|
||||
mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState := resourceParentChild(ctx, acdClient, appRealName, appNs)
|
||||
if len(mapUidToNode) > 0 {
|
||||
mapUIDToNode, mapParentToChild, parentNode, mapNodeNameToResourceState := resourceParentChild(ctx, acdClient, appRealName, appNs)
|
||||
if len(mapUIDToNode) > 0 {
|
||||
fmt.Println()
|
||||
printTreeView(mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState)
|
||||
printTreeView(mapUIDToNode, mapParentToChild, parentNode, mapNodeNameToResourceState)
|
||||
}
|
||||
case "tree=detailed":
|
||||
mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState := resourceParentChild(ctx, acdClient, appRealName, appNs)
|
||||
if len(mapUidToNode) > 0 {
|
||||
|
||||
mapUIDToNode, mapParentToChild, parentNode, mapNodeNameToResourceState := resourceParentChild(ctx, acdClient, appRealName, appNs)
|
||||
if len(mapUIDToNode) > 0 {
|
||||
fmt.Println()
|
||||
printTreeViewDetailed(mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState)
|
||||
printTreeViewDetailed(mapUIDToNode, mapParentToChild, parentNode, mapNodeNameToResourceState)
|
||||
}
|
||||
default:
|
||||
errors.CheckError(fmt.Errorf("unknown output format: %s", output))
|
||||
@@ -2733,7 +2748,7 @@ func setParameterOverrides(app *argoappv1.Application, parameters []string, sour
|
||||
}
|
||||
|
||||
// Print list of history ID's for an application.
|
||||
func printApplicationHistoryIds(revHistory []argoappv1.RevisionHistory) {
|
||||
func printApplicationHistoryIDs(revHistory []argoappv1.RevisionHistory) {
|
||||
for _, depInfo := range revHistory {
|
||||
fmt.Println(depInfo.ID)
|
||||
}
|
||||
@@ -2741,7 +2756,7 @@ func printApplicationHistoryIds(revHistory []argoappv1.RevisionHistory) {
|
||||
|
||||
// Print a history table for an application.
|
||||
func printApplicationHistoryTable(revHistory []argoappv1.RevisionHistory) {
|
||||
MAX_ALLOWED_REVISIONS := 7
|
||||
maxAllowedRevisions := 7
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
type history struct {
|
||||
id int64
|
||||
@@ -2754,8 +2769,8 @@ func printApplicationHistoryTable(revHistory []argoappv1.RevisionHistory) {
|
||||
if depInfo.Sources != nil {
|
||||
for i, sourceInfo := range depInfo.Sources {
|
||||
rev := sourceInfo.TargetRevision
|
||||
if len(depInfo.Revisions) == len(depInfo.Sources) && len(depInfo.Revisions[i]) >= MAX_ALLOWED_REVISIONS {
|
||||
rev = fmt.Sprintf("%s (%s)", rev, depInfo.Revisions[i][0:MAX_ALLOWED_REVISIONS])
|
||||
if len(depInfo.Revisions) == len(depInfo.Sources) && len(depInfo.Revisions[i]) >= maxAllowedRevisions {
|
||||
rev = fmt.Sprintf("%s (%s)", rev, depInfo.Revisions[i][0:maxAllowedRevisions])
|
||||
}
|
||||
if _, ok := varHistory[sourceInfo.RepoURL]; !ok {
|
||||
varHistoryKeys = append(varHistoryKeys, sourceInfo.RepoURL)
|
||||
@@ -2768,8 +2783,8 @@ func printApplicationHistoryTable(revHistory []argoappv1.RevisionHistory) {
|
||||
}
|
||||
} else {
|
||||
rev := depInfo.Source.TargetRevision
|
||||
if len(depInfo.Revision) >= MAX_ALLOWED_REVISIONS {
|
||||
rev = fmt.Sprintf("%s (%s)", rev, depInfo.Revision[0:MAX_ALLOWED_REVISIONS])
|
||||
if len(depInfo.Revision) >= maxAllowedRevisions {
|
||||
rev = fmt.Sprintf("%s (%s)", rev, depInfo.Revision[0:maxAllowedRevisions])
|
||||
}
|
||||
if _, ok := varHistory[depInfo.Source.RepoURL]; !ok {
|
||||
varHistoryKeys = append(varHistoryKeys, depInfo.Source.RepoURL)
|
||||
@@ -2821,7 +2836,7 @@ func NewApplicationHistoryCommand(clientOpts *argocdclient.ClientOptions) *cobra
|
||||
errors.CheckError(err)
|
||||
|
||||
if output == "id" {
|
||||
printApplicationHistoryIds(app.Status.History)
|
||||
printApplicationHistoryIDs(app.Status.History)
|
||||
} else {
|
||||
printApplicationHistoryTable(app.Status.History)
|
||||
}
|
||||
|
||||
@@ -164,12 +164,12 @@ func NewApplicationDeleteResourceCommand(clientOpts *argocdclient.ClientOptions)
|
||||
}
|
||||
|
||||
func parentChildInfo(nodes []v1alpha1.ResourceNode) (map[string]v1alpha1.ResourceNode, map[string][]string, map[string]struct{}) {
|
||||
mapUidToNode := make(map[string]v1alpha1.ResourceNode)
|
||||
mapUIDToNode := make(map[string]v1alpha1.ResourceNode)
|
||||
mapParentToChild := make(map[string][]string)
|
||||
parentNode := make(map[string]struct{})
|
||||
|
||||
for _, node := range nodes {
|
||||
mapUidToNode[node.UID] = node
|
||||
mapUIDToNode[node.UID] = node
|
||||
|
||||
if len(node.ParentRefs) > 0 {
|
||||
_, ok := mapParentToChild[node.ParentRefs[0].UID]
|
||||
@@ -182,7 +182,7 @@ func parentChildInfo(nodes []v1alpha1.ResourceNode) (map[string]v1alpha1.Resourc
|
||||
parentNode[node.UID] = struct{}{}
|
||||
}
|
||||
}
|
||||
return mapUidToNode, mapParentToChild, parentNode
|
||||
return mapUIDToNode, mapParentToChild, parentNode
|
||||
}
|
||||
|
||||
func printDetailedTreeViewAppResourcesNotOrphaned(nodeMapping map[string]v1alpha1.ResourceNode, parentChildMapping map[string][]string, parentNodes map[string]struct{}, w *tabwriter.Writer) {
|
||||
@@ -216,25 +216,25 @@ func printResources(listAll bool, orphaned bool, appResourceTree *v1alpha1.Appli
|
||||
fmt.Fprintf(w, "GROUP\tKIND\tNAMESPACE\tNAME\tORPHANED\tAGE\tHEALTH\tREASON\n")
|
||||
|
||||
if !orphaned || listAll {
|
||||
mapUidToNode, mapParentToChild, parentNode := parentChildInfo(appResourceTree.Nodes)
|
||||
printDetailedTreeViewAppResourcesNotOrphaned(mapUidToNode, mapParentToChild, parentNode, w)
|
||||
mapUIDToNode, mapParentToChild, parentNode := parentChildInfo(appResourceTree.Nodes)
|
||||
printDetailedTreeViewAppResourcesNotOrphaned(mapUIDToNode, mapParentToChild, parentNode, w)
|
||||
}
|
||||
|
||||
if orphaned || listAll {
|
||||
mapUidToNode, mapParentToChild, parentNode := parentChildInfo(appResourceTree.OrphanedNodes)
|
||||
printDetailedTreeViewAppResourcesOrphaned(mapUidToNode, mapParentToChild, parentNode, w)
|
||||
mapUIDToNode, mapParentToChild, parentNode := parentChildInfo(appResourceTree.OrphanedNodes)
|
||||
printDetailedTreeViewAppResourcesOrphaned(mapUIDToNode, mapParentToChild, parentNode, w)
|
||||
}
|
||||
case "tree":
|
||||
fmt.Fprintf(w, "GROUP\tKIND\tNAMESPACE\tNAME\tORPHANED\n")
|
||||
|
||||
if !orphaned || listAll {
|
||||
mapUidToNode, mapParentToChild, parentNode := parentChildInfo(appResourceTree.Nodes)
|
||||
printTreeViewAppResourcesNotOrphaned(mapUidToNode, mapParentToChild, parentNode, w)
|
||||
mapUIDToNode, mapParentToChild, parentNode := parentChildInfo(appResourceTree.Nodes)
|
||||
printTreeViewAppResourcesNotOrphaned(mapUIDToNode, mapParentToChild, parentNode, w)
|
||||
}
|
||||
|
||||
if orphaned || listAll {
|
||||
mapUidToNode, mapParentToChild, parentNode := parentChildInfo(appResourceTree.OrphanedNodes)
|
||||
printTreeViewAppResourcesOrphaned(mapUidToNode, mapParentToChild, parentNode, w)
|
||||
mapUIDToNode, mapParentToChild, parentNode := parentChildInfo(appResourceTree.OrphanedNodes)
|
||||
printTreeViewAppResourcesOrphaned(mapUIDToNode, mapParentToChild, parentNode, w)
|
||||
}
|
||||
default:
|
||||
headers := []any{"GROUP", "KIND", "NAMESPACE", "NAME", "ORPHANED"}
|
||||
|
||||
@@ -1029,11 +1029,10 @@ func TestTargetObjects_invalid(t *testing.T) {
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestCheckForDeleteEvent(_ *testing.T) {
|
||||
ctx := context.Background()
|
||||
func TestCheckForDeleteEvent(t *testing.T) {
|
||||
fakeClient := new(fakeAcdClient)
|
||||
|
||||
checkForDeleteEvent(ctx, fakeClient, "testApp")
|
||||
checkForDeleteEvent(t.Context(), fakeClient, "testApp")
|
||||
}
|
||||
|
||||
func TestPrintApplicationNames(t *testing.T) {
|
||||
@@ -1053,9 +1052,10 @@ func TestPrintApplicationNames(t *testing.T) {
|
||||
func Test_unset(t *testing.T) {
|
||||
kustomizeSource := &v1alpha1.ApplicationSource{
|
||||
Kustomize: &v1alpha1.ApplicationSourceKustomize{
|
||||
NamePrefix: "some-prefix",
|
||||
NameSuffix: "some-suffix",
|
||||
Version: "123",
|
||||
IgnoreMissingComponents: true,
|
||||
NamePrefix: "some-prefix",
|
||||
NameSuffix: "some-suffix",
|
||||
Version: "123",
|
||||
Images: v1alpha1.KustomizeImages{
|
||||
"old1=new:tag",
|
||||
"old2=new:tag",
|
||||
@@ -1155,6 +1155,15 @@ func Test_unset(t *testing.T) {
|
||||
assert.False(t, updated)
|
||||
assert.False(t, nothingToUnset)
|
||||
|
||||
assert.True(t, kustomizeSource.Kustomize.IgnoreMissingComponents)
|
||||
updated, nothingToUnset = unset(kustomizeSource, unsetOpts{ignoreMissingComponents: true})
|
||||
assert.False(t, kustomizeSource.Kustomize.IgnoreMissingComponents)
|
||||
assert.True(t, updated)
|
||||
assert.False(t, nothingToUnset)
|
||||
updated, nothingToUnset = unset(kustomizeSource, unsetOpts{ignoreMissingComponents: true})
|
||||
assert.False(t, updated)
|
||||
assert.False(t, nothingToUnset)
|
||||
|
||||
assert.Len(t, helmSource.Helm.Parameters, 2)
|
||||
updated, nothingToUnset = unset(helmSource, unsetOpts{parameters: []string{"name-1"}})
|
||||
assert.Len(t, helmSource.Helm.Parameters, 1)
|
||||
@@ -1862,7 +1871,7 @@ func testApp(name, project string, labels map[string]string, annotations map[str
|
||||
|
||||
func TestWaitOnApplicationStatus_JSON_YAML_WideOutput(t *testing.T) {
|
||||
acdClient := &customAcdClient{&fakeAcdClient{}}
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
var selectResource []*v1alpha1.SyncOperationResource
|
||||
watch := watchOpts{
|
||||
sync: false,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user