mirror of
https://github.com/argoproj/argo-cd.git
synced 2026-02-20 17:48:47 +01:00
Compare commits
85 Commits
appsetdocs
...
update-ver
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1d77740f95 | ||
|
|
58ded15863 | ||
|
|
8d0279895c | ||
|
|
6207fd0040 | ||
|
|
3875dde5cc | ||
|
|
17a535f6d4 | ||
|
|
180d6890af | ||
|
|
6ef7f61d9a | ||
|
|
c7937f101c | ||
|
|
03600ae7ac | ||
|
|
c6112c05fe | ||
|
|
49771c1d4f | ||
|
|
102853d31a | ||
|
|
10b9589f1c | ||
|
|
53dc116353 | ||
|
|
99aaf43bdb | ||
|
|
c8a62bb162 | ||
|
|
fd67e4970f | ||
|
|
2618ccca2d | ||
|
|
38e02ab9e8 | ||
|
|
2fe4536ed2 | ||
|
|
49163b09b1 | ||
|
|
c0f847f301 | ||
|
|
2e794fbbc5 | ||
|
|
a25c8a0eef | ||
|
|
c76a131b17 | ||
|
|
64a14a08e0 | ||
|
|
09eede0c17 | ||
|
|
f260510f38 | ||
|
|
079754c639 | ||
|
|
dc43124058 | ||
|
|
b6af657295 | ||
|
|
a3624a3f20 | ||
|
|
01ae20d1b3 | ||
|
|
89ef3563db | ||
|
|
831e4525c3 | ||
|
|
f8d6665c67 | ||
|
|
0680ddbdf9 | ||
|
|
ad36916ec4 | ||
|
|
af54ef8db5 | ||
|
|
68606c6caf | ||
|
|
6a8cb6eff0 | ||
|
|
d03ccf305c | ||
|
|
7f45c9e093 | ||
|
|
449e6939b2 | ||
|
|
99aab9a5f3 | ||
|
|
347f221adb | ||
|
|
1fcbe3f511 | ||
|
|
d417417c21 | ||
|
|
e7f98814a9 | ||
|
|
3f708b8b14 | ||
|
|
7bc333d193 | ||
|
|
e3b1d9327d | ||
|
|
deb07ee698 | ||
|
|
435989c07e | ||
|
|
2503eb32af | ||
|
|
be57dfe1fa | ||
|
|
e99c8b754b | ||
|
|
2076b4f73c | ||
|
|
5c595d8410 | ||
|
|
8340e1e43f | ||
|
|
1cddb8e607 | ||
|
|
262c8fa529 | ||
|
|
97a49a24cc | ||
|
|
a9a8d0e45f | ||
|
|
92de225ce5 | ||
|
|
a713e5023a | ||
|
|
ec60abd4d8 | ||
|
|
c6d9d50ee9 | ||
|
|
7244b8b40f | ||
|
|
8e81bb6c80 | ||
|
|
3bc2e1ae4c | ||
|
|
61f63f35ae | ||
|
|
5eb1f9bd16 | ||
|
|
4149f484bf | ||
|
|
0b2895977e | ||
|
|
99b30a87a6 | ||
|
|
9fc6ec116d | ||
|
|
f7f553f675 | ||
|
|
a9d9d07edd | ||
|
|
0f083c9e58 | ||
|
|
5392ca7e79 | ||
|
|
243ecc2f25 | ||
|
|
425b4087f3 | ||
|
|
74a367d10e |
5
.gitattributes
vendored
5
.gitattributes
vendored
@@ -5,14 +5,9 @@ docs/operator-manual/resource_actions_builtin.md linguist-generated=true
|
||||
docs/operator-manual/server-commands/argocd-*.md linguist-generated=true
|
||||
docs/user-guide/commands/argocd_*.md linguist-generated=true
|
||||
manifests/core-install.yaml linguist-generated=true
|
||||
manifests/core-install-with-hydrator.yaml linguist-generated=true
|
||||
manifests/crds/*-crd.yaml linguist-generated=true
|
||||
manifests/ha/install.yaml linguist-generated=true
|
||||
manifests/ha/install-with-hydrator.yaml linguist-generated=true
|
||||
manifests/ha/namespace-install.yaml linguist-generated=true
|
||||
manifests/ha/namespace-install-with-hydrator.yaml linguist-generated=true
|
||||
manifests/install.yaml linguist-generated=true
|
||||
manifests/install-with-hydrator.yaml linguist-generated=true
|
||||
manifests/namespace-install.yaml linguist-generated=true
|
||||
manifests/namespace-install-with-hydrator.yaml linguist-generated=true
|
||||
pkg/apis/api-rules/violation_exceptions.list linguist-generated=true
|
||||
|
||||
5
.github/dependabot.yml
vendored
5
.github/dependabot.yml
vendored
@@ -31,11 +31,6 @@ updates:
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
ignore:
|
||||
# We use consistent go and node versions across a lot of different files, and updating via dependabot would cause
|
||||
# drift among those files, instead we let renovate bot handle them.
|
||||
- dependency-name: "library/golang"
|
||||
- dependency-name: "library/node"
|
||||
|
||||
- package-ecosystem: "docker"
|
||||
directory: "/test/container/"
|
||||
|
||||
89
.github/workflows/bump-major-version.yaml
vendored
89
.github/workflows/bump-major-version.yaml
vendored
@@ -1,89 +0,0 @@
|
||||
name: Bump major version
|
||||
on:
|
||||
workflow_dispatch: {}
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
prepare-release:
|
||||
permissions:
|
||||
contents: write # for peter-evans/create-pull-request to create branch
|
||||
pull-requests: write # for peter-evans/create-pull-request to create a PR
|
||||
name: Automatically update major version
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# Get the current major version from go.mod and save it as a variable.
|
||||
- name: Get target version
|
||||
id: get-target-version
|
||||
run: |
|
||||
set -ue
|
||||
CURRENT_VERSION=$(grep 'module github.com/argoproj/argo-cd' go.mod | awk '{print $2}' | sed 's/.*\/v//')
|
||||
echo "TARGET_VERSION=$((CURRENT_VERSION + 1))" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Copy source code to GOPATH
|
||||
run: |
|
||||
mkdir -p ~/go/src/github.com/argoproj
|
||||
cp -a ../argo-cd ~/go/src/github.com/argoproj
|
||||
|
||||
- name: Run script to bump the version
|
||||
run: |
|
||||
hack/bump-major-version.sh
|
||||
working-directory: /home/runner/go/src/github.com/argoproj/argo-cd
|
||||
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Add ~/go/bin to PATH
|
||||
run: |
|
||||
echo "/home/runner/go/bin" >> $GITHUB_PATH
|
||||
- name: Add /usr/local/bin to PATH
|
||||
run: |
|
||||
echo "/usr/local/bin" >> $GITHUB_PATH
|
||||
- name: Download & vendor dependencies
|
||||
run: |
|
||||
# We need to vendor go modules for codegen yet
|
||||
go mod download
|
||||
go mod vendor -v
|
||||
working-directory: /home/runner/go/src/github.com/argoproj/argo-cd
|
||||
- name: Install toolchain for codegen
|
||||
run: |
|
||||
make install-codegen-tools-local
|
||||
make install-go-tools-local
|
||||
working-directory: /home/runner/go/src/github.com/argoproj/argo-cd
|
||||
# We install kustomize in the dist directory
|
||||
- name: Add dist to PATH
|
||||
run: |
|
||||
echo "/home/runner/work/argo-cd/argo-cd/dist" >> $GITHUB_PATH
|
||||
- name: Run codegen
|
||||
run: |
|
||||
set -x
|
||||
export GOPATH=$(go env GOPATH)
|
||||
make codegen-local
|
||||
working-directory: /home/runner/go/src/github.com/argoproj/argo-cd
|
||||
|
||||
- name: Copy changes back
|
||||
run: |
|
||||
# Copy the contents back, but skip the .git directory
|
||||
rsync -a --exclude=.git /home/runner/go/src/github.com/argoproj/argo-cd/ ../argo-cd
|
||||
|
||||
- name: Create pull request
|
||||
uses: peter-evans/create-pull-request@5e914681df9dc83aa4e4905692ca88beb2f9e91f # v7.0.5
|
||||
with:
|
||||
commit-message: "Bump major version to ${{ steps.get-target-version.outputs.TARGET_VERSION }}"
|
||||
title: "Bump major version to ${{ steps.get-target-version.outputs.TARGET_VERSION }}"
|
||||
body: |
|
||||
Congrats! You've just bumped the major version to ${{ steps.get-target-version.outputs.TARGET_VERSION }}.
|
||||
|
||||
Next steps:
|
||||
- [ ] Merge this PR
|
||||
- [ ] Add an upgrade guide to the docs for this version
|
||||
branch: bump-major-version
|
||||
branch-suffix: random
|
||||
signoff: true
|
||||
95
.github/workflows/ci-build.yaml
vendored
95
.github/workflows/ci-build.yaml
vendored
@@ -13,8 +13,7 @@ on:
|
||||
|
||||
env:
|
||||
# Golang version to use across CI steps
|
||||
# renovate: datasource=golang-version packageName=golang
|
||||
GOLANG_VERSION: '1.24.1'
|
||||
GOLANG_VERSION: '1.22'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
@@ -32,14 +31,14 @@ jobs:
|
||||
docs: ${{ steps.filter.outputs.docs_any_changed }}
|
||||
steps:
|
||||
- uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
|
||||
- uses: tj-actions/changed-files@bab30c2299617f6615ec02a68b9a40d10bd21366 # v45.0.5
|
||||
- uses: tj-actions/changed-files@e9772d140489982e0e3704fea5ee93d536f1e275 # v45.0.1
|
||||
id: filter
|
||||
with:
|
||||
# Any file which is not under docs/, ui/ or is not a markdown file is counted as a backend file
|
||||
files_yaml: |
|
||||
backend:
|
||||
- '!ui/**'
|
||||
- '!**.md'
|
||||
- '!**.md'
|
||||
- '!**/*.md'
|
||||
- '!docs/**'
|
||||
frontend:
|
||||
@@ -57,7 +56,7 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
|
||||
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Download all Go modules
|
||||
@@ -78,7 +77,7 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
|
||||
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Restore go build cache
|
||||
@@ -94,8 +93,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
|
||||
@@ -105,14 +104,13 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
|
||||
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Run golangci-lint
|
||||
uses: golangci/golangci-lint-action@971e284b6050e8a5849b72094c50ab08da042db8 # v6.1.1
|
||||
uses: golangci/golangci-lint-action@aaa42aa0628b4ae2578232a66b541047968fac86 # v6.1.0
|
||||
with:
|
||||
# renovate: datasource=go packageName=github.com/golangci/golangci-lint versioning=regex:^v(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)?$
|
||||
version: v1.64.7
|
||||
version: v1.58.2
|
||||
args: --verbose
|
||||
|
||||
test-go:
|
||||
@@ -133,7 +131,7 @@ jobs:
|
||||
- name: Create symlink in GOPATH
|
||||
run: ln -s $(pwd) ~/go/src/github.com/argoproj/argo-cd
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
|
||||
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Install required packages
|
||||
@@ -174,7 +172,7 @@ jobs:
|
||||
- name: Run all unit tests
|
||||
run: make test-local
|
||||
- name: Generate test results artifacts
|
||||
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
|
||||
uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0
|
||||
with:
|
||||
name: test-results
|
||||
path: test-results
|
||||
@@ -197,7 +195,7 @@ jobs:
|
||||
- name: Create symlink in GOPATH
|
||||
run: ln -s $(pwd) ~/go/src/github.com/argoproj/argo-cd
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
|
||||
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Install required packages
|
||||
@@ -238,7 +236,7 @@ jobs:
|
||||
- name: Run all unit tests
|
||||
run: make test-race-local
|
||||
- name: Generate test results artifacts
|
||||
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
|
||||
uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0
|
||||
with:
|
||||
name: race-results
|
||||
path: test-results/
|
||||
@@ -253,7 +251,7 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
|
||||
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Create symlink in GOPATH
|
||||
@@ -305,10 +303,9 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
|
||||
- name: Setup NodeJS
|
||||
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
|
||||
with:
|
||||
# renovate: datasource=node-version packageName=node versioning=node
|
||||
node-version: '22.9.0'
|
||||
node-version: '21.6.1'
|
||||
- name: Restore node dependency cache
|
||||
id: cache-dependencies
|
||||
uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
|
||||
@@ -370,13 +367,13 @@ jobs:
|
||||
path: test-results
|
||||
- name: combine-go-coverage
|
||||
# We generate coverage reports for all Argo CD components, but only the applicationset-controller,
|
||||
# app-controller, repo-server, and commit-server report contain coverage data. The other components currently
|
||||
# don't shut down gracefully, so no coverage data is produced. Once those components are fixed, we can add
|
||||
# references to their coverage output directories.
|
||||
# app-controller, and repo-server report contain coverage data. The other components currently don't shut down
|
||||
# gracefully, so no coverage data is produced. Once those components are fixed, we can add references to their
|
||||
# coverage output directories.
|
||||
run: |
|
||||
go tool covdata percent -i=test-results,e2e-code-coverage/applicationset-controller,e2e-code-coverage/repo-server,e2e-code-coverage/app-controller,e2e-code-coverage/commit-server -o test-results/full-coverage.out
|
||||
go tool covdata percent -i=test-results,e2e-code-coverage/applicationset-controller,e2e-code-coverage/repo-server,e2e-code-coverage/app-controller -o test-results/full-coverage.out
|
||||
- name: Upload code coverage information to codecov.io
|
||||
uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4.6.0
|
||||
uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0
|
||||
with:
|
||||
file: test-results/full-coverage.out
|
||||
fail_ci_if_error: true
|
||||
@@ -384,7 +381,7 @@ jobs:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
- name: Upload test results to Codecov
|
||||
if: github.ref == 'refs/heads/master' && github.event_name == 'push' && github.repository == 'argoproj/argo-cd'
|
||||
uses: codecov/test-results-action@9739113ad922ea0a9abb4b2c0f8bf6a4aa8ef820 # v1.0.1
|
||||
uses: codecov/test-results-action@1b5b448b98e58ba90d1a1a1d9fcb72ca2263be46 # v1.0.0
|
||||
with:
|
||||
file: test-results/junit.xml
|
||||
fail_ci_if_error: true
|
||||
@@ -393,7 +390,7 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
uses: SonarSource/sonarqube-scan-action@bfd4e558cda28cda6b5defafb9232d191be8c203 # v4.2.1
|
||||
uses: SonarSource/sonarqube-scan-action@aecaf43ae57e412bd97d70ef9ce6076e672fe0a9 # v2.2
|
||||
if: env.sonar_secret != ''
|
||||
test-e2e:
|
||||
name: Run end-to-end tests
|
||||
@@ -402,45 +399,37 @@ 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.32.1
|
||||
- version: v1.30.2
|
||||
# We designate the latest version because we only collect code coverage for that version.
|
||||
latest: true
|
||||
- version: v1.31.0
|
||||
- version: v1.29.6
|
||||
latest: false
|
||||
- version: v1.30.4
|
||||
- version: v1.28.11
|
||||
latest: false
|
||||
- version: v1.29.8
|
||||
- version: v1.27.15
|
||||
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:
|
||||
- name: Free Disk Space (Ubuntu)
|
||||
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be
|
||||
with:
|
||||
large-packages: false
|
||||
docker-images: false
|
||||
swap-storage: false
|
||||
tool-cache: false
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
|
||||
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: GH actions workaround - Kill XSP4 process
|
||||
@@ -487,7 +476,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.2.7-alpine
|
||||
docker pull redis:7.0.15-alpine
|
||||
- name: Create target directory for binaries in the build-process
|
||||
run: |
|
||||
mkdir -p dist
|
||||
@@ -517,13 +506,13 @@ jobs:
|
||||
goreman run stop-all || echo "goreman trouble"
|
||||
sleep 30
|
||||
- name: Upload e2e coverage report
|
||||
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
|
||||
uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0
|
||||
with:
|
||||
name: e2e-code-coverage
|
||||
path: /tmp/coverage
|
||||
if: ${{ matrix.k3s.latest }}
|
||||
- name: Upload e2e-server logs
|
||||
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
|
||||
uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0
|
||||
with:
|
||||
name: e2e-server-k8s${{ matrix.k3s.version }}.log
|
||||
path: /tmp/e2e-server.log
|
||||
|
||||
4
.github/workflows/codeql.yml
vendored
4
.github/workflows/codeql.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
||||
actions: read # for github/codeql-action/init to get workflow details
|
||||
contents: read # for actions/checkout to fetch code
|
||||
security-events: write # for github/codeql-action/autobuild to send a status report
|
||||
if: github.repository == 'argoproj/argo-cd' || vars.enable_codeql
|
||||
if: github.repository == 'argoproj/argo-cd'
|
||||
|
||||
# CodeQL runs on ubuntu-latest and windows-latest
|
||||
runs-on: ubuntu-22.04
|
||||
@@ -33,7 +33,7 @@ jobs:
|
||||
|
||||
# Use correct go version. https://github.com/github/codeql-action/issues/1842#issuecomment-1704398087
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
|
||||
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
|
||||
|
||||
10
.github/workflows/image-reuse.yaml
vendored
10
.github/workflows/image-reuse.yaml
vendored
@@ -17,9 +17,11 @@ on:
|
||||
platforms:
|
||||
required: true
|
||||
type: string
|
||||
default: linux/amd64
|
||||
push:
|
||||
required: true
|
||||
type: boolean
|
||||
default: false
|
||||
target:
|
||||
required: false
|
||||
type: string
|
||||
@@ -67,15 +69,15 @@ jobs:
|
||||
if: ${{ github.ref_type != 'tag'}}
|
||||
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
|
||||
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
|
||||
with:
|
||||
go-version: ${{ inputs.go-version }}
|
||||
|
||||
- name: Install cosign
|
||||
uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da # v3.7.0
|
||||
uses: sigstore/cosign-installer@4959ce089c160fddf62f7b42464195ba1a56d382 # v3.6.0
|
||||
|
||||
- uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3.2.0
|
||||
- uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0
|
||||
- uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db # v3.6.1
|
||||
|
||||
- name: Setup tags for container image as a CSV type
|
||||
run: |
|
||||
@@ -141,7 +143,7 @@ jobs:
|
||||
|
||||
- name: Build and push container image
|
||||
id: image
|
||||
uses: docker/build-push-action@48aba3b46d1b1fec4febb7c5d0c644b249a11355 #v6.10.0
|
||||
uses: docker/build-push-action@5cd11c3a4ced054e52742c5fd54dca954e0edd85 #v6.7.0
|
||||
with:
|
||||
context: .
|
||||
platforms: ${{ inputs.platforms }}
|
||||
|
||||
17
.github/workflows/image.yaml
vendored
17
.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,13 @@ 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.24.1
|
||||
go-version: 1.22
|
||||
platforms: ${{ needs.set-vars.outputs.platforms }}
|
||||
push: false
|
||||
|
||||
@@ -61,7 +60,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
|
||||
@@ -69,8 +68,7 @@ jobs:
|
||||
quay_image_name: quay.io/argoproj/argocd:latest
|
||||
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.24.1
|
||||
go-version: 1.22
|
||||
platforms: ${{ needs.set-vars.outputs.platforms }}
|
||||
push: true
|
||||
secrets:
|
||||
@@ -101,8 +99,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,3 +114,4 @@ 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
|
||||
|
||||
|
||||
2
.github/workflows/init-release.yaml
vendored
2
.github/workflows/init-release.yaml
vendored
@@ -64,7 +64,7 @@ jobs:
|
||||
git stash pop
|
||||
|
||||
- name: Create pull request
|
||||
uses: peter-evans/create-pull-request@5e914681df9dc83aa4e4905692ca88beb2f9e91f # v7.0.5
|
||||
uses: peter-evans/create-pull-request@d121e62763d8cc35b5fb1710e887d6e69a52d3a4 # v7.0.2
|
||||
with:
|
||||
commit-message: "Bump version to ${{ inputs.TARGET_VERSION }}"
|
||||
title: "Bump version to ${{ inputs.TARGET_VERSION }} on ${{ inputs.TARGET_BRANCH }} branch"
|
||||
|
||||
6
.github/workflows/pr-title-check.yml
vendored
6
.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.head_ref }}
|
||||
cancel-in-progress: true
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
|
||||
jobs:
|
||||
validate:
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
name: Validate PR Title
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: thehanimo/pr-title-checker@7fbfe05602bdd86f926d3fb3bccb6f3aed43bc70 # v1.4.3
|
||||
- uses: thehanimo/pr-title-checker@1d8cd483a2b73118406a187f54dca8a9415f1375 # v1.4.2
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
configuration_path: ".github/pr-title-checker-config.json"
|
||||
|
||||
86
.github/workflows/release.yaml
vendored
86
.github/workflows/release.yaml
vendored
@@ -10,8 +10,7 @@ on:
|
||||
permissions: {}
|
||||
|
||||
env:
|
||||
# renovate: datasource=golang-version packageName=golang
|
||||
GOLANG_VERSION: '1.24.1' # Note: go-version must also be set in job argocd-image.with.go-version
|
||||
GOLANG_VERSION: '1.22' # Note: go-version must also be set in job argocd-image.with.go-version
|
||||
|
||||
jobs:
|
||||
argocd-image:
|
||||
@@ -24,8 +23,7 @@ jobs:
|
||||
with:
|
||||
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.24.1
|
||||
go-version: 1.22
|
||||
platforms: linux/amd64,linux/arm64,linux/s390x,linux/ppc64le
|
||||
push: true
|
||||
secrets:
|
||||
@@ -33,20 +31,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:
|
||||
@@ -69,15 +67,19 @@ jobs:
|
||||
- name: Fetch all tags
|
||||
run: git fetch --force --tags
|
||||
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
|
||||
- name: Set GORELEASER_PREVIOUS_TAG # Workaround, GoReleaser uses 'git-describe' to determine a previous tag. Our tags are created in release branches.
|
||||
- name: Set GORELEASER_PREVIOUS_TAG # Workaround, GoReleaser uses 'git-describe' to determine a previous tag. Our tags are created in realease branches.
|
||||
run: |
|
||||
set -xue
|
||||
echo "GORELEASER_PREVIOUS_TAG=$(go run hack/get-previous-release/get-previous-version-for-release-notes.go ${{ github.ref_name }})" >> $GITHUB_ENV
|
||||
if echo ${{ github.ref_name }} | grep -E -- '-rc1+$';then
|
||||
echo "GORELEASER_PREVIOUS_TAG=$(git -c 'versionsort.suffix=-rc' tag --list --sort=version:refname | tail -n 2 | head -n 1)" >> $GITHUB_ENV
|
||||
else
|
||||
echo "This is not the first release on the branch, Using GoReleaser defaults"
|
||||
fi
|
||||
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
|
||||
- name: Set environment variables for ldflags
|
||||
id: set_ldflag
|
||||
@@ -94,20 +96,20 @@ jobs:
|
||||
tool-cache: false
|
||||
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@9ed2f89a662bf1735a48bc8557fd212fa902bebf # v6.1.0
|
||||
uses: goreleaser/goreleaser-action@286f3b13b1b49da4ac219696163fb8c1c93e1200 # v6.0.0
|
||||
id: run-goreleaser
|
||||
with:
|
||||
version: latest
|
||||
args: release --clean --timeout 55m
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
KUBECTL_VERSION: ${{ env.KUBECTL_VERSION }}
|
||||
KUBECTL_VERSION: ${{ env.KUBECTL_VERSION }}
|
||||
GIT_TREE_STATE: ${{ env.GIT_TREE_STATE }}
|
||||
|
||||
- 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 +130,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:
|
||||
@@ -151,7 +153,7 @@ jobs:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
|
||||
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
|
||||
@@ -164,7 +166,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: |
|
||||
@@ -184,7 +186,7 @@ jobs:
|
||||
fi
|
||||
|
||||
cd /tmp && tar -zcf sbom.tar.gz *.spdx
|
||||
|
||||
|
||||
- name: Generate SBOM hash
|
||||
shell: bash
|
||||
id: sbom-hash
|
||||
@@ -193,15 +195,15 @@ jobs:
|
||||
# base64 -w0 encodes to base64 and outputs on a single line.
|
||||
# sha256sum /tmp/sbom.tar.gz ... | base64 -w0
|
||||
echo "hashes=$(sha256sum /tmp/sbom.tar.gz | base64 -w0)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
|
||||
- name: Upload SBOM
|
||||
uses: softprops/action-gh-release@c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda # v2.2.1
|
||||
uses: softprops/action-gh-release@c062e08bd532815e2082a85e87e3ef29c3e6d191 # v2.0.8
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
files: |
|
||||
/tmp/sbom.tar.gz
|
||||
|
||||
|
||||
sbom-provenance:
|
||||
needs: [generate-sbom]
|
||||
permissions:
|
||||
@@ -209,13 +211,13 @@ jobs:
|
||||
id-token: write # Needed for provenance signing and ID
|
||||
contents: write # Needed for release uploads
|
||||
if: github.repository == 'argoproj/argo-cd'
|
||||
# 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
|
||||
# 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.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:
|
||||
needs:
|
||||
- argocd-image
|
||||
@@ -293,10 +295,10 @@ jobs:
|
||||
if: ${{ env.UPDATE_VERSION == 'true' }}
|
||||
|
||||
- name: Create PR to update VERSION on master branch
|
||||
uses: peter-evans/create-pull-request@5e914681df9dc83aa4e4905692ca88beb2f9e91f # v7.0.5
|
||||
uses: peter-evans/create-pull-request@d121e62763d8cc35b5fb1710e887d6e69a52d3a4 # v7.0.2
|
||||
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
.github/workflows/scorecard.yaml
vendored
2
.github/workflows/scorecard.yaml
vendored
@@ -54,7 +54,7 @@ jobs:
|
||||
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
||||
# format to the repository Actions tab.
|
||||
- name: "Upload artifact"
|
||||
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
|
||||
uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,7 +1,6 @@
|
||||
.vscode/
|
||||
.idea/
|
||||
.DS_Store
|
||||
.run/
|
||||
vendor/
|
||||
dist/*
|
||||
ui/dist/app/*
|
||||
|
||||
2
.gitpod.Dockerfile
vendored
2
.gitpod.Dockerfile
vendored
@@ -1,4 +1,4 @@
|
||||
FROM gitpod/workspace-full@sha256:a47a68ee7f9da10cd889ccce4661bc73f2c0d5a98d3d087e8bdfc0230b27964c
|
||||
FROM gitpod/workspace-full@sha256:230285e0b949e6d728d384b2029a4111db7b9c87c182f22f32a0be9e36b225df
|
||||
|
||||
USER root
|
||||
|
||||
|
||||
125
.golangci.yaml
125
.golangci.yaml
@@ -14,143 +14,32 @@ linters:
|
||||
- gocritic
|
||||
- gofumpt
|
||||
- goimports
|
||||
- gomodguard
|
||||
- gosimple
|
||||
- govet
|
||||
- importas
|
||||
- ineffassign
|
||||
- misspell
|
||||
# Disabled because of https://github.com/argoproj/argo-cd/issues/21705
|
||||
# - nolintlint
|
||||
- perfsprint
|
||||
- revive
|
||||
- staticcheck
|
||||
- testifylint
|
||||
- thelper
|
||||
- unparam
|
||||
- unused
|
||||
- usestdlibvars
|
||||
- usetesting
|
||||
- whitespace
|
||||
- whitespace
|
||||
linters-settings:
|
||||
gocritic:
|
||||
disabled-checks:
|
||||
- appendAssign
|
||||
- assignOp # Keep it disabled for readability
|
||||
- assignOp # Keep it disabled for readability
|
||||
- badCond
|
||||
- commentFormatting
|
||||
- exitAfterDefer
|
||||
- ifElseChain
|
||||
- mapKey
|
||||
- singleCaseSwitch
|
||||
- typeSwitchVar
|
||||
goimports:
|
||||
local-prefixes: github.com/argoproj/argo-cd/v3
|
||||
gomodguard:
|
||||
blocked:
|
||||
modules:
|
||||
- github.com/golang-jwt/jwt/v4:
|
||||
recommendations:
|
||||
- github.com/golang-jwt/jwt/v5
|
||||
- github.com/imdario/mergo:
|
||||
recommendations:
|
||||
- dario.cat/mergo
|
||||
reason: '`github.com/imdario/mergo` has been renamed.'
|
||||
- github.com/pkg/errors:
|
||||
recommendations:
|
||||
- errors
|
||||
importas:
|
||||
alias:
|
||||
- alias: jwtgo
|
||||
pkg: github.com/golang-jwt/jwt/v5
|
||||
- alias: appsv1
|
||||
pkg: k8s.io/api/apps/v1
|
||||
- alias: corev1
|
||||
pkg: k8s.io/api/core/v1
|
||||
- alias: rbacv1
|
||||
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
|
||||
pkg: k8s.io/client-go/informers/core/v1
|
||||
- alias: stderrors
|
||||
pkg: errors
|
||||
nolintlint:
|
||||
require-specific: true
|
||||
perfsprint:
|
||||
# Optimizes even if it requires an int or uint type cast.
|
||||
int-conversion: true
|
||||
# Optimizes into `err.Error()` even if it is only equivalent for non-nil errors.
|
||||
err-error: true
|
||||
# Optimizes `fmt.Errorf`.
|
||||
errorf: true
|
||||
# Optimizes `fmt.Sprintf` with only one argument.
|
||||
sprintf1: true
|
||||
# Optimizes into strings concatenation.
|
||||
strconcat: true
|
||||
revive:
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md
|
||||
rules:
|
||||
- name: bool-literal-in-expr
|
||||
- name: blank-imports
|
||||
disabled: true
|
||||
- name: context-as-argument
|
||||
arguments:
|
||||
- allowTypesBefore: '*testing.T,testing.TB'
|
||||
- name: context-keys-type
|
||||
disabled: true
|
||||
- name: dot-imports
|
||||
disabled: true
|
||||
- name: duplicated-imports
|
||||
- name: early-return
|
||||
arguments:
|
||||
- 'preserveScope'
|
||||
- name: empty-block
|
||||
disabled: true
|
||||
- name: error-naming
|
||||
disabled: true
|
||||
- name: error-return
|
||||
- name: error-strings
|
||||
disabled: true
|
||||
- name: errorf
|
||||
- name: identical-branches
|
||||
- name: if-return
|
||||
- name: increment-decrement
|
||||
- name: indent-error-flow
|
||||
arguments:
|
||||
- 'preserveScope'
|
||||
- name: modifies-parameter
|
||||
- name: optimize-operands-order
|
||||
- name: range
|
||||
- name: receiver-naming
|
||||
- name: redefines-builtin-id
|
||||
disabled: true
|
||||
- name: redundant-import-alias
|
||||
- name: superfluous-else
|
||||
arguments:
|
||||
- 'preserveScope'
|
||||
- name: time-equal
|
||||
- name: time-naming
|
||||
disabled: true
|
||||
- name: unexported-return
|
||||
disabled: true
|
||||
- name: unnecessary-stmt
|
||||
- name: unreachable-code
|
||||
- name: unused-parameter
|
||||
- name: use-any
|
||||
- name: useless-break
|
||||
- name: var-declaration
|
||||
- name: var-naming
|
||||
arguments:
|
||||
- ["ID"]
|
||||
- ["VM"]
|
||||
- - skipPackageNameChecks: true
|
||||
upperCaseConst: true
|
||||
local-prefixes: github.com/argoproj/argo-cd/v2
|
||||
testifylint:
|
||||
enable-all: true
|
||||
disable:
|
||||
- go-require
|
||||
usetesting:
|
||||
os-mkdir-temp: false
|
||||
run:
|
||||
timeout: 50m
|
||||
|
||||
@@ -16,11 +16,11 @@ builds:
|
||||
flags:
|
||||
- -v
|
||||
ldflags:
|
||||
- -X github.com/argoproj/argo-cd/v3/common.version={{ .Version }}
|
||||
- -X github.com/argoproj/argo-cd/v3/common.buildDate={{ .Date }}
|
||||
- -X github.com/argoproj/argo-cd/v3/common.gitCommit={{ .FullCommit }}
|
||||
- -X github.com/argoproj/argo-cd/v3/common.gitTreeState={{ .Env.GIT_TREE_STATE }}
|
||||
- -X github.com/argoproj/argo-cd/v3/common.kubectlVersion={{ .Env.KUBECTL_VERSION }}
|
||||
- -X github.com/argoproj/argo-cd/v2/common.version={{ .Version }}
|
||||
- -X github.com/argoproj/argo-cd/v2/common.buildDate={{ .Date }}
|
||||
- -X github.com/argoproj/argo-cd/v2/common.gitCommit={{ .FullCommit }}
|
||||
- -X github.com/argoproj/argo-cd/v2/common.gitTreeState={{ .Env.GIT_TREE_STATE }}
|
||||
- -X github.com/argoproj/argo-cd/v2/common.kubectlVersion={{ .Env.KUBECTL_VERSION }}
|
||||
- -extldflags="-static"
|
||||
goos:
|
||||
- linux
|
||||
@@ -79,8 +79,6 @@ release:
|
||||
|
||||
All Argo CD container images are signed by cosign. A Provenance is generated for container images and CLI binaries which meet the SLSA Level 3 specifications. See the [documentation](https://argo-cd.readthedocs.io/en/stable/operator-manual/signed-release-assets) on how to verify.
|
||||
|
||||
## Release Notes Blog Post
|
||||
For a detailed breakdown of the key changes and improvements in this release, check out the [official blog post](https://blog.argoproj.io/argo-cd-v2-14-release-candidate-57a664791e2a)
|
||||
|
||||
## Upgrading
|
||||
|
||||
|
||||
@@ -6,13 +6,13 @@ mockname: "{{.InterfaceName}}"
|
||||
with-expecter: false
|
||||
# individual interface config
|
||||
packages:
|
||||
github.com/argoproj/argo-cd/v3/applicationset/generators:
|
||||
github.com/argoproj/argo-cd/v2/applicationset/generators:
|
||||
interfaces:
|
||||
Generator:
|
||||
github.com/argoproj/argo-cd/v3/applicationset/services:
|
||||
github.com/argoproj/argo-cd/v2/applicationset/services:
|
||||
interfaces:
|
||||
Repos:
|
||||
github.com/argoproj/argo-cd/v3/applicationset/services/scm_provider:
|
||||
github.com/argoproj/argo-cd/v2/applicationset/services/scm_provider:
|
||||
config:
|
||||
dir: "applicationset/services/scm_provider/aws_codecommit/mocks"
|
||||
interfaces:
|
||||
@@ -23,27 +23,20 @@ packages:
|
||||
dir: "applicationset/services/scm_provider/azure_devops/git/mocks"
|
||||
interfaces:
|
||||
Client:
|
||||
github.com/argoproj/argo-cd/v3/applicationset/utils:
|
||||
github.com/argoproj/argo-cd/v2/applicationset/utils:
|
||||
interfaces:
|
||||
Renderer:
|
||||
github.com/argoproj/argo-cd/v3/commitserver/commit:
|
||||
interfaces:
|
||||
RepoClientFactory:
|
||||
github.com/argoproj/argo-cd/v3/commitserver/apiclient:
|
||||
interfaces:
|
||||
CommitServiceClient:
|
||||
Clientset:
|
||||
github.com/argoproj/argo-cd/v3/controller/cache:
|
||||
github.com/argoproj/argo-cd/v2/controller/cache:
|
||||
interfaces:
|
||||
LiveStateCache:
|
||||
github.com/argoproj/argo-cd/v3/reposerver/apiclient:
|
||||
github.com/argoproj/argo-cd/v2/reposerver/apiclient:
|
||||
interfaces:
|
||||
RepoServerServiceClient:
|
||||
RepoServerService_GenerateManifestWithFilesClient:
|
||||
github.com/argoproj/argo-cd/v3/server/application:
|
||||
github.com/argoproj/argo-cd/v2/server/application:
|
||||
interfaces:
|
||||
Broadcaster:
|
||||
github.com/argoproj/argo-cd/v3/server/extension:
|
||||
github.com/argoproj/argo-cd/v2/server/extension:
|
||||
interfaces:
|
||||
ApplicationGetter:
|
||||
ExtensionMetricsRegistry:
|
||||
@@ -51,32 +44,26 @@ packages:
|
||||
RbacEnforcer:
|
||||
SettingsGetter:
|
||||
UserGetter:
|
||||
github.com/argoproj/argo-cd/v3/util/db:
|
||||
github.com/argoproj/argo-cd/v2/util/db:
|
||||
interfaces:
|
||||
ArgoDB:
|
||||
github.com/argoproj/argo-cd/v3/util/git:
|
||||
github.com/argoproj/argo-cd/v2/util/git:
|
||||
interfaces:
|
||||
Client:
|
||||
github.com/argoproj/argo-cd/v3/util/helm:
|
||||
github.com/argoproj/argo-cd/v2/util/helm:
|
||||
interfaces:
|
||||
Client:
|
||||
github.com/argoproj/argo-cd/v3/util/io:
|
||||
github.com/argoproj/argo-cd/v2/util/io:
|
||||
interfaces:
|
||||
TempPaths:
|
||||
github.com/argoproj/argo-cd/v3/util/notification/argocd:
|
||||
github.com/argoproj/argo-cd/v2/util/notification/argocd:
|
||||
interfaces:
|
||||
Service:
|
||||
github.com/argoproj/argo-cd/v3/util/workloadidentity:
|
||||
interfaces:
|
||||
TokenProvider:
|
||||
# These mocks are not currently used, but they are part of the public API of this package.
|
||||
github.com/argoproj/argo-cd/v3/pkg/apiclient/session:
|
||||
github.com/argoproj/argo-cd/v2/pkg/apiclient/session:
|
||||
interfaces:
|
||||
SessionServiceServer:
|
||||
SessionServiceClient:
|
||||
github.com/argoproj/argo-cd/v3/pkg/apiclient/cluster:
|
||||
github.com/argoproj/argo-cd/v2/pkg/apiclient/cluster:
|
||||
interfaces:
|
||||
ClusterServiceServer:
|
||||
github.com/argoproj/argo-cd/v3/pkg/client/clientset/versioned/typed/application/v1alpha1:
|
||||
interfaces:
|
||||
AppProjectInterface:
|
||||
|
||||
@@ -9,4 +9,4 @@ python:
|
||||
build:
|
||||
os: "ubuntu-22.04"
|
||||
tools:
|
||||
python: "3.12"
|
||||
python: "3.7"
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
# Changelog
|
||||
|
||||
## v2.13.6 (2025-03-21)
|
||||
|
||||
### Bug fixes
|
||||
- fix: handle annotated git tags correctly in repo server cache (#21548) (#21771)
|
||||
|
||||
## v2.4.8 (2022-07-29)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
11
Dockerfile
11
Dockerfile
@@ -1,10 +1,10 @@
|
||||
ARG BASE_IMAGE=docker.io/library/ubuntu:24.04@sha256:80dd3c3b9c6cecb9f1667e9290b3bc61b78c2678c02cbdae5f0fea92cc6734ab
|
||||
ARG BASE_IMAGE=docker.io/library/ubuntu:24.04@sha256:3f85b7caad41a95462cf5b787d8a04604c8262cdcdf9a472b8c52ef83375fe15
|
||||
####################################################################################################
|
||||
# Builder image
|
||||
# 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.24.1@sha256:c5adecdb7b3f8c5ca3c88648a861882849cc8b02fed68ece31e25de88ad13418 AS builder
|
||||
FROM docker.io/library/golang:1.23.1@sha256:2fe82a3f3e006b4f2a316c6a21f62b66e1330ae211d039bb8d1128e12ed57bf1 AS builder
|
||||
|
||||
RUN echo 'deb http://archive.debian.org/debian buster-backports main' >> /etc/apt/sources.list
|
||||
|
||||
@@ -83,7 +83,7 @@ WORKDIR /home/argocd
|
||||
####################################################################################################
|
||||
# Argo CD UI stage
|
||||
####################################################################################################
|
||||
FROM --platform=$BUILDPLATFORM docker.io/library/node:23.0.0@sha256:e643c0b70dca9704dff42e12b17f5b719dbe4f95e6392fc2dfa0c5f02ea8044d AS argocd-ui
|
||||
FROM --platform=$BUILDPLATFORM docker.io/library/node:22.8.0@sha256:bd00c03095f7586432805dbf7989be10361d27987f93de904b1fc003949a4794 AS argocd-ui
|
||||
|
||||
WORKDIR /src
|
||||
COPY ["ui/package.json", "ui/yarn.lock", "./"]
|
||||
@@ -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.24.1@sha256:c5adecdb7b3f8c5ca3c88648a861882849cc8b02fed68ece31e25de88ad13418 AS argocd-build
|
||||
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.23.1@sha256:2fe82a3f3e006b4f2a316c6a21f62b66e1330ae211d039bb8d1128e12ed57bf1 AS argocd-build
|
||||
|
||||
WORKDIR /go/src/github.com/argoproj/argo-cd
|
||||
|
||||
@@ -140,8 +140,7 @@ RUN ln -s /usr/local/bin/argocd /usr/local/bin/argocd-server && \
|
||||
ln -s /usr/local/bin/argocd /usr/local/bin/argocd-dex && \
|
||||
ln -s /usr/local/bin/argocd /usr/local/bin/argocd-notifications && \
|
||||
ln -s /usr/local/bin/argocd /usr/local/bin/argocd-applicationset-controller && \
|
||||
ln -s /usr/local/bin/argocd /usr/local/bin/argocd-k8s-auth && \
|
||||
ln -s /usr/local/bin/argocd /usr/local/bin/argocd-commit-server
|
||||
ln -s /usr/local/bin/argocd /usr/local/bin/argocd-k8s-auth
|
||||
|
||||
USER $ARGOCD_USER_ID
|
||||
ENTRYPOINT ["/usr/bin/tini", "--"]
|
||||
|
||||
14
Makefile
14
Makefile
@@ -1,4 +1,4 @@
|
||||
PACKAGE=github.com/argoproj/argo-cd/v3/common
|
||||
PACKAGE=github.com/argoproj/argo-cd/v2/common
|
||||
CURRENT_DIR=$(shell pwd)
|
||||
DIST_DIR=${CURRENT_DIR}/dist
|
||||
CLI_NAME=argocd
|
||||
@@ -355,6 +355,11 @@ mod-vendor: test-tools-image
|
||||
mod-vendor-local: mod-download-local
|
||||
go mod vendor
|
||||
|
||||
# Deprecated - replace by install-tools-local
|
||||
.PHONY: install-lint-tools
|
||||
install-lint-tools:
|
||||
./hack/install.sh lint-tools
|
||||
|
||||
# Run linter on the code
|
||||
.PHONY: lint
|
||||
lint: test-tools-image
|
||||
@@ -430,7 +435,7 @@ test-e2e:
|
||||
test-e2e-local: cli-local
|
||||
# NO_PROXY ensures all tests don't go out through a proxy if one is configured on the test system
|
||||
export GO111MODULE=off
|
||||
DIST_DIR=${DIST_DIR} RERUN_FAILS=5 PACKAGES="./test/e2e" ARGOCD_E2E_RECORD=${ARGOCD_E2E_RECORD} ARGOCD_CONFIG_DIR=$(HOME)/.config/argocd-e2e ARGOCD_GPG_ENABLED=true NO_PROXY=* ./hack/test.sh -timeout $(ARGOCD_E2E_TEST_TIMEOUT) -v -args -test.gocoverdir="$(PWD)/test-results"
|
||||
DIST_DIR=${DIST_DIR} RERUN_FAILS=5 PACKAGES="./test/e2e" ARGOCD_E2E_RECORD=${ARGOCD_E2E_RECORD} ARGOCD_GPG_ENABLED=true NO_PROXY=* ./hack/test.sh -timeout $(ARGOCD_E2E_TEST_TIMEOUT) -v -args -test.gocoverdir="$(PWD)/test-results"
|
||||
|
||||
# Spawns a shell in the test server container for debugging purposes
|
||||
debug-test-server: test-tools-image
|
||||
@@ -467,7 +472,6 @@ start-e2e-local: mod-vendor-local dep-ui-local cli-local
|
||||
mkdir -p /tmp/coverage/repo-server
|
||||
mkdir -p /tmp/coverage/applicationset-controller
|
||||
mkdir -p /tmp/coverage/notification
|
||||
mkdir -p /tmp/coverage/commit-server
|
||||
# set paths for locally managed ssh known hosts and tls certs data
|
||||
ARGOCD_SSH_DATA_PATH=/tmp/argo-e2e/app/config/ssh \
|
||||
ARGOCD_TLS_DATA_PATH=/tmp/argo-e2e/app/config/tls \
|
||||
@@ -482,10 +486,8 @@ start-e2e-local: mod-vendor-local dep-ui-local cli-local
|
||||
BIN_MODE=$(ARGOCD_BIN_MODE) \
|
||||
ARGOCD_APPLICATION_NAMESPACES=argocd-e2e-external,argocd-e2e-external-2 \
|
||||
ARGOCD_APPLICATIONSET_CONTROLLER_NAMESPACES=argocd-e2e-external,argocd-e2e-external-2 \
|
||||
ARGOCD_APPLICATIONSET_CONTROLLER_TOKENREF_STRICT_MODE=true \
|
||||
ARGOCD_APPLICATIONSET_CONTROLLER_ALLOWED_SCM_PROVIDERS=http://127.0.0.1:8341,http://127.0.0.1:8342,http://127.0.0.1:8343,http://127.0.0.1:8344 \
|
||||
ARGOCD_E2E_TEST=true \
|
||||
ARGOCD_HYDRATOR_ENABLED=true \
|
||||
goreman -f $(ARGOCD_PROCFILE) start ${ARGOCD_START}
|
||||
ls -lrt /tmp/coverage
|
||||
|
||||
@@ -594,7 +596,6 @@ install-codegen-tools-local:
|
||||
.PHONY: install-go-tools-local
|
||||
install-go-tools-local:
|
||||
./hack/install.sh codegen-go-tools
|
||||
./hack/install.sh lint-tools
|
||||
|
||||
.PHONY: dep-ui
|
||||
dep-ui: test-tools-image
|
||||
@@ -675,6 +676,7 @@ help:
|
||||
@echo 'debug:'
|
||||
@echo ' list -- list all make targets'
|
||||
@echo ' install-tools-local -- install all the tools below'
|
||||
@echo ' install-lint-tools(-local)'
|
||||
@echo
|
||||
@echo 'codegen:'
|
||||
@echo ' codegen(-local) -- if using -local, run the following targets first'
|
||||
|
||||
9
Procfile
9
Procfile
@@ -1,10 +1,9 @@
|
||||
controller: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "GOCOVERDIR=${ARGOCD_COVERAGE_DIR:-/tmp/coverage/app-controller} HOSTNAME=testappcontroller-1 FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-application-controller $COMMAND --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --commit-server localhost:${ARGOCD_E2E_COMMITSERVER_PORT:-8086} --otlp-address=${ARGOCD_OTLP_ADDRESS} --application-namespaces=${ARGOCD_APPLICATION_NAMESPACES:-''} --server-side-diff-enabled=${ARGOCD_APPLICATION_CONTROLLER_SERVER_SIDE_DIFF:-'false'} --hydrator-enabled=${ARGOCD_HYDRATOR_ENABLED:='false'}"
|
||||
api-server: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "GOCOVERDIR=${ARGOCD_COVERAGE_DIR:-/tmp/coverage/api-server} FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-server $COMMAND --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --disable-auth=${ARGOCD_E2E_DISABLE_AUTH:-'true'} --insecure --dex-server http://localhost:${ARGOCD_E2E_DEX_PORT:-5556} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --port ${ARGOCD_E2E_APISERVER_PORT:-8080} --otlp-address=${ARGOCD_OTLP_ADDRESS} --application-namespaces=${ARGOCD_APPLICATION_NAMESPACES:-''} --hydrator-enabled=${ARGOCD_HYDRATOR_ENABLED:='false'}"
|
||||
dex: sh -c "ARGOCD_BINARY_NAME=argocd-dex go run github.com/argoproj/argo-cd/v3/cmd gendexcfg -o `pwd`/dist/dex.yaml && (test -f dist/dex.yaml || { echo 'Failed to generate dex configuration'; exit 1; }) && docker run --rm -p ${ARGOCD_E2E_DEX_PORT:-5556}:${ARGOCD_E2E_DEX_PORT:-5556} -v `pwd`/dist/dex.yaml:/dex.yaml ghcr.io/dexidp/dex:$(grep "image: ghcr.io/dexidp/dex" manifests/base/dex/argocd-dex-server-deployment.yaml | cut -d':' -f3) dex serve /dex.yaml"
|
||||
redis: hack/start-redis-with-password.sh
|
||||
controller: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "GOCOVERDIR=${ARGOCD_COVERAGE_DIR:-/tmp/coverage/app-controller} HOSTNAME=testappcontroller-1 FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-application-controller $COMMAND --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --otlp-address=${ARGOCD_OTLP_ADDRESS} --application-namespaces=${ARGOCD_APPLICATION_NAMESPACES:-''} --server-side-diff-enabled=${ARGOCD_APPLICATION_CONTROLLER_SERVER_SIDE_DIFF:-'false'}"
|
||||
api-server: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "GOCOVERDIR=${ARGOCD_COVERAGE_DIR:-/tmp/coverage/api-server} FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-server $COMMAND --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --disable-auth=${ARGOCD_E2E_DISABLE_AUTH:-'true'} --insecure --dex-server http://localhost:${ARGOCD_E2E_DEX_PORT:-5556} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --port ${ARGOCD_E2E_APISERVER_PORT:-8080} --otlp-address=${ARGOCD_OTLP_ADDRESS} --application-namespaces=${ARGOCD_APPLICATION_NAMESPACES:-''}"
|
||||
dex: sh -c "ARGOCD_BINARY_NAME=argocd-dex go run github.com/argoproj/argo-cd/v2/cmd gendexcfg -o `pwd`/dist/dex.yaml && (test -f dist/dex.yaml || { echo 'Failed to generate dex configuration'; exit 1; }) && docker run --rm -p ${ARGOCD_E2E_DEX_PORT:-5556}:${ARGOCD_E2E_DEX_PORT:-5556} -v `pwd`/dist/dex.yaml:/dex.yaml ghcr.io/dexidp/dex:$(grep "image: ghcr.io/dexidp/dex" manifests/base/dex/argocd-dex-server-deployment.yaml | cut -d':' -f3) dex serve /dex.yaml"
|
||||
redis: bash -c "if [ \"$ARGOCD_REDIS_LOCAL\" = 'true' ]; then redis-server --save '' --appendonly no --port ${ARGOCD_E2E_REDIS_PORT:-6379}; else docker run --rm --name argocd-redis -i -p ${ARGOCD_E2E_REDIS_PORT:-6379}:${ARGOCD_E2E_REDIS_PORT:-6379} docker.io/library/redis:$(grep "image: redis" manifests/base/redis/argocd-redis-deployment.yaml | cut -d':' -f3) --save '' --appendonly no --port ${ARGOCD_E2E_REDIS_PORT:-6379}; fi"
|
||||
repo-server: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "GOCOVERDIR=${ARGOCD_COVERAGE_DIR:-/tmp/coverage/repo-server} FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_GNUPGHOME=${ARGOCD_GNUPGHOME:-/tmp/argocd-local/gpg/keys} ARGOCD_PLUGINSOCKFILEPATH=${ARGOCD_PLUGINSOCKFILEPATH:-./test/cmp} ARGOCD_GPG_DATA_PATH=${ARGOCD_GPG_DATA_PATH:-/tmp/argocd-local/gpg/source} ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-repo-server ARGOCD_GPG_ENABLED=${ARGOCD_GPG_ENABLED:-false} $COMMAND --loglevel debug --port ${ARGOCD_E2E_REPOSERVER_PORT:-8081} --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --otlp-address=${ARGOCD_OTLP_ADDRESS}"
|
||||
cmp-server: [ "$ARGOCD_E2E_TEST" = 'true' ] && exit 0 || [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_BINARY_NAME=argocd-cmp-server ARGOCD_PLUGINSOCKFILEPATH=${ARGOCD_PLUGINSOCKFILEPATH:-./test/cmp} $COMMAND --config-dir-path ./test/cmp --loglevel debug --otlp-address=${ARGOCD_OTLP_ADDRESS}"
|
||||
commit-server: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "GOCOVERDIR=${ARGOCD_COVERAGE_DIR:-/tmp/coverage/commit-server} FORCE_LOG_COLORS=1 ARGOCD_BINARY_NAME=argocd-commit-server $COMMAND --loglevel debug --port ${ARGOCD_E2E_COMMITSERVER_PORT:-8086}"
|
||||
ui: sh -c 'cd ui && ${ARGOCD_E2E_YARN_CMD:-yarn} start'
|
||||
git-server: test/fixture/testrepos/start-git.sh
|
||||
helm-registry: test/fixture/testrepos/start-helm-registry.sh
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
[](https://codecov.io/gh/argoproj/argo-cd)
|
||||
[](https://bestpractices.coreinfrastructure.org/projects/4486)
|
||||
[](https://scorecard.dev/viewer/?uri=github.com/argoproj/argo-cd)
|
||||
[](https://app.fossa.com/projects/git%2Bgithub.com%2Fargoproj%2Fargo-cd?ref=badge_shield)
|
||||
|
||||
**Social:**
|
||||
[](https://twitter.com/argoproj)
|
||||
@@ -56,7 +57,7 @@ Participation in the Argo CD project is governed by the [CNCF Code of Conduct](h
|
||||
### Blogs and Presentations
|
||||
|
||||
1. [Awesome-Argo: A Curated List of Awesome Projects and Resources Related to Argo](https://github.com/terrytangyuan/awesome-argo)
|
||||
1. [Unveil the Secret Ingredients of Continuous Delivery at Enterprise Scale with Argo CD](https://akuity.io/blog/secret-ingredients-of-continuous-delivery-at-enterprise-scale-with-argocd/)
|
||||
1. [Unveil the Secret Ingredients of Continuous Delivery at Enterprise Scale with Argo CD](https://akuity.io/blog/unveil-the-secret-ingredients-of-continuous-delivery-at-enterprise-scale-with-argocd-kubecon-china-2021/)
|
||||
1. [GitOps Without Pipelines With ArgoCD Image Updater](https://youtu.be/avPUQin9kzU)
|
||||
1. [Combining Argo CD (GitOps), Crossplane (Control Plane), And KubeVela (OAM)](https://youtu.be/eEcgn_gU3SM)
|
||||
1. [How to Apply GitOps to Everything - Combining Argo CD and Crossplane](https://youtu.be/yrj4lmScKHQ)
|
||||
|
||||
@@ -3,9 +3,9 @@ header:
|
||||
expiration-date: '2024-10-31T00:00:00.000Z' # One year from initial release.
|
||||
last-updated: '2023-10-27'
|
||||
last-reviewed: '2023-10-27'
|
||||
commit-hash: 74a367d10e7110209610ba3ec225539ebe5f7522
|
||||
commit-hash: fe606708859574b9b6102a505e260fac5d3fb14e
|
||||
project-url: https://github.com/argoproj/argo-cd
|
||||
project-release: v2.14.0
|
||||
project-release: v2.13.0
|
||||
changelog: https://github.com/argoproj/argo-cd/releases
|
||||
license: https://github.com/argoproj/argo-cd/blob/master/LICENSE
|
||||
project-lifecycle:
|
||||
|
||||
23
USERS.md
23
USERS.md
@@ -16,8 +16,6 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [Adyen](https://www.adyen.com)
|
||||
1. [AirQo](https://airqo.net/)
|
||||
1. [Akuity](https://akuity.io/)
|
||||
1. [Alarm.com](https://alarm.com/)
|
||||
1. [Alauda](https://alauda.io/)
|
||||
1. [Albert Heijn](https://ah.nl/)
|
||||
1. [Alibaba Group](https://www.alibabagroup.com/)
|
||||
1. [Allianz Direct](https://www.allianzdirect.de/)
|
||||
@@ -30,14 +28,13 @@ 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)
|
||||
1. [Arturia](https://www.arturia.com)
|
||||
2. [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)
|
||||
1. [Axians ACSP](https://www.axians.fr)
|
||||
1. [Axual B.V.](https://axual.com)
|
||||
1. [Back Market](https://www.backmarket.com)
|
||||
1. [Bajaj Finserv Health Ltd.](https://www.bajajfinservhealth.in)
|
||||
1. [Baloise](https://www.baloise.com)
|
||||
1. [BCDevExchange DevOps Platform](https://bcdevexchange.org/DevOpsPlatform)
|
||||
1. [Beat](https://thebeat.co/en/)
|
||||
@@ -79,7 +76,6 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [Codility](https://www.codility.com/)
|
||||
1. [Cognizant](https://www.cognizant.com/)
|
||||
1. [Commonbond](https://commonbond.co/)
|
||||
1. [Compatio.AI](https://compatio.ai/)
|
||||
1. [Contlo](https://contlo.com/)
|
||||
1. [Coralogix](https://coralogix.com/)
|
||||
1. [Crédit Agricole CIB](https://www.ca-cib.com)
|
||||
@@ -89,13 +85,11 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [D2iQ](https://www.d2iq.com)
|
||||
1. [DaoCloud](https://daocloud.io/)
|
||||
1. [Datarisk](https://www.datarisk.io/)
|
||||
1. [Daydream](https://daydream.ing)
|
||||
1. [Deloitte](https://www.deloitte.com/)
|
||||
1. [Deutsche Telekom AG](https://telekom.com)
|
||||
1. [Devopsi - Poland Software/DevOps Consulting](https://devopsi.pl/)
|
||||
1. [Devtron Labs](https://github.com/devtron-labs/devtron)
|
||||
1. [DigitalOcean](https://www.digitalocean.com)
|
||||
1. [Divar](https://divar.ir)
|
||||
1. [Divistant](https://divistant.com)
|
||||
1. [Dott](https://ridedott.com)
|
||||
1. [Doximity](https://www.doximity.com/)
|
||||
@@ -121,7 +115,6 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [freee](https://corp.freee.co.jp/en/company/)
|
||||
1. [Freshop, Inc](https://www.freshop.com/)
|
||||
1. [Future PLC](https://www.futureplc.com/)
|
||||
1. [Flagler Health](https://www.flaglerhealth.io/)
|
||||
1. [G DATA CyberDefense AG](https://www.gdata-software.com/)
|
||||
1. [G-Research](https://www.gresearch.com/teams/open-source-software/)
|
||||
1. [Garner](https://www.garnercorp.com)
|
||||
@@ -147,7 +140,6 @@ 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)
|
||||
@@ -193,10 +185,10 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [Lian Chu Securities](https://lczq.com)
|
||||
1. [Liatrio](https://www.liatrio.com)
|
||||
1. [Lightricks](https://www.lightricks.com/)
|
||||
1. [LINE](https://linecorp.com/en/)
|
||||
1. [Loom](https://www.loom.com/)
|
||||
1. [Lucid Motors](https://www.lucidmotors.com/)
|
||||
1. [Lytt](https://www.lytt.co/)
|
||||
1. [LY Corporation](https://www.lycorp.co.jp/en/)
|
||||
1. [Magic Leap](https://www.magicleap.com/)
|
||||
1. [Majid Al Futtaim](https://www.majidalfuttaim.com/)
|
||||
1. [Major League Baseball](https://mlb.com)
|
||||
@@ -251,7 +243,6 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [Optoro](https://www.optoro.com/)
|
||||
1. [Orbital Insight](https://orbitalinsight.com/)
|
||||
1. [Oscar Health Insurance](https://hioscar.com/)
|
||||
1. [Outpost24](https://outpost24.com/)
|
||||
1. [p3r](https://www.p3r.one/)
|
||||
1. [Packlink](https://www.packlink.com/)
|
||||
1. [PagerDuty](https://www.pagerduty.com/)
|
||||
@@ -270,7 +261,6 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [PITS Globale Datenrettungsdienste](https://www.pitsdatenrettung.de/)
|
||||
1. [Platform9 Systems](https://platform9.com/)
|
||||
1. [Polarpoint.io](https://polarpoint.io)
|
||||
1. [Pollinate](https://www.pollinate.global)
|
||||
1. [PostFinance](https://github.com/postfinance)
|
||||
1. [Preferred Networks](https://preferred.jp/en/)
|
||||
1. [Previder BV](https://previder.nl)
|
||||
@@ -281,7 +271,6 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [PT Boer Technology (Btech)](https://btech.id/)
|
||||
1. [PUBG](https://www.pubg.com)
|
||||
1. [Puzzle ITC](https://www.puzzle.ch/)
|
||||
1. [Pvotal Technologies](https://pvotal.tech/)
|
||||
1. [Qonto](https://qonto.com)
|
||||
1. [QuintoAndar](https://quintoandar.com.br)
|
||||
1. [Quipper](https://www.quipper.com/)
|
||||
@@ -318,7 +307,6 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [Skyscanner](https://www.skyscanner.net/)
|
||||
1. [Smart Pension](https://www.smartpension.co.uk/)
|
||||
1. [Smilee.io](https://smilee.io)
|
||||
1. [Smilegate Stove](https://www.onstove.com/)
|
||||
1. [Smood.ch](https://www.smood.ch/)
|
||||
1. [Snapp](https://snapp.ir/)
|
||||
1. [Snyk](https://snyk.io/)
|
||||
@@ -338,17 +326,14 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [Swisscom](https://www.swisscom.ch)
|
||||
1. [Swissquote](https://github.com/swissquote)
|
||||
1. [Syncier](https://syncier.com/)
|
||||
1. [Synergy](https://synergy.net.au)
|
||||
1. [Syself](https://syself.com)
|
||||
1. [TableCheck](https://tablecheck.com/)
|
||||
1. [Tailor Brands](https://www.tailorbrands.com)
|
||||
1. [Tamkeen Technologies](https://tamkeentech.sa/)
|
||||
1. [TBC Bank](https://tbcbank.ge/)
|
||||
1. [Techcombank](https://www.techcombank.com.vn/trang-chu)
|
||||
1. [Technacy](https://www.technacy.it/)
|
||||
1. [Telavita](https://www.telavita.com.br/)
|
||||
1. [Tesla](https://tesla.com/)
|
||||
1. [TextNow](https://www.textnow.com/)
|
||||
1. [The Scale Factory](https://www.scalefactory.com/)
|
||||
1. [ThousandEyes](https://www.thousandeyes.com/)
|
||||
1. [Ticketmaster](https://ticketmaster.com)
|
||||
@@ -377,7 +362,6 @@ 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/)
|
||||
@@ -392,12 +376,9 @@ 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/)
|
||||
1. [ZDF](https://www.zdf.de/)
|
||||
1. [Zimpler](https://www.zimpler.com/)
|
||||
1. [ZipRecuiter](https://www.ziprecruiter.com/)
|
||||
1. [ZOZO](https://corp.zozo.com/)
|
||||
|
||||
|
||||
@@ -18,9 +18,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"runtime/debug"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -28,7 +26,7 @@ import (
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
log "github.com/sirupsen/logrus"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
apierr "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
@@ -45,19 +43,20 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/controllers/template"
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/generators"
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/metrics"
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/status"
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/utils"
|
||||
"github.com/argoproj/argo-cd/v3/common"
|
||||
"github.com/argoproj/argo-cd/v3/util/db"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/controllers/template"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/generators"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/metrics"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/status"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/utils"
|
||||
"github.com/argoproj/argo-cd/v2/common"
|
||||
"github.com/argoproj/argo-cd/v2/util/db"
|
||||
|
||||
argov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
argoutil "github.com/argoproj/argo-cd/v3/util/argo"
|
||||
"github.com/argoproj/argo-cd/v3/util/argo/normalizers"
|
||||
argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
appclientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned"
|
||||
argoutil "github.com/argoproj/argo-cd/v2/util/argo"
|
||||
"github.com/argoproj/argo-cd/v2/util/argo/normalizers"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/pkg/apis/application"
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/application"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -80,6 +79,7 @@ type ApplicationSetReconciler struct {
|
||||
Recorder record.EventRecorder
|
||||
Generators map[string]generators.Generator
|
||||
ArgoDB db.ArgoDB
|
||||
ArgoAppClientset appclientset.Interface
|
||||
KubeClientset kubernetes.Interface
|
||||
Policy argov1alpha1.ApplicationsSyncPolicy
|
||||
EnablePolicyOverride bool
|
||||
@@ -96,22 +96,9 @@ type ApplicationSetReconciler struct {
|
||||
// +kubebuilder:rbac:groups=argoproj.io,resources=applicationsets,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups=argoproj.io,resources=applicationsets/status,verbs=get;update;patch
|
||||
|
||||
func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, err error) {
|
||||
startReconcile := time.Now()
|
||||
func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||
logCtx := log.WithField("applicationset", req.NamespacedName)
|
||||
|
||||
defer func() {
|
||||
if rec := recover(); rec != nil {
|
||||
logCtx.Errorf("Recovered from panic: %+v\n%s", rec, debug.Stack())
|
||||
result = ctrl.Result{}
|
||||
var ok bool
|
||||
err, ok = rec.(error)
|
||||
if !ok {
|
||||
err = fmt.Errorf("%v", r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
var applicationSetInfo argov1alpha1.ApplicationSet
|
||||
parametersGenerated := false
|
||||
startTime := time.Now()
|
||||
@@ -155,7 +142,6 @@ 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{
|
||||
@@ -165,8 +151,7 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
|
||||
Status: argov1alpha1.ApplicationSetConditionStatusTrue,
|
||||
}, parametersGenerated,
|
||||
)
|
||||
// In order for the controller SDK to respect RequeueAfter, the error must be nil
|
||||
return ctrl.Result{RequeueAfter: ReconcileRequeueOnValidationError}, nil
|
||||
return ctrl.Result{RequeueAfter: ReconcileRequeueOnValidationError}, err
|
||||
}
|
||||
|
||||
parametersGenerated = true
|
||||
@@ -349,7 +334,7 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
|
||||
requeueAfter = ReconcileRequeueOnValidationError
|
||||
}
|
||||
|
||||
logCtx.WithField("requeueAfter", requeueAfter).Info("end reconcile in ", time.Since(startReconcile))
|
||||
logCtx.WithField("requeueAfter", requeueAfter).Info("end reconcile")
|
||||
|
||||
return ctrl.Result{
|
||||
RequeueAfter: requeueAfter,
|
||||
@@ -467,7 +452,7 @@ func (r *ApplicationSetReconciler) setApplicationSetStatusCondition(ctx context.
|
||||
updatedAppset.DeepCopyInto(applicationSet)
|
||||
return nil
|
||||
})
|
||||
if err != nil && !apierrors.IsNotFound(err) {
|
||||
if err != nil && !apierr.IsNotFound(err) {
|
||||
return fmt.Errorf("unable to set application set condition: %w", err)
|
||||
}
|
||||
}
|
||||
@@ -481,23 +466,22 @@ func (r *ApplicationSetReconciler) validateGeneratedApplications(ctx context.Con
|
||||
errorsByIndex := map[int]error{}
|
||||
namesSet := map[string]bool{}
|
||||
for i, app := range desiredApplications {
|
||||
if namesSet[app.Name] {
|
||||
if !namesSet[app.Name] {
|
||||
namesSet[app.Name] = true
|
||||
} else {
|
||||
errorsByIndex[i] = fmt.Errorf("ApplicationSet %s contains applications with duplicate name: %s", applicationSetInfo.Name, app.Name)
|
||||
continue
|
||||
}
|
||||
namesSet[app.Name] = true
|
||||
|
||||
appProject := &argov1alpha1.AppProject{}
|
||||
err := r.Client.Get(ctx, types.NamespacedName{Name: app.Spec.Project, Namespace: r.ArgoCDNamespace}, appProject)
|
||||
_, err := r.ArgoAppClientset.ArgoprojV1alpha1().AppProjects(r.ArgoCDNamespace).Get(ctx, app.Spec.GetProject(), metav1.GetOptions{})
|
||||
if err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
if apierr.IsNotFound(err) {
|
||||
errorsByIndex[i] = fmt.Errorf("application references project %s which does not exist", app.Spec.Project)
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err = argoutil.GetDestinationCluster(ctx, app.Spec.Destination, r.ArgoDB); err != nil {
|
||||
if err := utils.ValidateDestination(ctx, &app.Spec.Destination, r.KubeClientset, r.ArgoCDNamespace); err != nil {
|
||||
errorsByIndex[i] = fmt.Errorf("application destination spec is invalid: %s", err.Error())
|
||||
continue
|
||||
}
|
||||
@@ -552,13 +536,12 @@ func (r *ApplicationSetReconciler) SetupWithManager(mgr ctrl.Manager, enableProg
|
||||
return fmt.Errorf("error setting up with manager: %w", err)
|
||||
}
|
||||
|
||||
appOwnsHandler := getApplicationOwnsHandler(enableProgressiveSyncs)
|
||||
appSetOwnsHandler := getApplicationSetOwnsHandler()
|
||||
ownsHandler := getOwnsHandlerPredicates(enableProgressiveSyncs)
|
||||
|
||||
return ctrl.NewControllerManagedBy(mgr).WithOptions(controller.Options{
|
||||
MaxConcurrentReconciles: maxConcurrentReconciliations,
|
||||
}).For(&argov1alpha1.ApplicationSet{}, builder.WithPredicates(appSetOwnsHandler)).
|
||||
Owns(&argov1alpha1.Application{}, builder.WithPredicates(appOwnsHandler)).
|
||||
}).For(&argov1alpha1.ApplicationSet{}).
|
||||
Owns(&argov1alpha1.Application{}, builder.WithPredicates(ownsHandler)).
|
||||
WithEventFilter(ignoreNotAllowedNamespaces(r.ApplicationSetNamespaces)).
|
||||
Watches(
|
||||
&corev1.Secret{},
|
||||
@@ -566,6 +549,7 @@ func (r *ApplicationSetReconciler) SetupWithManager(mgr ctrl.Manager, enableProg
|
||||
Client: mgr.GetClient(),
|
||||
Log: log.WithField("type", "createSecretEventHandler"),
|
||||
}).
|
||||
// TODO: also watch Applications and respond on changes if we own them.
|
||||
Complete(r)
|
||||
}
|
||||
|
||||
@@ -720,6 +704,9 @@ func (r *ApplicationSetReconciler) getCurrentApplications(ctx context.Context, a
|
||||
// deleteInCluster will delete Applications that are currently on the cluster, but not in appList.
|
||||
// The function must be called after all generators had been called and generated applications
|
||||
func (r *ApplicationSetReconciler) deleteInCluster(ctx context.Context, logCtx *log.Entry, applicationSet argov1alpha1.ApplicationSet, desiredApplications []argov1alpha1.Application) error {
|
||||
// settingsMgr := settings.NewSettingsManager(context.TODO(), r.KubeClientset, applicationSet.Namespace)
|
||||
// argoDB := db.NewDB(applicationSet.Namespace, settingsMgr, r.KubeClientset)
|
||||
// clusterList, err := argoDB.ListClusters(ctx)
|
||||
clusterList, err := utils.ListClusters(ctx, r.KubeClientset, r.ArgoCDNamespace)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error listing clusters: %w", err)
|
||||
@@ -770,7 +757,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 []utils.ClusterSpecifier, appLog *log.Entry) error {
|
||||
func (r *ApplicationSetReconciler) removeFinalizerOnInvalidDestination(ctx context.Context, applicationSet argov1alpha1.ApplicationSet, app *argov1alpha1.Application, clusterList *argov1alpha1.ClusterList, 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
|
||||
@@ -779,18 +766,21 @@ func (r *ApplicationSetReconciler) removeFinalizerOnInvalidDestination(ctx conte
|
||||
var validDestination bool
|
||||
|
||||
// Detect if the destination is invalid (name doesn't correspond to a matching cluster)
|
||||
if destCluster, err := argoutil.GetDestinationCluster(ctx, app.Spec.Destination, r.ArgoDB); err != nil {
|
||||
if err := utils.ValidateDestination(ctx, &app.Spec.Destination, r.KubeClientset, r.ArgoCDNamespace); err != nil {
|
||||
appLog.Warnf("The destination cluster for %s couldn't be found: %v", app.Name, err)
|
||||
validDestination = false
|
||||
} else {
|
||||
// Detect if the destination's server field does not match an existing cluster
|
||||
|
||||
matchingCluster := false
|
||||
for _, cluster := range clusterList {
|
||||
if destCluster.Server != cluster.Server {
|
||||
for _, cluster := range clusterList.Items {
|
||||
// Server fields must match. Note that ValidateDestination ensures that the server field is set, if applicable.
|
||||
if app.Spec.Destination.Server != cluster.Server {
|
||||
continue
|
||||
}
|
||||
|
||||
if destCluster.Name != cluster.Name {
|
||||
// The name must match, if it is not empty
|
||||
if app.Spec.Destination.Name != "" && cluster.Name != app.Spec.Destination.Name {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -975,16 +965,17 @@ func (r *ApplicationSetReconciler) buildAppSyncMap(applicationSet argov1alpha1.A
|
||||
}
|
||||
|
||||
appStatus := applicationSet.Status.ApplicationStatus[idx]
|
||||
app, ok := appMap[appName]
|
||||
if !ok {
|
||||
|
||||
if app, ok := appMap[appName]; ok {
|
||||
syncEnabled = appSyncEnabledForNextStep(&applicationSet, app, appStatus)
|
||||
if !syncEnabled {
|
||||
break
|
||||
}
|
||||
} else {
|
||||
// application name not found in the list of applications managed by this ApplicationSet, maybe because it's being deleted
|
||||
syncEnabled = false
|
||||
break
|
||||
}
|
||||
syncEnabled = appSyncEnabledForNextStep(&applicationSet, app, appStatus)
|
||||
if !syncEnabled {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1053,21 +1044,20 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatus(ctx con
|
||||
LastTransitionTime: &now,
|
||||
Message: "No Application status found, defaulting status to Waiting.",
|
||||
Status: "Waiting",
|
||||
Step: strconv.Itoa(getAppStep(app.Name, appStepMap)),
|
||||
Step: fmt.Sprint(getAppStep(app.Name, appStepMap)),
|
||||
TargetRevisions: app.Status.GetRevisions(),
|
||||
}
|
||||
} else {
|
||||
// we have an existing AppStatus
|
||||
currentAppStatus = applicationSet.Status.ApplicationStatus[idx]
|
||||
if !reflect.DeepEqual(currentAppStatus.TargetRevisions, app.Status.GetRevisions()) {
|
||||
currentAppStatus.Message = "Application has pending changes, setting status to Waiting."
|
||||
|
||||
// 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.TargetRevisions = app.Status.GetRevisions()
|
||||
currentAppStatus.Status = "Waiting"
|
||||
currentAppStatus.LastTransitionTime = &now
|
||||
currentAppStatus.Step = strconv.Itoa(getAppStep(currentAppStatus.Application, appStepMap))
|
||||
}
|
||||
|
||||
appOutdated := false
|
||||
if progressiveSyncsRollingSyncStrategyEnabled(applicationSet) {
|
||||
@@ -1079,22 +1069,32 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatus(ctx con
|
||||
currentAppStatus.LastTransitionTime = &now
|
||||
currentAppStatus.Status = "Waiting"
|
||||
currentAppStatus.Message = "Application has pending changes, setting status to Waiting."
|
||||
currentAppStatus.Step = strconv.Itoa(getAppStep(currentAppStatus.Application, appStepMap))
|
||||
currentAppStatus.Step = fmt.Sprint(getAppStep(currentAppStatus.Application, appStepMap))
|
||||
currentAppStatus.TargetRevisions = app.Status.GetRevisions()
|
||||
}
|
||||
|
||||
if currentAppStatus.Status == "Pending" {
|
||||
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))
|
||||
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 = fmt.Sprint(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
|
||||
currentAppStatus.Status = "Progressing"
|
||||
currentAppStatus.Message = "Application resource became Progressing, updating status from Pending to Progressing."
|
||||
currentAppStatus.Step = strconv.Itoa(getAppStep(currentAppStatus.Application, appStepMap))
|
||||
currentAppStatus.Step = fmt.Sprint(getAppStep(currentAppStatus.Application, appStepMap))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1103,7 +1103,7 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatus(ctx con
|
||||
currentAppStatus.LastTransitionTime = &now
|
||||
currentAppStatus.Status = healthStatusString
|
||||
currentAppStatus.Message = "Application resource is already Healthy, updating status from Waiting to Healthy."
|
||||
currentAppStatus.Step = strconv.Itoa(getAppStep(currentAppStatus.Application, appStepMap))
|
||||
currentAppStatus.Step = fmt.Sprint(getAppStep(currentAppStatus.Application, appStepMap))
|
||||
}
|
||||
|
||||
if currentAppStatus.Status == "Progressing" && isApplicationHealthy(app) {
|
||||
@@ -1111,7 +1111,7 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatus(ctx con
|
||||
currentAppStatus.LastTransitionTime = &now
|
||||
currentAppStatus.Status = healthStatusString
|
||||
currentAppStatus.Message = "Application resource became Healthy, updating status from Progressing to Healthy."
|
||||
currentAppStatus.Step = strconv.Itoa(getAppStep(currentAppStatus.Application, appStepMap))
|
||||
currentAppStatus.Step = fmt.Sprint(getAppStep(currentAppStatus.Application, appStepMap))
|
||||
}
|
||||
|
||||
appStatuses = append(appStatuses, currentAppStatus)
|
||||
@@ -1145,10 +1145,10 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatusProgress
|
||||
|
||||
// populate updateCountMap with counts of existing Pending and Progressing Applications
|
||||
for _, appStatus := range applicationSet.Status.ApplicationStatus {
|
||||
totalCountMap[appStepMap[appStatus.Application]]++
|
||||
totalCountMap[appStepMap[appStatus.Application]] += 1
|
||||
|
||||
if appStatus.Status == "Pending" || appStatus.Status == "Progressing" {
|
||||
updateCountMap[appStepMap[appStatus.Application]]++
|
||||
updateCountMap[appStepMap[appStatus.Application]] += 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1182,9 +1182,9 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatusProgress
|
||||
appStatus.LastTransitionTime = &now
|
||||
appStatus.Status = "Pending"
|
||||
appStatus.Message = "Application moved to Pending status, watching for the Application resource to start Progressing."
|
||||
appStatus.Step = strconv.Itoa(getAppStep(appStatus.Application, appStepMap))
|
||||
appStatus.Step = fmt.Sprint(getAppStep(appStatus.Application, appStepMap))
|
||||
|
||||
updateCountMap[appStepMap[appStatus.Application]]++
|
||||
updateCountMap[appStepMap[appStatus.Application]] += 1
|
||||
}
|
||||
|
||||
appStatuses = append(appStatuses, appStatus)
|
||||
@@ -1285,7 +1285,7 @@ func (r *ApplicationSetReconciler) migrateStatus(ctx context.Context, appset *ar
|
||||
updatedAppset.DeepCopyInto(appset)
|
||||
return nil
|
||||
})
|
||||
if err != nil && !apierrors.IsNotFound(err) {
|
||||
if err != nil && !apierr.IsNotFound(err) {
|
||||
return fmt.Errorf("unable to set application set condition: %w", err)
|
||||
}
|
||||
}
|
||||
@@ -1450,7 +1450,7 @@ func syncApplication(application argov1alpha1.Application, prune bool) argov1alp
|
||||
return application
|
||||
}
|
||||
|
||||
func getApplicationOwnsHandler(enableProgressiveSyncs bool) predicate.Funcs {
|
||||
func getOwnsHandlerPredicates(enableProgressiveSyncs bool) predicate.Funcs {
|
||||
return predicate.Funcs{
|
||||
CreateFunc: func(e event.CreateEvent) bool {
|
||||
// if we are the owner and there is a create event, we most likely created it and do not need to
|
||||
@@ -1487,8 +1487,8 @@ func getApplicationOwnsHandler(enableProgressiveSyncs bool) predicate.Funcs {
|
||||
if !isApp {
|
||||
return false
|
||||
}
|
||||
requeue := shouldRequeueForApplication(appOld, appNew, enableProgressiveSyncs)
|
||||
logCtx.WithField("requeue", requeue).Debugf("requeue caused by application %s", appNew.Name)
|
||||
requeue := shouldRequeueApplicationSet(appOld, appNew, enableProgressiveSyncs)
|
||||
logCtx.WithField("requeue", requeue).Debugf("requeue: %t caused by application %s\n", requeue, appNew.Name)
|
||||
return requeue
|
||||
},
|
||||
GenericFunc: func(e event.GenericEvent) bool {
|
||||
@@ -1505,13 +1505,13 @@ func getApplicationOwnsHandler(enableProgressiveSyncs bool) predicate.Funcs {
|
||||
}
|
||||
}
|
||||
|
||||
// shouldRequeueForApplication determines when we want to requeue an ApplicationSet for reconciling based on an owned
|
||||
// shouldRequeueApplicationSet determines when we want to requeue an ApplicationSet for reconciling based on an owned
|
||||
// application change
|
||||
// The applicationset controller owns a subset of the Application CR.
|
||||
// We do not need to re-reconcile if parts of the application change outside the applicationset's control.
|
||||
// An example being, Application.ApplicationStatus.ReconciledAt which gets updated by the application controller.
|
||||
// Additionally, Application.ObjectMeta.ResourceVersion and Application.ObjectMeta.Generation which are set by K8s.
|
||||
func shouldRequeueForApplication(appOld *argov1alpha1.Application, appNew *argov1alpha1.Application, enableProgressiveSyncs bool) bool {
|
||||
func shouldRequeueApplicationSet(appOld *argov1alpha1.Application, appNew *argov1alpha1.Application, enableProgressiveSyncs bool) bool {
|
||||
if appOld == nil || appNew == nil {
|
||||
return false
|
||||
}
|
||||
@@ -1544,81 +1544,4 @@ func shouldRequeueForApplication(appOld *argov1alpha1.Application, appNew *argov
|
||||
return false
|
||||
}
|
||||
|
||||
func getApplicationSetOwnsHandler() predicate.Funcs {
|
||||
return predicate.Funcs{
|
||||
CreateFunc: func(e event.CreateEvent) bool {
|
||||
appSet, isApp := e.Object.(*argov1alpha1.ApplicationSet)
|
||||
if !isApp {
|
||||
return false
|
||||
}
|
||||
log.WithField("applicationset", appSet.QualifiedName()).Debugln("received create event")
|
||||
// Always queue a new applicationset
|
||||
return true
|
||||
},
|
||||
DeleteFunc: func(e event.DeleteEvent) bool {
|
||||
appSet, isApp := e.Object.(*argov1alpha1.ApplicationSet)
|
||||
if !isApp {
|
||||
return false
|
||||
}
|
||||
log.WithField("applicationset", appSet.QualifiedName()).Debugln("received delete event")
|
||||
// Always queue for the deletion of an applicationset
|
||||
return true
|
||||
},
|
||||
UpdateFunc: func(e event.UpdateEvent) bool {
|
||||
appSetOld, isAppSet := e.ObjectOld.(*argov1alpha1.ApplicationSet)
|
||||
if !isAppSet {
|
||||
return false
|
||||
}
|
||||
appSetNew, isAppSet := e.ObjectNew.(*argov1alpha1.ApplicationSet)
|
||||
if !isAppSet {
|
||||
return false
|
||||
}
|
||||
requeue := shouldRequeueForApplicationSet(appSetOld, appSetNew)
|
||||
log.WithField("applicationset", appSetNew.QualifiedName()).
|
||||
WithField("requeue", requeue).Debugln("received update event")
|
||||
return requeue
|
||||
},
|
||||
GenericFunc: func(e event.GenericEvent) bool {
|
||||
appSet, isApp := e.Object.(*argov1alpha1.ApplicationSet)
|
||||
if !isApp {
|
||||
return false
|
||||
}
|
||||
log.WithField("applicationset", appSet.QualifiedName()).Debugln("received generic event")
|
||||
// Always queue for the generic of an applicationset
|
||||
return true
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// shouldRequeueForApplicationSet determines when we need to requeue an applicationset
|
||||
func shouldRequeueForApplicationSet(appSetOld, appSetNew *argov1alpha1.ApplicationSet) bool {
|
||||
if appSetOld == nil || appSetNew == nil {
|
||||
return false
|
||||
}
|
||||
// only compare the applicationset spec, annotations, labels and finalizers, specifically avoiding
|
||||
// the status field. status is owned by the applicationset controller,
|
||||
// and we do not need to requeue when it does bookkeeping
|
||||
// NB: the ApplicationDestination comes from the ApplicationSpec being embedded
|
||||
// in the ApplicationSetTemplate from the generators
|
||||
if !cmp.Equal(appSetOld.Spec, appSetNew.Spec, cmpopts.EquateEmpty(), cmpopts.EquateComparable(argov1alpha1.ApplicationDestination{})) ||
|
||||
!cmp.Equal(appSetOld.ObjectMeta.GetLabels(), appSetNew.ObjectMeta.GetLabels(), cmpopts.EquateEmpty()) ||
|
||||
!cmp.Equal(appSetOld.ObjectMeta.GetFinalizers(), appSetNew.ObjectMeta.GetFinalizers(), cmpopts.EquateEmpty()) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Requeue only when the refresh annotation is newly added to the ApplicationSet.
|
||||
// Changes to other annotations made simultaneously might be missed, but such cases are rare.
|
||||
if !cmp.Equal(appSetOld.ObjectMeta.GetAnnotations(), appSetNew.ObjectMeta.GetAnnotations(), cmpopts.EquateEmpty()) {
|
||||
_, oldHasRefreshAnnotation := appSetOld.Annotations[common.AnnotationApplicationSetRefresh]
|
||||
_, newHasRefreshAnnotation := appSetNew.Annotations[common.AnnotationApplicationSetRefresh]
|
||||
|
||||
if oldHasRefreshAnnotation && !newHasRefreshAnnotation {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
var _ handler.EventHandler = &clusterSecretEventHandler{}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,8 +14,8 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/event"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/common"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/generators"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
// clusterSecretEventHandler is used when watching Secrets to check if they are ArgoCD Cluster Secrets, and if so
|
||||
@@ -50,7 +50,7 @@ type addRateLimitingInterface[T comparable] interface {
|
||||
|
||||
func (h *clusterSecretEventHandler) queueRelatedAppGenerators(ctx context.Context, q addRateLimitingInterface[reconcile.Request], object client.Object) {
|
||||
// Check for label, lookup all ApplicationSets that might match the cluster, queue them all
|
||||
if object.GetLabels()[common.LabelKeySecretType] != common.LabelValueSecretTypeCluster {
|
||||
if object.GetLabels()[generators.ArgoCDSecretTypeLabel] != generators.ArgoCDSecretTypeCluster {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
argocommon "github.com/argoproj/argo-cd/v3/common"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
|
||||
argov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/generators"
|
||||
argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
func TestClusterEventHandler(t *testing.T) {
|
||||
@@ -38,11 +38,11 @@ func TestClusterEventHandler(t *testing.T) {
|
||||
name: "no application sets should mean no requests",
|
||||
items: []argov1alpha1.ApplicationSet{},
|
||||
secret: corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "argocd",
|
||||
Name: "my-secret",
|
||||
Labels: map[string]string{
|
||||
argocommon.LabelKeySecretType: argocommon.LabelValueSecretTypeCluster,
|
||||
generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -52,7 +52,7 @@ func TestClusterEventHandler(t *testing.T) {
|
||||
name: "a cluster generator should produce a request",
|
||||
items: []argov1alpha1.ApplicationSet{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "my-app-set",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
@@ -66,11 +66,11 @@ func TestClusterEventHandler(t *testing.T) {
|
||||
},
|
||||
},
|
||||
secret: corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "argocd",
|
||||
Name: "my-secret",
|
||||
Labels: map[string]string{
|
||||
argocommon.LabelKeySecretType: argocommon.LabelValueSecretTypeCluster,
|
||||
generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -82,7 +82,7 @@ func TestClusterEventHandler(t *testing.T) {
|
||||
name: "multiple cluster generators should produce multiple requests",
|
||||
items: []argov1alpha1.ApplicationSet{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "my-app-set",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
@@ -95,7 +95,7 @@ func TestClusterEventHandler(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "my-app-set2",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
@@ -109,11 +109,11 @@ func TestClusterEventHandler(t *testing.T) {
|
||||
},
|
||||
},
|
||||
secret: corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "argocd",
|
||||
Name: "my-secret",
|
||||
Labels: map[string]string{
|
||||
argocommon.LabelKeySecretType: argocommon.LabelValueSecretTypeCluster,
|
||||
generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -126,7 +126,7 @@ func TestClusterEventHandler(t *testing.T) {
|
||||
name: "non-cluster generator should not match",
|
||||
items: []argov1alpha1.ApplicationSet{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "my-app-set",
|
||||
Namespace: "another-namespace",
|
||||
},
|
||||
@@ -139,7 +139,7 @@ func TestClusterEventHandler(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "app-set-non-cluster",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
@@ -153,11 +153,11 @@ func TestClusterEventHandler(t *testing.T) {
|
||||
},
|
||||
},
|
||||
secret: corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "argocd",
|
||||
Name: "my-secret",
|
||||
Labels: map[string]string{
|
||||
argocommon.LabelKeySecretType: argocommon.LabelValueSecretTypeCluster,
|
||||
generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -169,7 +169,7 @@ func TestClusterEventHandler(t *testing.T) {
|
||||
name: "non-argo cd secret should not match",
|
||||
items: []argov1alpha1.ApplicationSet{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "my-app-set",
|
||||
Namespace: "another-namespace",
|
||||
},
|
||||
@@ -183,7 +183,7 @@ func TestClusterEventHandler(t *testing.T) {
|
||||
},
|
||||
},
|
||||
secret: corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "argocd",
|
||||
Name: "my-non-argocd-secret",
|
||||
},
|
||||
@@ -194,7 +194,7 @@ func TestClusterEventHandler(t *testing.T) {
|
||||
name: "a matrix generator with a cluster generator should produce a request",
|
||||
items: []argov1alpha1.ApplicationSet{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "my-app-set",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
@@ -214,11 +214,11 @@ func TestClusterEventHandler(t *testing.T) {
|
||||
},
|
||||
},
|
||||
secret: corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "argocd",
|
||||
Name: "my-secret",
|
||||
Labels: map[string]string{
|
||||
argocommon.LabelKeySecretType: argocommon.LabelValueSecretTypeCluster,
|
||||
generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -230,7 +230,7 @@ func TestClusterEventHandler(t *testing.T) {
|
||||
name: "a matrix generator with non cluster generator should not match",
|
||||
items: []argov1alpha1.ApplicationSet{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "my-app-set",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
@@ -250,11 +250,11 @@ func TestClusterEventHandler(t *testing.T) {
|
||||
},
|
||||
},
|
||||
secret: corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "argocd",
|
||||
Name: "my-secret",
|
||||
Labels: map[string]string{
|
||||
argocommon.LabelKeySecretType: argocommon.LabelValueSecretTypeCluster,
|
||||
generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -264,7 +264,7 @@ func TestClusterEventHandler(t *testing.T) {
|
||||
name: "a matrix generator with a nested matrix generator containing a cluster generator should produce a request",
|
||||
items: []argov1alpha1.ApplicationSet{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "my-app-set",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
@@ -300,11 +300,11 @@ func TestClusterEventHandler(t *testing.T) {
|
||||
},
|
||||
},
|
||||
secret: corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "argocd",
|
||||
Name: "my-secret",
|
||||
Labels: map[string]string{
|
||||
argocommon.LabelKeySecretType: argocommon.LabelValueSecretTypeCluster,
|
||||
generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -316,7 +316,7 @@ func TestClusterEventHandler(t *testing.T) {
|
||||
name: "a matrix generator with a nested matrix generator containing non cluster generator should not match",
|
||||
items: []argov1alpha1.ApplicationSet{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "my-app-set",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
@@ -351,11 +351,11 @@ func TestClusterEventHandler(t *testing.T) {
|
||||
},
|
||||
},
|
||||
secret: corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "argocd",
|
||||
Name: "my-secret",
|
||||
Labels: map[string]string{
|
||||
argocommon.LabelKeySecretType: argocommon.LabelValueSecretTypeCluster,
|
||||
generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -365,7 +365,7 @@ func TestClusterEventHandler(t *testing.T) {
|
||||
name: "a merge generator with a cluster generator should produce a request",
|
||||
items: []argov1alpha1.ApplicationSet{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "my-app-set",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
@@ -385,11 +385,11 @@ func TestClusterEventHandler(t *testing.T) {
|
||||
},
|
||||
},
|
||||
secret: corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "argocd",
|
||||
Name: "my-secret",
|
||||
Labels: map[string]string{
|
||||
argocommon.LabelKeySecretType: argocommon.LabelValueSecretTypeCluster,
|
||||
generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -401,7 +401,7 @@ func TestClusterEventHandler(t *testing.T) {
|
||||
name: "a matrix generator with non cluster generator should not match",
|
||||
items: []argov1alpha1.ApplicationSet{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "my-app-set",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
@@ -421,11 +421,11 @@ func TestClusterEventHandler(t *testing.T) {
|
||||
},
|
||||
},
|
||||
secret: corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "argocd",
|
||||
Name: "my-secret",
|
||||
Labels: map[string]string{
|
||||
argocommon.LabelKeySecretType: argocommon.LabelValueSecretTypeCluster,
|
||||
generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -435,7 +435,7 @@ func TestClusterEventHandler(t *testing.T) {
|
||||
name: "a merge generator with a nested merge generator containing a cluster generator should produce a request",
|
||||
items: []argov1alpha1.ApplicationSet{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "my-app-set",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
@@ -471,11 +471,11 @@ func TestClusterEventHandler(t *testing.T) {
|
||||
},
|
||||
},
|
||||
secret: corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "argocd",
|
||||
Name: "my-secret",
|
||||
Labels: map[string]string{
|
||||
argocommon.LabelKeySecretType: argocommon.LabelValueSecretTypeCluster,
|
||||
generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -487,7 +487,7 @@ func TestClusterEventHandler(t *testing.T) {
|
||||
name: "a merge generator with a nested merge generator containing non cluster generator should not match",
|
||||
items: []argov1alpha1.ApplicationSet{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "my-app-set",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
@@ -522,11 +522,11 @@ func TestClusterEventHandler(t *testing.T) {
|
||||
},
|
||||
},
|
||||
secret: corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "argocd",
|
||||
Name: "my-secret",
|
||||
Labels: map[string]string{
|
||||
argocommon.LabelKeySecretType: argocommon.LabelValueSecretTypeCluster,
|
||||
generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -549,7 +549,7 @@ func TestClusterEventHandler(t *testing.T) {
|
||||
|
||||
mockAddRateLimitingInterface := mockAddRateLimitingInterface{}
|
||||
|
||||
handler.queueRelatedAppGenerators(t.Context(), &mockAddRateLimitingInterface, &test.secret)
|
||||
handler.queueRelatedAppGenerators(context.Background(), &mockAddRateLimitingInterface, &test.secret)
|
||||
|
||||
assert.ElementsMatch(t, mockAddRateLimitingInterface.addedItems, test.expectedRequests)
|
||||
})
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -15,15 +16,15 @@ import (
|
||||
"k8s.io/client-go/tools/record"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/generators"
|
||||
appsetmetrics "github.com/argoproj/argo-cd/v3/applicationset/metrics"
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/services/mocks"
|
||||
argov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/generators"
|
||||
appsetmetrics "github.com/argoproj/argo-cd/v2/applicationset/metrics"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/services/mocks"
|
||||
argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
func TestRequeueAfter(t *testing.T) {
|
||||
mockServer := &mocks.Repos{}
|
||||
ctx := t.Context()
|
||||
ctx := context.Background()
|
||||
scheme := runtime.NewScheme()
|
||||
err := argov1alpha1.AddToScheme(scheme)
|
||||
require.NoError(t, err)
|
||||
@@ -35,20 +36,20 @@ func TestRequeueAfter(t *testing.T) {
|
||||
appClientset := kubefake.NewSimpleClientset()
|
||||
k8sClient := fake.NewClientBuilder().Build()
|
||||
duckType := &unstructured.Unstructured{
|
||||
Object: map[string]any{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "v2quack",
|
||||
"kind": "Duck",
|
||||
"metadata": map[string]any{
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "mightyduck",
|
||||
"namespace": "namespace",
|
||||
"labels": map[string]any{"duck": "all-species"},
|
||||
"labels": map[string]interface{}{"duck": "all-species"},
|
||||
},
|
||||
"status": map[string]any{
|
||||
"decisions": []any{
|
||||
map[string]any{
|
||||
"status": map[string]interface{}{
|
||||
"decisions": []interface{}{
|
||||
map[string]interface{}{
|
||||
"clusterName": "staging-01",
|
||||
},
|
||||
map[string]any{
|
||||
map[string]interface{}{
|
||||
"clusterName": "production-01",
|
||||
},
|
||||
},
|
||||
@@ -56,10 +57,10 @@ func TestRequeueAfter(t *testing.T) {
|
||||
},
|
||||
}
|
||||
fakeDynClient := dynfake.NewSimpleDynamicClientWithCustomListKinds(runtime.NewScheme(), gvrToListKind, duckType)
|
||||
scmConfig := generators.NewSCMConfig("", []string{""}, true, nil, true)
|
||||
scmConfig := generators.NewSCMConfig("", []string{""}, true, nil)
|
||||
terminalGenerators := map[string]generators.Generator{
|
||||
"List": generators.NewListGenerator(),
|
||||
"Clusters": generators.NewClusterGenerator(ctx, k8sClient, appClientset, "argocd"),
|
||||
"Clusters": generators.NewClusterGenerator(k8sClient, ctx, appClientset, "argocd"),
|
||||
"Git": generators.NewGitGenerator(mockServer, "namespace"),
|
||||
"SCMProvider": generators.NewSCMProviderGenerator(fake.NewClientBuilder().WithObjects(&corev1.Secret{}).Build(), scmConfig),
|
||||
"ClusterDecisionResource": generators.NewDuckTypeGenerator(ctx, fakeDynClient, appClientset, "argocd"),
|
||||
@@ -89,7 +90,7 @@ func TestRequeueAfter(t *testing.T) {
|
||||
}
|
||||
|
||||
client := fake.NewClientBuilder().WithScheme(scheme).Build()
|
||||
metrics := appsetmetrics.NewFakeAppsetMetrics()
|
||||
metrics := appsetmetrics.NewFakeAppsetMetrics(client)
|
||||
r := ApplicationSetReconciler{
|
||||
Client: client,
|
||||
Scheme: scheme,
|
||||
@@ -99,8 +100,7 @@ func TestRequeueAfter(t *testing.T) {
|
||||
}
|
||||
|
||||
type args struct {
|
||||
appset *argov1alpha1.ApplicationSet
|
||||
requeueAfterOverride string
|
||||
appset *argov1alpha1.ApplicationSet
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -108,13 +108,11 @@ func TestRequeueAfter(t *testing.T) {
|
||||
want time.Duration
|
||||
wantErr assert.ErrorAssertionFunc
|
||||
}{
|
||||
{name: "Cluster", args: args{
|
||||
appset: &argov1alpha1.ApplicationSet{
|
||||
Spec: argov1alpha1.ApplicationSetSpec{
|
||||
Generators: []argov1alpha1.ApplicationSetGenerator{{Clusters: &argov1alpha1.ClusterGenerator{}}},
|
||||
},
|
||||
}, requeueAfterOverride: "",
|
||||
}, want: generators.NoRequeueAfter, wantErr: assert.NoError},
|
||||
{name: "Cluster", args: args{appset: &argov1alpha1.ApplicationSet{
|
||||
Spec: argov1alpha1.ApplicationSetSpec{
|
||||
Generators: []argov1alpha1.ApplicationSetGenerator{{Clusters: &argov1alpha1.ClusterGenerator{}}},
|
||||
},
|
||||
}}, want: generators.NoRequeueAfter, wantErr: assert.NoError},
|
||||
{name: "ClusterMergeNested", args: args{&argov1alpha1.ApplicationSet{
|
||||
Spec: argov1alpha1.ApplicationSetSpec{
|
||||
Generators: []argov1alpha1.ApplicationSetGenerator{
|
||||
@@ -129,7 +127,7 @@ func TestRequeueAfter(t *testing.T) {
|
||||
}},
|
||||
},
|
||||
},
|
||||
}, ""}, want: generators.DefaultRequeueAfterSeconds, wantErr: assert.NoError},
|
||||
}}, want: generators.DefaultRequeueAfterSeconds, wantErr: assert.NoError},
|
||||
{name: "ClusterMatrixNested", args: args{&argov1alpha1.ApplicationSet{
|
||||
Spec: argov1alpha1.ApplicationSetSpec{
|
||||
Generators: []argov1alpha1.ApplicationSetGenerator{
|
||||
@@ -144,65 +142,15 @@ func TestRequeueAfter(t *testing.T) {
|
||||
}},
|
||||
},
|
||||
},
|
||||
}, ""}, want: generators.DefaultRequeueAfterSeconds, wantErr: assert.NoError},
|
||||
}}, want: generators.DefaultRequeueAfterSeconds, wantErr: assert.NoError},
|
||||
{name: "ListGenerator", args: args{appset: &argov1alpha1.ApplicationSet{
|
||||
Spec: argov1alpha1.ApplicationSetSpec{
|
||||
Generators: []argov1alpha1.ApplicationSetGenerator{{List: &argov1alpha1.ListGenerator{}}},
|
||||
},
|
||||
}}, want: generators.NoRequeueAfter, wantErr: assert.NoError},
|
||||
{name: "DuckGenerator", args: args{appset: &argov1alpha1.ApplicationSet{
|
||||
Spec: argov1alpha1.ApplicationSetSpec{
|
||||
Generators: []argov1alpha1.ApplicationSetGenerator{{ClusterDecisionResource: &argov1alpha1.DuckTypeGenerator{}}},
|
||||
},
|
||||
}}, want: generators.DefaultRequeueAfterSeconds, wantErr: assert.NoError},
|
||||
{name: "OverrideRequeueDuck", args: args{
|
||||
appset: &argov1alpha1.ApplicationSet{
|
||||
Spec: argov1alpha1.ApplicationSetSpec{
|
||||
Generators: []argov1alpha1.ApplicationSetGenerator{{ClusterDecisionResource: &argov1alpha1.DuckTypeGenerator{}}},
|
||||
},
|
||||
}, requeueAfterOverride: "1h",
|
||||
}, want: 1 * time.Hour, wantErr: assert.NoError},
|
||||
{name: "OverrideRequeueGit", args: args{&argov1alpha1.ApplicationSet{
|
||||
Spec: argov1alpha1.ApplicationSetSpec{
|
||||
Generators: []argov1alpha1.ApplicationSetGenerator{
|
||||
{Git: &argov1alpha1.GitGenerator{}},
|
||||
},
|
||||
},
|
||||
}, "1h"}, want: 1 * time.Hour, wantErr: assert.NoError},
|
||||
{name: "OverrideRequeueMatrix", args: args{&argov1alpha1.ApplicationSet{
|
||||
Spec: argov1alpha1.ApplicationSetSpec{
|
||||
Generators: []argov1alpha1.ApplicationSetGenerator{
|
||||
{Clusters: &argov1alpha1.ClusterGenerator{}},
|
||||
{Merge: &argov1alpha1.MergeGenerator{
|
||||
Generators: []argov1alpha1.ApplicationSetNestedGenerator{
|
||||
{
|
||||
Clusters: &argov1alpha1.ClusterGenerator{},
|
||||
Git: &argov1alpha1.GitGenerator{},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}, "5m"}, want: 5 * time.Minute, wantErr: assert.NoError},
|
||||
{name: "OverrideRequeueMerge", args: args{&argov1alpha1.ApplicationSet{
|
||||
Spec: argov1alpha1.ApplicationSetSpec{
|
||||
Generators: []argov1alpha1.ApplicationSetGenerator{
|
||||
{Clusters: &argov1alpha1.ClusterGenerator{}},
|
||||
{Merge: &argov1alpha1.MergeGenerator{
|
||||
Generators: []argov1alpha1.ApplicationSetNestedGenerator{
|
||||
{
|
||||
Clusters: &argov1alpha1.ClusterGenerator{},
|
||||
Git: &argov1alpha1.GitGenerator{},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}, "12s"}, want: 12 * time.Second, wantErr: assert.NoError},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Setenv("ARGOCD_APPLICATIONSET_CONTROLLER_REQUEUE_AFTER", tt.args.requeueAfterOverride)
|
||||
assert.Equalf(t, tt.want, r.getMinRequeueAfter(tt.args.appset), "getMinRequeueAfter(%v)", tt.args.appset)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/utils"
|
||||
appv1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/utils"
|
||||
appv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
func applyTemplatePatch(app *appv1.Application, templatePatch string) (*appv1.Application, error) {
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
appv1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
appv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
func Test_ApplyTemplatePatch(t *testing.T) {
|
||||
|
||||
@@ -7,10 +7,10 @@ import (
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/generators"
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/utils"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/generators"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/utils"
|
||||
|
||||
argov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
func GenerateApplications(logCtx *log.Entry, applicationSetInfo argov1alpha1.ApplicationSet, g map[string]generators.Generator, renderer utils.Renderer, client client.Client) ([]argov1alpha1.Application, argov1alpha1.ApplicationSetReasonType, error) {
|
||||
@@ -20,7 +20,7 @@ func GenerateApplications(logCtx *log.Entry, applicationSetInfo argov1alpha1.App
|
||||
var applicationSetReason argov1alpha1.ApplicationSetReasonType
|
||||
|
||||
for _, requestedGenerator := range applicationSetInfo.Spec.Generators {
|
||||
t, err := generators.Transform(requestedGenerator, g, applicationSetInfo.Spec.Template, &applicationSetInfo, map[string]any{}, client)
|
||||
t, err := generators.Transform(requestedGenerator, g, applicationSetInfo.Spec.Template, &applicationSetInfo, map[string]interface{}{}, client)
|
||||
if err != nil {
|
||||
logCtx.WithError(err).WithField("generator", requestedGenerator).
|
||||
Error("error generating application from params")
|
||||
@@ -69,17 +69,15 @@ func GenerateApplications(logCtx *log.Entry, applicationSetInfo argov1alpha1.App
|
||||
res = append(res, *app)
|
||||
}
|
||||
}
|
||||
if log.IsLevelEnabled(log.DebugLevel) {
|
||||
logCtx.WithField("generator", requestedGenerator).Debugf("apps from generator: %+v", res)
|
||||
} else {
|
||||
logCtx.Infof("generated %d applications", len(res))
|
||||
}
|
||||
|
||||
logCtx.WithField("generator", requestedGenerator).Infof("generated %d applications", len(res))
|
||||
logCtx.WithField("generator", requestedGenerator).Debugf("apps from generator: %+v", res)
|
||||
}
|
||||
|
||||
return res, applicationSetReason, firstError
|
||||
}
|
||||
|
||||
func renderTemplatePatch(r utils.Renderer, app *argov1alpha1.Application, applicationSetInfo argov1alpha1.ApplicationSet, params map[string]any) (*argov1alpha1.Application, error) {
|
||||
func renderTemplatePatch(r utils.Renderer, app *argov1alpha1.Application, applicationSetInfo argov1alpha1.ApplicationSet, params map[string]interface{}) (*argov1alpha1.Application, error) {
|
||||
replacedTemplate, err := r.Replace(*applicationSetInfo.Spec.TemplatePatch, params, applicationSetInfo.Spec.GoTemplate, applicationSetInfo.Spec.GoTemplateOptions)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error replacing values in templatePatch: %w", err)
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package template
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"maps"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/mock"
|
||||
@@ -13,12 +12,13 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/generators"
|
||||
genmock "github.com/argoproj/argo-cd/v3/applicationset/generators/mocks"
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/utils"
|
||||
rendmock "github.com/argoproj/argo-cd/v3/applicationset/utils/mocks"
|
||||
"github.com/argoproj/argo-cd/v3/pkg/apis/application"
|
||||
"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/generators"
|
||||
genmock "github.com/argoproj/argo-cd/v2/applicationset/generators/mocks"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/utils"
|
||||
rendmock "github.com/argoproj/argo-cd/v2/applicationset/utils/mocks"
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/application"
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/util/collections"
|
||||
)
|
||||
|
||||
func TestGenerateApplications(t *testing.T) {
|
||||
@@ -31,7 +31,7 @@ func TestGenerateApplications(t *testing.T) {
|
||||
|
||||
for _, c := range []struct {
|
||||
name string
|
||||
params []map[string]any
|
||||
params []map[string]interface{}
|
||||
template v1alpha1.ApplicationSetTemplate
|
||||
generateParamsError error
|
||||
rendererError error
|
||||
@@ -40,7 +40,7 @@ func TestGenerateApplications(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "Generate two applications",
|
||||
params: []map[string]any{{"name": "app1"}, {"name": "app2"}},
|
||||
params: []map[string]interface{}{{"name": "app1"}, {"name": "app2"}},
|
||||
template: v1alpha1.ApplicationSetTemplate{
|
||||
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{
|
||||
Name: "name",
|
||||
@@ -53,13 +53,13 @@ func TestGenerateApplications(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "Handles error from the generator",
|
||||
generateParamsError: errors.New("error"),
|
||||
generateParamsError: fmt.Errorf("error"),
|
||||
expectErr: true,
|
||||
expectedReason: v1alpha1.ApplicationSetReasonApplicationParamsGenerationError,
|
||||
},
|
||||
{
|
||||
name: "Handles error from the render",
|
||||
params: []map[string]any{{"name": "app1"}, {"name": "app2"}},
|
||||
params: []map[string]interface{}{{"name": "app1"}, {"name": "app2"}},
|
||||
template: v1alpha1.ApplicationSetTemplate{
|
||||
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{
|
||||
Name: "name",
|
||||
@@ -68,7 +68,7 @@ func TestGenerateApplications(t *testing.T) {
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSpec{},
|
||||
},
|
||||
rendererError: errors.New("error"),
|
||||
rendererError: fmt.Errorf("error"),
|
||||
expectErr: true,
|
||||
expectedReason: v1alpha1.ApplicationSetReasonRenderTemplateParamsError,
|
||||
},
|
||||
@@ -153,7 +153,7 @@ func TestGenerateApplications(t *testing.T) {
|
||||
func TestMergeTemplateApplications(t *testing.T) {
|
||||
for _, c := range []struct {
|
||||
name string
|
||||
params []map[string]any
|
||||
params []map[string]interface{}
|
||||
template v1alpha1.ApplicationSetTemplate
|
||||
overrideTemplate v1alpha1.ApplicationSetTemplate
|
||||
expectedMerged v1alpha1.ApplicationSetTemplate
|
||||
@@ -161,7 +161,7 @@ func TestMergeTemplateApplications(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "Generate app",
|
||||
params: []map[string]any{{"name": "app1"}},
|
||||
params: []map[string]interface{}{{"name": "app1"}},
|
||||
template: v1alpha1.ApplicationSetTemplate{
|
||||
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{
|
||||
Name: "name",
|
||||
@@ -245,13 +245,13 @@ func TestMergeTemplateApplications(t *testing.T) {
|
||||
func TestGenerateAppsUsingPullRequestGenerator(t *testing.T) {
|
||||
for _, cases := range []struct {
|
||||
name string
|
||||
params []map[string]any
|
||||
params []map[string]interface{}
|
||||
template v1alpha1.ApplicationSetTemplate
|
||||
expectedApp []v1alpha1.Application
|
||||
}{
|
||||
{
|
||||
name: "Generate an application from a go template application set manifest using a pull request generator",
|
||||
params: []map[string]any{
|
||||
params: []map[string]interface{}{
|
||||
{
|
||||
"number": "1",
|
||||
"title": "title1",
|
||||
@@ -344,7 +344,7 @@ func TestGenerateAppsUsingPullRequestGenerator(t *testing.T) {
|
||||
assert.EqualValues(t, cases.expectedApp[0].ObjectMeta.Name, gotApp[0].ObjectMeta.Name)
|
||||
assert.EqualValues(t, cases.expectedApp[0].Spec.Source.TargetRevision, gotApp[0].Spec.Source.TargetRevision)
|
||||
assert.EqualValues(t, cases.expectedApp[0].Spec.Destination.Namespace, gotApp[0].Spec.Destination.Namespace)
|
||||
assert.True(t, maps.Equal(cases.expectedApp[0].ObjectMeta.Labels, gotApp[0].ObjectMeta.Labels))
|
||||
assert.True(t, collections.StringMapsEqual(cases.expectedApp[0].ObjectMeta.Labels, gotApp[0].ObjectMeta.Labels))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,16 +7,20 @@ import (
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/util/settings"
|
||||
"github.com/argoproj/argo-cd/v2/util/settings"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/utils"
|
||||
"github.com/argoproj/argo-cd/v3/common"
|
||||
argoappsetv1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/utils"
|
||||
argoappsetv1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
const (
|
||||
ArgoCDSecretTypeLabel = "argocd.argoproj.io/secret-type"
|
||||
ArgoCDSecretTypeCluster = "cluster"
|
||||
)
|
||||
|
||||
var _ Generator = (*ClusterGenerator)(nil)
|
||||
@@ -33,7 +37,7 @@ type ClusterGenerator struct {
|
||||
|
||||
var render = &utils.Render{}
|
||||
|
||||
func NewClusterGenerator(ctx context.Context, c client.Client, clientset kubernetes.Interface, namespace string) Generator {
|
||||
func NewClusterGenerator(c client.Client, ctx context.Context, clientset kubernetes.Interface, namespace string) Generator {
|
||||
settingsManager := settings.NewSettingsManager(ctx, clientset, namespace)
|
||||
|
||||
g := &ClusterGenerator{
|
||||
@@ -48,7 +52,7 @@ func NewClusterGenerator(ctx context.Context, c client.Client, clientset kuberne
|
||||
|
||||
// GetRequeueAfter never requeue the cluster generator because the `clusterSecretEventHandler` will requeue the appsets
|
||||
// when the cluster secrets change
|
||||
func (g *ClusterGenerator) GetRequeueAfter(_ *argoappsetv1alpha1.ApplicationSetGenerator) time.Duration {
|
||||
func (g *ClusterGenerator) GetRequeueAfter(appSetGenerator *argoappsetv1alpha1.ApplicationSetGenerator) time.Duration {
|
||||
return NoRequeueAfter
|
||||
}
|
||||
|
||||
@@ -56,8 +60,7 @@ func (g *ClusterGenerator) GetTemplate(appSetGenerator *argoappsetv1alpha1.Appli
|
||||
return &appSetGenerator.Clusters.Template
|
||||
}
|
||||
|
||||
func (g *ClusterGenerator) GenerateParams(appSetGenerator *argoappsetv1alpha1.ApplicationSetGenerator, appSet *argoappsetv1alpha1.ApplicationSet, _ client.Client) ([]map[string]any, error) {
|
||||
logCtx := log.WithField("applicationset", appSet.GetName()).WithField("namespace", appSet.GetNamespace())
|
||||
func (g *ClusterGenerator) GenerateParams(appSetGenerator *argoappsetv1alpha1.ApplicationSetGenerator, appSet *argoappsetv1alpha1.ApplicationSet, _ client.Client) ([]map[string]interface{}, error) {
|
||||
if appSetGenerator == nil {
|
||||
return nil, EmptyAppSetGeneratorError
|
||||
}
|
||||
@@ -70,7 +73,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 will include the local cluster in the list of clusters
|
||||
// ListCluster from Argo CD's util/db package 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)
|
||||
@@ -80,64 +83,48 @@ func (g *ClusterGenerator) GenerateParams(appSetGenerator *argoappsetv1alpha1.Ap
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
clusterSecrets, err := g.getSecretsByClusterName(logCtx, appSetGenerator)
|
||||
clusterSecrets, err := g.getSecretsByClusterName(appSetGenerator)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting cluster secrets: %w", err)
|
||||
}
|
||||
|
||||
res := []map[string]any{}
|
||||
res := []map[string]interface{}{}
|
||||
|
||||
secretsFound := []corev1.Secret{}
|
||||
|
||||
isFlatMode := appSetGenerator.Clusters.FlatList
|
||||
logCtx.Debugf("Using flat mode = %t for cluster generator", isFlatMode)
|
||||
clustersParams := make([]map[string]any, 0)
|
||||
|
||||
for _, cluster := range clustersFromArgoCD {
|
||||
for _, cluster := range clustersFromArgoCD.Items {
|
||||
// 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 {
|
||||
secretsFound = append(secretsFound, secretForCluster)
|
||||
} else if !ignoreLocalClusters {
|
||||
// If there is no secret for the cluster, it's the local cluster, so handle it here.
|
||||
params := map[string]any{}
|
||||
params := map[string]interface{}{}
|
||||
params["name"] = cluster.Name
|
||||
params["nameNormalized"] = cluster.Name
|
||||
params["server"] = cluster.Server
|
||||
params["project"] = ""
|
||||
|
||||
err = appendTemplatedValues(appSetGenerator.Clusters.Values, params, appSet.Spec.GoTemplate, appSet.Spec.GoTemplateOptions)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error appending templated values for local cluster: %w", err)
|
||||
}
|
||||
|
||||
if isFlatMode {
|
||||
clustersParams = append(clustersParams, params)
|
||||
} else {
|
||||
res = append(res, params)
|
||||
}
|
||||
res = append(res, params)
|
||||
|
||||
logCtx.WithField("cluster", "local cluster").Info("matched local cluster")
|
||||
log.WithField("cluster", "local cluster").Info("matched local cluster")
|
||||
}
|
||||
}
|
||||
|
||||
// For each matching cluster secret (non-local clusters only)
|
||||
for _, cluster := range secretsFound {
|
||||
params := map[string]any{}
|
||||
params := map[string]interface{}{}
|
||||
|
||||
params["name"] = string(cluster.Data["name"])
|
||||
params["nameNormalized"] = utils.SanitizeName(string(cluster.Data["name"]))
|
||||
params["server"] = string(cluster.Data["server"])
|
||||
|
||||
project, ok := cluster.Data["project"]
|
||||
if ok {
|
||||
params["project"] = string(project)
|
||||
} else {
|
||||
params["project"] = ""
|
||||
}
|
||||
|
||||
if appSet.Spec.GoTemplate {
|
||||
meta := map[string]any{}
|
||||
meta := map[string]interface{}{}
|
||||
|
||||
if len(cluster.ObjectMeta.Annotations) > 0 {
|
||||
meta["annotations"] = cluster.ObjectMeta.Annotations
|
||||
@@ -149,11 +136,11 @@ func (g *ClusterGenerator) GenerateParams(appSetGenerator *argoappsetv1alpha1.Ap
|
||||
params["metadata"] = meta
|
||||
} else {
|
||||
for key, value := range cluster.ObjectMeta.Annotations {
|
||||
params["metadata.annotations."+key] = value
|
||||
params[fmt.Sprintf("metadata.annotations.%s", key)] = value
|
||||
}
|
||||
|
||||
for key, value := range cluster.ObjectMeta.Labels {
|
||||
params["metadata.labels."+key] = value
|
||||
params[fmt.Sprintf("metadata.labels.%s", key)] = value
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,27 +149,19 @@ func (g *ClusterGenerator) GenerateParams(appSetGenerator *argoappsetv1alpha1.Ap
|
||||
return nil, fmt.Errorf("error appending templated values for cluster: %w", err)
|
||||
}
|
||||
|
||||
if isFlatMode {
|
||||
clustersParams = append(clustersParams, params)
|
||||
} else {
|
||||
res = append(res, params)
|
||||
}
|
||||
res = append(res, params)
|
||||
|
||||
logCtx.WithField("cluster", cluster.Name).Debug("matched cluster secret")
|
||||
log.WithField("cluster", cluster.Name).Info("matched cluster secret")
|
||||
}
|
||||
|
||||
if isFlatMode {
|
||||
res = append(res, map[string]any{
|
||||
"clusters": clustersParams,
|
||||
})
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (g *ClusterGenerator) getSecretsByClusterName(log *log.Entry, appSetGenerator *argoappsetv1alpha1.ApplicationSetGenerator) (map[string]corev1.Secret, error) {
|
||||
func (g *ClusterGenerator) getSecretsByClusterName(appSetGenerator *argoappsetv1alpha1.ApplicationSetGenerator) (map[string]corev1.Secret, error) {
|
||||
// List all Clusters:
|
||||
clusterSecretList := &corev1.SecretList{}
|
||||
|
||||
selector := metav1.AddLabelToSelector(&appSetGenerator.Clusters.Selector, common.LabelKeySecretType, common.LabelValueSecretTypeCluster)
|
||||
selector := metav1.AddLabelToSelector(&appSetGenerator.Clusters.Selector, ArgoCDSecretTypeLabel, ArgoCDSecretTypeCluster)
|
||||
secretSelector, err := metav1.LabelSelectorAsSelector(selector)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error converting label selector: %w", err)
|
||||
@@ -191,7 +170,7 @@ func (g *ClusterGenerator) getSecretsByClusterName(log *log.Entry, appSetGenerat
|
||||
if err := g.Client.List(context.Background(), clusterSecretList, client.MatchingLabelsSelector{Selector: secretSelector}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Debugf("clusters matching labels: %d", len(clusterSecretList.Items))
|
||||
log.Debug("clusters matching labels", "count", len(clusterSecretList.Items))
|
||||
|
||||
res := map[string]corev1.Secret{}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ package generators
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
@@ -13,8 +13,8 @@ import (
|
||||
|
||||
kubefake "k8s.io/client-go/kubernetes/fake"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/utils"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/utils"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -27,7 +27,7 @@ type possiblyErroringFakeCtrlRuntimeClient struct {
|
||||
|
||||
func (p *possiblyErroringFakeCtrlRuntimeClient) List(ctx context.Context, secretList client.ObjectList, opts ...client.ListOption) error {
|
||||
if p.shouldError {
|
||||
return errors.New("could not list Secrets")
|
||||
return fmt.Errorf("could not list Secrets")
|
||||
}
|
||||
return p.Client.List(ctx, secretList, opts...)
|
||||
}
|
||||
@@ -76,20 +76,18 @@ func TestGenerateParams(t *testing.T) {
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"config": []byte("{}"),
|
||||
"name": []byte("production_01/west"),
|
||||
"server": []byte("https://production-01.example.com"),
|
||||
"project": []byte("prod-project"),
|
||||
"config": []byte("{}"),
|
||||
"name": []byte("production_01/west"),
|
||||
"server": []byte("https://production-01.example.com"),
|
||||
},
|
||||
Type: corev1.SecretType("Opaque"),
|
||||
},
|
||||
}
|
||||
testCases := []struct {
|
||||
name string
|
||||
selector metav1.LabelSelector
|
||||
isFlatMode bool
|
||||
values map[string]string
|
||||
expected []map[string]any
|
||||
name string
|
||||
selector metav1.LabelSelector
|
||||
values map[string]string
|
||||
expected []map[string]interface{}
|
||||
// clientError is true if a k8s client error should be simulated
|
||||
clientError bool
|
||||
expectedError error
|
||||
@@ -106,17 +104,18 @@ func TestGenerateParams(t *testing.T) {
|
||||
"bat": "{{ metadata.labels.environment }}",
|
||||
"aaa": "{{ server }}",
|
||||
"no-op": "{{ this-does-not-exist }}",
|
||||
}, expected: []map[string]any{
|
||||
{"values.lol1": "lol", "values.lol2": "{{values.lol1}}{{values.lol1}}", "values.lol3": "{{values.lol2}}{{values.lol2}}{{values.lol2}}", "values.foo": "bar", "values.bar": "{{ metadata.annotations.foo.argoproj.io }}", "values.no-op": "{{ this-does-not-exist }}", "values.bat": "{{ metadata.labels.environment }}", "values.aaa": "https://kubernetes.default.svc", "nameNormalized": "in-cluster", "name": "in-cluster", "server": "https://kubernetes.default.svc", "project": ""},
|
||||
}, expected: []map[string]interface{}{
|
||||
{
|
||||
"values.lol1": "lol", "values.lol2": "{{values.lol1}}{{values.lol1}}", "values.lol3": "{{values.lol2}}{{values.lol2}}{{values.lol2}}", "values.foo": "bar", "values.bar": "production", "values.no-op": "{{ this-does-not-exist }}", "values.bat": "production", "values.aaa": "https://production-01.example.com", "name": "production_01/west", "nameNormalized": "production-01-west", "server": "https://production-01.example.com", "metadata.labels.environment": "production", "metadata.labels.org": "bar",
|
||||
"metadata.labels.argocd.argoproj.io/secret-type": "cluster", "metadata.annotations.foo.argoproj.io": "production", "project": "prod-project",
|
||||
"metadata.labels.argocd.argoproj.io/secret-type": "cluster", "metadata.annotations.foo.argoproj.io": "production",
|
||||
},
|
||||
|
||||
{
|
||||
"values.lol1": "lol", "values.lol2": "{{values.lol1}}{{values.lol1}}", "values.lol3": "{{values.lol2}}{{values.lol2}}{{values.lol2}}", "values.foo": "bar", "values.bar": "staging", "values.no-op": "{{ this-does-not-exist }}", "values.bat": "staging", "values.aaa": "https://staging-01.example.com", "name": "staging-01", "nameNormalized": "staging-01", "server": "https://staging-01.example.com", "metadata.labels.environment": "staging", "metadata.labels.org": "foo",
|
||||
"metadata.labels.argocd.argoproj.io/secret-type": "cluster", "metadata.annotations.foo.argoproj.io": "staging", "project": "",
|
||||
"metadata.labels.argocd.argoproj.io/secret-type": "cluster", "metadata.annotations.foo.argoproj.io": "staging",
|
||||
},
|
||||
|
||||
{"values.lol1": "lol", "values.lol2": "{{values.lol1}}{{values.lol1}}", "values.lol3": "{{values.lol2}}{{values.lol2}}{{values.lol2}}", "values.foo": "bar", "values.bar": "{{ metadata.annotations.foo.argoproj.io }}", "values.no-op": "{{ this-does-not-exist }}", "values.bat": "{{ metadata.labels.environment }}", "values.aaa": "https://kubernetes.default.svc", "nameNormalized": "in-cluster", "name": "in-cluster", "server": "https://kubernetes.default.svc"},
|
||||
},
|
||||
clientError: false,
|
||||
expectedError: nil,
|
||||
@@ -129,15 +128,15 @@ func TestGenerateParams(t *testing.T) {
|
||||
},
|
||||
},
|
||||
values: nil,
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"name": "production_01/west", "nameNormalized": "production-01-west", "server": "https://production-01.example.com", "metadata.labels.environment": "production", "metadata.labels.org": "bar",
|
||||
"metadata.labels.argocd.argoproj.io/secret-type": "cluster", "metadata.annotations.foo.argoproj.io": "production", "project": "prod-project",
|
||||
"metadata.labels.argocd.argoproj.io/secret-type": "cluster", "metadata.annotations.foo.argoproj.io": "production",
|
||||
},
|
||||
|
||||
{
|
||||
"name": "staging-01", "nameNormalized": "staging-01", "server": "https://staging-01.example.com", "metadata.labels.environment": "staging", "metadata.labels.org": "foo",
|
||||
"metadata.labels.argocd.argoproj.io/secret-type": "cluster", "metadata.annotations.foo.argoproj.io": "staging", "project": "",
|
||||
"metadata.labels.argocd.argoproj.io/secret-type": "cluster", "metadata.annotations.foo.argoproj.io": "staging",
|
||||
},
|
||||
},
|
||||
clientError: false,
|
||||
@@ -153,10 +152,10 @@ func TestGenerateParams(t *testing.T) {
|
||||
values: map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"values.foo": "bar", "name": "production_01/west", "nameNormalized": "production-01-west", "server": "https://production-01.example.com", "metadata.labels.environment": "production", "metadata.labels.org": "bar",
|
||||
"metadata.labels.argocd.argoproj.io/secret-type": "cluster", "metadata.annotations.foo.argoproj.io": "production", "project": "prod-project",
|
||||
"metadata.labels.argocd.argoproj.io/secret-type": "cluster", "metadata.annotations.foo.argoproj.io": "production",
|
||||
},
|
||||
},
|
||||
clientError: false,
|
||||
@@ -179,14 +178,14 @@ func TestGenerateParams(t *testing.T) {
|
||||
values: map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"values.foo": "bar", "name": "staging-01", "nameNormalized": "staging-01", "server": "https://staging-01.example.com", "metadata.labels.environment": "staging", "metadata.labels.org": "foo",
|
||||
"metadata.labels.argocd.argoproj.io/secret-type": "cluster", "metadata.annotations.foo.argoproj.io": "staging", "project": "",
|
||||
"metadata.labels.argocd.argoproj.io/secret-type": "cluster", "metadata.annotations.foo.argoproj.io": "staging",
|
||||
},
|
||||
{
|
||||
"values.foo": "bar", "name": "production_01/west", "nameNormalized": "production-01-west", "server": "https://production-01.example.com", "metadata.labels.environment": "production", "metadata.labels.org": "bar",
|
||||
"metadata.labels.argocd.argoproj.io/secret-type": "cluster", "metadata.annotations.foo.argoproj.io": "production", "project": "prod-project",
|
||||
"metadata.labels.argocd.argoproj.io/secret-type": "cluster", "metadata.annotations.foo.argoproj.io": "production",
|
||||
},
|
||||
},
|
||||
clientError: false,
|
||||
@@ -212,10 +211,10 @@ func TestGenerateParams(t *testing.T) {
|
||||
values: map[string]string{
|
||||
"name": "baz",
|
||||
},
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"values.name": "baz", "name": "staging-01", "nameNormalized": "staging-01", "server": "https://staging-01.example.com", "metadata.labels.environment": "staging", "metadata.labels.org": "foo",
|
||||
"metadata.labels.argocd.argoproj.io/secret-type": "cluster", "metadata.annotations.foo.argoproj.io": "staging", "project": "",
|
||||
"metadata.labels.argocd.argoproj.io/secret-type": "cluster", "metadata.annotations.foo.argoproj.io": "staging",
|
||||
},
|
||||
},
|
||||
clientError: false,
|
||||
@@ -227,75 +226,7 @@ func TestGenerateParams(t *testing.T) {
|
||||
values: nil,
|
||||
expected: nil,
|
||||
clientError: true,
|
||||
expectedError: errors.New("error getting cluster secrets: could not list Secrets"),
|
||||
},
|
||||
{
|
||||
name: "flat mode without selectors",
|
||||
selector: metav1.LabelSelector{},
|
||||
values: map[string]string{
|
||||
"lol1": "lol",
|
||||
"lol2": "{{values.lol1}}{{values.lol1}}",
|
||||
"lol3": "{{values.lol2}}{{values.lol2}}{{values.lol2}}",
|
||||
"foo": "bar",
|
||||
"bar": "{{ metadata.annotations.foo.argoproj.io }}",
|
||||
"bat": "{{ metadata.labels.environment }}",
|
||||
"aaa": "{{ server }}",
|
||||
"no-op": "{{ this-does-not-exist }}",
|
||||
},
|
||||
expected: []map[string]any{
|
||||
{
|
||||
"clusters": []map[string]any{
|
||||
{"values.lol1": "lol", "values.lol2": "{{values.lol1}}{{values.lol1}}", "values.lol3": "{{values.lol2}}{{values.lol2}}{{values.lol2}}", "values.foo": "bar", "values.bar": "{{ metadata.annotations.foo.argoproj.io }}", "values.no-op": "{{ this-does-not-exist }}", "values.bat": "{{ metadata.labels.environment }}", "values.aaa": "https://kubernetes.default.svc", "nameNormalized": "in-cluster", "name": "in-cluster", "server": "https://kubernetes.default.svc", "project": ""},
|
||||
{
|
||||
"values.lol1": "lol", "values.lol2": "{{values.lol1}}{{values.lol1}}", "values.lol3": "{{values.lol2}}{{values.lol2}}{{values.lol2}}", "values.foo": "bar", "values.bar": "production", "values.no-op": "{{ this-does-not-exist }}", "values.bat": "production", "values.aaa": "https://production-01.example.com", "name": "production_01/west", "nameNormalized": "production-01-west", "server": "https://production-01.example.com", "metadata.labels.environment": "production", "metadata.labels.org": "bar",
|
||||
"metadata.labels.argocd.argoproj.io/secret-type": "cluster", "metadata.annotations.foo.argoproj.io": "production", "project": "prod-project",
|
||||
},
|
||||
|
||||
{
|
||||
"values.lol1": "lol", "values.lol2": "{{values.lol1}}{{values.lol1}}", "values.lol3": "{{values.lol2}}{{values.lol2}}{{values.lol2}}", "values.foo": "bar", "values.bar": "staging", "values.no-op": "{{ this-does-not-exist }}", "values.bat": "staging", "values.aaa": "https://staging-01.example.com", "name": "staging-01", "nameNormalized": "staging-01", "server": "https://staging-01.example.com", "metadata.labels.environment": "staging", "metadata.labels.org": "foo",
|
||||
"metadata.labels.argocd.argoproj.io/secret-type": "cluster", "metadata.annotations.foo.argoproj.io": "staging", "project": "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
isFlatMode: true,
|
||||
clientError: false,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "production or staging with flat mode",
|
||||
selector: metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "environment",
|
||||
Operator: "In",
|
||||
Values: []string{
|
||||
"production",
|
||||
"staging",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
isFlatMode: true,
|
||||
values: map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
expected: []map[string]any{
|
||||
{
|
||||
"clusters": []map[string]any{
|
||||
{
|
||||
"values.foo": "bar", "name": "production_01/west", "nameNormalized": "production-01-west", "server": "https://production-01.example.com", "metadata.labels.environment": "production", "metadata.labels.org": "bar",
|
||||
"metadata.labels.argocd.argoproj.io/secret-type": "cluster", "metadata.annotations.foo.argoproj.io": "production", "project": "prod-project",
|
||||
},
|
||||
{
|
||||
"values.foo": "bar", "name": "staging-01", "nameNormalized": "staging-01", "server": "https://staging-01.example.com", "metadata.labels.environment": "staging", "metadata.labels.org": "foo",
|
||||
"metadata.labels.argocd.argoproj.io/secret-type": "cluster", "metadata.annotations.foo.argoproj.io": "staging", "project": "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
clientError: false,
|
||||
expectedError: nil,
|
||||
expectedError: fmt.Errorf("error getting cluster secrets: could not list Secrets"),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -315,7 +246,7 @@ func TestGenerateParams(t *testing.T) {
|
||||
testCase.clientError,
|
||||
}
|
||||
|
||||
clusterGenerator := NewClusterGenerator(t.Context(), cl, appClientset, "namespace")
|
||||
clusterGenerator := NewClusterGenerator(cl, context.Background(), appClientset, "namespace")
|
||||
|
||||
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
@@ -328,7 +259,6 @@ func TestGenerateParams(t *testing.T) {
|
||||
Clusters: &argoprojiov1alpha1.ClusterGenerator{
|
||||
Selector: testCase.selector,
|
||||
Values: testCase.values,
|
||||
FlatList: testCase.isFlatMode,
|
||||
},
|
||||
}, &applicationSetInfo, nil)
|
||||
|
||||
@@ -394,11 +324,10 @@ func TestGenerateParamsGoTemplate(t *testing.T) {
|
||||
},
|
||||
}
|
||||
testCases := []struct {
|
||||
name string
|
||||
selector metav1.LabelSelector
|
||||
values map[string]string
|
||||
isFlatMode bool
|
||||
expected []map[string]any
|
||||
name string
|
||||
selector metav1.LabelSelector
|
||||
values map[string]string
|
||||
expected []map[string]interface{}
|
||||
// clientError is true if a k8s client error should be simulated
|
||||
clientError bool
|
||||
expectedError error
|
||||
@@ -415,13 +344,12 @@ func TestGenerateParamsGoTemplate(t *testing.T) {
|
||||
"bat": "{{ if not (empty .metadata) }}{{.metadata.labels.environment}}{{ end }}",
|
||||
"aaa": "{{ .server }}",
|
||||
"no-op": "{{ .thisDoesNotExist }}",
|
||||
}, expected: []map[string]any{
|
||||
}, expected: []map[string]interface{}{
|
||||
{
|
||||
"name": "production_01/west",
|
||||
"nameNormalized": "production-01-west",
|
||||
"server": "https://production-01.example.com",
|
||||
"project": "",
|
||||
"metadata": map[string]any{
|
||||
"metadata": map[string]interface{}{
|
||||
"labels": map[string]string{
|
||||
"argocd.argoproj.io/secret-type": "cluster",
|
||||
"environment": "production",
|
||||
@@ -446,8 +374,7 @@ func TestGenerateParamsGoTemplate(t *testing.T) {
|
||||
"name": "staging-01",
|
||||
"nameNormalized": "staging-01",
|
||||
"server": "https://staging-01.example.com",
|
||||
"project": "",
|
||||
"metadata": map[string]any{
|
||||
"metadata": map[string]interface{}{
|
||||
"labels": map[string]string{
|
||||
"argocd.argoproj.io/secret-type": "cluster",
|
||||
"environment": "staging",
|
||||
@@ -472,7 +399,6 @@ func TestGenerateParamsGoTemplate(t *testing.T) {
|
||||
"nameNormalized": "in-cluster",
|
||||
"name": "in-cluster",
|
||||
"server": "https://kubernetes.default.svc",
|
||||
"project": "",
|
||||
"values": map[string]string{
|
||||
"lol1": "lol",
|
||||
"lol2": "<no value><no value>",
|
||||
@@ -496,13 +422,12 @@ func TestGenerateParamsGoTemplate(t *testing.T) {
|
||||
},
|
||||
},
|
||||
values: nil,
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"name": "production_01/west",
|
||||
"nameNormalized": "production-01-west",
|
||||
"server": "https://production-01.example.com",
|
||||
"project": "",
|
||||
"metadata": map[string]any{
|
||||
"metadata": map[string]interface{}{
|
||||
"labels": map[string]string{
|
||||
"argocd.argoproj.io/secret-type": "cluster",
|
||||
"environment": "production",
|
||||
@@ -517,8 +442,7 @@ func TestGenerateParamsGoTemplate(t *testing.T) {
|
||||
"name": "staging-01",
|
||||
"nameNormalized": "staging-01",
|
||||
"server": "https://staging-01.example.com",
|
||||
"project": "",
|
||||
"metadata": map[string]any{
|
||||
"metadata": map[string]interface{}{
|
||||
"labels": map[string]string{
|
||||
"argocd.argoproj.io/secret-type": "cluster",
|
||||
"environment": "staging",
|
||||
@@ -543,13 +467,12 @@ func TestGenerateParamsGoTemplate(t *testing.T) {
|
||||
values: map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"name": "production_01/west",
|
||||
"nameNormalized": "production-01-west",
|
||||
"server": "https://production-01.example.com",
|
||||
"project": "",
|
||||
"metadata": map[string]any{
|
||||
"metadata": map[string]interface{}{
|
||||
"labels": map[string]string{
|
||||
"argocd.argoproj.io/secret-type": "cluster",
|
||||
"environment": "production",
|
||||
@@ -584,13 +507,12 @@ func TestGenerateParamsGoTemplate(t *testing.T) {
|
||||
values: map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"name": "production_01/west",
|
||||
"nameNormalized": "production-01-west",
|
||||
"server": "https://production-01.example.com",
|
||||
"project": "",
|
||||
"metadata": map[string]any{
|
||||
"metadata": map[string]interface{}{
|
||||
"labels": map[string]string{
|
||||
"argocd.argoproj.io/secret-type": "cluster",
|
||||
"environment": "production",
|
||||
@@ -608,8 +530,7 @@ func TestGenerateParamsGoTemplate(t *testing.T) {
|
||||
"name": "staging-01",
|
||||
"nameNormalized": "staging-01",
|
||||
"server": "https://staging-01.example.com",
|
||||
"project": "",
|
||||
"metadata": map[string]any{
|
||||
"metadata": map[string]interface{}{
|
||||
"labels": map[string]string{
|
||||
"argocd.argoproj.io/secret-type": "cluster",
|
||||
"environment": "staging",
|
||||
@@ -647,13 +568,12 @@ func TestGenerateParamsGoTemplate(t *testing.T) {
|
||||
values: map[string]string{
|
||||
"name": "baz",
|
||||
},
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"name": "staging-01",
|
||||
"nameNormalized": "staging-01",
|
||||
"server": "https://staging-01.example.com",
|
||||
"project": "",
|
||||
"metadata": map[string]any{
|
||||
"metadata": map[string]interface{}{
|
||||
"labels": map[string]string{
|
||||
"argocd.argoproj.io/secret-type": "cluster",
|
||||
"environment": "staging",
|
||||
@@ -677,163 +597,7 @@ func TestGenerateParamsGoTemplate(t *testing.T) {
|
||||
values: nil,
|
||||
expected: nil,
|
||||
clientError: true,
|
||||
expectedError: errors.New("error getting cluster secrets: could not list Secrets"),
|
||||
},
|
||||
{
|
||||
name: "Clusters with flat list mode and no selector",
|
||||
selector: metav1.LabelSelector{},
|
||||
isFlatMode: true,
|
||||
values: map[string]string{
|
||||
"lol1": "lol",
|
||||
"lol2": "{{ .values.lol1 }}{{ .values.lol1 }}",
|
||||
"lol3": "{{ .values.lol2 }}{{ .values.lol2 }}{{ .values.lol2 }}",
|
||||
"foo": "bar",
|
||||
"bar": "{{ if not (empty .metadata) }}{{index .metadata.annotations \"foo.argoproj.io\" }}{{ end }}",
|
||||
"bat": "{{ if not (empty .metadata) }}{{.metadata.labels.environment}}{{ end }}",
|
||||
"aaa": "{{ .server }}",
|
||||
"no-op": "{{ .thisDoesNotExist }}",
|
||||
},
|
||||
expected: []map[string]any{
|
||||
{
|
||||
"clusters": []map[string]any{
|
||||
{
|
||||
"nameNormalized": "in-cluster",
|
||||
"name": "in-cluster",
|
||||
"server": "https://kubernetes.default.svc",
|
||||
"project": "",
|
||||
"values": map[string]string{
|
||||
"lol1": "lol",
|
||||
"lol2": "<no value><no value>",
|
||||
"lol3": "<no value><no value><no value>",
|
||||
"foo": "bar",
|
||||
"bar": "",
|
||||
"bat": "",
|
||||
"aaa": "https://kubernetes.default.svc",
|
||||
"no-op": "<no value>",
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "production_01/west",
|
||||
"nameNormalized": "production-01-west",
|
||||
"server": "https://production-01.example.com",
|
||||
"project": "",
|
||||
"metadata": map[string]any{
|
||||
"labels": map[string]string{
|
||||
"argocd.argoproj.io/secret-type": "cluster",
|
||||
"environment": "production",
|
||||
"org": "bar",
|
||||
},
|
||||
"annotations": map[string]string{
|
||||
"foo.argoproj.io": "production",
|
||||
},
|
||||
},
|
||||
"values": map[string]string{
|
||||
"lol1": "lol",
|
||||
"lol2": "<no value><no value>",
|
||||
"lol3": "<no value><no value><no value>",
|
||||
"foo": "bar",
|
||||
"bar": "production",
|
||||
"bat": "production",
|
||||
"aaa": "https://production-01.example.com",
|
||||
"no-op": "<no value>",
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "staging-01",
|
||||
"nameNormalized": "staging-01",
|
||||
"server": "https://staging-01.example.com",
|
||||
"project": "",
|
||||
"metadata": map[string]any{
|
||||
"labels": map[string]string{
|
||||
"argocd.argoproj.io/secret-type": "cluster",
|
||||
"environment": "staging",
|
||||
"org": "foo",
|
||||
},
|
||||
"annotations": map[string]string{
|
||||
"foo.argoproj.io": "staging",
|
||||
},
|
||||
},
|
||||
"values": map[string]string{
|
||||
"lol1": "lol",
|
||||
"lol2": "<no value><no value>",
|
||||
"lol3": "<no value><no value><no value>",
|
||||
"foo": "bar",
|
||||
"bar": "staging",
|
||||
"bat": "staging",
|
||||
"aaa": "https://staging-01.example.com",
|
||||
"no-op": "<no value>",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
clientError: false,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "production or staging with flat mode",
|
||||
selector: metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "environment",
|
||||
Operator: "In",
|
||||
Values: []string{
|
||||
"production",
|
||||
"staging",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
isFlatMode: true,
|
||||
values: map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
expected: []map[string]any{
|
||||
{
|
||||
"clusters": []map[string]any{
|
||||
{
|
||||
"name": "production_01/west",
|
||||
"nameNormalized": "production-01-west",
|
||||
"server": "https://production-01.example.com",
|
||||
"project": "",
|
||||
"metadata": map[string]any{
|
||||
"labels": map[string]string{
|
||||
"argocd.argoproj.io/secret-type": "cluster",
|
||||
"environment": "production",
|
||||
"org": "bar",
|
||||
},
|
||||
"annotations": map[string]string{
|
||||
"foo.argoproj.io": "production",
|
||||
},
|
||||
},
|
||||
"values": map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "staging-01",
|
||||
"nameNormalized": "staging-01",
|
||||
"server": "https://staging-01.example.com",
|
||||
"project": "",
|
||||
"metadata": map[string]any{
|
||||
"labels": map[string]string{
|
||||
"argocd.argoproj.io/secret-type": "cluster",
|
||||
"environment": "staging",
|
||||
"org": "foo",
|
||||
},
|
||||
"annotations": map[string]string{
|
||||
"foo.argoproj.io": "staging",
|
||||
},
|
||||
},
|
||||
"values": map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
clientError: false,
|
||||
expectedError: nil,
|
||||
expectedError: fmt.Errorf("error getting cluster secrets: could not list Secrets"),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -853,7 +617,7 @@ func TestGenerateParamsGoTemplate(t *testing.T) {
|
||||
testCase.clientError,
|
||||
}
|
||||
|
||||
clusterGenerator := NewClusterGenerator(t.Context(), cl, appClientset, "namespace")
|
||||
clusterGenerator := NewClusterGenerator(cl, context.Background(), appClientset, "namespace")
|
||||
|
||||
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
@@ -868,7 +632,6 @@ func TestGenerateParamsGoTemplate(t *testing.T) {
|
||||
Clusters: &argoprojiov1alpha1.ClusterGenerator{
|
||||
Selector: testCase.selector,
|
||||
Values: testCase.values,
|
||||
FlatList: testCase.isFlatMode,
|
||||
},
|
||||
}, &applicationSetInfo, nil)
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ package generators
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -10,7 +9,7 @@ import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/util/settings"
|
||||
"github.com/argoproj/argo-cd/v2/util/settings"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
@@ -18,8 +17,8 @@ import (
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/utils"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/utils"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
var _ Generator = (*DuckTypeGenerator)(nil)
|
||||
@@ -53,14 +52,14 @@ func (g *DuckTypeGenerator) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.
|
||||
return time.Duration(*appSetGenerator.ClusterDecisionResource.RequeueAfterSeconds) * time.Second
|
||||
}
|
||||
|
||||
return getDefaultRequeueAfter()
|
||||
return DefaultRequeueAfterSeconds
|
||||
}
|
||||
|
||||
func (g *DuckTypeGenerator) GetTemplate(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) *argoprojiov1alpha1.ApplicationSetTemplate {
|
||||
return &appSetGenerator.ClusterDecisionResource.Template
|
||||
}
|
||||
|
||||
func (g *DuckTypeGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, appSet *argoprojiov1alpha1.ApplicationSet, _ client.Client) ([]map[string]any, error) {
|
||||
func (g *DuckTypeGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, appSet *argoprojiov1alpha1.ApplicationSet, _ client.Client) ([]map[string]interface{}, error) {
|
||||
if appSetGenerator == nil {
|
||||
return nil, EmptyAppSetGeneratorError
|
||||
}
|
||||
@@ -97,13 +96,13 @@ func (g *DuckTypeGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.A
|
||||
// Validate the fields
|
||||
if kind == "" || versionIdx < 1 {
|
||||
log.Warningf("kind=%v, resourceName=%v, versionIdx=%v", kind, resourceName, versionIdx)
|
||||
return nil, errors.New("There is a problem with the apiVersion, kind or resourceName provided")
|
||||
return nil, fmt.Errorf("There is a problem with the apiVersion, kind or resourceName provided")
|
||||
}
|
||||
|
||||
if (resourceName == "" && labelSelector.MatchLabels == nil && labelSelector.MatchExpressions == nil) ||
|
||||
(resourceName != "" && (labelSelector.MatchExpressions != nil || labelSelector.MatchLabels != nil)) {
|
||||
log.Warningf("You must choose either resourceName=%v, labelSelector.matchLabels=%v or labelSelect.matchExpressions=%v", resourceName, labelSelector.MatchLabels, labelSelector.MatchExpressions)
|
||||
return nil, errors.New("There is a problem with the definition of the ClusterDecisionResource generator")
|
||||
return nil, fmt.Errorf("There is a problem with the definition of the ClusterDecisionResource generator")
|
||||
}
|
||||
|
||||
// Split up the apiVersion
|
||||
@@ -131,7 +130,7 @@ func (g *DuckTypeGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.A
|
||||
|
||||
if len(duckResources.Items) == 0 {
|
||||
log.Warning("no resource found, make sure you clusterDecisionResource is defined correctly")
|
||||
return nil, errors.New("no clusterDecisionResources found")
|
||||
return nil, fmt.Errorf("no clusterDecisionResources found")
|
||||
}
|
||||
|
||||
// Override the duck type in the status of the resource
|
||||
@@ -147,77 +146,81 @@ func (g *DuckTypeGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.A
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
res := []map[string]any{}
|
||||
clusterDecisions := []any{}
|
||||
res := []map[string]interface{}{}
|
||||
clusterDecisions := []interface{}{}
|
||||
|
||||
// Build the decision slice
|
||||
for _, duckResource := range duckResources.Items {
|
||||
log.WithField("duckResourceName", duckResource.GetName()).Debug("found resource")
|
||||
|
||||
if duckResource.Object["status"] == nil || len(duckResource.Object["status"].(map[string]any)) == 0 {
|
||||
if duckResource.Object["status"] == nil || len(duckResource.Object["status"].(map[string]interface{})) == 0 {
|
||||
log.Warningf("clusterDecisionResource: %s, has no status", duckResource.GetName())
|
||||
continue
|
||||
}
|
||||
|
||||
log.WithField("duckResourceStatus", duckResource.Object["status"]).Debug("found resource")
|
||||
|
||||
clusterDecisions = append(clusterDecisions, duckResource.Object["status"].(map[string]any)[statusListKey].([]any)...)
|
||||
clusterDecisions = append(clusterDecisions, duckResource.Object["status"].(map[string]interface{})[statusListKey].([]interface{})...)
|
||||
}
|
||||
log.Infof("Number of decisions found: %v", len(clusterDecisions))
|
||||
|
||||
if len(clusterDecisions) == 0 {
|
||||
// Read this outside the loop to improve performance
|
||||
argoClusters := clustersFromArgoCD.Items
|
||||
|
||||
if len(clusterDecisions) > 0 {
|
||||
for _, cluster := range clusterDecisions {
|
||||
// generated instance of cluster params
|
||||
params := map[string]interface{}{}
|
||||
|
||||
log.Infof("cluster: %v", cluster)
|
||||
matchValue := cluster.(map[string]interface{})[matchKey]
|
||||
if matchValue == nil || matchValue.(string) == "" {
|
||||
log.Warningf("matchKey=%v not found in \"%v\" list: %v\n", matchKey, statusListKey, cluster.(map[string]interface{}))
|
||||
continue
|
||||
}
|
||||
|
||||
strMatchValue := matchValue.(string)
|
||||
log.WithField(matchKey, strMatchValue).Debug("validate against ArgoCD")
|
||||
|
||||
found := false
|
||||
|
||||
for _, argoCluster := range argoClusters {
|
||||
if argoCluster.Name == strMatchValue {
|
||||
log.WithField(matchKey, argoCluster.Name).Info("matched cluster in ArgoCD")
|
||||
params["name"] = argoCluster.Name
|
||||
params["server"] = argoCluster.Server
|
||||
|
||||
found = true
|
||||
break // Stop looking
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
log.WithField(matchKey, strMatchValue).Warning("unmatched cluster in ArgoCD")
|
||||
continue
|
||||
}
|
||||
|
||||
for key, value := range cluster.(map[string]interface{}) {
|
||||
params[key] = value.(string)
|
||||
}
|
||||
|
||||
for key, value := range appSetGenerator.ClusterDecisionResource.Values {
|
||||
if appSet.Spec.GoTemplate {
|
||||
if params["values"] == nil {
|
||||
params["values"] = map[string]string{}
|
||||
}
|
||||
params["values"].(map[string]string)[key] = value
|
||||
} else {
|
||||
params[fmt.Sprintf("values.%s", key)] = value
|
||||
}
|
||||
}
|
||||
|
||||
res = append(res, params)
|
||||
}
|
||||
} else {
|
||||
log.Warningf("clusterDecisionResource status.%s missing", statusListKey)
|
||||
return nil, nil
|
||||
}
|
||||
for _, cluster := range clusterDecisions {
|
||||
// generated instance of cluster params
|
||||
params := map[string]any{}
|
||||
|
||||
log.Infof("cluster: %v", cluster)
|
||||
matchValue := cluster.(map[string]any)[matchKey]
|
||||
if matchValue == nil || matchValue.(string) == "" {
|
||||
log.Warningf("matchKey=%v not found in \"%v\" list: %v\n", matchKey, statusListKey, cluster.(map[string]any))
|
||||
continue
|
||||
}
|
||||
|
||||
strMatchValue := matchValue.(string)
|
||||
log.WithField(matchKey, strMatchValue).Debug("validate against ArgoCD")
|
||||
|
||||
found := false
|
||||
|
||||
for _, argoCluster := range clustersFromArgoCD {
|
||||
if argoCluster.Name == strMatchValue {
|
||||
log.WithField(matchKey, argoCluster.Name).Info("matched cluster in ArgoCD")
|
||||
params["name"] = argoCluster.Name
|
||||
params["server"] = argoCluster.Server
|
||||
|
||||
found = true
|
||||
break // Stop looking
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
log.WithField(matchKey, strMatchValue).Warning("unmatched cluster in ArgoCD")
|
||||
continue
|
||||
}
|
||||
|
||||
for key, value := range cluster.(map[string]any) {
|
||||
params[key] = value.(string)
|
||||
}
|
||||
|
||||
for key, value := range appSetGenerator.ClusterDecisionResource.Values {
|
||||
if appSet.Spec.GoTemplate {
|
||||
if params["values"] == nil {
|
||||
params["values"] = map[string]string{}
|
||||
}
|
||||
params["values"].(map[string]string)[key] = value
|
||||
} else {
|
||||
params["values."+key] = value
|
||||
}
|
||||
}
|
||||
|
||||
res = append(res, params)
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package generators
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -15,11 +16,11 @@ import (
|
||||
kubefake "k8s.io/client-go/kubernetes/fake"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
const (
|
||||
resourceAPIVersion = "mallard.io/v1"
|
||||
resourceApiVersion = "mallard.io/v1"
|
||||
resourceKind = "ducks"
|
||||
resourceName = "quak"
|
||||
)
|
||||
@@ -77,20 +78,20 @@ func TestGenerateParamsForDuckType(t *testing.T) {
|
||||
}
|
||||
|
||||
duckType := &unstructured.Unstructured{
|
||||
Object: map[string]any{
|
||||
"apiVersion": resourceAPIVersion,
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": resourceApiVersion,
|
||||
"kind": "Duck",
|
||||
"metadata": map[string]any{
|
||||
"metadata": map[string]interface{}{
|
||||
"name": resourceName,
|
||||
"namespace": "namespace",
|
||||
"labels": map[string]any{"duck": "all-species"},
|
||||
"labels": map[string]interface{}{"duck": "all-species"},
|
||||
},
|
||||
"status": map[string]any{
|
||||
"decisions": []any{
|
||||
map[string]any{
|
||||
"status": map[string]interface{}{
|
||||
"decisions": []interface{}{
|
||||
map[string]interface{}{
|
||||
"clusterName": "staging-01",
|
||||
},
|
||||
map[string]any{
|
||||
map[string]interface{}{
|
||||
"clusterName": "production-01",
|
||||
},
|
||||
},
|
||||
@@ -99,17 +100,17 @@ func TestGenerateParamsForDuckType(t *testing.T) {
|
||||
}
|
||||
|
||||
duckTypeProdOnly := &unstructured.Unstructured{
|
||||
Object: map[string]any{
|
||||
"apiVersion": resourceAPIVersion,
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": resourceApiVersion,
|
||||
"kind": "Duck",
|
||||
"metadata": map[string]any{
|
||||
"metadata": map[string]interface{}{
|
||||
"name": resourceName,
|
||||
"namespace": "namespace",
|
||||
"labels": map[string]any{"duck": "spotted"},
|
||||
"labels": map[string]interface{}{"duck": "spotted"},
|
||||
},
|
||||
"status": map[string]any{
|
||||
"decisions": []any{
|
||||
map[string]any{
|
||||
"status": map[string]interface{}{
|
||||
"decisions": []interface{}{
|
||||
map[string]interface{}{
|
||||
"clusterName": "production-01",
|
||||
},
|
||||
},
|
||||
@@ -118,15 +119,15 @@ func TestGenerateParamsForDuckType(t *testing.T) {
|
||||
}
|
||||
|
||||
duckTypeEmpty := &unstructured.Unstructured{
|
||||
Object: map[string]any{
|
||||
"apiVersion": resourceAPIVersion,
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": resourceApiVersion,
|
||||
"kind": "Duck",
|
||||
"metadata": map[string]any{
|
||||
"metadata": map[string]interface{}{
|
||||
"name": resourceName,
|
||||
"namespace": "namespace",
|
||||
"labels": map[string]any{"duck": "canvasback"},
|
||||
"labels": map[string]interface{}{"duck": "canvasback"},
|
||||
},
|
||||
"status": map[string]any{},
|
||||
"status": map[string]interface{}{},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -136,7 +137,7 @@ func TestGenerateParamsForDuckType(t *testing.T) {
|
||||
Namespace: "namespace",
|
||||
},
|
||||
Data: map[string]string{
|
||||
"apiVersion": resourceAPIVersion,
|
||||
"apiVersion": resourceApiVersion,
|
||||
"kind": resourceKind,
|
||||
"statusListKey": "decisions",
|
||||
"matchKey": "clusterName",
|
||||
@@ -150,7 +151,7 @@ func TestGenerateParamsForDuckType(t *testing.T) {
|
||||
labelSelector metav1.LabelSelector
|
||||
resource *unstructured.Unstructured
|
||||
values map[string]string
|
||||
expected []map[string]any
|
||||
expected []map[string]interface{}
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
@@ -158,8 +159,8 @@ func TestGenerateParamsForDuckType(t *testing.T) {
|
||||
resourceName: "",
|
||||
resource: duckType,
|
||||
values: nil,
|
||||
expected: []map[string]any{},
|
||||
expectedError: errors.New("There is a problem with the definition of the ClusterDecisionResource generator"),
|
||||
expected: []map[string]interface{}{},
|
||||
expectedError: fmt.Errorf("There is a problem with the definition of the ClusterDecisionResource generator"),
|
||||
},
|
||||
/*** This does not work with the FAKE runtime client, fieldSelectors are broken.
|
||||
{
|
||||
@@ -176,7 +177,7 @@ func TestGenerateParamsForDuckType(t *testing.T) {
|
||||
resourceName: resourceName,
|
||||
resource: duckType,
|
||||
values: nil,
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{"clusterName": "production-01", "name": "production-01", "server": "https://production-01.example.com"},
|
||||
|
||||
{"clusterName": "staging-01", "name": "staging-01", "server": "https://staging-01.example.com"},
|
||||
@@ -190,7 +191,7 @@ func TestGenerateParamsForDuckType(t *testing.T) {
|
||||
values: map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{"clusterName": "production-01", "values.foo": "bar", "name": "production-01", "server": "https://production-01.example.com"},
|
||||
},
|
||||
expectedError: nil,
|
||||
@@ -218,7 +219,7 @@ func TestGenerateParamsForDuckType(t *testing.T) {
|
||||
labelSelector: metav1.LabelSelector{MatchLabels: map[string]string{"duck": "all-species"}},
|
||||
resource: duckType,
|
||||
values: nil,
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{"clusterName": "production-01", "name": "production-01", "server": "https://production-01.example.com"},
|
||||
|
||||
{"clusterName": "staging-01", "name": "staging-01", "server": "https://staging-01.example.com"},
|
||||
@@ -233,7 +234,7 @@ func TestGenerateParamsForDuckType(t *testing.T) {
|
||||
values: map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{"clusterName": "production-01", "values.foo": "bar", "name": "production-01", "server": "https://production-01.example.com"},
|
||||
},
|
||||
expectedError: nil,
|
||||
@@ -250,7 +251,7 @@ func TestGenerateParamsForDuckType(t *testing.T) {
|
||||
}},
|
||||
resource: duckType,
|
||||
values: nil,
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{"clusterName": "production-01", "name": "production-01", "server": "https://production-01.example.com"},
|
||||
|
||||
{"clusterName": "staging-01", "name": "staging-01", "server": "https://staging-01.example.com"},
|
||||
@@ -270,7 +271,7 @@ func TestGenerateParamsForDuckType(t *testing.T) {
|
||||
resource: duckType,
|
||||
values: nil,
|
||||
expected: nil,
|
||||
expectedError: errors.New("There is a problem with the definition of the ClusterDecisionResource generator"),
|
||||
expectedError: fmt.Errorf("There is a problem with the definition of the ClusterDecisionResource generator"),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -292,7 +293,7 @@ func TestGenerateParamsForDuckType(t *testing.T) {
|
||||
|
||||
fakeDynClient := dynfake.NewSimpleDynamicClientWithCustomListKinds(runtime.NewScheme(), gvrToListKind, testCase.resource)
|
||||
|
||||
duckTypeGenerator := NewDuckTypeGenerator(t.Context(), fakeDynClient, appClientset, "namespace")
|
||||
duckTypeGenerator := NewDuckTypeGenerator(context.Background(), fakeDynClient, appClientset, "namespace")
|
||||
|
||||
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
@@ -373,20 +374,20 @@ func TestGenerateParamsForDuckTypeGoTemplate(t *testing.T) {
|
||||
}
|
||||
|
||||
duckType := &unstructured.Unstructured{
|
||||
Object: map[string]any{
|
||||
"apiVersion": resourceAPIVersion,
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": resourceApiVersion,
|
||||
"kind": "Duck",
|
||||
"metadata": map[string]any{
|
||||
"metadata": map[string]interface{}{
|
||||
"name": resourceName,
|
||||
"namespace": "namespace",
|
||||
"labels": map[string]any{"duck": "all-species"},
|
||||
"labels": map[string]interface{}{"duck": "all-species"},
|
||||
},
|
||||
"status": map[string]any{
|
||||
"decisions": []any{
|
||||
map[string]any{
|
||||
"status": map[string]interface{}{
|
||||
"decisions": []interface{}{
|
||||
map[string]interface{}{
|
||||
"clusterName": "staging-01",
|
||||
},
|
||||
map[string]any{
|
||||
map[string]interface{}{
|
||||
"clusterName": "production-01",
|
||||
},
|
||||
},
|
||||
@@ -395,17 +396,17 @@ func TestGenerateParamsForDuckTypeGoTemplate(t *testing.T) {
|
||||
}
|
||||
|
||||
duckTypeProdOnly := &unstructured.Unstructured{
|
||||
Object: map[string]any{
|
||||
"apiVersion": resourceAPIVersion,
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": resourceApiVersion,
|
||||
"kind": "Duck",
|
||||
"metadata": map[string]any{
|
||||
"metadata": map[string]interface{}{
|
||||
"name": resourceName,
|
||||
"namespace": "namespace",
|
||||
"labels": map[string]any{"duck": "spotted"},
|
||||
"labels": map[string]interface{}{"duck": "spotted"},
|
||||
},
|
||||
"status": map[string]any{
|
||||
"decisions": []any{
|
||||
map[string]any{
|
||||
"status": map[string]interface{}{
|
||||
"decisions": []interface{}{
|
||||
map[string]interface{}{
|
||||
"clusterName": "production-01",
|
||||
},
|
||||
},
|
||||
@@ -414,15 +415,15 @@ func TestGenerateParamsForDuckTypeGoTemplate(t *testing.T) {
|
||||
}
|
||||
|
||||
duckTypeEmpty := &unstructured.Unstructured{
|
||||
Object: map[string]any{
|
||||
"apiVersion": resourceAPIVersion,
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": resourceApiVersion,
|
||||
"kind": "Duck",
|
||||
"metadata": map[string]any{
|
||||
"metadata": map[string]interface{}{
|
||||
"name": resourceName,
|
||||
"namespace": "namespace",
|
||||
"labels": map[string]any{"duck": "canvasback"},
|
||||
"labels": map[string]interface{}{"duck": "canvasback"},
|
||||
},
|
||||
"status": map[string]any{},
|
||||
"status": map[string]interface{}{},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -432,7 +433,7 @@ func TestGenerateParamsForDuckTypeGoTemplate(t *testing.T) {
|
||||
Namespace: "namespace",
|
||||
},
|
||||
Data: map[string]string{
|
||||
"apiVersion": resourceAPIVersion,
|
||||
"apiVersion": resourceApiVersion,
|
||||
"kind": resourceKind,
|
||||
"statusListKey": "decisions",
|
||||
"matchKey": "clusterName",
|
||||
@@ -446,7 +447,7 @@ func TestGenerateParamsForDuckTypeGoTemplate(t *testing.T) {
|
||||
labelSelector metav1.LabelSelector
|
||||
resource *unstructured.Unstructured
|
||||
values map[string]string
|
||||
expected []map[string]any
|
||||
expected []map[string]interface{}
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
@@ -454,8 +455,8 @@ func TestGenerateParamsForDuckTypeGoTemplate(t *testing.T) {
|
||||
resourceName: "",
|
||||
resource: duckType,
|
||||
values: nil,
|
||||
expected: []map[string]any{},
|
||||
expectedError: errors.New("There is a problem with the definition of the ClusterDecisionResource generator"),
|
||||
expected: []map[string]interface{}{},
|
||||
expectedError: fmt.Errorf("There is a problem with the definition of the ClusterDecisionResource generator"),
|
||||
},
|
||||
/*** This does not work with the FAKE runtime client, fieldSelectors are broken.
|
||||
{
|
||||
@@ -472,7 +473,7 @@ func TestGenerateParamsForDuckTypeGoTemplate(t *testing.T) {
|
||||
resourceName: resourceName,
|
||||
resource: duckType,
|
||||
values: nil,
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{"clusterName": "production-01", "name": "production-01", "server": "https://production-01.example.com"},
|
||||
|
||||
{"clusterName": "staging-01", "name": "staging-01", "server": "https://staging-01.example.com"},
|
||||
@@ -486,7 +487,7 @@ func TestGenerateParamsForDuckTypeGoTemplate(t *testing.T) {
|
||||
values: map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{"clusterName": "production-01", "values": map[string]string{"foo": "bar"}, "name": "production-01", "server": "https://production-01.example.com"},
|
||||
},
|
||||
expectedError: nil,
|
||||
@@ -514,7 +515,7 @@ func TestGenerateParamsForDuckTypeGoTemplate(t *testing.T) {
|
||||
labelSelector: metav1.LabelSelector{MatchLabels: map[string]string{"duck": "all-species"}},
|
||||
resource: duckType,
|
||||
values: nil,
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{"clusterName": "production-01", "name": "production-01", "server": "https://production-01.example.com"},
|
||||
|
||||
{"clusterName": "staging-01", "name": "staging-01", "server": "https://staging-01.example.com"},
|
||||
@@ -529,7 +530,7 @@ func TestGenerateParamsForDuckTypeGoTemplate(t *testing.T) {
|
||||
values: map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{"clusterName": "production-01", "values": map[string]string{"foo": "bar"}, "name": "production-01", "server": "https://production-01.example.com"},
|
||||
},
|
||||
expectedError: nil,
|
||||
@@ -546,7 +547,7 @@ func TestGenerateParamsForDuckTypeGoTemplate(t *testing.T) {
|
||||
}},
|
||||
resource: duckType,
|
||||
values: nil,
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{"clusterName": "production-01", "name": "production-01", "server": "https://production-01.example.com"},
|
||||
|
||||
{"clusterName": "staging-01", "name": "staging-01", "server": "https://staging-01.example.com"},
|
||||
@@ -566,7 +567,7 @@ func TestGenerateParamsForDuckTypeGoTemplate(t *testing.T) {
|
||||
resource: duckType,
|
||||
values: nil,
|
||||
expected: nil,
|
||||
expectedError: errors.New("There is a problem with the definition of the ClusterDecisionResource generator"),
|
||||
expectedError: fmt.Errorf("There is a problem with the definition of the ClusterDecisionResource generator"),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -588,7 +589,7 @@ func TestGenerateParamsForDuckTypeGoTemplate(t *testing.T) {
|
||||
|
||||
fakeDynClient := dynfake.NewSimpleDynamicClientWithCustomListKinds(runtime.NewScheme(), gvrToListKind, testCase.resource)
|
||||
|
||||
duckTypeGenerator := NewDuckTypeGenerator(t.Context(), fakeDynClient, appClientset, "namespace")
|
||||
duckTypeGenerator := NewDuckTypeGenerator(context.Background(), fakeDynClient, appClientset, "namespace")
|
||||
|
||||
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
|
||||
@@ -7,13 +7,13 @@ import (
|
||||
"github.com/jeremywohl/flatten"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/utils"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/utils"
|
||||
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
|
||||
"dario.cat/mergo"
|
||||
"github.com/imdario/mergo"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
@@ -22,12 +22,12 @@ const (
|
||||
)
|
||||
|
||||
type TransformResult struct {
|
||||
Params []map[string]any
|
||||
Params []map[string]interface{}
|
||||
Template argoprojiov1alpha1.ApplicationSetTemplate
|
||||
}
|
||||
|
||||
// Transform a spec generator to list of paramSets and a template
|
||||
func Transform(requestedGenerator argoprojiov1alpha1.ApplicationSetGenerator, allGenerators map[string]Generator, baseTemplate argoprojiov1alpha1.ApplicationSetTemplate, appSet *argoprojiov1alpha1.ApplicationSet, genParams map[string]any, client client.Client) ([]TransformResult, error) {
|
||||
func Transform(requestedGenerator argoprojiov1alpha1.ApplicationSetGenerator, allGenerators map[string]Generator, baseTemplate argoprojiov1alpha1.ApplicationSetTemplate, appSet *argoprojiov1alpha1.ApplicationSet, genParams map[string]interface{}, client client.Client) ([]TransformResult, error) {
|
||||
// This is a custom version of the `LabelSelectorAsSelector` that is in k8s.io/apimachinery. This has been copied
|
||||
// verbatim from that package, with the difference that we do not have any restrictions on label values. This is done
|
||||
// so that, among other things, we can match on cluster urls.
|
||||
@@ -52,7 +52,7 @@ func Transform(requestedGenerator argoprojiov1alpha1.ApplicationSetGenerator, al
|
||||
}
|
||||
continue
|
||||
}
|
||||
var params []map[string]any
|
||||
var params []map[string]interface{}
|
||||
if len(genParams) != 0 {
|
||||
tempInterpolatedGenerator, err := InterpolateGenerator(&requestedGenerator, genParams, appSet.Spec.GoTemplate, appSet.Spec.GoTemplateOptions)
|
||||
interpolatedGenerator = &tempInterpolatedGenerator
|
||||
@@ -74,7 +74,7 @@ func Transform(requestedGenerator argoprojiov1alpha1.ApplicationSetGenerator, al
|
||||
}
|
||||
continue
|
||||
}
|
||||
var filterParams []map[string]any
|
||||
var filterParams []map[string]interface{}
|
||||
for _, param := range params {
|
||||
flatParam, err := flattenParameters(param)
|
||||
if err != nil {
|
||||
@@ -123,7 +123,7 @@ func GetRelevantGenerators(requestedGenerator *argoprojiov1alpha1.ApplicationSet
|
||||
return res
|
||||
}
|
||||
|
||||
func flattenParameters(in map[string]any) (map[string]string, error) {
|
||||
func flattenParameters(in map[string]interface{}) (map[string]string, error) {
|
||||
flat, err := flatten.Flatten(in, "", flatten.DotStyle)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error flatenning parameters: %w", err)
|
||||
@@ -149,7 +149,7 @@ func mergeGeneratorTemplate(g Generator, requestedGenerator *argoprojiov1alpha1.
|
||||
|
||||
// InterpolateGenerator allows interpolating the matrix's 2nd child generator with values from the 1st child generator
|
||||
// "params" parameter is an array, where each index corresponds to a generator. Each index contains a map w/ that generator's parameters.
|
||||
func InterpolateGenerator(requestedGenerator *argoprojiov1alpha1.ApplicationSetGenerator, params map[string]any, useGoTemplate bool, goTemplateOptions []string) (argoprojiov1alpha1.ApplicationSetGenerator, error) {
|
||||
func InterpolateGenerator(requestedGenerator *argoprojiov1alpha1.ApplicationSetGenerator, params map[string]interface{}, useGoTemplate bool, goTemplateOptions []string) (argoprojiov1alpha1.ApplicationSetGenerator, error) {
|
||||
render := utils.Render{}
|
||||
interpolatedGenerator, err := render.RenderGeneratorParams(requestedGenerator, params, useGoTemplate, goTemplateOptions)
|
||||
if err != nil {
|
||||
@@ -159,3 +159,16 @@ 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
|
||||
}
|
||||
|
||||
@@ -10,9 +10,9 @@ import (
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/services/mocks"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/services/mocks"
|
||||
|
||||
argov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
|
||||
"github.com/stretchr/testify/mock"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
@@ -27,19 +27,19 @@ func TestMatchValues(t *testing.T) {
|
||||
name string
|
||||
elements []apiextensionsv1.JSON
|
||||
selector *metav1.LabelSelector
|
||||
expected []map[string]any
|
||||
expected []map[string]interface{}
|
||||
}{
|
||||
{
|
||||
name: "no filter",
|
||||
elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url"}`)}},
|
||||
selector: &metav1.LabelSelector{},
|
||||
expected: []map[string]any{{"cluster": "cluster", "url": "url"}},
|
||||
expected: []map[string]interface{}{{"cluster": "cluster", "url": "url"}},
|
||||
},
|
||||
{
|
||||
name: "nil",
|
||||
elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url"}`)}},
|
||||
selector: nil,
|
||||
expected: []map[string]any{{"cluster": "cluster", "url": "url"}},
|
||||
expected: []map[string]interface{}{{"cluster": "cluster", "url": "url"}},
|
||||
},
|
||||
{
|
||||
name: "values.foo should be foo but is ignore element",
|
||||
@@ -49,7 +49,7 @@ func TestMatchValues(t *testing.T) {
|
||||
"values.foo": "foo",
|
||||
},
|
||||
},
|
||||
expected: []map[string]any{},
|
||||
expected: []map[string]interface{}{},
|
||||
},
|
||||
{
|
||||
name: "values.foo should be bar",
|
||||
@@ -59,7 +59,7 @@ func TestMatchValues(t *testing.T) {
|
||||
"values.foo": "bar",
|
||||
},
|
||||
},
|
||||
expected: []map[string]any{{"cluster": "cluster", "url": "url", "values.foo": "bar"}},
|
||||
expected: []map[string]interface{}{{"cluster": "cluster", "url": "url", "values.foo": "bar"}},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -101,19 +101,19 @@ func TestMatchValuesGoTemplate(t *testing.T) {
|
||||
name string
|
||||
elements []apiextensionsv1.JSON
|
||||
selector *metav1.LabelSelector
|
||||
expected []map[string]any
|
||||
expected []map[string]interface{}
|
||||
}{
|
||||
{
|
||||
name: "no filter",
|
||||
elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url"}`)}},
|
||||
selector: &metav1.LabelSelector{},
|
||||
expected: []map[string]any{{"cluster": "cluster", "url": "url"}},
|
||||
expected: []map[string]interface{}{{"cluster": "cluster", "url": "url"}},
|
||||
},
|
||||
{
|
||||
name: "nil",
|
||||
elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url"}`)}},
|
||||
selector: nil,
|
||||
expected: []map[string]any{{"cluster": "cluster", "url": "url"}},
|
||||
expected: []map[string]interface{}{{"cluster": "cluster", "url": "url"}},
|
||||
},
|
||||
{
|
||||
name: "values.foo should be foo but is ignore element",
|
||||
@@ -123,7 +123,7 @@ func TestMatchValuesGoTemplate(t *testing.T) {
|
||||
"values.foo": "foo",
|
||||
},
|
||||
},
|
||||
expected: []map[string]any{},
|
||||
expected: []map[string]interface{}{},
|
||||
},
|
||||
{
|
||||
name: "values.foo should be bar",
|
||||
@@ -133,7 +133,7 @@ func TestMatchValuesGoTemplate(t *testing.T) {
|
||||
"values.foo": "bar",
|
||||
},
|
||||
},
|
||||
expected: []map[string]any{{"cluster": "cluster", "url": "url", "values": map[string]any{"foo": "bar"}}},
|
||||
expected: []map[string]interface{}{{"cluster": "cluster", "url": "url", "values": map[string]interface{}{"foo": "bar"}}},
|
||||
},
|
||||
{
|
||||
name: "values.0 should be bar",
|
||||
@@ -143,7 +143,7 @@ func TestMatchValuesGoTemplate(t *testing.T) {
|
||||
"values.0": "bar",
|
||||
},
|
||||
},
|
||||
expected: []map[string]any{{"cluster": "cluster", "url": "url", "values": []any{"bar"}}},
|
||||
expected: []map[string]interface{}{{"cluster": "cluster", "url": "url", "values": []interface{}{"bar"}}},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -184,14 +184,14 @@ func TestTransForm(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
selector *metav1.LabelSelector
|
||||
expected []map[string]any
|
||||
expected []map[string]interface{}
|
||||
}{
|
||||
{
|
||||
name: "server filter",
|
||||
selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{"server": "https://production-01.example.com"},
|
||||
},
|
||||
expected: []map[string]any{{
|
||||
expected: []map[string]interface{}{{
|
||||
"metadata.annotations.foo.argoproj.io": "production",
|
||||
"metadata.labels.argocd.argoproj.io/secret-type": "cluster",
|
||||
"metadata.labels.environment": "production",
|
||||
@@ -199,7 +199,6 @@ func TestTransForm(t *testing.T) {
|
||||
"name": "production_01/west",
|
||||
"nameNormalized": "production-01-west",
|
||||
"server": "https://production-01.example.com",
|
||||
"project": "",
|
||||
}},
|
||||
},
|
||||
{
|
||||
@@ -207,7 +206,7 @@ func TestTransForm(t *testing.T) {
|
||||
selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{"server": "https://some-really-long-url-that-will-exceed-63-characters.com"},
|
||||
},
|
||||
expected: []map[string]any{{
|
||||
expected: []map[string]interface{}{{
|
||||
"metadata.annotations.foo.argoproj.io": "production",
|
||||
"metadata.labels.argocd.argoproj.io/secret-type": "cluster",
|
||||
"metadata.labels.environment": "production",
|
||||
@@ -215,7 +214,6 @@ func TestTransForm(t *testing.T) {
|
||||
"name": "some-really-long-server-url",
|
||||
"nameNormalized": "some-really-long-server-url",
|
||||
"server": "https://some-really-long-url-that-will-exceed-63-characters.com",
|
||||
"project": "",
|
||||
}},
|
||||
},
|
||||
}
|
||||
@@ -342,7 +340,7 @@ func getMockClusterGenerator() Generator {
|
||||
appClientset := kubefake.NewSimpleClientset(runtimeClusters...)
|
||||
|
||||
fakeClient := fake.NewClientBuilder().WithObjects(clusters...).Build()
|
||||
return NewClusterGenerator(context.Background(), fakeClient, appClientset, "namespace")
|
||||
return NewClusterGenerator(fakeClient, context.Background(), appClientset, "namespace")
|
||||
}
|
||||
|
||||
func getMockGitGenerator() Generator {
|
||||
@@ -413,7 +411,7 @@ func TestInterpolateGenerator(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
gitGeneratorParams := map[string]any{
|
||||
gitGeneratorParams := map[string]interface{}{
|
||||
"path": "p1/p2/app3",
|
||||
"path.basename": "app3",
|
||||
"path[0]": "p1",
|
||||
@@ -442,7 +440,7 @@ func TestInterpolateGenerator(t *testing.T) {
|
||||
Template: argov1alpha1.ApplicationSetTemplate{},
|
||||
},
|
||||
}
|
||||
clusterGeneratorParams := map[string]any{
|
||||
clusterGeneratorParams := map[string]interface{}{
|
||||
"name": "production_01/west", "server": "https://production-01.example.com",
|
||||
}
|
||||
interpolatedGenerator, err = InterpolateGenerator(requestedGenerator, clusterGeneratorParams, false, nil)
|
||||
@@ -468,8 +466,8 @@ func TestInterpolateGenerator_go(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
gitGeneratorParams := map[string]any{
|
||||
"path": map[string]any{
|
||||
gitGeneratorParams := map[string]interface{}{
|
||||
"path": map[string]interface{}{
|
||||
"path": "p1/p2/app3",
|
||||
"segments": []string{"p1", "p2", "app3"},
|
||||
},
|
||||
@@ -497,7 +495,7 @@ func TestInterpolateGenerator_go(t *testing.T) {
|
||||
Template: argov1alpha1.ApplicationSetTemplate{},
|
||||
},
|
||||
}
|
||||
clusterGeneratorParams := map[string]any{
|
||||
clusterGeneratorParams := map[string]interface{}{
|
||||
"name": "production_01/west", "server": "https://production-01.example.com",
|
||||
}
|
||||
interpolatedGenerator, err = InterpolateGenerator(requestedGenerator, clusterGeneratorParams, true, nil)
|
||||
@@ -512,7 +510,7 @@ func TestInterpolateGenerator_go(t *testing.T) {
|
||||
func TestInterpolateGeneratorError(t *testing.T) {
|
||||
type args struct {
|
||||
requestedGenerator *argov1alpha1.ApplicationSetGenerator
|
||||
params map[string]any
|
||||
params map[string]interface{}
|
||||
useGoTemplate bool
|
||||
goTemplateOptions []string
|
||||
}
|
||||
@@ -530,7 +528,7 @@ func TestInterpolateGeneratorError(t *testing.T) {
|
||||
}, want: argov1alpha1.ApplicationSetGenerator{}, expectedErrStr: "generator is empty"},
|
||||
{name: "No Params", args: args{
|
||||
requestedGenerator: &argov1alpha1.ApplicationSetGenerator{},
|
||||
params: map[string]any{},
|
||||
params: map[string]interface{}{},
|
||||
useGoTemplate: false,
|
||||
goTemplateOptions: nil,
|
||||
}, want: argov1alpha1.ApplicationSetGenerator{}, expectedErrStr: ""},
|
||||
@@ -545,7 +543,7 @@ func TestInterpolateGeneratorError(t *testing.T) {
|
||||
"resolved": "{{ index .rmap (default .override .test) }}",
|
||||
},
|
||||
}},
|
||||
params: map[string]any{
|
||||
params: map[string]interface{}{
|
||||
"name": "in-cluster",
|
||||
"override": "foo",
|
||||
},
|
||||
|
||||
@@ -15,10 +15,10 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/services"
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/utils"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v3/util/gpg"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/services"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/utils"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/util/gpg"
|
||||
)
|
||||
|
||||
var _ Generator = (*GitGenerator)(nil)
|
||||
@@ -48,10 +48,10 @@ func (g *GitGenerator) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.Appli
|
||||
return time.Duration(*appSetGenerator.Git.RequeueAfterSeconds) * time.Second
|
||||
}
|
||||
|
||||
return getDefaultRequeueAfter()
|
||||
return DefaultRequeueAfterSeconds
|
||||
}
|
||||
|
||||
func (g *GitGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, appSet *argoprojiov1alpha1.ApplicationSet, client client.Client) ([]map[string]any, error) {
|
||||
func (g *GitGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, appSet *argoprojiov1alpha1.ApplicationSet, client client.Client) ([]map[string]interface{}, error) {
|
||||
if appSetGenerator == nil {
|
||||
return nil, EmptyAppSetGeneratorError
|
||||
}
|
||||
@@ -81,18 +81,13 @@ 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, project, appSet.Spec.GoTemplateOptions)
|
||||
case len(appSetGenerator.Git.Files) != 0:
|
||||
res, err = g.generateParamsForGitFiles(appSetGenerator, noRevisionCache, verifyCommit, appSet.Spec.GoTemplate, project, appSet.Spec.GoTemplateOptions)
|
||||
default:
|
||||
var res []map[string]interface{}
|
||||
if len(appSetGenerator.Git.Directories) != 0 {
|
||||
res, err = g.generateParamsForGitDirectories(appSetGenerator, noRevisionCache, verifyCommit, appSet.Spec.GoTemplate, appSet.Spec.GoTemplateOptions)
|
||||
} else if len(appSetGenerator.Git.Files) != 0 {
|
||||
res, err = g.generateParamsForGitFiles(appSetGenerator, noRevisionCache, verifyCommit, appSet.Spec.GoTemplate, appSet.Spec.GoTemplateOptions)
|
||||
} else {
|
||||
return nil, EmptyAppSetGeneratorError
|
||||
}
|
||||
if err != nil {
|
||||
@@ -102,9 +97,9 @@ func (g *GitGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.Applic
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (g *GitGenerator) generateParamsForGitDirectories(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, noRevisionCache, verifyCommit, useGoTemplate bool, project string, goTemplateOptions []string) ([]map[string]any, error) {
|
||||
func (g *GitGenerator) generateParamsForGitDirectories(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, noRevisionCache, verifyCommit bool, useGoTemplate bool, goTemplateOptions []string) ([]map[string]interface{}, error) {
|
||||
// Directories, not files
|
||||
allPaths, err := g.repos.GetDirectories(context.TODO(), appSetGenerator.Git.RepoURL, appSetGenerator.Git.Revision, project, noRevisionCache, verifyCommit)
|
||||
allPaths, err := g.repos.GetDirectories(context.TODO(), appSetGenerator.Git.RepoURL, appSetGenerator.Git.Revision, noRevisionCache, verifyCommit)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting directories from repo: %w", err)
|
||||
}
|
||||
@@ -127,11 +122,11 @@ func (g *GitGenerator) generateParamsForGitDirectories(appSetGenerator *argoproj
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (g *GitGenerator) generateParamsForGitFiles(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, noRevisionCache, verifyCommit, useGoTemplate bool, project string, goTemplateOptions []string) ([]map[string]any, error) {
|
||||
func (g *GitGenerator) generateParamsForGitFiles(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, noRevisionCache, verifyCommit bool, useGoTemplate bool, goTemplateOptions []string) ([]map[string]interface{}, 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, project, requestedPath.Path, noRevisionCache, verifyCommit)
|
||||
files, err := g.repos.GetFiles(context.TODO(), appSetGenerator.Git.RepoURL, appSetGenerator.Git.Revision, requestedPath.Path, noRevisionCache, verifyCommit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -149,7 +144,7 @@ func (g *GitGenerator) generateParamsForGitFiles(appSetGenerator *argoprojiov1al
|
||||
sort.Strings(allPaths)
|
||||
|
||||
// Generate params from each path, and return
|
||||
res := []map[string]any{}
|
||||
res := []map[string]interface{}{}
|
||||
for _, path := range allPaths {
|
||||
// A JSON / YAML file path can contain multiple sets of parameters (ie it is an array)
|
||||
paramsArray, err := g.generateParamsFromGitFile(path, allFiles[path], appSetGenerator.Git.Values, useGoTemplate, goTemplateOptions, appSetGenerator.Git.PathParamPrefix)
|
||||
@@ -162,14 +157,14 @@ func (g *GitGenerator) generateParamsForGitFiles(appSetGenerator *argoprojiov1al
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (g *GitGenerator) generateParamsFromGitFile(filePath string, fileContent []byte, values map[string]string, useGoTemplate bool, goTemplateOptions []string, pathParamPrefix string) ([]map[string]any, error) {
|
||||
objectsFound := []map[string]any{}
|
||||
func (g *GitGenerator) generateParamsFromGitFile(filePath string, fileContent []byte, values map[string]string, useGoTemplate bool, goTemplateOptions []string, pathParamPrefix string) ([]map[string]interface{}, error) {
|
||||
objectsFound := []map[string]interface{}{}
|
||||
|
||||
// First, we attempt to parse as an array
|
||||
err := yaml.Unmarshal(fileContent, &objectsFound)
|
||||
if err != nil {
|
||||
// If unable to parse as an array, attempt to parse as a single object
|
||||
singleObj := make(map[string]any)
|
||||
singleObj := make(map[string]interface{})
|
||||
err = yaml.Unmarshal(fileContent, &singleObj)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse file: %w", err)
|
||||
@@ -177,20 +172,20 @@ func (g *GitGenerator) generateParamsFromGitFile(filePath string, fileContent []
|
||||
objectsFound = append(objectsFound, singleObj)
|
||||
} else if len(objectsFound) == 0 {
|
||||
// If file is valid but empty, add a default empty item
|
||||
objectsFound = append(objectsFound, map[string]any{})
|
||||
objectsFound = append(objectsFound, map[string]interface{}{})
|
||||
}
|
||||
|
||||
res := []map[string]any{}
|
||||
res := []map[string]interface{}{}
|
||||
|
||||
for _, objectFound := range objectsFound {
|
||||
params := map[string]any{}
|
||||
params := map[string]interface{}{}
|
||||
|
||||
if useGoTemplate {
|
||||
for k, v := range objectFound {
|
||||
params[k] = v
|
||||
}
|
||||
|
||||
paramPath := map[string]any{}
|
||||
paramPath := map[string]interface{}{}
|
||||
|
||||
paramPath["path"] = path.Dir(filePath)
|
||||
paramPath["basename"] = path.Base(paramPath["path"].(string))
|
||||
@@ -199,7 +194,7 @@ func (g *GitGenerator) generateParamsFromGitFile(filePath string, fileContent []
|
||||
paramPath["filenameNormalized"] = utils.SanitizeName(path.Base(paramPath["filename"].(string)))
|
||||
paramPath["segments"] = strings.Split(paramPath["path"].(string), "/")
|
||||
if pathParamPrefix != "" {
|
||||
params[pathParamPrefix] = map[string]any{"path": paramPath}
|
||||
params[pathParamPrefix] = map[string]interface{}{"path": paramPath}
|
||||
} else {
|
||||
params["path"] = paramPath
|
||||
}
|
||||
@@ -266,19 +261,19 @@ func (g *GitGenerator) filterApps(directories []argoprojiov1alpha1.GitDirectoryG
|
||||
return res
|
||||
}
|
||||
|
||||
func (g *GitGenerator) generateParamsFromApps(requestedApps []string, appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, useGoTemplate bool, goTemplateOptions []string) ([]map[string]any, error) {
|
||||
res := make([]map[string]any, len(requestedApps))
|
||||
func (g *GitGenerator) generateParamsFromApps(requestedApps []string, appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, useGoTemplate bool, goTemplateOptions []string) ([]map[string]interface{}, error) {
|
||||
res := make([]map[string]interface{}, len(requestedApps))
|
||||
for i, a := range requestedApps {
|
||||
params := make(map[string]any, 5)
|
||||
params := make(map[string]interface{}, 5)
|
||||
|
||||
if useGoTemplate {
|
||||
paramPath := map[string]any{}
|
||||
paramPath := map[string]interface{}{}
|
||||
paramPath["path"] = a
|
||||
paramPath["basename"] = path.Base(a)
|
||||
paramPath["basenameNormalized"] = utils.SanitizeName(path.Base(a))
|
||||
paramPath["segments"] = strings.Split(paramPath["path"].(string), "/")
|
||||
if appSetGenerator.Git.PathParamPrefix != "" {
|
||||
params[appSetGenerator.Git.PathParamPrefix] = map[string]any{"path": paramPath}
|
||||
params[appSetGenerator.Git.PathParamPrefix] = map[string]interface{}{"path": paramPath}
|
||||
} else {
|
||||
params["path"] = paramPath
|
||||
}
|
||||
@@ -307,11 +302,3 @@ func (g *GitGenerator) generateParamsFromApps(requestedApps []string, appSetGene
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func resolveProjectName(project string) string {
|
||||
if strings.Contains(project, "{{") {
|
||||
return ""
|
||||
}
|
||||
|
||||
return project
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,12 @@
|
||||
package generators
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v3/util/env"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
// Generator defines the interface implemented by all ApplicationSet generators.
|
||||
@@ -15,7 +14,7 @@ type Generator interface {
|
||||
// GenerateParams interprets the ApplicationSet and generates all relevant parameters for the application template.
|
||||
// The expected / desired list of parameters is returned, it then will be render and reconciled
|
||||
// against the current state of the Applications in the cluster.
|
||||
GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, applicationSetInfo *argoprojiov1alpha1.ApplicationSet, client client.Client) ([]map[string]any, error)
|
||||
GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, applicationSetInfo *argoprojiov1alpha1.ApplicationSet, client client.Client) ([]map[string]interface{}, error)
|
||||
|
||||
// GetRequeueAfter is the generator can controller the next reconciled loop
|
||||
// In case there is more then one generator the time will be the minimum of the times.
|
||||
@@ -27,15 +26,11 @@ type Generator interface {
|
||||
}
|
||||
|
||||
var (
|
||||
EmptyAppSetGeneratorError = errors.New("ApplicationSet is empty")
|
||||
EmptyAppSetGeneratorError = fmt.Errorf("ApplicationSet is empty")
|
||||
NoRequeueAfter time.Duration
|
||||
)
|
||||
|
||||
// DefaultRequeueAfterSeconds is used when GetRequeueAfter is not specified, it is the default time to wait before the next reconcile loop
|
||||
const (
|
||||
DefaultRequeueAfterSeconds = 3 * time.Minute
|
||||
)
|
||||
|
||||
func getDefaultRequeueAfter() time.Duration {
|
||||
// Default is 3 minutes, min is 1 second, max is 1 year
|
||||
return env.ParseDurationFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_REQUEUE_AFTER", DefaultRequeueAfterSeconds, 1*time.Second, 8760*time.Hour)
|
||||
}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
package generators
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_getDefaultRequeueAfter(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
requeueAfterEnv string
|
||||
want time.Duration
|
||||
}{
|
||||
{name: "Default", requeueAfterEnv: "", want: DefaultRequeueAfterSeconds},
|
||||
{name: "Min", requeueAfterEnv: "1s", want: 1 * time.Second},
|
||||
{name: "Max", requeueAfterEnv: "8760h", want: 8760 * time.Hour},
|
||||
{name: "Override", requeueAfterEnv: "10m", want: 10 * time.Minute},
|
||||
{name: "LessThanMin", requeueAfterEnv: "1ms", want: DefaultRequeueAfterSeconds},
|
||||
{name: "MoreThanMax", requeueAfterEnv: "8761h", want: DefaultRequeueAfterSeconds},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Setenv("ARGOCD_APPLICATIONSET_CONTROLLER_REQUEUE_AFTER", tt.requeueAfterEnv)
|
||||
assert.Equalf(t, tt.want, getDefaultRequeueAfter(), "getDefaultRequeueAfter()")
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -2,14 +2,13 @@ package generators
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
var _ Generator = (*ListGenerator)(nil)
|
||||
@@ -21,7 +20,7 @@ func NewListGenerator() Generator {
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *ListGenerator) GetRequeueAfter(_ *argoprojiov1alpha1.ApplicationSetGenerator) time.Duration {
|
||||
func (g *ListGenerator) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) time.Duration {
|
||||
return NoRequeueAfter
|
||||
}
|
||||
|
||||
@@ -29,7 +28,7 @@ func (g *ListGenerator) GetTemplate(appSetGenerator *argoprojiov1alpha1.Applicat
|
||||
return &appSetGenerator.List.Template
|
||||
}
|
||||
|
||||
func (g *ListGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, appSet *argoprojiov1alpha1.ApplicationSet, _ client.Client) ([]map[string]any, error) {
|
||||
func (g *ListGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, appSet *argoprojiov1alpha1.ApplicationSet, _ client.Client) ([]map[string]interface{}, error) {
|
||||
if appSetGenerator == nil {
|
||||
return nil, EmptyAppSetGeneratorError
|
||||
}
|
||||
@@ -38,11 +37,11 @@ func (g *ListGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.Appli
|
||||
return nil, EmptyAppSetGeneratorError
|
||||
}
|
||||
|
||||
res := make([]map[string]any, len(appSetGenerator.List.Elements))
|
||||
res := make([]map[string]interface{}, len(appSetGenerator.List.Elements))
|
||||
|
||||
for i, tmpItem := range appSetGenerator.List.Elements {
|
||||
params := map[string]any{}
|
||||
var element map[string]any
|
||||
params := map[string]interface{}{}
|
||||
var element map[string]interface{}
|
||||
err := json.Unmarshal(tmpItem.Raw, &element)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error unmarshling list element %w", err)
|
||||
@@ -53,16 +52,16 @@ func (g *ListGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.Appli
|
||||
} else {
|
||||
for key, value := range element {
|
||||
if key == "values" {
|
||||
values, ok := (value).(map[string]any)
|
||||
values, ok := (value).(map[string]interface{})
|
||||
if !ok {
|
||||
return nil, errors.New("error parsing values map")
|
||||
return nil, fmt.Errorf("error parsing values map")
|
||||
}
|
||||
for k, v := range values {
|
||||
value, ok := v.(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("error parsing value as string %w", err)
|
||||
}
|
||||
params["values."+k] = value
|
||||
params[fmt.Sprintf("values.%s", k)] = value
|
||||
}
|
||||
} else {
|
||||
v, ok := value.(string)
|
||||
@@ -78,7 +77,7 @@ func (g *ListGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.Appli
|
||||
|
||||
// Append elements from ElementsYaml to the response
|
||||
if len(appSetGenerator.List.ElementsYaml) > 0 {
|
||||
var yamlElements []map[string]any
|
||||
var yamlElements []map[string]interface{}
|
||||
err := yaml.Unmarshal([]byte(appSetGenerator.List.ElementsYaml), &yamlElements)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error unmarshling decoded ElementsYaml %w", err)
|
||||
|
||||
@@ -8,20 +8,20 @@ import (
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
func TestGenerateListParams(t *testing.T) {
|
||||
testCases := []struct {
|
||||
elements []apiextensionsv1.JSON
|
||||
expected []map[string]any
|
||||
expected []map[string]interface{}
|
||||
}{
|
||||
{
|
||||
elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url"}`)}},
|
||||
expected: []map[string]any{{"cluster": "cluster", "url": "url"}},
|
||||
expected: []map[string]interface{}{{"cluster": "cluster", "url": "url"}},
|
||||
}, {
|
||||
elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url","values":{"foo":"bar"}}`)}},
|
||||
expected: []map[string]any{{"cluster": "cluster", "url": "url", "values.foo": "bar"}},
|
||||
expected: []map[string]interface{}{{"cluster": "cluster", "url": "url", "values.foo": "bar"}},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -49,14 +49,14 @@ func TestGenerateListParams(t *testing.T) {
|
||||
func TestGenerateListParamsGoTemplate(t *testing.T) {
|
||||
testCases := []struct {
|
||||
elements []apiextensionsv1.JSON
|
||||
expected []map[string]any
|
||||
expected []map[string]interface{}
|
||||
}{
|
||||
{
|
||||
elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url"}`)}},
|
||||
expected: []map[string]any{{"cluster": "cluster", "url": "url"}},
|
||||
expected: []map[string]interface{}{{"cluster": "cluster", "url": "url"}},
|
||||
}, {
|
||||
elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url","values":{"foo":"bar"}}`)}},
|
||||
expected: []map[string]any{{"cluster": "cluster", "url": "url", "values": map[string]any{"foo": "bar"}}},
|
||||
expected: []map[string]interface{}{{"cluster": "cluster", "url": "url", "values": map[string]interface{}{"foo": "bar"}}},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
package generators
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"dario.cat/mergo"
|
||||
"github.com/imdario/mergo"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/utils"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/utils"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var _ Generator = (*MatrixGenerator)(nil)
|
||||
|
||||
var (
|
||||
ErrMoreThanTwoGenerators = errors.New("found more than two generators, Matrix support only two")
|
||||
ErrLessThanTwoGenerators = errors.New("found less than two generators, Matrix support only two")
|
||||
ErrMoreThenOneInnerGenerators = errors.New("found more than one generator in matrix.Generators")
|
||||
ErrMoreThanTwoGenerators = fmt.Errorf("found more than two generators, Matrix support only two")
|
||||
ErrLessThanTwoGenerators = fmt.Errorf("found less than two generators, Matrix support only two")
|
||||
ErrMoreThenOneInnerGenerators = fmt.Errorf("found more than one generator in matrix.Generators")
|
||||
)
|
||||
|
||||
type MatrixGenerator struct {
|
||||
@@ -32,7 +33,7 @@ func NewMatrixGenerator(supportedGenerators map[string]Generator) Generator {
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *MatrixGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, appSet *argoprojiov1alpha1.ApplicationSet, client client.Client) ([]map[string]any, error) {
|
||||
func (m *MatrixGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, appSet *argoprojiov1alpha1.ApplicationSet, client client.Client) ([]map[string]interface{}, error) {
|
||||
if appSetGenerator.Matrix == nil {
|
||||
return nil, EmptyAppSetGeneratorError
|
||||
}
|
||||
@@ -45,7 +46,7 @@ func (m *MatrixGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.App
|
||||
return nil, ErrMoreThanTwoGenerators
|
||||
}
|
||||
|
||||
res := []map[string]any{}
|
||||
res := []map[string]interface{}{}
|
||||
|
||||
g0, err := m.getParams(appSetGenerator.Matrix.Generators[0], appSet, nil, client)
|
||||
if err != nil {
|
||||
@@ -58,7 +59,7 @@ func (m *MatrixGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.App
|
||||
}
|
||||
for _, b := range g1 {
|
||||
if appSet.Spec.GoTemplate {
|
||||
tmp := map[string]any{}
|
||||
tmp := map[string]interface{}{}
|
||||
if err := mergo.Merge(&tmp, b, mergo.WithOverride); err != nil {
|
||||
return nil, fmt.Errorf("failed to merge params from the second generator in the matrix generator with temp map: %w", err)
|
||||
}
|
||||
@@ -79,15 +80,27 @@ func (m *MatrixGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.App
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (m *MatrixGenerator) getParams(appSetBaseGenerator argoprojiov1alpha1.ApplicationSetNestedGenerator, appSet *argoprojiov1alpha1.ApplicationSet, params map[string]any, client client.Client) ([]map[string]any, error) {
|
||||
func (m *MatrixGenerator) getParams(appSetBaseGenerator argoprojiov1alpha1.ApplicationSetNestedGenerator, appSet *argoprojiov1alpha1.ApplicationSet, params map[string]interface{}, client client.Client) ([]map[string]interface{}, error) {
|
||||
matrixGen, err := getMatrixGenerator(appSetBaseGenerator)
|
||||
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{
|
||||
@@ -112,7 +125,7 @@ func (m *MatrixGenerator) getParams(appSetBaseGenerator argoprojiov1alpha1.Appli
|
||||
}
|
||||
|
||||
if len(t) == 0 {
|
||||
return nil, errors.New("child generator generated no parameters")
|
||||
return nil, fmt.Errorf("child generator generated no parameters")
|
||||
}
|
||||
|
||||
if len(t) > 1 {
|
||||
@@ -155,8 +168,9 @@ func (m *MatrixGenerator) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.Ap
|
||||
|
||||
if found {
|
||||
return res
|
||||
} else {
|
||||
return NoRequeueAfter
|
||||
}
|
||||
return NoRequeueAfter
|
||||
}
|
||||
|
||||
func getMatrixGenerator(r argoprojiov1alpha1.ApplicationSetNestedGenerator) (*argoprojiov1alpha1.MatrixGenerator, error) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package generators
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -12,35 +13,36 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/services/mocks"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/services/mocks"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
func TestMatrixGenerate(t *testing.T) {
|
||||
gitGenerator := &v1alpha1.GitGenerator{
|
||||
gitGenerator := &argoprojiov1alpha1.GitGenerator{
|
||||
RepoURL: "RepoURL",
|
||||
Revision: "Revision",
|
||||
Directories: []v1alpha1.GitDirectoryGeneratorItem{{Path: "*"}},
|
||||
Directories: []argoprojiov1alpha1.GitDirectoryGeneratorItem{{Path: "*"}},
|
||||
}
|
||||
|
||||
listGenerator := &v1alpha1.ListGenerator{
|
||||
listGenerator := &argoprojiov1alpha1.ListGenerator{
|
||||
Elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "Cluster","url": "Url", "templated": "test-{{path.basenameNormalized}}"}`)}},
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
baseGenerators []v1alpha1.ApplicationSetNestedGenerator
|
||||
baseGenerators []argoprojiov1alpha1.ApplicationSetNestedGenerator
|
||||
expectedErr error
|
||||
expected []map[string]any
|
||||
expected []map[string]interface{}
|
||||
}{
|
||||
{
|
||||
name: "happy flow - generate params",
|
||||
baseGenerators: []v1alpha1.ApplicationSetNestedGenerator{
|
||||
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
|
||||
{
|
||||
Git: gitGenerator,
|
||||
},
|
||||
@@ -48,16 +50,16 @@ func TestMatrixGenerate(t *testing.T) {
|
||||
List: listGenerator,
|
||||
},
|
||||
},
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{"path": "app1", "path.basename": "app1", "path.basenameNormalized": "app1", "cluster": "Cluster", "url": "Url", "templated": "test-app1"},
|
||||
{"path": "app2", "path.basename": "app2", "path.basenameNormalized": "app2", "cluster": "Cluster", "url": "Url", "templated": "test-app2"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "happy flow - generate params from two lists",
|
||||
baseGenerators: []v1alpha1.ApplicationSetNestedGenerator{
|
||||
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
|
||||
{
|
||||
List: &v1alpha1.ListGenerator{
|
||||
List: &argoprojiov1alpha1.ListGenerator{
|
||||
Elements: []apiextensionsv1.JSON{
|
||||
{Raw: []byte(`{"a": "1"}`)},
|
||||
{Raw: []byte(`{"a": "2"}`)},
|
||||
@@ -65,7 +67,7 @@ func TestMatrixGenerate(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
List: &v1alpha1.ListGenerator{
|
||||
List: &argoprojiov1alpha1.ListGenerator{
|
||||
Elements: []apiextensionsv1.JSON{
|
||||
{Raw: []byte(`{"b": "1"}`)},
|
||||
{Raw: []byte(`{"b": "2"}`)},
|
||||
@@ -73,7 +75,7 @@ func TestMatrixGenerate(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{"a": "1", "b": "1"},
|
||||
{"a": "1", "b": "2"},
|
||||
{"a": "2", "b": "1"},
|
||||
@@ -82,7 +84,7 @@ func TestMatrixGenerate(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "returns error if there is less than two base generators",
|
||||
baseGenerators: []v1alpha1.ApplicationSetNestedGenerator{
|
||||
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
|
||||
{
|
||||
Git: gitGenerator,
|
||||
},
|
||||
@@ -91,7 +93,7 @@ func TestMatrixGenerate(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "returns error if there is more than two base generators",
|
||||
baseGenerators: []v1alpha1.ApplicationSetNestedGenerator{
|
||||
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
|
||||
{
|
||||
List: listGenerator,
|
||||
},
|
||||
@@ -106,7 +108,7 @@ func TestMatrixGenerate(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "returns error if there is more than one inner generator in the first base generator",
|
||||
baseGenerators: []v1alpha1.ApplicationSetNestedGenerator{
|
||||
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
|
||||
{
|
||||
Git: gitGenerator,
|
||||
List: listGenerator,
|
||||
@@ -119,7 +121,7 @@ func TestMatrixGenerate(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "returns error if there is more than one inner generator in the second base generator",
|
||||
baseGenerators: []v1alpha1.ApplicationSetNestedGenerator{
|
||||
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
|
||||
{
|
||||
List: listGenerator,
|
||||
},
|
||||
@@ -137,19 +139,19 @@ func TestMatrixGenerate(t *testing.T) {
|
||||
|
||||
t.Run(testCaseCopy.name, func(t *testing.T) {
|
||||
genMock := &generatorMock{}
|
||||
appSet := &v1alpha1.ApplicationSet{
|
||||
appSet := &argoprojiov1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "set",
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSetSpec{},
|
||||
Spec: argoprojiov1alpha1.ApplicationSetSpec{},
|
||||
}
|
||||
|
||||
for _, g := range testCaseCopy.baseGenerators {
|
||||
gitGeneratorSpec := v1alpha1.ApplicationSetGenerator{
|
||||
gitGeneratorSpec := argoprojiov1alpha1.ApplicationSetGenerator{
|
||||
Git: g.Git,
|
||||
List: g.List,
|
||||
}
|
||||
genMock.On("GenerateParams", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), appSet, mock.Anything).Return([]map[string]any{
|
||||
genMock.On("GenerateParams", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), appSet, mock.Anything).Return([]map[string]interface{}{
|
||||
{
|
||||
"path": "app1",
|
||||
"path.basename": "app1",
|
||||
@@ -163,7 +165,7 @@ func TestMatrixGenerate(t *testing.T) {
|
||||
}, nil)
|
||||
|
||||
genMock.On("GetTemplate", &gitGeneratorSpec).
|
||||
Return(&v1alpha1.ApplicationSetTemplate{})
|
||||
Return(&argoprojiov1alpha1.ApplicationSetTemplate{})
|
||||
}
|
||||
|
||||
matrixGenerator := NewMatrixGenerator(
|
||||
@@ -173,10 +175,10 @@ func TestMatrixGenerate(t *testing.T) {
|
||||
},
|
||||
)
|
||||
|
||||
got, err := matrixGenerator.GenerateParams(&v1alpha1.ApplicationSetGenerator{
|
||||
Matrix: &v1alpha1.MatrixGenerator{
|
||||
got, err := matrixGenerator.GenerateParams(&argoprojiov1alpha1.ApplicationSetGenerator{
|
||||
Matrix: &argoprojiov1alpha1.MatrixGenerator{
|
||||
Generators: testCaseCopy.baseGenerators,
|
||||
Template: v1alpha1.ApplicationSetTemplate{},
|
||||
Template: argoprojiov1alpha1.ApplicationSetTemplate{},
|
||||
},
|
||||
}, appSet, nil)
|
||||
|
||||
@@ -191,25 +193,25 @@ func TestMatrixGenerate(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMatrixGenerateGoTemplate(t *testing.T) {
|
||||
gitGenerator := &v1alpha1.GitGenerator{
|
||||
gitGenerator := &argoprojiov1alpha1.GitGenerator{
|
||||
RepoURL: "RepoURL",
|
||||
Revision: "Revision",
|
||||
Directories: []v1alpha1.GitDirectoryGeneratorItem{{Path: "*"}},
|
||||
Directories: []argoprojiov1alpha1.GitDirectoryGeneratorItem{{Path: "*"}},
|
||||
}
|
||||
|
||||
listGenerator := &v1alpha1.ListGenerator{
|
||||
listGenerator := &argoprojiov1alpha1.ListGenerator{
|
||||
Elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "Cluster","url": "Url"}`)}},
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
baseGenerators []v1alpha1.ApplicationSetNestedGenerator
|
||||
baseGenerators []argoprojiov1alpha1.ApplicationSetNestedGenerator
|
||||
expectedErr error
|
||||
expected []map[string]any
|
||||
expected []map[string]interface{}
|
||||
}{
|
||||
{
|
||||
name: "happy flow - generate params",
|
||||
baseGenerators: []v1alpha1.ApplicationSetNestedGenerator{
|
||||
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
|
||||
{
|
||||
Git: gitGenerator,
|
||||
},
|
||||
@@ -217,7 +219,7 @@ func TestMatrixGenerateGoTemplate(t *testing.T) {
|
||||
List: listGenerator,
|
||||
},
|
||||
},
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"path": map[string]string{
|
||||
"path": "app1",
|
||||
@@ -240,9 +242,9 @@ func TestMatrixGenerateGoTemplate(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "happy flow - generate params from two lists",
|
||||
baseGenerators: []v1alpha1.ApplicationSetNestedGenerator{
|
||||
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
|
||||
{
|
||||
List: &v1alpha1.ListGenerator{
|
||||
List: &argoprojiov1alpha1.ListGenerator{
|
||||
Elements: []apiextensionsv1.JSON{
|
||||
{Raw: []byte(`{"a": "1"}`)},
|
||||
{Raw: []byte(`{"a": "2"}`)},
|
||||
@@ -250,7 +252,7 @@ func TestMatrixGenerateGoTemplate(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
List: &v1alpha1.ListGenerator{
|
||||
List: &argoprojiov1alpha1.ListGenerator{
|
||||
Elements: []apiextensionsv1.JSON{
|
||||
{Raw: []byte(`{"b": "1"}`)},
|
||||
{Raw: []byte(`{"b": "2"}`)},
|
||||
@@ -258,7 +260,7 @@ func TestMatrixGenerateGoTemplate(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{"a": "1", "b": "1"},
|
||||
{"a": "1", "b": "2"},
|
||||
{"a": "2", "b": "1"},
|
||||
@@ -267,29 +269,29 @@ func TestMatrixGenerateGoTemplate(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "parameter override: first list elements take precedence",
|
||||
baseGenerators: []v1alpha1.ApplicationSetNestedGenerator{
|
||||
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
|
||||
{
|
||||
List: &v1alpha1.ListGenerator{
|
||||
List: &argoprojiov1alpha1.ListGenerator{
|
||||
Elements: []apiextensionsv1.JSON{
|
||||
{Raw: []byte(`{"booleanFalse": false, "booleanTrue": true, "stringFalse": "false", "stringTrue": "true"}`)},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
List: &v1alpha1.ListGenerator{
|
||||
List: &argoprojiov1alpha1.ListGenerator{
|
||||
Elements: []apiextensionsv1.JSON{
|
||||
{Raw: []byte(`{"booleanFalse": true, "booleanTrue": false, "stringFalse": "true", "stringTrue": "false"}`)},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{"booleanFalse": false, "booleanTrue": true, "stringFalse": "false", "stringTrue": "true"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "returns error if there is less than two base generators",
|
||||
baseGenerators: []v1alpha1.ApplicationSetNestedGenerator{
|
||||
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
|
||||
{
|
||||
Git: gitGenerator,
|
||||
},
|
||||
@@ -298,7 +300,7 @@ func TestMatrixGenerateGoTemplate(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "returns error if there is more than two base generators",
|
||||
baseGenerators: []v1alpha1.ApplicationSetNestedGenerator{
|
||||
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
|
||||
{
|
||||
List: listGenerator,
|
||||
},
|
||||
@@ -313,7 +315,7 @@ func TestMatrixGenerateGoTemplate(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "returns error if there is more than one inner generator in the first base generator",
|
||||
baseGenerators: []v1alpha1.ApplicationSetNestedGenerator{
|
||||
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
|
||||
{
|
||||
Git: gitGenerator,
|
||||
List: listGenerator,
|
||||
@@ -326,7 +328,7 @@ func TestMatrixGenerateGoTemplate(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "returns error if there is more than one inner generator in the second base generator",
|
||||
baseGenerators: []v1alpha1.ApplicationSetNestedGenerator{
|
||||
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
|
||||
{
|
||||
List: listGenerator,
|
||||
},
|
||||
@@ -344,21 +346,21 @@ func TestMatrixGenerateGoTemplate(t *testing.T) {
|
||||
|
||||
t.Run(testCaseCopy.name, func(t *testing.T) {
|
||||
genMock := &generatorMock{}
|
||||
appSet := &v1alpha1.ApplicationSet{
|
||||
appSet := &argoprojiov1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "set",
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
Spec: argoprojiov1alpha1.ApplicationSetSpec{
|
||||
GoTemplate: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, g := range testCaseCopy.baseGenerators {
|
||||
gitGeneratorSpec := v1alpha1.ApplicationSetGenerator{
|
||||
gitGeneratorSpec := argoprojiov1alpha1.ApplicationSetGenerator{
|
||||
Git: g.Git,
|
||||
List: g.List,
|
||||
}
|
||||
genMock.On("GenerateParams", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), appSet, mock.Anything).Return([]map[string]any{
|
||||
genMock.On("GenerateParams", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), appSet, mock.Anything).Return([]map[string]interface{}{
|
||||
{
|
||||
"path": map[string]string{
|
||||
"path": "app1",
|
||||
@@ -376,7 +378,7 @@ func TestMatrixGenerateGoTemplate(t *testing.T) {
|
||||
}, nil)
|
||||
|
||||
genMock.On("GetTemplate", &gitGeneratorSpec).
|
||||
Return(&v1alpha1.ApplicationSetTemplate{})
|
||||
Return(&argoprojiov1alpha1.ApplicationSetTemplate{})
|
||||
}
|
||||
|
||||
matrixGenerator := NewMatrixGenerator(
|
||||
@@ -386,10 +388,10 @@ func TestMatrixGenerateGoTemplate(t *testing.T) {
|
||||
},
|
||||
)
|
||||
|
||||
got, err := matrixGenerator.GenerateParams(&v1alpha1.ApplicationSetGenerator{
|
||||
Matrix: &v1alpha1.MatrixGenerator{
|
||||
got, err := matrixGenerator.GenerateParams(&argoprojiov1alpha1.ApplicationSetGenerator{
|
||||
Matrix: &argoprojiov1alpha1.MatrixGenerator{
|
||||
Generators: testCaseCopy.baseGenerators,
|
||||
Template: v1alpha1.ApplicationSetTemplate{},
|
||||
Template: argoprojiov1alpha1.ApplicationSetTemplate{},
|
||||
},
|
||||
}, appSet, nil)
|
||||
|
||||
@@ -404,31 +406,31 @@ func TestMatrixGenerateGoTemplate(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMatrixGetRequeueAfter(t *testing.T) {
|
||||
gitGenerator := &v1alpha1.GitGenerator{
|
||||
gitGenerator := &argoprojiov1alpha1.GitGenerator{
|
||||
RepoURL: "RepoURL",
|
||||
Revision: "Revision",
|
||||
Directories: []v1alpha1.GitDirectoryGeneratorItem{{Path: "*"}},
|
||||
Directories: []argoprojiov1alpha1.GitDirectoryGeneratorItem{{Path: "*"}},
|
||||
}
|
||||
|
||||
listGenerator := &v1alpha1.ListGenerator{
|
||||
listGenerator := &argoprojiov1alpha1.ListGenerator{
|
||||
Elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "Cluster","url": "Url"}`)}},
|
||||
}
|
||||
|
||||
pullRequestGenerator := &v1alpha1.PullRequestGenerator{}
|
||||
pullRequestGenerator := &argoprojiov1alpha1.PullRequestGenerator{}
|
||||
|
||||
scmGenerator := &v1alpha1.SCMProviderGenerator{}
|
||||
scmGenerator := &argoprojiov1alpha1.SCMProviderGenerator{}
|
||||
|
||||
duckTypeGenerator := &v1alpha1.DuckTypeGenerator{}
|
||||
duckTypeGenerator := &argoprojiov1alpha1.DuckTypeGenerator{}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
baseGenerators []v1alpha1.ApplicationSetNestedGenerator
|
||||
baseGenerators []argoprojiov1alpha1.ApplicationSetNestedGenerator
|
||||
gitGetRequeueAfter time.Duration
|
||||
expected time.Duration
|
||||
}{
|
||||
{
|
||||
name: "return NoRequeueAfter if all the inner baseGenerators returns it",
|
||||
baseGenerators: []v1alpha1.ApplicationSetNestedGenerator{
|
||||
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
|
||||
{
|
||||
Git: gitGenerator,
|
||||
},
|
||||
@@ -441,7 +443,7 @@ func TestMatrixGetRequeueAfter(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "returns the minimal time",
|
||||
baseGenerators: []v1alpha1.ApplicationSetNestedGenerator{
|
||||
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
|
||||
{
|
||||
Git: gitGenerator,
|
||||
},
|
||||
@@ -454,7 +456,7 @@ func TestMatrixGetRequeueAfter(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "returns the minimal time for pull request",
|
||||
baseGenerators: []v1alpha1.ApplicationSetNestedGenerator{
|
||||
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
|
||||
{
|
||||
Git: gitGenerator,
|
||||
},
|
||||
@@ -467,7 +469,7 @@ func TestMatrixGetRequeueAfter(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "returns the default time if no requeueAfterSeconds is provided",
|
||||
baseGenerators: []v1alpha1.ApplicationSetNestedGenerator{
|
||||
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
|
||||
{
|
||||
Git: gitGenerator,
|
||||
},
|
||||
@@ -479,7 +481,7 @@ func TestMatrixGetRequeueAfter(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "returns the default time for duck type generator",
|
||||
baseGenerators: []v1alpha1.ApplicationSetNestedGenerator{
|
||||
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
|
||||
{
|
||||
Git: gitGenerator,
|
||||
},
|
||||
@@ -491,7 +493,7 @@ func TestMatrixGetRequeueAfter(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "returns the default time for scm generator",
|
||||
baseGenerators: []v1alpha1.ApplicationSetNestedGenerator{
|
||||
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
|
||||
{
|
||||
Git: gitGenerator,
|
||||
},
|
||||
@@ -510,7 +512,7 @@ func TestMatrixGetRequeueAfter(t *testing.T) {
|
||||
mock := &generatorMock{}
|
||||
|
||||
for _, g := range testCaseCopy.baseGenerators {
|
||||
gitGeneratorSpec := v1alpha1.ApplicationSetGenerator{
|
||||
gitGeneratorSpec := argoprojiov1alpha1.ApplicationSetGenerator{
|
||||
Git: g.Git,
|
||||
List: g.List,
|
||||
PullRequest: g.PullRequest,
|
||||
@@ -530,10 +532,10 @@ func TestMatrixGetRequeueAfter(t *testing.T) {
|
||||
},
|
||||
)
|
||||
|
||||
got := matrixGenerator.GetRequeueAfter(&v1alpha1.ApplicationSetGenerator{
|
||||
Matrix: &v1alpha1.MatrixGenerator{
|
||||
got := matrixGenerator.GetRequeueAfter(&argoprojiov1alpha1.ApplicationSetGenerator{
|
||||
Matrix: &argoprojiov1alpha1.MatrixGenerator{
|
||||
Generators: testCaseCopy.baseGenerators,
|
||||
Template: v1alpha1.ApplicationSetTemplate{},
|
||||
Template: argoprojiov1alpha1.ApplicationSetTemplate{},
|
||||
},
|
||||
})
|
||||
|
||||
@@ -543,16 +545,16 @@ func TestMatrixGetRequeueAfter(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestInterpolatedMatrixGenerate(t *testing.T) {
|
||||
interpolatedGitGenerator := &v1alpha1.GitGenerator{
|
||||
interpolatedGitGenerator := &argoprojiov1alpha1.GitGenerator{
|
||||
RepoURL: "RepoURL",
|
||||
Revision: "Revision",
|
||||
Files: []v1alpha1.GitFileGeneratorItem{
|
||||
Files: []argoprojiov1alpha1.GitFileGeneratorItem{
|
||||
{Path: "examples/git-generator-files-discovery/cluster-config/dev/config.json"},
|
||||
{Path: "examples/git-generator-files-discovery/cluster-config/prod/config.json"},
|
||||
},
|
||||
}
|
||||
|
||||
interpolatedClusterGenerator := &v1alpha1.ClusterGenerator{
|
||||
interpolatedClusterGenerator := &argoprojiov1alpha1.ClusterGenerator{
|
||||
Selector: metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{"environment": "{{path.basename}}"},
|
||||
MatchExpressions: nil,
|
||||
@@ -560,14 +562,14 @@ func TestInterpolatedMatrixGenerate(t *testing.T) {
|
||||
}
|
||||
testCases := []struct {
|
||||
name string
|
||||
baseGenerators []v1alpha1.ApplicationSetNestedGenerator
|
||||
baseGenerators []argoprojiov1alpha1.ApplicationSetNestedGenerator
|
||||
expectedErr error
|
||||
expected []map[string]any
|
||||
expected []map[string]interface{}
|
||||
clientError bool
|
||||
}{
|
||||
{
|
||||
name: "happy flow - generate interpolated params",
|
||||
baseGenerators: []v1alpha1.ApplicationSetNestedGenerator{
|
||||
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
|
||||
{
|
||||
Git: interpolatedGitGenerator,
|
||||
},
|
||||
@@ -575,9 +577,9 @@ func TestInterpolatedMatrixGenerate(t *testing.T) {
|
||||
Clusters: interpolatedClusterGenerator,
|
||||
},
|
||||
},
|
||||
expected: []map[string]any{
|
||||
{"path": "examples/git-generator-files-discovery/cluster-config/dev/config.json", "path.basename": "dev", "path.basenameNormalized": "dev", "name": "dev-01", "nameNormalized": "dev-01", "server": "https://dev-01.example.com", "metadata.labels.environment": "dev", "metadata.labels.argocd.argoproj.io/secret-type": "cluster", "project": ""},
|
||||
{"path": "examples/git-generator-files-discovery/cluster-config/prod/config.json", "path.basename": "prod", "path.basenameNormalized": "prod", "name": "prod-01", "nameNormalized": "prod-01", "server": "https://prod-01.example.com", "metadata.labels.environment": "prod", "metadata.labels.argocd.argoproj.io/secret-type": "cluster", "project": ""},
|
||||
expected: []map[string]interface{}{
|
||||
{"path": "examples/git-generator-files-discovery/cluster-config/dev/config.json", "path.basename": "dev", "path.basenameNormalized": "dev", "name": "dev-01", "nameNormalized": "dev-01", "server": "https://dev-01.example.com", "metadata.labels.environment": "dev", "metadata.labels.argocd.argoproj.io/secret-type": "cluster"},
|
||||
{"path": "examples/git-generator-files-discovery/cluster-config/prod/config.json", "path.basename": "prod", "path.basenameNormalized": "prod", "name": "prod-01", "nameNormalized": "prod-01", "server": "https://prod-01.example.com", "metadata.labels.environment": "prod", "metadata.labels.argocd.argoproj.io/secret-type": "cluster"},
|
||||
},
|
||||
clientError: false,
|
||||
},
|
||||
@@ -635,7 +637,7 @@ func TestInterpolatedMatrixGenerate(t *testing.T) {
|
||||
|
||||
t.Run(testCaseCopy.name, func(t *testing.T) {
|
||||
genMock := &generatorMock{}
|
||||
appSet := &v1alpha1.ApplicationSet{}
|
||||
appSet := &argoprojiov1alpha1.ApplicationSet{}
|
||||
|
||||
appClientset := kubefake.NewSimpleClientset(runtimeClusters...)
|
||||
fakeClient := fake.NewClientBuilder().WithObjects(clusters...).Build()
|
||||
@@ -643,14 +645,14 @@ func TestInterpolatedMatrixGenerate(t *testing.T) {
|
||||
fakeClient,
|
||||
testCase.clientError,
|
||||
}
|
||||
clusterGenerator := NewClusterGenerator(t.Context(), cl, appClientset, "namespace")
|
||||
clusterGenerator := NewClusterGenerator(cl, context.Background(), appClientset, "namespace")
|
||||
|
||||
for _, g := range testCaseCopy.baseGenerators {
|
||||
gitGeneratorSpec := v1alpha1.ApplicationSetGenerator{
|
||||
gitGeneratorSpec := argoprojiov1alpha1.ApplicationSetGenerator{
|
||||
Git: g.Git,
|
||||
Clusters: g.Clusters,
|
||||
}
|
||||
genMock.On("GenerateParams", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), appSet).Return([]map[string]any{
|
||||
genMock.On("GenerateParams", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), appSet).Return([]map[string]interface{}{
|
||||
{
|
||||
"path": "examples/git-generator-files-discovery/cluster-config/dev/config.json",
|
||||
"path.basename": "dev",
|
||||
@@ -663,7 +665,7 @@ func TestInterpolatedMatrixGenerate(t *testing.T) {
|
||||
},
|
||||
}, nil)
|
||||
genMock.On("GetTemplate", &gitGeneratorSpec).
|
||||
Return(&v1alpha1.ApplicationSetTemplate{})
|
||||
Return(&argoprojiov1alpha1.ApplicationSetTemplate{})
|
||||
}
|
||||
matrixGenerator := NewMatrixGenerator(
|
||||
map[string]Generator{
|
||||
@@ -672,10 +674,10 @@ func TestInterpolatedMatrixGenerate(t *testing.T) {
|
||||
},
|
||||
)
|
||||
|
||||
got, err := matrixGenerator.GenerateParams(&v1alpha1.ApplicationSetGenerator{
|
||||
Matrix: &v1alpha1.MatrixGenerator{
|
||||
got, err := matrixGenerator.GenerateParams(&argoprojiov1alpha1.ApplicationSetGenerator{
|
||||
Matrix: &argoprojiov1alpha1.MatrixGenerator{
|
||||
Generators: testCaseCopy.baseGenerators,
|
||||
Template: v1alpha1.ApplicationSetTemplate{},
|
||||
Template: argoprojiov1alpha1.ApplicationSetTemplate{},
|
||||
},
|
||||
}, appSet, nil)
|
||||
|
||||
@@ -690,16 +692,16 @@ func TestInterpolatedMatrixGenerate(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestInterpolatedMatrixGenerateGoTemplate(t *testing.T) {
|
||||
interpolatedGitGenerator := &v1alpha1.GitGenerator{
|
||||
interpolatedGitGenerator := &argoprojiov1alpha1.GitGenerator{
|
||||
RepoURL: "RepoURL",
|
||||
Revision: "Revision",
|
||||
Files: []v1alpha1.GitFileGeneratorItem{
|
||||
Files: []argoprojiov1alpha1.GitFileGeneratorItem{
|
||||
{Path: "examples/git-generator-files-discovery/cluster-config/dev/config.json"},
|
||||
{Path: "examples/git-generator-files-discovery/cluster-config/prod/config.json"},
|
||||
},
|
||||
}
|
||||
|
||||
interpolatedClusterGenerator := &v1alpha1.ClusterGenerator{
|
||||
interpolatedClusterGenerator := &argoprojiov1alpha1.ClusterGenerator{
|
||||
Selector: metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{"environment": "{{.path.basename}}"},
|
||||
MatchExpressions: nil,
|
||||
@@ -707,14 +709,14 @@ func TestInterpolatedMatrixGenerateGoTemplate(t *testing.T) {
|
||||
}
|
||||
testCases := []struct {
|
||||
name string
|
||||
baseGenerators []v1alpha1.ApplicationSetNestedGenerator
|
||||
baseGenerators []argoprojiov1alpha1.ApplicationSetNestedGenerator
|
||||
expectedErr error
|
||||
expected []map[string]any
|
||||
expected []map[string]interface{}
|
||||
clientError bool
|
||||
}{
|
||||
{
|
||||
name: "happy flow - generate interpolated params",
|
||||
baseGenerators: []v1alpha1.ApplicationSetNestedGenerator{
|
||||
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
|
||||
{
|
||||
Git: interpolatedGitGenerator,
|
||||
},
|
||||
@@ -722,7 +724,7 @@ func TestInterpolatedMatrixGenerateGoTemplate(t *testing.T) {
|
||||
Clusters: interpolatedClusterGenerator,
|
||||
},
|
||||
},
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"path": map[string]string{
|
||||
"path": "examples/git-generator-files-discovery/cluster-config/dev/config.json",
|
||||
@@ -732,8 +734,7 @@ func TestInterpolatedMatrixGenerateGoTemplate(t *testing.T) {
|
||||
"name": "dev-01",
|
||||
"nameNormalized": "dev-01",
|
||||
"server": "https://dev-01.example.com",
|
||||
"project": "",
|
||||
"metadata": map[string]any{
|
||||
"metadata": map[string]interface{}{
|
||||
"labels": map[string]string{
|
||||
"environment": "dev",
|
||||
"argocd.argoproj.io/secret-type": "cluster",
|
||||
@@ -749,8 +750,7 @@ func TestInterpolatedMatrixGenerateGoTemplate(t *testing.T) {
|
||||
"name": "prod-01",
|
||||
"nameNormalized": "prod-01",
|
||||
"server": "https://prod-01.example.com",
|
||||
"project": "",
|
||||
"metadata": map[string]any{
|
||||
"metadata": map[string]interface{}{
|
||||
"labels": map[string]string{
|
||||
"environment": "prod",
|
||||
"argocd.argoproj.io/secret-type": "cluster",
|
||||
@@ -814,8 +814,8 @@ func TestInterpolatedMatrixGenerateGoTemplate(t *testing.T) {
|
||||
|
||||
t.Run(testCaseCopy.name, func(t *testing.T) {
|
||||
genMock := &generatorMock{}
|
||||
appSet := &v1alpha1.ApplicationSet{
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
appSet := &argoprojiov1alpha1.ApplicationSet{
|
||||
Spec: argoprojiov1alpha1.ApplicationSetSpec{
|
||||
GoTemplate: true,
|
||||
},
|
||||
}
|
||||
@@ -826,14 +826,14 @@ func TestInterpolatedMatrixGenerateGoTemplate(t *testing.T) {
|
||||
fakeClient,
|
||||
testCase.clientError,
|
||||
}
|
||||
clusterGenerator := NewClusterGenerator(t.Context(), cl, appClientset, "namespace")
|
||||
clusterGenerator := NewClusterGenerator(cl, context.Background(), appClientset, "namespace")
|
||||
|
||||
for _, g := range testCaseCopy.baseGenerators {
|
||||
gitGeneratorSpec := v1alpha1.ApplicationSetGenerator{
|
||||
gitGeneratorSpec := argoprojiov1alpha1.ApplicationSetGenerator{
|
||||
Git: g.Git,
|
||||
Clusters: g.Clusters,
|
||||
}
|
||||
genMock.On("GenerateParams", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), appSet).Return([]map[string]any{
|
||||
genMock.On("GenerateParams", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), appSet).Return([]map[string]interface{}{
|
||||
{
|
||||
"path": map[string]string{
|
||||
"path": "examples/git-generator-files-discovery/cluster-config/dev/config.json",
|
||||
@@ -850,7 +850,7 @@ func TestInterpolatedMatrixGenerateGoTemplate(t *testing.T) {
|
||||
},
|
||||
}, nil)
|
||||
genMock.On("GetTemplate", &gitGeneratorSpec).
|
||||
Return(&v1alpha1.ApplicationSetTemplate{})
|
||||
Return(&argoprojiov1alpha1.ApplicationSetTemplate{})
|
||||
}
|
||||
matrixGenerator := NewMatrixGenerator(
|
||||
map[string]Generator{
|
||||
@@ -859,10 +859,10 @@ func TestInterpolatedMatrixGenerateGoTemplate(t *testing.T) {
|
||||
},
|
||||
)
|
||||
|
||||
got, err := matrixGenerator.GenerateParams(&v1alpha1.ApplicationSetGenerator{
|
||||
Matrix: &v1alpha1.MatrixGenerator{
|
||||
got, err := matrixGenerator.GenerateParams(&argoprojiov1alpha1.ApplicationSetGenerator{
|
||||
Matrix: &argoprojiov1alpha1.MatrixGenerator{
|
||||
Generators: testCaseCopy.baseGenerators,
|
||||
Template: v1alpha1.ApplicationSetTemplate{},
|
||||
Template: argoprojiov1alpha1.ApplicationSetTemplate{},
|
||||
},
|
||||
}, appSet, nil)
|
||||
|
||||
@@ -877,28 +877,28 @@ func TestInterpolatedMatrixGenerateGoTemplate(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMatrixGenerateListElementsYaml(t *testing.T) {
|
||||
gitGenerator := &v1alpha1.GitGenerator{
|
||||
gitGenerator := &argoprojiov1alpha1.GitGenerator{
|
||||
RepoURL: "RepoURL",
|
||||
Revision: "Revision",
|
||||
Files: []v1alpha1.GitFileGeneratorItem{
|
||||
Files: []argoprojiov1alpha1.GitFileGeneratorItem{
|
||||
{Path: "config.yaml"},
|
||||
},
|
||||
}
|
||||
|
||||
listGenerator := &v1alpha1.ListGenerator{
|
||||
listGenerator := &argoprojiov1alpha1.ListGenerator{
|
||||
Elements: []apiextensionsv1.JSON{},
|
||||
ElementsYaml: "{{ .foo.bar | toJson }}",
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
baseGenerators []v1alpha1.ApplicationSetNestedGenerator
|
||||
baseGenerators []argoprojiov1alpha1.ApplicationSetNestedGenerator
|
||||
expectedErr error
|
||||
expected []map[string]any
|
||||
expected []map[string]interface{}
|
||||
}{
|
||||
{
|
||||
name: "happy flow - generate params",
|
||||
baseGenerators: []v1alpha1.ApplicationSetNestedGenerator{
|
||||
baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
|
||||
{
|
||||
Git: gitGenerator,
|
||||
},
|
||||
@@ -906,23 +906,23 @@ func TestMatrixGenerateListElementsYaml(t *testing.T) {
|
||||
List: listGenerator,
|
||||
},
|
||||
},
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"chart": "a",
|
||||
"version": "1",
|
||||
"foo": map[string]any{
|
||||
"bar": []any{
|
||||
map[string]any{
|
||||
"foo": map[string]interface{}{
|
||||
"bar": []interface{}{
|
||||
map[string]interface{}{
|
||||
"chart": "a",
|
||||
"version": "1",
|
||||
},
|
||||
map[string]any{
|
||||
map[string]interface{}{
|
||||
"chart": "b",
|
||||
"version": "2",
|
||||
},
|
||||
},
|
||||
},
|
||||
"path": map[string]any{
|
||||
"path": map[string]interface{}{
|
||||
"basename": "dir",
|
||||
"basenameNormalized": "dir",
|
||||
"filename": "file_name.yaml",
|
||||
@@ -937,19 +937,19 @@ func TestMatrixGenerateListElementsYaml(t *testing.T) {
|
||||
{
|
||||
"chart": "b",
|
||||
"version": "2",
|
||||
"foo": map[string]any{
|
||||
"bar": []any{
|
||||
map[string]any{
|
||||
"foo": map[string]interface{}{
|
||||
"bar": []interface{}{
|
||||
map[string]interface{}{
|
||||
"chart": "a",
|
||||
"version": "1",
|
||||
},
|
||||
map[string]any{
|
||||
map[string]interface{}{
|
||||
"chart": "b",
|
||||
"version": "2",
|
||||
},
|
||||
},
|
||||
},
|
||||
"path": map[string]any{
|
||||
"path": map[string]interface{}{
|
||||
"basename": "dir",
|
||||
"basenameNormalized": "dir",
|
||||
"filename": "file_name.yaml",
|
||||
@@ -970,34 +970,34 @@ func TestMatrixGenerateListElementsYaml(t *testing.T) {
|
||||
|
||||
t.Run(testCaseCopy.name, func(t *testing.T) {
|
||||
genMock := &generatorMock{}
|
||||
appSet := &v1alpha1.ApplicationSet{
|
||||
appSet := &argoprojiov1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "set",
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
Spec: argoprojiov1alpha1.ApplicationSetSpec{
|
||||
GoTemplate: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, g := range testCaseCopy.baseGenerators {
|
||||
gitGeneratorSpec := v1alpha1.ApplicationSetGenerator{
|
||||
gitGeneratorSpec := argoprojiov1alpha1.ApplicationSetGenerator{
|
||||
Git: g.Git,
|
||||
List: g.List,
|
||||
}
|
||||
genMock.On("GenerateParams", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), appSet).Return([]map[string]any{{
|
||||
"foo": map[string]any{
|
||||
"bar": []any{
|
||||
map[string]any{
|
||||
"foo": map[string]interface{}{
|
||||
"bar": []interface{}{
|
||||
map[string]interface{}{
|
||||
"chart": "a",
|
||||
"version": "1",
|
||||
},
|
||||
map[string]any{
|
||||
map[string]interface{}{
|
||||
"chart": "b",
|
||||
"version": "2",
|
||||
},
|
||||
},
|
||||
},
|
||||
"path": map[string]any{
|
||||
"path": map[string]interface{}{
|
||||
"basename": "dir",
|
||||
"basenameNormalized": "dir",
|
||||
"filename": "file_name.yaml",
|
||||
@@ -1010,7 +1010,7 @@ func TestMatrixGenerateListElementsYaml(t *testing.T) {
|
||||
},
|
||||
}}, nil)
|
||||
genMock.On("GetTemplate", &gitGeneratorSpec).
|
||||
Return(&v1alpha1.ApplicationSetTemplate{})
|
||||
Return(&argoprojiov1alpha1.ApplicationSetTemplate{})
|
||||
}
|
||||
|
||||
matrixGenerator := NewMatrixGenerator(
|
||||
@@ -1020,10 +1020,10 @@ func TestMatrixGenerateListElementsYaml(t *testing.T) {
|
||||
},
|
||||
)
|
||||
|
||||
got, err := matrixGenerator.GenerateParams(&v1alpha1.ApplicationSetGenerator{
|
||||
Matrix: &v1alpha1.MatrixGenerator{
|
||||
got, err := matrixGenerator.GenerateParams(&argoprojiov1alpha1.ApplicationSetGenerator{
|
||||
Matrix: &argoprojiov1alpha1.MatrixGenerator{
|
||||
Generators: testCaseCopy.baseGenerators,
|
||||
Template: v1alpha1.ApplicationSetTemplate{},
|
||||
Template: argoprojiov1alpha1.ApplicationSetTemplate{},
|
||||
},
|
||||
}, appSet, nil)
|
||||
|
||||
@@ -1041,19 +1041,19 @@ type generatorMock struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
func (g *generatorMock) GetTemplate(appSetGenerator *v1alpha1.ApplicationSetGenerator) *v1alpha1.ApplicationSetTemplate {
|
||||
func (g *generatorMock) GetTemplate(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) *argoprojiov1alpha1.ApplicationSetTemplate {
|
||||
args := g.Called(appSetGenerator)
|
||||
|
||||
return args.Get(0).(*v1alpha1.ApplicationSetTemplate)
|
||||
return args.Get(0).(*argoprojiov1alpha1.ApplicationSetTemplate)
|
||||
}
|
||||
|
||||
func (g *generatorMock) GenerateParams(appSetGenerator *v1alpha1.ApplicationSetGenerator, appSet *v1alpha1.ApplicationSet, _ client.Client) ([]map[string]any, error) {
|
||||
func (g *generatorMock) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, appSet *argoprojiov1alpha1.ApplicationSet, _ client.Client) ([]map[string]interface{}, error) {
|
||||
args := g.Called(appSetGenerator, appSet)
|
||||
|
||||
return args.Get(0).([]map[string]any), args.Error(1)
|
||||
return args.Get(0).([]map[string]interface{}), args.Error(1)
|
||||
}
|
||||
|
||||
func (g *generatorMock) GetRequeueAfter(appSetGenerator *v1alpha1.ApplicationSetGenerator) time.Duration {
|
||||
func (g *generatorMock) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) time.Duration {
|
||||
args := g.Called(appSetGenerator)
|
||||
|
||||
return args.Get(0).(time.Duration)
|
||||
@@ -1073,20 +1073,20 @@ func TestGitGenerator_GenerateParams_list_x_git_matrix_generator(t *testing.T) {
|
||||
// of that bug.
|
||||
|
||||
listGeneratorMock := &generatorMock{}
|
||||
listGeneratorMock.On("GenerateParams", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), mock.AnythingOfType("*v1alpha1.ApplicationSet"), mock.Anything).Return([]map[string]any{
|
||||
listGeneratorMock.On("GenerateParams", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), mock.AnythingOfType("*v1alpha1.ApplicationSet"), mock.Anything).Return([]map[string]interface{}{
|
||||
{"some": "value"},
|
||||
}, nil)
|
||||
listGeneratorMock.On("GetTemplate", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator")).Return(&v1alpha1.ApplicationSetTemplate{})
|
||||
listGeneratorMock.On("GetTemplate", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator")).Return(&argoprojiov1alpha1.ApplicationSetTemplate{})
|
||||
|
||||
gitGeneratorSpec := &v1alpha1.GitGenerator{
|
||||
gitGeneratorSpec := &argoprojiov1alpha1.GitGenerator{
|
||||
RepoURL: "https://git.example.com",
|
||||
Files: []v1alpha1.GitFileGeneratorItem{
|
||||
Files: []argoprojiov1alpha1.GitFileGeneratorItem{
|
||||
{Path: "some/path.json"},
|
||||
},
|
||||
}
|
||||
|
||||
repoServiceMock := &mocks.Repos{}
|
||||
repoServiceMock.On("GetFiles", mock.Anything, 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).Return(map[string][]byte{
|
||||
"some/path.json": []byte("test: content"),
|
||||
}, nil)
|
||||
gitGenerator := NewGitGenerator(repoServiceMock, "")
|
||||
@@ -1096,10 +1096,10 @@ func TestGitGenerator_GenerateParams_list_x_git_matrix_generator(t *testing.T) {
|
||||
"Git": gitGenerator,
|
||||
})
|
||||
|
||||
matrixGeneratorSpec := &v1alpha1.MatrixGenerator{
|
||||
Generators: []v1alpha1.ApplicationSetNestedGenerator{
|
||||
matrixGeneratorSpec := &argoprojiov1alpha1.MatrixGenerator{
|
||||
Generators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{
|
||||
{
|
||||
List: &v1alpha1.ListGenerator{
|
||||
List: &argoprojiov1alpha1.ListGenerator{
|
||||
Elements: []apiextensionsv1.JSON{
|
||||
{
|
||||
Raw: []byte(`{"some": "value"}`),
|
||||
@@ -1116,15 +1116,15 @@ func TestGitGenerator_GenerateParams_list_x_git_matrix_generator(t *testing.T) {
|
||||
scheme := runtime.NewScheme()
|
||||
err := v1alpha1.AddToScheme(scheme)
|
||||
require.NoError(t, err)
|
||||
appProject := v1alpha1.AppProject{}
|
||||
appProject := argoprojiov1alpha1.AppProject{}
|
||||
|
||||
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appProject).Build()
|
||||
|
||||
params, err := matrixGenerator.GenerateParams(&v1alpha1.ApplicationSetGenerator{
|
||||
params, err := matrixGenerator.GenerateParams(&argoprojiov1alpha1.ApplicationSetGenerator{
|
||||
Matrix: matrixGeneratorSpec,
|
||||
}, &v1alpha1.ApplicationSet{}, client)
|
||||
}, &argoprojiov1alpha1.ApplicationSet{}, client)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []map[string]any{{
|
||||
assert.Equal(t, []map[string]interface{}{{
|
||||
"path": "some",
|
||||
"path.basename": "some",
|
||||
"path.basenameNormalized": "some",
|
||||
|
||||
@@ -2,23 +2,24 @@ package generators
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"dario.cat/mergo"
|
||||
"github.com/imdario/mergo"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/utils"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/utils"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var _ Generator = (*MergeGenerator)(nil)
|
||||
|
||||
var (
|
||||
ErrLessThanTwoGeneratorsInMerge = errors.New("found less than two generators, Merge requires two or more")
|
||||
ErrNoMergeKeys = errors.New("no merge keys were specified, Merge requires at least one")
|
||||
ErrNonUniqueParamSets = errors.New("the parameters from a generator were not unique by the given mergeKeys, Merge requires all param sets to be unique")
|
||||
ErrLessThanTwoGeneratorsInMerge = fmt.Errorf("found less than two generators, Merge requires two or more")
|
||||
ErrNoMergeKeys = fmt.Errorf("no merge keys were specified, Merge requires at least one")
|
||||
ErrNonUniqueParamSets = fmt.Errorf("the parameters from a generator were not unique by the given mergeKeys, Merge requires all param sets to be unique")
|
||||
)
|
||||
|
||||
type MergeGenerator struct {
|
||||
@@ -36,8 +37,8 @@ func NewMergeGenerator(supportedGenerators map[string]Generator) Generator {
|
||||
|
||||
// getParamSetsForAllGenerators generates params for each child generator in a MergeGenerator. Param sets are returned
|
||||
// in slices ordered according to the order of the given generators.
|
||||
func (m *MergeGenerator) getParamSetsForAllGenerators(generators []argoprojiov1alpha1.ApplicationSetNestedGenerator, appSet *argoprojiov1alpha1.ApplicationSet, client client.Client) ([][]map[string]any, error) {
|
||||
var paramSets [][]map[string]any
|
||||
func (m *MergeGenerator) getParamSetsForAllGenerators(generators []argoprojiov1alpha1.ApplicationSetNestedGenerator, appSet *argoprojiov1alpha1.ApplicationSet, client client.Client) ([][]map[string]interface{}, error) {
|
||||
var paramSets [][]map[string]interface{}
|
||||
for i, generator := range generators {
|
||||
generatorParamSets, err := m.getParams(generator, appSet, client)
|
||||
if err != nil {
|
||||
@@ -50,7 +51,7 @@ func (m *MergeGenerator) getParamSetsForAllGenerators(generators []argoprojiov1a
|
||||
}
|
||||
|
||||
// GenerateParams gets the params produced by the MergeGenerator.
|
||||
func (m *MergeGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, appSet *argoprojiov1alpha1.ApplicationSet, client client.Client) ([]map[string]any, error) {
|
||||
func (m *MergeGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, appSet *argoprojiov1alpha1.ApplicationSet, client client.Client) ([]map[string]interface{}, error) {
|
||||
if appSetGenerator.Merge == nil {
|
||||
return nil, EmptyAppSetGeneratorError
|
||||
}
|
||||
@@ -93,11 +94,11 @@ func (m *MergeGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.Appl
|
||||
}
|
||||
}
|
||||
|
||||
mergedParamSets := make([]map[string]any, len(baseParamSetsByMergeKey))
|
||||
mergedParamSets := make([]map[string]interface{}, len(baseParamSetsByMergeKey))
|
||||
i := 0
|
||||
for _, mergedParamSet := range baseParamSetsByMergeKey {
|
||||
mergedParamSets[i] = mergedParamSet
|
||||
i++
|
||||
i += 1
|
||||
}
|
||||
|
||||
return mergedParamSets, nil
|
||||
@@ -106,7 +107,7 @@ func (m *MergeGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.Appl
|
||||
// getParamSetsByMergeKey converts the given list of parameter sets to a map of parameter sets where the key is the
|
||||
// unique key of the parameter set as determined by the given mergeKeys. If any two parameter sets share the same merge
|
||||
// key, getParamSetsByMergeKey will throw NonUniqueParamSets.
|
||||
func getParamSetsByMergeKey(mergeKeys []string, paramSets []map[string]any) (map[string]map[string]any, error) {
|
||||
func getParamSetsByMergeKey(mergeKeys []string, paramSets []map[string]interface{}) (map[string]map[string]interface{}, error) {
|
||||
if len(mergeKeys) < 1 {
|
||||
return nil, ErrNoMergeKeys
|
||||
}
|
||||
@@ -116,17 +117,17 @@ func getParamSetsByMergeKey(mergeKeys []string, paramSets []map[string]any) (map
|
||||
deDuplicatedMergeKeys[mergeKey] = false
|
||||
}
|
||||
|
||||
paramSetsByMergeKey := make(map[string]map[string]any, len(paramSets))
|
||||
paramSetsByMergeKey := make(map[string]map[string]interface{}, len(paramSets))
|
||||
for _, paramSet := range paramSets {
|
||||
paramSetKey := make(map[string]any)
|
||||
paramSetKey := make(map[string]interface{})
|
||||
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)
|
||||
}
|
||||
@@ -137,15 +138,27 @@ func getParamSetsByMergeKey(mergeKeys []string, paramSets []map[string]any) (map
|
||||
}
|
||||
|
||||
// getParams get the parameters generated by this generator.
|
||||
func (m *MergeGenerator) getParams(appSetBaseGenerator argoprojiov1alpha1.ApplicationSetNestedGenerator, appSet *argoprojiov1alpha1.ApplicationSet, client client.Client) ([]map[string]any, error) {
|
||||
func (m *MergeGenerator) getParams(appSetBaseGenerator argoprojiov1alpha1.ApplicationSetNestedGenerator, appSet *argoprojiov1alpha1.ApplicationSet, client client.Client) ([]map[string]interface{}, error) {
|
||||
matrixGen, err := getMatrixGenerator(appSetBaseGenerator)
|
||||
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{
|
||||
@@ -163,13 +176,13 @@ func (m *MergeGenerator) getParams(appSetBaseGenerator argoprojiov1alpha1.Applic
|
||||
m.supportedGenerators,
|
||||
argoprojiov1alpha1.ApplicationSetTemplate{},
|
||||
appSet,
|
||||
map[string]any{}, client)
|
||||
map[string]interface{}{}, client)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("child generator returned an error on parameter generation: %w", err)
|
||||
}
|
||||
|
||||
if len(t) == 0 {
|
||||
return nil, errors.New("child generator generated no parameters")
|
||||
return nil, fmt.Errorf("child generator generated no parameters")
|
||||
}
|
||||
|
||||
if len(t) > 1 {
|
||||
@@ -210,8 +223,9 @@ func (m *MergeGenerator) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.App
|
||||
|
||||
if found {
|
||||
return res
|
||||
} else {
|
||||
return NoRequeueAfter
|
||||
}
|
||||
return NoRequeueAfter
|
||||
}
|
||||
|
||||
func getMergeGenerator(r argoprojiov1alpha1.ApplicationSetNestedGenerator) (*argoprojiov1alpha1.MergeGenerator, error) {
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
func getNestedListGenerator(json string) *argoprojiov1alpha1.ApplicationSetNestedGenerator {
|
||||
@@ -36,15 +36,15 @@ func getTerminalListGeneratorMultiple(jsons []string) argoprojiov1alpha1.Applica
|
||||
return generator
|
||||
}
|
||||
|
||||
func listOfMapsToSet(maps []map[string]any) (map[string]bool, error) {
|
||||
func listOfMapsToSet(maps []map[string]interface{}) (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
|
||||
}
|
||||
@@ -55,7 +55,7 @@ func TestMergeGenerate(t *testing.T) {
|
||||
baseGenerators []argoprojiov1alpha1.ApplicationSetNestedGenerator
|
||||
mergeKeys []string
|
||||
expectedErr error
|
||||
expected []map[string]any
|
||||
expected []map[string]interface{}
|
||||
}{
|
||||
{
|
||||
name: "no generators",
|
||||
@@ -79,7 +79,7 @@ func TestMergeGenerate(t *testing.T) {
|
||||
*getNestedListGenerator(`{"a": "3_1","b": "different","c": "3_3"}`), // gets ignored because its merge key value isn't in the base params set
|
||||
},
|
||||
mergeKeys: []string{"b"},
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{"a": "2_1", "b": "same", "c": "1_3"},
|
||||
},
|
||||
},
|
||||
@@ -90,7 +90,7 @@ func TestMergeGenerate(t *testing.T) {
|
||||
*getNestedListGenerator(`{"a": "a"}`),
|
||||
},
|
||||
mergeKeys: []string{"b"},
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{"a": "a"},
|
||||
},
|
||||
},
|
||||
@@ -101,7 +101,7 @@ func TestMergeGenerate(t *testing.T) {
|
||||
*getNestedListGenerator(`{"b": "b"}`),
|
||||
},
|
||||
mergeKeys: []string{"b"},
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{"a": "a"},
|
||||
},
|
||||
},
|
||||
@@ -119,7 +119,7 @@ func TestMergeGenerate(t *testing.T) {
|
||||
*getNestedListGenerator(`{"a": "1", "b": "1", "c": "added"}`),
|
||||
},
|
||||
mergeKeys: []string{"a", "b"},
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{"a": "1", "b": "1", "c": "added"},
|
||||
{"a": "1", "b": "2"},
|
||||
{"a": "2", "b": "1"},
|
||||
@@ -141,7 +141,7 @@ func TestMergeGenerate(t *testing.T) {
|
||||
*getNestedListGenerator(`{"a": "1", "b": "3", "d": "added"}`),
|
||||
},
|
||||
mergeKeys: []string{"a", "b"},
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{"a": "1", "b": "3", "c": "added", "d": "added"},
|
||||
{"a": "2", "b": "2"},
|
||||
},
|
||||
@@ -196,8 +196,7 @@ func TestMergeGenerate(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func toAPIExtensionsJSON(t *testing.T, g any) *apiextensionsv1.JSON {
|
||||
t.Helper()
|
||||
func toAPIExtensionsJSON(t *testing.T, g interface{}) *apiextensionsv1.JSON {
|
||||
resVal, err := json.Marshal(g)
|
||||
if err != nil {
|
||||
t.Error("unable to unmarshal json", g)
|
||||
@@ -213,9 +212,9 @@ func TestParamSetsAreUniqueByMergeKeys(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
mergeKeys []string
|
||||
paramSets []map[string]any
|
||||
paramSets []map[string]interface{}
|
||||
expectedErr error
|
||||
expected map[string]map[string]any
|
||||
expected map[string]map[string]interface{}
|
||||
}{
|
||||
{
|
||||
name: "no merge keys",
|
||||
@@ -225,13 +224,13 @@ func TestParamSetsAreUniqueByMergeKeys(t *testing.T) {
|
||||
{
|
||||
name: "no paramSets",
|
||||
mergeKeys: []string{"key"},
|
||||
expected: make(map[string]map[string]any),
|
||||
expected: make(map[string]map[string]interface{}),
|
||||
},
|
||||
{
|
||||
name: "simple key, unique paramSets",
|
||||
mergeKeys: []string{"key"},
|
||||
paramSets: []map[string]any{{"key": "a"}, {"key": "b"}},
|
||||
expected: map[string]map[string]any{
|
||||
paramSets: []map[string]interface{}{{"key": "a"}, {"key": "b"}},
|
||||
expected: map[string]map[string]interface{}{
|
||||
`{"key":"a"}`: {"key": "a"},
|
||||
`{"key":"b"}`: {"key": "b"},
|
||||
},
|
||||
@@ -239,23 +238,23 @@ func TestParamSetsAreUniqueByMergeKeys(t *testing.T) {
|
||||
{
|
||||
name: "simple key object, unique paramSets",
|
||||
mergeKeys: []string{"key"},
|
||||
paramSets: []map[string]any{{"key": map[string]any{"hello": "world"}}, {"key": "b"}},
|
||||
expected: map[string]map[string]any{
|
||||
`{"key":{"hello":"world"}}`: {"key": map[string]any{"hello": "world"}},
|
||||
paramSets: []map[string]interface{}{{"key": map[string]interface{}{"hello": "world"}}, {"key": "b"}},
|
||||
expected: map[string]map[string]interface{}{
|
||||
`{"key":{"hello":"world"}}`: {"key": map[string]interface{}{"hello": "world"}},
|
||||
`{"key":"b"}`: {"key": "b"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "simple key, non-unique paramSets",
|
||||
mergeKeys: []string{"key"},
|
||||
paramSets: []map[string]any{{"key": "a"}, {"key": "b"}, {"key": "b"}},
|
||||
paramSets: []map[string]interface{}{{"key": "a"}, {"key": "b"}, {"key": "b"}},
|
||||
expectedErr: fmt.Errorf("%w. Duplicate key was %s", ErrNonUniqueParamSets, `{"key":"b"}`),
|
||||
},
|
||||
{
|
||||
name: "simple key, duplicated key name, unique paramSets",
|
||||
mergeKeys: []string{"key", "key"},
|
||||
paramSets: []map[string]any{{"key": "a"}, {"key": "b"}},
|
||||
expected: map[string]map[string]any{
|
||||
paramSets: []map[string]interface{}{{"key": "a"}, {"key": "b"}},
|
||||
expected: map[string]map[string]interface{}{
|
||||
`{"key":"a"}`: {"key": "a"},
|
||||
`{"key":"b"}`: {"key": "b"},
|
||||
},
|
||||
@@ -263,18 +262,18 @@ func TestParamSetsAreUniqueByMergeKeys(t *testing.T) {
|
||||
{
|
||||
name: "simple key, duplicated key name, non-unique paramSets",
|
||||
mergeKeys: []string{"key", "key"},
|
||||
paramSets: []map[string]any{{"key": "a"}, {"key": "b"}, {"key": "b"}},
|
||||
paramSets: []map[string]interface{}{{"key": "a"}, {"key": "b"}, {"key": "b"}},
|
||||
expectedErr: fmt.Errorf("%w. Duplicate key was %s", ErrNonUniqueParamSets, `{"key":"b"}`),
|
||||
},
|
||||
{
|
||||
name: "compound key, unique paramSets",
|
||||
mergeKeys: []string{"key1", "key2"},
|
||||
paramSets: []map[string]any{
|
||||
paramSets: []map[string]interface{}{
|
||||
{"key1": "a", "key2": "a"},
|
||||
{"key1": "a", "key2": "b"},
|
||||
{"key1": "b", "key2": "a"},
|
||||
},
|
||||
expected: map[string]map[string]any{
|
||||
expected: map[string]map[string]interface{}{
|
||||
`{"key1":"a","key2":"a"}`: {"key1": "a", "key2": "a"},
|
||||
`{"key1":"a","key2":"b"}`: {"key1": "a", "key2": "b"},
|
||||
`{"key1":"b","key2":"a"}`: {"key1": "b", "key2": "a"},
|
||||
@@ -283,13 +282,13 @@ func TestParamSetsAreUniqueByMergeKeys(t *testing.T) {
|
||||
{
|
||||
name: "compound key object, unique paramSets",
|
||||
mergeKeys: []string{"key1", "key2"},
|
||||
paramSets: []map[string]any{
|
||||
{"key1": "a", "key2": map[string]any{"hello": "world"}},
|
||||
paramSets: []map[string]interface{}{
|
||||
{"key1": "a", "key2": map[string]interface{}{"hello": "world"}},
|
||||
{"key1": "a", "key2": "b"},
|
||||
{"key1": "b", "key2": "a"},
|
||||
},
|
||||
expected: map[string]map[string]any{
|
||||
`{"key1":"a","key2":{"hello":"world"}}`: {"key1": "a", "key2": map[string]any{"hello": "world"}},
|
||||
expected: map[string]map[string]interface{}{
|
||||
`{"key1":"a","key2":{"hello":"world"}}`: {"key1": "a", "key2": map[string]interface{}{"hello": "world"}},
|
||||
`{"key1":"a","key2":"b"}`: {"key1": "a", "key2": "b"},
|
||||
`{"key1":"b","key2":"a"}`: {"key1": "b", "key2": "a"},
|
||||
},
|
||||
@@ -297,12 +296,12 @@ func TestParamSetsAreUniqueByMergeKeys(t *testing.T) {
|
||||
{
|
||||
name: "compound key, duplicate key names, unique paramSets",
|
||||
mergeKeys: []string{"key1", "key1", "key2"},
|
||||
paramSets: []map[string]any{
|
||||
paramSets: []map[string]interface{}{
|
||||
{"key1": "a", "key2": "a"},
|
||||
{"key1": "a", "key2": "b"},
|
||||
{"key1": "b", "key2": "a"},
|
||||
},
|
||||
expected: map[string]map[string]any{
|
||||
expected: map[string]map[string]interface{}{
|
||||
`{"key1":"a","key2":"a"}`: {"key1": "a", "key2": "a"},
|
||||
`{"key1":"a","key2":"b"}`: {"key1": "a", "key2": "b"},
|
||||
`{"key1":"b","key2":"a"}`: {"key1": "b", "key2": "a"},
|
||||
@@ -311,7 +310,7 @@ func TestParamSetsAreUniqueByMergeKeys(t *testing.T) {
|
||||
{
|
||||
name: "compound key, non-unique paramSets",
|
||||
mergeKeys: []string{"key1", "key2"},
|
||||
paramSets: []map[string]any{
|
||||
paramSets: []map[string]interface{}{
|
||||
{"key1": "a", "key2": "a"},
|
||||
{"key1": "a", "key2": "a"},
|
||||
{"key1": "b", "key2": "a"},
|
||||
@@ -321,7 +320,7 @@ func TestParamSetsAreUniqueByMergeKeys(t *testing.T) {
|
||||
{
|
||||
name: "compound key, duplicate key names, non-unique paramSets",
|
||||
mergeKeys: []string{"key1", "key1", "key2"},
|
||||
paramSets: []map[string]any{
|
||||
paramSets: []map[string]interface{}{
|
||||
{"key1": "a", "key2": "a"},
|
||||
{"key1": "a", "key2": "a"},
|
||||
{"key1": "b", "key2": "a"},
|
||||
|
||||
4
applicationset/generators/mocks/Generator.go
generated
4
applicationset/generators/mocks/Generator.go
generated
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.52.4. DO NOT EDIT.
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
time "time"
|
||||
|
||||
v1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
v1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
// Generator is an autogenerated mock type for the Generator type
|
||||
|
||||
@@ -2,7 +2,6 @@ package generators
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -13,10 +12,10 @@ import (
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v3/util/settings"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/util/settings"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/services/plugin"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/services/plugin"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -32,7 +31,7 @@ type PluginGenerator struct {
|
||||
namespace string
|
||||
}
|
||||
|
||||
func NewPluginGenerator(ctx context.Context, client client.Client, clientset kubernetes.Interface, namespace string) Generator {
|
||||
func NewPluginGenerator(client client.Client, ctx context.Context, clientset kubernetes.Interface, namespace string) Generator {
|
||||
g := &PluginGenerator{
|
||||
client: client,
|
||||
ctx: ctx,
|
||||
@@ -56,7 +55,7 @@ func (g *PluginGenerator) GetTemplate(appSetGenerator *argoprojiov1alpha1.Applic
|
||||
return &appSetGenerator.Plugin.Template
|
||||
}
|
||||
|
||||
func (g *PluginGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, applicationSetInfo *argoprojiov1alpha1.ApplicationSet, _ client.Client) ([]map[string]any, error) {
|
||||
func (g *PluginGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, applicationSetInfo *argoprojiov1alpha1.ApplicationSet, _ client.Client) ([]map[string]interface{}, error) {
|
||||
if appSetGenerator == nil {
|
||||
return nil, EmptyAppSetGeneratorError
|
||||
}
|
||||
@@ -106,18 +105,18 @@ func (g *PluginGenerator) getPluginFromGenerator(ctx context.Context, appSetName
|
||||
}
|
||||
}
|
||||
|
||||
pluginClient, err := plugin.NewPluginService(appSetName, cm["baseUrl"], token, requestTimeout)
|
||||
pluginClient, err := plugin.NewPluginService(ctx, appSetName, cm["baseUrl"], token, requestTimeout)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error initializing plugin client: %w", err)
|
||||
}
|
||||
return pluginClient, nil
|
||||
}
|
||||
|
||||
func (g *PluginGenerator) generateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, appSet *argoprojiov1alpha1.ApplicationSet, objectsFound []map[string]any, pluginParams argoprojiov1alpha1.PluginParameters, useGoTemplate bool) ([]map[string]any, error) {
|
||||
res := []map[string]any{}
|
||||
func (g *PluginGenerator) generateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, appSet *argoprojiov1alpha1.ApplicationSet, objectsFound []map[string]interface{}, pluginParams argoprojiov1alpha1.PluginParameters, useGoTemplate bool) ([]map[string]interface{}, error) {
|
||||
res := []map[string]interface{}{}
|
||||
|
||||
for _, objectFound := range objectsFound {
|
||||
params := map[string]any{}
|
||||
params := map[string]interface{}{}
|
||||
|
||||
if useGoTemplate {
|
||||
for k, v := range objectFound {
|
||||
@@ -133,7 +132,7 @@ func (g *PluginGenerator) generateParams(appSetGenerator *argoprojiov1alpha1.App
|
||||
}
|
||||
}
|
||||
|
||||
params["generator"] = map[string]any{
|
||||
params["generator"] = map[string]interface{}{
|
||||
"input": map[string]argoprojiov1alpha1.PluginParameters{
|
||||
"parameters": pluginParams,
|
||||
},
|
||||
@@ -193,14 +192,14 @@ func (g *PluginGenerator) getConfigMap(ctx context.Context, configMapRef string)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
baseURL, ok := cm.Data["baseUrl"]
|
||||
if !ok || baseURL == "" {
|
||||
return nil, errors.New("baseUrl not found in ConfigMap")
|
||||
baseUrl, ok := cm.Data["baseUrl"]
|
||||
if !ok || baseUrl == "" {
|
||||
return nil, fmt.Errorf("baseUrl not found in ConfigMap")
|
||||
}
|
||||
|
||||
token, ok := cm.Data["token"]
|
||||
if !ok || token == "" {
|
||||
return nil, errors.New("token not found in ConfigMap")
|
||||
return nil, fmt.Errorf("token not found in ConfigMap")
|
||||
}
|
||||
|
||||
return cm.Data, nil
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package generators
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
@@ -19,25 +19,25 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/services/plugin"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/services/plugin"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
func TestPluginGenerateParams(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
configmap *corev1.ConfigMap
|
||||
secret *corev1.Secret
|
||||
configmap *v1.ConfigMap
|
||||
secret *v1.Secret
|
||||
inputParameters map[string]apiextensionsv1.JSON
|
||||
values map[string]string
|
||||
gotemplate bool
|
||||
expected []map[string]any
|
||||
expected []map[string]interface{}
|
||||
content []byte
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "simple case",
|
||||
configmap: &corev1.ConfigMap{
|
||||
configmap: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "first-plugin-cm",
|
||||
Namespace: "default",
|
||||
@@ -47,7 +47,7 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
"token": "$plugin.token",
|
||||
},
|
||||
},
|
||||
secret: &corev1.Secret{
|
||||
secret: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "argocd-secret",
|
||||
Namespace: "default",
|
||||
@@ -73,13 +73,13 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
"key3": 123
|
||||
}]
|
||||
}}`),
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"key1": "val1",
|
||||
"key2.key2_1": "val2_1",
|
||||
"key2.key2_2.key2_2_1": "val2_2_1",
|
||||
"key3": "123",
|
||||
"generator": map[string]any{
|
||||
"generator": map[string]interface{}{
|
||||
"input": argoprojiov1alpha1.PluginInput{
|
||||
Parameters: argoprojiov1alpha1.PluginParameters{
|
||||
"pkey1": {Raw: []byte(`"val1"`)},
|
||||
@@ -93,7 +93,7 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "simple case with values",
|
||||
configmap: &corev1.ConfigMap{
|
||||
configmap: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "first-plugin-cm",
|
||||
Namespace: "default",
|
||||
@@ -103,7 +103,7 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
"token": "$plugin.token",
|
||||
},
|
||||
},
|
||||
secret: &corev1.Secret{
|
||||
secret: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "argocd-secret",
|
||||
Namespace: "default",
|
||||
@@ -133,7 +133,7 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
"key3": 123
|
||||
}]
|
||||
}}`),
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"key1": "val1",
|
||||
"key2.key2_1": "val2_1",
|
||||
@@ -141,7 +141,7 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
"key3": "123",
|
||||
"values.valuekey1": "valuevalue1",
|
||||
"values.valuekey2": "templated-val1",
|
||||
"generator": map[string]any{
|
||||
"generator": map[string]interface{}{
|
||||
"input": argoprojiov1alpha1.PluginInput{
|
||||
Parameters: argoprojiov1alpha1.PluginParameters{
|
||||
"pkey1": {Raw: []byte(`"val1"`)},
|
||||
@@ -155,7 +155,7 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "simple case with gotemplate",
|
||||
configmap: &corev1.ConfigMap{
|
||||
configmap: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "first-plugin-cm",
|
||||
Namespace: "default",
|
||||
@@ -165,7 +165,7 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
"token": "$plugin.token",
|
||||
},
|
||||
},
|
||||
secret: &corev1.Secret{
|
||||
secret: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "argocd-secret",
|
||||
Namespace: "default",
|
||||
@@ -191,17 +191,17 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
"key3": 123
|
||||
}]
|
||||
}}`),
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"key1": "val1",
|
||||
"key2": map[string]any{
|
||||
"key2": map[string]interface{}{
|
||||
"key2_1": "val2_1",
|
||||
"key2_2": map[string]any{
|
||||
"key2_2": map[string]interface{}{
|
||||
"key2_2_1": "val2_2_1",
|
||||
},
|
||||
},
|
||||
"key3": float64(123),
|
||||
"generator": map[string]any{
|
||||
"generator": map[string]interface{}{
|
||||
"input": argoprojiov1alpha1.PluginInput{
|
||||
Parameters: argoprojiov1alpha1.PluginParameters{
|
||||
"pkey1": {Raw: []byte(`"val1"`)},
|
||||
@@ -215,7 +215,7 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "simple case with appended params",
|
||||
configmap: &corev1.ConfigMap{
|
||||
configmap: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "first-plugin-cm",
|
||||
Namespace: "default",
|
||||
@@ -225,7 +225,7 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
"token": "$plugin.token",
|
||||
},
|
||||
},
|
||||
secret: &corev1.Secret{
|
||||
secret: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "argocd-secret",
|
||||
Namespace: "default",
|
||||
@@ -250,14 +250,14 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
"key3": 123,
|
||||
"pkey2": "valplugin"
|
||||
}]}}`),
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"key1": "val1",
|
||||
"key2.key2_1": "val2_1",
|
||||
"key2.key2_2.key2_2_1": "val2_2_1",
|
||||
"key3": "123",
|
||||
"pkey2": "valplugin",
|
||||
"generator": map[string]any{
|
||||
"generator": map[string]interface{}{
|
||||
"input": argoprojiov1alpha1.PluginInput{
|
||||
Parameters: argoprojiov1alpha1.PluginParameters{
|
||||
"pkey1": {Raw: []byte(`"val1"`)},
|
||||
@@ -271,7 +271,7 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "no params",
|
||||
configmap: &corev1.ConfigMap{
|
||||
configmap: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "first-plugin-cm",
|
||||
Namespace: "default",
|
||||
@@ -281,7 +281,7 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
"token": "$plugin.token",
|
||||
},
|
||||
},
|
||||
secret: &corev1.Secret{
|
||||
secret: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "argocd-secret",
|
||||
Namespace: "default",
|
||||
@@ -304,14 +304,14 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
"key3": 123
|
||||
}]
|
||||
}}`),
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"key1": "val1",
|
||||
"key2.key2_1": "val2_1",
|
||||
"key2.key2_2.key2_2_1": "val2_2_1",
|
||||
"key3": "123",
|
||||
"generator": map[string]any{
|
||||
"input": map[string]map[string]any{
|
||||
"generator": map[string]interface{}{
|
||||
"input": map[string]map[string]interface{}{
|
||||
"parameters": {},
|
||||
},
|
||||
},
|
||||
@@ -321,7 +321,7 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "empty return",
|
||||
configmap: &corev1.ConfigMap{
|
||||
configmap: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "first-plugin-cm",
|
||||
Namespace: "default",
|
||||
@@ -331,7 +331,7 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
"token": "$plugin.token",
|
||||
},
|
||||
},
|
||||
secret: &corev1.Secret{
|
||||
secret: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "argocd-secret",
|
||||
Namespace: "default",
|
||||
@@ -343,12 +343,12 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
inputParameters: map[string]apiextensionsv1.JSON{},
|
||||
gotemplate: false,
|
||||
content: []byte(`{"input": {"parameters": []}}`),
|
||||
expected: []map[string]any{},
|
||||
expected: []map[string]interface{}{},
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "wrong return",
|
||||
configmap: &corev1.ConfigMap{
|
||||
configmap: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "first-plugin-cm",
|
||||
Namespace: "default",
|
||||
@@ -358,7 +358,7 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
"token": "$plugin.token",
|
||||
},
|
||||
},
|
||||
secret: &corev1.Secret{
|
||||
secret: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "argocd-secret",
|
||||
Namespace: "default",
|
||||
@@ -370,12 +370,12 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
inputParameters: map[string]apiextensionsv1.JSON{},
|
||||
gotemplate: false,
|
||||
content: []byte(`wrong body ...`),
|
||||
expected: []map[string]any{},
|
||||
expectedError: errors.New("error listing params: error get api 'set': invalid character 'w' looking for beginning of value: wrong body ..."),
|
||||
expected: []map[string]interface{}{},
|
||||
expectedError: fmt.Errorf("error listing params: error get api 'set': invalid character 'w' looking for beginning of value: wrong body ..."),
|
||||
},
|
||||
{
|
||||
name: "external secret",
|
||||
configmap: &corev1.ConfigMap{
|
||||
configmap: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "first-plugin-cm",
|
||||
Namespace: "default",
|
||||
@@ -385,7 +385,7 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
"token": "$plugin-secret:plugin.token",
|
||||
},
|
||||
},
|
||||
secret: &corev1.Secret{
|
||||
secret: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "plugin-secret",
|
||||
Namespace: "default",
|
||||
@@ -410,14 +410,14 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
"key3": 123,
|
||||
"pkey2": "valplugin"
|
||||
}]}}`),
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"key1": "val1",
|
||||
"key2.key2_1": "val2_1",
|
||||
"key2.key2_2.key2_2_1": "val2_2_1",
|
||||
"key3": "123",
|
||||
"pkey2": "valplugin",
|
||||
"generator": map[string]any{
|
||||
"generator": map[string]interface{}{
|
||||
"input": argoprojiov1alpha1.PluginInput{
|
||||
Parameters: argoprojiov1alpha1.PluginParameters{
|
||||
"pkey1": {Raw: []byte(`"val1"`)},
|
||||
@@ -431,7 +431,7 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "no secret",
|
||||
configmap: &corev1.ConfigMap{
|
||||
configmap: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "first-plugin-cm",
|
||||
Namespace: "default",
|
||||
@@ -441,7 +441,7 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
"token": "$plugin.token",
|
||||
},
|
||||
},
|
||||
secret: &corev1.Secret{},
|
||||
secret: &v1.Secret{},
|
||||
inputParameters: map[string]apiextensionsv1.JSON{
|
||||
"pkey1": {Raw: []byte(`"val1"`)},
|
||||
"pkey2": {Raw: []byte(`"val2"`)},
|
||||
@@ -459,13 +459,13 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
"key3": 123
|
||||
}]
|
||||
}}`),
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"key1": "val1",
|
||||
"key2.key2_1": "val2_1",
|
||||
"key2.key2_2.key2_2_1": "val2_2_1",
|
||||
"key3": "123",
|
||||
"generator": map[string]any{
|
||||
"generator": map[string]interface{}{
|
||||
"input": argoprojiov1alpha1.PluginInput{
|
||||
Parameters: argoprojiov1alpha1.PluginParameters{
|
||||
"pkey1": {Raw: []byte(`"val1"`)},
|
||||
@@ -475,12 +475,12 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: errors.New("error getting plugin from generator: error fetching Secret token: error fetching secret default/argocd-secret: secrets \"argocd-secret\" not found"),
|
||||
expectedError: fmt.Errorf("error getting plugin from generator: error fetching Secret token: error fetching secret default/argocd-secret: secrets \"argocd-secret\" not found"),
|
||||
},
|
||||
{
|
||||
name: "no configmap",
|
||||
configmap: &corev1.ConfigMap{},
|
||||
secret: &corev1.Secret{
|
||||
configmap: &v1.ConfigMap{},
|
||||
secret: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "argocd-secret",
|
||||
Namespace: "default",
|
||||
@@ -506,13 +506,13 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
"key3": 123
|
||||
}]
|
||||
}}`),
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"key1": "val1",
|
||||
"key2.key2_1": "val2_1",
|
||||
"key2.key2_2.key2_2_1": "val2_2_1",
|
||||
"key3": "123",
|
||||
"generator": map[string]any{
|
||||
"generator": map[string]interface{}{
|
||||
"input": argoprojiov1alpha1.PluginInput{
|
||||
Parameters: argoprojiov1alpha1.PluginParameters{
|
||||
"pkey1": {Raw: []byte(`"val1"`)},
|
||||
@@ -522,11 +522,11 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: errors.New("error getting plugin from generator: error fetching ConfigMap: configmaps \"\" not found"),
|
||||
expectedError: fmt.Errorf("error getting plugin from generator: error fetching ConfigMap: configmaps \"\" not found"),
|
||||
},
|
||||
{
|
||||
name: "no baseUrl",
|
||||
configmap: &corev1.ConfigMap{
|
||||
configmap: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "first-plugin-cm",
|
||||
Namespace: "default",
|
||||
@@ -535,7 +535,7 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
"token": "$plugin.token",
|
||||
},
|
||||
},
|
||||
secret: &corev1.Secret{
|
||||
secret: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "argocd-secret",
|
||||
Namespace: "default",
|
||||
@@ -561,13 +561,13 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
"key3": 123
|
||||
}]
|
||||
}}`),
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"key1": "val1",
|
||||
"key2.key2_1": "val2_1",
|
||||
"key2.key2_2.key2_2_1": "val2_2_1",
|
||||
"key3": "123",
|
||||
"generator": map[string]any{
|
||||
"generator": map[string]interface{}{
|
||||
"input": argoprojiov1alpha1.PluginInput{
|
||||
Parameters: argoprojiov1alpha1.PluginParameters{
|
||||
"pkey1": {Raw: []byte(`"val1"`)},
|
||||
@@ -577,11 +577,11 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: errors.New("error getting plugin from generator: error fetching ConfigMap: baseUrl not found in ConfigMap"),
|
||||
expectedError: fmt.Errorf("error getting plugin from generator: error fetching ConfigMap: baseUrl not found in ConfigMap"),
|
||||
},
|
||||
{
|
||||
name: "no token",
|
||||
configmap: &corev1.ConfigMap{
|
||||
configmap: &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "first-plugin-cm",
|
||||
Namespace: "default",
|
||||
@@ -590,7 +590,7 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
"baseUrl": "http://127.0.0.1",
|
||||
},
|
||||
},
|
||||
secret: &corev1.Secret{},
|
||||
secret: &v1.Secret{},
|
||||
inputParameters: map[string]apiextensionsv1.JSON{
|
||||
"pkey1": {Raw: []byte(`"val1"`)},
|
||||
"pkey2": {Raw: []byte(`"val2"`)},
|
||||
@@ -608,13 +608,13 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
"key3": 123
|
||||
}]
|
||||
}}`),
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"key1": "val1",
|
||||
"key2.key2_1": "val2_1",
|
||||
"key2.key2_2.key2_2_1": "val2_2_1",
|
||||
"key3": "123",
|
||||
"generator": map[string]any{
|
||||
"generator": map[string]interface{}{
|
||||
"input": argoprojiov1alpha1.PluginInput{
|
||||
Parameters: argoprojiov1alpha1.PluginParameters{
|
||||
"pkey1": {Raw: []byte(`"val1"`)},
|
||||
@@ -624,11 +624,11 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: errors.New("error getting plugin from generator: error fetching ConfigMap: token not found in ConfigMap"),
|
||||
expectedError: fmt.Errorf("error getting plugin from generator: error fetching ConfigMap: token not found in ConfigMap"),
|
||||
},
|
||||
}
|
||||
|
||||
ctx := t.Context()
|
||||
ctx := context.Background()
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
@@ -670,7 +670,7 @@ func TestPluginGenerateParams(t *testing.T) {
|
||||
|
||||
fakeClientWithCache := fake.NewClientBuilder().WithObjects([]client.Object{testCase.configmap, testCase.secret}...).Build()
|
||||
|
||||
pluginGenerator := NewPluginGenerator(ctx, fakeClientWithCache, fakeClient, "default")
|
||||
pluginGenerator := NewPluginGenerator(fakeClientWithCache, ctx, fakeClient, "default")
|
||||
|
||||
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
@@ -690,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))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package generators
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
@@ -11,9 +10,9 @@ import (
|
||||
|
||||
"github.com/gosimple/slug"
|
||||
|
||||
pullrequest "github.com/argoproj/argo-cd/v3/applicationset/services/pull_request"
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/utils"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
pullrequest "github.com/argoproj/argo-cd/v2/applicationset/services/pull_request"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/utils"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
var _ Generator = (*PullRequestGenerator)(nil)
|
||||
@@ -51,7 +50,7 @@ func (g *PullRequestGenerator) GetTemplate(appSetGenerator *argoprojiov1alpha1.A
|
||||
return &appSetGenerator.PullRequest.Template
|
||||
}
|
||||
|
||||
func (g *PullRequestGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, applicationSetInfo *argoprojiov1alpha1.ApplicationSet, _ client.Client) ([]map[string]any, error) {
|
||||
func (g *PullRequestGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, applicationSetInfo *argoprojiov1alpha1.ApplicationSet, _ client.Client) ([]map[string]interface{}, error) {
|
||||
if appSetGenerator == nil {
|
||||
return nil, EmptyAppSetGeneratorError
|
||||
}
|
||||
@@ -70,7 +69,7 @@ func (g *PullRequestGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error listing repos: %w", err)
|
||||
}
|
||||
params := make([]map[string]any, 0, len(pulls))
|
||||
params := make([]map[string]interface{}, 0, len(pulls))
|
||||
|
||||
// In order to follow the DNS label standard as defined in RFC 1123,
|
||||
// we need to limit the 'branch' to 50 to give room to append/suffix-ing it
|
||||
@@ -96,7 +95,7 @@ func (g *PullRequestGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha
|
||||
shortSHALength7 = len(pull.HeadSHA)
|
||||
}
|
||||
|
||||
paramMap := map[string]any{
|
||||
paramMap := map[string]interface{}{
|
||||
"number": strconv.Itoa(pull.Number),
|
||||
"title": pull.Title,
|
||||
"branch": pull.Branch,
|
||||
@@ -109,11 +108,6 @@ 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
|
||||
@@ -145,19 +139,19 @@ func (g *PullRequestGenerator) selectServiceProvider(ctx context.Context, genera
|
||||
return nil, fmt.Errorf("error fetching CA certificates from ConfigMap: %w", prErr)
|
||||
}
|
||||
}
|
||||
token, err := utils.GetSecretRef(ctx, g.client, providerConfig.TokenRef, applicationSetInfo.Namespace, g.tokenRefStrictMode)
|
||||
token, err := utils.GetSecretRef(ctx, g.client, providerConfig.TokenRef, applicationSetInfo.Namespace)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error fetching Secret token: %w", err)
|
||||
}
|
||||
return pullrequest.NewGitLabService(token, providerConfig.API, providerConfig.Project, providerConfig.Labels, providerConfig.PullRequestState, g.scmRootCAPath, providerConfig.Insecure, caCerts)
|
||||
return pullrequest.NewGitLabService(ctx, token, providerConfig.API, providerConfig.Project, providerConfig.Labels, providerConfig.PullRequestState, g.scmRootCAPath, providerConfig.Insecure, caCerts)
|
||||
}
|
||||
if generatorConfig.Gitea != nil {
|
||||
providerConfig := generatorConfig.Gitea
|
||||
token, err := utils.GetSecretRef(ctx, g.client, providerConfig.TokenRef, applicationSetInfo.Namespace, g.tokenRefStrictMode)
|
||||
token, err := utils.GetSecretRef(ctx, g.client, providerConfig.TokenRef, applicationSetInfo.Namespace)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error fetching Secret token: %w", err)
|
||||
}
|
||||
return pullrequest.NewGiteaService(token, providerConfig.API, providerConfig.Owner, providerConfig.Repo, providerConfig.Insecure)
|
||||
return pullrequest.NewGiteaService(ctx, token, providerConfig.API, providerConfig.Owner, providerConfig.Repo, providerConfig.Insecure)
|
||||
}
|
||||
if generatorConfig.BitbucketServer != nil {
|
||||
providerConfig := generatorConfig.BitbucketServer
|
||||
@@ -170,46 +164,48 @@ func (g *PullRequestGenerator) selectServiceProvider(ctx context.Context, genera
|
||||
}
|
||||
}
|
||||
if providerConfig.BearerToken != nil {
|
||||
appToken, err := utils.GetSecretRef(ctx, g.client, providerConfig.BearerToken.TokenRef, applicationSetInfo.Namespace, g.tokenRefStrictMode)
|
||||
appToken, err := utils.GetSecretRef(ctx, g.client, providerConfig.BearerToken.TokenRef, applicationSetInfo.Namespace)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error fetching Secret Bearer token: %w", err)
|
||||
}
|
||||
return pullrequest.NewBitbucketServiceBearerToken(ctx, appToken, providerConfig.API, providerConfig.Project, providerConfig.Repo, g.scmRootCAPath, providerConfig.Insecure, caCerts)
|
||||
} else if providerConfig.BasicAuth != nil {
|
||||
password, err := utils.GetSecretRef(ctx, g.client, providerConfig.BasicAuth.PasswordRef, applicationSetInfo.Namespace, g.tokenRefStrictMode)
|
||||
password, err := utils.GetSecretRef(ctx, g.client, providerConfig.BasicAuth.PasswordRef, applicationSetInfo.Namespace)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error fetching Secret token: %w", err)
|
||||
}
|
||||
return pullrequest.NewBitbucketServiceBasicAuth(ctx, providerConfig.BasicAuth.Username, password, providerConfig.API, providerConfig.Project, providerConfig.Repo, g.scmRootCAPath, providerConfig.Insecure, caCerts)
|
||||
} else {
|
||||
return pullrequest.NewBitbucketServiceNoAuth(ctx, providerConfig.API, providerConfig.Project, providerConfig.Repo, g.scmRootCAPath, providerConfig.Insecure, caCerts)
|
||||
}
|
||||
return pullrequest.NewBitbucketServiceNoAuth(ctx, providerConfig.API, providerConfig.Project, providerConfig.Repo, g.scmRootCAPath, providerConfig.Insecure, caCerts)
|
||||
}
|
||||
if generatorConfig.Bitbucket != nil {
|
||||
providerConfig := generatorConfig.Bitbucket
|
||||
if providerConfig.BearerToken != nil {
|
||||
appToken, err := utils.GetSecretRef(ctx, g.client, providerConfig.BearerToken.TokenRef, applicationSetInfo.Namespace, g.tokenRefStrictMode)
|
||||
appToken, err := utils.GetSecretRef(ctx, g.client, providerConfig.BearerToken.TokenRef, applicationSetInfo.Namespace)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error fetching Secret Bearer token: %w", err)
|
||||
}
|
||||
return pullrequest.NewBitbucketCloudServiceBearerToken(providerConfig.API, appToken, providerConfig.Owner, providerConfig.Repo)
|
||||
} else if providerConfig.BasicAuth != nil {
|
||||
password, err := utils.GetSecretRef(ctx, g.client, providerConfig.BasicAuth.PasswordRef, applicationSetInfo.Namespace, g.tokenRefStrictMode)
|
||||
password, err := utils.GetSecretRef(ctx, g.client, providerConfig.BasicAuth.PasswordRef, applicationSetInfo.Namespace)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error fetching Secret token: %w", err)
|
||||
}
|
||||
return pullrequest.NewBitbucketCloudServiceBasicAuth(providerConfig.API, providerConfig.BasicAuth.Username, password, providerConfig.Owner, providerConfig.Repo)
|
||||
} else {
|
||||
return pullrequest.NewBitbucketCloudServiceNoAuth(providerConfig.API, providerConfig.Owner, providerConfig.Repo)
|
||||
}
|
||||
return pullrequest.NewBitbucketCloudServiceNoAuth(providerConfig.API, providerConfig.Owner, providerConfig.Repo)
|
||||
}
|
||||
if generatorConfig.AzureDevOps != nil {
|
||||
providerConfig := generatorConfig.AzureDevOps
|
||||
token, err := utils.GetSecretRef(ctx, g.client, providerConfig.TokenRef, applicationSetInfo.Namespace, g.tokenRefStrictMode)
|
||||
token, err := utils.GetSecretRef(ctx, g.client, providerConfig.TokenRef, applicationSetInfo.Namespace)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error fetching Secret token: %w", err)
|
||||
}
|
||||
return pullrequest.NewAzureDevOpsService(token, providerConfig.API, providerConfig.Organization, providerConfig.Project, providerConfig.Repo, providerConfig.Labels)
|
||||
return pullrequest.NewAzureDevOpsService(ctx, token, providerConfig.API, providerConfig.Organization, providerConfig.Project, providerConfig.Repo, providerConfig.Labels)
|
||||
}
|
||||
return nil, errors.New("no Pull Request provider implementation configured")
|
||||
return nil, fmt.Errorf("no Pull Request provider implementation configured")
|
||||
}
|
||||
|
||||
func (g *PullRequestGenerator) github(ctx context.Context, cfg *argoprojiov1alpha1.PullRequestGeneratorGithub, applicationSetInfo *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) {
|
||||
@@ -223,9 +219,9 @@ func (g *PullRequestGenerator) github(ctx context.Context, cfg *argoprojiov1alph
|
||||
}
|
||||
|
||||
// always default to token, even if not set (public access)
|
||||
token, err := utils.GetSecretRef(ctx, g.client, cfg.TokenRef, applicationSetInfo.Namespace, g.tokenRefStrictMode)
|
||||
token, err := utils.GetSecretRef(ctx, g.client, cfg.TokenRef, applicationSetInfo.Namespace)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error fetching Secret token: %w", err)
|
||||
}
|
||||
return pullrequest.NewGithubService(token, cfg.API, cfg.Owner, cfg.Repo, cfg.Labels)
|
||||
return pullrequest.NewGithubService(ctx, token, cfg.API, cfg.Owner, cfg.Repo, cfg.Labels)
|
||||
}
|
||||
|
||||
@@ -2,23 +2,22 @@ package generators
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
pullrequest "github.com/argoproj/argo-cd/v3/applicationset/services/pull_request"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
pullrequest "github.com/argoproj/argo-cd/v2/applicationset/services/pull_request"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
func TestPullRequestGithubGenerateParams(t *testing.T) {
|
||||
ctx := t.Context()
|
||||
ctx := context.Background()
|
||||
cases := []struct {
|
||||
selectFunc func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error)
|
||||
values map[string]string
|
||||
expected []map[string]any
|
||||
expected []map[string]interface{}
|
||||
expectedErr error
|
||||
applicationSet argoprojiov1alpha1.ApplicationSet
|
||||
}{
|
||||
@@ -39,7 +38,7 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
|
||||
nil,
|
||||
)
|
||||
},
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"number": "1",
|
||||
"title": "title1",
|
||||
@@ -72,7 +71,7 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
|
||||
nil,
|
||||
)
|
||||
},
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"number": "2",
|
||||
"title": "title2",
|
||||
@@ -105,7 +104,7 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
|
||||
nil,
|
||||
)
|
||||
},
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"number": "1",
|
||||
"title": "title1",
|
||||
@@ -125,51 +124,12 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
|
||||
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(
|
||||
ctx,
|
||||
nil,
|
||||
errors.New("fake error"),
|
||||
fmt.Errorf("fake error"),
|
||||
)
|
||||
},
|
||||
expected: nil,
|
||||
expectedErr: errors.New("error listing repos: fake error"),
|
||||
expectedErr: fmt.Errorf("error listing repos: fake error"),
|
||||
},
|
||||
{
|
||||
selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) {
|
||||
@@ -189,7 +149,7 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
|
||||
nil,
|
||||
)
|
||||
},
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"number": "1",
|
||||
"title": "title1",
|
||||
@@ -230,7 +190,7 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
|
||||
nil,
|
||||
)
|
||||
},
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"number": "1",
|
||||
"title": "title1",
|
||||
@@ -259,14 +219,12 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
|
||||
selectServiceProviderFunc: c.selectFunc,
|
||||
}
|
||||
generatorConfig := argoprojiov1alpha1.ApplicationSetGenerator{
|
||||
PullRequest: &argoprojiov1alpha1.PullRequestGenerator{
|
||||
Values: c.values,
|
||||
},
|
||||
PullRequest: &argoprojiov1alpha1.PullRequestGenerator{},
|
||||
}
|
||||
|
||||
got, gotErr := gen.GenerateParams(&generatorConfig, &c.applicationSet, nil)
|
||||
if c.expectedErr != nil {
|
||||
require.EqualError(t, gotErr, c.expectedErr.Error())
|
||||
assert.Equal(t, c.expectedErr.Error(), gotErr.Error())
|
||||
} else {
|
||||
require.NoError(t, gotErr)
|
||||
}
|
||||
@@ -325,7 +283,7 @@ func TestAllowedSCMProviderPullRequest(t *testing.T) {
|
||||
"gitea.myorg.com",
|
||||
"bitbucket.myorg.com",
|
||||
"azuredevops.myorg.com",
|
||||
}, true, nil, true))
|
||||
}, true, nil))
|
||||
|
||||
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
@@ -348,7 +306,7 @@ func TestAllowedSCMProviderPullRequest(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSCMProviderDisabled_PRGenerator(t *testing.T) {
|
||||
generator := NewPullRequestGenerator(nil, NewSCMConfig("", []string{}, false, nil, true))
|
||||
generator := NewPullRequestGenerator(nil, NewSCMConfig("", []string{}, false, nil))
|
||||
|
||||
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
|
||||
@@ -11,11 +11,11 @@ import (
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/services/github_app_auth"
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/services/scm_provider"
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/utils"
|
||||
"github.com/argoproj/argo-cd/v3/common"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/services/github_app_auth"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/services/scm_provider"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/utils"
|
||||
"github.com/argoproj/argo-cd/v2/common"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
var _ Generator = (*SCMProviderGenerator)(nil)
|
||||
@@ -35,16 +35,14 @@ type SCMConfig struct {
|
||||
allowedSCMProviders []string
|
||||
enableSCMProviders bool
|
||||
GitHubApps github_app_auth.Credentials
|
||||
tokenRefStrictMode bool
|
||||
}
|
||||
|
||||
func NewSCMConfig(scmRootCAPath string, allowedSCMProviders []string, enableSCMProviders bool, gitHubApps github_app_auth.Credentials, tokenRefStrictMode bool) SCMConfig {
|
||||
func NewSCMConfig(scmRootCAPath string, allowedSCMProviders []string, enableSCMProviders bool, gitHubApps github_app_auth.Credentials) SCMConfig {
|
||||
return SCMConfig{
|
||||
scmRootCAPath: scmRootCAPath,
|
||||
allowedSCMProviders: allowedSCMProviders,
|
||||
enableSCMProviders: enableSCMProviders,
|
||||
GitHubApps: gitHubApps,
|
||||
tokenRefStrictMode: tokenRefStrictMode,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,7 +114,7 @@ func ScmProviderAllowed(applicationSetInfo *argoprojiov1alpha1.ApplicationSet, g
|
||||
return NewErrDisallowedSCMProvider(url, allowedScmProviders)
|
||||
}
|
||||
|
||||
func (g *SCMProviderGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, applicationSetInfo *argoprojiov1alpha1.ApplicationSet, _ client.Client) ([]map[string]any, error) {
|
||||
func (g *SCMProviderGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, applicationSetInfo *argoprojiov1alpha1.ApplicationSet, _ client.Client) ([]map[string]interface{}, error) {
|
||||
if appSetGenerator == nil {
|
||||
return nil, EmptyAppSetGeneratorError
|
||||
}
|
||||
@@ -138,16 +136,15 @@ func (g *SCMProviderGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha
|
||||
|
||||
ctx := context.Background()
|
||||
var provider scm_provider.SCMProviderService
|
||||
switch {
|
||||
case g.overrideProvider != nil:
|
||||
if g.overrideProvider != nil {
|
||||
provider = g.overrideProvider
|
||||
case providerConfig.Github != nil:
|
||||
} else if providerConfig.Github != nil {
|
||||
var err error
|
||||
provider, err = g.githubProvider(ctx, providerConfig.Github, applicationSetInfo)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("scm provider: %w", err)
|
||||
}
|
||||
case providerConfig.Gitlab != nil:
|
||||
} else if providerConfig.Gitlab != nil {
|
||||
providerConfig := providerConfig.Gitlab
|
||||
var caCerts []byte
|
||||
var scmError error
|
||||
@@ -157,24 +154,24 @@ func (g *SCMProviderGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha
|
||||
return nil, fmt.Errorf("error fetching CA certificates from ConfigMap: %w", scmError)
|
||||
}
|
||||
}
|
||||
token, err := utils.GetSecretRef(ctx, g.client, providerConfig.TokenRef, applicationSetInfo.Namespace, g.tokenRefStrictMode)
|
||||
token, err := utils.GetSecretRef(ctx, g.client, providerConfig.TokenRef, applicationSetInfo.Namespace)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error fetching Gitlab token: %w", err)
|
||||
}
|
||||
provider, err = scm_provider.NewGitlabProvider(providerConfig.Group, token, providerConfig.API, providerConfig.AllBranches, providerConfig.IncludeSubgroups, providerConfig.WillIncludeSharedProjects(), providerConfig.Insecure, g.scmRootCAPath, providerConfig.Topic, caCerts)
|
||||
provider, err = scm_provider.NewGitlabProvider(ctx, providerConfig.Group, token, providerConfig.API, providerConfig.AllBranches, providerConfig.IncludeSubgroups, providerConfig.WillIncludeSharedProjects(), providerConfig.Insecure, g.scmRootCAPath, providerConfig.Topic, caCerts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error initializing Gitlab service: %w", err)
|
||||
}
|
||||
case providerConfig.Gitea != nil:
|
||||
token, err := utils.GetSecretRef(ctx, g.client, providerConfig.Gitea.TokenRef, applicationSetInfo.Namespace, g.tokenRefStrictMode)
|
||||
} else if providerConfig.Gitea != nil {
|
||||
token, err := utils.GetSecretRef(ctx, g.client, providerConfig.Gitea.TokenRef, applicationSetInfo.Namespace)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error fetching Gitea token: %w", err)
|
||||
}
|
||||
provider, err = scm_provider.NewGiteaProvider(providerConfig.Gitea.Owner, token, providerConfig.Gitea.API, providerConfig.Gitea.AllBranches, providerConfig.Gitea.Insecure)
|
||||
provider, err = scm_provider.NewGiteaProvider(ctx, providerConfig.Gitea.Owner, token, providerConfig.Gitea.API, providerConfig.Gitea.AllBranches, providerConfig.Gitea.Insecure)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error initializing Gitea service: %w", err)
|
||||
}
|
||||
case providerConfig.BitbucketServer != nil:
|
||||
} else if providerConfig.BitbucketServer != nil {
|
||||
providerConfig := providerConfig.BitbucketServer
|
||||
var caCerts []byte
|
||||
var scmError error
|
||||
@@ -184,51 +181,50 @@ func (g *SCMProviderGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha
|
||||
return nil, fmt.Errorf("error fetching CA certificates from ConfigMap: %w", scmError)
|
||||
}
|
||||
}
|
||||
switch {
|
||||
case providerConfig.BearerToken != nil:
|
||||
appToken, err := utils.GetSecretRef(ctx, g.client, providerConfig.BearerToken.TokenRef, applicationSetInfo.Namespace, g.tokenRefStrictMode)
|
||||
if providerConfig.BearerToken != nil {
|
||||
appToken, err := utils.GetSecretRef(ctx, g.client, providerConfig.BearerToken.TokenRef, applicationSetInfo.Namespace)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error fetching Secret Bearer token: %w", err)
|
||||
}
|
||||
provider, scmError = scm_provider.NewBitbucketServerProviderBearerToken(ctx, appToken, providerConfig.API, providerConfig.Project, providerConfig.AllBranches, g.scmRootCAPath, providerConfig.Insecure, caCerts)
|
||||
case providerConfig.BasicAuth != nil:
|
||||
password, err := utils.GetSecretRef(ctx, g.client, providerConfig.BasicAuth.PasswordRef, applicationSetInfo.Namespace, g.tokenRefStrictMode)
|
||||
} else if providerConfig.BasicAuth != nil {
|
||||
password, err := utils.GetSecretRef(ctx, g.client, providerConfig.BasicAuth.PasswordRef, applicationSetInfo.Namespace)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error fetching Secret token: %w", err)
|
||||
}
|
||||
provider, scmError = scm_provider.NewBitbucketServerProviderBasicAuth(ctx, providerConfig.BasicAuth.Username, password, providerConfig.API, providerConfig.Project, providerConfig.AllBranches, g.scmRootCAPath, providerConfig.Insecure, caCerts)
|
||||
default:
|
||||
} else {
|
||||
provider, scmError = scm_provider.NewBitbucketServerProviderNoAuth(ctx, providerConfig.API, providerConfig.Project, providerConfig.AllBranches, g.scmRootCAPath, providerConfig.Insecure, caCerts)
|
||||
}
|
||||
if scmError != nil {
|
||||
return nil, fmt.Errorf("error initializing Bitbucket Server service: %w", scmError)
|
||||
}
|
||||
case providerConfig.AzureDevOps != nil:
|
||||
token, err := utils.GetSecretRef(ctx, g.client, providerConfig.AzureDevOps.AccessTokenRef, applicationSetInfo.Namespace, g.tokenRefStrictMode)
|
||||
} else if providerConfig.AzureDevOps != nil {
|
||||
token, err := utils.GetSecretRef(ctx, g.client, providerConfig.AzureDevOps.AccessTokenRef, applicationSetInfo.Namespace)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error fetching Azure Devops access token: %w", err)
|
||||
}
|
||||
provider, err = scm_provider.NewAzureDevOpsProvider(token, providerConfig.AzureDevOps.Organization, providerConfig.AzureDevOps.API, providerConfig.AzureDevOps.TeamProject, providerConfig.AzureDevOps.AllBranches)
|
||||
provider, err = scm_provider.NewAzureDevOpsProvider(ctx, token, providerConfig.AzureDevOps.Organization, providerConfig.AzureDevOps.API, providerConfig.AzureDevOps.TeamProject, providerConfig.AzureDevOps.AllBranches)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error initializing Azure Devops service: %w", err)
|
||||
}
|
||||
case providerConfig.Bitbucket != nil:
|
||||
appPassword, err := utils.GetSecretRef(ctx, g.client, providerConfig.Bitbucket.AppPasswordRef, applicationSetInfo.Namespace, g.tokenRefStrictMode)
|
||||
} else if providerConfig.Bitbucket != nil {
|
||||
appPassword, err := utils.GetSecretRef(ctx, g.client, providerConfig.Bitbucket.AppPasswordRef, applicationSetInfo.Namespace)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error fetching Bitbucket cloud appPassword: %w", err)
|
||||
}
|
||||
provider, err = scm_provider.NewBitBucketCloudProvider(providerConfig.Bitbucket.Owner, providerConfig.Bitbucket.User, appPassword, providerConfig.Bitbucket.AllBranches)
|
||||
provider, err = scm_provider.NewBitBucketCloudProvider(ctx, providerConfig.Bitbucket.Owner, providerConfig.Bitbucket.User, appPassword, providerConfig.Bitbucket.AllBranches)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error initializing Bitbucket cloud service: %w", err)
|
||||
}
|
||||
case providerConfig.AWSCodeCommit != nil:
|
||||
} else if providerConfig.AWSCodeCommit != nil {
|
||||
var awsErr error
|
||||
provider, awsErr = scm_provider.NewAWSCodeCommitProvider(ctx, providerConfig.AWSCodeCommit.TagFilters, providerConfig.AWSCodeCommit.Role, providerConfig.AWSCodeCommit.Region, providerConfig.AWSCodeCommit.AllBranches)
|
||||
if awsErr != nil {
|
||||
return nil, fmt.Errorf("error initializing AWS codecommit service: %w", awsErr)
|
||||
}
|
||||
default:
|
||||
return nil, errors.New("no SCM provider implementation configured")
|
||||
} else {
|
||||
return nil, fmt.Errorf("no SCM provider implementation configured")
|
||||
}
|
||||
|
||||
// Find all the available repos.
|
||||
@@ -236,7 +232,7 @@ func (g *SCMProviderGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error listing repos: %w", err)
|
||||
}
|
||||
paramsArray := make([]map[string]any, 0, len(repos))
|
||||
paramsArray := make([]map[string]interface{}, 0, len(repos))
|
||||
var shortSHALength int
|
||||
var shortSHALength7 int
|
||||
for _, repo := range repos {
|
||||
@@ -250,7 +246,7 @@ func (g *SCMProviderGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha
|
||||
shortSHALength7 = len(repo.SHA)
|
||||
}
|
||||
|
||||
params := map[string]any{
|
||||
params := map[string]interface{}{
|
||||
"organization": repo.Organization,
|
||||
"repository": repo.Repository,
|
||||
"url": repo.URL,
|
||||
@@ -287,9 +283,9 @@ func (g *SCMProviderGenerator) githubProvider(ctx context.Context, github *argop
|
||||
)
|
||||
}
|
||||
|
||||
token, err := utils.GetSecretRef(ctx, g.client, github.TokenRef, applicationSetInfo.Namespace, g.tokenRefStrictMode)
|
||||
token, err := utils.GetSecretRef(ctx, g.client, github.TokenRef, applicationSetInfo.Namespace)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error fetching Github token: %w", err)
|
||||
}
|
||||
return scm_provider.NewGithubProvider(github.Organization, token, github.API, github.AllBranches)
|
||||
return scm_provider.NewGithubProvider(ctx, github.Organization, token, github.API, github.AllBranches)
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/services/scm_provider"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/services/scm_provider"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
func TestSCMProviderGenerateParams(t *testing.T) {
|
||||
@@ -16,7 +16,7 @@ func TestSCMProviderGenerateParams(t *testing.T) {
|
||||
name string
|
||||
repos []*scm_provider.Repository
|
||||
values map[string]string
|
||||
expected []map[string]any
|
||||
expected []map[string]interface{}
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
@@ -38,7 +38,7 @@ func TestSCMProviderGenerateParams(t *testing.T) {
|
||||
SHA: "59d0",
|
||||
},
|
||||
},
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"organization": "myorg",
|
||||
"repository": "repo1",
|
||||
@@ -79,7 +79,7 @@ func TestSCMProviderGenerateParams(t *testing.T) {
|
||||
"foo": "bar",
|
||||
"should_i_force_push_to": "{{ branch }}?",
|
||||
},
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"organization": "myorg",
|
||||
"repository": "repo3",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
package generators
|
||||
|
||||
type SCMGeneratorWithCustomApiUrl interface { //nolint:revive //FIXME(var-naming)
|
||||
type SCMGeneratorWithCustomApiUrl interface {
|
||||
CustomApiUrl() string
|
||||
}
|
||||
|
||||
@@ -7,18 +7,18 @@ import (
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/services"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/services"
|
||||
)
|
||||
|
||||
func GetGenerators(ctx context.Context, c client.Client, k8sClient kubernetes.Interface, namespace string, argoCDService services.Repos, dynamicClient dynamic.Interface, scmConfig SCMConfig) map[string]Generator {
|
||||
terminalGenerators := map[string]Generator{
|
||||
"List": NewListGenerator(),
|
||||
"Clusters": NewClusterGenerator(ctx, c, k8sClient, namespace),
|
||||
"Clusters": NewClusterGenerator(c, ctx, k8sClient, namespace),
|
||||
"Git": NewGitGenerator(argoCDService, namespace),
|
||||
"SCMProvider": NewSCMProviderGenerator(c, scmConfig),
|
||||
"ClusterDecisionResource": NewDuckTypeGenerator(ctx, dynamicClient, k8sClient, namespace),
|
||||
"PullRequest": NewPullRequestGenerator(c, scmConfig),
|
||||
"Plugin": NewPluginGenerator(ctx, c, k8sClient, namespace),
|
||||
"Plugin": NewPluginGenerator(c, ctx, k8sClient, namespace),
|
||||
}
|
||||
|
||||
nestedGenerators := map[string]Generator{
|
||||
|
||||
@@ -4,11 +4,11 @@ import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func appendTemplatedValues(values map[string]string, params map[string]any, useGoTemplate bool, goTemplateOptions []string) error {
|
||||
func appendTemplatedValues(values map[string]string, params map[string]interface{}, useGoTemplate bool, goTemplateOptions []string) error {
|
||||
// We create a local map to ensure that we do not fall victim to a billion-laughs attack. We iterate through the
|
||||
// cluster values map and only replace values in said map if it has already been allowlisted in the params map.
|
||||
// Once we iterate through all the cluster values we can then safely merge the `tmp` map into the main params map.
|
||||
tmp := map[string]any{}
|
||||
tmp := map[string]interface{}{}
|
||||
|
||||
for key, value := range values {
|
||||
result, err := replaceTemplatedString(value, params, useGoTemplate, goTemplateOptions)
|
||||
@@ -22,7 +22,7 @@ func appendTemplatedValues(values map[string]string, params map[string]any, useG
|
||||
}
|
||||
tmp["values"].(map[string]string)[key] = result
|
||||
} else {
|
||||
tmp["values."+key] = result
|
||||
tmp[fmt.Sprintf("values.%s", key)] = result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ func appendTemplatedValues(values map[string]string, params map[string]any, useG
|
||||
return nil
|
||||
}
|
||||
|
||||
func replaceTemplatedString(value string, params map[string]any, useGoTemplate bool, goTemplateOptions []string) (string, error) {
|
||||
func replaceTemplatedString(value string, params map[string]interface{}, useGoTemplate bool, goTemplateOptions []string) (string, error) {
|
||||
replacedTmplStr, err := render.Replace(value, params, useGoTemplate, goTemplateOptions)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to replace templated string with rendered values: %w", err)
|
||||
|
||||
@@ -11,18 +11,18 @@ func TestValueInterpolation(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
values map[string]string
|
||||
params map[string]any
|
||||
expected map[string]any
|
||||
params map[string]interface{}
|
||||
expected map[string]interface{}
|
||||
}{
|
||||
{
|
||||
name: "Simple interpolation",
|
||||
values: map[string]string{
|
||||
"hello": "{{ world }}",
|
||||
},
|
||||
params: map[string]any{
|
||||
params: map[string]interface{}{
|
||||
"world": "world!",
|
||||
},
|
||||
expected: map[string]any{
|
||||
expected: map[string]interface{}{
|
||||
"world": "world!",
|
||||
"values.hello": "world!",
|
||||
},
|
||||
@@ -32,8 +32,8 @@ func TestValueInterpolation(t *testing.T) {
|
||||
values: map[string]string{
|
||||
"non-existent": "{{ non-existent }}",
|
||||
},
|
||||
params: map[string]any{},
|
||||
expected: map[string]any{
|
||||
params: map[string]interface{}{},
|
||||
expected: map[string]interface{}{
|
||||
"values.non-existent": "{{ non-existent }}",
|
||||
},
|
||||
},
|
||||
@@ -44,8 +44,8 @@ func TestValueInterpolation(t *testing.T) {
|
||||
"lol2": "{{values.lol1}}{{values.lol1}}",
|
||||
"lol3": "{{values.lol2}}{{values.lol2}}{{values.lol2}}",
|
||||
},
|
||||
params: map[string]any{},
|
||||
expected: map[string]any{
|
||||
params: map[string]interface{}{},
|
||||
expected: map[string]interface{}{
|
||||
"values.lol1": "lol",
|
||||
"values.lol2": "{{values.lol1}}{{values.lol1}}",
|
||||
"values.lol3": "{{values.lol2}}{{values.lol2}}{{values.lol2}}",
|
||||
@@ -66,18 +66,18 @@ func TestValueInterpolationWithGoTemplating(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
values map[string]string
|
||||
params map[string]any
|
||||
expected map[string]any
|
||||
params map[string]interface{}
|
||||
expected map[string]interface{}
|
||||
}{
|
||||
{
|
||||
name: "Simple interpolation",
|
||||
values: map[string]string{
|
||||
"hello": "{{ .world }}",
|
||||
},
|
||||
params: map[string]any{
|
||||
params: map[string]interface{}{
|
||||
"world": "world!",
|
||||
},
|
||||
expected: map[string]any{
|
||||
expected: map[string]interface{}{
|
||||
"world": "world!",
|
||||
"values": map[string]string{
|
||||
"hello": "world!",
|
||||
@@ -89,8 +89,8 @@ func TestValueInterpolationWithGoTemplating(t *testing.T) {
|
||||
values: map[string]string{
|
||||
"non_existent": "{{ default \"bar\" .non_existent }}",
|
||||
},
|
||||
params: map[string]any{},
|
||||
expected: map[string]any{
|
||||
params: map[string]interface{}{},
|
||||
expected: map[string]interface{}{
|
||||
"values": map[string]string{
|
||||
"non_existent": "bar",
|
||||
},
|
||||
@@ -103,8 +103,8 @@ func TestValueInterpolationWithGoTemplating(t *testing.T) {
|
||||
"lol2": "{{.values.lol1}}{{.values.lol1}}",
|
||||
"lol3": "{{.values.lol2}}{{.values.lol2}}{{.values.lol2}}",
|
||||
},
|
||||
params: map[string]any{},
|
||||
expected: map[string]any{
|
||||
params: map[string]interface{}{},
|
||||
expected: map[string]interface{}{
|
||||
"values": map[string]string{
|
||||
"lol1": "lol",
|
||||
"lol2": "<no value><no value>",
|
||||
|
||||
@@ -2,10 +2,11 @@ package metrics
|
||||
|
||||
import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
// Fake implementation for testing
|
||||
func NewFakeAppsetMetrics() *ApplicationsetMetrics {
|
||||
func NewFakeAppsetMetrics(client ctrlclient.WithWatch) *ApplicationsetMetrics {
|
||||
reconcileHistogram := prometheus.NewHistogramVec(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "argocd_appset_reconcile",
|
||||
|
||||
@@ -7,10 +7,9 @@ import (
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"sigs.k8s.io/controller-runtime/pkg/metrics"
|
||||
|
||||
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"
|
||||
argoappv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
applisters "github.com/argoproj/argo-cd/v2/pkg/client/listers/application/v1alpha1"
|
||||
metricsutil "github.com/argoproj/argo-cd/v2/util/metrics"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -58,10 +57,6 @@ 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,
|
||||
}
|
||||
|
||||
@@ -7,19 +7,23 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/utils"
|
||||
argoappv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
"sigs.k8s.io/controller-runtime/pkg/metrics"
|
||||
"sigs.k8s.io/yaml"
|
||||
fake "sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/utils"
|
||||
argoappv1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
metricsutil "github.com/argoproj/argo-cd/v3/util/metrics"
|
||||
prometheus "github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
metricsutil "github.com/argoproj/argo-cd/v2/util/metrics"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/metrics"
|
||||
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -174,7 +178,7 @@ func TestApplicationsetCollector(t *testing.T) {
|
||||
appsetCollector := newAppsetCollector(utils.NewAppsetLister(client), collectedLabels, filter)
|
||||
|
||||
metrics.Registry.MustRegister(appsetCollector)
|
||||
req, err := http.NewRequest(http.MethodGet, "/metrics", nil)
|
||||
req, err := http.NewRequest("GET", "/metrics", nil)
|
||||
require.NoError(t, err)
|
||||
rr := httptest.NewRecorder()
|
||||
handler := promhttp.HandlerFor(metrics.Registry, promhttp.HandlerOpts{})
|
||||
@@ -216,7 +220,7 @@ func TestObserveReconcile(t *testing.T) {
|
||||
|
||||
appsetMetrics := NewApplicationsetMetrics(utils.NewAppsetLister(client), collectedLabels, filter)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, "/metrics", nil)
|
||||
req, err := http.NewRequest("GET", "/metrics", nil)
|
||||
require.NoError(t, err)
|
||||
rr := httptest.NewRecorder()
|
||||
handler := promhttp.HandlerFor(metrics.Registry, promhttp.HandlerOpts{})
|
||||
|
||||
@@ -5,9 +5,9 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/bradleyfalzon/ghinstallation/v2"
|
||||
"github.com/google/go-github/v66/github"
|
||||
"github.com/google/go-github/v63/github"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/services/github_app_auth"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/services/github_app_auth"
|
||||
)
|
||||
|
||||
// Client builds a github client for the given app authentication.
|
||||
|
||||
@@ -65,7 +65,7 @@ func newClient(baseURL string, options ...ClientOptionFunc) (*Client, error) {
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (c *Client) NewRequestWithContext(ctx context.Context, method, path string, body any) (*http.Request, error) {
|
||||
func (c *Client) NewRequest(method, path string, body interface{}, options []ClientOptionFunc) (*http.Request, error) {
|
||||
// Make sure the given URL end with a slash
|
||||
if !strings.HasSuffix(c.baseURL, "/") {
|
||||
c.baseURL += "/"
|
||||
@@ -82,7 +82,7 @@ func (c *Client) NewRequestWithContext(ctx context.Context, method, path string,
|
||||
}
|
||||
}
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, method, c.baseURL+path, buf)
|
||||
req, err := http.NewRequest(method, c.baseURL+path, buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -102,7 +102,7 @@ func (c *Client) NewRequestWithContext(ctx context.Context, method, path string,
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func (c *Client) Do(req *http.Request, v any) (*http.Response, error) {
|
||||
func (c *Client) Do(ctx context.Context, req *http.Request, v interface{}) (*http.Response, error) {
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -134,7 +134,7 @@ func (c *Client) Do(req *http.Request, v any) (*http.Response, error) {
|
||||
|
||||
// CheckResponse checks the API response for errors, and returns them if present.
|
||||
func CheckResponse(resp *http.Response) error {
|
||||
if c := resp.StatusCode; http.StatusOK <= c && c < http.StatusMultipleChoices {
|
||||
if c := resp.StatusCode; 200 <= c && c <= 299 {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ func CheckResponse(resp *http.Response) error {
|
||||
return fmt.Errorf("API error with status code %d: %w", resp.StatusCode, err)
|
||||
}
|
||||
|
||||
var raw map[string]any
|
||||
var raw map[string]interface{}
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return fmt.Errorf("API error with status code %d: %s", resp.StatusCode, string(data))
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package http
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
@@ -10,11 +10,10 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestClient(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, err := w.Write([]byte("Hello, World!"))
|
||||
if err != nil {
|
||||
@@ -25,17 +24,21 @@ func TestClient(t *testing.T) {
|
||||
|
||||
var clientOptionFns []ClientOptionFunc
|
||||
_, err := NewClient(server.URL, clientOptionFns...)
|
||||
require.NoError(t, err, "Failed to create client")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create client: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientDo(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
for _, c := range []struct {
|
||||
name string
|
||||
params map[string]string
|
||||
content []byte
|
||||
fakeServer *httptest.Server
|
||||
clientOptionFns []ClientOptionFunc
|
||||
expected []map[string]any
|
||||
expected []map[string]interface{}
|
||||
expectedCode int
|
||||
expectedError error
|
||||
}{
|
||||
@@ -45,7 +48,7 @@ func TestClientDo(t *testing.T) {
|
||||
"pkey1": "val1",
|
||||
"pkey2": "val2",
|
||||
},
|
||||
fakeServer: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
fakeServer: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, err := w.Write([]byte(`[{
|
||||
"key1": "val1",
|
||||
@@ -62,19 +65,19 @@ func TestClientDo(t *testing.T) {
|
||||
}
|
||||
})),
|
||||
clientOptionFns: nil,
|
||||
expected: []map[string]any{
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"key1": "val1",
|
||||
"key2": map[string]any{
|
||||
"key2": map[string]interface{}{
|
||||
"key2_1": "val2_1",
|
||||
"key2_2": map[string]any{
|
||||
"key2_2": map[string]interface{}{
|
||||
"key2_2_1": "val2_2_1",
|
||||
},
|
||||
},
|
||||
"key3": float64(123),
|
||||
},
|
||||
},
|
||||
expectedCode: http.StatusOK,
|
||||
expectedCode: 200,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
@@ -105,9 +108,9 @@ func TestClientDo(t *testing.T) {
|
||||
}
|
||||
})),
|
||||
clientOptionFns: nil,
|
||||
expected: []map[string]any(nil),
|
||||
expectedCode: http.StatusUnauthorized,
|
||||
expectedError: errors.New("API error with status code 401: "),
|
||||
expected: []map[string]interface{}(nil),
|
||||
expectedCode: 401,
|
||||
expectedError: fmt.Errorf("API error with status code 401: "),
|
||||
},
|
||||
} {
|
||||
cc := c
|
||||
@@ -115,14 +118,18 @@ func TestClientDo(t *testing.T) {
|
||||
defer cc.fakeServer.Close()
|
||||
|
||||
client, err := NewClient(cc.fakeServer.URL, cc.clientOptionFns...)
|
||||
require.NoError(t, err, "NewClient returned unexpected error")
|
||||
if err != nil {
|
||||
t.Fatalf("NewClient returned unexpected error: %v", err)
|
||||
}
|
||||
|
||||
req, err := client.NewRequestWithContext(t.Context(), http.MethodPost, "", cc.params)
|
||||
require.NoError(t, err, "NewRequest returned unexpected error")
|
||||
req, err := client.NewRequest("POST", "", cc.params, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("NewRequest returned unexpected error: %v", err)
|
||||
}
|
||||
|
||||
var data []map[string]any
|
||||
var data []map[string]interface{}
|
||||
|
||||
resp, err := client.Do(req, &data)
|
||||
resp, err := client.Do(ctx, req, &data)
|
||||
|
||||
if cc.expectedError != nil {
|
||||
assert.EqualError(t, err, cc.expectedError.Error())
|
||||
@@ -142,5 +149,12 @@ func TestCheckResponse(t *testing.T) {
|
||||
}
|
||||
|
||||
err := CheckResponse(resp)
|
||||
require.EqualError(t, err, "API error with status code 400: invalid_request")
|
||||
if err == nil {
|
||||
t.Error("Expected an error, got nil")
|
||||
}
|
||||
|
||||
expected := "API error with status code 400: invalid_request"
|
||||
if err.Error() != expected {
|
||||
t.Errorf("Expected error '%s', got '%s'", expected, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
38
applicationset/services/mocks/Repos.go
generated
38
applicationset/services/mocks/Repos.go
generated
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.52.4. DO NOT EDIT.
|
||||
// Code generated by mockery v2.43.2. 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, 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)
|
||||
// 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)
|
||||
|
||||
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, 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, error)); ok {
|
||||
return 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)
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, bool, bool) []string); ok {
|
||||
r0 = rf(ctx, repoURL, revision, noRevisionCache, verifyCommit)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]string)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, string, string, bool, bool) error); ok {
|
||||
r1 = rf(ctx, repoURL, revision, project, noRevisionCache, verifyCommit)
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, string, bool, bool) error); ok {
|
||||
r1 = rf(ctx, repoURL, revision, 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, 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)
|
||||
// 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)
|
||||
|
||||
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, 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, 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); ok {
|
||||
r0 = 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)
|
||||
} 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, string, bool, bool) error); ok {
|
||||
r1 = rf(ctx, repoURL, revision, project, pattern, noRevisionCache, verifyCommit)
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, string, string, bool, bool) error); ok {
|
||||
r1 = rf(ctx, repoURL, revision, pattern, noRevisionCache, verifyCommit)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
internalhttp "github.com/argoproj/argo-cd/v3/applicationset/services/internal/http"
|
||||
"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
internalhttp "github.com/argoproj/argo-cd/v2/applicationset/services/internal/http"
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
// ServiceRequest is the request object sent to the plugin service.
|
||||
@@ -20,7 +20,7 @@ type ServiceRequest struct {
|
||||
|
||||
type Output struct {
|
||||
// Parameters is the list of parameter sets returned by the plugin.
|
||||
Parameters []map[string]any `json:"parameters"`
|
||||
Parameters []map[string]interface{} `json:"parameters"`
|
||||
}
|
||||
|
||||
// ServiceResponse is the response object returned by the plugin service.
|
||||
@@ -34,7 +34,7 @@ type Service struct {
|
||||
appSetName string
|
||||
}
|
||||
|
||||
func NewPluginService(appSetName string, baseURL string, token string, requestTimeout int) (*Service, error) {
|
||||
func NewPluginService(ctx context.Context, appSetName string, baseURL string, token string, requestTimeout int) (*Service, error) {
|
||||
var clientOptionFns []internalhttp.ClientOptionFunc
|
||||
|
||||
clientOptionFns = append(clientOptionFns, internalhttp.WithToken(token))
|
||||
@@ -55,14 +55,14 @@ func NewPluginService(appSetName string, baseURL string, token string, requestTi
|
||||
}
|
||||
|
||||
func (p *Service) List(ctx context.Context, parameters v1alpha1.PluginParameters) (*ServiceResponse, error) {
|
||||
req, err := p.client.NewRequestWithContext(ctx, http.MethodPost, "api/v1/getparams.execute", ServiceRequest{ApplicationSetName: p.appSetName, Input: v1alpha1.PluginInput{Parameters: parameters}})
|
||||
req, err := p.client.NewRequest(http.MethodPost, "api/v1/getparams.execute", ServiceRequest{ApplicationSetName: p.appSetName, Input: v1alpha1.PluginInput{Parameters: parameters}}, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("NewRequest returned unexpected error: %w", err)
|
||||
}
|
||||
|
||||
var data ServiceResponse
|
||||
|
||||
_, err = p.client.Do(req, &data)
|
||||
_, err = p.client.Do(ctx, req, &data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error get api '%s': %w", p.appSetName, err)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
@@ -8,7 +9,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestPlugin(t *testing.T) {
|
||||
@@ -30,14 +30,20 @@ func TestPlugin(t *testing.T) {
|
||||
ts := httptest.NewServer(handler)
|
||||
defer ts.Close()
|
||||
|
||||
client, err := NewPluginService("plugin-test", ts.URL, token, 0)
|
||||
require.NoError(t, err)
|
||||
client, err := NewPluginService(context.Background(), "plugin-test", ts.URL, token, 0)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
data, err := client.List(t.Context(), nil)
|
||||
require.NoError(t, err)
|
||||
data, err := client.List(context.Background(), nil)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
var expectedData ServiceResponse
|
||||
err = json.Unmarshal([]byte(expectedJSON), &expectedData)
|
||||
require.NoError(t, err)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, &expectedData, data)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/common"
|
||||
"github.com/argoproj/argo-cd/v2/common"
|
||||
)
|
||||
|
||||
// ParseSecretKey retrieves secret appSetName if different from common ArgoCDSecretName.
|
||||
@@ -11,7 +12,7 @@ func ParseSecretKey(key string) (secretName string, tokenKey string) {
|
||||
if strings.Contains(key, ":") {
|
||||
parts := strings.Split(key, ":")
|
||||
secretName = parts[0][1:]
|
||||
tokenKey = "$" + parts[1]
|
||||
tokenKey = fmt.Sprintf("$%s", parts[1])
|
||||
} else {
|
||||
secretName = common.ArgoCDSecretName
|
||||
tokenKey = key
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/microsoft/azure-devops-go-api/azuredevops"
|
||||
"github.com/microsoft/azure-devops-go-api/azuredevops/core"
|
||||
"github.com/microsoft/azure-devops-go-api/azuredevops/git"
|
||||
core "github.com/microsoft/azure-devops-go-api/azuredevops/core"
|
||||
git "github.com/microsoft/azure-devops-go-api/azuredevops/git"
|
||||
)
|
||||
|
||||
const AZURE_DEVOPS_DEFAULT_URL = "https://dev.azure.com"
|
||||
@@ -41,14 +41,14 @@ var (
|
||||
_ AzureDevOpsClientFactory = &devopsFactoryImpl{}
|
||||
)
|
||||
|
||||
func NewAzureDevOpsService(token, url, organization, project, repo string, labels []string) (PullRequestService, error) {
|
||||
organizationURL := buildURL(url, organization)
|
||||
func NewAzureDevOpsService(ctx context.Context, token, url, organization, project, repo string, labels []string) (PullRequestService, error) {
|
||||
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{
|
||||
@@ -82,7 +82,6 @@ func (a *AzureDevOpsService) List(ctx context.Context) ([]*PullRequest, error) {
|
||||
pr.Repository.Name == nil ||
|
||||
pr.PullRequestId == nil ||
|
||||
pr.SourceRefName == nil ||
|
||||
pr.TargetRefName == nil ||
|
||||
pr.LastMergeSourceCommit == nil ||
|
||||
pr.LastMergeSourceCommit.CommitId == nil {
|
||||
continue
|
||||
@@ -95,13 +94,12 @@ func (a *AzureDevOpsService) List(ctx context.Context) ([]*PullRequest, error) {
|
||||
|
||||
if *pr.Repository.Name == a.repo {
|
||||
pullRequests = append(pullRequests, &PullRequest{
|
||||
Number: *pr.PullRequestId,
|
||||
Title: *pr.Title,
|
||||
Branch: strings.Replace(*pr.SourceRefName, "refs/heads/", "", 1),
|
||||
TargetBranch: strings.Replace(*pr.TargetRefName, "refs/heads/", "", 1),
|
||||
HeadSHA: *pr.LastMergeSourceCommit.CommitId,
|
||||
Labels: azureDevOpsLabels,
|
||||
Author: strings.Split(*pr.CreatedBy.UniqueName, "@")[0], // Get the part before the @ in the email-address
|
||||
Number: *pr.PullRequestId,
|
||||
Title: *pr.Title,
|
||||
Branch: strings.Replace(*pr.SourceRefName, "refs/heads/", "", 1),
|
||||
HeadSHA: *pr.LastMergeSourceCommit.CommitId,
|
||||
Labels: azureDevOpsLabels,
|
||||
Author: strings.Split(*pr.CreatedBy.UniqueName, "@")[0], // Get the part before the @ in the email-address
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,12 +7,12 @@ import (
|
||||
"github.com/microsoft/azure-devops-go-api/azuredevops/webapi"
|
||||
|
||||
"github.com/microsoft/azure-devops-go-api/azuredevops/core"
|
||||
"github.com/microsoft/azure-devops-go-api/azuredevops/git"
|
||||
git "github.com/microsoft/azure-devops-go-api/azuredevops/git"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
azureMock "github.com/argoproj/argo-cd/v3/applicationset/services/scm_provider/azure_devops/git/mocks"
|
||||
azureMock "github.com/argoproj/argo-cd/v2/applicationset/services/scm_provider/azure_devops/git/mocks"
|
||||
)
|
||||
|
||||
func createBoolPtr(x bool) *bool {
|
||||
@@ -61,20 +61,19 @@ func (m *AzureClientFactoryMock) GetClient(ctx context.Context) (git.Client, err
|
||||
func TestListPullRequest(t *testing.T) {
|
||||
teamProject := "myorg_project"
|
||||
repoName := "myorg_project_repo"
|
||||
prID := 123
|
||||
prTitle := "feat(123)"
|
||||
prHeadSha := "cd4973d9d14a08ffe6b641a89a68891d6aac8056"
|
||||
ctx := t.Context()
|
||||
pr_id := 123
|
||||
pr_title := "feat(123)"
|
||||
pr_head_sha := "cd4973d9d14a08ffe6b641a89a68891d6aac8056"
|
||||
ctx := context.Background()
|
||||
uniqueName := "testName"
|
||||
|
||||
pullRequestMock := []git.GitPullRequest{
|
||||
{
|
||||
PullRequestId: createIntPtr(prID),
|
||||
Title: createStringPtr(prTitle),
|
||||
PullRequestId: createIntPtr(pr_id),
|
||||
Title: createStringPtr(pr_title),
|
||||
SourceRefName: createStringPtr("refs/heads/feature-branch"),
|
||||
TargetRefName: createStringPtr("refs/heads/main"),
|
||||
LastMergeSourceCommit: &git.GitCommitRef{
|
||||
CommitId: createStringPtr(prHeadSha),
|
||||
CommitId: createStringPtr(pr_head_sha),
|
||||
},
|
||||
Labels: &[]core.WebApiTagDefinition{},
|
||||
Repository: &git.GitRepository{
|
||||
@@ -107,10 +106,9 @@ func TestListPullRequest(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, list, 1)
|
||||
assert.Equal(t, "feature-branch", list[0].Branch)
|
||||
assert.Equal(t, "main", list[0].TargetBranch)
|
||||
assert.Equal(t, prHeadSha, list[0].HeadSHA)
|
||||
assert.Equal(t, pr_head_sha, list[0].HeadSHA)
|
||||
assert.Equal(t, "feat(123)", list[0].Title)
|
||||
assert.Equal(t, prID, list[0].Number)
|
||||
assert.Equal(t, pr_id, list[0].Number)
|
||||
assert.Equal(t, uniqueName, list[0].Author)
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package pull_request
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
@@ -52,7 +51,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 +64,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 +80,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 +96,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) {
|
||||
@@ -113,14 +112,14 @@ func (b *BitbucketCloudService) List(_ context.Context) ([]*PullRequest, error)
|
||||
return nil, fmt.Errorf("error listing pull requests for %s/%s: %w", b.owner, b.repositorySlug, err)
|
||||
}
|
||||
|
||||
resp, ok := response.(map[string]any)
|
||||
resp, ok := response.(map[string]interface{})
|
||||
if !ok {
|
||||
return nil, errors.New("unknown type returned from bitbucket pull requests")
|
||||
return nil, fmt.Errorf("unknown type returned from bitbucket pull requests")
|
||||
}
|
||||
|
||||
repoArray, ok := resp["values"].([]any)
|
||||
repoArray, ok := resp["values"].([]interface{})
|
||||
if !ok {
|
||||
return nil, errors.New("unknown type returned from response values")
|
||||
return nil, fmt.Errorf("unknown type returned from response values")
|
||||
}
|
||||
|
||||
jsonStr, err := json.Marshal(repoArray)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package pull_request
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
@@ -10,11 +11,10 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
func defaultHandlerCloud(t *testing.T) func(http.ResponseWriter, *http.Request) {
|
||||
t.Helper()
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
var err error
|
||||
@@ -53,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) {
|
||||
@@ -86,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(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 1)
|
||||
assert.Equal(t, 101, pullRequests[0].Number)
|
||||
@@ -104,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(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 1)
|
||||
assert.Equal(t, 101, pullRequests[0].Number)
|
||||
@@ -122,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(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 1)
|
||||
assert.Equal(t, 101, pullRequests[0].Number)
|
||||
@@ -213,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(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 3)
|
||||
assert.Equal(t, PullRequest{
|
||||
@@ -240,12 +240,12 @@ func TestListPullRequestPaginationCloud(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestListResponseErrorCloud(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(500)
|
||||
}))
|
||||
defer ts.Close()
|
||||
svc, _ := NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO")
|
||||
_, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
_, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
@@ -269,7 +269,7 @@ func TestListResponseMalformedCloud(t *testing.T) {
|
||||
}))
|
||||
defer ts.Close()
|
||||
svc, _ := NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO")
|
||||
_, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
_, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
@@ -293,7 +293,7 @@ func TestListResponseMalformedValuesCloud(t *testing.T) {
|
||||
}))
|
||||
defer ts.Close()
|
||||
svc, _ := NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO")
|
||||
_, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
_, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
@@ -318,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(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.NoError(t, err)
|
||||
assert.Empty(t, pullRequests)
|
||||
}
|
||||
@@ -405,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(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{
|
||||
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{
|
||||
{
|
||||
BranchMatch: ®exp,
|
||||
},
|
||||
@@ -430,7 +430,7 @@ func TestListPullRequestBranchMatchCloud(t *testing.T) {
|
||||
regexp = `.*2$`
|
||||
svc, err = NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO")
|
||||
require.NoError(t, err)
|
||||
pullRequests, err = ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{
|
||||
pullRequests, err = ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{
|
||||
{
|
||||
BranchMatch: ®exp,
|
||||
},
|
||||
@@ -448,7 +448,7 @@ func TestListPullRequestBranchMatchCloud(t *testing.T) {
|
||||
regexp = `[\d{2}`
|
||||
svc, err = NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO")
|
||||
require.NoError(t, err)
|
||||
_, err = ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{
|
||||
_, err = ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{
|
||||
{
|
||||
BranchMatch: ®exp,
|
||||
},
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
bitbucketv1 "github.com/gfleury/go-bitbucket-v1"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/utils"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/utils"
|
||||
)
|
||||
|
||||
type BitbucketService struct {
|
||||
@@ -64,7 +64,7 @@ func newBitbucketService(ctx context.Context, bitbucketConfig *bitbucketv1.Confi
|
||||
}
|
||||
|
||||
func (b *BitbucketService) List(_ context.Context) ([]*PullRequest, error) {
|
||||
paged := map[string]any{
|
||||
paged := map[string]interface{}{
|
||||
"limit": 100,
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package pull_request
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"io"
|
||||
@@ -11,11 +12,10 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
func defaultHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
|
||||
t.Helper()
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
var err error
|
||||
@@ -63,9 +63,9 @@ func TestListPullRequestNoAuth(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
svc, err := NewBitbucketServiceNoAuth(t.Context(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
svc, err := NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 1)
|
||||
assert.Equal(t, 101, pullRequests[0].Number)
|
||||
@@ -164,9 +164,9 @@ func TestListPullRequestPagination(t *testing.T) {
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
svc, err := NewBitbucketServiceNoAuth(t.Context(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
svc, err := NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 3)
|
||||
assert.Equal(t, PullRequest{
|
||||
@@ -206,9 +206,9 @@ func TestListPullRequestBasicAuth(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
svc, err := NewBitbucketServiceBasicAuth(t.Context(), "user", "password", ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
svc, err := NewBitbucketServiceBasicAuth(context.Background(), "user", "password", ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 1)
|
||||
assert.Equal(t, 101, pullRequests[0].Number)
|
||||
@@ -223,9 +223,9 @@ func TestListPullRequestBearerAuth(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
svc, err := NewBitbucketServiceBearerToken(t.Context(), "tolkien", ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
svc, err := NewBitbucketServiceBearerToken(context.Background(), "tolkien", ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 1)
|
||||
assert.Equal(t, 101, pullRequests[0].Number)
|
||||
@@ -276,7 +276,7 @@ func TestListPullRequestTLS(t *testing.T) {
|
||||
defer ts.Close()
|
||||
|
||||
var certs []byte
|
||||
if test.passCerts {
|
||||
if test.passCerts == true {
|
||||
for _, cert := range ts.TLS.Certificates {
|
||||
for _, c := range cert.Certificate {
|
||||
parsedCert, err := x509.ParseCertificate(c)
|
||||
@@ -289,9 +289,9 @@ func TestListPullRequestTLS(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
svc, err := NewBitbucketServiceBasicAuth(t.Context(), "user", "password", ts.URL, "PROJECT", "REPO", "", test.tlsInsecure, certs)
|
||||
svc, err := NewBitbucketServiceBasicAuth(context.Background(), "user", "password", ts.URL, "PROJECT", "REPO", "", test.tlsInsecure, certs)
|
||||
require.NoError(t, err)
|
||||
_, err = ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
_, err = ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
if test.requireErr {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
@@ -302,12 +302,12 @@ func TestListPullRequestTLS(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestListResponseError(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}))
|
||||
defer ts.Close()
|
||||
svc, _ := NewBitbucketServiceNoAuth(t.Context(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
_, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
svc, _ := NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
_, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
@@ -331,8 +331,8 @@ func TestListResponseMalformed(t *testing.T) {
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
svc, _ := NewBitbucketServiceNoAuth(t.Context(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
_, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
svc, _ := NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
_, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
@@ -356,9 +356,9 @@ func TestListResponseEmpty(t *testing.T) {
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
svc, err := NewBitbucketServiceNoAuth(t.Context(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
svc, err := NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.NoError(t, err)
|
||||
assert.Empty(t, pullRequests)
|
||||
}
|
||||
@@ -452,9 +452,9 @@ func TestListPullRequestBranchMatch(t *testing.T) {
|
||||
}))
|
||||
defer ts.Close()
|
||||
regexp := `feature-1[\d]{2}`
|
||||
svc, err := NewBitbucketServiceNoAuth(t.Context(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
svc, err := NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{
|
||||
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{
|
||||
{
|
||||
BranchMatch: ®exp,
|
||||
},
|
||||
@@ -481,9 +481,9 @@ func TestListPullRequestBranchMatch(t *testing.T) {
|
||||
}, *pullRequests[1])
|
||||
|
||||
regexp = `.*2$`
|
||||
svc, err = NewBitbucketServiceNoAuth(t.Context(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
svc, err = NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
pullRequests, err = ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{
|
||||
pullRequests, err = ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{
|
||||
{
|
||||
BranchMatch: ®exp,
|
||||
},
|
||||
@@ -501,9 +501,9 @@ func TestListPullRequestBranchMatch(t *testing.T) {
|
||||
}, *pullRequests[0])
|
||||
|
||||
regexp = `[\d{2}`
|
||||
svc, err = NewBitbucketServiceNoAuth(t.Context(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
svc, err = NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
_, err = ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{
|
||||
_, err = ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{
|
||||
{
|
||||
BranchMatch: ®exp,
|
||||
},
|
||||
|
||||
@@ -18,6 +18,6 @@ func NewFakeService(_ context.Context, listPullReuests []*PullRequest, listError
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (g *FakeService) List(_ context.Context) ([]*PullRequest, error) {
|
||||
func (g *FakeService) List(ctx context.Context) ([]*PullRequest, error) {
|
||||
return g.listPullReuests, g.listError
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ type GiteaService struct {
|
||||
|
||||
var _ PullRequestService = (*GiteaService)(nil)
|
||||
|
||||
func NewGiteaService(token, url, owner, repo string, insecure bool) (PullRequestService, error) {
|
||||
func NewGiteaService(ctx context.Context, token, url, owner, repo string, insecure bool) (PullRequestService, error) {
|
||||
if token == "" {
|
||||
token = os.Getenv("GITEA_TOKEN")
|
||||
}
|
||||
@@ -49,7 +49,6 @@ func (g *GiteaService) List(ctx context.Context) ([]*PullRequest, error) {
|
||||
opts := gitea.ListPullRequestsOptions{
|
||||
State: gitea.StateOpen,
|
||||
}
|
||||
g.client.SetContext(ctx)
|
||||
prs, _, err := g.client.ListRepoPullRequests(g.owner, g.repo, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package pull_request
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
@@ -13,7 +14,6 @@ import (
|
||||
)
|
||||
|
||||
func giteaMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
|
||||
t.Helper()
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Println(r.RequestURI)
|
||||
@@ -250,9 +250,9 @@ func TestGiteaList(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
giteaMockHandler(t)(w, r)
|
||||
}))
|
||||
host, err := NewGiteaService("", ts.URL, "test-argocd", "pr-test", false)
|
||||
host, err := NewGiteaService(context.Background(), "", ts.URL, "test-argocd", "pr-test", false)
|
||||
require.NoError(t, err)
|
||||
prs, err := host.List(t.Context())
|
||||
prs, err := host.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, prs, 1)
|
||||
assert.Equal(t, 1, prs[0].Number)
|
||||
|
||||
@@ -3,10 +3,10 @@ package pull_request
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/google/go-github/v66/github"
|
||||
"github.com/google/go-github/v63/github"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
type GithubService struct {
|
||||
@@ -18,15 +18,21 @@ type GithubService struct {
|
||||
|
||||
var _ PullRequestService = (*GithubService)(nil)
|
||||
|
||||
func NewGithubService(token, url, owner, repo string, labels []string) (PullRequestService, error) {
|
||||
func NewGithubService(ctx context.Context, token, url, owner, repo string, labels []string) (PullRequestService, error) {
|
||||
var ts oauth2.TokenSource
|
||||
// Undocumented environment variable to set a default token, to be used in testing to dodge anonymous rate limits.
|
||||
if token == "" {
|
||||
token = os.Getenv("GITHUB_TOKEN")
|
||||
}
|
||||
httpClient := &http.Client{}
|
||||
if token != "" {
|
||||
ts = oauth2.StaticTokenSource(
|
||||
&oauth2.Token{AccessToken: token},
|
||||
)
|
||||
}
|
||||
httpClient := oauth2.NewClient(ctx, ts)
|
||||
var client *github.Client
|
||||
if url == "" {
|
||||
client = github.NewClient(httpClient).WithAuthToken(token)
|
||||
client = github.NewClient(httpClient)
|
||||
} else {
|
||||
var err error
|
||||
client, err = github.NewClient(httpClient).WithEnterpriseURLs(url, url)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package pull_request
|
||||
|
||||
import (
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/services/github_app_auth"
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/services/internal/github_app"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/services/github_app_auth"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/services/internal/github_app"
|
||||
)
|
||||
|
||||
func NewGithubAppService(g github_app_auth.Authentication, url, owner, repo string, labels []string) (PullRequestService, error) {
|
||||
|
||||
@@ -3,8 +3,8 @@ package pull_request
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-github/v66/github"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/google/go-github/v63/github"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func toPtr(s string) *string {
|
||||
@@ -52,8 +52,9 @@ func TestContainLabels(t *testing.T) {
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.Name, func(t *testing.T) {
|
||||
got := containLabels(c.Labels, c.PullLabels)
|
||||
require.Equal(t, got, c.Expect)
|
||||
if got := containLabels(c.Labels, c.PullLabels); got != c.Expect {
|
||||
t.Errorf("expect: %v, got: %v", c.Expect, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -82,7 +83,7 @@ func TestGetGitHubPRLabelNames(t *testing.T) {
|
||||
for _, test := range Tests {
|
||||
t.Run(test.Name, func(t *testing.T) {
|
||||
labels := getGithubPRLabelNames(test.PullLabels)
|
||||
require.Equal(t, test.ExpectedResult, labels)
|
||||
assert.Equal(t, test.ExpectedResult, labels)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,9 +7,9 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/hashicorp/go-retryablehttp"
|
||||
gitlab "gitlab.com/gitlab-org/api/client-go"
|
||||
gitlab "github.com/xanzy/go-gitlab"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/utils"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/utils"
|
||||
)
|
||||
|
||||
type GitLabService struct {
|
||||
@@ -21,7 +21,7 @@ type GitLabService struct {
|
||||
|
||||
var _ PullRequestService = (*GitLabService)(nil)
|
||||
|
||||
func NewGitLabService(token, url, project string, labels []string, pullRequestState string, scmRootCAPath string, insecure bool, caCerts []byte) (PullRequestService, error) {
|
||||
func NewGitLabService(ctx context.Context, token, url, project string, labels []string, pullRequestState string, scmRootCAPath string, insecure bool, caCerts []byte) (PullRequestService, error) {
|
||||
var clientOptionFns []gitlab.ClientOptionFunc
|
||||
|
||||
// Set a custom Gitlab base URL if one is provided
|
||||
@@ -74,7 +74,7 @@ func (g *GitLabService) List(ctx context.Context) ([]*PullRequest, error) {
|
||||
|
||||
pullRequests := []*PullRequest{}
|
||||
for {
|
||||
mrs, resp, err := g.client.MergeRequests.ListProjectMergeRequests(g.project, opts, gitlab.WithContext(ctx))
|
||||
mrs, resp, err := g.client.MergeRequests.ListProjectMergeRequests(g.project, opts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error listing merge requests for project '%s': %w", g.project, err)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package pull_request
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"io"
|
||||
@@ -14,12 +15,14 @@ import (
|
||||
)
|
||||
|
||||
func writeMRListResponse(t *testing.T, w io.Writer) {
|
||||
t.Helper()
|
||||
f, err := os.Open("fixtures/gitlab_mr_list_response.json")
|
||||
require.NoErrorf(t, err, "error opening fixture file: %v", err)
|
||||
if err != nil {
|
||||
t.Fatalf("error opening fixture file: %v", err)
|
||||
}
|
||||
|
||||
_, err = io.Copy(w, f)
|
||||
require.NoErrorf(t, err, "error writing response: %v", err)
|
||||
if _, err = io.Copy(w, f); err != nil {
|
||||
t.Fatalf("error writing response: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGitLabServiceCustomBaseURL(t *testing.T) {
|
||||
@@ -34,10 +37,10 @@ func TestGitLabServiceCustomBaseURL(t *testing.T) {
|
||||
writeMRListResponse(t, w)
|
||||
})
|
||||
|
||||
svc, err := NewGitLabService("", server.URL, "278964", nil, "", "", false, nil)
|
||||
svc, err := NewGitLabService(context.Background(), "", server.URL, "278964", nil, "", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = svc.List(t.Context())
|
||||
_, err = svc.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
@@ -53,10 +56,10 @@ func TestGitLabServiceToken(t *testing.T) {
|
||||
writeMRListResponse(t, w)
|
||||
})
|
||||
|
||||
svc, err := NewGitLabService("token-123", server.URL, "278964", nil, "", "", false, nil)
|
||||
svc, err := NewGitLabService(context.Background(), "token-123", server.URL, "278964", nil, "", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = svc.List(t.Context())
|
||||
_, err = svc.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
@@ -72,10 +75,10 @@ func TestList(t *testing.T) {
|
||||
writeMRListResponse(t, w)
|
||||
})
|
||||
|
||||
svc, err := NewGitLabService("", server.URL, "278964", []string{}, "", "", false, nil)
|
||||
svc, err := NewGitLabService(context.Background(), "", server.URL, "278964", []string{}, "", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
prs, err := svc.List(t.Context())
|
||||
prs, err := svc.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, prs, 1)
|
||||
assert.Equal(t, 15442, prs[0].Number)
|
||||
@@ -98,10 +101,10 @@ func TestListWithLabels(t *testing.T) {
|
||||
writeMRListResponse(t, w)
|
||||
})
|
||||
|
||||
svc, err := NewGitLabService("", server.URL, "278964", []string{"feature", "ready"}, "", "", false, nil)
|
||||
svc, err := NewGitLabService(context.Background(), "", server.URL, "278964", []string{"feature", "ready"}, "", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = svc.List(t.Context())
|
||||
_, err = svc.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
@@ -117,10 +120,10 @@ func TestListWithState(t *testing.T) {
|
||||
writeMRListResponse(t, w)
|
||||
})
|
||||
|
||||
svc, err := NewGitLabService("", server.URL, "278964", []string{}, "opened", "", false, nil)
|
||||
svc, err := NewGitLabService(context.Background(), "", server.URL, "278964", []string{}, "opened", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = svc.List(t.Context())
|
||||
_, err = svc.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
@@ -160,13 +163,13 @@ func TestListWithStateTLS(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
writeMRListResponse(t, w)
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
var certs []byte
|
||||
if test.passCerts {
|
||||
if test.passCerts == true {
|
||||
for _, cert := range ts.TLS.Certificates {
|
||||
for _, c := range cert.Certificate {
|
||||
parsedCert, err := x509.ParseCertificate(c)
|
||||
@@ -179,10 +182,10 @@ func TestListWithStateTLS(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
svc, err := NewGitLabService("", ts.URL, "278964", []string{}, "opened", "", test.tlsInsecure, certs)
|
||||
svc, err := NewGitLabService(context.Background(), "", ts.URL, "278964", []string{}, "opened", "", test.tlsInsecure, certs)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = svc.List(t.Context())
|
||||
_, err = svc.List(context.Background())
|
||||
if test.requireErr {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
func compileFilters(filters []argoprojiov1alpha1.PullRequestGeneratorFilter) ([]*Filter, error) {
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package pull_request
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
func strp(s string) *string {
|
||||
@@ -15,7 +16,7 @@ func strp(s string) *string {
|
||||
|
||||
func TestFilterBranchMatchBadRegexp(t *testing.T) {
|
||||
provider, _ := NewFakeService(
|
||||
t.Context(),
|
||||
context.Background(),
|
||||
[]*PullRequest{
|
||||
{
|
||||
Number: 1,
|
||||
@@ -33,13 +34,13 @@ func TestFilterBranchMatchBadRegexp(t *testing.T) {
|
||||
BranchMatch: strp("("),
|
||||
},
|
||||
}
|
||||
_, err := ListPullRequests(t.Context(), provider, filters)
|
||||
_, err := ListPullRequests(context.Background(), provider, filters)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestFilterBranchMatch(t *testing.T) {
|
||||
provider, _ := NewFakeService(
|
||||
t.Context(),
|
||||
context.Background(),
|
||||
[]*PullRequest{
|
||||
{
|
||||
Number: 1,
|
||||
@@ -81,7 +82,7 @@ func TestFilterBranchMatch(t *testing.T) {
|
||||
BranchMatch: strp("w"),
|
||||
},
|
||||
}
|
||||
pullRequests, err := ListPullRequests(t.Context(), provider, filters)
|
||||
pullRequests, err := ListPullRequests(context.Background(), provider, filters)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 1)
|
||||
assert.Equal(t, "two", pullRequests[0].Branch)
|
||||
@@ -89,7 +90,7 @@ func TestFilterBranchMatch(t *testing.T) {
|
||||
|
||||
func TestFilterTargetBranchMatch(t *testing.T) {
|
||||
provider, _ := NewFakeService(
|
||||
t.Context(),
|
||||
context.Background(),
|
||||
[]*PullRequest{
|
||||
{
|
||||
Number: 1,
|
||||
@@ -131,7 +132,7 @@ func TestFilterTargetBranchMatch(t *testing.T) {
|
||||
TargetBranchMatch: strp("1"),
|
||||
},
|
||||
}
|
||||
pullRequests, err := ListPullRequests(t.Context(), provider, filters)
|
||||
pullRequests, err := ListPullRequests(context.Background(), provider, filters)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 1)
|
||||
assert.Equal(t, "two", pullRequests[0].Branch)
|
||||
@@ -139,7 +140,7 @@ func TestFilterTargetBranchMatch(t *testing.T) {
|
||||
|
||||
func TestMultiFilterOr(t *testing.T) {
|
||||
provider, _ := NewFakeService(
|
||||
t.Context(),
|
||||
context.Background(),
|
||||
[]*PullRequest{
|
||||
{
|
||||
Number: 1,
|
||||
@@ -184,7 +185,7 @@ func TestMultiFilterOr(t *testing.T) {
|
||||
BranchMatch: strp("r"),
|
||||
},
|
||||
}
|
||||
pullRequests, err := ListPullRequests(t.Context(), provider, filters)
|
||||
pullRequests, err := ListPullRequests(context.Background(), provider, filters)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 3)
|
||||
assert.Equal(t, "two", pullRequests[0].Branch)
|
||||
@@ -194,7 +195,7 @@ func TestMultiFilterOr(t *testing.T) {
|
||||
|
||||
func TestMultiFilterOrWithTargetBranchFilter(t *testing.T) {
|
||||
provider, _ := NewFakeService(
|
||||
t.Context(),
|
||||
context.Background(),
|
||||
[]*PullRequest{
|
||||
{
|
||||
Number: 1,
|
||||
@@ -241,7 +242,7 @@ func TestMultiFilterOrWithTargetBranchFilter(t *testing.T) {
|
||||
TargetBranchMatch: strp("3"),
|
||||
},
|
||||
}
|
||||
pullRequests, err := ListPullRequests(t.Context(), provider, filters)
|
||||
pullRequests, err := ListPullRequests(context.Background(), provider, filters)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 2)
|
||||
assert.Equal(t, "two", pullRequests[0].Branch)
|
||||
@@ -250,7 +251,7 @@ func TestMultiFilterOrWithTargetBranchFilter(t *testing.T) {
|
||||
|
||||
func TestNoFilters(t *testing.T) {
|
||||
provider, _ := NewFakeService(
|
||||
t.Context(),
|
||||
context.Background(),
|
||||
[]*PullRequest{
|
||||
{
|
||||
Number: 1,
|
||||
@@ -272,7 +273,7 @@ func TestNoFilters(t *testing.T) {
|
||||
nil,
|
||||
)
|
||||
filters := []argoprojiov1alpha1.PullRequestGeneratorFilter{}
|
||||
repos, err := ListPullRequests(t.Context(), provider, filters)
|
||||
repos, err := ListPullRequests(context.Background(), provider, filters)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, repos, 2)
|
||||
assert.Equal(t, "one", repos[0].Branch)
|
||||
|
||||
@@ -4,54 +4,39 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"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/db"
|
||||
"github.com/argoproj/argo-cd/v3/util/io"
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/reposerver/apiclient"
|
||||
"github.com/argoproj/argo-cd/v2/util/git"
|
||||
"github.com/argoproj/argo-cd/v2/util/io"
|
||||
)
|
||||
|
||||
type argoCDService struct {
|
||||
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)
|
||||
getRepository func(ctx context.Context, url, project string) (*v1alpha1.Repository, error)
|
||||
storecreds git.CredsStore
|
||||
submoduleEnabled bool
|
||||
repoServerClientSet apiclient.Clientset
|
||||
newFileGlobbingEnabled bool
|
||||
}
|
||||
|
||||
type Repos interface {
|
||||
// GetFiles returns content of files (not directories) within the target repo
|
||||
GetFiles(ctx context.Context, repoURL, revision, project, pattern string, noRevisionCache, verifyCommit bool) (map[string][]byte, error)
|
||||
GetFiles(ctx context.Context, repoURL string, revision string, 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, revision, project string, noRevisionCache, verifyCommit bool) ([]string, error)
|
||||
GetDirectories(ctx context.Context, repoURL string, revision string, noRevisionCache, verifyCommit bool) ([]string, error)
|
||||
}
|
||||
|
||||
func NewArgoCDService(db db.ArgoDB, submoduleEnabled bool, repoClientset apiclient.Clientset, newFileGlobbingEnabled bool) Repos {
|
||||
func NewArgoCDService(getRepository func(ctx context.Context, url, project string) (*v1alpha1.Repository, error), submoduleEnabled bool, repoClientset apiclient.Clientset, newFileGlobbingEnabled bool) (Repos, error) {
|
||||
return &argoCDService{
|
||||
getRepository: db.GetRepository,
|
||||
getRepository: getRepository,
|
||||
submoduleEnabled: submoduleEnabled,
|
||||
repoServerClientSet: repoClientset,
|
||||
newFileGlobbingEnabled: newFileGlobbingEnabled,
|
||||
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)
|
||||
},
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
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)
|
||||
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, "")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error in GetRepository: %w", err)
|
||||
}
|
||||
@@ -65,15 +50,21 @@ func (a *argoCDService) GetFiles(ctx context.Context, repoURL, revision, project
|
||||
NoRevisionCache: noRevisionCache,
|
||||
VerifyCommit: verifyCommit,
|
||||
}
|
||||
fileResponse, err := a.getGitFilesFromRepoServer(ctx, fileRequest)
|
||||
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)
|
||||
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, revision, project string, noRevisionCache, verifyCommit bool) ([]string, error) {
|
||||
repo, err := a.getRepository(ctx, repoURL, project)
|
||||
func (a *argoCDService) GetDirectories(ctx context.Context, repoURL string, revision string, noRevisionCache, verifyCommit bool) ([]string, error) {
|
||||
repo, err := a.getRepository(ctx, repoURL, "")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error in GetRepository: %w", err)
|
||||
}
|
||||
@@ -86,7 +77,13 @@ func (a *argoCDService) GetDirectories(ctx context.Context, repoURL, revision, p
|
||||
VerifyCommit: verifyCommit,
|
||||
}
|
||||
|
||||
dirResponse, err := a.getGitDirectoriesFromRepoServer(ctx, dirRequest)
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error retrieving Git Directories: %w", err)
|
||||
}
|
||||
|
||||
@@ -2,26 +2,26 @@ package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"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/db"
|
||||
"github.com/argoproj/argo-cd/v3/util/settings"
|
||||
"github.com/argoproj/argo-cd/v2/reposerver/apiclient"
|
||||
repo_mocks "github.com/argoproj/argo-cd/v2/reposerver/apiclient/mocks"
|
||||
"github.com/argoproj/argo-cd/v2/util/git"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
func TestGetDirectories(t *testing.T) {
|
||||
type fields struct {
|
||||
submoduleEnabled bool
|
||||
getRepository func(ctx context.Context, url, project string) (*v1alpha1.Repository, error)
|
||||
getGitDirectories func(ctx context.Context, req *apiclient.GitDirectoriesRequest) (*apiclient.GitDirectoriesResponse, error)
|
||||
storecreds git.CredsStore
|
||||
submoduleEnabled bool
|
||||
getRepository func(ctx context.Context, url, project string) (*v1alpha1.Repository, error)
|
||||
repoServerClientFuncs []func(*repo_mocks.RepoServerServiceClient)
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
@@ -38,49 +38,58 @@ func TestGetDirectories(t *testing.T) {
|
||||
wantErr assert.ErrorAssertionFunc
|
||||
}{
|
||||
{name: "ErrorGettingRepos", fields: fields{
|
||||
getRepository: func(_ context.Context, _, _ string) (*v1alpha1.Repository, error) {
|
||||
return nil, errors.New("unable to get repos")
|
||||
getRepository: func(ctx context.Context, url, project string) (*v1alpha1.Repository, error) {
|
||||
return nil, fmt.Errorf("unable to get repos")
|
||||
},
|
||||
}, args: args{}, want: nil, wantErr: assert.Error},
|
||||
{name: "ErrorGettingDirs", fields: fields{
|
||||
getRepository: func(_ context.Context, _, _ string) (*v1alpha1.Repository, error) {
|
||||
getRepository: func(ctx context.Context, url, project string) (*v1alpha1.Repository, error) {
|
||||
return &v1alpha1.Repository{}, nil
|
||||
},
|
||||
getGitDirectories: func(_ context.Context, _ *apiclient.GitDirectoriesRequest) (*apiclient.GitDirectoriesResponse, error) {
|
||||
return nil, errors.New("unable to get dirs")
|
||||
repoServerClientFuncs: []func(*repo_mocks.RepoServerServiceClient){
|
||||
func(client *repo_mocks.RepoServerServiceClient) {
|
||||
client.On("GetGitDirectories", mock.Anything, mock.Anything).Return(nil, fmt.Errorf("unable to get dirs"))
|
||||
},
|
||||
},
|
||||
}, args: args{}, want: nil, wantErr: assert.Error},
|
||||
{name: "HappyCase", fields: fields{
|
||||
getRepository: func(_ context.Context, _, _ string) (*v1alpha1.Repository, error) {
|
||||
return &v1alpha1.Repository{
|
||||
Repo: "foo",
|
||||
}, nil
|
||||
},
|
||||
getGitDirectories: func(_ context.Context, _ *apiclient.GitDirectoriesRequest) (*apiclient.GitDirectoriesResponse, error) {
|
||||
return &apiclient.GitDirectoriesResponse{
|
||||
Paths: []string{"foo", "foo/bar", "bar/foo"},
|
||||
}, nil
|
||||
},
|
||||
}, 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) {
|
||||
getRepository: func(ctx context.Context, url, project string) (*v1alpha1.Repository, error) {
|
||||
return &v1alpha1.Repository{}, nil
|
||||
},
|
||||
getGitDirectories: func(_ context.Context, _ *apiclient.GitDirectoriesRequest) (*apiclient.GitDirectoriesResponse, error) {
|
||||
return nil, errors.New("revision HEAD is not signed")
|
||||
repoServerClientFuncs: []func(*repo_mocks.RepoServerServiceClient){
|
||||
func(client *repo_mocks.RepoServerServiceClient) {
|
||||
client.On("GetGitDirectories", mock.Anything, mock.Anything).Return(&apiclient.GitDirectoriesResponse{
|
||||
Paths: []string{"foo", "foo/bar", "bar/foo"},
|
||||
}, nil)
|
||||
},
|
||||
},
|
||||
}, args: args{}, want: []string{"foo", "foo/bar", "bar/foo"}, wantErr: assert.NoError},
|
||||
{name: "ErrorVerifyingCommit", fields: fields{
|
||||
getRepository: func(ctx context.Context, url, project 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, fmt.Errorf("revision HEAD is not signed"))
|
||||
},
|
||||
},
|
||||
}, args: args{}, want: nil, wantErr: assert.Error},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
a := &argoCDService{
|
||||
getRepository: tt.fields.getRepository,
|
||||
submoduleEnabled: tt.fields.submoduleEnabled,
|
||||
getGitDirectoriesFromRepoServer: tt.fields.getGitDirectories,
|
||||
mockRepoClient := &repo_mocks.RepoServerServiceClient{}
|
||||
// decorate the mocks
|
||||
for i := range tt.fields.repoServerClientFuncs {
|
||||
tt.fields.repoServerClientFuncs[i](mockRepoClient)
|
||||
}
|
||||
got, err := a.GetDirectories(tt.args.ctx, tt.args.repoURL, tt.args.revision, "", tt.args.noRevisionCache, tt.args.verifyCommit)
|
||||
|
||||
a := &argoCDService{
|
||||
getRepository: tt.fields.getRepository,
|
||||
storecreds: tt.fields.storecreds,
|
||||
submoduleEnabled: tt.fields.submoduleEnabled,
|
||||
repoServerClientSet: &repo_mocks.Clientset{RepoServerServiceClient: mockRepoClient},
|
||||
}
|
||||
got, err := a.GetDirectories(tt.args.ctx, tt.args.repoURL, tt.args.revision, 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
|
||||
}
|
||||
@@ -91,9 +100,10 @@ func TestGetDirectories(t *testing.T) {
|
||||
|
||||
func TestGetFiles(t *testing.T) {
|
||||
type fields struct {
|
||||
submoduleEnabled bool
|
||||
getRepository func(ctx context.Context, url, project string) (*v1alpha1.Repository, error)
|
||||
getGitFiles func(ctx context.Context, req *apiclient.GitFilesRequest) (*apiclient.GitFilesResponse, error)
|
||||
storecreds git.CredsStore
|
||||
submoduleEnabled bool
|
||||
repoServerClientFuncs []func(*repo_mocks.RepoServerServiceClient)
|
||||
getRepository func(ctx context.Context, url, project string) (*v1alpha1.Repository, error)
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
@@ -111,55 +121,64 @@ func TestGetFiles(t *testing.T) {
|
||||
wantErr assert.ErrorAssertionFunc
|
||||
}{
|
||||
{name: "ErrorGettingRepos", fields: fields{
|
||||
getRepository: func(_ context.Context, _, _ string) (*v1alpha1.Repository, error) {
|
||||
return nil, errors.New("unable to get repos")
|
||||
getRepository: func(ctx context.Context, url, project string) (*v1alpha1.Repository, error) {
|
||||
return nil, fmt.Errorf("unable to get repos")
|
||||
},
|
||||
}, args: args{}, want: nil, wantErr: assert.Error},
|
||||
{name: "ErrorGettingFiles", fields: fields{
|
||||
getRepository: func(_ context.Context, _, _ string) (*v1alpha1.Repository, error) {
|
||||
getRepository: func(ctx context.Context, url, project string) (*v1alpha1.Repository, error) {
|
||||
return &v1alpha1.Repository{}, nil
|
||||
},
|
||||
getGitFiles: func(_ context.Context, _ *apiclient.GitFilesRequest) (*apiclient.GitFilesResponse, error) {
|
||||
return nil, errors.New("unable to get files")
|
||||
repoServerClientFuncs: []func(*repo_mocks.RepoServerServiceClient){
|
||||
func(client *repo_mocks.RepoServerServiceClient) {
|
||||
client.On("GetGitFiles", mock.Anything, mock.Anything).Return(nil, fmt.Errorf("unable to get files"))
|
||||
},
|
||||
},
|
||||
}, args: args{}, want: nil, wantErr: assert.Error},
|
||||
{name: "HappyCase", fields: fields{
|
||||
getRepository: func(_ context.Context, _, _ string) (*v1alpha1.Repository, error) {
|
||||
return &v1alpha1.Repository{
|
||||
Repo: "foo",
|
||||
}, nil
|
||||
getRepository: func(ctx context.Context, url, project string) (*v1alpha1.Repository, error) {
|
||||
return &v1alpha1.Repository{}, 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
|
||||
repoServerClientFuncs: []func(*repo_mocks.RepoServerServiceClient){
|
||||
func(client *repo_mocks.RepoServerServiceClient) {
|
||||
client.On("GetGitFiles", mock.Anything, mock.Anything).Return(&apiclient.GitFilesResponse{
|
||||
Map: map[string][]byte{
|
||||
"foo.json": []byte("hello: world!"),
|
||||
"bar.yaml": []byte("yay: appsets"),
|
||||
},
|
||||
}, nil)
|
||||
},
|
||||
},
|
||||
}, args: args{
|
||||
repoURL: "foo",
|
||||
}, want: map[string][]byte{
|
||||
}, args: args{}, want: map[string][]byte{
|
||||
"foo.json": []byte("hello: world!"),
|
||||
"bar.yaml": []byte("yay: appsets"),
|
||||
}, wantErr: assert.NoError},
|
||||
{name: "ErrorVerifyingCommit", fields: fields{
|
||||
getRepository: func(_ context.Context, _, _ string) (*v1alpha1.Repository, error) {
|
||||
getRepository: func(ctx context.Context, url, project string) (*v1alpha1.Repository, error) {
|
||||
return &v1alpha1.Repository{}, nil
|
||||
},
|
||||
getGitFiles: func(_ context.Context, _ *apiclient.GitFilesRequest) (*apiclient.GitFilesResponse, error) {
|
||||
return nil, errors.New("revision HEAD is not signed")
|
||||
repoServerClientFuncs: []func(*repo_mocks.RepoServerServiceClient){
|
||||
func(client *repo_mocks.RepoServerServiceClient) {
|
||||
client.On("GetGitFiles", mock.Anything, mock.Anything).Return(nil, fmt.Errorf("revision HEAD is not signed"))
|
||||
},
|
||||
},
|
||||
}, args: args{}, want: nil, wantErr: assert.Error},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
a := &argoCDService{
|
||||
getRepository: tt.fields.getRepository,
|
||||
submoduleEnabled: tt.fields.submoduleEnabled,
|
||||
getGitFilesFromRepoServer: tt.fields.getGitFiles,
|
||||
mockRepoClient := &repo_mocks.RepoServerServiceClient{}
|
||||
// decorate the mocks
|
||||
for i := range tt.fields.repoServerClientFuncs {
|
||||
tt.fields.repoServerClientFuncs[i](mockRepoClient)
|
||||
}
|
||||
got, err := a.GetFiles(tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.pattern, "", tt.args.noRevisionCache, tt.args.verifyCommit)
|
||||
|
||||
a := &argoCDService{
|
||||
getRepository: tt.fields.getRepository,
|
||||
storecreds: tt.fields.storecreds,
|
||||
submoduleEnabled: tt.fields.submoduleEnabled,
|
||||
repoServerClientSet: &repo_mocks.Clientset{RepoServerServiceClient: mockRepoClient},
|
||||
}
|
||||
got, err := a.GetFiles(tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.pattern, 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
|
||||
}
|
||||
@@ -169,9 +188,9 @@ func TestGetFiles(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNewArgoCDService(t *testing.T) {
|
||||
testNamespace := "test"
|
||||
clientset := fake.NewClientset()
|
||||
testDB := db.NewDB(testNamespace, settings.NewSettingsManager(t.Context(), clientset, testNamespace), clientset)
|
||||
service := NewArgoCDService(testDB, false, &repo_mocks.Clientset{}, false)
|
||||
service, err := NewArgoCDService(func(ctx context.Context, url, project string) (*v1alpha1.Repository, error) {
|
||||
return &v1alpha1.Repository{}, nil
|
||||
}, false, &repo_mocks.Clientset{}, false)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, service)
|
||||
}
|
||||
|
||||
@@ -21,13 +21,13 @@ import (
|
||||
"golang.org/x/exp/maps"
|
||||
"k8s.io/utils/strings/slices"
|
||||
|
||||
application "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
application "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
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.52.4. DO NOT EDIT.
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.52.4. DO NOT EDIT.
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package scm_provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sort"
|
||||
"testing"
|
||||
@@ -12,8 +13,8 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/services/scm_provider/aws_codecommit/mocks"
|
||||
"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/services/scm_provider/aws_codecommit/mocks"
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
type awsCodeCommitTestRepository struct {
|
||||
@@ -22,7 +23,7 @@ type awsCodeCommitTestRepository struct {
|
||||
arn string
|
||||
accountId string
|
||||
defaultBranch string
|
||||
expectedCloneURL string
|
||||
expectedCloneUrl string
|
||||
getRepositoryError error
|
||||
getRepositoryNilMetadata bool
|
||||
valid bool
|
||||
@@ -48,7 +49,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,
|
||||
},
|
||||
},
|
||||
@@ -73,7 +74,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,
|
||||
},
|
||||
},
|
||||
@@ -95,7 +96,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,
|
||||
},
|
||||
{
|
||||
@@ -159,7 +160,7 @@ func TestAWSCodeCommitListRepos(t *testing.T) {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
codeCommitClient := mocks.NewAWSCodeCommitClient(t)
|
||||
taggingClient := mocks.NewAWSTaggingClient(t)
|
||||
ctx := t.Context()
|
||||
ctx := context.Background()
|
||||
codecommitRepoNameIdPairs := make([]*codecommit.RepositoryNameIdPair, 0)
|
||||
resourceTaggings := make([]*resourcegroupstaggingapi.ResourceTagMapping, 0)
|
||||
validRepositories := make([]*awsCodeCommitTestRepository, 0)
|
||||
@@ -225,7 +226,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")
|
||||
}
|
||||
}
|
||||
@@ -348,7 +349,7 @@ func TestAWSCodeCommitRepoHasPath(t *testing.T) {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
codeCommitClient := mocks.NewAWSCodeCommitClient(t)
|
||||
taggingClient := mocks.NewAWSTaggingClient(t)
|
||||
ctx := t.Context()
|
||||
ctx := context.Background()
|
||||
if testCase.expectedGetFolderPath != "" {
|
||||
codeCommitClient.
|
||||
On("GetFolderWithContext", ctx, &codecommit.GetFolderInput{
|
||||
@@ -381,7 +382,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
|
||||
@@ -421,7 +422,7 @@ func TestAWSCodeCommitGetBranches(t *testing.T) {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
codeCommitClient := mocks.NewAWSCodeCommitClient(t)
|
||||
taggingClient := mocks.NewAWSTaggingClient(t)
|
||||
ctx := t.Context()
|
||||
ctx := context.Background()
|
||||
if testCase.allBranches {
|
||||
codeCommitClient.
|
||||
On("ListBranchesWithContext", ctx, &codecommit.ListBranchesInput{
|
||||
@@ -444,7 +445,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 {
|
||||
@@ -453,7 +454,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)
|
||||
}
|
||||
|
||||
@@ -57,9 +57,9 @@ var (
|
||||
_ AzureDevOpsClientFactory = &devopsFactoryImpl{}
|
||||
)
|
||||
|
||||
func NewAzureDevOpsProvider(accessToken string, org string, url string, project string, allBranches bool) (*AzureDevOpsProvider, error) {
|
||||
func NewAzureDevOpsProvider(ctx context.Context, accessToken string, org string, url string, project string, allBranches bool) (*AzureDevOpsProvider, error) {
|
||||
if accessToken == "" {
|
||||
return nil, errors.New("no access token provided")
|
||||
return nil, fmt.Errorf("no access token provided")
|
||||
}
|
||||
|
||||
devOpsURL, err := getValidDevOpsURL(url, org)
|
||||
@@ -72,7 +72,7 @@ func NewAzureDevOpsProvider(accessToken string, org string, url string, project
|
||||
return &AzureDevOpsProvider{organization: org, teamProject: project, accessToken: accessToken, clientFactory: &devopsFactoryImpl{connection: connection}, allBranches: allBranches}, nil
|
||||
}
|
||||
|
||||
func (g *AzureDevOpsProvider) ListRepos(ctx context.Context, _ string) ([]*Repository, error) {
|
||||
func (g *AzureDevOpsProvider) ListRepos(ctx context.Context, cloneProtocol string) ([]*Repository, error) {
|
||||
gitClient, err := g.clientFactory.GetClient(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get Azure DevOps client: %w", err)
|
||||
@@ -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.52.4. DO NOT EDIT.
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ package scm_provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
@@ -15,7 +14,7 @@ import (
|
||||
"github.com/microsoft/azure-devops-go-api/azuredevops"
|
||||
azureGit "github.com/microsoft/azure-devops-go-api/azuredevops/git"
|
||||
|
||||
azureMock "github.com/argoproj/argo-cd/v3/applicationset/services/scm_provider/azure_devops/git/mocks"
|
||||
azureMock "github.com/argoproj/argo-cd/v2/applicationset/services/scm_provider/azure_devops/git/mocks"
|
||||
)
|
||||
|
||||
func s(input string) *string {
|
||||
@@ -29,7 +28,7 @@ func TestAzureDevopsRepoHasPath(t *testing.T) {
|
||||
path := "dir/subdir/item.yaml"
|
||||
branchName := "my/featurebranch"
|
||||
|
||||
ctx := t.Context()
|
||||
ctx := context.Background()
|
||||
uuid := uuid.New().String()
|
||||
|
||||
testCases := []struct {
|
||||
@@ -42,7 +41,7 @@ func TestAzureDevopsRepoHasPath(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "RepoHasPath when Azure DevOps client factory fails returns error",
|
||||
clientError: errors.New("Client factory error"),
|
||||
clientError: fmt.Errorf("Client factory error"),
|
||||
},
|
||||
{
|
||||
name: "RepoHasPath when found returns true",
|
||||
@@ -63,7 +62,7 @@ func TestAzureDevopsRepoHasPath(t *testing.T) {
|
||||
{
|
||||
name: "RepoHasPath when unknown Azure DevOps error occurs returns error",
|
||||
pathFound: false,
|
||||
azureDevopsError: errors.New("Undefined error from Azure Devops"),
|
||||
azureDevopsError: fmt.Errorf("Undefined error from Azure Devops"),
|
||||
returnError: true,
|
||||
errorMessage: "failed to check for path existence",
|
||||
},
|
||||
@@ -115,7 +114,7 @@ func TestGetDefaultBranchOnDisabledRepo(t *testing.T) {
|
||||
repoName := "myorg_project_repo"
|
||||
defaultBranch := "main"
|
||||
|
||||
ctx := t.Context()
|
||||
ctx := context.Background()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
@@ -134,7 +133,7 @@ func TestGetDefaultBranchOnDisabledRepo(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "other error when calling azure devops returns error",
|
||||
azureDevOpsError: errors.New("some unknown error"),
|
||||
azureDevOpsError: fmt.Errorf("some unknown error"),
|
||||
shouldReturnError: true,
|
||||
},
|
||||
}
|
||||
@@ -174,7 +173,7 @@ func TestGetAllBranchesOnDisabledRepo(t *testing.T) {
|
||||
repoName := "myorg_project_repo"
|
||||
defaultBranch := "main"
|
||||
|
||||
ctx := t.Context()
|
||||
ctx := context.Background()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
@@ -193,7 +192,7 @@ func TestGetAllBranchesOnDisabledRepo(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "other error when calling azure devops returns error",
|
||||
azureDevOpsError: errors.New("some unknown error"),
|
||||
azureDevOpsError: fmt.Errorf("some unknown error"),
|
||||
shouldReturnError: true,
|
||||
},
|
||||
}
|
||||
@@ -233,7 +232,7 @@ func TestAzureDevOpsGetDefaultBranchStripsRefsName(t *testing.T) {
|
||||
teamProject := "myorg_project"
|
||||
repoName := "myorg_project_repo"
|
||||
|
||||
ctx := t.Context()
|
||||
ctx := context.Background()
|
||||
uuid := uuid.New().String()
|
||||
strippedBranchName := "somebranch"
|
||||
defaultBranch := fmt.Sprintf("refs/heads/%v", strippedBranchName)
|
||||
@@ -264,7 +263,7 @@ func TestAzureDevOpsGetBranchesDefultBranchOnly(t *testing.T) {
|
||||
teamProject := "myorg_project"
|
||||
repoName := "myorg_project_repo"
|
||||
|
||||
ctx := t.Context()
|
||||
ctx := context.Background()
|
||||
uuid := uuid.New().String()
|
||||
|
||||
defaultBranch := "main"
|
||||
@@ -272,7 +271,7 @@ func TestAzureDevOpsGetBranchesDefultBranchOnly(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
expectedBranch *azureGit.GitBranchStats
|
||||
getBranchesAPIError error
|
||||
getBranchesApiError error
|
||||
clientError error
|
||||
}{
|
||||
{
|
||||
@@ -281,11 +280,11 @@ 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: fmt.Errorf("Remote Azure Devops GetBranches error"),
|
||||
},
|
||||
{
|
||||
name: "GetBranches AllBranches false when Azure DevOps client fails returns error",
|
||||
clientError: errors.New("Could not get Azure Devops API client"),
|
||||
clientError: fmt.Errorf("Could not get Azure Devops API client"),
|
||||
},
|
||||
{
|
||||
name: "GetBranches AllBranches false when branch returned with long commit SHA",
|
||||
@@ -300,7 +299,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 +313,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 +334,13 @@ func TestAzureDevopsGetBranches(t *testing.T) {
|
||||
teamProject := "myorg_project"
|
||||
repoName := "myorg_project_repo"
|
||||
|
||||
ctx := t.Context()
|
||||
ctx := context.Background()
|
||||
uuid := uuid.New().String()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
expectedBranches *[]azureGit.GitBranchStats
|
||||
getBranchesAPIError error
|
||||
getBranchesApiError error
|
||||
clientError error
|
||||
allBranches bool
|
||||
expectedProcessingErrorMsg string
|
||||
@@ -353,7 +352,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: fmt.Errorf("Remote Azure Devops GetBranches error"),
|
||||
allBranches: true,
|
||||
},
|
||||
{
|
||||
@@ -363,7 +362,7 @@ func TestAzureDevopsGetBranches(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "GetBranches when git client retrievel fails returns error",
|
||||
clientError: errors.New("Could not get Azure Devops API client"),
|
||||
clientError: fmt.Errorf("Could not get Azure Devops API client"),
|
||||
allBranches: true,
|
||||
},
|
||||
{
|
||||
@@ -384,7 +383,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 +402,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 +426,7 @@ func TestGetAzureDevopsRepositories(t *testing.T) {
|
||||
teamProject := "myorg_project"
|
||||
|
||||
uuid := uuid.New()
|
||||
ctx := t.Context()
|
||||
ctx := context.Background()
|
||||
|
||||
repoId := &uuid
|
||||
|
||||
@@ -448,7 +447,7 @@ func TestGetAzureDevopsRepositories(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "ListRepos when Azure DevOps request fails returns error",
|
||||
getRepositoriesError: errors.New("Could not get repos"),
|
||||
getRepositoriesError: fmt.Errorf("Could not get repos"),
|
||||
},
|
||||
{
|
||||
name: "ListRepos when repo has no name returns empty list",
|
||||
|
||||
@@ -2,7 +2,6 @@ package scm_provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
@@ -52,7 +51,7 @@ func (c *ExtendedClient) GetContents(repo *Repository, path string) (bool, error
|
||||
|
||||
var _ SCMProviderService = &BitBucketCloudProvider{}
|
||||
|
||||
func NewBitBucketCloudProvider(owner string, user string, password string, allBranches bool) (*BitBucketCloudProvider, error) {
|
||||
func NewBitBucketCloudProvider(ctx context.Context, owner string, user string, password string, allBranches bool) (*BitBucketCloudProvider, error) {
|
||||
client := &ExtendedClient{
|
||||
bitbucket.NewBasicAuth(user, password),
|
||||
user,
|
||||
@@ -62,7 +61,7 @@ func NewBitBucketCloudProvider(owner string, user string, password string, allBr
|
||||
return &BitBucketCloudProvider{client: client, owner: owner, allBranches: allBranches}, nil
|
||||
}
|
||||
|
||||
func (g *BitBucketCloudProvider) GetBranches(_ context.Context, repo *Repository) ([]*Repository, error) {
|
||||
func (g *BitBucketCloudProvider) GetBranches(ctx context.Context, repo *Repository) ([]*Repository, error) {
|
||||
repos := []*Repository{}
|
||||
branches, err := g.listBranches(repo)
|
||||
if err != nil {
|
||||
@@ -87,7 +86,7 @@ func (g *BitBucketCloudProvider) GetBranches(_ context.Context, repo *Repository
|
||||
return repos, nil
|
||||
}
|
||||
|
||||
func (g *BitBucketCloudProvider) ListRepos(_ context.Context, cloneProtocol string) ([]*Repository, error) {
|
||||
func (g *BitBucketCloudProvider) ListRepos(ctx context.Context, cloneProtocol string) ([]*Repository, error) {
|
||||
if cloneProtocol == "" {
|
||||
cloneProtocol = "ssh"
|
||||
}
|
||||
@@ -101,7 +100,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 +108,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,
|
||||
})
|
||||
@@ -117,7 +116,7 @@ func (g *BitBucketCloudProvider) ListRepos(_ context.Context, cloneProtocol stri
|
||||
return repos, nil
|
||||
}
|
||||
|
||||
func (g *BitBucketCloudProvider) RepoHasPath(_ context.Context, repo *Repository, path string) (bool, error) {
|
||||
func (g *BitBucketCloudProvider) RepoHasPath(ctx context.Context, repo *Repository, path string) (bool, error) {
|
||||
contents, err := g.client.GetContents(repo, path)
|
||||
if err != nil {
|
||||
return false, err
|
||||
@@ -154,19 +153,19 @@ func (g *BitBucketCloudProvider) listBranches(repo *Repository) ([]bitbucket.Rep
|
||||
}
|
||||
|
||||
func findCloneURL(cloneProtocol string, repo *bitbucket.Repository) (*string, error) {
|
||||
cloneLinks, ok := repo.Links["clone"].([]any)
|
||||
cloneLinks, ok := repo.Links["clone"].([]interface{})
|
||||
if !ok {
|
||||
return nil, errors.New("unknown type returned from repo links")
|
||||
return nil, fmt.Errorf("unknown type returned from repo links")
|
||||
}
|
||||
for _, link := range cloneLinks {
|
||||
linkEntry, ok := link.(map[string]any)
|
||||
linkEntry, ok := link.(map[string]interface{})
|
||||
if !ok {
|
||||
return nil, errors.New("unknown type returned from clone link")
|
||||
return nil, fmt.Errorf("unknown type returned from clone link")
|
||||
}
|
||||
if linkEntry["name"] == cloneProtocol {
|
||||
url, ok := linkEntry["href"].(string)
|
||||
if !ok {
|
||||
return nil, errors.New("could not find href for clone link")
|
||||
return nil, fmt.Errorf("could not find href for clone link")
|
||||
}
|
||||
return &url, nil
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package scm_provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@@ -9,7 +10,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
func TestBitbucketHasRepo(t *testing.T) {
|
||||
@@ -86,14 +87,14 @@ func TestBitbucketHasRepo(t *testing.T) {
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
provider, _ := NewBitBucketCloudProvider(c.owner, "user", "password", false)
|
||||
provider, _ := NewBitBucketCloudProvider(context.Background(), c.owner, "user", "password", false)
|
||||
repo := &Repository{
|
||||
Organization: c.owner,
|
||||
Repository: c.repo,
|
||||
SHA: c.sha,
|
||||
Branch: "main",
|
||||
}
|
||||
hasPath, err := provider.RepoHasPath(t.Context(), repo, c.path)
|
||||
hasPath, err := provider.RepoHasPath(context.Background(), repo, c.path)
|
||||
if err != nil {
|
||||
require.Error(t, fmt.Errorf("Error in test %w", err))
|
||||
}
|
||||
@@ -486,8 +487,8 @@ 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(t.Context(), provider, c.filters, c.proto)
|
||||
provider, _ := NewBitBucketCloudProvider(context.Background(), c.owner, "user", "password", c.allBranches)
|
||||
rawRepos, err := ListRepos(context.Background(), provider, c.filters, c.proto)
|
||||
if c.hasError {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
bitbucketv1 "github.com/gfleury/go-bitbucket-v1"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/applicationset/utils"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/utils"
|
||||
)
|
||||
|
||||
type BitbucketServerProvider struct {
|
||||
@@ -64,7 +64,7 @@ func newBitbucketServerProvider(ctx context.Context, bitbucketConfig *bitbucketv
|
||||
}
|
||||
|
||||
func (b *BitbucketServerProvider) ListRepos(_ context.Context, cloneProtocol string) ([]*Repository, error) {
|
||||
paged := map[string]any{
|
||||
paged := map[string]interface{}{
|
||||
"limit": 100,
|
||||
}
|
||||
repos := []*Repository{}
|
||||
@@ -122,14 +122,14 @@ func (b *BitbucketServerProvider) ListRepos(_ context.Context, cloneProtocol str
|
||||
}
|
||||
|
||||
func (b *BitbucketServerProvider) RepoHasPath(_ context.Context, repo *Repository, path string) (bool, error) {
|
||||
opts := map[string]any{
|
||||
opts := map[string]interface{}{
|
||||
"limit": 100,
|
||||
"at": repo.Branch,
|
||||
"type_": true,
|
||||
}
|
||||
// No need to query for all pages here
|
||||
response, err := b.client.DefaultApi.GetContent_0(repo.Organization, repo.Repository, path, opts)
|
||||
if response != nil && response.StatusCode == http.StatusNotFound {
|
||||
if response != nil && response.StatusCode == 404 {
|
||||
// File/directory not found
|
||||
return false, nil
|
||||
}
|
||||
@@ -174,7 +174,7 @@ func (b *BitbucketServerProvider) listBranches(repo *Repository) ([]bitbucketv1.
|
||||
}
|
||||
// Otherwise, scrape the GetBranches API.
|
||||
branches := []bitbucketv1.Branch{}
|
||||
paged := map[string]any{
|
||||
paged := map[string]interface{}{
|
||||
"limit": 100,
|
||||
}
|
||||
for {
|
||||
@@ -203,7 +203,7 @@ func (b *BitbucketServerProvider) getDefaultBranch(org string, repo string) (*bi
|
||||
response, err := b.client.DefaultApi.GetDefaultBranch(org, repo)
|
||||
// The API will return 404 if a default branch is set but doesn't exist. In case the repo is empty and default branch is unset,
|
||||
// we will get an EOF and a nil response.
|
||||
if (response != nil && response.StatusCode == http.StatusNotFound) || (response == nil && err != nil && errors.Is(err, io.EOF)) {
|
||||
if (response != nil && response.StatusCode == 404) || (response == nil && err != nil && errors.Is(err, io.EOF)) {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package scm_provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"io"
|
||||
@@ -13,7 +14,6 @@ import (
|
||||
)
|
||||
|
||||
func defaultHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
|
||||
t.Helper()
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
var err error
|
||||
@@ -82,7 +82,6 @@ func defaultHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
|
||||
}
|
||||
|
||||
func verifyDefaultRepo(t *testing.T, err error, repos []*Repository) {
|
||||
t.Helper()
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, repos, 1)
|
||||
assert.Equal(t, Repository{
|
||||
@@ -102,9 +101,9 @@ func TestListReposNoAuth(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", true, "", false, nil)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.ListRepos(t.Context(), "ssh")
|
||||
repos, err := provider.ListRepos(context.Background(), "ssh")
|
||||
verifyDefaultRepo(t, err, repos)
|
||||
}
|
||||
|
||||
@@ -194,9 +193,9 @@ func TestListReposPagination(t *testing.T) {
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", true, "", false, nil)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.ListRepos(t.Context(), "ssh")
|
||||
repos, err := provider.ListRepos(context.Background(), "ssh")
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, repos, 2)
|
||||
assert.Equal(t, Repository{
|
||||
@@ -271,9 +270,9 @@ func TestGetBranchesBranchPagination(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", true, "", false, nil)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.GetBranches(t.Context(), &Repository{
|
||||
repos, err := provider.GetBranches(context.Background(), &Repository{
|
||||
Organization: "PROJECT",
|
||||
Repository: "REPO",
|
||||
URL: "ssh://git@mycompany.bitbucket.org/PROJECT/REPO.git",
|
||||
@@ -306,7 +305,8 @@ func TestGetBranchesBranchPagination(t *testing.T) {
|
||||
func TestGetBranchesDefaultOnly(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Empty(t, r.Header.Get("Authorization"))
|
||||
if r.RequestURI == "/rest/api/1.0/projects/PROJECT/repos/REPO/branches/default" {
|
||||
switch r.RequestURI {
|
||||
case "/rest/api/1.0/projects/PROJECT/repos/REPO/branches/default":
|
||||
_, err := io.WriteString(w, `{
|
||||
"id": "refs/heads/default",
|
||||
"displayId": "default",
|
||||
@@ -323,9 +323,9 @@ func TestGetBranchesDefaultOnly(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.GetBranches(t.Context(), &Repository{
|
||||
repos, err := provider.GetBranches(context.Background(), &Repository{
|
||||
Organization: "PROJECT",
|
||||
Repository: "REPO",
|
||||
URL: "ssh://git@mycompany.bitbucket.org/PROJECT/REPO.git",
|
||||
@@ -348,15 +348,16 @@ func TestGetBranchesDefaultOnly(t *testing.T) {
|
||||
func TestGetBranchesMissingDefault(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Empty(t, r.Header.Get("Authorization"))
|
||||
if r.RequestURI == "/rest/api/1.0/projects/PROJECT/repos/REPO/branches/default" {
|
||||
switch r.RequestURI {
|
||||
case "/rest/api/1.0/projects/PROJECT/repos/REPO/branches/default":
|
||||
http.Error(w, "Not found", http.StatusNotFound)
|
||||
}
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.GetBranches(t.Context(), &Repository{
|
||||
repos, err := provider.GetBranches(context.Background(), &Repository{
|
||||
Organization: "PROJECT",
|
||||
Repository: "REPO",
|
||||
URL: "ssh://git@mycompany.bitbucket.org/PROJECT/REPO.git",
|
||||
@@ -368,16 +369,17 @@ func TestGetBranchesMissingDefault(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetBranchesEmptyRepo(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Empty(t, r.Header.Get("Authorization"))
|
||||
if r.RequestURI == "/rest/api/1.0/projects/PROJECT/repos/REPO/branches/default" {
|
||||
switch r.RequestURI {
|
||||
case "/rest/api/1.0/projects/PROJECT/repos/REPO/branches/default":
|
||||
return
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.GetBranches(t.Context(), &Repository{
|
||||
repos, err := provider.GetBranches(context.Background(), &Repository{
|
||||
Organization: "PROJECT",
|
||||
Repository: "REPO",
|
||||
URL: "ssh://git@mycompany.bitbucket.org/PROJECT/REPO.git",
|
||||
@@ -391,15 +393,16 @@ func TestGetBranchesEmptyRepo(t *testing.T) {
|
||||
func TestGetBranchesErrorDefaultBranch(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Empty(t, r.Header.Get("Authorization"))
|
||||
if r.RequestURI == "/rest/api/1.0/projects/PROJECT/repos/REPO/branches/default" {
|
||||
switch r.RequestURI {
|
||||
case "/rest/api/1.0/projects/PROJECT/repos/REPO/branches/default":
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
}
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
_, err = provider.GetBranches(t.Context(), &Repository{
|
||||
_, err = provider.GetBranches(context.Background(), &Repository{
|
||||
Organization: "PROJECT",
|
||||
Repository: "REPO",
|
||||
URL: "ssh://git@mycompany.bitbucket.org/PROJECT/REPO.git",
|
||||
@@ -451,7 +454,7 @@ func TestListReposTLS(t *testing.T) {
|
||||
defer ts.Close()
|
||||
|
||||
var certs []byte
|
||||
if test.passCerts {
|
||||
if test.passCerts == true {
|
||||
for _, cert := range ts.TLS.Certificates {
|
||||
for _, c := range cert.Certificate {
|
||||
parsedCert, err := x509.ParseCertificate(c)
|
||||
@@ -464,9 +467,9 @@ func TestListReposTLS(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
provider, err := NewBitbucketServerProviderBasicAuth(t.Context(), "user", "password", ts.URL, "PROJECT", true, "", test.tlsInsecure, certs)
|
||||
provider, err := NewBitbucketServerProviderBasicAuth(context.Background(), "user", "password", ts.URL, "PROJECT", true, "", test.tlsInsecure, certs)
|
||||
require.NoError(t, err)
|
||||
_, err = provider.ListRepos(t.Context(), "ssh")
|
||||
_, err = provider.ListRepos(context.Background(), "ssh")
|
||||
if test.requireErr {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
@@ -483,9 +486,9 @@ func TestListReposBasicAuth(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderBasicAuth(t.Context(), "user", "password", ts.URL, "PROJECT", true, "", false, nil)
|
||||
provider, err := NewBitbucketServerProviderBasicAuth(context.Background(), "user", "password", ts.URL, "PROJECT", true, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.ListRepos(t.Context(), "ssh")
|
||||
repos, err := provider.ListRepos(context.Background(), "ssh")
|
||||
verifyDefaultRepo(t, err, repos)
|
||||
}
|
||||
|
||||
@@ -496,16 +499,17 @@ func TestListReposBearerAuth(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderBearerToken(t.Context(), "tolkien", ts.URL, "PROJECT", true, "", false, nil)
|
||||
provider, err := NewBitbucketServerProviderBearerToken(context.Background(), "tolkien", ts.URL, "PROJECT", true, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.ListRepos(t.Context(), "ssh")
|
||||
repos, err := provider.ListRepos(context.Background(), "ssh")
|
||||
verifyDefaultRepo(t, err, repos)
|
||||
}
|
||||
|
||||
func TestListReposDefaultBranch(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Empty(t, r.Header.Get("Authorization"))
|
||||
if r.RequestURI == "/rest/api/1.0/projects/PROJECT/repos/REPO/branches/default" {
|
||||
switch r.RequestURI {
|
||||
case "/rest/api/1.0/projects/PROJECT/repos/REPO/branches/default":
|
||||
_, err := io.WriteString(w, `{
|
||||
"id": "refs/heads/default",
|
||||
"displayId": "default",
|
||||
@@ -522,9 +526,9 @@ func TestListReposDefaultBranch(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.ListRepos(t.Context(), "ssh")
|
||||
repos, err := provider.ListRepos(context.Background(), "ssh")
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, repos, 1)
|
||||
assert.Equal(t, Repository{
|
||||
@@ -541,15 +545,16 @@ func TestListReposDefaultBranch(t *testing.T) {
|
||||
func TestListReposMissingDefaultBranch(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Empty(t, r.Header.Get("Authorization"))
|
||||
if r.RequestURI == "/rest/api/1.0/projects/PROJECT/repos/REPO/branches/default" {
|
||||
switch r.RequestURI {
|
||||
case "/rest/api/1.0/projects/PROJECT/repos/REPO/branches/default":
|
||||
http.Error(w, "Not found", http.StatusNotFound)
|
||||
}
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.ListRepos(t.Context(), "ssh")
|
||||
repos, err := provider.ListRepos(context.Background(), "ssh")
|
||||
require.NoError(t, err)
|
||||
assert.Empty(t, repos)
|
||||
}
|
||||
@@ -557,15 +562,16 @@ func TestListReposMissingDefaultBranch(t *testing.T) {
|
||||
func TestListReposErrorDefaultBranch(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Empty(t, r.Header.Get("Authorization"))
|
||||
if r.RequestURI == "/rest/api/1.0/projects/PROJECT/repos/REPO/branches/default" {
|
||||
switch r.RequestURI {
|
||||
case "/rest/api/1.0/projects/PROJECT/repos/REPO/branches/default":
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
}
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
_, err = provider.ListRepos(t.Context(), "ssh")
|
||||
_, err = provider.ListRepos(context.Background(), "ssh")
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
@@ -575,9 +581,9 @@ func TestListReposCloneProtocol(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", true, "", false, nil)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.ListRepos(t.Context(), "https")
|
||||
repos, err := provider.ListRepos(context.Background(), "https")
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, repos, 1)
|
||||
assert.Equal(t, Repository{
|
||||
@@ -597,9 +603,9 @@ func TestListReposUnknownProtocol(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", true, "", false, nil)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
_, errProtocol := provider.ListRepos(t.Context(), "http")
|
||||
_, errProtocol := provider.ListRepos(context.Background(), "http")
|
||||
require.Error(t, errProtocol)
|
||||
}
|
||||
|
||||
@@ -635,37 +641,37 @@ func TestBitbucketServerHasPath(t *testing.T) {
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", true, "", false, nil)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repo := &Repository{
|
||||
Organization: "PROJECT",
|
||||
Repository: "REPO",
|
||||
Branch: "main",
|
||||
}
|
||||
ok, err := provider.RepoHasPath(t.Context(), repo, "pkg")
|
||||
ok, err := provider.RepoHasPath(context.Background(), repo, "pkg")
|
||||
require.NoError(t, err)
|
||||
assert.True(t, ok)
|
||||
|
||||
ok, err = provider.RepoHasPath(t.Context(), repo, "pkg/")
|
||||
ok, err = provider.RepoHasPath(context.Background(), repo, "pkg/")
|
||||
require.NoError(t, err)
|
||||
assert.True(t, ok)
|
||||
|
||||
ok, err = provider.RepoHasPath(t.Context(), repo, "anotherpkg/file.txt")
|
||||
ok, err = provider.RepoHasPath(context.Background(), repo, "anotherpkg/file.txt")
|
||||
require.NoError(t, err)
|
||||
assert.True(t, ok)
|
||||
|
||||
ok, err = provider.RepoHasPath(t.Context(), repo, "anotherpkg/missing.txt")
|
||||
ok, err = provider.RepoHasPath(context.Background(), repo, "anotherpkg/missing.txt")
|
||||
require.NoError(t, err)
|
||||
assert.False(t, ok)
|
||||
|
||||
ok, err = provider.RepoHasPath(t.Context(), repo, "notathing")
|
||||
ok, err = provider.RepoHasPath(context.Background(), repo, "notathing")
|
||||
require.NoError(t, err)
|
||||
assert.False(t, ok)
|
||||
|
||||
ok, err = provider.RepoHasPath(t.Context(), repo, "return-redirect")
|
||||
ok, err = provider.RepoHasPath(context.Background(), repo, "return-redirect")
|
||||
require.NoError(t, err)
|
||||
assert.True(t, ok)
|
||||
|
||||
_, err = provider.RepoHasPath(t.Context(), repo, "unauthorized-response")
|
||||
_, err = provider.RepoHasPath(context.Background(), repo, "unauthorized-response")
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user