mirror of
https://github.com/argoproj/argo-cd.git
synced 2026-02-20 09:38:49 +01:00
Compare commits
276 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e4115e6fd | ||
|
|
539a3e33fa | ||
|
|
0e0a9ebdf1 | ||
|
|
dad6fa22d5 | ||
|
|
bdb2608993 | ||
|
|
1dd2821631 | ||
|
|
5ccea0d4ab | ||
|
|
992716b12c | ||
|
|
d56206fb4e | ||
|
|
b21768d9d9 | ||
|
|
3091db84d3 | ||
|
|
f17c6c1dde | ||
|
|
a21980cde6 | ||
|
|
80e85967e5 | ||
|
|
ed14baab81 | ||
|
|
1a94032408 | ||
|
|
74bbc4f7f1 | ||
|
|
6205f97772 | ||
|
|
4f64f0f2f2 | ||
|
|
da1e95dbe1 | ||
|
|
658311d554 | ||
|
|
8a8c28fcb4 | ||
|
|
82e5363634 | ||
|
|
21ed19b366 | ||
|
|
a96e665598 | ||
|
|
d61f18df22 | ||
|
|
79ce7c811b | ||
|
|
2db38409ee | ||
|
|
e04d7cb578 | ||
|
|
34d06096e5 | ||
|
|
5403f956e4 | ||
|
|
e9d6431780 | ||
|
|
dc544da6ae | ||
|
|
5188ea2969 | ||
|
|
e83abdace8 | ||
|
|
f110570512 | ||
|
|
4a7a82cdba | ||
|
|
b5a3712303 | ||
|
|
db02eaa7e0 | ||
|
|
6ee584594a | ||
|
|
60c53c6fc4 | ||
|
|
26fb098ae8 | ||
|
|
267f243a89 | ||
|
|
8362ecc94b | ||
|
|
3658f8ec37 | ||
|
|
d9337a3849 | ||
|
|
0894ddc89e | ||
|
|
42de68d67f | ||
|
|
2edc1bad9a | ||
|
|
234c7ecdf9 | ||
|
|
f8a4399033 | ||
|
|
ad7438312f | ||
|
|
6a18c21ea8 | ||
|
|
2a0a0ea1cc | ||
|
|
3c7b6886bf | ||
|
|
44b1dfce90 | ||
|
|
3996a18bc9 | ||
|
|
592e0b5879 | ||
|
|
7878ddf086 | ||
|
|
e2c5a555ce | ||
|
|
348f5013ff | ||
|
|
34b411cca7 | ||
|
|
75e73834bf | ||
|
|
6cc898ff37 | ||
|
|
2769dd3931 | ||
|
|
8b1bddd5f7 | ||
|
|
473a695585 | ||
|
|
aa2b331153 | ||
|
|
0019042c9d | ||
|
|
8e5bf5dadc | ||
|
|
d894d22a63 | ||
|
|
3ec6604149 | ||
|
|
7c41233419 | ||
|
|
11629d18d3 | ||
|
|
25c2f2fbc6 | ||
|
|
714d1ad01f | ||
|
|
889c36cd21 | ||
|
|
929e85553d | ||
|
|
dcfa738f1c | ||
|
|
4c158faf32 | ||
|
|
be042e2dcf | ||
|
|
2465ebbab0 | ||
|
|
a03bda68f2 | ||
|
|
fec106a260 | ||
|
|
58f16c1c58 | ||
|
|
dba8086f4a | ||
|
|
ddc0b0fd3f | ||
|
|
f1018e88a0 | ||
|
|
8952273d1f | ||
|
|
f05de86401 | ||
|
|
e85d97bbc1 | ||
|
|
b95347c5e3 | ||
|
|
1cef4de066 | ||
|
|
30f05e8726 | ||
|
|
21fe286f6e | ||
|
|
25909f1671 | ||
|
|
6f94113935 | ||
|
|
56bb5734de | ||
|
|
326cc4a06b | ||
|
|
e26c105e52 | ||
|
|
20f55285cd | ||
|
|
9026f14a0b | ||
|
|
67776ad864 | ||
|
|
3406078b89 | ||
|
|
58b56767bc | ||
|
|
d0313c5ba4 | ||
|
|
9ca2c53d1d | ||
|
|
ba32783a40 | ||
|
|
85a782e91e | ||
|
|
3daaca9211 | ||
|
|
3bc3d22b2a | ||
|
|
e36248cb22 | ||
|
|
e647690860 | ||
|
|
edf631c979 | ||
|
|
77a8100d3a | ||
|
|
975449c8d8 | ||
|
|
560c7c2cde | ||
|
|
5eafab12bc | ||
|
|
386d848178 | ||
|
|
66eac6dd80 | ||
|
|
555dbba268 | ||
|
|
ff3e36c3ce | ||
|
|
834223a59c | ||
|
|
3d77d9ced0 | ||
|
|
65fddab260 | ||
|
|
745ec52d9c | ||
|
|
4c34678c24 | ||
|
|
9dd1083c98 | ||
|
|
f6c06046e6 | ||
|
|
13be1aec2c | ||
|
|
c9c7989f8c | ||
|
|
5d21725225 | ||
|
|
505998298f | ||
|
|
f26b76a7aa | ||
|
|
f9078f78b6 | ||
|
|
a7cb6ed9bb | ||
|
|
64b76f2fa0 | ||
|
|
c59cb52b27 | ||
|
|
22e498e9ca | ||
|
|
ea725a9c7c | ||
|
|
b6960973b7 | ||
|
|
bb1bb3f4eb | ||
|
|
530bcd7cf6 | ||
|
|
07db0e0937 | ||
|
|
54646ed55c | ||
|
|
d6bc02b195 | ||
|
|
824d0dced7 | ||
|
|
a06cdb3880 | ||
|
|
484e83d210 | ||
|
|
30a1623e38 | ||
|
|
45b7593e82 | ||
|
|
32e6ca2337 | ||
|
|
c5d0acf7ec | ||
|
|
7af5793c5b | ||
|
|
4f22dbda14 | ||
|
|
c14143635c | ||
|
|
7fdddbe59b | ||
|
|
dfaacef76f | ||
|
|
7631d207e3 | ||
|
|
ed336c222e | ||
|
|
c6f2d2896d | ||
|
|
e7760b5e93 | ||
|
|
7f338e910f | ||
|
|
da7467bea7 | ||
|
|
10ce884f7c | ||
|
|
9712642eea | ||
|
|
79e43e85ab | ||
|
|
f7e7c2fc44 | ||
|
|
de76937242 | ||
|
|
57baaad030 | ||
|
|
2b340f7139 | ||
|
|
fdf05670aa | ||
|
|
69908ceadd | ||
|
|
19e3c1ae49 | ||
|
|
aa2837deac | ||
|
|
9347d8d587 | ||
|
|
c69dd943bc | ||
|
|
af1217ffad | ||
|
|
a071f93b71 | ||
|
|
ddb809f3ce | ||
|
|
b9099935bc | ||
|
|
fd677c6570 | ||
|
|
91c935b6d8 | ||
|
|
6db9186b58 | ||
|
|
5c6c0c8c4f | ||
|
|
a47243a935 | ||
|
|
b0024d145b | ||
|
|
cc250aef32 | ||
|
|
f8966d837f | ||
|
|
4653a9b150 | ||
|
|
1bf2b7148b | ||
|
|
21a64d3a6a | ||
|
|
14ae4c43d9 | ||
|
|
79b18e03dc | ||
|
|
866b248df8 | ||
|
|
20b5969b8f | ||
|
|
99c243cf81 | ||
|
|
6061fd8d0c | ||
|
|
2e7ebf77d5 | ||
|
|
efb394fb86 | ||
|
|
48a0dad326 | ||
|
|
f02d8f4fdf | ||
|
|
18ccd7a667 | ||
|
|
b96be4c5e4 | ||
|
|
5fffcfaf6b | ||
|
|
74c09a563e | ||
|
|
3c5ff60759 | ||
|
|
9a8f3cd6b0 | ||
|
|
12b626b82a | ||
|
|
a2e6434811 | ||
|
|
06b0f957b8 | ||
|
|
c6f96d7615 | ||
|
|
1d59f46997 | ||
|
|
1de81a4db2 | ||
|
|
73bdbb511a | ||
|
|
4312bc059f | ||
|
|
eca1f21d64 | ||
|
|
dc8be08e0b | ||
|
|
c3f108f85c | ||
|
|
1aa898cbb4 | ||
|
|
9b3a4d150d | ||
|
|
5a034f2261 | ||
|
|
d171d05997 | ||
|
|
e6a034995c | ||
|
|
3d3620e6a0 | ||
|
|
51c8013d9c | ||
|
|
0a14ef9b25 | ||
|
|
8ca96a9d0e | ||
|
|
2988401c47 | ||
|
|
dafb37c88d | ||
|
|
95be90b5f9 | ||
|
|
428da83bde | ||
|
|
5355430bce | ||
|
|
81151d5fc0 | ||
|
|
ee2dc25ff1 | ||
|
|
999b75fdc0 | ||
|
|
6f84afca3b | ||
|
|
ad5f6724b5 | ||
|
|
b33922fafb | ||
|
|
f358e8ddba | ||
|
|
ba0ee5d01f | ||
|
|
0183aac005 | ||
|
|
56c12db389 | ||
|
|
73984bdcab | ||
|
|
03acafef1c | ||
|
|
a5805416df | ||
|
|
6b433e3bd1 | ||
|
|
13b70c56ce | ||
|
|
b92e00d598 | ||
|
|
f11de952a6 | ||
|
|
41b8e4406b | ||
|
|
587c5ba1c6 | ||
|
|
b35acd4ffe | ||
|
|
ad6508b9de | ||
|
|
c95d4eef58 | ||
|
|
25e3a61938 | ||
|
|
9d72f1ec5c | ||
|
|
a624c90845 | ||
|
|
3dcddee199 | ||
|
|
1e916d9bb9 | ||
|
|
f655b0b2df | ||
|
|
cbb4c50018 | ||
|
|
e98d3b2a87 | ||
|
|
f7d854ec9e | ||
|
|
d2436d9f4d | ||
|
|
1aeed6a6b1 | ||
|
|
c83a988009 | ||
|
|
331944aa6a | ||
|
|
e6dc415d34 | ||
|
|
6bc0b29dfe | ||
|
|
7c7af4040a | ||
|
|
ff1d37fae6 | ||
|
|
70755aa3c5 | ||
|
|
5bf93d4955 | ||
|
|
c88d3a9ab4 | ||
|
|
04edbe90d1 |
13
.gitattributes
vendored
Normal file
13
.gitattributes
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
**/*.pb.go linguist-generated=true
|
||||
**/mocks/*.go linguist-generated=true
|
||||
assets/swagger.json linguist-generated=true
|
||||
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/crds/*-crd.yaml linguist-generated=true
|
||||
manifests/ha/install.yaml linguist-generated=true
|
||||
manifests/ha/namespace-install.yaml linguist-generated=true
|
||||
manifests/install.yaml linguist-generated=true
|
||||
manifests/namespace-install.yaml linguist-generated=true
|
||||
pkg/apis/api-rules/violation_exceptions.list linguist-generated=true
|
||||
43
.github/ISSUE_TEMPLATE/new_dev_tool.md
vendored
Normal file
43
.github/ISSUE_TEMPLATE/new_dev_tool.md
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
---
|
||||
name: New Dev Tool Request
|
||||
about: This is a request for adding a new tool for setting up a dev environment.
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
Checklist:
|
||||
|
||||
* [ ] I am willing to maintain this tool, or have another Argo CD maintainer who is.
|
||||
* [ ] I have another Argo CD maintainer who is willing to help maintain this tool (there needs to be at least two maintainers willing to maintain this tool)
|
||||
* [ ] I have a lead sponsor who is a core Argo CD maintainer
|
||||
* [ ] There is a PR which adds said tool - this is so that the maintainers can assess the impact of having this in the tree
|
||||
* [ ] I have given a motivation why this should be added
|
||||
|
||||
### The proposer
|
||||
|
||||
<-- The username(s) of the person(s) proposing the tool -->
|
||||
|
||||
### The proposed tool
|
||||
|
||||
<!-- The tool itself, with a link to the tool’s website -->
|
||||
|
||||
### Motivation
|
||||
|
||||
<!-- Why this tool would be useful to have in the tree. -->
|
||||
|
||||
### Link to PR (Optional)
|
||||
|
||||
<!-- A PR adding the tool to the tree -->
|
||||
|
||||
### Lead Sponsor(s)
|
||||
|
||||
Final approval requires sponsorship from at least one core maintainer.
|
||||
|
||||
- @<sponsor-1>
|
||||
|
||||
### Co-sponsors
|
||||
|
||||
These will be the co-maintainers of the specified tool.
|
||||
|
||||
- @<sponsor-1>
|
||||
5
.github/dependabot.yml
vendored
5
.github/dependabot.yml
vendored
@@ -4,8 +4,13 @@ updates:
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
open-pull-requests-limit: 20
|
||||
ignore:
|
||||
- dependency-name: k8s.io/*
|
||||
groups:
|
||||
otel:
|
||||
patterns:
|
||||
- "^go.opentelemetry.io/.*"
|
||||
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
|
||||
53
.github/workflows/ci-build.yaml
vendored
53
.github/workflows/ci-build.yaml
vendored
@@ -31,7 +31,7 @@ jobs:
|
||||
docs: ${{ steps.filter.outputs.docs_any_changed }}
|
||||
steps:
|
||||
- uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
|
||||
- uses: tj-actions/changed-files@d6babd6899969df1a11d14c368283ea4436bca78 # v44.5.2
|
||||
- uses: tj-actions/changed-files@c65cd883420fd2eb864698a825fc4162dd94482c # v44.5.7
|
||||
id: filter
|
||||
with:
|
||||
# Any file which is not under docs/, ui/ or is not a markdown file is counted as a backend file
|
||||
@@ -56,7 +56,7 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1
|
||||
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Download all Go modules
|
||||
@@ -77,7 +77,7 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1
|
||||
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Restore go build cache
|
||||
@@ -104,11 +104,11 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1
|
||||
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Run golangci-lint
|
||||
uses: golangci/golangci-lint-action@a4f60bb28d35aeee14e6880718e0c85ff1882e64 # v6.0.1
|
||||
uses: golangci/golangci-lint-action@aaa42aa0628b4ae2578232a66b541047968fac86 # v6.1.0
|
||||
with:
|
||||
version: v1.58.2
|
||||
args: --verbose
|
||||
@@ -131,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@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1
|
||||
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Install required packages
|
||||
@@ -172,7 +172,7 @@ jobs:
|
||||
- name: Run all unit tests
|
||||
run: make test-local
|
||||
- name: Generate test results artifacts
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6
|
||||
with:
|
||||
name: test-results
|
||||
path: test-results
|
||||
@@ -195,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@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1
|
||||
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Install required packages
|
||||
@@ -236,7 +236,7 @@ jobs:
|
||||
- name: Run all unit tests
|
||||
run: make test-race-local
|
||||
- name: Generate test results artifacts
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6
|
||||
with:
|
||||
name: race-results
|
||||
path: test-results/
|
||||
@@ -251,7 +251,7 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1
|
||||
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Create symlink in GOPATH
|
||||
@@ -303,7 +303,7 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
|
||||
- name: Setup NodeJS
|
||||
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
|
||||
with:
|
||||
node-version: '21.6.1'
|
||||
- name: Restore node dependency cache
|
||||
@@ -354,21 +354,22 @@ jobs:
|
||||
run: |
|
||||
rm -rf ui/node_modules/argo-ui/node_modules
|
||||
- name: Get e2e code coverage
|
||||
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7
|
||||
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
|
||||
with:
|
||||
name: e2e-code-coverage
|
||||
path: e2e-code-coverage
|
||||
- name: Get unit test code coverage
|
||||
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7
|
||||
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
|
||||
with:
|
||||
name: test-results
|
||||
path: test-results
|
||||
- name: combine-go-coverage
|
||||
# We generate coverage reports for all Argo CD components, but only the applicationset-controller report
|
||||
# contains 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.
|
||||
# We generate coverage reports for all Argo CD components, but only the applicationset-controller,
|
||||
# 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 -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@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0
|
||||
with:
|
||||
@@ -380,7 +381,7 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
uses: SonarSource/sonarqube-scan-action@540792c588b5c2740ad2bb4667db5cd46ae678f2 # v2.2
|
||||
uses: SonarSource/sonarqube-scan-action@aecaf43ae57e412bd97d70ef9ce6076e672fe0a9 # v2.2
|
||||
if: env.sonar_secret != ''
|
||||
test-e2e:
|
||||
name: Run end-to-end tests
|
||||
@@ -390,14 +391,14 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
k3s:
|
||||
- version: v1.29.1
|
||||
- version: v1.30.2
|
||||
# We designate the latest version because we only collect code coverage for that version.
|
||||
latest: true
|
||||
- version: v1.28.6
|
||||
- version: v1.29.6
|
||||
latest: false
|
||||
- version: v1.27.10
|
||||
- version: v1.28.11
|
||||
latest: false
|
||||
- version: v1.26.13
|
||||
- version: v1.27.15
|
||||
latest: false
|
||||
needs:
|
||||
- build-go
|
||||
@@ -419,7 +420,7 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1
|
||||
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: GH actions workaround - Kill XSP4 process
|
||||
@@ -464,7 +465,7 @@ jobs:
|
||||
git config --global user.email "john.doe@example.com"
|
||||
- name: Pull Docker image required for tests
|
||||
run: |
|
||||
docker pull ghcr.io/dexidp/dex:v2.38.0
|
||||
docker pull ghcr.io/dexidp/dex:v2.41.1
|
||||
docker pull argoproj/argo-cd-ci-builder:v1.0.0
|
||||
docker pull redis:7.0.15-alpine
|
||||
- name: Create target directory for binaries in the build-process
|
||||
@@ -496,13 +497,13 @@ jobs:
|
||||
goreman run stop-all || echo "goreman trouble"
|
||||
sleep 30
|
||||
- name: Upload e2e coverage report
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6
|
||||
with:
|
||||
name: e2e-code-coverage
|
||||
path: /tmp/coverage
|
||||
if: ${{ matrix.k3s.latest }}
|
||||
- name: Upload e2e-server logs
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6
|
||||
with:
|
||||
name: e2e-server-k8s${{ matrix.k3s.version }}.log
|
||||
path: /tmp/e2e-server.log
|
||||
|
||||
2
.github/workflows/codeql.yml
vendored
2
.github/workflows/codeql.yml
vendored
@@ -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@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1
|
||||
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
|
||||
|
||||
16
.github/workflows/image-reuse.yaml
vendored
16
.github/workflows/image-reuse.yaml
vendored
@@ -69,15 +69,15 @@ jobs:
|
||||
if: ${{ github.ref_type != 'tag'}}
|
||||
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1
|
||||
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
|
||||
with:
|
||||
go-version: ${{ inputs.go-version }}
|
||||
|
||||
- name: Install cosign
|
||||
uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 # v3.5.0
|
||||
uses: sigstore/cosign-installer@4959ce089c160fddf62f7b42464195ba1a56d382 # v3.6.0
|
||||
|
||||
- uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3 # v3.0.0
|
||||
- uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0
|
||||
- uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3.2.0
|
||||
- uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db # v3.6.1
|
||||
|
||||
- name: Setup tags for container image as a CSV type
|
||||
run: |
|
||||
@@ -104,7 +104,7 @@ jobs:
|
||||
echo 'EOF' >> $GITHUB_ENV
|
||||
|
||||
- name: Login to Quay.io
|
||||
uses: docker/login-action@0d4c9c5ea7693da7b068278f7b52bda2a190a446 # v3.2.0
|
||||
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
|
||||
with:
|
||||
registry: quay.io
|
||||
username: ${{ secrets.quay_username }}
|
||||
@@ -112,7 +112,7 @@ jobs:
|
||||
if: ${{ inputs.quay_image_name && inputs.push }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@0d4c9c5ea7693da7b068278f7b52bda2a190a446 # v3.2.0
|
||||
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ secrets.ghcr_username }}
|
||||
@@ -120,7 +120,7 @@ jobs:
|
||||
if: ${{ inputs.ghcr_image_name && inputs.push }}
|
||||
|
||||
- name: Login to dockerhub Container Registry
|
||||
uses: docker/login-action@0d4c9c5ea7693da7b068278f7b52bda2a190a446 # v3.2.0
|
||||
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
|
||||
with:
|
||||
username: ${{ secrets.docker_username }}
|
||||
password: ${{ secrets.docker_password }}
|
||||
@@ -143,7 +143,7 @@ jobs:
|
||||
|
||||
- name: Build and push container image
|
||||
id: image
|
||||
uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 #v5.4.0
|
||||
uses: docker/build-push-action@16ebe778df0e7752d2cfcbd924afdbbd89c1a755 #v6.6.1
|
||||
with:
|
||||
context: .
|
||||
platforms: ${{ inputs.platforms }}
|
||||
|
||||
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@6d6857d36972b65feb161a90e484f2984215f83e # v6.0.5
|
||||
uses: peter-evans/create-pull-request@c5a7806660adbe173f04e3e038b0ccdcd758773c # v6.1.0
|
||||
with:
|
||||
commit-message: "Bump version to ${{ inputs.TARGET_VERSION }}"
|
||||
title: "Bump version to ${{ inputs.TARGET_VERSION }} on ${{ inputs.TARGET_BRANCH }} branch"
|
||||
|
||||
10
.github/workflows/release.yaml
vendored
10
.github/workflows/release.yaml
vendored
@@ -77,7 +77,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1
|
||||
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
|
||||
@@ -153,7 +153,7 @@ jobs:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1
|
||||
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
|
||||
@@ -197,7 +197,7 @@ jobs:
|
||||
echo "hashes=$(sha256sum /tmp/sbom.tar.gz | base64 -w0)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Upload SBOM
|
||||
uses: softprops/action-gh-release@69320dbe05506a9a39fc8ae11030b214ec2d1f87 # v2.0.5
|
||||
uses: softprops/action-gh-release@c062e08bd532815e2082a85e87e3ef29c3e6d191 # v2.0.8
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
@@ -291,11 +291,11 @@ jobs:
|
||||
# Replace the 'project-release: vX.X.X-rcX' line in SECURITY-INSIGHTS.yml
|
||||
sed -i "s/project-release: v.*$/project-release: v${{ env.NEW_VERSION }}/" SECURITY-INSIGHTS.yml
|
||||
# Update the 'commit-hash: XXXXXXX' line in SECURITY-INSIGHTS.yml
|
||||
sed -i "s/commit-hash: .*/commit-hash: ${{ env.NEW_VERSION }}/" SECURITY-INSIGHTS.yml
|
||||
sed -i "s/commit-hash: .*/commit-hash: ${{ env.COMMIT_HASH }}/" SECURITY-INSIGHTS.yml
|
||||
if: ${{ env.UPDATE_VERSION == 'true' }}
|
||||
|
||||
- name: Create PR to update VERSION on master branch
|
||||
uses: peter-evans/create-pull-request@6d6857d36972b65feb161a90e484f2984215f83e # v6.0.5
|
||||
uses: peter-evans/create-pull-request@c5a7806660adbe173f04e3e038b0ccdcd758773c # v6.1.0
|
||||
with:
|
||||
commit-message: Bump version in master
|
||||
title: "chore: Bump version in master"
|
||||
|
||||
4
.github/workflows/scorecard.yaml
vendored
4
.github/workflows/scorecard.yaml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
persist-credentials: false
|
||||
|
||||
- name: "Run analysis"
|
||||
uses: ossf/scorecard-action@dc50aa9510b46c811795eb24b2f1ba02a914e534 # v2.3.3
|
||||
uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
@@ -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@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
|
||||
2
.gitpod.Dockerfile
vendored
2
.gitpod.Dockerfile
vendored
@@ -1,4 +1,4 @@
|
||||
FROM gitpod/workspace-full@sha256:8dd34e72ae5b9e6f60d267dd6287befc2cf5ad1a11c64e9d93daa60c952a2154
|
||||
FROM gitpod/workspace-full@sha256:fbff2dce4236535b96de0e94622bbe9a44fba954ca064862004c34e3e08904df
|
||||
|
||||
USER root
|
||||
|
||||
|
||||
@@ -36,8 +36,6 @@ linters-settings:
|
||||
testifylint:
|
||||
enable-all: true
|
||||
disable:
|
||||
- error-is-as
|
||||
- float-compare
|
||||
- go-require
|
||||
run:
|
||||
timeout: 50m
|
||||
|
||||
68
.mockery.yaml
Normal file
68
.mockery.yaml
Normal file
@@ -0,0 +1,68 @@
|
||||
# global config
|
||||
filename: "{{.InterfaceName}}.go"
|
||||
dir: "{{.InterfaceDir}}/mocks"
|
||||
outpkg: "mocks"
|
||||
mockname: "{{.InterfaceName}}"
|
||||
with-expecter: false
|
||||
# individual interface config
|
||||
packages:
|
||||
github.com/argoproj/argo-cd/v2/applicationset/generators:
|
||||
interfaces:
|
||||
Generator:
|
||||
github.com/argoproj/argo-cd/v2/applicationset/services:
|
||||
interfaces:
|
||||
Repos:
|
||||
github.com/argoproj/argo-cd/v2/applicationset/services/scm_provider:
|
||||
config:
|
||||
dir: "applicationset/services/scm_provider/aws_codecommit/mocks"
|
||||
interfaces:
|
||||
AWSCodeCommitClient:
|
||||
AWSTaggingClient:
|
||||
github.com/microsoft/azure-devops-go-api/azuredevops/git:
|
||||
config:
|
||||
dir: "applicationset/services/scm_provider/azure_devops/git/mocks"
|
||||
interfaces:
|
||||
Client:
|
||||
github.com/argoproj/argo-cd/v2/applicationset/utils:
|
||||
interfaces:
|
||||
Renderer:
|
||||
github.com/argoproj/argo-cd/v2/controller/cache:
|
||||
interfaces:
|
||||
LiveStateCache:
|
||||
github.com/argoproj/argo-cd/v2/reposerver/apiclient:
|
||||
interfaces:
|
||||
RepoServerServiceClient:
|
||||
RepoServerService_GenerateManifestWithFilesClient:
|
||||
github.com/argoproj/argo-cd/v2/server/application:
|
||||
interfaces:
|
||||
Broadcaster:
|
||||
github.com/argoproj/argo-cd/v2/server/extension:
|
||||
interfaces:
|
||||
ApplicationGetter:
|
||||
ExtensionMetricsRegistry:
|
||||
ProjectGetter:
|
||||
RbacEnforcer:
|
||||
SettingsGetter:
|
||||
github.com/argoproj/argo-cd/v2/util/db:
|
||||
interfaces:
|
||||
ArgoDB:
|
||||
github.com/argoproj/argo-cd/v2/util/git:
|
||||
interfaces:
|
||||
Client:
|
||||
github.com/argoproj/argo-cd/v2/util/helm:
|
||||
interfaces:
|
||||
Client:
|
||||
github.com/argoproj/argo-cd/v2/util/io:
|
||||
interfaces:
|
||||
TempPaths:
|
||||
github.com/argoproj/argo-cd/v2/util/notification/argocd:
|
||||
interfaces:
|
||||
Service:
|
||||
# These mocks are not currently used, but they are part of the public API of this package.
|
||||
github.com/argoproj/argo-cd/v2/pkg/apiclient/session:
|
||||
interfaces:
|
||||
SessionServiceServer:
|
||||
SessionServiceClient:
|
||||
github.com/argoproj/argo-cd/v2/pkg/apiclient/cluster:
|
||||
interfaces:
|
||||
ClusterServiceServer:
|
||||
@@ -4,7 +4,7 @@ ARG BASE_IMAGE=docker.io/library/ubuntu:24.04@sha256:3f85b7caad41a95462cf5b787d8
|
||||
# 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.22.4@sha256:c2010b9c2342431a24a2e64e33d9eb2e484af49e72c820e200d332d214d5e61f AS builder
|
||||
FROM docker.io/library/golang:1.22.6@sha256:2bd56f00ff47baf33e64eae7996b65846c7cb5e0a46e0a882ef179fd89654afa AS builder
|
||||
|
||||
RUN echo 'deb http://archive.debian.org/debian buster-backports main' >> /etc/apt/sources.list
|
||||
|
||||
@@ -101,7 +101,7 @@ RUN HOST_ARCH=$TARGETARCH NODE_ENV='production' NODE_ONLINE_ENV='online' NODE_OP
|
||||
####################################################################################################
|
||||
# Argo CD Build stage which performs the actual build of Argo CD binaries
|
||||
####################################################################################################
|
||||
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.22.4@sha256:c2010b9c2342431a24a2e64e33d9eb2e484af49e72c820e200d332d214d5e61f AS argocd-build
|
||||
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.22.6@sha256:2bd56f00ff47baf33e64eae7996b65846c7cb5e0a46e0a882ef179fd89654afa AS argocd-build
|
||||
|
||||
WORKDIR /go/src/github.com/argoproj/argo-cd
|
||||
|
||||
|
||||
11
Makefile
11
Makefile
@@ -192,6 +192,10 @@ endif
|
||||
.PHONY: all
|
||||
all: cli image
|
||||
|
||||
.PHONY: mockgen
|
||||
mockgen:
|
||||
./hack/generate-mock.sh
|
||||
|
||||
.PHONY: gogen
|
||||
gogen:
|
||||
export GO111MODULE=off
|
||||
@@ -229,13 +233,16 @@ clientgen:
|
||||
clidocsgen:
|
||||
go run tools/cmd-docs/main.go
|
||||
|
||||
.PHONY: actionsdocsgen
|
||||
actionsdocsgen:
|
||||
hack/generate-actions-list.sh
|
||||
|
||||
.PHONY: codegen-local
|
||||
codegen-local: mod-vendor-local gogen protogen clientgen openapigen clidocsgen manifests-local notification-docs notification-catalog
|
||||
codegen-local: mod-vendor-local mockgen gogen protogen clientgen openapigen clidocsgen actionsdocsgen manifests-local notification-docs notification-catalog
|
||||
rm -rf vendor/
|
||||
|
||||
.PHONY: codegen-local-fast
|
||||
codegen-local-fast: gogen protogen-fast clientgen openapigen clidocsgen manifests-local notification-docs notification-catalog
|
||||
codegen-local-fast: mockgen gogen protogen-fast clientgen openapigen clidocsgen manifests-local notification-docs notification-catalog
|
||||
|
||||
.PHONY: codegen
|
||||
codegen: test-tools-image
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
Test for DCO. do not merge
|
||||
|
||||
**Releases:**
|
||||
[](https://github.com/argoproj/argo-cd/releases/latest)
|
||||
[](https://artifacthub.io/packages/helm/argo/argo-cd)
|
||||
@@ -7,7 +9,7 @@
|
||||
[](https://github.com/argoproj/argo-cd/actions?query=workflow%3A%22Integration+tests%22)
|
||||
[](https://codecov.io/gh/argoproj/argo-cd)
|
||||
[](https://bestpractices.coreinfrastructure.org/projects/4486)
|
||||
[](https://api.securityscorecards.dev/projects/github.com/argoproj/argo-cd)
|
||||
[](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:**
|
||||
|
||||
@@ -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: b71277c6beb949d0199d647a582bc25822b88838
|
||||
commit-hash: fe606708859574b9b6102a505e260fac5d3fb14e
|
||||
project-url: https://github.com/argoproj/argo-cd
|
||||
project-release: v2.9.0-rc3
|
||||
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:
|
||||
|
||||
20
USERS.md
20
USERS.md
@@ -43,9 +43,11 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [BioBox Analytics](https://biobox.io)
|
||||
1. [BMW Group](https://www.bmwgroup.com/)
|
||||
1. [Boozt](https://www.booztgroup.com/)
|
||||
1. [Bosch](https://www.bosch.com/)
|
||||
1. [Boticario](https://www.boticario.com.br/)
|
||||
1. [Broker Consulting, a.s.](https://www.bcas.cz/en/)
|
||||
1. [Bulder Bank](https://bulderbank.no)
|
||||
1. [Cabify](https://cabify.com/en)
|
||||
1. [CAM](https://cam-inc.co.jp)
|
||||
1. [Camptocamp](https://camptocamp.com)
|
||||
1. [Candis](https://www.candis.io)
|
||||
@@ -62,12 +64,14 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [Cisco ET&I](https://eti.cisco.com/)
|
||||
1. [Cloud Posse](https://www.cloudposse.com/)
|
||||
1. [Cloud Scale](https://cloudscaleinc.com/)
|
||||
1. [CloudScript](https://www.cloudscript.com.br/)
|
||||
1. [CloudGeometry](https://www.cloudgeometry.io/)
|
||||
1. [Cloudmate](https://cloudmt.co.kr/)
|
||||
1. [Cloudogu](https://cloudogu.com/)
|
||||
1. [Cobalt](https://www.cobalt.io/)
|
||||
1. [Codefresh](https://www.codefresh.io/)
|
||||
1. [Codility](https://www.codility.com/)
|
||||
1. [Cognizant](https://www.cognizant.com/)
|
||||
1. [Commonbond](https://commonbond.co/)
|
||||
1. [Contlo](https://contlo.com/)
|
||||
1. [Coralogix](https://coralogix.com/)
|
||||
@@ -109,9 +113,11 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [Freshop, Inc](https://www.freshop.com/)
|
||||
1. [Future PLC](https://www.futureplc.com/)
|
||||
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)
|
||||
1. [Generali Deutschland AG](https://www.generali.de/)
|
||||
1. [Gepardec](https://gepardec.com/)
|
||||
1. [Getir](https://getir.com)
|
||||
1. [GetYourGuide](https://www.getyourguide.com/)
|
||||
1. [Gitpod](https://www.gitpod.io)
|
||||
1. [Gllue](https://gllue.com)
|
||||
@@ -128,6 +134,7 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [Groww](https://groww.in)
|
||||
1. [Grupo MasMovil](https://grupomasmovil.com/en/)
|
||||
1. [Handelsbanken](https://www.handelsbanken.se)
|
||||
1. [Hazelcast](https://hazelcast.com/)
|
||||
1. [Healy](https://www.healyworld.net)
|
||||
1. [Helio](https://helio.exchange)
|
||||
1. [Hetki](https://hetki.ai)
|
||||
@@ -146,6 +153,7 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [Index Exchange](https://www.indexexchange.com/)
|
||||
1. [Info Support](https://www.infosupport.com/)
|
||||
1. [InsideBoard](https://www.insideboard.com)
|
||||
1. [Instruqt](https://www.instruqt.com)
|
||||
1. [Intuit](https://www.intuit.com/)
|
||||
1. [Jellysmack](https://www.jellysmack.com)
|
||||
1. [Joblift](https://joblift.com/)
|
||||
@@ -155,6 +163,7 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [Karrot](https://www.daangn.com/)
|
||||
1. [KarrotPay](https://www.daangnpay.com/)
|
||||
1. [Kasa](https://kasa.co.kr/)
|
||||
1. [Kave Home](https://kavehome.com)
|
||||
1. [Keeeb](https://www.keeeb.com/)
|
||||
1. [KelkooGroup](https://www.kelkoogroup.com)
|
||||
1. [Keptn](https://keptn.sh)
|
||||
@@ -167,6 +176,8 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [Kurly](https://www.kurly.com/)
|
||||
1. [Kvist](https://kvistsolutions.com)
|
||||
1. [Kyriba](https://www.kyriba.com/)
|
||||
1. [LeFigaro](https://www.lefigaro.fr/)
|
||||
1. [Lely](https://www.lely.com/)
|
||||
1. [LexisNexis](https://www.lexisnexis.com/)
|
||||
1. [Lian Chu Securities](https://lczq.com)
|
||||
1. [Liatrio](https://www.liatrio.com)
|
||||
@@ -197,11 +208,14 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [Money Forward](https://corp.moneyforward.com/en/)
|
||||
1. [MOO Print](https://www.moo.com/)
|
||||
1. [MTN Group](https://www.mtn.com/)
|
||||
1. [Municipality of The Hague](https://www.denhaag.nl/)
|
||||
1. [My Job Glasses](https://myjobglasses.com)
|
||||
1. [Natura &Co](https://naturaeco.com/)
|
||||
1. [Nethopper](https://nethopper.io)
|
||||
1. [New Relic](https://newrelic.com/)
|
||||
1. [Nextbasket](https://nextbasket.com)
|
||||
1. [Nextdoor](https://nextdoor.com/)
|
||||
1. [Next Fit Sistemas](https://nextfit.com.br/)
|
||||
1. [Nikkei](https://www.nikkei.co.jp/nikkeiinfo/en/)
|
||||
1. [Nitro](https://gonitro.com)
|
||||
1. [NYCU, CS IT Center](https://it.cs.nycu.edu.tw)
|
||||
@@ -213,6 +227,7 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [omegaUp](https://omegaUp.com)
|
||||
1. [Omni](https://omni.se/)
|
||||
1. [Oncourse Home Solutions](https://oncoursehome.com/)
|
||||
1. [Open Analytics](https://openanalytics.eu)
|
||||
1. [openEuler](https://openeuler.org)
|
||||
1. [openGauss](https://opengauss.org/)
|
||||
1. [OpenGov](https://opengov.com)
|
||||
@@ -245,6 +260,7 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [PostFinance](https://github.com/postfinance)
|
||||
1. [Preferred Networks](https://preferred.jp/en/)
|
||||
1. [Previder BV](https://previder.nl)
|
||||
1. [Priceline](https://priceline.com)
|
||||
1. [Procore](https://www.procore.com)
|
||||
1. [Productboard](https://www.productboard.com/)
|
||||
1. [Prudential](https://prudential.com.sg)
|
||||
@@ -260,6 +276,7 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [Redpill Linpro](https://www.redpill-linpro.com/)
|
||||
1. [Reenigne Cloud](https://reenigne.ca)
|
||||
1. [reev.com](https://www.reev.com/)
|
||||
1. [Relex Solutions](https://www.relexsolutions.com/)
|
||||
1. [RightRev](https://rightrev.com/)
|
||||
1. [Rijkswaterstaat](https://www.rijkswaterstaat.nl/en)
|
||||
1. [Rise](https://www.risecard.eu/)
|
||||
@@ -276,10 +293,13 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [Schwarz IT](https://jobs.schwarz/it-mission)
|
||||
1. [SCRM Lidl International Hub](https://scrm.lidl)
|
||||
1. [SEEK](https://seek.com.au)
|
||||
1. [SEKAI](https://www.sekai.io/)
|
||||
1. [Semgrep](https://semgrep.com)
|
||||
1. [Shield](https://shield.com)
|
||||
1. [SI Analytics](https://si-analytics.ai)
|
||||
1. [Sidewalk Entertainment](https://sidewalkplay.com/)
|
||||
1. [Skit](https://skit.ai/)
|
||||
1. [Skribble](https://skribble.com)
|
||||
1. [Skyscanner](https://www.skyscanner.net/)
|
||||
1. [Smart Pension](https://www.smartpension.co.uk/)
|
||||
1. [Smilee.io](https://smilee.io)
|
||||
|
||||
@@ -43,7 +43,9 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/controllers/template"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/generators"
|
||||
"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"
|
||||
@@ -126,23 +128,26 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
if err := r.migrateStatus(ctx, &applicationSetInfo); err != nil {
|
||||
logCtx.Errorf("failed to migrate status subresource %v", err)
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
// Log a warning if there are unrecognized generators
|
||||
_ = utils.CheckInvalidGenerators(&applicationSetInfo)
|
||||
// desiredApplications is the main list of all expected Applications from all generators in this appset.
|
||||
desiredApplications, applicationSetReason, generatorsErr := r.generateApplications(logCtx, applicationSetInfo)
|
||||
if generatorsErr != nil {
|
||||
desiredApplications, applicationSetReason, err := template.GenerateApplications(logCtx, applicationSetInfo, r.Generators, r.Renderer, r.Client)
|
||||
if err != nil {
|
||||
_ = r.setApplicationSetStatusCondition(ctx,
|
||||
&applicationSetInfo,
|
||||
argov1alpha1.ApplicationSetCondition{
|
||||
Type: argov1alpha1.ApplicationSetConditionErrorOccurred,
|
||||
Message: generatorsErr.Error(),
|
||||
Message: err.Error(),
|
||||
Reason: string(applicationSetReason),
|
||||
Status: argov1alpha1.ApplicationSetConditionStatusTrue,
|
||||
}, parametersGenerated,
|
||||
)
|
||||
if len(desiredApplications) < 1 {
|
||||
return ctrl.Result{}, generatorsErr
|
||||
}
|
||||
return ctrl.Result{RequeueAfter: ReconcileRequeueOnValidationError}, err
|
||||
}
|
||||
|
||||
parametersGenerated = true
|
||||
@@ -320,7 +325,7 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
|
||||
|
||||
requeueAfter := r.getMinRequeueAfter(&applicationSetInfo)
|
||||
|
||||
if len(validateErrors) == 0 && generatorsErr == nil {
|
||||
if len(validateErrors) == 0 {
|
||||
if err := r.setApplicationSetStatusCondition(ctx,
|
||||
&applicationSetInfo,
|
||||
argov1alpha1.ApplicationSetCondition{
|
||||
@@ -495,88 +500,6 @@ func (r *ApplicationSetReconciler) getMinRequeueAfter(applicationSetInfo *argov1
|
||||
return res
|
||||
}
|
||||
|
||||
func getTempApplication(applicationSetTemplate argov1alpha1.ApplicationSetTemplate) *argov1alpha1.Application {
|
||||
var tmplApplication argov1alpha1.Application
|
||||
tmplApplication.Annotations = applicationSetTemplate.Annotations
|
||||
tmplApplication.Labels = applicationSetTemplate.Labels
|
||||
tmplApplication.Namespace = applicationSetTemplate.Namespace
|
||||
tmplApplication.Name = applicationSetTemplate.Name
|
||||
tmplApplication.Spec = applicationSetTemplate.Spec
|
||||
tmplApplication.Finalizers = applicationSetTemplate.Finalizers
|
||||
|
||||
return &tmplApplication
|
||||
}
|
||||
|
||||
func (r *ApplicationSetReconciler) generateApplications(logCtx *log.Entry, applicationSetInfo argov1alpha1.ApplicationSet) ([]argov1alpha1.Application, argov1alpha1.ApplicationSetReasonType, error) {
|
||||
var res []argov1alpha1.Application
|
||||
|
||||
var firstError error
|
||||
var applicationSetReason argov1alpha1.ApplicationSetReasonType
|
||||
|
||||
for _, requestedGenerator := range applicationSetInfo.Spec.Generators {
|
||||
t, err := generators.Transform(requestedGenerator, r.Generators, applicationSetInfo.Spec.Template, &applicationSetInfo, map[string]interface{}{}, r.Client)
|
||||
if err != nil {
|
||||
logCtx.WithError(err).WithField("generator", requestedGenerator).
|
||||
Error("error generating application from params")
|
||||
if firstError == nil {
|
||||
firstError = err
|
||||
applicationSetReason = argov1alpha1.ApplicationSetReasonApplicationParamsGenerationError
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
for _, a := range t {
|
||||
tmplApplication := getTempApplication(a.Template)
|
||||
|
||||
for _, p := range a.Params {
|
||||
app, err := r.Renderer.RenderTemplateParams(tmplApplication, applicationSetInfo.Spec.SyncPolicy, p, applicationSetInfo.Spec.GoTemplate, applicationSetInfo.Spec.GoTemplateOptions)
|
||||
if err != nil {
|
||||
logCtx.WithError(err).WithField("params", a.Params).WithField("generator", requestedGenerator).
|
||||
Error("error generating application from params")
|
||||
|
||||
if firstError == nil {
|
||||
firstError = err
|
||||
applicationSetReason = argov1alpha1.ApplicationSetReasonRenderTemplateParamsError
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if applicationSetInfo.Spec.TemplatePatch != nil {
|
||||
patchedApplication, err := r.applyTemplatePatch(app, applicationSetInfo, p)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("params", a.Params).WithField("generator", requestedGenerator).
|
||||
Error("error generating application from params")
|
||||
|
||||
if firstError == nil {
|
||||
firstError = err
|
||||
applicationSetReason = argov1alpha1.ApplicationSetReasonRenderTemplateParamsError
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
app = patchedApplication
|
||||
}
|
||||
|
||||
res = append(res, *app)
|
||||
}
|
||||
}
|
||||
|
||||
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 (r *ApplicationSetReconciler) applyTemplatePatch(app *argov1alpha1.Application, applicationSetInfo argov1alpha1.ApplicationSet, params map[string]interface{}) (*argov1alpha1.Application, error) {
|
||||
replacedTemplate, err := r.Renderer.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)
|
||||
}
|
||||
|
||||
return applyTemplatePatch(app, replacedTemplate)
|
||||
}
|
||||
|
||||
func ignoreNotAllowedNamespaces(namespaces []string) predicate.Predicate {
|
||||
return predicate.Funcs{
|
||||
CreateFunc: func(e event.CreateEvent) bool {
|
||||
@@ -650,10 +573,6 @@ func (r *ApplicationSetReconciler) createOrUpdateInCluster(ctx context.Context,
|
||||
var firstError error
|
||||
// Creates or updates the application in appList
|
||||
for _, generatedApp := range desiredApplications {
|
||||
// The app's namespace must be the same as the AppSet's namespace to preserve the appsets-in-any-namespace
|
||||
// security boundary.
|
||||
generatedApp.Namespace = applicationSet.Namespace
|
||||
|
||||
appLog := logCtx.WithFields(log.Fields{"app": generatedApp.QualifiedName()})
|
||||
|
||||
// Normalize to avoid fighting with the application controller.
|
||||
@@ -925,14 +844,14 @@ func (r *ApplicationSetReconciler) removeFinalizerOnInvalidDestination(ctx conte
|
||||
func (r *ApplicationSetReconciler) removeOwnerReferencesOnDeleteAppSet(ctx context.Context, applicationSet argov1alpha1.ApplicationSet) error {
|
||||
applications, err := r.getCurrentApplications(ctx, applicationSet)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("error getting current applications for ApplicationSet: %w", err)
|
||||
}
|
||||
|
||||
for _, app := range applications {
|
||||
app.SetOwnerReferences([]metav1.OwnerReference{})
|
||||
err := r.Client.Update(ctx, &app)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("error updating application: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1153,6 +1072,13 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatus(ctx con
|
||||
} else {
|
||||
// we have an existing AppStatus
|
||||
currentAppStatus = applicationSet.Status.ApplicationStatus[idx]
|
||||
|
||||
// upgrade any existing AppStatus that might have been set by an older argo-cd version
|
||||
// note: currentAppStatus.TargetRevisions may be set to empty list earlier during migrations,
|
||||
// to prevent other usage of r.Client.Status().Update to fail before reaching here.
|
||||
if currentAppStatus.TargetRevisions == nil || len(currentAppStatus.TargetRevisions) == 0 {
|
||||
currentAppStatus.TargetRevisions = app.Status.GetRevisions()
|
||||
}
|
||||
}
|
||||
|
||||
appOutdated := false
|
||||
@@ -1350,9 +1276,30 @@ func findApplicationStatusIndex(appStatuses []argov1alpha1.ApplicationSetApplica
|
||||
return -1
|
||||
}
|
||||
|
||||
// migrateStatus run migrations on the status subresource of ApplicationSet early during the run of ApplicationSetReconciler.Reconcile
|
||||
// this handles any defaulting of values - which would otherwise cause the references to r.Client.Status().Update to fail given missing required fields.
|
||||
func (r *ApplicationSetReconciler) migrateStatus(ctx context.Context, appset *argov1alpha1.ApplicationSet) error {
|
||||
update := false
|
||||
if statusList := appset.Status.ApplicationStatus; statusList != nil {
|
||||
for idx := range statusList {
|
||||
if statusList[idx].TargetRevisions == nil {
|
||||
statusList[idx].TargetRevisions = []string{}
|
||||
update = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if update {
|
||||
if err := r.Client.Status().Update(ctx, appset); err != nil {
|
||||
return fmt.Errorf("unable to set application set status: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *ApplicationSetReconciler) updateResourcesStatus(ctx context.Context, logCtx *log.Entry, appset *argov1alpha1.ApplicationSet, apps []argov1alpha1.Application) error {
|
||||
statusMap := getResourceStatusMap(appset)
|
||||
statusMap = buildResourceStatus(statusMap, apps)
|
||||
statusMap := status.GetResourceStatusMap(appset)
|
||||
statusMap = status.BuildResourceStatus(statusMap, apps)
|
||||
|
||||
statuses := []argov1alpha1.ResourceStatus{}
|
||||
for _, status := range statusMap {
|
||||
@@ -1377,59 +1324,7 @@ func (r *ApplicationSetReconciler) updateResourcesStatus(ctx context.Context, lo
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildResourceStatus(statusMap map[string]argov1alpha1.ResourceStatus, apps []argov1alpha1.Application) map[string]argov1alpha1.ResourceStatus {
|
||||
appMap := map[string]argov1alpha1.Application{}
|
||||
for _, app := range apps {
|
||||
appCopy := app
|
||||
appMap[app.Name] = app
|
||||
|
||||
gvk := app.GroupVersionKind()
|
||||
// Create status if it does not exist
|
||||
status, ok := statusMap[app.Name]
|
||||
if !ok {
|
||||
status = argov1alpha1.ResourceStatus{
|
||||
Group: gvk.Group,
|
||||
Version: gvk.Version,
|
||||
Kind: gvk.Kind,
|
||||
Name: app.Name,
|
||||
Namespace: app.Namespace,
|
||||
Status: app.Status.Sync.Status,
|
||||
Health: &appCopy.Status.Health,
|
||||
}
|
||||
}
|
||||
|
||||
status.Group = gvk.Group
|
||||
status.Version = gvk.Version
|
||||
status.Kind = gvk.Kind
|
||||
status.Name = app.Name
|
||||
status.Namespace = app.Namespace
|
||||
status.Status = app.Status.Sync.Status
|
||||
status.Health = &appCopy.Status.Health
|
||||
|
||||
statusMap[app.Name] = status
|
||||
}
|
||||
cleanupDeletedApplicationStatuses(statusMap, appMap)
|
||||
|
||||
return statusMap
|
||||
}
|
||||
|
||||
func getResourceStatusMap(appset *argov1alpha1.ApplicationSet) map[string]argov1alpha1.ResourceStatus {
|
||||
statusMap := map[string]argov1alpha1.ResourceStatus{}
|
||||
for _, status := range appset.Status.Resources {
|
||||
statusMap[status.Name] = status
|
||||
}
|
||||
return statusMap
|
||||
}
|
||||
|
||||
func cleanupDeletedApplicationStatuses(statusMap map[string]argov1alpha1.ResourceStatus, apps map[string]argov1alpha1.Application) {
|
||||
for name := range statusMap {
|
||||
if _, ok := apps[name]; !ok {
|
||||
delete(statusMap, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// setApplicationSetApplicationStatus updates the ApplicationSet's status field
|
||||
// setAppSetApplicationStatus updates the ApplicationSet's status field
|
||||
// with any new/changed Application statuses.
|
||||
func (r *ApplicationSetReconciler) setAppSetApplicationStatus(ctx context.Context, logCtx *log.Entry, applicationSet *argov1alpha1.ApplicationSet, applicationStatuses []argov1alpha1.ApplicationSetApplicationStatus) error {
|
||||
needToUpdateStatus := false
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -56,14 +56,14 @@ func TestRequeueAfter(t *testing.T) {
|
||||
},
|
||||
}
|
||||
fakeDynClient := dynfake.NewSimpleDynamicClientWithCustomListKinds(runtime.NewScheme(), gvrToListKind, duckType)
|
||||
|
||||
scmConfig := generators.NewSCMConfig("", []string{""}, true, nil)
|
||||
terminalGenerators := map[string]generators.Generator{
|
||||
"List": generators.NewListGenerator(),
|
||||
"Clusters": generators.NewClusterGenerator(k8sClient, ctx, appClientset, "argocd"),
|
||||
"Git": generators.NewGitGenerator(mockServer),
|
||||
"SCMProvider": generators.NewSCMProviderGenerator(fake.NewClientBuilder().WithObjects(&corev1.Secret{}).Build(), generators.SCMAuthProviders{}, "", []string{""}, true),
|
||||
"SCMProvider": generators.NewSCMProviderGenerator(fake.NewClientBuilder().WithObjects(&corev1.Secret{}).Build(), scmConfig),
|
||||
"ClusterDecisionResource": generators.NewDuckTypeGenerator(ctx, fakeDynClient, appClientset, "argocd"),
|
||||
"PullRequest": generators.NewPullRequestGenerator(k8sClient, generators.SCMAuthProviders{}, "", []string{""}, true),
|
||||
"PullRequest": generators.NewPullRequestGenerator(k8sClient, scmConfig),
|
||||
}
|
||||
|
||||
nestedGenerators := map[string]generators.Generator{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package controllers
|
||||
package template
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -1,4 +1,4 @@
|
||||
package controllers
|
||||
package template
|
||||
|
||||
import (
|
||||
"testing"
|
||||
99
applicationset/controllers/template/template.go
Normal file
99
applicationset/controllers/template/template.go
Normal file
@@ -0,0 +1,99 @@
|
||||
package template
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/generators"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/utils"
|
||||
|
||||
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) {
|
||||
var res []argov1alpha1.Application
|
||||
|
||||
var firstError error
|
||||
var applicationSetReason argov1alpha1.ApplicationSetReasonType
|
||||
|
||||
for _, requestedGenerator := range applicationSetInfo.Spec.Generators {
|
||||
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")
|
||||
if firstError == nil {
|
||||
firstError = err
|
||||
applicationSetReason = argov1alpha1.ApplicationSetReasonApplicationParamsGenerationError
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
for _, a := range t {
|
||||
tmplApplication := GetTempApplication(a.Template)
|
||||
|
||||
for _, p := range a.Params {
|
||||
app, err := renderer.RenderTemplateParams(tmplApplication, applicationSetInfo.Spec.SyncPolicy, p, applicationSetInfo.Spec.GoTemplate, applicationSetInfo.Spec.GoTemplateOptions)
|
||||
if err != nil {
|
||||
logCtx.WithError(err).WithField("params", a.Params).WithField("generator", requestedGenerator).
|
||||
Error("error generating application from params")
|
||||
|
||||
if firstError == nil {
|
||||
firstError = err
|
||||
applicationSetReason = argov1alpha1.ApplicationSetReasonRenderTemplateParamsError
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if applicationSetInfo.Spec.TemplatePatch != nil {
|
||||
patchedApplication, err := renderTemplatePatch(renderer, app, applicationSetInfo, p)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("params", a.Params).WithField("generator", requestedGenerator).
|
||||
Error("error generating application from params")
|
||||
|
||||
if firstError == nil {
|
||||
firstError = err
|
||||
applicationSetReason = argov1alpha1.ApplicationSetReasonRenderTemplateParamsError
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
app = patchedApplication
|
||||
}
|
||||
|
||||
// The app's namespace must be the same as the AppSet's namespace to preserve the appsets-in-any-namespace
|
||||
// security boundary.
|
||||
app.Namespace = applicationSetInfo.Namespace
|
||||
res = append(res, *app)
|
||||
}
|
||||
}
|
||||
|
||||
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]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)
|
||||
}
|
||||
|
||||
return applyTemplatePatch(app, replacedTemplate)
|
||||
}
|
||||
|
||||
func GetTempApplication(applicationSetTemplate argov1alpha1.ApplicationSetTemplate) *argov1alpha1.Application {
|
||||
var tmplApplication argov1alpha1.Application
|
||||
tmplApplication.Annotations = applicationSetTemplate.Annotations
|
||||
tmplApplication.Labels = applicationSetTemplate.Labels
|
||||
tmplApplication.Namespace = applicationSetTemplate.Namespace
|
||||
tmplApplication.Name = applicationSetTemplate.Name
|
||||
tmplApplication.Spec = applicationSetTemplate.Spec
|
||||
tmplApplication.Finalizers = applicationSetTemplate.Finalizers
|
||||
|
||||
return &tmplApplication
|
||||
}
|
||||
350
applicationset/controllers/template/template_test.go
Normal file
350
applicationset/controllers/template/template_test.go
Normal file
@@ -0,0 +1,350 @@
|
||||
package template
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
"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) {
|
||||
scheme := runtime.NewScheme()
|
||||
err := v1alpha1.AddToScheme(scheme)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = v1alpha1.AddToScheme(scheme)
|
||||
require.NoError(t, err)
|
||||
|
||||
for _, c := range []struct {
|
||||
name string
|
||||
params []map[string]interface{}
|
||||
template v1alpha1.ApplicationSetTemplate
|
||||
generateParamsError error
|
||||
rendererError error
|
||||
expectErr bool
|
||||
expectedReason v1alpha1.ApplicationSetReasonType
|
||||
}{
|
||||
{
|
||||
name: "Generate two applications",
|
||||
params: []map[string]interface{}{{"name": "app1"}, {"name": "app2"}},
|
||||
template: v1alpha1.ApplicationSetTemplate{
|
||||
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{
|
||||
Name: "name",
|
||||
Namespace: "namespace",
|
||||
Labels: map[string]string{"label_name": "label_value"},
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSpec{},
|
||||
},
|
||||
expectedReason: "",
|
||||
},
|
||||
{
|
||||
name: "Handles error from the generator",
|
||||
generateParamsError: fmt.Errorf("error"),
|
||||
expectErr: true,
|
||||
expectedReason: v1alpha1.ApplicationSetReasonApplicationParamsGenerationError,
|
||||
},
|
||||
{
|
||||
name: "Handles error from the render",
|
||||
params: []map[string]interface{}{{"name": "app1"}, {"name": "app2"}},
|
||||
template: v1alpha1.ApplicationSetTemplate{
|
||||
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{
|
||||
Name: "name",
|
||||
Namespace: "namespace",
|
||||
Labels: map[string]string{"label_name": "label_value"},
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSpec{},
|
||||
},
|
||||
rendererError: fmt.Errorf("error"),
|
||||
expectErr: true,
|
||||
expectedReason: v1alpha1.ApplicationSetReasonRenderTemplateParamsError,
|
||||
},
|
||||
} {
|
||||
cc := c
|
||||
app := v1alpha1.Application{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test",
|
||||
Namespace: "namespace",
|
||||
},
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: application.ApplicationKind,
|
||||
APIVersion: "argoproj.io/v1alpha1",
|
||||
},
|
||||
}
|
||||
|
||||
t.Run(cc.name, func(t *testing.T) {
|
||||
generatorMock := genmock.Generator{}
|
||||
generator := v1alpha1.ApplicationSetGenerator{
|
||||
List: &v1alpha1.ListGenerator{},
|
||||
}
|
||||
|
||||
generatorMock.On("GenerateParams", &generator, mock.AnythingOfType("*v1alpha1.ApplicationSet"), mock.Anything).
|
||||
Return(cc.params, cc.generateParamsError)
|
||||
|
||||
generatorMock.On("GetTemplate", &generator).
|
||||
Return(&v1alpha1.ApplicationSetTemplate{})
|
||||
|
||||
rendererMock := rendmock.Renderer{}
|
||||
|
||||
var expectedApps []v1alpha1.Application
|
||||
|
||||
if cc.generateParamsError == nil {
|
||||
for _, p := range cc.params {
|
||||
if cc.rendererError != nil {
|
||||
rendererMock.On("RenderTemplateParams", GetTempApplication(cc.template), mock.AnythingOfType("*v1alpha1.ApplicationSetSyncPolicy"), p, false, []string(nil)).
|
||||
Return(nil, cc.rendererError)
|
||||
} else {
|
||||
rendererMock.On("RenderTemplateParams", GetTempApplication(cc.template), mock.AnythingOfType("*v1alpha1.ApplicationSetSyncPolicy"), p, false, []string(nil)).
|
||||
Return(&app, nil)
|
||||
expectedApps = append(expectedApps, app)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
generators := map[string]generators.Generator{
|
||||
"List": &generatorMock,
|
||||
}
|
||||
renderer := &rendererMock
|
||||
|
||||
got, reason, err := GenerateApplications(log.NewEntry(log.StandardLogger()), v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "name",
|
||||
Namespace: "namespace",
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
Generators: []v1alpha1.ApplicationSetGenerator{generator},
|
||||
Template: cc.template,
|
||||
},
|
||||
},
|
||||
generators,
|
||||
renderer,
|
||||
nil,
|
||||
)
|
||||
|
||||
if cc.expectErr {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
assert.Equal(t, expectedApps, got)
|
||||
assert.Equal(t, cc.expectedReason, reason)
|
||||
generatorMock.AssertNumberOfCalls(t, "GenerateParams", 1)
|
||||
|
||||
if cc.generateParamsError == nil {
|
||||
rendererMock.AssertNumberOfCalls(t, "RenderTemplateParams", len(cc.params))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMergeTemplateApplications(t *testing.T) {
|
||||
for _, c := range []struct {
|
||||
name string
|
||||
params []map[string]interface{}
|
||||
template v1alpha1.ApplicationSetTemplate
|
||||
overrideTemplate v1alpha1.ApplicationSetTemplate
|
||||
expectedMerged v1alpha1.ApplicationSetTemplate
|
||||
expectedApps []v1alpha1.Application
|
||||
}{
|
||||
{
|
||||
name: "Generate app",
|
||||
params: []map[string]interface{}{{"name": "app1"}},
|
||||
template: v1alpha1.ApplicationSetTemplate{
|
||||
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{
|
||||
Name: "name",
|
||||
Namespace: "namespace",
|
||||
Labels: map[string]string{"label_name": "label_value"},
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSpec{},
|
||||
},
|
||||
overrideTemplate: v1alpha1.ApplicationSetTemplate{
|
||||
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{
|
||||
Name: "test",
|
||||
Labels: map[string]string{"foo": "bar"},
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSpec{},
|
||||
},
|
||||
expectedMerged: v1alpha1.ApplicationSetTemplate{
|
||||
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{
|
||||
Name: "test",
|
||||
Namespace: "namespace",
|
||||
Labels: map[string]string{"label_name": "label_value", "foo": "bar"},
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSpec{},
|
||||
},
|
||||
expectedApps: []v1alpha1.Application{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test",
|
||||
Namespace: "test",
|
||||
Labels: map[string]string{"foo": "bar"},
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSpec{},
|
||||
},
|
||||
},
|
||||
},
|
||||
} {
|
||||
cc := c
|
||||
|
||||
t.Run(cc.name, func(t *testing.T) {
|
||||
generatorMock := genmock.Generator{}
|
||||
generator := v1alpha1.ApplicationSetGenerator{
|
||||
List: &v1alpha1.ListGenerator{},
|
||||
}
|
||||
|
||||
generatorMock.On("GenerateParams", &generator, mock.AnythingOfType("*v1alpha1.ApplicationSet"), mock.Anything).
|
||||
Return(cc.params, nil)
|
||||
|
||||
generatorMock.On("GetTemplate", &generator).
|
||||
Return(&cc.overrideTemplate)
|
||||
|
||||
rendererMock := rendmock.Renderer{}
|
||||
|
||||
rendererMock.On("RenderTemplateParams", GetTempApplication(cc.expectedMerged), mock.AnythingOfType("*v1alpha1.ApplicationSetSyncPolicy"), cc.params[0], false, []string(nil)).
|
||||
Return(&cc.expectedApps[0], nil)
|
||||
|
||||
generators := map[string]generators.Generator{
|
||||
"List": &generatorMock,
|
||||
}
|
||||
renderer := &rendererMock
|
||||
|
||||
got, _, _ := GenerateApplications(log.NewEntry(log.StandardLogger()), v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "name",
|
||||
Namespace: "namespace",
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
Generators: []v1alpha1.ApplicationSetGenerator{generator},
|
||||
Template: cc.template,
|
||||
},
|
||||
},
|
||||
generators,
|
||||
renderer,
|
||||
nil,
|
||||
)
|
||||
|
||||
assert.Equal(t, cc.expectedApps, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Test app generation from a go template application set using a pull request generator
|
||||
func TestGenerateAppsUsingPullRequestGenerator(t *testing.T) {
|
||||
for _, cases := range []struct {
|
||||
name string
|
||||
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]interface{}{
|
||||
{
|
||||
"number": "1",
|
||||
"title": "title1",
|
||||
"branch": "branch1",
|
||||
"branch_slug": "branchSlug1",
|
||||
"head_sha": "089d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
"head_short_sha": "089d92cb",
|
||||
"branch_slugify_default": "feat/a_really+long_pull_request_name_to_test_argo_slugification_and_branch_name_shortening_feature",
|
||||
"branch_slugify_smarttruncate_disabled": "feat/areallylongpullrequestnametotestargoslugificationandbranchnameshorteningfeature",
|
||||
"branch_slugify_smarttruncate_enabled": "feat/testwithsmarttruncateenabledramdomlonglistofcharacters",
|
||||
"labels": []string{"label1"},
|
||||
},
|
||||
},
|
||||
template: v1alpha1.ApplicationSetTemplate{
|
||||
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{
|
||||
Name: "AppSet-{{.branch}}-{{.number}}",
|
||||
Labels: map[string]string{
|
||||
"app1": "{{index .labels 0}}",
|
||||
"branch-test1": "AppSet-{{.branch_slugify_default | slugify }}",
|
||||
"branch-test2": "AppSet-{{.branch_slugify_smarttruncate_disabled | slugify 49 false }}",
|
||||
"branch-test3": "AppSet-{{.branch_slugify_smarttruncate_enabled | slugify 50 true }}",
|
||||
},
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSpec{
|
||||
Source: &v1alpha1.ApplicationSource{
|
||||
RepoURL: "https://testurl/testRepo",
|
||||
TargetRevision: "{{.head_short_sha}}",
|
||||
},
|
||||
Destination: v1alpha1.ApplicationDestination{
|
||||
Server: "https://kubernetes.default.svc",
|
||||
Namespace: "AppSet-{{.branch_slug}}-{{.head_sha}}",
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedApp: []v1alpha1.Application{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "AppSet-branch1-1",
|
||||
Labels: map[string]string{
|
||||
"app1": "label1",
|
||||
"branch-test1": "AppSet-feat-a-really-long-pull-request-name-to-test-argo",
|
||||
"branch-test2": "AppSet-feat-areallylongpullrequestnametotestargoslugific",
|
||||
"branch-test3": "AppSet-feat",
|
||||
},
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSpec{
|
||||
Source: &v1alpha1.ApplicationSource{
|
||||
RepoURL: "https://testurl/testRepo",
|
||||
TargetRevision: "089d92cb",
|
||||
},
|
||||
Destination: v1alpha1.ApplicationDestination{
|
||||
Server: "https://kubernetes.default.svc",
|
||||
Namespace: "AppSet-branchSlug1-089d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} {
|
||||
t.Run(cases.name, func(t *testing.T) {
|
||||
generatorMock := genmock.Generator{}
|
||||
generator := v1alpha1.ApplicationSetGenerator{
|
||||
PullRequest: &v1alpha1.PullRequestGenerator{},
|
||||
}
|
||||
|
||||
generatorMock.On("GenerateParams", &generator, mock.AnythingOfType("*v1alpha1.ApplicationSet"), mock.Anything).
|
||||
Return(cases.params, nil)
|
||||
|
||||
generatorMock.On("GetTemplate", &generator).
|
||||
Return(&cases.template, nil)
|
||||
|
||||
generators := map[string]generators.Generator{
|
||||
"PullRequest": &generatorMock,
|
||||
}
|
||||
renderer := &utils.Render{}
|
||||
|
||||
gotApp, _, _ := GenerateApplications(log.NewEntry(log.StandardLogger()), v1alpha1.ApplicationSet{
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
GoTemplate: true,
|
||||
Generators: []v1alpha1.ApplicationSetGenerator{{
|
||||
PullRequest: &v1alpha1.PullRequestGenerator{},
|
||||
}},
|
||||
Template: cases.template,
|
||||
},
|
||||
},
|
||||
generators,
|
||||
renderer,
|
||||
nil,
|
||||
)
|
||||
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, collections.StringMapsEqual(cases.expectedApp[0].ObjectMeta.Labels, gotApp[0].ObjectMeta.Labels))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -85,7 +85,7 @@ func (g *ClusterGenerator) GenerateParams(appSetGenerator *argoappsetv1alpha1.Ap
|
||||
|
||||
clusterSecrets, err := g.getSecretsByClusterName(appSetGenerator)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("error getting cluster secrets: %w", err)
|
||||
}
|
||||
|
||||
res := []map[string]interface{}{}
|
||||
@@ -106,7 +106,7 @@ func (g *ClusterGenerator) GenerateParams(appSetGenerator *argoappsetv1alpha1.Ap
|
||||
|
||||
err = appendTemplatedValues(appSetGenerator.Clusters.Values, params, appSet.Spec.GoTemplate, appSet.Spec.GoTemplateOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("error appending templated values for local cluster: %w", err)
|
||||
}
|
||||
|
||||
res = append(res, params)
|
||||
@@ -146,7 +146,7 @@ func (g *ClusterGenerator) GenerateParams(appSetGenerator *argoappsetv1alpha1.Ap
|
||||
|
||||
err = appendTemplatedValues(appSetGenerator.Clusters.Values, params, appSet.Spec.GoTemplate, appSet.Spec.GoTemplateOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("error appending templated values for cluster: %w", err)
|
||||
}
|
||||
|
||||
res = append(res, params)
|
||||
@@ -164,7 +164,7 @@ func (g *ClusterGenerator) getSecretsByClusterName(appSetGenerator *argoappsetv1
|
||||
selector := metav1.AddLabelToSelector(&appSetGenerator.Clusters.Selector, ArgoCDSecretTypeLabel, ArgoCDSecretTypeCluster)
|
||||
secretSelector, err := metav1.LabelSelectorAsSelector(selector)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("error converting label selector: %w", err)
|
||||
}
|
||||
|
||||
if err := g.Client.List(context.Background(), clusterSecretList, client.MatchingLabelsSelector{Selector: secretSelector}); err != nil {
|
||||
|
||||
@@ -226,7 +226,7 @@ func TestGenerateParams(t *testing.T) {
|
||||
values: nil,
|
||||
expected: nil,
|
||||
clientError: true,
|
||||
expectedError: fmt.Errorf("could not list Secrets"),
|
||||
expectedError: fmt.Errorf("error getting cluster secrets: could not list Secrets"),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -597,7 +597,7 @@ func TestGenerateParamsGoTemplate(t *testing.T) {
|
||||
values: nil,
|
||||
expected: nil,
|
||||
clientError: true,
|
||||
expectedError: fmt.Errorf("could not list Secrets"),
|
||||
expectedError: fmt.Errorf("error getting cluster secrets: could not list Secrets"),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ func (g *DuckTypeGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.A
|
||||
duckResources, err := g.dynClient.Resource(duckGVR).Namespace(g.namespace).List(g.ctx, listOptions)
|
||||
if err != nil {
|
||||
log.WithField("GVK", duckGVR).Warning("resources were not found")
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to get dynamic resources: %w", err)
|
||||
}
|
||||
|
||||
if len(duckResources.Items) == 0 {
|
||||
|
||||
@@ -1073,7 +1073,7 @@ 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")).Return([]map[string]interface{}{
|
||||
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(&argoprojiov1alpha1.ApplicationSetTemplate{})
|
||||
|
||||
100
applicationset/generators/mocks/Generator.go
generated
Normal file
100
applicationset/generators/mocks/Generator.go
generated
Normal file
@@ -0,0 +1,100 @@
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
client "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
time "time"
|
||||
|
||||
v1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
// Generator is an autogenerated mock type for the Generator type
|
||||
type Generator struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// GenerateParams provides a mock function with given fields: appSetGenerator, applicationSetInfo, _a2
|
||||
func (_m *Generator) GenerateParams(appSetGenerator *v1alpha1.ApplicationSetGenerator, applicationSetInfo *v1alpha1.ApplicationSet, _a2 client.Client) ([]map[string]interface{}, error) {
|
||||
ret := _m.Called(appSetGenerator, applicationSetInfo, _a2)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GenerateParams")
|
||||
}
|
||||
|
||||
var r0 []map[string]interface{}
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(*v1alpha1.ApplicationSetGenerator, *v1alpha1.ApplicationSet, client.Client) ([]map[string]interface{}, error)); ok {
|
||||
return rf(appSetGenerator, applicationSetInfo, _a2)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(*v1alpha1.ApplicationSetGenerator, *v1alpha1.ApplicationSet, client.Client) []map[string]interface{}); ok {
|
||||
r0 = rf(appSetGenerator, applicationSetInfo, _a2)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]map[string]interface{})
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(*v1alpha1.ApplicationSetGenerator, *v1alpha1.ApplicationSet, client.Client) error); ok {
|
||||
r1 = rf(appSetGenerator, applicationSetInfo, _a2)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetRequeueAfter provides a mock function with given fields: appSetGenerator
|
||||
func (_m *Generator) GetRequeueAfter(appSetGenerator *v1alpha1.ApplicationSetGenerator) time.Duration {
|
||||
ret := _m.Called(appSetGenerator)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetRequeueAfter")
|
||||
}
|
||||
|
||||
var r0 time.Duration
|
||||
if rf, ok := ret.Get(0).(func(*v1alpha1.ApplicationSetGenerator) time.Duration); ok {
|
||||
r0 = rf(appSetGenerator)
|
||||
} else {
|
||||
r0 = ret.Get(0).(time.Duration)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// GetTemplate provides a mock function with given fields: appSetGenerator
|
||||
func (_m *Generator) GetTemplate(appSetGenerator *v1alpha1.ApplicationSetGenerator) *v1alpha1.ApplicationSetTemplate {
|
||||
ret := _m.Called(appSetGenerator)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetTemplate")
|
||||
}
|
||||
|
||||
var r0 *v1alpha1.ApplicationSetTemplate
|
||||
if rf, ok := ret.Get(0).(func(*v1alpha1.ApplicationSetGenerator) *v1alpha1.ApplicationSetTemplate); ok {
|
||||
r0 = rf(appSetGenerator)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*v1alpha1.ApplicationSetTemplate)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// NewGenerator creates a new instance of Generator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewGenerator(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *Generator {
|
||||
mock := &Generator{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
@@ -6,12 +6,12 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/gosimple/slug"
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
@@ -24,19 +24,13 @@ const (
|
||||
type PullRequestGenerator struct {
|
||||
client client.Client
|
||||
selectServiceProviderFunc func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error)
|
||||
auth SCMAuthProviders
|
||||
scmRootCAPath string
|
||||
allowedSCMProviders []string
|
||||
enableSCMProviders bool
|
||||
SCMConfig
|
||||
}
|
||||
|
||||
func NewPullRequestGenerator(client client.Client, auth SCMAuthProviders, scmRootCAPath string, allowedScmProviders []string, enableSCMProviders bool) Generator {
|
||||
func NewPullRequestGenerator(client client.Client, scmConfig SCMConfig) Generator {
|
||||
g := &PullRequestGenerator{
|
||||
client: client,
|
||||
auth: auth,
|
||||
scmRootCAPath: scmRootCAPath,
|
||||
allowedSCMProviders: allowedScmProviders,
|
||||
enableSCMProviders: enableSCMProviders,
|
||||
client: client,
|
||||
SCMConfig: scmConfig,
|
||||
}
|
||||
g.selectServiceProviderFunc = g.selectServiceProvider
|
||||
return g
|
||||
@@ -103,6 +97,7 @@ func (g *PullRequestGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha
|
||||
|
||||
paramMap := map[string]interface{}{
|
||||
"number": strconv.Itoa(pull.Number),
|
||||
"title": pull.Title,
|
||||
"branch": pull.Branch,
|
||||
"branch_slug": slug.Make(pull.Branch),
|
||||
"target_branch": pull.TargetBranch,
|
||||
@@ -110,6 +105,7 @@ func (g *PullRequestGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha
|
||||
"head_sha": pull.HeadSHA,
|
||||
"head_short_sha": pull.HeadSHA[:shortSHALength],
|
||||
"head_short_sha_7": pull.HeadSHA[:shortSHALength7],
|
||||
"author": pull.Author,
|
||||
}
|
||||
|
||||
// PR lables will only be supported for Go Template appsets, since fasttemplate will be deprecated.
|
||||
@@ -135,15 +131,23 @@ func (g *PullRequestGenerator) selectServiceProvider(ctx context.Context, genera
|
||||
}
|
||||
if generatorConfig.GitLab != nil {
|
||||
providerConfig := generatorConfig.GitLab
|
||||
token, err := g.getSecretRef(ctx, providerConfig.TokenRef, applicationSetInfo.Namespace)
|
||||
var caCerts []byte
|
||||
var prErr error
|
||||
if providerConfig.CARef != nil {
|
||||
caCerts, prErr = utils.GetConfigMapData(ctx, g.client, providerConfig.CARef, applicationSetInfo.Namespace)
|
||||
if prErr != nil {
|
||||
return nil, fmt.Errorf("error fetching CA certificates from ConfigMap: %w", prErr)
|
||||
}
|
||||
}
|
||||
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(ctx, token, providerConfig.API, providerConfig.Project, providerConfig.Labels, providerConfig.PullRequestState, g.scmRootCAPath, providerConfig.Insecure)
|
||||
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 := g.getSecretRef(ctx, providerConfig.TokenRef, applicationSetInfo.Namespace)
|
||||
token, err := utils.GetSecretRef(ctx, g.client, providerConfig.TokenRef, applicationSetInfo.Namespace)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error fetching Secret token: %w", err)
|
||||
}
|
||||
@@ -151,26 +155,40 @@ func (g *PullRequestGenerator) selectServiceProvider(ctx context.Context, genera
|
||||
}
|
||||
if generatorConfig.BitbucketServer != nil {
|
||||
providerConfig := generatorConfig.BitbucketServer
|
||||
if providerConfig.BasicAuth != nil {
|
||||
password, err := g.getSecretRef(ctx, providerConfig.BasicAuth.PasswordRef, applicationSetInfo.Namespace)
|
||||
var caCerts []byte
|
||||
var prErr error
|
||||
if providerConfig.CARef != nil {
|
||||
caCerts, prErr = utils.GetConfigMapData(ctx, g.client, providerConfig.CARef, applicationSetInfo.Namespace)
|
||||
if prErr != nil {
|
||||
return nil, fmt.Errorf("error fetching CA certificates from ConfigMap: %w", prErr)
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
return pullrequest.NewBitbucketServiceBearerToken(ctx, providerConfig.API, appToken, 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)
|
||||
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)
|
||||
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)
|
||||
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 := g.getSecretRef(ctx, providerConfig.BearerToken.TokenRef, applicationSetInfo.Namespace)
|
||||
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 := g.getSecretRef(ctx, providerConfig.BasicAuth.PasswordRef, applicationSetInfo.Namespace)
|
||||
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)
|
||||
}
|
||||
@@ -181,7 +199,7 @@ func (g *PullRequestGenerator) selectServiceProvider(ctx context.Context, genera
|
||||
}
|
||||
if generatorConfig.AzureDevOps != nil {
|
||||
providerConfig := generatorConfig.AzureDevOps
|
||||
token, err := g.getSecretRef(ctx, providerConfig.TokenRef, applicationSetInfo.Namespace)
|
||||
token, err := utils.GetSecretRef(ctx, g.client, providerConfig.TokenRef, applicationSetInfo.Namespace)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error fetching Secret token: %w", err)
|
||||
}
|
||||
@@ -193,7 +211,7 @@ func (g *PullRequestGenerator) selectServiceProvider(ctx context.Context, genera
|
||||
func (g *PullRequestGenerator) github(ctx context.Context, cfg *argoprojiov1alpha1.PullRequestGeneratorGithub, applicationSetInfo *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) {
|
||||
// use an app if it was configured
|
||||
if cfg.AppSecretName != "" {
|
||||
auth, err := g.auth.GitHubApps.GetAuthSecret(ctx, cfg.AppSecretName)
|
||||
auth, err := g.GitHubApps.GetAuthSecret(ctx, cfg.AppSecretName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting GitHub App secret: %w", err)
|
||||
}
|
||||
@@ -201,33 +219,9 @@ func (g *PullRequestGenerator) github(ctx context.Context, cfg *argoprojiov1alph
|
||||
}
|
||||
|
||||
// always default to token, even if not set (public access)
|
||||
token, err := g.getSecretRef(ctx, cfg.TokenRef, applicationSetInfo.Namespace)
|
||||
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(ctx, token, cfg.API, cfg.Owner, cfg.Repo, cfg.Labels)
|
||||
}
|
||||
|
||||
// getSecretRef gets the value of the key for the specified Secret resource.
|
||||
func (g *PullRequestGenerator) getSecretRef(ctx context.Context, ref *argoprojiov1alpha1.SecretRef, namespace string) (string, error) {
|
||||
if ref == nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
secret := &corev1.Secret{}
|
||||
err := g.client.Get(
|
||||
ctx,
|
||||
client.ObjectKey{
|
||||
Name: ref.SecretName,
|
||||
Namespace: namespace,
|
||||
},
|
||||
secret)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error fetching secret %s/%s: %w", namespace, ref.SecretName, err)
|
||||
}
|
||||
tokenBytes, ok := secret.Data[ref.Key]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("key %q in secret %s/%s not found", ref.Key, namespace, ref.SecretName)
|
||||
}
|
||||
return string(tokenBytes), nil
|
||||
}
|
||||
|
||||
@@ -7,9 +7,7 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
|
||||
pullrequest "github.com/argoproj/argo-cd/v2/applicationset/services/pull_request"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
@@ -30,9 +28,11 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
|
||||
[]*pullrequest.PullRequest{
|
||||
{
|
||||
Number: 1,
|
||||
Title: "title1",
|
||||
Branch: "branch1",
|
||||
TargetBranch: "master",
|
||||
HeadSHA: "089d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
Author: "testName",
|
||||
},
|
||||
},
|
||||
nil,
|
||||
@@ -41,6 +41,7 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"number": "1",
|
||||
"title": "title1",
|
||||
"branch": "branch1",
|
||||
"branch_slug": "branch1",
|
||||
"target_branch": "master",
|
||||
@@ -48,6 +49,7 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
|
||||
"head_sha": "089d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
"head_short_sha": "089d92cb",
|
||||
"head_short_sha_7": "089d92c",
|
||||
"author": "testName",
|
||||
},
|
||||
},
|
||||
expectedErr: nil,
|
||||
@@ -59,9 +61,11 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
|
||||
[]*pullrequest.PullRequest{
|
||||
{
|
||||
Number: 2,
|
||||
Title: "title2",
|
||||
Branch: "feat/areally+long_pull_request_name_to_test_argo_slugification_and_branch_name_shortening_feature",
|
||||
TargetBranch: "feat/anotherreally+long_pull_request_name_to_test_argo_slugification_and_branch_name_shortening_feature",
|
||||
HeadSHA: "9b34ff5bd418e57d58891eb0aa0728043ca1e8be",
|
||||
Author: "testName",
|
||||
},
|
||||
},
|
||||
nil,
|
||||
@@ -70,6 +74,7 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"number": "2",
|
||||
"title": "title2",
|
||||
"branch": "feat/areally+long_pull_request_name_to_test_argo_slugification_and_branch_name_shortening_feature",
|
||||
"branch_slug": "feat-areally-long-pull-request-name-to-test-argo",
|
||||
"target_branch": "feat/anotherreally+long_pull_request_name_to_test_argo_slugification_and_branch_name_shortening_feature",
|
||||
@@ -77,6 +82,7 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
|
||||
"head_sha": "9b34ff5bd418e57d58891eb0aa0728043ca1e8be",
|
||||
"head_short_sha": "9b34ff5b",
|
||||
"head_short_sha_7": "9b34ff5",
|
||||
"author": "testName",
|
||||
},
|
||||
},
|
||||
expectedErr: nil,
|
||||
@@ -88,9 +94,11 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
|
||||
[]*pullrequest.PullRequest{
|
||||
{
|
||||
Number: 1,
|
||||
Title: "title1",
|
||||
Branch: "a-very-short-sha",
|
||||
TargetBranch: "master",
|
||||
HeadSHA: "abcd",
|
||||
Author: "testName",
|
||||
},
|
||||
},
|
||||
nil,
|
||||
@@ -99,6 +107,7 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"number": "1",
|
||||
"title": "title1",
|
||||
"branch": "a-very-short-sha",
|
||||
"branch_slug": "a-very-short-sha",
|
||||
"target_branch": "master",
|
||||
@@ -106,6 +115,7 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
|
||||
"head_sha": "abcd",
|
||||
"head_short_sha": "abcd",
|
||||
"head_short_sha_7": "abcd",
|
||||
"author": "testName",
|
||||
},
|
||||
},
|
||||
expectedErr: nil,
|
||||
@@ -128,10 +138,12 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
|
||||
[]*pullrequest.PullRequest{
|
||||
{
|
||||
Number: 1,
|
||||
Title: "title1",
|
||||
Branch: "branch1",
|
||||
TargetBranch: "master",
|
||||
HeadSHA: "089d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
Labels: []string{"preview"},
|
||||
Author: "testName",
|
||||
},
|
||||
},
|
||||
nil,
|
||||
@@ -140,6 +152,7 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"number": "1",
|
||||
"title": "title1",
|
||||
"branch": "branch1",
|
||||
"branch_slug": "branch1",
|
||||
"target_branch": "master",
|
||||
@@ -148,6 +161,7 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
|
||||
"head_short_sha": "089d92cb",
|
||||
"head_short_sha_7": "089d92c",
|
||||
"labels": []string{"preview"},
|
||||
"author": "testName",
|
||||
},
|
||||
},
|
||||
expectedErr: nil,
|
||||
@@ -165,10 +179,12 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
|
||||
[]*pullrequest.PullRequest{
|
||||
{
|
||||
Number: 1,
|
||||
Title: "title1",
|
||||
Branch: "branch1",
|
||||
TargetBranch: "master",
|
||||
HeadSHA: "089d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
Labels: []string{"preview"},
|
||||
Author: "testName",
|
||||
},
|
||||
},
|
||||
nil,
|
||||
@@ -177,6 +193,7 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"number": "1",
|
||||
"title": "title1",
|
||||
"branch": "branch1",
|
||||
"branch_slug": "branch1",
|
||||
"target_branch": "master",
|
||||
@@ -184,6 +201,7 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
|
||||
"head_sha": "089d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
"head_short_sha": "089d92cb",
|
||||
"head_short_sha_7": "089d92c",
|
||||
"author": "testName",
|
||||
},
|
||||
},
|
||||
expectedErr: nil,
|
||||
@@ -214,76 +232,10 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPullRequestGetSecretRef(t *testing.T) {
|
||||
secret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "test-secret", Namespace: "test"},
|
||||
Data: map[string][]byte{
|
||||
"my-token": []byte("secret"),
|
||||
},
|
||||
}
|
||||
gen := &PullRequestGenerator{client: fake.NewClientBuilder().WithObjects(secret).Build()}
|
||||
ctx := context.Background()
|
||||
|
||||
cases := []struct {
|
||||
name, namespace, token string
|
||||
ref *argoprojiov1alpha1.SecretRef
|
||||
hasError bool
|
||||
}{
|
||||
{
|
||||
name: "valid ref",
|
||||
ref: &argoprojiov1alpha1.SecretRef{SecretName: "test-secret", Key: "my-token"},
|
||||
namespace: "test",
|
||||
token: "secret",
|
||||
hasError: false,
|
||||
},
|
||||
{
|
||||
name: "nil ref",
|
||||
ref: nil,
|
||||
namespace: "test",
|
||||
token: "",
|
||||
hasError: false,
|
||||
},
|
||||
{
|
||||
name: "wrong name",
|
||||
ref: &argoprojiov1alpha1.SecretRef{SecretName: "other", Key: "my-token"},
|
||||
namespace: "test",
|
||||
token: "",
|
||||
hasError: true,
|
||||
},
|
||||
{
|
||||
name: "wrong key",
|
||||
ref: &argoprojiov1alpha1.SecretRef{SecretName: "test-secret", Key: "other-token"},
|
||||
namespace: "test",
|
||||
token: "",
|
||||
hasError: true,
|
||||
},
|
||||
{
|
||||
name: "wrong namespace",
|
||||
ref: &argoprojiov1alpha1.SecretRef{SecretName: "test-secret", Key: "my-token"},
|
||||
namespace: "other",
|
||||
token: "",
|
||||
hasError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
token, err := gen.getSecretRef(ctx, c.ref, c.namespace)
|
||||
if c.hasError {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
assert.Equal(t, c.token, token)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllowedSCMProviderPullRequest(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
providerConfig *argoprojiov1alpha1.PullRequestGenerator
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "Error Github",
|
||||
@@ -292,7 +244,6 @@ func TestAllowedSCMProviderPullRequest(t *testing.T) {
|
||||
API: "https://myservice.mynamespace.svc.cluster.local",
|
||||
},
|
||||
},
|
||||
expectedError: &ErrDisallowedSCMProvider{},
|
||||
},
|
||||
{
|
||||
name: "Error Gitlab",
|
||||
@@ -301,7 +252,6 @@ func TestAllowedSCMProviderPullRequest(t *testing.T) {
|
||||
API: "https://myservice.mynamespace.svc.cluster.local",
|
||||
},
|
||||
},
|
||||
expectedError: &ErrDisallowedSCMProvider{},
|
||||
},
|
||||
{
|
||||
name: "Error Gitea",
|
||||
@@ -310,7 +260,6 @@ func TestAllowedSCMProviderPullRequest(t *testing.T) {
|
||||
API: "https://myservice.mynamespace.svc.cluster.local",
|
||||
},
|
||||
},
|
||||
expectedError: &ErrDisallowedSCMProvider{},
|
||||
},
|
||||
{
|
||||
name: "Error Bitbucket",
|
||||
@@ -319,7 +268,6 @@ func TestAllowedSCMProviderPullRequest(t *testing.T) {
|
||||
API: "https://myservice.mynamespace.svc.cluster.local",
|
||||
},
|
||||
},
|
||||
expectedError: &ErrDisallowedSCMProvider{},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -329,13 +277,13 @@ func TestAllowedSCMProviderPullRequest(t *testing.T) {
|
||||
t.Run(testCaseCopy.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
pullRequestGenerator := NewPullRequestGenerator(nil, SCMAuthProviders{}, "", []string{
|
||||
pullRequestGenerator := NewPullRequestGenerator(nil, NewSCMConfig("", []string{
|
||||
"github.myorg.com",
|
||||
"gitlab.myorg.com",
|
||||
"gitea.myorg.com",
|
||||
"bitbucket.myorg.com",
|
||||
"azuredevops.myorg.com",
|
||||
}, true)
|
||||
}, true, nil))
|
||||
|
||||
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
@@ -351,13 +299,14 @@ func TestAllowedSCMProviderPullRequest(t *testing.T) {
|
||||
_, err := pullRequestGenerator.GenerateParams(&applicationSetInfo.Spec.Generators[0], &applicationSetInfo, nil)
|
||||
|
||||
require.Error(t, err, "Must return an error")
|
||||
assert.ErrorAs(t, err, testCaseCopy.expectedError)
|
||||
var expectedError ErrDisallowedSCMProvider
|
||||
assert.ErrorAs(t, err, &expectedError)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSCMProviderDisabled_PRGenerator(t *testing.T) {
|
||||
generator := NewPullRequestGenerator(nil, SCMAuthProviders{}, "", []string{}, false)
|
||||
generator := NewPullRequestGenerator(nil, NewSCMConfig("", []string{}, false, nil))
|
||||
|
||||
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
@@ -29,29 +28,36 @@ type SCMProviderGenerator struct {
|
||||
client client.Client
|
||||
// Testing hooks.
|
||||
overrideProvider scm_provider.SCMProviderService
|
||||
SCMAuthProviders
|
||||
SCMConfig
|
||||
}
|
||||
type SCMConfig struct {
|
||||
scmRootCAPath string
|
||||
allowedSCMProviders []string
|
||||
enableSCMProviders bool
|
||||
GitHubApps github_app_auth.Credentials
|
||||
}
|
||||
|
||||
type SCMAuthProviders struct {
|
||||
GitHubApps github_app_auth.Credentials
|
||||
}
|
||||
|
||||
func NewSCMProviderGenerator(client client.Client, providers SCMAuthProviders, scmRootCAPath string, allowedSCMProviders []string, enableSCMProviders bool) Generator {
|
||||
return &SCMProviderGenerator{
|
||||
client: client,
|
||||
SCMAuthProviders: providers,
|
||||
func NewSCMConfig(scmRootCAPath string, allowedSCMProviders []string, enableSCMProviders bool, gitHubApps github_app_auth.Credentials) SCMConfig {
|
||||
return SCMConfig{
|
||||
scmRootCAPath: scmRootCAPath,
|
||||
allowedSCMProviders: allowedSCMProviders,
|
||||
enableSCMProviders: enableSCMProviders,
|
||||
GitHubApps: gitHubApps,
|
||||
}
|
||||
}
|
||||
|
||||
func NewSCMProviderGenerator(client client.Client, scmConfig SCMConfig) Generator {
|
||||
return &SCMProviderGenerator{
|
||||
client: client,
|
||||
SCMConfig: scmConfig,
|
||||
}
|
||||
}
|
||||
|
||||
// Testing generator
|
||||
func NewTestSCMProviderGenerator(overrideProvider scm_provider.SCMProviderService) Generator {
|
||||
return &SCMProviderGenerator{overrideProvider: overrideProvider, enableSCMProviders: true}
|
||||
return &SCMProviderGenerator{overrideProvider: overrideProvider, SCMConfig: SCMConfig{
|
||||
enableSCMProviders: true,
|
||||
}}
|
||||
}
|
||||
|
||||
func (g *SCMProviderGenerator) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) time.Duration {
|
||||
@@ -139,16 +145,25 @@ func (g *SCMProviderGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha
|
||||
return nil, fmt.Errorf("scm provider: %w", err)
|
||||
}
|
||||
} else if providerConfig.Gitlab != nil {
|
||||
token, err := g.getSecretRef(ctx, providerConfig.Gitlab.TokenRef, applicationSetInfo.Namespace)
|
||||
providerConfig := providerConfig.Gitlab
|
||||
var caCerts []byte
|
||||
var scmError error
|
||||
if providerConfig.CARef != nil {
|
||||
caCerts, scmError = utils.GetConfigMapData(ctx, g.client, providerConfig.CARef, applicationSetInfo.Namespace)
|
||||
if scmError != nil {
|
||||
return nil, fmt.Errorf("error fetching CA certificates from ConfigMap: %w", scmError)
|
||||
}
|
||||
}
|
||||
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(ctx, providerConfig.Gitlab.Group, token, providerConfig.Gitlab.API, providerConfig.Gitlab.AllBranches, providerConfig.Gitlab.IncludeSubgroups, providerConfig.Gitlab.WillIncludeSharedProjects(), providerConfig.Gitlab.Insecure, g.scmRootCAPath, providerConfig.Gitlab.Topic)
|
||||
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)
|
||||
}
|
||||
} else if providerConfig.Gitea != nil {
|
||||
token, err := g.getSecretRef(ctx, providerConfig.Gitea.TokenRef, applicationSetInfo.Namespace)
|
||||
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)
|
||||
}
|
||||
@@ -158,21 +173,34 @@ func (g *SCMProviderGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha
|
||||
}
|
||||
} else if providerConfig.BitbucketServer != nil {
|
||||
providerConfig := providerConfig.BitbucketServer
|
||||
var caCerts []byte
|
||||
var scmError error
|
||||
if providerConfig.BasicAuth != nil {
|
||||
password, err := g.getSecretRef(ctx, providerConfig.BasicAuth.PasswordRef, applicationSetInfo.Namespace)
|
||||
if providerConfig.CARef != nil {
|
||||
caCerts, scmError = utils.GetConfigMapData(ctx, g.client, providerConfig.CARef, applicationSetInfo.Namespace)
|
||||
if scmError != nil {
|
||||
return nil, fmt.Errorf("error fetching CA certificates from ConfigMap: %w", scmError)
|
||||
}
|
||||
}
|
||||
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)
|
||||
} 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)
|
||||
provider, scmError = scm_provider.NewBitbucketServerProviderBasicAuth(ctx, providerConfig.BasicAuth.Username, password, providerConfig.API, providerConfig.Project, providerConfig.AllBranches, g.scmRootCAPath, providerConfig.Insecure, caCerts)
|
||||
} else {
|
||||
provider, scmError = scm_provider.NewBitbucketServerProviderNoAuth(ctx, providerConfig.API, providerConfig.Project, providerConfig.AllBranches)
|
||||
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)
|
||||
}
|
||||
} else if providerConfig.AzureDevOps != nil {
|
||||
token, err := g.getSecretRef(ctx, providerConfig.AzureDevOps.AccessTokenRef, applicationSetInfo.Namespace)
|
||||
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)
|
||||
}
|
||||
@@ -181,7 +209,7 @@ func (g *SCMProviderGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha
|
||||
return nil, fmt.Errorf("error initializing Azure Devops service: %w", err)
|
||||
}
|
||||
} else if providerConfig.Bitbucket != nil {
|
||||
appPassword, err := g.getSecretRef(ctx, providerConfig.Bitbucket.AppPasswordRef, applicationSetInfo.Namespace)
|
||||
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)
|
||||
}
|
||||
@@ -240,29 +268,6 @@ func (g *SCMProviderGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha
|
||||
return paramsArray, nil
|
||||
}
|
||||
|
||||
func (g *SCMProviderGenerator) getSecretRef(ctx context.Context, ref *argoprojiov1alpha1.SecretRef, namespace string) (string, error) {
|
||||
if ref == nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
secret := &corev1.Secret{}
|
||||
err := g.client.Get(
|
||||
ctx,
|
||||
client.ObjectKey{
|
||||
Name: ref.SecretName,
|
||||
Namespace: namespace,
|
||||
},
|
||||
secret)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error fetching secret %s/%s: %w", namespace, ref.SecretName, err)
|
||||
}
|
||||
tokenBytes, ok := secret.Data[ref.Key]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("key %q in secret %s/%s not found", ref.Key, namespace, ref.SecretName)
|
||||
}
|
||||
return string(tokenBytes), nil
|
||||
}
|
||||
|
||||
func (g *SCMProviderGenerator) githubProvider(ctx context.Context, github *argoprojiov1alpha1.SCMProviderGeneratorGithub, applicationSetInfo *argoprojiov1alpha1.ApplicationSet) (scm_provider.SCMProviderService, error) {
|
||||
if github.AppSecretName != "" {
|
||||
auth, err := g.GitHubApps.GetAuthSecret(ctx, github.AppSecretName)
|
||||
@@ -278,7 +283,7 @@ func (g *SCMProviderGenerator) githubProvider(ctx context.Context, github *argop
|
||||
)
|
||||
}
|
||||
|
||||
token, err := g.getSecretRef(ctx, github.TokenRef, applicationSetInfo.Namespace)
|
||||
token, err := utils.GetSecretRef(ctx, g.client, github.TokenRef, applicationSetInfo.Namespace)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error fetching Github token: %w", err)
|
||||
}
|
||||
|
||||
@@ -1,84 +1,16 @@
|
||||
package generators
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/services/scm_provider"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
func TestSCMProviderGetSecretRef(t *testing.T) {
|
||||
secret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "test-secret", Namespace: "test"},
|
||||
Data: map[string][]byte{
|
||||
"my-token": []byte("secret"),
|
||||
},
|
||||
}
|
||||
gen := &SCMProviderGenerator{client: fake.NewClientBuilder().WithObjects(secret).Build()}
|
||||
ctx := context.Background()
|
||||
|
||||
cases := []struct {
|
||||
name, namespace, token string
|
||||
ref *argoprojiov1alpha1.SecretRef
|
||||
hasError bool
|
||||
}{
|
||||
{
|
||||
name: "valid ref",
|
||||
ref: &argoprojiov1alpha1.SecretRef{SecretName: "test-secret", Key: "my-token"},
|
||||
namespace: "test",
|
||||
token: "secret",
|
||||
hasError: false,
|
||||
},
|
||||
{
|
||||
name: "nil ref",
|
||||
ref: nil,
|
||||
namespace: "test",
|
||||
token: "",
|
||||
hasError: false,
|
||||
},
|
||||
{
|
||||
name: "wrong name",
|
||||
ref: &argoprojiov1alpha1.SecretRef{SecretName: "other", Key: "my-token"},
|
||||
namespace: "test",
|
||||
token: "",
|
||||
hasError: true,
|
||||
},
|
||||
{
|
||||
name: "wrong key",
|
||||
ref: &argoprojiov1alpha1.SecretRef{SecretName: "test-secret", Key: "other-token"},
|
||||
namespace: "test",
|
||||
token: "",
|
||||
hasError: true,
|
||||
},
|
||||
{
|
||||
name: "wrong namespace",
|
||||
ref: &argoprojiov1alpha1.SecretRef{SecretName: "test-secret", Key: "my-token"},
|
||||
namespace: "other",
|
||||
token: "",
|
||||
hasError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
token, err := gen.getSecretRef(ctx, c.ref, c.namespace)
|
||||
if c.hasError {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
assert.Equal(t, c.token, token)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSCMProviderGenerateParams(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
@@ -174,7 +106,7 @@ func TestSCMProviderGenerateParams(t *testing.T) {
|
||||
mockProvider := &scm_provider.MockProvider{
|
||||
Repos: testCaseCopy.repos,
|
||||
}
|
||||
scmGenerator := &SCMProviderGenerator{overrideProvider: mockProvider, enableSCMProviders: true}
|
||||
scmGenerator := &SCMProviderGenerator{overrideProvider: mockProvider, SCMConfig: SCMConfig{enableSCMProviders: true}}
|
||||
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "set",
|
||||
@@ -204,7 +136,6 @@ func TestAllowedSCMProvider(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
providerConfig *argoprojiov1alpha1.SCMProviderGenerator
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "Error Github",
|
||||
@@ -213,7 +144,6 @@ func TestAllowedSCMProvider(t *testing.T) {
|
||||
API: "https://myservice.mynamespace.svc.cluster.local",
|
||||
},
|
||||
},
|
||||
expectedError: &ErrDisallowedSCMProvider{},
|
||||
},
|
||||
{
|
||||
name: "Error Gitlab",
|
||||
@@ -222,7 +152,6 @@ func TestAllowedSCMProvider(t *testing.T) {
|
||||
API: "https://myservice.mynamespace.svc.cluster.local",
|
||||
},
|
||||
},
|
||||
expectedError: &ErrDisallowedSCMProvider{},
|
||||
},
|
||||
{
|
||||
name: "Error Gitea",
|
||||
@@ -231,7 +160,6 @@ func TestAllowedSCMProvider(t *testing.T) {
|
||||
API: "https://myservice.mynamespace.svc.cluster.local",
|
||||
},
|
||||
},
|
||||
expectedError: &ErrDisallowedSCMProvider{},
|
||||
},
|
||||
{
|
||||
name: "Error Bitbucket",
|
||||
@@ -240,7 +168,6 @@ func TestAllowedSCMProvider(t *testing.T) {
|
||||
API: "https://myservice.mynamespace.svc.cluster.local",
|
||||
},
|
||||
},
|
||||
expectedError: &ErrDisallowedSCMProvider{},
|
||||
},
|
||||
{
|
||||
name: "Error AzureDevops",
|
||||
@@ -249,7 +176,6 @@ func TestAllowedSCMProvider(t *testing.T) {
|
||||
API: "https://myservice.mynamespace.svc.cluster.local",
|
||||
},
|
||||
},
|
||||
expectedError: &ErrDisallowedSCMProvider{},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -260,14 +186,16 @@ func TestAllowedSCMProvider(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
scmGenerator := &SCMProviderGenerator{
|
||||
allowedSCMProviders: []string{
|
||||
"github.myorg.com",
|
||||
"gitlab.myorg.com",
|
||||
"gitea.myorg.com",
|
||||
"bitbucket.myorg.com",
|
||||
"azuredevops.myorg.com",
|
||||
SCMConfig: SCMConfig{
|
||||
allowedSCMProviders: []string{
|
||||
"github.myorg.com",
|
||||
"gitlab.myorg.com",
|
||||
"gitea.myorg.com",
|
||||
"bitbucket.myorg.com",
|
||||
"azuredevops.myorg.com",
|
||||
},
|
||||
enableSCMProviders: true,
|
||||
},
|
||||
enableSCMProviders: true,
|
||||
}
|
||||
|
||||
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
|
||||
@@ -284,13 +212,14 @@ func TestAllowedSCMProvider(t *testing.T) {
|
||||
_, err := scmGenerator.GenerateParams(&applicationSetInfo.Spec.Generators[0], &applicationSetInfo, nil)
|
||||
|
||||
require.Error(t, err, "Must return an error")
|
||||
assert.ErrorAs(t, err, testCaseCopy.expectedError)
|
||||
var expectedError ErrDisallowedSCMProvider
|
||||
assert.ErrorAs(t, err, &expectedError)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSCMProviderDisabled_SCMGenerator(t *testing.T) {
|
||||
generator := &SCMProviderGenerator{enableSCMProviders: false}
|
||||
generator := &SCMProviderGenerator{SCMConfig: SCMConfig{enableSCMProviders: false}}
|
||||
|
||||
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
|
||||
49
applicationset/generators/utils.go
Normal file
49
applicationset/generators/utils.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package generators
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"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(c, ctx, k8sClient, namespace),
|
||||
"Git": NewGitGenerator(argoCDService),
|
||||
"SCMProvider": NewSCMProviderGenerator(c, scmConfig),
|
||||
"ClusterDecisionResource": NewDuckTypeGenerator(ctx, dynamicClient, k8sClient, namespace),
|
||||
"PullRequest": NewPullRequestGenerator(c, scmConfig),
|
||||
"Plugin": NewPluginGenerator(c, ctx, k8sClient, namespace),
|
||||
}
|
||||
|
||||
nestedGenerators := map[string]Generator{
|
||||
"List": terminalGenerators["List"],
|
||||
"Clusters": terminalGenerators["Clusters"],
|
||||
"Git": terminalGenerators["Git"],
|
||||
"SCMProvider": terminalGenerators["SCMProvider"],
|
||||
"ClusterDecisionResource": terminalGenerators["ClusterDecisionResource"],
|
||||
"PullRequest": terminalGenerators["PullRequest"],
|
||||
"Plugin": terminalGenerators["Plugin"],
|
||||
"Matrix": NewMatrixGenerator(terminalGenerators),
|
||||
"Merge": NewMergeGenerator(terminalGenerators),
|
||||
}
|
||||
|
||||
topLevelGenerators := map[string]Generator{
|
||||
"List": terminalGenerators["List"],
|
||||
"Clusters": terminalGenerators["Clusters"],
|
||||
"Git": terminalGenerators["Git"],
|
||||
"SCMProvider": terminalGenerators["SCMProvider"],
|
||||
"ClusterDecisionResource": terminalGenerators["ClusterDecisionResource"],
|
||||
"PullRequest": terminalGenerators["PullRequest"],
|
||||
"Plugin": terminalGenerators["Plugin"],
|
||||
"Matrix": NewMatrixGenerator(nestedGenerators),
|
||||
"Merge": NewMergeGenerator(nestedGenerators),
|
||||
}
|
||||
|
||||
return topLevelGenerators
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/bradleyfalzon/ghinstallation/v2"
|
||||
"github.com/google/go-github/v35/github"
|
||||
"github.com/google/go-github/v63/github"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/services/github_app_auth"
|
||||
)
|
||||
@@ -26,7 +26,7 @@ func Client(g github_app_auth.Authentication, url string) (*github.Client, error
|
||||
} else {
|
||||
rt.BaseURL = url
|
||||
httpClient := http.Client{Transport: rt}
|
||||
client, err = github.NewEnterpriseClient(url, url, &httpClient)
|
||||
client, err = github.NewClient(&httpClient).WithEnterpriseURLs(url, url)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create github enterprise client: %w", err)
|
||||
}
|
||||
|
||||
2
applicationset/services/mocks/Repos.go
generated
2
applicationset/services/mocks/Repos.go
generated
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.40.2. DO NOT EDIT.
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
|
||||
@@ -95,9 +95,11 @@ 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),
|
||||
HeadSHA: *pr.LastMergeSourceCommit.CommitId,
|
||||
Labels: azureDevOpsLabels,
|
||||
Author: strings.Split(*pr.CreatedBy.UniqueName, "@")[0], // Get the part before the @ in the email-address
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/microsoft/azure-devops-go-api/azuredevops/webapi"
|
||||
|
||||
"github.com/microsoft/azure-devops-go-api/azuredevops/core"
|
||||
git "github.com/microsoft/azure-devops-go-api/azuredevops/git"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -29,6 +31,10 @@ func createLabelsPtr(x []core.WebApiTagDefinition) *[]core.WebApiTagDefinition {
|
||||
return &x
|
||||
}
|
||||
|
||||
func createUniqueNamePtr(x string) *string {
|
||||
return &x
|
||||
}
|
||||
|
||||
type AzureClientFactoryMock struct {
|
||||
mock *mock.Mock
|
||||
}
|
||||
@@ -56,12 +62,15 @@ func TestListPullRequest(t *testing.T) {
|
||||
teamProject := "myorg_project"
|
||||
repoName := "myorg_project_repo"
|
||||
pr_id := 123
|
||||
pr_title := "feat(123)"
|
||||
pr_head_sha := "cd4973d9d14a08ffe6b641a89a68891d6aac8056"
|
||||
ctx := context.Background()
|
||||
uniqueName := "testName"
|
||||
|
||||
pullRequestMock := []git.GitPullRequest{
|
||||
{
|
||||
PullRequestId: createIntPtr(pr_id),
|
||||
Title: createStringPtr(pr_title),
|
||||
SourceRefName: createStringPtr("refs/heads/feature-branch"),
|
||||
LastMergeSourceCommit: &git.GitCommitRef{
|
||||
CommitId: createStringPtr(pr_head_sha),
|
||||
@@ -70,6 +79,9 @@ func TestListPullRequest(t *testing.T) {
|
||||
Repository: &git.GitRepository{
|
||||
Name: createStringPtr(repoName),
|
||||
},
|
||||
CreatedBy: &webapi.IdentityRef{
|
||||
UniqueName: createUniqueNamePtr(uniqueName + "@example.com"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -95,7 +107,9 @@ func TestListPullRequest(t *testing.T) {
|
||||
assert.Len(t, list, 1)
|
||||
assert.Equal(t, "feature-branch", list[0].Branch)
|
||||
assert.Equal(t, pr_head_sha, list[0].HeadSHA)
|
||||
assert.Equal(t, "feat(123)", list[0].Title)
|
||||
assert.Equal(t, pr_id, list[0].Number)
|
||||
assert.Equal(t, uniqueName, list[0].Author)
|
||||
}
|
||||
|
||||
func TestConvertLabes(t *testing.T) {
|
||||
|
||||
@@ -17,7 +17,9 @@ type BitbucketCloudService struct {
|
||||
|
||||
type BitbucketCloudPullRequest struct {
|
||||
ID int `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Source BitbucketCloudPullRequestSource `json:"source"`
|
||||
Author string `json:"author"`
|
||||
}
|
||||
|
||||
type BitbucketCloudPullRequestSource struct {
|
||||
@@ -129,8 +131,10 @@ func (b *BitbucketCloudService) List(_ context.Context) ([]*PullRequest, error)
|
||||
for _, pull := range pulls {
|
||||
pullRequests = append(pullRequests, &PullRequest{
|
||||
Number: pull.ID,
|
||||
Title: pull.Title,
|
||||
Branch: pull.Source.Branch.Name,
|
||||
HeadSHA: pull.Source.Commit.Hash,
|
||||
Author: pull.Author,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ func defaultHandlerCloud(t *testing.T) func(http.ResponseWriter, *http.Request)
|
||||
"values": [
|
||||
{
|
||||
"id": 101,
|
||||
"title": "feat(foo-bar)",
|
||||
"source": {
|
||||
"branch": {
|
||||
"name": "feature/foo-bar"
|
||||
@@ -35,7 +36,8 @@ func defaultHandlerCloud(t *testing.T) func(http.ResponseWriter, *http.Request)
|
||||
"type": "commit",
|
||||
"hash": "1a8dd249c04a"
|
||||
}
|
||||
}
|
||||
},
|
||||
"author": "testName"
|
||||
}
|
||||
]
|
||||
}`)
|
||||
@@ -86,8 +88,10 @@ func TestListPullRequestBearerTokenCloud(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 1)
|
||||
assert.Equal(t, 101, pullRequests[0].Number)
|
||||
assert.Equal(t, "feat(foo-bar)", pullRequests[0].Title)
|
||||
assert.Equal(t, "feature/foo-bar", pullRequests[0].Branch)
|
||||
assert.Equal(t, "1a8dd249c04a", pullRequests[0].HeadSHA)
|
||||
assert.Equal(t, "testName", pullRequests[0].Author)
|
||||
}
|
||||
|
||||
func TestListPullRequestNoAuthCloud(t *testing.T) {
|
||||
@@ -102,8 +106,10 @@ func TestListPullRequestNoAuthCloud(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 1)
|
||||
assert.Equal(t, 101, pullRequests[0].Number)
|
||||
assert.Equal(t, "feat(foo-bar)", pullRequests[0].Title)
|
||||
assert.Equal(t, "feature/foo-bar", pullRequests[0].Branch)
|
||||
assert.Equal(t, "1a8dd249c04a", pullRequests[0].HeadSHA)
|
||||
assert.Equal(t, "testName", pullRequests[0].Author)
|
||||
}
|
||||
|
||||
func TestListPullRequestBasicAuthCloud(t *testing.T) {
|
||||
@@ -118,8 +124,10 @@ func TestListPullRequestBasicAuthCloud(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 1)
|
||||
assert.Equal(t, 101, pullRequests[0].Number)
|
||||
assert.Equal(t, "feat(foo-bar)", pullRequests[0].Title)
|
||||
assert.Equal(t, "feature/foo-bar", pullRequests[0].Branch)
|
||||
assert.Equal(t, "1a8dd249c04a", pullRequests[0].HeadSHA)
|
||||
assert.Equal(t, "testName", pullRequests[0].Author)
|
||||
}
|
||||
|
||||
func TestListPullRequestPaginationCloud(t *testing.T) {
|
||||
@@ -136,6 +144,7 @@ func TestListPullRequestPaginationCloud(t *testing.T) {
|
||||
"values": [
|
||||
{
|
||||
"id": 101,
|
||||
"title": "feat(101)",
|
||||
"source": {
|
||||
"branch": {
|
||||
"name": "feature-101"
|
||||
@@ -144,10 +153,12 @@ func TestListPullRequestPaginationCloud(t *testing.T) {
|
||||
"type": "commit",
|
||||
"hash": "1a8dd249c04a"
|
||||
}
|
||||
}
|
||||
},
|
||||
"author": "testName"
|
||||
},
|
||||
{
|
||||
"id": 102,
|
||||
"title": "feat(102)",
|
||||
"source": {
|
||||
"branch": {
|
||||
"name": "feature-102"
|
||||
@@ -156,7 +167,8 @@ func TestListPullRequestPaginationCloud(t *testing.T) {
|
||||
"type": "commit",
|
||||
"hash": "4cf807e67a6d"
|
||||
}
|
||||
}
|
||||
},
|
||||
"author": "testName"
|
||||
}
|
||||
]
|
||||
}`, r.Host))
|
||||
@@ -169,6 +181,7 @@ func TestListPullRequestPaginationCloud(t *testing.T) {
|
||||
"values": [
|
||||
{
|
||||
"id": 103,
|
||||
"title": "feat(103)",
|
||||
"source": {
|
||||
"branch": {
|
||||
"name": "feature-103"
|
||||
@@ -177,7 +190,8 @@ func TestListPullRequestPaginationCloud(t *testing.T) {
|
||||
"type": "commit",
|
||||
"hash": "6344d9623e3b"
|
||||
}
|
||||
}
|
||||
},
|
||||
"author": "testName"
|
||||
}
|
||||
]
|
||||
}`, r.Host))
|
||||
@@ -196,18 +210,24 @@ func TestListPullRequestPaginationCloud(t *testing.T) {
|
||||
assert.Len(t, pullRequests, 3)
|
||||
assert.Equal(t, PullRequest{
|
||||
Number: 101,
|
||||
Title: "feat(101)",
|
||||
Branch: "feature-101",
|
||||
HeadSHA: "1a8dd249c04a",
|
||||
Author: "testName",
|
||||
}, *pullRequests[0])
|
||||
assert.Equal(t, PullRequest{
|
||||
Number: 102,
|
||||
Title: "feat(102)",
|
||||
Branch: "feature-102",
|
||||
HeadSHA: "4cf807e67a6d",
|
||||
Author: "testName",
|
||||
}, *pullRequests[1])
|
||||
assert.Equal(t, PullRequest{
|
||||
Number: 103,
|
||||
Title: "feat(103)",
|
||||
Branch: "feature-103",
|
||||
HeadSHA: "6344d9623e3b",
|
||||
Author: "testName",
|
||||
}, *pullRequests[2])
|
||||
}
|
||||
|
||||
@@ -309,6 +329,7 @@ func TestListPullRequestBranchMatchCloud(t *testing.T) {
|
||||
"values": [
|
||||
{
|
||||
"id": 101,
|
||||
"title": "feat(101)",
|
||||
"source": {
|
||||
"branch": {
|
||||
"name": "feature-101"
|
||||
@@ -317,10 +338,12 @@ func TestListPullRequestBranchMatchCloud(t *testing.T) {
|
||||
"type": "commit",
|
||||
"hash": "1a8dd249c04a"
|
||||
}
|
||||
}
|
||||
},
|
||||
"author": "testName"
|
||||
},
|
||||
{
|
||||
"id": 200,
|
||||
"title": "feat(200)",
|
||||
"source": {
|
||||
"branch": {
|
||||
"name": "feature-200"
|
||||
@@ -329,7 +352,8 @@ func TestListPullRequestBranchMatchCloud(t *testing.T) {
|
||||
"type": "commit",
|
||||
"hash": "4cf807e67a6d"
|
||||
}
|
||||
}
|
||||
},
|
||||
"author": "testName"
|
||||
}
|
||||
]
|
||||
}`, r.Host))
|
||||
@@ -342,6 +366,7 @@ func TestListPullRequestBranchMatchCloud(t *testing.T) {
|
||||
"values": [
|
||||
{
|
||||
"id": 102,
|
||||
"title": "feat(102)",
|
||||
"source": {
|
||||
"branch": {
|
||||
"name": "feature-102"
|
||||
@@ -350,7 +375,8 @@ func TestListPullRequestBranchMatchCloud(t *testing.T) {
|
||||
"type": "commit",
|
||||
"hash": "6344d9623e3b"
|
||||
}
|
||||
}
|
||||
},
|
||||
"author": "testName"
|
||||
}
|
||||
]
|
||||
}`, r.Host))
|
||||
@@ -374,13 +400,17 @@ func TestListPullRequestBranchMatchCloud(t *testing.T) {
|
||||
assert.Len(t, pullRequests, 2)
|
||||
assert.Equal(t, PullRequest{
|
||||
Number: 101,
|
||||
Title: "feat(101)",
|
||||
Branch: "feature-101",
|
||||
HeadSHA: "1a8dd249c04a",
|
||||
Author: "testName",
|
||||
}, *pullRequests[0])
|
||||
assert.Equal(t, PullRequest{
|
||||
Number: 102,
|
||||
Title: "feat(102)",
|
||||
Branch: "feature-102",
|
||||
HeadSHA: "6344d9623e3b",
|
||||
Author: "testName",
|
||||
}, *pullRequests[1])
|
||||
|
||||
regexp = `.*2$`
|
||||
@@ -395,8 +425,10 @@ func TestListPullRequestBranchMatchCloud(t *testing.T) {
|
||||
assert.Len(t, pullRequests, 1)
|
||||
assert.Equal(t, PullRequest{
|
||||
Number: 102,
|
||||
Title: "feat(102)",
|
||||
Branch: "feature-102",
|
||||
HeadSHA: "6344d9623e3b",
|
||||
Author: "testName",
|
||||
}, *pullRequests[0])
|
||||
|
||||
regexp = `[\d{2}`
|
||||
|
||||
@@ -3,6 +3,7 @@ package pull_request
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
bitbucketv1 "github.com/gfleury/go-bitbucket-v1"
|
||||
log "github.com/sirupsen/logrus"
|
||||
@@ -20,7 +21,7 @@ type BitbucketService struct {
|
||||
|
||||
var _ PullRequestService = (*BitbucketService)(nil)
|
||||
|
||||
func NewBitbucketServiceBasicAuth(ctx context.Context, username, password, url, projectKey, repositorySlug string) (PullRequestService, error) {
|
||||
func NewBitbucketServiceBasicAuth(ctx context.Context, username, password, url, projectKey, repositorySlug string, scmRootCAPath string, insecure bool, caCerts []byte) (PullRequestService, error) {
|
||||
bitbucketConfig := bitbucketv1.NewConfiguration(url)
|
||||
// Avoid the XSRF check
|
||||
bitbucketConfig.AddDefaultHeader("x-atlassian-token", "no-check")
|
||||
@@ -30,15 +31,29 @@ func NewBitbucketServiceBasicAuth(ctx context.Context, username, password, url,
|
||||
UserName: username,
|
||||
Password: password,
|
||||
})
|
||||
return newBitbucketService(ctx, bitbucketConfig, projectKey, repositorySlug)
|
||||
return newBitbucketService(ctx, bitbucketConfig, projectKey, repositorySlug, scmRootCAPath, insecure, caCerts)
|
||||
}
|
||||
|
||||
func NewBitbucketServiceNoAuth(ctx context.Context, url, projectKey, repositorySlug string) (PullRequestService, error) {
|
||||
return newBitbucketService(ctx, bitbucketv1.NewConfiguration(url), projectKey, repositorySlug)
|
||||
func NewBitbucketServiceBearerToken(ctx context.Context, bearerToken, url, projectKey, repositorySlug string, scmRootCAPath string, insecure bool, caCerts []byte) (PullRequestService, error) {
|
||||
bitbucketConfig := bitbucketv1.NewConfiguration(url)
|
||||
// Avoid the XSRF check
|
||||
bitbucketConfig.AddDefaultHeader("x-atlassian-token", "no-check")
|
||||
bitbucketConfig.AddDefaultHeader("x-requested-with", "XMLHttpRequest")
|
||||
|
||||
ctx = context.WithValue(ctx, bitbucketv1.ContextAccessToken, bearerToken)
|
||||
return newBitbucketService(ctx, bitbucketConfig, projectKey, repositorySlug, scmRootCAPath, insecure, caCerts)
|
||||
}
|
||||
|
||||
func newBitbucketService(ctx context.Context, bitbucketConfig *bitbucketv1.Configuration, projectKey, repositorySlug string) (PullRequestService, error) {
|
||||
func NewBitbucketServiceNoAuth(ctx context.Context, url, projectKey, repositorySlug string, scmRootCAPath string, insecure bool, caCerts []byte) (PullRequestService, error) {
|
||||
return newBitbucketService(ctx, bitbucketv1.NewConfiguration(url), projectKey, repositorySlug, scmRootCAPath, insecure, caCerts)
|
||||
}
|
||||
|
||||
func newBitbucketService(ctx context.Context, bitbucketConfig *bitbucketv1.Configuration, projectKey, repositorySlug string, scmRootCAPath string, insecure bool, caCerts []byte) (PullRequestService, error) {
|
||||
bitbucketConfig.BasePath = utils.NormalizeBitbucketBasePath(bitbucketConfig.BasePath)
|
||||
tlsConfig := utils.GetTlsConfig(scmRootCAPath, insecure, caCerts)
|
||||
bitbucketConfig.HTTPClient = &http.Client{Transport: &http.Transport{
|
||||
TLSClientConfig: tlsConfig,
|
||||
}}
|
||||
bitbucketClient := bitbucketv1.NewAPIClient(ctx, bitbucketConfig)
|
||||
|
||||
return &BitbucketService{
|
||||
@@ -68,10 +83,12 @@ func (b *BitbucketService) List(_ context.Context) ([]*PullRequest, error) {
|
||||
for _, pull := range pulls {
|
||||
pullRequests = append(pullRequests, &PullRequest{
|
||||
Number: pull.ID,
|
||||
Title: pull.Title,
|
||||
Branch: pull.FromRef.DisplayID, // ID: refs/heads/main DisplayID: main
|
||||
TargetBranch: pull.ToRef.DisplayID,
|
||||
HeadSHA: pull.FromRef.LatestCommit, // This is not defined in the official docs, but works in practice
|
||||
Labels: []string{}, // Not supported by library
|
||||
Author: pull.Author.User.Name,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@ package pull_request
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@@ -26,6 +28,7 @@ func defaultHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
|
||||
"values": [
|
||||
{
|
||||
"id": 101,
|
||||
"title": "feat(ABC) : 123",
|
||||
"toRef": {
|
||||
"latestCommit": "5b766e3564a3453808f3cd3dd3f2e5fad8ef0e7a",
|
||||
"displayId": "master",
|
||||
@@ -35,6 +38,11 @@ func defaultHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
|
||||
"id": "refs/heads/feature-ABC-123",
|
||||
"displayId": "feature-ABC-123",
|
||||
"latestCommit": "cb3cf2e4d1517c83e720d2585b9402dbef71f992"
|
||||
},
|
||||
"author": {
|
||||
"user": {
|
||||
"name": "testName"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -55,15 +63,17 @@ func TestListPullRequestNoAuth(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
svc, err := NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO")
|
||||
svc, err := NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 1)
|
||||
assert.Equal(t, 101, pullRequests[0].Number)
|
||||
assert.Equal(t, "feat(ABC) : 123", pullRequests[0].Title)
|
||||
assert.Equal(t, "feature-ABC-123", pullRequests[0].Branch)
|
||||
assert.Equal(t, "master", pullRequests[0].TargetBranch)
|
||||
assert.Equal(t, "cb3cf2e4d1517c83e720d2585b9402dbef71f992", pullRequests[0].HeadSHA)
|
||||
assert.Equal(t, "testName", pullRequests[0].Author)
|
||||
}
|
||||
|
||||
func TestListPullRequestPagination(t *testing.T) {
|
||||
@@ -79,6 +89,7 @@ func TestListPullRequestPagination(t *testing.T) {
|
||||
"values": [
|
||||
{
|
||||
"id": 101,
|
||||
"title": "feat(101)",
|
||||
"toRef": {
|
||||
"latestCommit": "5b766e3564a3453808f3cd3dd3f2e5fad8ef0e7a",
|
||||
"displayId": "master",
|
||||
@@ -88,10 +99,16 @@ func TestListPullRequestPagination(t *testing.T) {
|
||||
"id": "refs/heads/feature-101",
|
||||
"displayId": "feature-101",
|
||||
"latestCommit": "ab3cf2e4d1517c83e720d2585b9402dbef71f992"
|
||||
},
|
||||
"author": {
|
||||
"user": {
|
||||
"name": "testName"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 102,
|
||||
"title": "feat(102)",
|
||||
"toRef": {
|
||||
"latestCommit": "5b766e3564a3453808f3cd3dd3f2e5fad8ef0e7a",
|
||||
"displayId": "branch",
|
||||
@@ -101,6 +118,11 @@ func TestListPullRequestPagination(t *testing.T) {
|
||||
"id": "refs/heads/feature-102",
|
||||
"displayId": "feature-102",
|
||||
"latestCommit": "bb3cf2e4d1517c83e720d2585b9402dbef71f992"
|
||||
},
|
||||
"author": {
|
||||
"user": {
|
||||
"name": "testName"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -114,6 +136,7 @@ func TestListPullRequestPagination(t *testing.T) {
|
||||
"values": [
|
||||
{
|
||||
"id": 200,
|
||||
"title": "feat(200)",
|
||||
"toRef": {
|
||||
"latestCommit": "5b766e3564a3453808f3cd3dd3f2e5fad8ef0e7a",
|
||||
"displayId": "master",
|
||||
@@ -123,6 +146,11 @@ func TestListPullRequestPagination(t *testing.T) {
|
||||
"id": "refs/heads/feature-200",
|
||||
"displayId": "feature-200",
|
||||
"latestCommit": "cb3cf2e4d1517c83e720d2585b9402dbef71f992"
|
||||
},
|
||||
"author": {
|
||||
"user": {
|
||||
"name": "testName"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -136,31 +164,37 @@ func TestListPullRequestPagination(t *testing.T) {
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
svc, err := NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO")
|
||||
svc, err := NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 3)
|
||||
assert.Equal(t, PullRequest{
|
||||
Number: 101,
|
||||
Title: "feat(101)",
|
||||
Branch: "feature-101",
|
||||
TargetBranch: "master",
|
||||
HeadSHA: "ab3cf2e4d1517c83e720d2585b9402dbef71f992",
|
||||
Labels: []string{},
|
||||
Author: "testName",
|
||||
}, *pullRequests[0])
|
||||
assert.Equal(t, PullRequest{
|
||||
Number: 102,
|
||||
Title: "feat(102)",
|
||||
Branch: "feature-102",
|
||||
TargetBranch: "branch",
|
||||
HeadSHA: "bb3cf2e4d1517c83e720d2585b9402dbef71f992",
|
||||
Labels: []string{},
|
||||
Author: "testName",
|
||||
}, *pullRequests[1])
|
||||
assert.Equal(t, PullRequest{
|
||||
Number: 200,
|
||||
Title: "feat(200)",
|
||||
Branch: "feature-200",
|
||||
TargetBranch: "master",
|
||||
HeadSHA: "cb3cf2e4d1517c83e720d2585b9402dbef71f992",
|
||||
Labels: []string{},
|
||||
Author: "testName",
|
||||
}, *pullRequests[2])
|
||||
}
|
||||
|
||||
@@ -172,7 +206,7 @@ func TestListPullRequestBasicAuth(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
svc, err := NewBitbucketServiceBasicAuth(context.Background(), "user", "password", ts.URL, "PROJECT", "REPO")
|
||||
svc, err := NewBitbucketServiceBasicAuth(context.Background(), "user", "password", ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.NoError(t, err)
|
||||
@@ -182,12 +216,97 @@ func TestListPullRequestBasicAuth(t *testing.T) {
|
||||
assert.Equal(t, "cb3cf2e4d1517c83e720d2585b9402dbef71f992", pullRequests[0].HeadSHA)
|
||||
}
|
||||
|
||||
func TestListPullRequestBearerAuth(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "Bearer tolkien", r.Header.Get("Authorization"))
|
||||
assert.Equal(t, "no-check", r.Header.Get("X-Atlassian-Token"))
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
svc, err := NewBitbucketServiceBearerToken(context.Background(), "tolkien", ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, pullRequests, 1)
|
||||
assert.Equal(t, 101, pullRequests[0].Number)
|
||||
assert.Equal(t, "feat(ABC) : 123", pullRequests[0].Title)
|
||||
assert.Equal(t, "feature-ABC-123", pullRequests[0].Branch)
|
||||
assert.Equal(t, "cb3cf2e4d1517c83e720d2585b9402dbef71f992", pullRequests[0].HeadSHA)
|
||||
}
|
||||
|
||||
func TestListPullRequestTLS(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
tlsInsecure bool
|
||||
passCerts bool
|
||||
requireErr bool
|
||||
}{
|
||||
{
|
||||
name: "TLS Insecure: true, No Certs",
|
||||
tlsInsecure: true,
|
||||
passCerts: false,
|
||||
requireErr: false,
|
||||
},
|
||||
{
|
||||
name: "TLS Insecure: true, With Certs",
|
||||
tlsInsecure: true,
|
||||
passCerts: true,
|
||||
requireErr: false,
|
||||
},
|
||||
{
|
||||
name: "TLS Insecure: false, With Certs",
|
||||
tlsInsecure: false,
|
||||
passCerts: true,
|
||||
requireErr: false,
|
||||
},
|
||||
{
|
||||
name: "TLS Insecure: false, No Certs",
|
||||
tlsInsecure: false,
|
||||
passCerts: false,
|
||||
requireErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
var certs []byte
|
||||
if test.passCerts == true {
|
||||
for _, cert := range ts.TLS.Certificates {
|
||||
for _, c := range cert.Certificate {
|
||||
parsedCert, err := x509.ParseCertificate(c)
|
||||
require.NoError(t, err, "Failed to parse certificate")
|
||||
certs = append(certs, pem.EncodeToMemory(&pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: parsedCert.Raw,
|
||||
})...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
svc, err := NewBitbucketServiceBasicAuth(context.Background(), "user", "password", ts.URL, "PROJECT", "REPO", "", test.tlsInsecure, certs)
|
||||
require.NoError(t, err)
|
||||
_, err = ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
if test.requireErr {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestListResponseError(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}))
|
||||
defer ts.Close()
|
||||
svc, _ := NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO")
|
||||
svc, _ := NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
_, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.Error(t, err)
|
||||
}
|
||||
@@ -212,7 +331,7 @@ func TestListResponseMalformed(t *testing.T) {
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
svc, _ := NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO")
|
||||
svc, _ := NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
_, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.Error(t, err)
|
||||
}
|
||||
@@ -237,7 +356,7 @@ func TestListResponseEmpty(t *testing.T) {
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
svc, err := NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO")
|
||||
svc, err := NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
|
||||
require.NoError(t, err)
|
||||
@@ -257,6 +376,7 @@ func TestListPullRequestBranchMatch(t *testing.T) {
|
||||
"values": [
|
||||
{
|
||||
"id": 101,
|
||||
"title": "feat(101)",
|
||||
"toRef": {
|
||||
"latestCommit": "5b766e3564a3453808f3cd3dd3f2e5fad8ef0e7a",
|
||||
"displayId": "master",
|
||||
@@ -266,10 +386,16 @@ func TestListPullRequestBranchMatch(t *testing.T) {
|
||||
"id": "refs/heads/feature-101",
|
||||
"displayId": "feature-101",
|
||||
"latestCommit": "ab3cf2e4d1517c83e720d2585b9402dbef71f992"
|
||||
},
|
||||
"author": {
|
||||
"user": {
|
||||
"name": "testName"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 102,
|
||||
"title": "feat(102)",
|
||||
"toRef": {
|
||||
"latestCommit": "5b766e3564a3453808f3cd3dd3f2e5fad8ef0e7a",
|
||||
"displayId": "branch",
|
||||
@@ -279,6 +405,11 @@ func TestListPullRequestBranchMatch(t *testing.T) {
|
||||
"id": "refs/heads/feature-102",
|
||||
"displayId": "feature-102",
|
||||
"latestCommit": "bb3cf2e4d1517c83e720d2585b9402dbef71f992"
|
||||
},
|
||||
"author": {
|
||||
"user": {
|
||||
"name": "testName"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -292,6 +423,7 @@ func TestListPullRequestBranchMatch(t *testing.T) {
|
||||
"values": [
|
||||
{
|
||||
"id": 200,
|
||||
"title": "feat(200)",
|
||||
"toRef": {
|
||||
"latestCommit": "5b766e3564a3453808f3cd3dd3f2e5fad8ef0e7a",
|
||||
"displayId": "master",
|
||||
@@ -301,6 +433,11 @@ func TestListPullRequestBranchMatch(t *testing.T) {
|
||||
"id": "refs/heads/feature-200",
|
||||
"displayId": "feature-200",
|
||||
"latestCommit": "cb3cf2e4d1517c83e720d2585b9402dbef71f992"
|
||||
},
|
||||
"author": {
|
||||
"user": {
|
||||
"name": "testName"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -315,7 +452,7 @@ func TestListPullRequestBranchMatch(t *testing.T) {
|
||||
}))
|
||||
defer ts.Close()
|
||||
regexp := `feature-1[\d]{2}`
|
||||
svc, err := NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO")
|
||||
svc, err := NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{
|
||||
{
|
||||
@@ -326,21 +463,25 @@ func TestListPullRequestBranchMatch(t *testing.T) {
|
||||
assert.Len(t, pullRequests, 2)
|
||||
assert.Equal(t, PullRequest{
|
||||
Number: 101,
|
||||
Title: "feat(101)",
|
||||
Branch: "feature-101",
|
||||
TargetBranch: "master",
|
||||
HeadSHA: "ab3cf2e4d1517c83e720d2585b9402dbef71f992",
|
||||
Labels: []string{},
|
||||
Author: "testName",
|
||||
}, *pullRequests[0])
|
||||
assert.Equal(t, PullRequest{
|
||||
Number: 102,
|
||||
Title: "feat(102)",
|
||||
Branch: "feature-102",
|
||||
TargetBranch: "branch",
|
||||
HeadSHA: "bb3cf2e4d1517c83e720d2585b9402dbef71f992",
|
||||
Labels: []string{},
|
||||
Author: "testName",
|
||||
}, *pullRequests[1])
|
||||
|
||||
regexp = `.*2$`
|
||||
svc, err = NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO")
|
||||
svc, err = NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
pullRequests, err = ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{
|
||||
{
|
||||
@@ -351,14 +492,16 @@ func TestListPullRequestBranchMatch(t *testing.T) {
|
||||
assert.Len(t, pullRequests, 1)
|
||||
assert.Equal(t, PullRequest{
|
||||
Number: 102,
|
||||
Title: "feat(102)",
|
||||
Branch: "feature-102",
|
||||
TargetBranch: "branch",
|
||||
HeadSHA: "bb3cf2e4d1517c83e720d2585b9402dbef71f992",
|
||||
Labels: []string{},
|
||||
Author: "testName",
|
||||
}, *pullRequests[0])
|
||||
|
||||
regexp = `[\d{2}`
|
||||
svc, err = NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO")
|
||||
svc, err = NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
_, err = ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{
|
||||
{
|
||||
|
||||
@@ -57,10 +57,12 @@ func (g *GiteaService) List(ctx context.Context) ([]*PullRequest, error) {
|
||||
for _, pr := range prs {
|
||||
list = append(list, &PullRequest{
|
||||
Number: int(pr.Index),
|
||||
Title: pr.Title,
|
||||
Branch: pr.Head.Ref,
|
||||
TargetBranch: pr.Base.Ref,
|
||||
HeadSHA: pr.Head.Sha,
|
||||
Labels: getGiteaPRLabelNames(pr.Labels),
|
||||
Author: pr.Poster.UserName,
|
||||
})
|
||||
}
|
||||
return list, nil
|
||||
|
||||
@@ -256,9 +256,11 @@ func TestGiteaList(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, prs, 1)
|
||||
assert.Equal(t, 1, prs[0].Number)
|
||||
assert.Equal(t, "add an empty file", prs[0].Title)
|
||||
assert.Equal(t, "test", prs[0].Branch)
|
||||
assert.Equal(t, "main", prs[0].TargetBranch)
|
||||
assert.Equal(t, "7bbaf62d92ddfafd9cc8b340c619abaec32bc09f", prs[0].HeadSHA)
|
||||
assert.Equal(t, "graytshirt", prs[0].Author)
|
||||
}
|
||||
|
||||
func TestGetGiteaPRLabelNames(t *testing.T) {
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/google/go-github/v35/github"
|
||||
"github.com/google/go-github/v63/github"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
@@ -35,7 +35,7 @@ func NewGithubService(ctx context.Context, token, url, owner, repo string, label
|
||||
client = github.NewClient(httpClient)
|
||||
} else {
|
||||
var err error
|
||||
client, err = github.NewEnterpriseClient(url, url, httpClient)
|
||||
client, err = github.NewClient(httpClient).WithEnterpriseURLs(url, url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -66,10 +66,12 @@ func (g *GithubService) List(ctx context.Context) ([]*PullRequest, error) {
|
||||
}
|
||||
pullRequests = append(pullRequests, &PullRequest{
|
||||
Number: *pull.Number,
|
||||
Title: *pull.Title,
|
||||
Branch: *pull.Head.Ref,
|
||||
TargetBranch: *pull.Base.Ref,
|
||||
HeadSHA: *pull.Head.SHA,
|
||||
Labels: getGithubPRLabelNames(pull.Labels),
|
||||
Author: *pull.User.Login,
|
||||
})
|
||||
}
|
||||
if resp.NextPage == 0 {
|
||||
|
||||
@@ -3,7 +3,7 @@ package pull_request
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-github/v35/github"
|
||||
"github.com/google/go-github/v63/github"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ type GitLabService struct {
|
||||
|
||||
var _ PullRequestService = (*GitLabService)(nil)
|
||||
|
||||
func NewGitLabService(ctx context.Context, token, url, project string, labels []string, pullRequestState string, scmRootCAPath string, insecure bool) (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
|
||||
@@ -34,7 +34,7 @@ func NewGitLabService(ctx context.Context, token, url, project string, labels []
|
||||
}
|
||||
|
||||
tr := http.DefaultTransport.(*http.Transport).Clone()
|
||||
tr.TLSClientConfig = utils.GetTlsConfig(scmRootCAPath, insecure)
|
||||
tr.TLSClientConfig = utils.GetTlsConfig(scmRootCAPath, insecure, caCerts)
|
||||
|
||||
retryClient := retryablehttp.NewClient()
|
||||
retryClient.HTTPClient.Transport = tr
|
||||
@@ -56,11 +56,11 @@ func NewGitLabService(ctx context.Context, token, url, project string, labels []
|
||||
|
||||
func (g *GitLabService) List(ctx context.Context) ([]*PullRequest, error) {
|
||||
// Filter the merge requests on labels, if they are specified.
|
||||
var labels *gitlab.Labels
|
||||
var labels *gitlab.LabelOptions
|
||||
if len(g.labels) > 0 {
|
||||
labels = (*gitlab.Labels)(&g.labels)
|
||||
var labelsList gitlab.LabelOptions = g.labels
|
||||
labels = &labelsList
|
||||
}
|
||||
|
||||
opts := &gitlab.ListProjectMergeRequestsOptions{
|
||||
ListOptions: gitlab.ListOptions{
|
||||
PerPage: 100,
|
||||
@@ -81,10 +81,12 @@ func (g *GitLabService) List(ctx context.Context) ([]*PullRequest, error) {
|
||||
for _, mr := range mrs {
|
||||
pullRequests = append(pullRequests, &PullRequest{
|
||||
Number: mr.IID,
|
||||
Title: mr.Title,
|
||||
Branch: mr.SourceBranch,
|
||||
TargetBranch: mr.TargetBranch,
|
||||
HeadSHA: mr.SHA,
|
||||
Labels: mr.Labels,
|
||||
Author: mr.Author.Username,
|
||||
})
|
||||
}
|
||||
if resp.NextPage == 0 {
|
||||
|
||||
@@ -2,6 +2,8 @@ package pull_request
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@@ -35,7 +37,7 @@ func TestGitLabServiceCustomBaseURL(t *testing.T) {
|
||||
writeMRListResponse(t, w)
|
||||
})
|
||||
|
||||
svc, err := NewGitLabService(context.Background(), "", server.URL, "278964", nil, "", "", false)
|
||||
svc, err := NewGitLabService(context.Background(), "", server.URL, "278964", nil, "", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = svc.List(context.Background())
|
||||
@@ -54,7 +56,7 @@ func TestGitLabServiceToken(t *testing.T) {
|
||||
writeMRListResponse(t, w)
|
||||
})
|
||||
|
||||
svc, err := NewGitLabService(context.Background(), "token-123", server.URL, "278964", nil, "", "", false)
|
||||
svc, err := NewGitLabService(context.Background(), "token-123", server.URL, "278964", nil, "", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = svc.List(context.Background())
|
||||
@@ -73,16 +75,18 @@ func TestList(t *testing.T) {
|
||||
writeMRListResponse(t, w)
|
||||
})
|
||||
|
||||
svc, err := NewGitLabService(context.Background(), "", server.URL, "278964", []string{}, "", "", false)
|
||||
svc, err := NewGitLabService(context.Background(), "", server.URL, "278964", []string{}, "", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
prs, err := svc.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, prs, 1)
|
||||
assert.Equal(t, 15442, prs[0].Number)
|
||||
assert.Equal(t, "Draft: Use structured logging for DB load balancer", prs[0].Title)
|
||||
assert.Equal(t, "use-structured-logging-for-db-load-balancer", prs[0].Branch)
|
||||
assert.Equal(t, "master", prs[0].TargetBranch)
|
||||
assert.Equal(t, "2fc4e8b972ff3208ec63b6143e34ad67ff343ad7", prs[0].HeadSHA)
|
||||
assert.Equal(t, "hfyngvason", prs[0].Author)
|
||||
}
|
||||
|
||||
func TestListWithLabels(t *testing.T) {
|
||||
@@ -97,7 +101,7 @@ func TestListWithLabels(t *testing.T) {
|
||||
writeMRListResponse(t, w)
|
||||
})
|
||||
|
||||
svc, err := NewGitLabService(context.Background(), "", server.URL, "278964", []string{"feature", "ready"}, "", "", false)
|
||||
svc, err := NewGitLabService(context.Background(), "", server.URL, "278964", []string{"feature", "ready"}, "", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = svc.List(context.Background())
|
||||
@@ -116,9 +120,77 @@ func TestListWithState(t *testing.T) {
|
||||
writeMRListResponse(t, w)
|
||||
})
|
||||
|
||||
svc, err := NewGitLabService(context.Background(), "", server.URL, "278964", []string{}, "opened", "", false)
|
||||
svc, err := NewGitLabService(context.Background(), "", server.URL, "278964", []string{}, "opened", "", false, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = svc.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestListWithStateTLS(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
tlsInsecure bool
|
||||
passCerts bool
|
||||
requireErr bool
|
||||
}{
|
||||
{
|
||||
name: "TLS Insecure: true, No Certs",
|
||||
tlsInsecure: true,
|
||||
passCerts: false,
|
||||
requireErr: false,
|
||||
},
|
||||
{
|
||||
name: "TLS Insecure: true, With Certs",
|
||||
tlsInsecure: true,
|
||||
passCerts: true,
|
||||
requireErr: false,
|
||||
},
|
||||
{
|
||||
name: "TLS Insecure: false, With Certs",
|
||||
tlsInsecure: false,
|
||||
passCerts: true,
|
||||
requireErr: false,
|
||||
},
|
||||
{
|
||||
name: "TLS Insecure: false, No Certs",
|
||||
tlsInsecure: false,
|
||||
passCerts: false,
|
||||
requireErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
writeMRListResponse(t, w)
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
var certs []byte
|
||||
if test.passCerts == true {
|
||||
for _, cert := range ts.TLS.Certificates {
|
||||
for _, c := range cert.Certificate {
|
||||
parsedCert, err := x509.ParseCertificate(c)
|
||||
require.NoError(t, err, "Failed to parse certificate")
|
||||
certs = append(certs, pem.EncodeToMemory(&pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: parsedCert.Raw,
|
||||
})...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
svc, err := NewGitLabService(context.Background(), "", ts.URL, "278964", []string{}, "opened", "", test.tlsInsecure, certs)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = svc.List(context.Background())
|
||||
if test.requireErr {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ import (
|
||||
type PullRequest struct {
|
||||
// Number is a number that will be the ID of the pull request.
|
||||
Number int
|
||||
// Title of the pull request.
|
||||
Title string
|
||||
// Branch is the name of the branch from which the pull request originated.
|
||||
Branch string
|
||||
// TargetBranch is the name of the target branch of the pull request.
|
||||
@@ -16,6 +18,8 @@ type PullRequest struct {
|
||||
HeadSHA string
|
||||
// Labels of the pull request.
|
||||
Labels []string
|
||||
// Author is the author of the pull request.
|
||||
Author string
|
||||
}
|
||||
|
||||
type PullRequestService interface {
|
||||
|
||||
@@ -20,9 +20,11 @@ func TestFilterBranchMatchBadRegexp(t *testing.T) {
|
||||
[]*PullRequest{
|
||||
{
|
||||
Number: 1,
|
||||
Title: "PR branch1",
|
||||
Branch: "branch1",
|
||||
TargetBranch: "master",
|
||||
HeadSHA: "089d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
Author: "name1",
|
||||
},
|
||||
},
|
||||
nil,
|
||||
@@ -42,27 +44,35 @@ func TestFilterBranchMatch(t *testing.T) {
|
||||
[]*PullRequest{
|
||||
{
|
||||
Number: 1,
|
||||
Title: "PR one",
|
||||
Branch: "one",
|
||||
TargetBranch: "master",
|
||||
HeadSHA: "189d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
Author: "name1",
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Title: "PR two",
|
||||
Branch: "two",
|
||||
TargetBranch: "master",
|
||||
HeadSHA: "289d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
Author: "name2",
|
||||
},
|
||||
{
|
||||
Number: 3,
|
||||
Title: "PR three",
|
||||
Branch: "three",
|
||||
TargetBranch: "master",
|
||||
HeadSHA: "389d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
Author: "name3",
|
||||
},
|
||||
{
|
||||
Number: 4,
|
||||
Title: "PR four",
|
||||
Branch: "four",
|
||||
TargetBranch: "master",
|
||||
HeadSHA: "489d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
Author: "name4",
|
||||
},
|
||||
},
|
||||
nil,
|
||||
@@ -84,27 +94,35 @@ func TestFilterTargetBranchMatch(t *testing.T) {
|
||||
[]*PullRequest{
|
||||
{
|
||||
Number: 1,
|
||||
Title: "PR one",
|
||||
Branch: "one",
|
||||
TargetBranch: "master",
|
||||
HeadSHA: "189d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
Author: "name1",
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Title: "PR two",
|
||||
Branch: "two",
|
||||
TargetBranch: "branch1",
|
||||
HeadSHA: "289d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
Author: "name2",
|
||||
},
|
||||
{
|
||||
Number: 3,
|
||||
Title: "PR three",
|
||||
Branch: "three",
|
||||
TargetBranch: "branch2",
|
||||
HeadSHA: "389d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
Author: "name3",
|
||||
},
|
||||
{
|
||||
Number: 4,
|
||||
Title: "PR four",
|
||||
Branch: "four",
|
||||
TargetBranch: "branch3",
|
||||
HeadSHA: "489d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
Author: "name4",
|
||||
},
|
||||
},
|
||||
nil,
|
||||
@@ -126,27 +144,35 @@ func TestMultiFilterOr(t *testing.T) {
|
||||
[]*PullRequest{
|
||||
{
|
||||
Number: 1,
|
||||
Title: "PR one",
|
||||
Branch: "one",
|
||||
TargetBranch: "master",
|
||||
HeadSHA: "189d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
Author: "name1",
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Title: "PR two",
|
||||
Branch: "two",
|
||||
TargetBranch: "master",
|
||||
HeadSHA: "289d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
Author: "name2",
|
||||
},
|
||||
{
|
||||
Number: 3,
|
||||
Title: "PR three",
|
||||
Branch: "three",
|
||||
TargetBranch: "master",
|
||||
HeadSHA: "389d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
Author: "name3",
|
||||
},
|
||||
{
|
||||
Number: 4,
|
||||
Title: "PR four",
|
||||
Branch: "four",
|
||||
TargetBranch: "master",
|
||||
HeadSHA: "489d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
Author: "name4",
|
||||
},
|
||||
},
|
||||
nil,
|
||||
@@ -173,27 +199,35 @@ func TestMultiFilterOrWithTargetBranchFilter(t *testing.T) {
|
||||
[]*PullRequest{
|
||||
{
|
||||
Number: 1,
|
||||
Title: "PR one",
|
||||
Branch: "one",
|
||||
TargetBranch: "master",
|
||||
HeadSHA: "189d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
Author: "name1",
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Title: "PR two",
|
||||
Branch: "two",
|
||||
TargetBranch: "branch1",
|
||||
HeadSHA: "289d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
Author: "name2",
|
||||
},
|
||||
{
|
||||
Number: 3,
|
||||
Title: "PR three",
|
||||
Branch: "three",
|
||||
TargetBranch: "branch2",
|
||||
HeadSHA: "389d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
Author: "name3",
|
||||
},
|
||||
{
|
||||
Number: 4,
|
||||
Title: "PR four",
|
||||
Branch: "four",
|
||||
TargetBranch: "branch3",
|
||||
HeadSHA: "489d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
Author: "name4",
|
||||
},
|
||||
},
|
||||
nil,
|
||||
@@ -221,15 +255,19 @@ func TestNoFilters(t *testing.T) {
|
||||
[]*PullRequest{
|
||||
{
|
||||
Number: 1,
|
||||
Title: "PR one",
|
||||
Branch: "one",
|
||||
TargetBranch: "master",
|
||||
HeadSHA: "189d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
Author: "name1",
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Title: "PR two",
|
||||
Branch: "two",
|
||||
TargetBranch: "master",
|
||||
HeadSHA: "289d92cbf9ff857a39e6feccd32798ca700fb958",
|
||||
Author: "name2",
|
||||
},
|
||||
},
|
||||
nil,
|
||||
|
||||
@@ -18,8 +18,6 @@ type argoCDService struct {
|
||||
newFileGlobbingEnabled bool
|
||||
}
|
||||
|
||||
//go:generate go run github.com/vektra/mockery/v2@v2.40.2 --name=Repos
|
||||
|
||||
type Repos interface {
|
||||
// GetFiles returns content of files (not directories) within the target repo
|
||||
GetFiles(ctx context.Context, repoURL string, revision string, pattern string, noRevisionCache, verifyCommit bool) (map[string][]byte, error)
|
||||
|
||||
@@ -191,6 +191,6 @@ func TestNewArgoCDService(t *testing.T) {
|
||||
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, err)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, service)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.26.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
@@ -17,14 +17,6 @@ type AWSCodeCommitClient struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type AWSCodeCommitClient_Expecter struct {
|
||||
mock *mock.Mock
|
||||
}
|
||||
|
||||
func (_m *AWSCodeCommitClient) EXPECT() *AWSCodeCommitClient_Expecter {
|
||||
return &AWSCodeCommitClient_Expecter{mock: &_m.Mock}
|
||||
}
|
||||
|
||||
// GetFolderWithContext provides a mock function with given fields: _a0, _a1, _a2
|
||||
func (_m *AWSCodeCommitClient) GetFolderWithContext(_a0 context.Context, _a1 *codecommit.GetFolderInput, _a2 ...request.Option) (*codecommit.GetFolderOutput, error) {
|
||||
_va := make([]interface{}, len(_a2))
|
||||
@@ -36,6 +28,10 @@ func (_m *AWSCodeCommitClient) GetFolderWithContext(_a0 context.Context, _a1 *co
|
||||
_ca = append(_ca, _va...)
|
||||
ret := _m.Called(_ca...)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetFolderWithContext")
|
||||
}
|
||||
|
||||
var r0 *codecommit.GetFolderOutput
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *codecommit.GetFolderInput, ...request.Option) (*codecommit.GetFolderOutput, error)); ok {
|
||||
@@ -58,43 +54,6 @@ func (_m *AWSCodeCommitClient) GetFolderWithContext(_a0 context.Context, _a1 *co
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// AWSCodeCommitClient_GetFolderWithContext_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetFolderWithContext'
|
||||
type AWSCodeCommitClient_GetFolderWithContext_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// GetFolderWithContext is a helper method to define mock.On call
|
||||
// - _a0 context.Context
|
||||
// - _a1 *codecommit.GetFolderInput
|
||||
// - _a2 ...request.Option
|
||||
func (_e *AWSCodeCommitClient_Expecter) GetFolderWithContext(_a0 interface{}, _a1 interface{}, _a2 ...interface{}) *AWSCodeCommitClient_GetFolderWithContext_Call {
|
||||
return &AWSCodeCommitClient_GetFolderWithContext_Call{Call: _e.mock.On("GetFolderWithContext",
|
||||
append([]interface{}{_a0, _a1}, _a2...)...)}
|
||||
}
|
||||
|
||||
func (_c *AWSCodeCommitClient_GetFolderWithContext_Call) Run(run func(_a0 context.Context, _a1 *codecommit.GetFolderInput, _a2 ...request.Option)) *AWSCodeCommitClient_GetFolderWithContext_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
variadicArgs := make([]request.Option, len(args)-2)
|
||||
for i, a := range args[2:] {
|
||||
if a != nil {
|
||||
variadicArgs[i] = a.(request.Option)
|
||||
}
|
||||
}
|
||||
run(args[0].(context.Context), args[1].(*codecommit.GetFolderInput), variadicArgs...)
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *AWSCodeCommitClient_GetFolderWithContext_Call) Return(_a0 *codecommit.GetFolderOutput, _a1 error) *AWSCodeCommitClient_GetFolderWithContext_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *AWSCodeCommitClient_GetFolderWithContext_Call) RunAndReturn(run func(context.Context, *codecommit.GetFolderInput, ...request.Option) (*codecommit.GetFolderOutput, error)) *AWSCodeCommitClient_GetFolderWithContext_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// GetRepositoryWithContext provides a mock function with given fields: _a0, _a1, _a2
|
||||
func (_m *AWSCodeCommitClient) GetRepositoryWithContext(_a0 context.Context, _a1 *codecommit.GetRepositoryInput, _a2 ...request.Option) (*codecommit.GetRepositoryOutput, error) {
|
||||
_va := make([]interface{}, len(_a2))
|
||||
@@ -106,6 +65,10 @@ func (_m *AWSCodeCommitClient) GetRepositoryWithContext(_a0 context.Context, _a1
|
||||
_ca = append(_ca, _va...)
|
||||
ret := _m.Called(_ca...)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetRepositoryWithContext")
|
||||
}
|
||||
|
||||
var r0 *codecommit.GetRepositoryOutput
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *codecommit.GetRepositoryInput, ...request.Option) (*codecommit.GetRepositoryOutput, error)); ok {
|
||||
@@ -128,43 +91,6 @@ func (_m *AWSCodeCommitClient) GetRepositoryWithContext(_a0 context.Context, _a1
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// AWSCodeCommitClient_GetRepositoryWithContext_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetRepositoryWithContext'
|
||||
type AWSCodeCommitClient_GetRepositoryWithContext_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// GetRepositoryWithContext is a helper method to define mock.On call
|
||||
// - _a0 context.Context
|
||||
// - _a1 *codecommit.GetRepositoryInput
|
||||
// - _a2 ...request.Option
|
||||
func (_e *AWSCodeCommitClient_Expecter) GetRepositoryWithContext(_a0 interface{}, _a1 interface{}, _a2 ...interface{}) *AWSCodeCommitClient_GetRepositoryWithContext_Call {
|
||||
return &AWSCodeCommitClient_GetRepositoryWithContext_Call{Call: _e.mock.On("GetRepositoryWithContext",
|
||||
append([]interface{}{_a0, _a1}, _a2...)...)}
|
||||
}
|
||||
|
||||
func (_c *AWSCodeCommitClient_GetRepositoryWithContext_Call) Run(run func(_a0 context.Context, _a1 *codecommit.GetRepositoryInput, _a2 ...request.Option)) *AWSCodeCommitClient_GetRepositoryWithContext_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
variadicArgs := make([]request.Option, len(args)-2)
|
||||
for i, a := range args[2:] {
|
||||
if a != nil {
|
||||
variadicArgs[i] = a.(request.Option)
|
||||
}
|
||||
}
|
||||
run(args[0].(context.Context), args[1].(*codecommit.GetRepositoryInput), variadicArgs...)
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *AWSCodeCommitClient_GetRepositoryWithContext_Call) Return(_a0 *codecommit.GetRepositoryOutput, _a1 error) *AWSCodeCommitClient_GetRepositoryWithContext_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *AWSCodeCommitClient_GetRepositoryWithContext_Call) RunAndReturn(run func(context.Context, *codecommit.GetRepositoryInput, ...request.Option) (*codecommit.GetRepositoryOutput, error)) *AWSCodeCommitClient_GetRepositoryWithContext_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// ListBranchesWithContext provides a mock function with given fields: _a0, _a1, _a2
|
||||
func (_m *AWSCodeCommitClient) ListBranchesWithContext(_a0 context.Context, _a1 *codecommit.ListBranchesInput, _a2 ...request.Option) (*codecommit.ListBranchesOutput, error) {
|
||||
_va := make([]interface{}, len(_a2))
|
||||
@@ -176,6 +102,10 @@ func (_m *AWSCodeCommitClient) ListBranchesWithContext(_a0 context.Context, _a1
|
||||
_ca = append(_ca, _va...)
|
||||
ret := _m.Called(_ca...)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for ListBranchesWithContext")
|
||||
}
|
||||
|
||||
var r0 *codecommit.ListBranchesOutput
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *codecommit.ListBranchesInput, ...request.Option) (*codecommit.ListBranchesOutput, error)); ok {
|
||||
@@ -198,43 +128,6 @@ func (_m *AWSCodeCommitClient) ListBranchesWithContext(_a0 context.Context, _a1
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// AWSCodeCommitClient_ListBranchesWithContext_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListBranchesWithContext'
|
||||
type AWSCodeCommitClient_ListBranchesWithContext_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// ListBranchesWithContext is a helper method to define mock.On call
|
||||
// - _a0 context.Context
|
||||
// - _a1 *codecommit.ListBranchesInput
|
||||
// - _a2 ...request.Option
|
||||
func (_e *AWSCodeCommitClient_Expecter) ListBranchesWithContext(_a0 interface{}, _a1 interface{}, _a2 ...interface{}) *AWSCodeCommitClient_ListBranchesWithContext_Call {
|
||||
return &AWSCodeCommitClient_ListBranchesWithContext_Call{Call: _e.mock.On("ListBranchesWithContext",
|
||||
append([]interface{}{_a0, _a1}, _a2...)...)}
|
||||
}
|
||||
|
||||
func (_c *AWSCodeCommitClient_ListBranchesWithContext_Call) Run(run func(_a0 context.Context, _a1 *codecommit.ListBranchesInput, _a2 ...request.Option)) *AWSCodeCommitClient_ListBranchesWithContext_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
variadicArgs := make([]request.Option, len(args)-2)
|
||||
for i, a := range args[2:] {
|
||||
if a != nil {
|
||||
variadicArgs[i] = a.(request.Option)
|
||||
}
|
||||
}
|
||||
run(args[0].(context.Context), args[1].(*codecommit.ListBranchesInput), variadicArgs...)
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *AWSCodeCommitClient_ListBranchesWithContext_Call) Return(_a0 *codecommit.ListBranchesOutput, _a1 error) *AWSCodeCommitClient_ListBranchesWithContext_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *AWSCodeCommitClient_ListBranchesWithContext_Call) RunAndReturn(run func(context.Context, *codecommit.ListBranchesInput, ...request.Option) (*codecommit.ListBranchesOutput, error)) *AWSCodeCommitClient_ListBranchesWithContext_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// ListRepositoriesWithContext provides a mock function with given fields: _a0, _a1, _a2
|
||||
func (_m *AWSCodeCommitClient) ListRepositoriesWithContext(_a0 context.Context, _a1 *codecommit.ListRepositoriesInput, _a2 ...request.Option) (*codecommit.ListRepositoriesOutput, error) {
|
||||
_va := make([]interface{}, len(_a2))
|
||||
@@ -246,6 +139,10 @@ func (_m *AWSCodeCommitClient) ListRepositoriesWithContext(_a0 context.Context,
|
||||
_ca = append(_ca, _va...)
|
||||
ret := _m.Called(_ca...)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for ListRepositoriesWithContext")
|
||||
}
|
||||
|
||||
var r0 *codecommit.ListRepositoriesOutput
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *codecommit.ListRepositoriesInput, ...request.Option) (*codecommit.ListRepositoriesOutput, error)); ok {
|
||||
@@ -268,50 +165,12 @@ func (_m *AWSCodeCommitClient) ListRepositoriesWithContext(_a0 context.Context,
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// AWSCodeCommitClient_ListRepositoriesWithContext_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListRepositoriesWithContext'
|
||||
type AWSCodeCommitClient_ListRepositoriesWithContext_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// ListRepositoriesWithContext is a helper method to define mock.On call
|
||||
// - _a0 context.Context
|
||||
// - _a1 *codecommit.ListRepositoriesInput
|
||||
// - _a2 ...request.Option
|
||||
func (_e *AWSCodeCommitClient_Expecter) ListRepositoriesWithContext(_a0 interface{}, _a1 interface{}, _a2 ...interface{}) *AWSCodeCommitClient_ListRepositoriesWithContext_Call {
|
||||
return &AWSCodeCommitClient_ListRepositoriesWithContext_Call{Call: _e.mock.On("ListRepositoriesWithContext",
|
||||
append([]interface{}{_a0, _a1}, _a2...)...)}
|
||||
}
|
||||
|
||||
func (_c *AWSCodeCommitClient_ListRepositoriesWithContext_Call) Run(run func(_a0 context.Context, _a1 *codecommit.ListRepositoriesInput, _a2 ...request.Option)) *AWSCodeCommitClient_ListRepositoriesWithContext_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
variadicArgs := make([]request.Option, len(args)-2)
|
||||
for i, a := range args[2:] {
|
||||
if a != nil {
|
||||
variadicArgs[i] = a.(request.Option)
|
||||
}
|
||||
}
|
||||
run(args[0].(context.Context), args[1].(*codecommit.ListRepositoriesInput), variadicArgs...)
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *AWSCodeCommitClient_ListRepositoriesWithContext_Call) Return(_a0 *codecommit.ListRepositoriesOutput, _a1 error) *AWSCodeCommitClient_ListRepositoriesWithContext_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *AWSCodeCommitClient_ListRepositoriesWithContext_Call) RunAndReturn(run func(context.Context, *codecommit.ListRepositoriesInput, ...request.Option) (*codecommit.ListRepositoriesOutput, error)) *AWSCodeCommitClient_ListRepositoriesWithContext_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
type mockConstructorTestingTNewAWSCodeCommitClient interface {
|
||||
// NewAWSCodeCommitClient creates a new instance of AWSCodeCommitClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewAWSCodeCommitClient(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}
|
||||
|
||||
// NewAWSCodeCommitClient creates a new instance of AWSCodeCommitClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
func NewAWSCodeCommitClient(t mockConstructorTestingTNewAWSCodeCommitClient) *AWSCodeCommitClient {
|
||||
}) *AWSCodeCommitClient {
|
||||
mock := &AWSCodeCommitClient{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.26.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
@@ -16,14 +16,6 @@ type AWSTaggingClient struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type AWSTaggingClient_Expecter struct {
|
||||
mock *mock.Mock
|
||||
}
|
||||
|
||||
func (_m *AWSTaggingClient) EXPECT() *AWSTaggingClient_Expecter {
|
||||
return &AWSTaggingClient_Expecter{mock: &_m.Mock}
|
||||
}
|
||||
|
||||
// GetResourcesWithContext provides a mock function with given fields: _a0, _a1, _a2
|
||||
func (_m *AWSTaggingClient) GetResourcesWithContext(_a0 context.Context, _a1 *resourcegroupstaggingapi.GetResourcesInput, _a2 ...request.Option) (*resourcegroupstaggingapi.GetResourcesOutput, error) {
|
||||
_va := make([]interface{}, len(_a2))
|
||||
@@ -35,6 +27,10 @@ func (_m *AWSTaggingClient) GetResourcesWithContext(_a0 context.Context, _a1 *re
|
||||
_ca = append(_ca, _va...)
|
||||
ret := _m.Called(_ca...)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetResourcesWithContext")
|
||||
}
|
||||
|
||||
var r0 *resourcegroupstaggingapi.GetResourcesOutput
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *resourcegroupstaggingapi.GetResourcesInput, ...request.Option) (*resourcegroupstaggingapi.GetResourcesOutput, error)); ok {
|
||||
@@ -57,50 +53,12 @@ func (_m *AWSTaggingClient) GetResourcesWithContext(_a0 context.Context, _a1 *re
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// AWSTaggingClient_GetResourcesWithContext_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetResourcesWithContext'
|
||||
type AWSTaggingClient_GetResourcesWithContext_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// GetResourcesWithContext is a helper method to define mock.On call
|
||||
// - _a0 context.Context
|
||||
// - _a1 *resourcegroupstaggingapi.GetResourcesInput
|
||||
// - _a2 ...request.Option
|
||||
func (_e *AWSTaggingClient_Expecter) GetResourcesWithContext(_a0 interface{}, _a1 interface{}, _a2 ...interface{}) *AWSTaggingClient_GetResourcesWithContext_Call {
|
||||
return &AWSTaggingClient_GetResourcesWithContext_Call{Call: _e.mock.On("GetResourcesWithContext",
|
||||
append([]interface{}{_a0, _a1}, _a2...)...)}
|
||||
}
|
||||
|
||||
func (_c *AWSTaggingClient_GetResourcesWithContext_Call) Run(run func(_a0 context.Context, _a1 *resourcegroupstaggingapi.GetResourcesInput, _a2 ...request.Option)) *AWSTaggingClient_GetResourcesWithContext_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
variadicArgs := make([]request.Option, len(args)-2)
|
||||
for i, a := range args[2:] {
|
||||
if a != nil {
|
||||
variadicArgs[i] = a.(request.Option)
|
||||
}
|
||||
}
|
||||
run(args[0].(context.Context), args[1].(*resourcegroupstaggingapi.GetResourcesInput), variadicArgs...)
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *AWSTaggingClient_GetResourcesWithContext_Call) Return(_a0 *resourcegroupstaggingapi.GetResourcesOutput, _a1 error) *AWSTaggingClient_GetResourcesWithContext_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *AWSTaggingClient_GetResourcesWithContext_Call) RunAndReturn(run func(context.Context, *resourcegroupstaggingapi.GetResourcesInput, ...request.Option) (*resourcegroupstaggingapi.GetResourcesOutput, error)) *AWSTaggingClient_GetResourcesWithContext_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
type mockConstructorTestingTNewAWSTaggingClient interface {
|
||||
// NewAWSTaggingClient creates a new instance of AWSTaggingClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewAWSTaggingClient(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}
|
||||
|
||||
// NewAWSTaggingClient creates a new instance of AWSTaggingClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
func NewAWSTaggingClient(t mockConstructorTestingTNewAWSTaggingClient) *AWSTaggingClient {
|
||||
}) *AWSTaggingClient {
|
||||
mock := &AWSTaggingClient{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
|
||||
@@ -178,8 +178,8 @@ func TestAWSCodeCommitListRepos(t *testing.T) {
|
||||
if repo.getRepositoryNilMetadata {
|
||||
repoMetadata = nil
|
||||
}
|
||||
codeCommitClient.EXPECT().
|
||||
GetRepositoryWithContext(ctx, &codecommit.GetRepositoryInput{RepositoryName: aws.String(repo.name)}).
|
||||
codeCommitClient.
|
||||
On("GetRepositoryWithContext", ctx, &codecommit.GetRepositoryInput{RepositoryName: aws.String(repo.name)}).
|
||||
Return(&codecommit.GetRepositoryOutput{RepositoryMetadata: repoMetadata}, repo.getRepositoryError)
|
||||
codecommitRepoNameIdPairs = append(codecommitRepoNameIdPairs, &codecommit.RepositoryNameIdPair{
|
||||
RepositoryId: aws.String(repo.id),
|
||||
@@ -194,14 +194,14 @@ func TestAWSCodeCommitListRepos(t *testing.T) {
|
||||
}
|
||||
|
||||
if testCase.expectListAtCodeCommit {
|
||||
codeCommitClient.EXPECT().
|
||||
ListRepositoriesWithContext(ctx, &codecommit.ListRepositoriesInput{}).
|
||||
codeCommitClient.
|
||||
On("ListRepositoriesWithContext", ctx, &codecommit.ListRepositoriesInput{}).
|
||||
Return(&codecommit.ListRepositoriesOutput{
|
||||
Repositories: codecommitRepoNameIdPairs,
|
||||
}, testCase.listRepositoryError)
|
||||
} else {
|
||||
taggingClient.EXPECT().
|
||||
GetResourcesWithContext(ctx, mock.MatchedBy(equalIgnoringTagFilterOrder(&resourcegroupstaggingapi.GetResourcesInput{
|
||||
taggingClient.
|
||||
On("GetResourcesWithContext", ctx, mock.MatchedBy(equalIgnoringTagFilterOrder(&resourcegroupstaggingapi.GetResourcesInput{
|
||||
TagFilters: testCase.expectTagFilters,
|
||||
ResourceTypeFilters: aws.StringSlice([]string{resourceTypeCodeCommitRepository}),
|
||||
}))).
|
||||
@@ -351,8 +351,8 @@ func TestAWSCodeCommitRepoHasPath(t *testing.T) {
|
||||
taggingClient := mocks.NewAWSTaggingClient(t)
|
||||
ctx := context.Background()
|
||||
if testCase.expectedGetFolderPath != "" {
|
||||
codeCommitClient.EXPECT().
|
||||
GetFolderWithContext(ctx, &codecommit.GetFolderInput{
|
||||
codeCommitClient.
|
||||
On("GetFolderWithContext", ctx, &codecommit.GetFolderInput{
|
||||
CommitSpecifier: aws.String(branch),
|
||||
FolderPath: aws.String(testCase.expectedGetFolderPath),
|
||||
RepositoryName: aws.String(repoName),
|
||||
@@ -424,14 +424,14 @@ func TestAWSCodeCommitGetBranches(t *testing.T) {
|
||||
taggingClient := mocks.NewAWSTaggingClient(t)
|
||||
ctx := context.Background()
|
||||
if testCase.allBranches {
|
||||
codeCommitClient.EXPECT().
|
||||
ListBranchesWithContext(ctx, &codecommit.ListBranchesInput{
|
||||
codeCommitClient.
|
||||
On("ListBranchesWithContext", ctx, &codecommit.ListBranchesInput{
|
||||
RepositoryName: aws.String(name),
|
||||
}).
|
||||
Return(&codecommit.ListBranchesOutput{Branches: aws.StringSlice(testCase.branches)}, testCase.apiError)
|
||||
} else {
|
||||
codeCommitClient.EXPECT().
|
||||
GetRepositoryWithContext(ctx, &codecommit.GetRepositoryInput{RepositoryName: aws.String(name)}).
|
||||
codeCommitClient.
|
||||
On("GetRepositoryWithContext", ctx, &codecommit.GetRepositoryInput{RepositoryName: aws.String(name)}).
|
||||
Return(&codecommit.GetRepositoryOutput{RepositoryMetadata: &codecommit.RepositoryMetadata{
|
||||
AccountId: aws.String(organization),
|
||||
DefaultBranch: aws.String(defaultBranch),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.40.2. DO NOT EDIT.
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
|
||||
@@ -17,8 +17,6 @@ import (
|
||||
azureMock "github.com/argoproj/argo-cd/v2/applicationset/services/scm_provider/azure_devops/git/mocks"
|
||||
)
|
||||
|
||||
//go:generate go run github.com/vektra/mockery/v2@v2.40.2 --srcpkg=github.com/microsoft/azure-devops-go-api/azuredevops/git --name=Client --output=azure_devops/git/mocks --outpkg=mocks
|
||||
|
||||
func s(input string) *string {
|
||||
return ptr.To(input)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
bitbucketv1 "github.com/gfleury/go-bitbucket-v1"
|
||||
log "github.com/sirupsen/logrus"
|
||||
@@ -20,7 +21,7 @@ type BitbucketServerProvider struct {
|
||||
|
||||
var _ SCMProviderService = &BitbucketServerProvider{}
|
||||
|
||||
func NewBitbucketServerProviderBasicAuth(ctx context.Context, username, password, url, projectKey string, allBranches bool) (*BitbucketServerProvider, error) {
|
||||
func NewBitbucketServerProviderBasicAuth(ctx context.Context, username, password, url, projectKey string, allBranches bool, scmRootCAPath string, insecure bool, caCerts []byte) (*BitbucketServerProvider, error) {
|
||||
bitbucketConfig := bitbucketv1.NewConfiguration(url)
|
||||
// Avoid the XSRF check
|
||||
bitbucketConfig.AddDefaultHeader("x-atlassian-token", "no-check")
|
||||
@@ -30,15 +31,29 @@ func NewBitbucketServerProviderBasicAuth(ctx context.Context, username, password
|
||||
UserName: username,
|
||||
Password: password,
|
||||
})
|
||||
return newBitbucketServerProvider(ctx, bitbucketConfig, projectKey, allBranches)
|
||||
return newBitbucketServerProvider(ctx, bitbucketConfig, projectKey, allBranches, scmRootCAPath, insecure, caCerts)
|
||||
}
|
||||
|
||||
func NewBitbucketServerProviderNoAuth(ctx context.Context, url, projectKey string, allBranches bool) (*BitbucketServerProvider, error) {
|
||||
return newBitbucketServerProvider(ctx, bitbucketv1.NewConfiguration(url), projectKey, allBranches)
|
||||
func NewBitbucketServerProviderBearerToken(ctx context.Context, bearerToken, url, projectKey string, allBranches bool, scmRootCAPath string, insecure bool, caCerts []byte) (*BitbucketServerProvider, error) {
|
||||
bitbucketConfig := bitbucketv1.NewConfiguration(url)
|
||||
// Avoid the XSRF check
|
||||
bitbucketConfig.AddDefaultHeader("x-atlassian-token", "no-check")
|
||||
bitbucketConfig.AddDefaultHeader("x-requested-with", "XMLHttpRequest")
|
||||
|
||||
ctx = context.WithValue(ctx, bitbucketv1.ContextAccessToken, bearerToken)
|
||||
return newBitbucketServerProvider(ctx, bitbucketConfig, projectKey, allBranches, scmRootCAPath, insecure, caCerts)
|
||||
}
|
||||
|
||||
func newBitbucketServerProvider(ctx context.Context, bitbucketConfig *bitbucketv1.Configuration, projectKey string, allBranches bool) (*BitbucketServerProvider, error) {
|
||||
func NewBitbucketServerProviderNoAuth(ctx context.Context, url, projectKey string, allBranches bool, scmRootCAPath string, insecure bool, caCerts []byte) (*BitbucketServerProvider, error) {
|
||||
return newBitbucketServerProvider(ctx, bitbucketv1.NewConfiguration(url), projectKey, allBranches, scmRootCAPath, insecure, caCerts)
|
||||
}
|
||||
|
||||
func newBitbucketServerProvider(ctx context.Context, bitbucketConfig *bitbucketv1.Configuration, projectKey string, allBranches bool, scmRootCAPath string, insecure bool, caCerts []byte) (*BitbucketServerProvider, error) {
|
||||
bitbucketConfig.BasePath = utils.NormalizeBitbucketBasePath(bitbucketConfig.BasePath)
|
||||
tlsConfig := utils.GetTlsConfig(scmRootCAPath, insecure, caCerts)
|
||||
bitbucketConfig.HTTPClient = &http.Client{Transport: &http.Transport{
|
||||
TLSClientConfig: tlsConfig,
|
||||
}}
|
||||
bitbucketClient := bitbucketv1.NewAPIClient(ctx, bitbucketConfig)
|
||||
|
||||
return &BitbucketServerProvider{
|
||||
|
||||
@@ -2,6 +2,8 @@ package scm_provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@@ -99,7 +101,7 @@ func TestListReposNoAuth(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.ListRepos(context.Background(), "ssh")
|
||||
verifyDefaultRepo(t, err, repos)
|
||||
@@ -191,7 +193,7 @@ func TestListReposPagination(t *testing.T) {
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.ListRepos(context.Background(), "ssh")
|
||||
require.NoError(t, err)
|
||||
@@ -268,7 +270,7 @@ func TestGetBranchesBranchPagination(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.GetBranches(context.Background(), &Repository{
|
||||
Organization: "PROJECT",
|
||||
@@ -321,7 +323,7 @@ func TestGetBranchesDefaultOnly(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.GetBranches(context.Background(), &Repository{
|
||||
Organization: "PROJECT",
|
||||
@@ -353,7 +355,7 @@ func TestGetBranchesMissingDefault(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.GetBranches(context.Background(), &Repository{
|
||||
Organization: "PROJECT",
|
||||
@@ -375,7 +377,7 @@ func TestGetBranchesEmptyRepo(t *testing.T) {
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.GetBranches(context.Background(), &Repository{
|
||||
Organization: "PROJECT",
|
||||
@@ -398,7 +400,7 @@ func TestGetBranchesErrorDefaultBranch(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
_, err = provider.GetBranches(context.Background(), &Repository{
|
||||
Organization: "PROJECT",
|
||||
@@ -410,6 +412,73 @@ func TestGetBranchesErrorDefaultBranch(t *testing.T) {
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestListReposTLS(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
tlsInsecure bool
|
||||
passCerts bool
|
||||
requireErr bool
|
||||
}{
|
||||
{
|
||||
name: "TLS Insecure: true, No Certs",
|
||||
tlsInsecure: true,
|
||||
passCerts: false,
|
||||
requireErr: false,
|
||||
},
|
||||
{
|
||||
name: "TLS Insecure: true, With Certs",
|
||||
tlsInsecure: true,
|
||||
passCerts: true,
|
||||
requireErr: false,
|
||||
},
|
||||
{
|
||||
name: "TLS Insecure: false, With Certs",
|
||||
tlsInsecure: false,
|
||||
passCerts: true,
|
||||
requireErr: false,
|
||||
},
|
||||
{
|
||||
name: "TLS Insecure: false, No Certs",
|
||||
tlsInsecure: false,
|
||||
passCerts: false,
|
||||
requireErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
var certs []byte
|
||||
if test.passCerts == true {
|
||||
for _, cert := range ts.TLS.Certificates {
|
||||
for _, c := range cert.Certificate {
|
||||
parsedCert, err := x509.ParseCertificate(c)
|
||||
require.NoError(t, err, "Failed to parse certificate")
|
||||
certs = append(certs, pem.EncodeToMemory(&pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: parsedCert.Raw,
|
||||
})...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider, err := NewBitbucketServerProviderBasicAuth(context.Background(), "user", "password", ts.URL, "PROJECT", true, "", test.tlsInsecure, certs)
|
||||
require.NoError(t, err)
|
||||
_, err = provider.ListRepos(context.Background(), "ssh")
|
||||
if test.requireErr {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestListReposBasicAuth(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "Basic dXNlcjpwYXNzd29yZA==", r.Header.Get("Authorization"))
|
||||
@@ -417,7 +486,20 @@ func TestListReposBasicAuth(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderBasicAuth(context.Background(), "user", "password", ts.URL, "PROJECT", true)
|
||||
provider, err := NewBitbucketServerProviderBasicAuth(context.Background(), "user", "password", ts.URL, "PROJECT", true, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.ListRepos(context.Background(), "ssh")
|
||||
verifyDefaultRepo(t, err, repos)
|
||||
}
|
||||
|
||||
func TestListReposBearerAuth(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "Bearer tolkien", r.Header.Get("Authorization"))
|
||||
assert.Equal(t, "no-check", r.Header.Get("X-Atlassian-Token"))
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderBearerToken(context.Background(), "tolkien", ts.URL, "PROJECT", true, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.ListRepos(context.Background(), "ssh")
|
||||
verifyDefaultRepo(t, err, repos)
|
||||
@@ -444,7 +526,7 @@ func TestListReposDefaultBranch(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.ListRepos(context.Background(), "ssh")
|
||||
require.NoError(t, err)
|
||||
@@ -470,7 +552,7 @@ func TestListReposMissingDefaultBranch(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.ListRepos(context.Background(), "ssh")
|
||||
require.NoError(t, err)
|
||||
@@ -487,7 +569,7 @@ func TestListReposErrorDefaultBranch(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
_, err = provider.ListRepos(context.Background(), "ssh")
|
||||
require.Error(t, err)
|
||||
@@ -499,7 +581,7 @@ func TestListReposCloneProtocol(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repos, err := provider.ListRepos(context.Background(), "https")
|
||||
require.NoError(t, err)
|
||||
@@ -521,7 +603,7 @@ func TestListReposUnknownProtocol(t *testing.T) {
|
||||
defaultHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
_, errProtocol := provider.ListRepos(context.Background(), "http")
|
||||
require.Error(t, errProtocol)
|
||||
@@ -559,7 +641,7 @@ func TestBitbucketServerHasPath(t *testing.T) {
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true)
|
||||
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true, "", false, nil)
|
||||
require.NoError(t, err)
|
||||
repo := &Repository{
|
||||
Organization: "PROJECT",
|
||||
|
||||
@@ -2,12 +2,11 @@ package scm_provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/google/go-github/v35/github"
|
||||
"github.com/google/go-github/v63/github"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
@@ -36,7 +35,7 @@ func NewGithubProvider(ctx context.Context, organization string, token string, u
|
||||
client = github.NewClient(httpClient)
|
||||
} else {
|
||||
var err error
|
||||
client, err = github.NewEnterpriseClient(url, url, httpClient)
|
||||
client, err = github.NewClient(httpClient).WithEnterpriseURLs(url, url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -120,14 +119,11 @@ func (g *GithubProvider) RepoHasPath(ctx context.Context, repo *Repository, path
|
||||
func (g *GithubProvider) listBranches(ctx context.Context, repo *Repository) ([]github.Branch, error) {
|
||||
// If we don't specifically want to query for all branches, just use the default branch and call it a day.
|
||||
if !g.allBranches {
|
||||
defaultBranch, _, err := g.client.Repositories.GetBranch(ctx, repo.Organization, repo.Repository, repo.Branch)
|
||||
defaultBranch, resp, err := g.client.Repositories.GetBranch(ctx, repo.Organization, repo.Repository, repo.Branch, 0)
|
||||
if err != nil {
|
||||
var githubErrorResponse *github.ErrorResponse
|
||||
if errors.As(err, &githubErrorResponse) {
|
||||
if githubErrorResponse.Response.StatusCode == http.StatusNotFound {
|
||||
// Default branch doesn't exist, so the repo is empty.
|
||||
return []github.Branch{}, nil
|
||||
}
|
||||
if resp.StatusCode == http.StatusNotFound {
|
||||
// Default branch doesn't exist, so the repo is empty.
|
||||
return []github.Branch{}, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ type GitlabProvider struct {
|
||||
|
||||
var _ SCMProviderService = &GitlabProvider{}
|
||||
|
||||
func NewGitlabProvider(ctx context.Context, organization string, token string, url string, allBranches, includeSubgroups, includeSharedProjects, insecure bool, scmRootCAPath, topic string) (*GitlabProvider, error) {
|
||||
func NewGitlabProvider(ctx context.Context, organization string, token string, url string, allBranches, includeSubgroups, includeSharedProjects, insecure bool, scmRootCAPath, topic string, caCerts []byte) (*GitlabProvider, error) {
|
||||
// Undocumented environment variable to set a default token, to be used in testing to dodge anonymous rate limits.
|
||||
if token == "" {
|
||||
token = os.Getenv("GITLAB_TOKEN")
|
||||
@@ -32,7 +32,7 @@ func NewGitlabProvider(ctx context.Context, organization string, token string, u
|
||||
var client *gitlab.Client
|
||||
|
||||
tr := http.DefaultTransport.(*http.Transport).Clone()
|
||||
tr.TLSClientConfig = utils.GetTlsConfig(scmRootCAPath, insecure)
|
||||
tr.TLSClientConfig = utils.GetTlsConfig(scmRootCAPath, insecure, caCerts)
|
||||
|
||||
retryClient := retryablehttp.NewClient()
|
||||
retryClient.HTTPClient.Transport = tr
|
||||
|
||||
@@ -2,6 +2,8 @@ package scm_provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
@@ -1121,7 +1123,7 @@ func TestGitlabListRepos(t *testing.T) {
|
||||
}))
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
provider, _ := NewGitlabProvider(context.Background(), "test-argocd-proton", "", ts.URL, c.allBranches, c.includeSubgroups, c.includeSharedProjects, c.insecure, "", c.topic)
|
||||
provider, _ := NewGitlabProvider(context.Background(), "test-argocd-proton", "", ts.URL, c.allBranches, c.includeSubgroups, c.includeSharedProjects, c.insecure, "", c.topic, nil)
|
||||
rawRepos, err := ListRepos(context.Background(), provider, c.filters, c.proto)
|
||||
if c.hasError {
|
||||
require.Error(t, err)
|
||||
@@ -1160,7 +1162,7 @@ func TestGitlabHasPath(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
gitlabMockHandler(t)(w, r)
|
||||
}))
|
||||
host, _ := NewGitlabProvider(context.Background(), "test-argocd-proton", "", ts.URL, false, true, true, false, "", "")
|
||||
host, _ := NewGitlabProvider(context.Background(), "test-argocd-proton", "", ts.URL, false, true, true, false, "", "", nil)
|
||||
repo := &Repository{
|
||||
Organization: "test-argocd-proton",
|
||||
Repository: "argocd",
|
||||
@@ -1206,7 +1208,7 @@ func TestGitlabGetBranches(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
gitlabMockHandler(t)(w, r)
|
||||
}))
|
||||
host, _ := NewGitlabProvider(context.Background(), "test-argocd-proton", "", ts.URL, false, true, true, false, "", "")
|
||||
host, _ := NewGitlabProvider(context.Background(), "test-argocd-proton", "", ts.URL, false, true, true, false, "", "", nil)
|
||||
|
||||
repo := &Repository{
|
||||
RepositoryId: 27084533,
|
||||
@@ -1227,3 +1229,74 @@ func TestGitlabGetBranches(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetBranchesTLS(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
tlsInsecure bool
|
||||
passCerts bool
|
||||
requireErr bool
|
||||
}{
|
||||
{
|
||||
name: "TLS Insecure: true, No Certs",
|
||||
tlsInsecure: true,
|
||||
passCerts: false,
|
||||
requireErr: false,
|
||||
},
|
||||
{
|
||||
name: "TLS Insecure: true, With Certs",
|
||||
tlsInsecure: true,
|
||||
passCerts: true,
|
||||
requireErr: false,
|
||||
},
|
||||
{
|
||||
name: "TLS Insecure: false, With Certs",
|
||||
tlsInsecure: false,
|
||||
passCerts: true,
|
||||
requireErr: false,
|
||||
},
|
||||
{
|
||||
name: "TLS Insecure: false, No Certs",
|
||||
tlsInsecure: false,
|
||||
passCerts: false,
|
||||
requireErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
gitlabMockHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
var certs []byte
|
||||
if test.passCerts == true {
|
||||
for _, cert := range ts.TLS.Certificates {
|
||||
for _, c := range cert.Certificate {
|
||||
parsedCert, err := x509.ParseCertificate(c)
|
||||
require.NoError(t, err, "Failed to parse certificate")
|
||||
certs = append(certs, pem.EncodeToMemory(&pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: parsedCert.Raw,
|
||||
})...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
host, err := NewGitlabProvider(context.Background(), "test-argocd-proton", "", ts.URL, false, true, true, test.tlsInsecure, "", "", certs)
|
||||
require.NoError(t, err)
|
||||
repo := &Repository{
|
||||
RepositoryId: 27084533,
|
||||
Branch: "master",
|
||||
}
|
||||
_, err = host.GetBranches(context.Background(), repo)
|
||||
if test.requireErr {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
57
applicationset/status/resource_status.go
Normal file
57
applicationset/status/resource_status.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package status
|
||||
|
||||
import (
|
||||
argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
func BuildResourceStatus(statusMap map[string]argov1alpha1.ResourceStatus, apps []argov1alpha1.Application) map[string]argov1alpha1.ResourceStatus {
|
||||
appMap := map[string]argov1alpha1.Application{}
|
||||
for _, app := range apps {
|
||||
appCopy := app
|
||||
appMap[app.Name] = app
|
||||
|
||||
gvk := app.GroupVersionKind()
|
||||
// Create status if it does not exist
|
||||
status, ok := statusMap[app.Name]
|
||||
if !ok {
|
||||
status = argov1alpha1.ResourceStatus{
|
||||
Group: gvk.Group,
|
||||
Version: gvk.Version,
|
||||
Kind: gvk.Kind,
|
||||
Name: app.Name,
|
||||
Namespace: app.Namespace,
|
||||
Status: app.Status.Sync.Status,
|
||||
Health: &appCopy.Status.Health,
|
||||
}
|
||||
}
|
||||
|
||||
status.Group = gvk.Group
|
||||
status.Version = gvk.Version
|
||||
status.Kind = gvk.Kind
|
||||
status.Name = app.Name
|
||||
status.Namespace = app.Namespace
|
||||
status.Status = app.Status.Sync.Status
|
||||
status.Health = &appCopy.Status.Health
|
||||
|
||||
statusMap[app.Name] = status
|
||||
}
|
||||
cleanupDeletedApplicationStatuses(statusMap, appMap)
|
||||
|
||||
return statusMap
|
||||
}
|
||||
|
||||
func GetResourceStatusMap(appset *argov1alpha1.ApplicationSet) map[string]argov1alpha1.ResourceStatus {
|
||||
statusMap := map[string]argov1alpha1.ResourceStatus{}
|
||||
for _, status := range appset.Status.Resources {
|
||||
statusMap[status.Name] = status
|
||||
}
|
||||
return statusMap
|
||||
}
|
||||
|
||||
func cleanupDeletedApplicationStatuses(statusMap map[string]argov1alpha1.ResourceStatus, apps map[string]argov1alpha1.Application) {
|
||||
for name := range statusMap {
|
||||
if _, ok := apps[name]; !ok {
|
||||
delete(statusMap, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
54
applicationset/utils/kubernetes.go
Normal file
54
applicationset/utils/kubernetes.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
// getSecretRef gets the value of the key for the specified Secret resource.
|
||||
func GetSecretRef(ctx context.Context, k8sClient client.Client, ref *argoprojiov1alpha1.SecretRef, namespace string) (string, error) {
|
||||
if ref == nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
secret := &corev1.Secret{}
|
||||
err := k8sClient.Get(
|
||||
ctx,
|
||||
client.ObjectKey{
|
||||
Name: ref.SecretName,
|
||||
Namespace: namespace,
|
||||
},
|
||||
secret)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error fetching secret %s/%s: %w", namespace, ref.SecretName, err)
|
||||
}
|
||||
tokenBytes, ok := secret.Data[ref.Key]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("key %q in secret %s/%s not found", ref.Key, namespace, ref.SecretName)
|
||||
}
|
||||
return string(tokenBytes), nil
|
||||
}
|
||||
|
||||
func GetConfigMapData(ctx context.Context, k8sClient client.Client, ref *argoprojiov1alpha1.ConfigMapKeyRef, namespace string) ([]byte, error) {
|
||||
if ref == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
configMap := &corev1.ConfigMap{}
|
||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: ref.ConfigMapName, Namespace: namespace}, configMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, ok := configMap.Data[ref.Key]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("key %s not found in ConfigMap %s", ref.Key, configMap.Name)
|
||||
}
|
||||
|
||||
return []byte(data), nil
|
||||
}
|
||||
146
applicationset/utils/kubernetes_test.go
Normal file
146
applicationset/utils/kubernetes_test.go
Normal file
@@ -0,0 +1,146 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
func TestGetSecretRef(t *testing.T) {
|
||||
secret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "test-secret", Namespace: "test"},
|
||||
Data: map[string][]byte{
|
||||
"my-token": []byte("secret"),
|
||||
},
|
||||
}
|
||||
client := fake.NewClientBuilder().WithObjects(secret).Build()
|
||||
ctx := context.Background()
|
||||
|
||||
cases := []struct {
|
||||
name, namespace, token string
|
||||
ref *argoprojiov1alpha1.SecretRef
|
||||
hasError bool
|
||||
}{
|
||||
{
|
||||
name: "valid ref",
|
||||
ref: &argoprojiov1alpha1.SecretRef{SecretName: "test-secret", Key: "my-token"},
|
||||
namespace: "test",
|
||||
token: "secret",
|
||||
hasError: false,
|
||||
},
|
||||
{
|
||||
name: "nil ref",
|
||||
ref: nil,
|
||||
namespace: "test",
|
||||
token: "",
|
||||
hasError: false,
|
||||
},
|
||||
{
|
||||
name: "wrong name",
|
||||
ref: &argoprojiov1alpha1.SecretRef{SecretName: "other", Key: "my-token"},
|
||||
namespace: "test",
|
||||
token: "",
|
||||
hasError: true,
|
||||
},
|
||||
{
|
||||
name: "wrong key",
|
||||
ref: &argoprojiov1alpha1.SecretRef{SecretName: "test-secret", Key: "other-token"},
|
||||
namespace: "test",
|
||||
token: "",
|
||||
hasError: true,
|
||||
},
|
||||
{
|
||||
name: "wrong namespace",
|
||||
ref: &argoprojiov1alpha1.SecretRef{SecretName: "test-secret", Key: "my-token"},
|
||||
namespace: "other",
|
||||
token: "",
|
||||
hasError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
token, err := GetSecretRef(ctx, client, c.ref, c.namespace)
|
||||
if c.hasError {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
assert.Equal(t, c.token, token)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetConfigMapData(t *testing.T) {
|
||||
configMap := &corev1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "test-configmap", Namespace: "test"},
|
||||
Data: map[string]string{
|
||||
"my-data": "configmap-data",
|
||||
},
|
||||
}
|
||||
client := fake.NewClientBuilder().WithObjects(configMap).Build()
|
||||
ctx := context.Background()
|
||||
|
||||
cases := []struct {
|
||||
name, namespace, data string
|
||||
ref *argoprojiov1alpha1.ConfigMapKeyRef
|
||||
hasError bool
|
||||
}{
|
||||
{
|
||||
name: "valid ref",
|
||||
ref: &argoprojiov1alpha1.ConfigMapKeyRef{ConfigMapName: "test-configmap", Key: "my-data"},
|
||||
namespace: "test",
|
||||
data: "configmap-data",
|
||||
hasError: false,
|
||||
},
|
||||
{
|
||||
name: "nil ref",
|
||||
ref: nil,
|
||||
namespace: "test",
|
||||
data: "",
|
||||
hasError: false,
|
||||
},
|
||||
{
|
||||
name: "wrong name",
|
||||
ref: &argoprojiov1alpha1.ConfigMapKeyRef{ConfigMapName: "other", Key: "my-data"},
|
||||
namespace: "test",
|
||||
data: "",
|
||||
hasError: true,
|
||||
},
|
||||
{
|
||||
name: "wrong key",
|
||||
ref: &argoprojiov1alpha1.ConfigMapKeyRef{ConfigMapName: "test-configmap", Key: "other-data"},
|
||||
namespace: "test",
|
||||
data: "",
|
||||
hasError: true,
|
||||
},
|
||||
{
|
||||
name: "wrong namespace",
|
||||
ref: &argoprojiov1alpha1.ConfigMapKeyRef{ConfigMapName: "test-configmap", Key: "my-data"},
|
||||
namespace: "other",
|
||||
data: "",
|
||||
hasError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
data, err := GetConfigMapData(ctx, client, c.ref, c.namespace)
|
||||
if c.hasError {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
if !c.hasError {
|
||||
assert.Equal(t, c.data, string(data))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
86
applicationset/utils/mocks/Renderer.go
generated
Normal file
86
applicationset/utils/mocks/Renderer.go
generated
Normal file
@@ -0,0 +1,86 @@
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
v1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
// Renderer is an autogenerated mock type for the Renderer type
|
||||
type Renderer struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// RenderTemplateParams provides a mock function with given fields: tmpl, syncPolicy, params, useGoTemplate, goTemplateOptions
|
||||
func (_m *Renderer) RenderTemplateParams(tmpl *v1alpha1.Application, syncPolicy *v1alpha1.ApplicationSetSyncPolicy, params map[string]interface{}, useGoTemplate bool, goTemplateOptions []string) (*v1alpha1.Application, error) {
|
||||
ret := _m.Called(tmpl, syncPolicy, params, useGoTemplate, goTemplateOptions)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for RenderTemplateParams")
|
||||
}
|
||||
|
||||
var r0 *v1alpha1.Application
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(*v1alpha1.Application, *v1alpha1.ApplicationSetSyncPolicy, map[string]interface{}, bool, []string) (*v1alpha1.Application, error)); ok {
|
||||
return rf(tmpl, syncPolicy, params, useGoTemplate, goTemplateOptions)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(*v1alpha1.Application, *v1alpha1.ApplicationSetSyncPolicy, map[string]interface{}, bool, []string) *v1alpha1.Application); ok {
|
||||
r0 = rf(tmpl, syncPolicy, params, useGoTemplate, goTemplateOptions)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*v1alpha1.Application)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(*v1alpha1.Application, *v1alpha1.ApplicationSetSyncPolicy, map[string]interface{}, bool, []string) error); ok {
|
||||
r1 = rf(tmpl, syncPolicy, params, useGoTemplate, goTemplateOptions)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Replace provides a mock function with given fields: tmpl, replaceMap, useGoTemplate, goTemplateOptions
|
||||
func (_m *Renderer) Replace(tmpl string, replaceMap map[string]interface{}, useGoTemplate bool, goTemplateOptions []string) (string, error) {
|
||||
ret := _m.Called(tmpl, replaceMap, useGoTemplate, goTemplateOptions)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Replace")
|
||||
}
|
||||
|
||||
var r0 string
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(string, map[string]interface{}, bool, []string) (string, error)); ok {
|
||||
return rf(tmpl, replaceMap, useGoTemplate, goTemplateOptions)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(string, map[string]interface{}, bool, []string) string); ok {
|
||||
r0 = rf(tmpl, replaceMap, useGoTemplate, goTemplateOptions)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(string, map[string]interface{}, bool, []string) error); ok {
|
||||
r1 = rf(tmpl, replaceMap, useGoTemplate, goTemplateOptions)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// NewRenderer creates a new instance of Renderer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewRenderer(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *Renderer {
|
||||
mock := &Renderer{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
@@ -483,7 +483,7 @@ func SlugifyName(args ...interface{}) string {
|
||||
return urlSlug
|
||||
}
|
||||
|
||||
func getTlsConfigWithCACert(scmRootCAPath string) *tls.Config {
|
||||
func getTlsConfigWithCACert(scmRootCAPath string, caCerts []byte) *tls.Config {
|
||||
tlsConfig := &tls.Config{}
|
||||
|
||||
if scmRootCAPath != "" {
|
||||
@@ -497,8 +497,12 @@ func getTlsConfigWithCACert(scmRootCAPath string) *tls.Config {
|
||||
log.Errorf("error reading certificate from file '%s', proceeding without custom rootCA : %s", scmRootCAPath, err)
|
||||
return tlsConfig
|
||||
}
|
||||
caCerts = append(caCerts, rootCA...)
|
||||
}
|
||||
|
||||
if len(caCerts) > 0 {
|
||||
certPool := x509.NewCertPool()
|
||||
ok := certPool.AppendCertsFromPEM([]byte(rootCA))
|
||||
ok := certPool.AppendCertsFromPEM(caCerts)
|
||||
if !ok {
|
||||
log.Errorf("failed to append certificates from PEM: proceeding without custom rootCA")
|
||||
} else {
|
||||
@@ -508,8 +512,8 @@ func getTlsConfigWithCACert(scmRootCAPath string) *tls.Config {
|
||||
return tlsConfig
|
||||
}
|
||||
|
||||
func GetTlsConfig(scmRootCAPath string, insecure bool) *tls.Config {
|
||||
tlsConfig := getTlsConfigWithCACert(scmRootCAPath)
|
||||
func GetTlsConfig(scmRootCAPath string, insecure bool, caCerts []byte) *tls.Config {
|
||||
tlsConfig := getTlsConfigWithCACert(scmRootCAPath, caCerts)
|
||||
|
||||
if insecure {
|
||||
tlsConfig.InsecureSkipVerify = true
|
||||
|
||||
@@ -1260,11 +1260,8 @@ func TestSlugify(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetTLSConfig(t *testing.T) {
|
||||
// certParsed, err := tls.X509KeyPair(test.Cert, test.PrivateKey)
|
||||
// require.NoError(t, err)
|
||||
|
||||
temppath := t.TempDir()
|
||||
cert := `
|
||||
certFromFile := `
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFvTCCA6WgAwIBAgIUGrTmW3qc39zqnE08e3qNDhUkeWswDQYJKoZIhvcNAQEL
|
||||
BQAwbjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAklMMRAwDgYDVQQHDAdDaGljYWdv
|
||||
@@ -1298,50 +1295,96 @@ NoB2rjufaB0GQi1azdboMvdGSOxhSCAR8otWT5yDrywCqVnEvjw0oxKmuRduNe2/
|
||||
r2AaraPFgrprnxUibP4L7jxdr+iiw5bWN9/B81PodrS7n5TNtnfnpZD6X6rThqOP
|
||||
xO7Tr5lAo74vNUkF2EHNaI28/RGnJPm2TIxZqy4rNH6L
|
||||
-----END CERTIFICATE-----
|
||||
`
|
||||
|
||||
certFromCM := `
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDOTCCAiGgAwIBAgIQSRJrEpBGFc7tNb1fb5pKFzANBgkqhkiG9w0BAQsFADAS
|
||||
MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw
|
||||
MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEA6Gba5tHV1dAKouAaXO3/ebDUU4rvwCUg/CNaJ2PT5xLD4N1Vcb8r
|
||||
bFSW2HXKq+MPfVdwIKR/1DczEoAGf/JWQTW7EgzlXrCd3rlajEX2D73faWJekD0U
|
||||
aUgz5vtrTXZ90BQL7WvRICd7FlEZ6FPOcPlumiyNmzUqtwGhO+9ad1W5BqJaRI6P
|
||||
YfouNkwR6Na4TzSj5BrqUfP0FwDizKSJ0XXmh8g8G9mtwxOSN3Ru1QFc61Xyeluk
|
||||
POGKBV/q6RBNklTNe0gI8usUMlYyoC7ytppNMW7X2vodAelSu25jgx2anj9fDVZu
|
||||
h7AXF5+4nJS4AAt0n1lNY7nGSsdZas8PbQIDAQABo4GIMIGFMA4GA1UdDwEB/wQE
|
||||
AwICpDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
|
||||
DgQWBBStsdjh3/JCXXYlQryOrL4Sh7BW5TAuBgNVHREEJzAlggtleGFtcGxlLmNv
|
||||
bYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQsFAAOCAQEAxWGI
|
||||
5NhpF3nwwy/4yB4i/CwwSpLrWUa70NyhvprUBC50PxiXav1TeDzwzLx/o5HyNwsv
|
||||
cxv3HdkLW59i/0SlJSrNnWdfZ19oTcS+6PtLoVyISgtyN6DpkKpdG1cOkW3Cy2P2
|
||||
+tK/tKHRP1Y/Ra0RiDpOAmqn0gCOFGz8+lqDIor/T7MTpibL3IxqWfPrvfVRHL3B
|
||||
grw/ZQTTIVjjh4JBSW3WyWgNo/ikC1lrVxzl4iPUGptxT36Cr7Zk2Bsg0XqwbOvK
|
||||
5d+NTDREkSnUbie4GeutujmX3Dsx88UiV6UY/4lHJa6I5leHUNOHahRbpbWeOfs/
|
||||
WkBKOclmOV2xlTVuPw==
|
||||
-----END CERTIFICATE-----
|
||||
`
|
||||
|
||||
rootCAPath := path.Join(temppath, "foo.example.com")
|
||||
err := os.WriteFile(rootCAPath, []byte(cert), 0o666)
|
||||
err := os.WriteFile(rootCAPath, []byte(certFromFile), 0o666)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
certPool := x509.NewCertPool()
|
||||
ok := certPool.AppendCertsFromPEM([]byte(cert))
|
||||
assert.True(t, ok)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
scmRootCAPath string
|
||||
insecure bool
|
||||
caCerts []byte
|
||||
validateCertInTlsConfig bool
|
||||
}{
|
||||
{
|
||||
name: "Insecure mode configured, SCM Root CA Path not set",
|
||||
scmRootCAPath: "",
|
||||
insecure: true,
|
||||
caCerts: nil,
|
||||
validateCertInTlsConfig: false,
|
||||
},
|
||||
{
|
||||
name: "SCM Root CA Path set, Insecure mode set to false",
|
||||
scmRootCAPath: rootCAPath,
|
||||
insecure: false,
|
||||
caCerts: nil,
|
||||
validateCertInTlsConfig: true,
|
||||
},
|
||||
{
|
||||
name: "SCM Root CA Path set, Insecure mode set to true",
|
||||
scmRootCAPath: rootCAPath,
|
||||
insecure: true,
|
||||
caCerts: nil,
|
||||
validateCertInTlsConfig: true,
|
||||
},
|
||||
{
|
||||
name: "Cert passed, Insecure mode set to false",
|
||||
scmRootCAPath: "",
|
||||
insecure: false,
|
||||
caCerts: []byte(certFromCM),
|
||||
validateCertInTlsConfig: true,
|
||||
},
|
||||
{
|
||||
name: "SCM Root CA Path set, cert passed, Insecure mode set to false",
|
||||
scmRootCAPath: rootCAPath,
|
||||
insecure: false,
|
||||
caCerts: []byte(certFromCM),
|
||||
validateCertInTlsConfig: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
tlsConfig := GetTlsConfig(testCase.scmRootCAPath, testCase.insecure)
|
||||
certPool := x509.NewCertPool()
|
||||
tlsConfig := GetTlsConfig(testCase.scmRootCAPath, testCase.insecure, testCase.caCerts)
|
||||
assert.Equal(t, testCase.insecure, tlsConfig.InsecureSkipVerify)
|
||||
if testCase.caCerts != nil {
|
||||
ok := certPool.AppendCertsFromPEM([]byte(certFromCM))
|
||||
assert.True(t, ok)
|
||||
}
|
||||
if testCase.scmRootCAPath != "" {
|
||||
ok := certPool.AppendCertsFromPEM([]byte(certFromFile))
|
||||
assert.True(t, ok)
|
||||
}
|
||||
assert.NotNil(t, tlsConfig)
|
||||
if testCase.validateCertInTlsConfig {
|
||||
assert.NotNil(t, tlsConfig)
|
||||
assert.True(t, tlsConfig.RootCAs.Equal(certPool))
|
||||
}
|
||||
})
|
||||
|
||||
@@ -2,7 +2,6 @@ package webhook
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"html"
|
||||
"net/http"
|
||||
@@ -10,6 +9,7 @@ import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/util/retry"
|
||||
@@ -26,16 +26,17 @@ import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var errBasicAuthVerificationFailed = errors.New("basic auth verification failed")
|
||||
const payloadQueueSize = 50000
|
||||
|
||||
type WebhookHandler struct {
|
||||
namespace string
|
||||
github *github.Webhook
|
||||
gitlab *gitlab.Webhook
|
||||
azuredevops *azuredevops.Webhook
|
||||
azuredevopsAuthHandler func(r *http.Request) error
|
||||
client client.Client
|
||||
generators map[string]generators.Generator
|
||||
sync.WaitGroup // for testing
|
||||
namespace string
|
||||
github *github.Webhook
|
||||
gitlab *gitlab.Webhook
|
||||
azuredevops *azuredevops.Webhook
|
||||
client client.Client
|
||||
generators map[string]generators.Generator
|
||||
queue chan interface{}
|
||||
}
|
||||
|
||||
type gitGeneratorInfo struct {
|
||||
@@ -66,7 +67,7 @@ type prGeneratorGitlabInfo struct {
|
||||
APIHostname string
|
||||
}
|
||||
|
||||
func NewWebhookHandler(namespace string, argocdSettingsMgr *argosettings.SettingsManager, client client.Client, generators map[string]generators.Generator) (*WebhookHandler, error) {
|
||||
func NewWebhookHandler(namespace string, webhookParallelism int, argocdSettingsMgr *argosettings.SettingsManager, client client.Client, generators map[string]generators.Generator) (*WebhookHandler, error) {
|
||||
// register the webhook secrets stored under "argocd-secret" for verifying incoming payloads
|
||||
argocdSettings, err := argocdSettingsMgr.GetSettings()
|
||||
if err != nil {
|
||||
@@ -80,29 +81,40 @@ func NewWebhookHandler(namespace string, argocdSettingsMgr *argosettings.Setting
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to init GitLab webhook: %w", err)
|
||||
}
|
||||
azuredevopsHandler, err := azuredevops.New()
|
||||
azuredevopsHandler, err := azuredevops.New(azuredevops.Options.BasicAuth(argocdSettings.WebhookAzureDevOpsUsername, argocdSettings.WebhookAzureDevOpsPassword))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to init Azure DevOps webhook: %w", err)
|
||||
}
|
||||
azuredevopsAuthHandler := func(r *http.Request) error {
|
||||
if argocdSettings.WebhookAzureDevOpsUsername != "" && argocdSettings.WebhookAzureDevOpsPassword != "" {
|
||||
username, password, ok := r.BasicAuth()
|
||||
if !ok || username != argocdSettings.WebhookAzureDevOpsUsername || password != argocdSettings.WebhookAzureDevOpsPassword {
|
||||
return errBasicAuthVerificationFailed
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
webhookHandler := &WebhookHandler{
|
||||
namespace: namespace,
|
||||
github: githubHandler,
|
||||
gitlab: gitlabHandler,
|
||||
azuredevops: azuredevopsHandler,
|
||||
client: client,
|
||||
generators: generators,
|
||||
queue: make(chan interface{}, payloadQueueSize),
|
||||
}
|
||||
|
||||
return &WebhookHandler{
|
||||
namespace: namespace,
|
||||
github: githubHandler,
|
||||
gitlab: gitlabHandler,
|
||||
azuredevops: azuredevopsHandler,
|
||||
azuredevopsAuthHandler: azuredevopsAuthHandler,
|
||||
client: client,
|
||||
generators: generators,
|
||||
}, nil
|
||||
webhookHandler.startWorkerPool(webhookParallelism)
|
||||
|
||||
return webhookHandler, nil
|
||||
}
|
||||
|
||||
func (h *WebhookHandler) startWorkerPool(webhookParallelism int) {
|
||||
for i := 0; i < webhookParallelism; i++ {
|
||||
h.Add(1)
|
||||
go func() {
|
||||
defer h.Done()
|
||||
for {
|
||||
payload, ok := <-h.queue
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
h.HandleEvent(payload)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func (h *WebhookHandler) HandleEvent(payload interface{}) {
|
||||
@@ -153,13 +165,7 @@ func (h *WebhookHandler) Handler(w http.ResponseWriter, r *http.Request) {
|
||||
case r.Header.Get("X-Gitlab-Event") != "":
|
||||
payload, err = h.gitlab.Parse(r, gitlab.PushEvents, gitlab.TagEvents, gitlab.MergeRequestEvents)
|
||||
case r.Header.Get("X-Vss-Activityid") != "":
|
||||
if err = h.azuredevopsAuthHandler(r); err != nil {
|
||||
if errors.Is(err, errBasicAuthVerificationFailed) {
|
||||
log.WithField(common.SecurityField, common.SecurityHigh).Infof("Azure DevOps webhook basic auth verification failed")
|
||||
}
|
||||
} else {
|
||||
payload, err = h.azuredevops.Parse(r, azuredevops.GitPushEventType, azuredevops.GitPullRequestCreatedEventType, azuredevops.GitPullRequestUpdatedEventType, azuredevops.GitPullRequestMergedEventType)
|
||||
}
|
||||
payload, err = h.azuredevops.Parse(r, azuredevops.GitPushEventType, azuredevops.GitPullRequestCreatedEventType, azuredevops.GitPullRequestUpdatedEventType, azuredevops.GitPullRequestMergedEventType)
|
||||
default:
|
||||
log.Debug("Ignoring unknown webhook event")
|
||||
http.Error(w, "Unknown webhook event", http.StatusBadRequest)
|
||||
@@ -176,7 +182,12 @@ func (h *WebhookHandler) Handler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
h.HandleEvent(payload)
|
||||
select {
|
||||
case h.queue <- payload:
|
||||
default:
|
||||
log.Info("Queue is full, discarding webhook payload")
|
||||
http.Error(w, "Queue is full, discarding webhook payload", http.StatusServiceUnavailable)
|
||||
}
|
||||
}
|
||||
|
||||
func parseRevision(ref string) string {
|
||||
|
||||
@@ -178,6 +178,7 @@ func TestWebhookHandler(t *testing.T) {
|
||||
}
|
||||
|
||||
namespace := "test"
|
||||
webhookParallelism := 10
|
||||
fakeClient := newFakeClient(namespace)
|
||||
scheme := runtime.NewScheme()
|
||||
err := v1alpha1.AddToScheme(scheme)
|
||||
@@ -206,7 +207,7 @@ func TestWebhookHandler(t *testing.T) {
|
||||
fakeAppWithMergeAndNestedGitGenerator("merge-nested-git-github", namespace, "https://github.com/org/repo"),
|
||||
).Build()
|
||||
set := argosettings.NewSettingsManager(context.TODO(), fakeClient, namespace)
|
||||
h, err := NewWebhookHandler(namespace, set, fc, mockGenerators())
|
||||
h, err := NewWebhookHandler(namespace, webhookParallelism, set, fc, mockGenerators())
|
||||
require.NoError(t, err)
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "/api/webhook", nil)
|
||||
@@ -217,6 +218,8 @@ func TestWebhookHandler(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
h.Handler(w, req)
|
||||
close(h.queue)
|
||||
h.Wait()
|
||||
assert.Equal(t, test.expectedStatusCode, w.Code)
|
||||
|
||||
list := &v1alpha1.ApplicationSetList{}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Built-in policy which defines two roles: role:readonly and role:admin,
|
||||
# and additionally assigns the admin user to the role:admin role.
|
||||
# There are two policy formats:
|
||||
# 1. Applications, logs, and exec (which belong to a project):
|
||||
# p, <user/group>, <resource>, <action>, <project>/<object>
|
||||
# 1. Applications, applicationsets, logs, and exec (which belong to a project):
|
||||
# p, <role/user/group>, <resource>, <action>, <project>/<object>, <allow/deny>
|
||||
# 2. All other resources:
|
||||
# p, <user/group>, <resource>, <action>, <object>
|
||||
# p, <role/user/group>, <resource>, <action>, <object>, <allow/deny>
|
||||
|
||||
p, role:readonly, applications, get, */*, allow
|
||||
p, role:readonly, certificates, get, *, allow
|
||||
|
||||
|
87
assets/swagger.json
generated
87
assets/swagger.json
generated
@@ -1967,6 +1967,11 @@
|
||||
"type": "boolean",
|
||||
"name": "upsert",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"name": "dryRun",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -5044,6 +5049,13 @@
|
||||
"repositoryManifestResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"commands": {
|
||||
"type": "array",
|
||||
"title": "Commands is the list of commands used to hydrate the manifests",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"manifests": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -6471,6 +6483,13 @@
|
||||
"type": "object",
|
||||
"title": "ApplicationSourceHelm holds helm specific options",
|
||||
"properties": {
|
||||
"apiVersions": {
|
||||
"description": "APIVersions specifies the Kubernetes resource API versions to pass to Helm when templating manifests. By default,\nArgo CD uses the API versions of the target cluster. The format is [group/]version/kind.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"fileParameters": {
|
||||
"type": "array",
|
||||
"title": "FileParameters are file parameters to the helm template",
|
||||
@@ -6482,6 +6501,14 @@
|
||||
"type": "boolean",
|
||||
"title": "IgnoreMissingValueFiles prevents helm template from failing when valueFiles do not exist locally by not appending them to helm template --values"
|
||||
},
|
||||
"kubeVersion": {
|
||||
"description": "KubeVersion specifies the Kubernetes API version to pass to Helm when templating manifests. By default, Argo CD\nuses the Kubernetes version of the target cluster.",
|
||||
"type": "string"
|
||||
},
|
||||
"namespace": {
|
||||
"description": "Namespace is an optional namespace to template with. If left empty, defaults to the app's destination namespace.",
|
||||
"type": "string"
|
||||
},
|
||||
"parameters": {
|
||||
"type": "array",
|
||||
"title": "Parameters is a list of Helm parameters which are passed to the helm template command upon manifest generation",
|
||||
@@ -6552,6 +6579,13 @@
|
||||
"type": "object",
|
||||
"title": "ApplicationSourceKustomize holds options specific to an Application source specific to Kustomize",
|
||||
"properties": {
|
||||
"apiVersions": {
|
||||
"description": "APIVersions specifies the Kubernetes resource API versions to pass to Helm when templating manifests. By default,\nArgo CD uses the API versions of the target cluster. The format is [group/]version/kind.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"commonAnnotations": {
|
||||
"type": "object",
|
||||
"title": "CommonAnnotations is a list of additional annotations to add to rendered manifests",
|
||||
@@ -6592,6 +6626,10 @@
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"kubeVersion": {
|
||||
"description": "KubeVersion specifies the Kubernetes API version to pass to Helm when templating manifests. By default, Argo CD\nuses the Kubernetes version of the target cluster.",
|
||||
"type": "string"
|
||||
},
|
||||
"labelWithoutSelector": {
|
||||
"type": "boolean",
|
||||
"title": "LabelWithoutSelector specifies whether to apply common labels to resource selectors or not"
|
||||
@@ -6876,6 +6914,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1alpha1BearerTokenBitbucket": {
|
||||
"description": "BearerTokenBitbucket defines the Bearer token for BitBucket AppToken auth.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"tokenRef": {
|
||||
"$ref": "#/definitions/v1alpha1SecretRef"
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1alpha1BearerTokenBitbucketCloud": {
|
||||
"description": "BearerTokenBitbucketCloud defines the Bearer token for BitBucket AppToken auth.",
|
||||
"type": "object",
|
||||
@@ -6960,7 +7007,7 @@
|
||||
},
|
||||
"serverVersion": {
|
||||
"type": "string",
|
||||
"title": "DEPRECATED: use Info.ServerVersion field instead.\nThe server version"
|
||||
"title": "Deprecated: use Info.ServerVersion field instead.\nThe server version"
|
||||
},
|
||||
"shard": {
|
||||
"description": "Shard contains optional shard number. Calculated on the fly by the application controller if not specified.",
|
||||
@@ -7138,6 +7185,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1alpha1ConfigMapKeyRef": {
|
||||
"description": "Utility struct for a reference to a configmap key.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"configMapName": {
|
||||
"type": "string"
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1alpha1ConnectionState": {
|
||||
"type": "object",
|
||||
"title": "ConnectionState contains information about remote resource connection state, currently used for clusters and repositories",
|
||||
@@ -7962,6 +8021,16 @@
|
||||
"basicAuth": {
|
||||
"$ref": "#/definitions/v1alpha1BasicAuthBitbucketServer"
|
||||
},
|
||||
"bearerToken": {
|
||||
"$ref": "#/definitions/v1alpha1BearerTokenBitbucket"
|
||||
},
|
||||
"caRef": {
|
||||
"$ref": "#/definitions/v1alpha1ConfigMapKeyRef"
|
||||
},
|
||||
"insecure": {
|
||||
"type": "boolean",
|
||||
"title": "Allow self-signed TLS / Certificates; default: false"
|
||||
},
|
||||
"project": {
|
||||
"description": "Project to scan. Required.",
|
||||
"type": "string"
|
||||
@@ -7992,6 +8061,9 @@
|
||||
"description": "The GitLab API URL to talk to. If blank, uses https://gitlab.com/.",
|
||||
"type": "string"
|
||||
},
|
||||
"caRef": {
|
||||
"$ref": "#/definitions/v1alpha1ConfigMapKeyRef"
|
||||
},
|
||||
"insecure": {
|
||||
"type": "boolean",
|
||||
"title": "Skips validating the SCM provider's TLS certificate - useful for self-signed certificates.; default: false"
|
||||
@@ -8869,6 +8941,16 @@
|
||||
"basicAuth": {
|
||||
"$ref": "#/definitions/v1alpha1BasicAuthBitbucketServer"
|
||||
},
|
||||
"bearerToken": {
|
||||
"$ref": "#/definitions/v1alpha1BearerTokenBitbucket"
|
||||
},
|
||||
"caRef": {
|
||||
"$ref": "#/definitions/v1alpha1ConfigMapKeyRef"
|
||||
},
|
||||
"insecure": {
|
||||
"type": "boolean",
|
||||
"title": "Allow self-signed TLS / Certificates; default: false"
|
||||
},
|
||||
"project": {
|
||||
"description": "Project to scan. Required.",
|
||||
"type": "string"
|
||||
@@ -8969,6 +9051,9 @@
|
||||
"description": "The Gitlab API URL to talk to.",
|
||||
"type": "string"
|
||||
},
|
||||
"caRef": {
|
||||
"$ref": "#/definitions/v1alpha1ConfigMapKeyRef"
|
||||
},
|
||||
"group": {
|
||||
"description": "Gitlab group to scan. Required. You can use either the project id (recommended) or the full namespaced path.",
|
||||
"type": "string"
|
||||
|
||||
@@ -4,6 +4,9 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/argoproj/pkg/stats"
|
||||
@@ -188,10 +191,22 @@ func NewCommand() *cobra.Command {
|
||||
defer closeTracer()
|
||||
}
|
||||
|
||||
// Graceful shutdown code
|
||||
sigCh := make(chan os.Signal, 1)
|
||||
signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)
|
||||
go func() {
|
||||
s := <-sigCh
|
||||
log.Printf("got signal %v, attempting graceful shutdown", s)
|
||||
cancel()
|
||||
}()
|
||||
|
||||
go appController.Run(ctx, statusProcessors, operationProcessors)
|
||||
|
||||
// Wait forever
|
||||
select {}
|
||||
<-ctx.Done()
|
||||
|
||||
log.Println("clean shutdown")
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/reposerver/apiclient"
|
||||
logutils "github.com/argoproj/argo-cd/v2/util/log"
|
||||
"github.com/argoproj/argo-cd/v2/util/tls"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/controllers"
|
||||
@@ -69,6 +70,7 @@ func NewCommand() *cobra.Command {
|
||||
globalPreservedAnnotations []string
|
||||
globalPreservedLabels []string
|
||||
enableScmProviders bool
|
||||
webhookParallelism int
|
||||
)
|
||||
scheme := runtime.NewScheme()
|
||||
_ = clientgoscheme.AddToScheme(scheme)
|
||||
@@ -94,6 +96,8 @@ func NewCommand() *cobra.Command {
|
||||
cli.SetLogFormat(cmdutil.LogFormat)
|
||||
cli.SetLogLevel(cmdutil.LogLevel)
|
||||
|
||||
ctrl.SetLogger(logutils.NewLogrusLogger(logutils.NewWithCurrentConfig()))
|
||||
|
||||
restConfig, err := clientConfig.ClientConfig()
|
||||
errors.CheckError(err)
|
||||
|
||||
@@ -126,7 +130,14 @@ func NewCommand() *cobra.Command {
|
||||
}
|
||||
}
|
||||
|
||||
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
|
||||
cfg := ctrl.GetConfigOrDie()
|
||||
err = appv1alpha1.SetK8SConfigDefaults(cfg)
|
||||
if err != nil {
|
||||
log.Error(err, "Unable to apply K8s REST config defaults")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
mgr, err := ctrl.NewManager(cfg, ctrl.Options{
|
||||
Scheme: scheme,
|
||||
Metrics: metricsserver.Options{
|
||||
BindAddress: metricsAddr,
|
||||
@@ -152,9 +163,7 @@ func NewCommand() *cobra.Command {
|
||||
appSetConfig := appclientset.NewForConfigOrDie(mgr.GetConfig())
|
||||
argoCDDB := db.NewDB(namespace, argoSettingsMgr, k8sClient)
|
||||
|
||||
scmAuth := generators.SCMAuthProviders{
|
||||
GitHubApps: github_app.NewAuthCredentials(argoCDDB.(db.RepoCredsDB)),
|
||||
}
|
||||
scmConfig := generators.NewSCMConfig(scmRootCAPath, allowedScmProviders, enableScmProviders, github_app.NewAuthCredentials(argoCDDB.(db.RepoCredsDB)))
|
||||
|
||||
tlsConfig := apiclient.TLSConfiguration{
|
||||
DisableTLS: repoServerPlaintext,
|
||||
@@ -174,42 +183,10 @@ func NewCommand() *cobra.Command {
|
||||
argoCDService, err := services.NewArgoCDService(argoCDDB.GetRepository, gitSubmoduleEnabled, repoClientset, enableNewGitFileGlobbing)
|
||||
errors.CheckError(err)
|
||||
|
||||
terminalGenerators := map[string]generators.Generator{
|
||||
"List": generators.NewListGenerator(),
|
||||
"Clusters": generators.NewClusterGenerator(mgr.GetClient(), ctx, k8sClient, namespace),
|
||||
"Git": generators.NewGitGenerator(argoCDService),
|
||||
"SCMProvider": generators.NewSCMProviderGenerator(mgr.GetClient(), scmAuth, scmRootCAPath, allowedScmProviders, enableScmProviders),
|
||||
"ClusterDecisionResource": generators.NewDuckTypeGenerator(ctx, dynamicClient, k8sClient, namespace),
|
||||
"PullRequest": generators.NewPullRequestGenerator(mgr.GetClient(), scmAuth, scmRootCAPath, allowedScmProviders, enableScmProviders),
|
||||
"Plugin": generators.NewPluginGenerator(mgr.GetClient(), ctx, k8sClient, namespace),
|
||||
}
|
||||
|
||||
nestedGenerators := map[string]generators.Generator{
|
||||
"List": terminalGenerators["List"],
|
||||
"Clusters": terminalGenerators["Clusters"],
|
||||
"Git": terminalGenerators["Git"],
|
||||
"SCMProvider": terminalGenerators["SCMProvider"],
|
||||
"ClusterDecisionResource": terminalGenerators["ClusterDecisionResource"],
|
||||
"PullRequest": terminalGenerators["PullRequest"],
|
||||
"Plugin": terminalGenerators["Plugin"],
|
||||
"Matrix": generators.NewMatrixGenerator(terminalGenerators),
|
||||
"Merge": generators.NewMergeGenerator(terminalGenerators),
|
||||
}
|
||||
|
||||
topLevelGenerators := map[string]generators.Generator{
|
||||
"List": terminalGenerators["List"],
|
||||
"Clusters": terminalGenerators["Clusters"],
|
||||
"Git": terminalGenerators["Git"],
|
||||
"SCMProvider": terminalGenerators["SCMProvider"],
|
||||
"ClusterDecisionResource": terminalGenerators["ClusterDecisionResource"],
|
||||
"PullRequest": terminalGenerators["PullRequest"],
|
||||
"Plugin": terminalGenerators["Plugin"],
|
||||
"Matrix": generators.NewMatrixGenerator(nestedGenerators),
|
||||
"Merge": generators.NewMergeGenerator(nestedGenerators),
|
||||
}
|
||||
topLevelGenerators := generators.GetGenerators(ctx, mgr.GetClient(), k8sClient, namespace, argoCDService, dynamicClient, scmConfig)
|
||||
|
||||
// start a webhook server that listens to incoming webhook payloads
|
||||
webhookHandler, err := webhook.NewWebhookHandler(namespace, argoSettingsMgr, mgr.GetClient(), topLevelGenerators)
|
||||
webhookHandler, err := webhook.NewWebhookHandler(namespace, webhookParallelism, argoSettingsMgr, mgr.GetClient(), topLevelGenerators)
|
||||
if err != nil {
|
||||
log.Error(err, "failed to create webhook handler")
|
||||
}
|
||||
@@ -258,7 +235,7 @@ func NewCommand() *cobra.Command {
|
||||
"Enabling this will ensure there is only one active controller manager.")
|
||||
command.Flags().StringSliceVar(&applicationSetNamespaces, "applicationset-namespaces", env.StringsFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_NAMESPACES", []string{}, ","), "Argo CD applicationset namespaces")
|
||||
command.Flags().StringVar(&argocdRepoServer, "argocd-repo-server", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER", common.DefaultRepoServerAddr), "Argo CD repo server address")
|
||||
command.Flags().StringVar(&policy, "policy", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_POLICY", ""), "Modify how application is synced between the generator and the cluster. Default is 'sync' (create & update & delete), options: 'create-only', 'create-update' (no deletion), 'create-delete' (no update)")
|
||||
command.Flags().StringVar(&policy, "policy", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_POLICY", ""), "Modify how application is synced between the generator and the cluster. Default is '' (empty), which means AppSets default to 'sync', but they may override that default. Setting an explicit value prevents AppSet-level overrides, unless --allow-policy-override is enabled. Explicit options are: 'sync' (create & update & delete), 'create-only', 'create-update' (no deletion), 'create-delete' (no update)")
|
||||
command.Flags().BoolVar(&enablePolicyOverride, "enable-policy-override", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_POLICY_OVERRIDE", policy == ""), "For security reason if 'policy' is set, it is not possible to override it at applicationSet level. 'allow-policy-override' allows user to define their own policy")
|
||||
command.Flags().BoolVar(&debugLog, "debug", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_DEBUG", false), "Print debug logs. Takes precedence over loglevel")
|
||||
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_LOGFORMAT", "text"), "Set the logging format. One of: text|json")
|
||||
@@ -275,6 +252,7 @@ func NewCommand() *cobra.Command {
|
||||
command.Flags().StringVar(&scmRootCAPath, "scm-root-ca-path", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_SCM_ROOT_CA_PATH", ""), "Provide Root CA Path for self-signed TLS Certificates")
|
||||
command.Flags().StringSliceVar(&globalPreservedAnnotations, "preserved-annotations", env.StringsFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_GLOBAL_PRESERVED_ANNOTATIONS", []string{}, ","), "Sets global preserved field values for annotations")
|
||||
command.Flags().StringSliceVar(&globalPreservedLabels, "preserved-labels", env.StringsFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_GLOBAL_PRESERVED_LABELS", []string{}, ","), "Sets global preserved field values for labels")
|
||||
command.Flags().IntVar(&webhookParallelism, "webhook-parallelism-limit", env.ParseNumFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_WEBHOOK_PARALLELISM_LIMIT", 50, 1, 1000), "Number of webhook requests processed concurrently")
|
||||
return &command
|
||||
}
|
||||
|
||||
|
||||
@@ -81,8 +81,8 @@ func NewCommand() *cobra.Command {
|
||||
},
|
||||
}
|
||||
|
||||
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", "text", "Set the logging format. One of: text|json")
|
||||
command.Flags().StringVar(&cmdutil.LogLevel, "loglevel", "info", "Set the logging level. One of: debug|info|warn|error")
|
||||
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_CMP_SERVER_LOGFORMAT", "text"), "Set the logging format. One of: text|json")
|
||||
command.Flags().StringVar(&cmdutil.LogLevel, "loglevel", env.StringFromEnv("ARGOCD_CMP_SERVER_LOGLEVEL", "info"), "Set the logging level. One of: trace|debug|info|warn|error")
|
||||
command.Flags().StringVar(&configFilePath, "config-dir-path", common.DefaultPluginConfigFilePath, "Config management plugin configuration file location, Default is '/home/argocd/cmp-server/config/'")
|
||||
command.Flags().StringVar(&otlpAddress, "otlp-address", env.StringFromEnv("ARGOCD_CMP_SERVER_OTLP_ADDRESS", ""), "OpenTelemetry collector address to send traces to")
|
||||
command.Flags().BoolVar(&otlpInsecure, "otlp-insecure", env.ParseBoolFromEnv("ARGOCD_CMP_SERVER_OTLP_INSECURE", true), "OpenTelemetry collector insecure mode")
|
||||
|
||||
@@ -5,8 +5,6 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/util/git"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
@@ -33,9 +31,9 @@ func NewCommand() *cobra.Command {
|
||||
if len(os.Args) != 2 {
|
||||
errors.CheckError(fmt.Errorf("expected 1 argument, got %d", len(os.Args)-1))
|
||||
}
|
||||
nonce := os.Getenv(git.ASKPASS_NONCE_ENV)
|
||||
nonce := os.Getenv(askpass.ASKPASS_NONCE_ENV)
|
||||
if nonce == "" {
|
||||
errors.CheckError(fmt.Errorf("%s is not set", git.ASKPASS_NONCE_ENV))
|
||||
errors.CheckError(fmt.Errorf("%s is not set", askpass.ASKPASS_NONCE_ENV))
|
||||
}
|
||||
conn, err := grpc_util.BlockingDial(ctx, "unix", askpass.SocketPath, nil, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
errors.CheckError(err)
|
||||
|
||||
@@ -5,6 +5,10 @@ import (
|
||||
"math"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/argoproj/pkg/stats"
|
||||
@@ -115,7 +119,7 @@ func NewCommand() *cobra.Command {
|
||||
helmRegistryMaxIndexSizeQuantity, err := resource.ParseQuantity(helmRegistryMaxIndexSize)
|
||||
errors.CheckError(err)
|
||||
|
||||
askPassServer := askpass.NewServer()
|
||||
askPassServer := askpass.NewServer(askpass.SocketPath)
|
||||
metricsServer := metrics.NewMetricsServer()
|
||||
cacheutil.CollectMetrics(redisClient, metricsServer)
|
||||
server, err := reposerver.NewServer(metricsServer, cache, tlsConfigCustomizer, repository.RepoServerInitConstants{
|
||||
@@ -173,7 +177,7 @@ func NewCommand() *cobra.Command {
|
||||
})
|
||||
http.Handle("/metrics", metricsServer.GetHandler())
|
||||
go func() { errors.CheckError(http.ListenAndServe(fmt.Sprintf("%s:%d", metricsHost, metricsPort), nil)) }()
|
||||
go func() { errors.CheckError(askPassServer.Run(askpass.SocketPath)) }()
|
||||
go func() { errors.CheckError(askPassServer.Run()) }()
|
||||
|
||||
if gpg.IsGPGEnabled() {
|
||||
log.Infof("Initializing GnuPG keyring at %s", common.GetGnuPGHomePath())
|
||||
@@ -192,8 +196,27 @@ func NewCommand() *cobra.Command {
|
||||
stats.RegisterStackDumper()
|
||||
stats.StartStatsTicker(10 * time.Minute)
|
||||
stats.RegisterHeapDumper("memprofile")
|
||||
|
||||
// Graceful shutdown code adapted from https://gist.github.com/embano1/e0bf49d24f1cdd07cffad93097c04f0a
|
||||
sigCh := make(chan os.Signal, 1)
|
||||
signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
s := <-sigCh
|
||||
log.Printf("got signal %v, attempting graceful shutdown", s)
|
||||
grpc.GracefulStop()
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
log.Println("starting grpc server")
|
||||
err = grpc.Serve(listener)
|
||||
errors.CheckError(err)
|
||||
if err != nil {
|
||||
log.Fatalf("could not serve: %v", err)
|
||||
}
|
||||
wg.Wait()
|
||||
log.Println("clean shutdown")
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
@@ -12,8 +12,10 @@ import (
|
||||
"github.com/argoproj/pkg/stats"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
cmdutil "github.com/argoproj/argo-cd/v2/cmd/util"
|
||||
"github.com/argoproj/argo-cd/v2/common"
|
||||
@@ -42,6 +44,7 @@ const (
|
||||
var (
|
||||
failureRetryCount = env.ParseNumFromEnv(failureRetryCountEnv, 0, 0, 10)
|
||||
failureRetryPeriodMilliSeconds = env.ParseNumFromEnv(failureRetryPeriodMilliSecondsEnv, 100, 0, 1000)
|
||||
gitSubmoduleEnabled = env.ParseBoolFromEnv(common.EnvGitSubmoduleEnabled, true)
|
||||
)
|
||||
|
||||
// NewCommand returns a new instance of an argocd command
|
||||
@@ -79,6 +82,13 @@ func NewCommand() *cobra.Command {
|
||||
staticAssetsDir string
|
||||
applicationNamespaces []string
|
||||
enableProxyExtension bool
|
||||
webhookParallelism int
|
||||
|
||||
// ApplicationSet
|
||||
enableNewGitFileGlobbing bool
|
||||
scmRootCAPath string
|
||||
allowedScmProviders []string
|
||||
enableScmProviders bool
|
||||
)
|
||||
command := &cobra.Command{
|
||||
Use: cliName,
|
||||
@@ -130,6 +140,12 @@ func NewCommand() *cobra.Command {
|
||||
StrictValidation: repoServerStrictTLS,
|
||||
}
|
||||
|
||||
dynamicClient := dynamic.NewForConfigOrDie(config)
|
||||
|
||||
controllerClient, err := client.New(config, client.Options{})
|
||||
errors.CheckError(err)
|
||||
controllerClient = client.NewDryRunClient(controllerClient)
|
||||
|
||||
// Load CA information to use for validating connections to the
|
||||
// repository server, if strict TLS validation was requested.
|
||||
if !repoServerPlaintext && repoServerStrictTLS {
|
||||
@@ -179,37 +195,48 @@ func NewCommand() *cobra.Command {
|
||||
}
|
||||
|
||||
argoCDOpts := server.ArgoCDServerOpts{
|
||||
Insecure: insecure,
|
||||
ListenPort: listenPort,
|
||||
ListenHost: listenHost,
|
||||
MetricsPort: metricsPort,
|
||||
MetricsHost: metricsHost,
|
||||
Namespace: namespace,
|
||||
BaseHRef: baseHRef,
|
||||
RootPath: rootPath,
|
||||
KubeClientset: kubeclientset,
|
||||
AppClientset: appClientSet,
|
||||
RepoClientset: repoclientset,
|
||||
DexServerAddr: dexServerAddress,
|
||||
DexTLSConfig: dexTlsConfig,
|
||||
DisableAuth: disableAuth,
|
||||
ContentTypes: contentTypesList,
|
||||
EnableGZip: enableGZip,
|
||||
TLSConfigCustomizer: tlsConfigCustomizer,
|
||||
Cache: cache,
|
||||
RepoServerCache: repoServerCache,
|
||||
XFrameOptions: frameOptions,
|
||||
ContentSecurityPolicy: contentSecurityPolicy,
|
||||
RedisClient: redisClient,
|
||||
StaticAssetsDir: staticAssetsDir,
|
||||
ApplicationNamespaces: applicationNamespaces,
|
||||
EnableProxyExtension: enableProxyExtension,
|
||||
Insecure: insecure,
|
||||
ListenPort: listenPort,
|
||||
ListenHost: listenHost,
|
||||
MetricsPort: metricsPort,
|
||||
MetricsHost: metricsHost,
|
||||
Namespace: namespace,
|
||||
BaseHRef: baseHRef,
|
||||
RootPath: rootPath,
|
||||
DynamicClientset: dynamicClient,
|
||||
KubeControllerClientset: controllerClient,
|
||||
KubeClientset: kubeclientset,
|
||||
AppClientset: appClientSet,
|
||||
RepoClientset: repoclientset,
|
||||
DexServerAddr: dexServerAddress,
|
||||
DexTLSConfig: dexTlsConfig,
|
||||
DisableAuth: disableAuth,
|
||||
ContentTypes: contentTypesList,
|
||||
EnableGZip: enableGZip,
|
||||
TLSConfigCustomizer: tlsConfigCustomizer,
|
||||
Cache: cache,
|
||||
RepoServerCache: repoServerCache,
|
||||
XFrameOptions: frameOptions,
|
||||
ContentSecurityPolicy: contentSecurityPolicy,
|
||||
RedisClient: redisClient,
|
||||
StaticAssetsDir: staticAssetsDir,
|
||||
ApplicationNamespaces: applicationNamespaces,
|
||||
EnableProxyExtension: enableProxyExtension,
|
||||
WebhookParallelism: webhookParallelism,
|
||||
}
|
||||
|
||||
appsetOpts := server.ApplicationSetOpts{
|
||||
GitSubmoduleEnabled: gitSubmoduleEnabled,
|
||||
EnableNewGitFileGlobbing: enableNewGitFileGlobbing,
|
||||
ScmRootCAPath: scmRootCAPath,
|
||||
AllowedScmProviders: allowedScmProviders,
|
||||
EnableScmProviders: enableScmProviders,
|
||||
}
|
||||
|
||||
stats.RegisterStackDumper()
|
||||
stats.StartStatsTicker(10 * time.Minute)
|
||||
stats.RegisterHeapDumper("memprofile")
|
||||
argocd := server.NewServer(ctx, argoCDOpts)
|
||||
argocd := server.NewServer(ctx, argoCDOpts, appsetOpts)
|
||||
argocd.Init(ctx)
|
||||
lns, err := argocd.Listen()
|
||||
errors.CheckError(err)
|
||||
@@ -232,7 +259,7 @@ func NewCommand() *cobra.Command {
|
||||
Example: templates.Examples(`
|
||||
# Start the Argo CD API server with default settings
|
||||
$ argocd-server
|
||||
|
||||
|
||||
# Start the Argo CD API server on a custom port and enable tracing
|
||||
$ argocd-server --port 8888 --otlp-address localhost:4317
|
||||
`),
|
||||
@@ -269,6 +296,14 @@ func NewCommand() *cobra.Command {
|
||||
command.Flags().BoolVar(&dexServerStrictTLS, "dex-server-strict-tls", env.ParseBoolFromEnv("ARGOCD_SERVER_DEX_SERVER_STRICT_TLS", false), "Perform strict validation of TLS certificates when connecting to dex server")
|
||||
command.Flags().StringSliceVar(&applicationNamespaces, "application-namespaces", env.StringsFromEnv("ARGOCD_APPLICATION_NAMESPACES", []string{}, ","), "List of additional namespaces where application resources can be managed in")
|
||||
command.Flags().BoolVar(&enableProxyExtension, "enable-proxy-extension", env.ParseBoolFromEnv("ARGOCD_SERVER_ENABLE_PROXY_EXTENSION", false), "Enable Proxy Extension feature")
|
||||
command.Flags().IntVar(&webhookParallelism, "webhook-parallelism-limit", env.ParseNumFromEnv("ARGOCD_SERVER_WEBHOOK_PARALLELISM_LIMIT", 50, 1, 1000), "Number of webhook requests processed concurrently")
|
||||
|
||||
// Flags related to the applicationSet component.
|
||||
command.Flags().StringVar(&scmRootCAPath, "appset-scm-root-ca-path", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_SCM_ROOT_CA_PATH", ""), "Provide Root CA Path for self-signed TLS Certificates")
|
||||
command.Flags().BoolVar(&enableScmProviders, "appset-enable-scm-providers", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_SCM_PROVIDERS", true), "Enable retrieving information from SCM providers, used by the SCM and PR generators (Default: true)")
|
||||
command.Flags().StringSliceVar(&allowedScmProviders, "appset-allowed-scm-providers", env.StringsFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_ALLOWED_SCM_PROVIDERS", []string{}, ","), "The list of allowed custom SCM provider API URLs. This restriction does not apply to SCM or PR generators which do not accept a custom API URL. (Default: Empty = all)")
|
||||
command.Flags().BoolVar(&enableNewGitFileGlobbing, "appset-enable-new-git-file-globbing", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_NEW_GIT_FILE_GLOBBING", false), "Enable new globbing in Git files generator.")
|
||||
|
||||
tlsConfigCustomizerSrc = tls.AddTLSFlagsToCmd(command)
|
||||
cacheSrc = servercache.AddCacheFlagsToCmd(command, cacheutil.Options{
|
||||
OnClientCreated: func(client *redis.Client) {
|
||||
|
||||
@@ -218,35 +218,3 @@ func specsEqual(left, right unstructured.Unstructured) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func iterateStringFields(obj interface{}, callback func(name string, val string) string) {
|
||||
if mapField, ok := obj.(map[string]interface{}); ok {
|
||||
for field, val := range mapField {
|
||||
if strVal, ok := val.(string); ok {
|
||||
mapField[field] = callback(field, strVal)
|
||||
} else {
|
||||
iterateStringFields(val, callback)
|
||||
}
|
||||
}
|
||||
} else if arrayField, ok := obj.([]interface{}); ok {
|
||||
for i := range arrayField {
|
||||
iterateStringFields(arrayField[i], callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func redactor(dirtyString string) string {
|
||||
config := make(map[string]interface{})
|
||||
err := yaml.Unmarshal([]byte(dirtyString), &config)
|
||||
errors.CheckError(err)
|
||||
iterateStringFields(config, func(name string, val string) string {
|
||||
if name == "clientSecret" || name == "secret" || name == "bindPW" {
|
||||
return "********"
|
||||
} else {
|
||||
return val
|
||||
}
|
||||
})
|
||||
data, err := yaml.Marshal(config)
|
||||
errors.CheckError(err)
|
||||
return string(data)
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@ func NewGenAppSpecCommand() *cobra.Command {
|
||||
outputFormat string
|
||||
annotations []string
|
||||
inline bool
|
||||
setFinalizer bool
|
||||
)
|
||||
command := &cobra.Command{
|
||||
Use: "generate-spec APPNAME",
|
||||
@@ -112,7 +113,9 @@ func NewGenAppSpecCommand() *cobra.Command {
|
||||
c.HelpFunc()(c, args)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if setFinalizer {
|
||||
app.Finalizers = append(app.Finalizers, "resources-finalizer.argocd.argoproj.io")
|
||||
}
|
||||
out, closer, err := getOutWriter(inline, fileURL)
|
||||
errors.CheckError(err)
|
||||
defer io.Close(closer)
|
||||
@@ -126,6 +129,7 @@ func NewGenAppSpecCommand() *cobra.Command {
|
||||
command.Flags().StringArrayVarP(&annotations, "annotations", "", []string{}, "Set metadata annotations (e.g. example=value)")
|
||||
command.Flags().StringVarP(&outputFormat, "output", "o", "yaml", "Output format. One of: json|yaml")
|
||||
command.Flags().BoolVarP(&inline, "inline", "i", false, "If set then generated resource is written back to the file specified in --file flag")
|
||||
command.Flags().BoolVar(&setFinalizer, "set-finalizer", false, "Sets deletion finalizer on the application, application resources will be cascaded on deletion")
|
||||
|
||||
// Only complete files with appropriate extension.
|
||||
err := command.Flags().SetAnnotation("file", cobra.BashCompFilenameExt, []string{"json", "yaml", "yml"})
|
||||
|
||||
@@ -104,7 +104,12 @@ func loadClusters(ctx context.Context, kubeClient *kubernetes.Clientset, appClie
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client := redis.NewClient(&redis.Options{Addr: fmt.Sprintf("localhost:%d", port)})
|
||||
|
||||
redisOptions := &redis.Options{Addr: fmt.Sprintf("localhost:%d", port)}
|
||||
if err = common.SetOptionalRedisPasswordFromKubeConfig(ctx, kubeClient, namespace, redisOptions); err != nil {
|
||||
log.Warnf("Failed to fetch & set redis password for namespace %s: %v", namespace, err)
|
||||
}
|
||||
client := redis.NewClient(redisOptions)
|
||||
compressionType, err := cacheutil.CompressionTypeFromString(redisCompressionStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -17,5 +17,5 @@ func TestProjectAllowListGen(t *testing.T) {
|
||||
|
||||
globalProj, err := generateProjectAllowList(resourceList, "testdata/test_clusterrole.yaml", "testproj")
|
||||
require.NoError(t, err)
|
||||
assert.Positive(t, len(globalProj.Spec.NamespaceResourceWhitelist))
|
||||
assert.NotEmpty(t, globalProj.Spec.NamespaceResourceWhitelist)
|
||||
}
|
||||
|
||||
@@ -6,25 +6,18 @@ import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apierr "k8s.io/apimachinery/pkg/api/errors"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/util/cli"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/common"
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/util/cli"
|
||||
"github.com/argoproj/argo-cd/v2/util/errors"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
defaulRedisInitialPasswordSecretName = "argocd-redis"
|
||||
defaultResisInitialPasswordKey = "auth"
|
||||
)
|
||||
|
||||
func generateRandomPassword() (string, error) {
|
||||
@@ -52,8 +45,8 @@ func NewRedisInitialPasswordCommand() *cobra.Command {
|
||||
namespace, _, err := clientConfig.Namespace()
|
||||
errors.CheckError(err)
|
||||
|
||||
redisInitialPasswordSecretName := defaulRedisInitialPasswordSecretName
|
||||
redisInitialPasswordKey := defaultResisInitialPasswordKey
|
||||
redisInitialPasswordSecretName := common.DefaultRedisInitialPasswordSecretName
|
||||
redisInitialPasswordKey := common.DefaultRedisInitialPasswordKey
|
||||
fmt.Printf("Checking for initial Redis password in secret %s/%s at key %s. \n", namespace, redisInitialPasswordSecretName, redisInitialPasswordKey)
|
||||
|
||||
config, err := clientConfig.ClientConfig()
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var textToRedact = `
|
||||
connectors:
|
||||
- config:
|
||||
clientID: aabbccddeeff00112233
|
||||
clientSecret: |
|
||||
theSecret
|
||||
orgs:
|
||||
- name: your-github-org
|
||||
redirectURI: https://argocd.example.com/api/dex/callback
|
||||
id: github
|
||||
name: GitHub
|
||||
type: github
|
||||
- config:
|
||||
bindDN: uid=serviceaccount,cn=users,dc=example,dc=com
|
||||
bindPW: theSecret
|
||||
host: ldap.example.com:636
|
||||
id: ldap
|
||||
name: LDAP
|
||||
type: ldap
|
||||
grpc:
|
||||
addr: 0.0.0.0:5557
|
||||
telemetry:
|
||||
http: 0.0.0.0:5558
|
||||
issuer: https://argocd.example.com/api/dex
|
||||
oauth2:
|
||||
skipApprovalScreen: true
|
||||
staticClients:
|
||||
- id: argo-cd
|
||||
name: Argo CD
|
||||
redirectURIs:
|
||||
- https://argocd.example.com/auth/callback
|
||||
secret: Dis9M-GA11oTwZVQQWdDklPQw-sWXZkWJFyyEhMs
|
||||
- id: argo-cd-cli
|
||||
name: Argo CD CLI
|
||||
public: true
|
||||
redirectURIs:
|
||||
- http://localhost
|
||||
storage:
|
||||
type: memory
|
||||
web:
|
||||
http: 0.0.0.0:5556`
|
||||
|
||||
var expectedRedaction = `connectors:
|
||||
- config:
|
||||
clientID: aabbccddeeff00112233
|
||||
clientSecret: '********'
|
||||
orgs:
|
||||
- name: your-github-org
|
||||
redirectURI: https://argocd.example.com/api/dex/callback
|
||||
id: github
|
||||
name: GitHub
|
||||
type: github
|
||||
- config:
|
||||
bindDN: uid=serviceaccount,cn=users,dc=example,dc=com
|
||||
bindPW: '********'
|
||||
host: ldap.example.com:636
|
||||
id: ldap
|
||||
name: LDAP
|
||||
type: ldap
|
||||
grpc:
|
||||
addr: 0.0.0.0:5557
|
||||
issuer: https://argocd.example.com/api/dex
|
||||
oauth2:
|
||||
skipApprovalScreen: true
|
||||
staticClients:
|
||||
- id: argo-cd
|
||||
name: Argo CD
|
||||
redirectURIs:
|
||||
- https://argocd.example.com/auth/callback
|
||||
secret: '********'
|
||||
- id: argo-cd-cli
|
||||
name: Argo CD CLI
|
||||
public: true
|
||||
redirectURIs:
|
||||
- http://localhost
|
||||
storage:
|
||||
type: memory
|
||||
telemetry:
|
||||
http: 0.0.0.0:5558
|
||||
web:
|
||||
http: 0.0.0.0:5556
|
||||
`
|
||||
|
||||
func TestSecretsRedactor(t *testing.T) {
|
||||
assert.Equal(t, expectedRedaction, redactor(textToRedact))
|
||||
}
|
||||
@@ -122,7 +122,7 @@ func NewRBACCommand() *cobra.Command {
|
||||
return command
|
||||
}
|
||||
|
||||
// NewRBACCanRoleCommand is the command for 'rbac can-role'
|
||||
// NewRBACCanCommand is the command for 'rbac can-role'
|
||||
func NewRBACCanCommand() *cobra.Command {
|
||||
var (
|
||||
policyFile string
|
||||
|
||||
@@ -776,8 +776,6 @@ func NewApplicationSetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Com
|
||||
}
|
||||
}
|
||||
|
||||
// sourcePosition startes with 1, thus, it needs to be decreased by 1 to find the correct index in the list of sources
|
||||
sourcePosition = sourcePosition - 1
|
||||
visited := cmdutil.SetAppSpecOptions(c.Flags(), &app.Spec, &appOpts, sourcePosition)
|
||||
if visited == 0 {
|
||||
log.Error("Please set at least one option to update")
|
||||
@@ -2169,7 +2167,7 @@ func getAppNamesBySelector(ctx context.Context, appIf application.ApplicationSer
|
||||
return appNames, nil
|
||||
}
|
||||
|
||||
// ResourceDiff tracks the state of a resource when waiting on an application status.
|
||||
// ResourceState tracks the state of a resource when waiting on an application status.
|
||||
type resourceState struct {
|
||||
Group string
|
||||
Kind string
|
||||
@@ -2361,6 +2359,10 @@ func waitOnApplicationStatus(ctx context.Context, acdClient argocdclient.Client,
|
||||
// time when the sync status lags behind when an operation completes
|
||||
refresh := false
|
||||
|
||||
// printSummary controls whether we print the app summary table, OperationState, and ResourceState
|
||||
// We don't want to print these when output type is json or yaml, as the output would become unparsable.
|
||||
printSummary := output != "json" && output != "yaml"
|
||||
|
||||
appRealName, appNs := argo.ParseFromQualifiedName(appName, "")
|
||||
|
||||
printFinalStatus := func(app *argoappv1.Application) *argoappv1.Application {
|
||||
@@ -2377,11 +2379,13 @@ func waitOnApplicationStatus(ctx context.Context, acdClient argocdclient.Client,
|
||||
_ = conn.Close()
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
printAppSummaryTable(app, appURL(ctx, acdClient, appName), nil)
|
||||
fmt.Println()
|
||||
if watch.operation {
|
||||
printOperationResult(app.Status.OperationState)
|
||||
if printSummary {
|
||||
fmt.Println()
|
||||
printAppSummaryTable(app, appURL(ctx, acdClient, appName), nil)
|
||||
fmt.Println()
|
||||
if watch.operation {
|
||||
printOperationResult(app.Status.OperationState)
|
||||
}
|
||||
}
|
||||
|
||||
switch output {
|
||||
@@ -2396,13 +2400,13 @@ func waitOnApplicationStatus(ctx context.Context, acdClient argocdclient.Client,
|
||||
_ = w.Flush()
|
||||
}
|
||||
case "tree":
|
||||
mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState := resourceParentChild(ctx, acdClient, appName, appNs)
|
||||
mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState := resourceParentChild(ctx, acdClient, appRealName, appNs)
|
||||
if len(mapUidToNode) > 0 {
|
||||
fmt.Println()
|
||||
printTreeView(mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState)
|
||||
}
|
||||
case "tree=detailed":
|
||||
mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState := resourceParentChild(ctx, acdClient, appName, appNs)
|
||||
mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState := resourceParentChild(ctx, acdClient, appRealName, appNs)
|
||||
if len(mapUidToNode) > 0 {
|
||||
fmt.Println()
|
||||
printTreeViewDetailed(mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState)
|
||||
@@ -2421,17 +2425,26 @@ func waitOnApplicationStatus(ctx context.Context, acdClient argocdclient.Client,
|
||||
AppNamespace: &appNs,
|
||||
})
|
||||
errors.CheckError(err)
|
||||
fmt.Println()
|
||||
fmt.Println("This is the state of the app after `wait` timed out:")
|
||||
|
||||
if printSummary {
|
||||
fmt.Println()
|
||||
fmt.Println("This is the state of the app after `wait` timed out:")
|
||||
}
|
||||
|
||||
printFinalStatus(app)
|
||||
cancel()
|
||||
fmt.Println()
|
||||
fmt.Println("The command timed out waiting for the conditions to be met.")
|
||||
|
||||
if printSummary {
|
||||
fmt.Println()
|
||||
fmt.Println("The command timed out waiting for the conditions to be met.")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
w := tabwriter.NewWriter(os.Stdout, 5, 0, 2, ' ', 0)
|
||||
_, _ = fmt.Fprintf(w, waitFormatString, "TIMESTAMP", "GROUP", "KIND", "NAMESPACE", "NAME", "STATUS", "HEALTH", "HOOK", "MESSAGE")
|
||||
if printSummary {
|
||||
_, _ = fmt.Fprintf(w, waitFormatString, "TIMESTAMP", "GROUP", "KIND", "NAMESPACE", "NAME", "STATUS", "HEALTH", "HOOK", "MESSAGE")
|
||||
}
|
||||
|
||||
prevStates := make(map[string]*resourceState)
|
||||
conn, appClient := acdClient.NewApplicationClientOrDie()
|
||||
@@ -2515,7 +2528,7 @@ func waitOnApplicationStatus(ctx context.Context, acdClient argocdclient.Client,
|
||||
prevStates[stateKey] = newState
|
||||
doPrint = true
|
||||
}
|
||||
if doPrint {
|
||||
if doPrint && printSummary {
|
||||
_, _ = fmt.Fprintf(w, waitFormatString, prevStates[stateKey].FormatItems()...)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,25 @@ package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/reposerver/apiclient"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
argocdclient "github.com/argoproj/argo-cd/v2/pkg/apiclient"
|
||||
accountpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/account"
|
||||
applicationpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/application"
|
||||
@@ -1849,6 +1861,316 @@ func testApp(name, project string, labels map[string]string, annotations map[str
|
||||
}
|
||||
}
|
||||
|
||||
func TestWaitOnApplicationStatus_JSON_YAML_WideOutput(t *testing.T) {
|
||||
acdClient := &customAcdClient{&fakeAcdClient{}}
|
||||
ctx := context.Background()
|
||||
var selectResource []*v1alpha1.SyncOperationResource
|
||||
watch := watchOpts{
|
||||
sync: false,
|
||||
health: false,
|
||||
operation: true,
|
||||
suspended: false,
|
||||
}
|
||||
watch = getWatchOpts(watch)
|
||||
|
||||
output, err := captureOutput(func() error {
|
||||
_, _, _ = waitOnApplicationStatus(ctx, acdClient, "app-name", 0, watch, selectResource, "json")
|
||||
return nil
|
||||
},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, json.Valid([]byte(output)))
|
||||
|
||||
output, err = captureOutput(func() error {
|
||||
_, _, _ = waitOnApplicationStatus(ctx, acdClient, "app-name", 0, watch, selectResource, "yaml")
|
||||
return nil
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
err = yaml.Unmarshal([]byte(output), &v1alpha1.Application{})
|
||||
require.NoError(t, err)
|
||||
|
||||
output, _ = captureOutput(func() error {
|
||||
_, _, _ = waitOnApplicationStatus(ctx, acdClient, "app-name", 0, watch, selectResource, "")
|
||||
return nil
|
||||
})
|
||||
timeStr := time.Now().Format("2006-01-02T15:04:05-07:00")
|
||||
|
||||
expectation := `TIMESTAMP GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE
|
||||
%s Service default service-name1 Synced Healthy
|
||||
%s apps Deployment default test Synced Healthy
|
||||
|
||||
Name: argocd/test
|
||||
Project: default
|
||||
Server: local
|
||||
Namespace: argocd
|
||||
URL: http://localhost:8080/applications/app-name
|
||||
Source:
|
||||
- Repo: test
|
||||
Target: master
|
||||
Path: /test
|
||||
Helm Values: path1,path2
|
||||
Name Prefix: prefix
|
||||
SyncWindow: Sync Allowed
|
||||
Sync Policy: Automated (Prune)
|
||||
Sync Status: OutOfSync from master
|
||||
Health Status: Progressing (health-message)
|
||||
|
||||
Operation: Sync
|
||||
Sync Revision: revision
|
||||
Phase:
|
||||
Start: 0001-01-01 00:00:00 +0000 UTC
|
||||
Finished: 2020-11-10 23:00:00 +0000 UTC
|
||||
Duration: 2333448h16m18.871345152s
|
||||
Message: test
|
||||
|
||||
GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE
|
||||
Service default service-name1 Synced Healthy
|
||||
apps Deployment default test Synced Healthy
|
||||
`
|
||||
expectation = fmt.Sprintf(expectation, timeStr, timeStr)
|
||||
expectationParts := strings.Split(expectation, "\n")
|
||||
slices.Sort(expectationParts)
|
||||
expectationSorted := strings.Join(expectationParts, "\n")
|
||||
outputParts := strings.Split(output, "\n")
|
||||
slices.Sort(outputParts)
|
||||
outputSorted := strings.Join(outputParts, "\n")
|
||||
// Need to compare sorted since map entries may not keep a specific order during serialization, leading to flakiness.
|
||||
assert.Equalf(t, expectationSorted, outputSorted, "Incorrect output %q, should be %q (items order doesn't matter)", output, expectation)
|
||||
}
|
||||
|
||||
type customAcdClient struct {
|
||||
*fakeAcdClient
|
||||
}
|
||||
|
||||
func (c *customAcdClient) WatchApplicationWithRetry(ctx context.Context, appName string, revision string) chan *v1alpha1.ApplicationWatchEvent {
|
||||
appEventsCh := make(chan *v1alpha1.ApplicationWatchEvent)
|
||||
_, appClient := c.NewApplicationClientOrDie()
|
||||
app, _ := appClient.Get(ctx, &applicationpkg.ApplicationQuery{})
|
||||
|
||||
newApp := v1alpha1.Application{
|
||||
TypeMeta: app.TypeMeta,
|
||||
ObjectMeta: app.ObjectMeta,
|
||||
Spec: app.Spec,
|
||||
Status: app.Status,
|
||||
Operation: app.Operation,
|
||||
}
|
||||
|
||||
go func() {
|
||||
appEventsCh <- &v1alpha1.ApplicationWatchEvent{
|
||||
Type: watch.Bookmark,
|
||||
Application: newApp,
|
||||
}
|
||||
close(appEventsCh)
|
||||
}()
|
||||
|
||||
return appEventsCh
|
||||
}
|
||||
|
||||
func (c *customAcdClient) NewApplicationClientOrDie() (io.Closer, applicationpkg.ApplicationServiceClient) {
|
||||
return &fakeConnection{}, &fakeAppServiceClient{}
|
||||
}
|
||||
|
||||
func (c *customAcdClient) NewSettingsClientOrDie() (io.Closer, settingspkg.SettingsServiceClient) {
|
||||
return &fakeConnection{}, &fakeSettingsServiceClient{}
|
||||
}
|
||||
|
||||
type fakeConnection struct{}
|
||||
|
||||
func (c *fakeConnection) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type fakeSettingsServiceClient struct{}
|
||||
|
||||
func (f fakeSettingsServiceClient) Get(ctx context.Context, in *settingspkg.SettingsQuery, opts ...grpc.CallOption) (*settingspkg.Settings, error) {
|
||||
return &settingspkg.Settings{
|
||||
URL: "http://localhost:8080",
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f fakeSettingsServiceClient) GetPlugins(ctx context.Context, in *settingspkg.SettingsQuery, opts ...grpc.CallOption) (*settingspkg.SettingsPluginsResponse, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
type fakeAppServiceClient struct{}
|
||||
|
||||
func (c *fakeAppServiceClient) Get(ctx context.Context, in *applicationpkg.ApplicationQuery, opts ...grpc.CallOption) (*v1alpha1.Application, error) {
|
||||
time := metav1.Date(2020, time.November, 10, 23, 0, 0, 0, time.UTC)
|
||||
return &v1alpha1.Application{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSpec{
|
||||
SyncPolicy: &v1alpha1.SyncPolicy{
|
||||
Automated: &v1alpha1.SyncPolicyAutomated{
|
||||
Prune: true,
|
||||
},
|
||||
},
|
||||
Project: "default",
|
||||
Destination: v1alpha1.ApplicationDestination{Server: "local", Namespace: "argocd"},
|
||||
Source: &v1alpha1.ApplicationSource{
|
||||
RepoURL: "test",
|
||||
TargetRevision: "master",
|
||||
Path: "/test",
|
||||
Helm: &v1alpha1.ApplicationSourceHelm{
|
||||
ValueFiles: []string{"path1", "path2"},
|
||||
},
|
||||
Kustomize: &v1alpha1.ApplicationSourceKustomize{NamePrefix: "prefix"},
|
||||
},
|
||||
},
|
||||
Status: v1alpha1.ApplicationStatus{
|
||||
Resources: []v1alpha1.ResourceStatus{
|
||||
{
|
||||
Group: "",
|
||||
Kind: "Service",
|
||||
Namespace: "default",
|
||||
Name: "service-name1",
|
||||
Status: "Synced",
|
||||
Health: &v1alpha1.HealthStatus{
|
||||
Status: health.HealthStatusHealthy,
|
||||
Message: "health-message",
|
||||
},
|
||||
},
|
||||
{
|
||||
Group: "apps",
|
||||
Kind: "Deployment",
|
||||
Namespace: "default",
|
||||
Name: "test",
|
||||
Status: "Synced",
|
||||
Health: &v1alpha1.HealthStatus{
|
||||
Status: health.HealthStatusHealthy,
|
||||
Message: "health-message",
|
||||
},
|
||||
},
|
||||
},
|
||||
OperationState: &v1alpha1.OperationState{
|
||||
SyncResult: &v1alpha1.SyncOperationResult{
|
||||
Revision: "revision",
|
||||
},
|
||||
FinishedAt: &time,
|
||||
Message: "test",
|
||||
},
|
||||
Sync: v1alpha1.SyncStatus{
|
||||
Status: v1alpha1.SyncStatusCodeOutOfSync,
|
||||
},
|
||||
Health: v1alpha1.HealthStatus{
|
||||
Status: health.HealthStatusProgressing,
|
||||
Message: "health-message",
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *fakeAppServiceClient) List(ctx context.Context, in *applicationpkg.ApplicationQuery, opts ...grpc.CallOption) (*v1alpha1.ApplicationList, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeAppServiceClient) ListResourceEvents(ctx context.Context, in *applicationpkg.ApplicationResourceEventsQuery, opts ...grpc.CallOption) (*v1.EventList, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeAppServiceClient) Watch(ctx context.Context, in *applicationpkg.ApplicationQuery, opts ...grpc.CallOption) (applicationpkg.ApplicationService_WatchClient, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeAppServiceClient) Create(ctx context.Context, in *applicationpkg.ApplicationCreateRequest, opts ...grpc.CallOption) (*v1alpha1.Application, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeAppServiceClient) GetApplicationSyncWindows(ctx context.Context, in *applicationpkg.ApplicationSyncWindowsQuery, opts ...grpc.CallOption) (*applicationpkg.ApplicationSyncWindowsResponse, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeAppServiceClient) RevisionMetadata(ctx context.Context, in *applicationpkg.RevisionMetadataQuery, opts ...grpc.CallOption) (*v1alpha1.RevisionMetadata, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeAppServiceClient) RevisionChartDetails(ctx context.Context, in *applicationpkg.RevisionMetadataQuery, opts ...grpc.CallOption) (*v1alpha1.ChartDetails, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeAppServiceClient) GetManifests(ctx context.Context, in *applicationpkg.ApplicationManifestQuery, opts ...grpc.CallOption) (*apiclient.ManifestResponse, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeAppServiceClient) GetManifestsWithFiles(ctx context.Context, opts ...grpc.CallOption) (applicationpkg.ApplicationService_GetManifestsWithFilesClient, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeAppServiceClient) Update(ctx context.Context, in *applicationpkg.ApplicationUpdateRequest, opts ...grpc.CallOption) (*v1alpha1.Application, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeAppServiceClient) UpdateSpec(ctx context.Context, in *applicationpkg.ApplicationUpdateSpecRequest, opts ...grpc.CallOption) (*v1alpha1.ApplicationSpec, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeAppServiceClient) Patch(ctx context.Context, in *applicationpkg.ApplicationPatchRequest, opts ...grpc.CallOption) (*v1alpha1.Application, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeAppServiceClient) Delete(ctx context.Context, in *applicationpkg.ApplicationDeleteRequest, opts ...grpc.CallOption) (*applicationpkg.ApplicationResponse, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeAppServiceClient) Sync(ctx context.Context, in *applicationpkg.ApplicationSyncRequest, opts ...grpc.CallOption) (*v1alpha1.Application, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeAppServiceClient) ManagedResources(ctx context.Context, in *applicationpkg.ResourcesQuery, opts ...grpc.CallOption) (*applicationpkg.ManagedResourcesResponse, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeAppServiceClient) ResourceTree(ctx context.Context, in *applicationpkg.ResourcesQuery, opts ...grpc.CallOption) (*v1alpha1.ApplicationTree, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeAppServiceClient) WatchResourceTree(ctx context.Context, in *applicationpkg.ResourcesQuery, opts ...grpc.CallOption) (applicationpkg.ApplicationService_WatchResourceTreeClient, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeAppServiceClient) Rollback(ctx context.Context, in *applicationpkg.ApplicationRollbackRequest, opts ...grpc.CallOption) (*v1alpha1.Application, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeAppServiceClient) TerminateOperation(ctx context.Context, in *applicationpkg.OperationTerminateRequest, opts ...grpc.CallOption) (*applicationpkg.OperationTerminateResponse, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeAppServiceClient) GetResource(ctx context.Context, in *applicationpkg.ApplicationResourceRequest, opts ...grpc.CallOption) (*applicationpkg.ApplicationResourceResponse, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeAppServiceClient) PatchResource(ctx context.Context, in *applicationpkg.ApplicationResourcePatchRequest, opts ...grpc.CallOption) (*applicationpkg.ApplicationResourceResponse, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeAppServiceClient) ListResourceActions(ctx context.Context, in *applicationpkg.ApplicationResourceRequest, opts ...grpc.CallOption) (*applicationpkg.ResourceActionsListResponse, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeAppServiceClient) RunResourceAction(ctx context.Context, in *applicationpkg.ResourceActionRunRequest, opts ...grpc.CallOption) (*applicationpkg.ApplicationResponse, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeAppServiceClient) DeleteResource(ctx context.Context, in *applicationpkg.ApplicationResourceDeleteRequest, opts ...grpc.CallOption) (*applicationpkg.ApplicationResponse, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeAppServiceClient) PodLogs(ctx context.Context, in *applicationpkg.ApplicationPodLogsQuery, opts ...grpc.CallOption) (applicationpkg.ApplicationService_PodLogsClient, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeAppServiceClient) ListLinks(ctx context.Context, in *applicationpkg.ListAppLinksRequest, opts ...grpc.CallOption) (*applicationpkg.LinksResponse, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeAppServiceClient) ListResourceLinks(ctx context.Context, in *applicationpkg.ApplicationResourceRequest, opts ...grpc.CallOption) (*applicationpkg.LinksResponse, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
type fakeAcdClient struct{}
|
||||
|
||||
func (c *fakeAcdClient) ClientOptions() argocdclient.ClientOptions {
|
||||
|
||||
@@ -114,13 +114,17 @@ func NewApplicationSetGetCommand(clientOpts *argocdclient.ClientOptions) *cobra.
|
||||
|
||||
// NewApplicationSetCreateCommand returns a new instance of an `argocd appset create` command
|
||||
func NewApplicationSetCreateCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
var upsert bool
|
||||
var output string
|
||||
var upsert, dryRun bool
|
||||
command := &cobra.Command{
|
||||
Use: "create",
|
||||
Short: "Create one or more ApplicationSets",
|
||||
Example: templates.Examples(`
|
||||
# Create ApplicationSets
|
||||
argocd appset create <filename or URL> (<filename or URL>...)
|
||||
|
||||
# Dry-run AppSet creation to see what applications would be managed
|
||||
argocd appset create --dry-run <filename or URL> -o json | jq -r '.status.resources[].name'
|
||||
`),
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
ctx := c.Context()
|
||||
@@ -157,10 +161,16 @@ func NewApplicationSetCreateCommand(clientOpts *argocdclient.ClientOptions) *cob
|
||||
appSetCreateRequest := applicationset.ApplicationSetCreateRequest{
|
||||
Applicationset: appset,
|
||||
Upsert: upsert,
|
||||
DryRun: dryRun,
|
||||
}
|
||||
created, err := appIf.Create(ctx, &appSetCreateRequest)
|
||||
errors.CheckError(err)
|
||||
|
||||
dryRunMsg := ""
|
||||
if dryRun {
|
||||
dryRunMsg = " (dry-run)"
|
||||
}
|
||||
|
||||
var action string
|
||||
if existing == nil {
|
||||
action = "created"
|
||||
@@ -170,11 +180,31 @@ func NewApplicationSetCreateCommand(clientOpts *argocdclient.ClientOptions) *cob
|
||||
action = "updated"
|
||||
}
|
||||
|
||||
fmt.Printf("ApplicationSet '%s' %s\n", created.ObjectMeta.Name, action)
|
||||
c.PrintErrf("ApplicationSet '%s' %s%s\n", created.ObjectMeta.Name, action, dryRunMsg)
|
||||
|
||||
switch output {
|
||||
case "yaml", "json":
|
||||
err := PrintResource(created, output)
|
||||
errors.CheckError(err)
|
||||
case "wide", "":
|
||||
printAppSetSummaryTable(created)
|
||||
|
||||
if len(created.Status.Conditions) > 0 {
|
||||
fmt.Println()
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
printAppSetConditions(w, created)
|
||||
_ = w.Flush()
|
||||
fmt.Println()
|
||||
}
|
||||
default:
|
||||
errors.CheckError(fmt.Errorf("unknown output format: %s", output))
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
command.Flags().BoolVar(&upsert, "upsert", false, "Allows to override ApplicationSet with the same name even if supplied ApplicationSet spec is different from existing spec")
|
||||
command.Flags().BoolVar(&dryRun, "dry-run", false, "Allows to evaluate the ApplicationSet template on the server to get a preview of the applications that would be created")
|
||||
command.Flags().StringVarP(&output, "output", "o", "wide", "Output format. One of: json|yaml|wide")
|
||||
return command
|
||||
}
|
||||
|
||||
@@ -189,7 +219,7 @@ func NewApplicationSetListCommand(clientOpts *argocdclient.ClientOptions) *cobra
|
||||
command := &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "List ApplicationSets",
|
||||
Example: templates.Examples(`
|
||||
Example: templates.Examples(`
|
||||
# List all ApplicationSets
|
||||
argocd appset list
|
||||
`),
|
||||
@@ -230,7 +260,7 @@ func NewApplicationSetDeleteCommand(clientOpts *argocdclient.ClientOptions) *cob
|
||||
command := &cobra.Command{
|
||||
Use: "delete",
|
||||
Short: "Delete one or more ApplicationSets",
|
||||
Example: templates.Examples(`
|
||||
Example: templates.Examples(`
|
||||
# Delete an applicationset
|
||||
argocd appset delete APPSETNAME (APPSETNAME...)
|
||||
`),
|
||||
|
||||
@@ -8,23 +8,23 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/cmd/argocd/commands/initialize"
|
||||
"github.com/argoproj/argo-cd/v2/common"
|
||||
|
||||
"github.com/alicebob/miniredis/v2"
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
"github.com/redis/go-redis/v9"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
cache2 "k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"k8s.io/utils/ptr"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/cmd/argocd/commands/initialize"
|
||||
"github.com/argoproj/argo-cd/v2/common"
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apiclient"
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
appclientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned"
|
||||
@@ -231,6 +231,17 @@ func MaybeStartLocalServer(ctx context.Context, clientOpts *apiclient.ClientOpti
|
||||
return fmt.Errorf("error creating kubernetes clientset: %w", err)
|
||||
}
|
||||
|
||||
dynamicClientset, err := dynamic.NewForConfig(restConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating kubernetes dynamic clientset: %w", err)
|
||||
}
|
||||
|
||||
controllerClientset, err := client.New(restConfig, client.Options{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating kubernetes controller clientset: %w", err)
|
||||
}
|
||||
controllerClientset = client.NewDryRunClient(controllerClientset)
|
||||
|
||||
namespace, _, err := clientConfig.Namespace()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting namespace: %w", err)
|
||||
@@ -241,20 +252,27 @@ func MaybeStartLocalServer(ctx context.Context, clientOpts *apiclient.ClientOpti
|
||||
return fmt.Errorf("error running miniredis: %w", err)
|
||||
}
|
||||
appstateCache := appstatecache.NewCache(cache.NewCache(&forwardCacheClient{namespace: namespace, context: ctxStr, compression: compression, redisHaProxyName: clientOpts.RedisHaProxyName, redisName: clientOpts.RedisName}), time.Hour)
|
||||
|
||||
redisOptions := &redis.Options{Addr: mr.Addr()}
|
||||
if err = common.SetOptionalRedisPasswordFromKubeConfig(ctx, kubeClientset, namespace, redisOptions); err != nil {
|
||||
log.Warnf("Failed to fetch & set redis password for namespace %s: %v", namespace, err)
|
||||
}
|
||||
srv := server.NewServer(ctx, server.ArgoCDServerOpts{
|
||||
EnableGZip: false,
|
||||
Namespace: namespace,
|
||||
ListenPort: *port,
|
||||
AppClientset: appClientset,
|
||||
DisableAuth: true,
|
||||
RedisClient: redis.NewClient(&redis.Options{Addr: mr.Addr()}),
|
||||
Cache: servercache.NewCache(appstateCache, 0, 0, 0),
|
||||
KubeClientset: kubeClientset,
|
||||
Insecure: true,
|
||||
ListenHost: *address,
|
||||
RepoClientset: &forwardRepoClientset{namespace: namespace, context: ctxStr, repoServerName: clientOpts.RepoServerName, kubeClientset: kubeClientset},
|
||||
EnableProxyExtension: false,
|
||||
})
|
||||
EnableGZip: false,
|
||||
Namespace: namespace,
|
||||
ListenPort: *port,
|
||||
AppClientset: appClientset,
|
||||
DisableAuth: true,
|
||||
RedisClient: redis.NewClient(redisOptions),
|
||||
Cache: servercache.NewCache(appstateCache, 0, 0, 0),
|
||||
KubeClientset: kubeClientset,
|
||||
DynamicClientset: dynamicClientset,
|
||||
KubeControllerClientset: controllerClientset,
|
||||
Insecure: true,
|
||||
ListenHost: *address,
|
||||
RepoClientset: &forwardRepoClientset{namespace: namespace, context: ctxStr, repoServerName: clientOpts.RepoServerName, kubeClientset: kubeClientset},
|
||||
EnableProxyExtension: false,
|
||||
}, server.ApplicationSetOpts{})
|
||||
srv.Init(ctx)
|
||||
|
||||
lns, err := srv.Listen()
|
||||
|
||||
@@ -37,12 +37,13 @@ import (
|
||||
// NewLoginCommand returns a new instance of `argocd login` command
|
||||
func NewLoginCommand(globalClientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
var (
|
||||
ctxName string
|
||||
username string
|
||||
password string
|
||||
sso bool
|
||||
ssoPort int
|
||||
skipTestTLS bool
|
||||
ctxName string
|
||||
username string
|
||||
password string
|
||||
sso bool
|
||||
ssoPort int
|
||||
skipTestTLS bool
|
||||
ssoLaunchBrowser bool
|
||||
)
|
||||
command := &cobra.Command{
|
||||
Use: "login SERVER",
|
||||
@@ -135,7 +136,7 @@ argocd login cd.argoproj.io --core`,
|
||||
errors.CheckError(err)
|
||||
oauth2conf, provider, err := acdClient.OIDCConfig(ctx, acdSet)
|
||||
errors.CheckError(err)
|
||||
tokenString, refreshToken = oauth2Login(ctx, ssoPort, acdSet.GetOIDCConfig(), oauth2conf, provider)
|
||||
tokenString, refreshToken = oauth2Login(ctx, ssoPort, acdSet.GetOIDCConfig(), oauth2conf, provider, ssoLaunchBrowser)
|
||||
}
|
||||
parser := jwt.NewParser(jwt.WithoutClaimsValidation())
|
||||
claims := jwt.MapClaims{}
|
||||
@@ -184,6 +185,7 @@ argocd login cd.argoproj.io --core`,
|
||||
command.Flags().IntVar(&ssoPort, "sso-port", DefaultSSOLocalPort, "Port to run local OAuth2 login application")
|
||||
command.Flags().
|
||||
BoolVar(&skipTestTLS, "skip-test-tls", false, "Skip testing whether the server is configured with TLS (this can help when the command hangs for no apparent reason)")
|
||||
command.Flags().BoolVar(&ssoLaunchBrowser, "sso-launch-browser", true, "Automatically launch the system default browser when performing SSO login")
|
||||
return command
|
||||
}
|
||||
|
||||
@@ -205,6 +207,7 @@ func oauth2Login(
|
||||
oidcSettings *settingspkg.OIDCConfig,
|
||||
oauth2conf *oauth2.Config,
|
||||
provider *oidc.Provider,
|
||||
ssoLaunchBrowser bool,
|
||||
) (string, string) {
|
||||
oauth2conf.RedirectURL = fmt.Sprintf("http://localhost:%d/auth/callback", port)
|
||||
oidcConf, err := oidcutil.ParseConfig(provider)
|
||||
@@ -304,8 +307,6 @@ func oauth2Login(
|
||||
http.HandleFunc("/auth/callback", callbackHandler)
|
||||
|
||||
// Redirect user to login & consent page to ask for permission for the scopes specified above.
|
||||
fmt.Printf("Opening browser for authentication\n")
|
||||
|
||||
var url string
|
||||
var oidcconfig oidcconfig.OIDCConfig
|
||||
grantType := oidcutil.InferGrantType(oidcConf)
|
||||
@@ -330,8 +331,7 @@ func oauth2Login(
|
||||
}
|
||||
fmt.Printf("Performing %s flow login: %s\n", grantType, url)
|
||||
time.Sleep(1 * time.Second)
|
||||
err = open.Start(url)
|
||||
errors.CheckError(err)
|
||||
ssoAuthFlow(url, ssoLaunchBrowser)
|
||||
go func() {
|
||||
log.Debugf("Listen: %s", srv.Addr)
|
||||
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
|
||||
@@ -363,3 +363,13 @@ func passwordLogin(ctx context.Context, acdClient argocdclient.Client, username,
|
||||
errors.CheckError(err)
|
||||
return createdSession.Token
|
||||
}
|
||||
|
||||
func ssoAuthFlow(url string, ssoLaunchBrowser bool) {
|
||||
if ssoLaunchBrowser {
|
||||
fmt.Printf("Opening system default browser for authentication\n")
|
||||
err := open.Start(url)
|
||||
errors.CheckError(err)
|
||||
} else {
|
||||
fmt.Printf("To authenticate, copy-and-paste the following URL into your preferred browser: %s\n", url)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,39 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
utils "github.com/argoproj/argo-cd/v2/util/io"
|
||||
|
||||
"github.com/golang-jwt/jwt/v4"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func captureStdout(callback func()) (string, error) {
|
||||
oldStdout := os.Stdout
|
||||
oldStderr := os.Stderr
|
||||
r, w, err := os.Pipe()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
os.Stdout = w
|
||||
defer func() {
|
||||
os.Stdout = oldStdout
|
||||
os.Stderr = oldStderr
|
||||
}()
|
||||
|
||||
callback()
|
||||
utils.Close(w)
|
||||
|
||||
data, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(data), err
|
||||
}
|
||||
|
||||
func Test_userDisplayName_email(t *testing.T) {
|
||||
claims := jwt.MapClaims{"iss": "qux", "sub": "foo", "email": "firstname.lastname@example.com", "groups": []string{"baz"}}
|
||||
actualName := userDisplayName(claims)
|
||||
@@ -27,3 +54,11 @@ func Test_userDisplayName_sub(t *testing.T) {
|
||||
expectedName := "foo"
|
||||
assert.Equal(t, expectedName, actualName)
|
||||
}
|
||||
|
||||
func Test_ssoAuthFlow_ssoLaunchBrowser_false(t *testing.T) {
|
||||
out, _ := captureStdout(func() {
|
||||
ssoAuthFlow("http://test-sso-browser-flow.com", false)
|
||||
})
|
||||
|
||||
assert.Contains(t, out, "To authenticate, copy-and-paste the following URL into your preferred browser: http://test-sso-browser-flow.com")
|
||||
}
|
||||
|
||||
@@ -921,6 +921,16 @@ func printProject(p *v1alpha1.AppProject, scopedRepositories []*v1alpha1.Reposit
|
||||
fmt.Printf(printProjFmtStr, "", p.Spec.SourceRepos[i])
|
||||
}
|
||||
|
||||
// Print source namespaces
|
||||
ns0 := "<none>"
|
||||
if len(p.Spec.SourceNamespaces) > 0 {
|
||||
ns0 = p.Spec.SourceNamespaces[0]
|
||||
}
|
||||
fmt.Printf(printProjFmtStr, "Source Namespaces:", ns0)
|
||||
for i := 1; i < len(p.Spec.SourceNamespaces); i++ {
|
||||
fmt.Printf(printProjFmtStr, "", p.Spec.SourceNamespaces[i])
|
||||
}
|
||||
|
||||
// Print scoped repositories
|
||||
scr0 := "<none>"
|
||||
if len(scopedRepositories) > 0 {
|
||||
|
||||
@@ -20,8 +20,9 @@ import (
|
||||
// NewReloginCommand returns a new instance of `argocd relogin` command
|
||||
func NewReloginCommand(globalClientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
var (
|
||||
password string
|
||||
ssoPort int
|
||||
password string
|
||||
ssoPort int
|
||||
ssoLaunchBrowser bool
|
||||
)
|
||||
command := &cobra.Command{
|
||||
Use: "relogin",
|
||||
@@ -72,7 +73,7 @@ func NewReloginCommand(globalClientOpts *argocdclient.ClientOptions) *cobra.Comm
|
||||
errors.CheckError(err)
|
||||
oauth2conf, provider, err := acdClient.OIDCConfig(ctx, acdSet)
|
||||
errors.CheckError(err)
|
||||
tokenString, refreshToken = oauth2Login(ctx, ssoPort, acdSet.GetOIDCConfig(), oauth2conf, provider)
|
||||
tokenString, refreshToken = oauth2Login(ctx, ssoPort, acdSet.GetOIDCConfig(), oauth2conf, provider, ssoLaunchBrowser)
|
||||
}
|
||||
|
||||
localCfg.UpsertUser(localconfig.User{
|
||||
@@ -99,5 +100,6 @@ argocd login cd.argoproj.io --core
|
||||
}
|
||||
command.Flags().StringVar(&password, "password", "", "The password of an account to authenticate")
|
||||
command.Flags().IntVar(&ssoPort, "sso-port", DefaultSSOLocalPort, "Port to run local OAuth2 login application")
|
||||
command.Flags().BoolVar(&ssoLaunchBrowser, "sso-launch-browser", true, "Automatically launch the default browser when performing SSO login")
|
||||
return command
|
||||
}
|
||||
|
||||
@@ -48,6 +48,9 @@ type AppOptions struct {
|
||||
helmVersion string
|
||||
helmPassCredentials bool
|
||||
helmSkipCrds bool
|
||||
helmNamespace string
|
||||
helmKubeVersion string
|
||||
helmApiVersions []string
|
||||
project string
|
||||
syncPolicy string
|
||||
syncOptions []string
|
||||
@@ -72,6 +75,8 @@ type AppOptions struct {
|
||||
kustomizeForceCommonLabels bool
|
||||
kustomizeForceCommonAnnotations bool
|
||||
kustomizeNamespace string
|
||||
kustomizeKubeVersion string
|
||||
kustomizeApiVersions []string
|
||||
pluginEnvs []string
|
||||
Validate bool
|
||||
directoryExclude string
|
||||
@@ -104,6 +109,9 @@ func AddAppFlags(command *cobra.Command, opts *AppOptions) {
|
||||
command.Flags().StringArrayVar(&opts.helmSetStrings, "helm-set-string", []string{}, "Helm set STRING values on the command line (can be repeated to set several values: --helm-set-string key1=val1 --helm-set-string key2=val2)")
|
||||
command.Flags().StringArrayVar(&opts.helmSetFiles, "helm-set-file", []string{}, "Helm set values from respective files specified via the command line (can be repeated to set several values: --helm-set-file key1=path1 --helm-set-file key2=path2)")
|
||||
command.Flags().BoolVar(&opts.helmSkipCrds, "helm-skip-crds", false, "Skip helm crd installation step")
|
||||
command.Flags().StringVar(&opts.helmNamespace, "helm-namespace", "", "Helm namespace to use when running helm template. If not set, use app.spec.destination.namespace")
|
||||
command.Flags().StringVar(&opts.helmKubeVersion, "helm-kube-version", "", "Helm kube-version to use when running helm template. If not set, use the kube version from the destination cluster")
|
||||
command.Flags().StringArrayVar(&opts.helmApiVersions, "helm-api-versions", []string{}, "Helm api-versions (in format [group/]version/kind) to use when running helm template (Can be repeated to set several values: --helm-api-versions traefik.io/v1alpha1/TLSOption --helm-api-versions v1/Service). If not set, use the api-versions from the destination cluster")
|
||||
command.Flags().StringVar(&opts.project, "project", "", "Application project name")
|
||||
command.Flags().StringVar(&opts.syncPolicy, "sync-policy", "", "Set the sync policy (one of: manual (aliases of manual: none), automated (aliases of automated: auto, automatic))")
|
||||
command.Flags().StringArrayVar(&opts.syncOptions, "sync-option", []string{}, "Add or remove a sync option, e.g add `Prune=false`. Remove using `!` prefix, e.g. `!Prune=false`")
|
||||
@@ -130,6 +138,8 @@ func AddAppFlags(command *cobra.Command, opts *AppOptions) {
|
||||
command.Flags().BoolVar(&opts.kustomizeForceCommonLabels, "kustomize-force-common-label", false, "Force common labels in Kustomize")
|
||||
command.Flags().BoolVar(&opts.kustomizeForceCommonAnnotations, "kustomize-force-common-annotation", false, "Force common annotations in Kustomize")
|
||||
command.Flags().StringVar(&opts.kustomizeNamespace, "kustomize-namespace", "", "Kustomize namespace")
|
||||
command.Flags().StringVar(&opts.kustomizeKubeVersion, "kustomize-kube-version", "", "kube-version to use when running helm template. If not set, use the kube version from the destination cluster. Only applicable when Helm is enabled for Kustomize builds")
|
||||
command.Flags().StringArrayVar(&opts.kustomizeApiVersions, "kustomize-api-versions", nil, "api-versions (in format [group/]version/kind) to use when running helm template (Can be repeated to set several values: --helm-api-versions traefik.io/v1alpha1/TLSOption --helm-api-versions v1/Service). If not set, use the api-versions from the destination cluster. Only applicable when Helm is enabled for Kustomize builds")
|
||||
command.Flags().StringVar(&opts.directoryExclude, "directory-exclude", "", "Set glob expression used to exclude files from application source path")
|
||||
command.Flags().StringVar(&opts.directoryInclude, "directory-include", "", "Set glob expression used to include files from application source path")
|
||||
command.Flags().Int64Var(&opts.retryLimit, "sync-retry-limit", 0, "Max number of allowed sync retries")
|
||||
@@ -266,6 +276,8 @@ type kustomizeOpts struct {
|
||||
forceCommonLabels bool
|
||||
forceCommonAnnotations bool
|
||||
namespace string
|
||||
kubeVersion string
|
||||
apiVersions []string
|
||||
}
|
||||
|
||||
func setKustomizeOpt(src *argoappv1.ApplicationSource, opts kustomizeOpts) {
|
||||
@@ -284,6 +296,12 @@ func setKustomizeOpt(src *argoappv1.ApplicationSource, opts kustomizeOpts) {
|
||||
if opts.namespace != "" {
|
||||
src.Kustomize.Namespace = opts.namespace
|
||||
}
|
||||
if opts.kubeVersion != "" {
|
||||
src.Kustomize.KubeVersion = opts.kubeVersion
|
||||
}
|
||||
if len(opts.apiVersions) > 0 {
|
||||
src.Kustomize.APIVersions = opts.apiVersions
|
||||
}
|
||||
if opts.commonLabels != nil {
|
||||
src.Kustomize.CommonLabels = opts.commonLabels
|
||||
}
|
||||
@@ -340,6 +358,9 @@ type helmOpts struct {
|
||||
helmSetFiles []string
|
||||
passCredentials bool
|
||||
skipCrds bool
|
||||
namespace string
|
||||
kubeVersion string
|
||||
apiVersions []string
|
||||
}
|
||||
|
||||
func setHelmOpt(src *argoappv1.ApplicationSource, opts helmOpts) {
|
||||
@@ -370,6 +391,15 @@ func setHelmOpt(src *argoappv1.ApplicationSource, opts helmOpts) {
|
||||
if opts.skipCrds {
|
||||
src.Helm.SkipCrds = opts.skipCrds
|
||||
}
|
||||
if opts.namespace != "" {
|
||||
src.Helm.Namespace = opts.namespace
|
||||
}
|
||||
if opts.kubeVersion != "" {
|
||||
src.Helm.KubeVersion = opts.kubeVersion
|
||||
}
|
||||
if len(opts.apiVersions) > 0 {
|
||||
src.Helm.APIVersions = opts.apiVersions
|
||||
}
|
||||
for _, text := range opts.helmSets {
|
||||
p, err := argoappv1.NewHelmParameter(text, false)
|
||||
if err != nil {
|
||||
@@ -628,6 +658,12 @@ func ConstructSource(source *argoappv1.ApplicationSource, appOpts AppOptions, fl
|
||||
setHelmOpt(source, helmOpts{helmSetFiles: appOpts.helmSetFiles})
|
||||
case "helm-skip-crds":
|
||||
setHelmOpt(source, helmOpts{skipCrds: appOpts.helmSkipCrds})
|
||||
case "helm-namespace":
|
||||
setHelmOpt(source, helmOpts{namespace: appOpts.helmNamespace})
|
||||
case "helm-kube-version":
|
||||
setHelmOpt(source, helmOpts{kubeVersion: appOpts.helmKubeVersion})
|
||||
case "helm-api-versions":
|
||||
setHelmOpt(source, helmOpts{apiVersions: appOpts.helmApiVersions})
|
||||
case "directory-recurse":
|
||||
if source.Directory != nil {
|
||||
source.Directory.Recurse = appOpts.directoryRecurse
|
||||
@@ -660,6 +696,10 @@ func ConstructSource(source *argoappv1.ApplicationSource, appOpts AppOptions, fl
|
||||
setKustomizeOpt(source, kustomizeOpts{version: appOpts.kustomizeVersion})
|
||||
case "kustomize-namespace":
|
||||
setKustomizeOpt(source, kustomizeOpts{namespace: appOpts.kustomizeNamespace})
|
||||
case "kustomize-kube-version":
|
||||
setKustomizeOpt(source, kustomizeOpts{kubeVersion: appOpts.kustomizeKubeVersion})
|
||||
case "kustomize-api-versions":
|
||||
setKustomizeOpt(source, kustomizeOpts{apiVersions: appOpts.kustomizeApiVersions})
|
||||
case "kustomize-common-label":
|
||||
parsedLabels, err := label.Parse(appOpts.kustomizeCommonLabels)
|
||||
errors.CheckError(err)
|
||||
|
||||
@@ -65,6 +65,21 @@ func Test_setHelmOpt(t *testing.T) {
|
||||
setHelmOpt(&src, helmOpts{skipCrds: true})
|
||||
assert.True(t, src.Helm.SkipCrds)
|
||||
})
|
||||
t.Run("HelmNamespace", func(t *testing.T) {
|
||||
src := v1alpha1.ApplicationSource{}
|
||||
setHelmOpt(&src, helmOpts{namespace: "custom-namespace"})
|
||||
assert.Equal(t, "custom-namespace", src.Helm.Namespace)
|
||||
})
|
||||
t.Run("HelmKubeVersion", func(t *testing.T) {
|
||||
src := v1alpha1.ApplicationSource{}
|
||||
setHelmOpt(&src, helmOpts{kubeVersion: "v1.16.0"})
|
||||
assert.Equal(t, "v1.16.0", src.Helm.KubeVersion)
|
||||
})
|
||||
t.Run("HelmApiVersions", func(t *testing.T) {
|
||||
src := v1alpha1.ApplicationSource{}
|
||||
setHelmOpt(&src, helmOpts{apiVersions: []string{"v1", "v2"}})
|
||||
assert.Equal(t, []string{"v1", "v2"}, src.Helm.APIVersions)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_setKustomizeOpt(t *testing.T) {
|
||||
@@ -114,6 +129,16 @@ func Test_setKustomizeOpt(t *testing.T) {
|
||||
setKustomizeOpt(&src, kustomizeOpts{namespace: "custom-namespace"})
|
||||
assert.Equal(t, &v1alpha1.ApplicationSourceKustomize{Namespace: "custom-namespace"}, src.Kustomize)
|
||||
})
|
||||
t.Run("KubeVersion", func(t *testing.T) {
|
||||
src := v1alpha1.ApplicationSource{}
|
||||
setKustomizeOpt(&src, kustomizeOpts{kubeVersion: "999.999.999"})
|
||||
assert.Equal(t, &v1alpha1.ApplicationSourceKustomize{KubeVersion: "999.999.999"}, src.Kustomize)
|
||||
})
|
||||
t.Run("ApiVersions", func(t *testing.T) {
|
||||
src := v1alpha1.ApplicationSource{}
|
||||
setKustomizeOpt(&src, kustomizeOpts{apiVersions: []string{"v1", "v2"}})
|
||||
assert.Equal(t, &v1alpha1.ApplicationSourceKustomize{APIVersions: []string{"v1", "v2"}}, src.Kustomize)
|
||||
})
|
||||
t.Run("Common labels", func(t *testing.T) {
|
||||
src := v1alpha1.ApplicationSource{}
|
||||
setKustomizeOpt(&src, kustomizeOpts{commonLabels: map[string]string{"foo1": "bar1", "foo2": "bar2"}})
|
||||
@@ -233,6 +258,32 @@ func Test_setAppSpecOptions(t *testing.T) {
|
||||
require.NoError(t, f.SetFlag("kustomize-replica", "my-statefulset=4"))
|
||||
assert.Equal(t, v1alpha1.KustomizeReplicas{{Name: "my-deployment", Count: intstr.FromInt(2)}, {Name: "my-statefulset", Count: intstr.FromInt(4)}}, f.spec.Source.Kustomize.Replicas)
|
||||
})
|
||||
t.Run("Kustomize Namespace", func(t *testing.T) {
|
||||
require.NoError(t, f.SetFlag("kustomize-namespace", "override-namespace"))
|
||||
assert.Equal(t, "override-namespace", f.spec.Source.Kustomize.Namespace)
|
||||
})
|
||||
t.Run("Kustomize Kube Version", func(t *testing.T) {
|
||||
require.NoError(t, f.SetFlag("kustomize-kube-version", "999.999.999"))
|
||||
assert.Equal(t, "999.999.999", f.spec.Source.Kustomize.KubeVersion)
|
||||
})
|
||||
t.Run("Kustomize API Versions", func(t *testing.T) {
|
||||
require.NoError(t, f.SetFlag("kustomize-api-versions", "v1"))
|
||||
require.NoError(t, f.SetFlag("kustomize-api-versions", "v2"))
|
||||
assert.Equal(t, []string{"v1", "v2"}, f.spec.Source.Kustomize.APIVersions)
|
||||
})
|
||||
t.Run("Helm Namespace", func(t *testing.T) {
|
||||
require.NoError(t, f.SetFlag("helm-namespace", "override-namespace"))
|
||||
assert.Equal(t, "override-namespace", f.spec.Source.Helm.Namespace)
|
||||
})
|
||||
t.Run("Helm Kube Version", func(t *testing.T) {
|
||||
require.NoError(t, f.SetFlag("kustomize-kube-version", "999.999.999"))
|
||||
assert.Equal(t, "999.999.999", f.spec.Source.Kustomize.KubeVersion)
|
||||
})
|
||||
t.Run("Helm API Versions", func(t *testing.T) {
|
||||
require.NoError(t, f.SetFlag("helm-api-versions", "v1"))
|
||||
require.NoError(t, f.SetFlag("helm-api-versions", "v2"))
|
||||
assert.Equal(t, []string{"v1", "v2"}, f.spec.Source.Helm.APIVersions)
|
||||
})
|
||||
}
|
||||
|
||||
func newMultiSourceAppOptionsFixture() *appOptionsFixture {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -53,8 +52,8 @@ func Test_newCluster(t *testing.T) {
|
||||
&v1alpha1.AWSAuthConfig{},
|
||||
&v1alpha1.ExecProviderConfig{}, labels, nil)
|
||||
|
||||
assert.True(t, strings.Contains(string(clusterWithFiles.Config.CertData), "test-cert-data"))
|
||||
assert.True(t, strings.Contains(string(clusterWithFiles.Config.KeyData), "test-key-data"))
|
||||
assert.Contains(t, string(clusterWithFiles.Config.CertData), "test-cert-data")
|
||||
assert.Contains(t, string(clusterWithFiles.Config.KeyData), "test-key-data")
|
||||
assert.Equal(t, "", clusterWithFiles.Config.BearerToken)
|
||||
assert.Equal(t, labels, clusterWithFiles.Labels)
|
||||
assert.Nil(t, clusterWithFiles.Annotations)
|
||||
|
||||
295
cmpserver/apiclient/plugin.pb.go
generated
295
cmpserver/apiclient/plugin.pb.go
generated
@@ -11,6 +11,7 @@ import (
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
emptypb "google.golang.org/protobuf/types/known/emptypb"
|
||||
io "io"
|
||||
math "math"
|
||||
math_bits "math/bits"
|
||||
@@ -467,6 +468,54 @@ func (m *File) GetChunk() []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckPluginConfigurationResponse contains a list of plugin configuration flags.
|
||||
type CheckPluginConfigurationResponse struct {
|
||||
IsDiscoveryConfigured bool `protobuf:"varint,1,opt,name=isDiscoveryConfigured,proto3" json:"isDiscoveryConfigured,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *CheckPluginConfigurationResponse) Reset() { *m = CheckPluginConfigurationResponse{} }
|
||||
func (m *CheckPluginConfigurationResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*CheckPluginConfigurationResponse) ProtoMessage() {}
|
||||
func (*CheckPluginConfigurationResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_b21875a7079a06ed, []int{7}
|
||||
}
|
||||
func (m *CheckPluginConfigurationResponse) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *CheckPluginConfigurationResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_CheckPluginConfigurationResponse.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalToSizedBuffer(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (m *CheckPluginConfigurationResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_CheckPluginConfigurationResponse.Merge(m, src)
|
||||
}
|
||||
func (m *CheckPluginConfigurationResponse) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *CheckPluginConfigurationResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_CheckPluginConfigurationResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_CheckPluginConfigurationResponse proto.InternalMessageInfo
|
||||
|
||||
func (m *CheckPluginConfigurationResponse) GetIsDiscoveryConfigured() bool {
|
||||
if m != nil {
|
||||
return m.IsDiscoveryConfigured
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*AppStreamRequest)(nil), "plugin.AppStreamRequest")
|
||||
proto.RegisterType((*ManifestRequestMetadata)(nil), "plugin.ManifestRequestMetadata")
|
||||
@@ -475,48 +524,54 @@ func init() {
|
||||
proto.RegisterType((*RepositoryResponse)(nil), "plugin.RepositoryResponse")
|
||||
proto.RegisterType((*ParametersAnnouncementResponse)(nil), "plugin.ParametersAnnouncementResponse")
|
||||
proto.RegisterType((*File)(nil), "plugin.File")
|
||||
proto.RegisterType((*CheckPluginConfigurationResponse)(nil), "plugin.CheckPluginConfigurationResponse")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("cmpserver/plugin/plugin.proto", fileDescriptor_b21875a7079a06ed) }
|
||||
|
||||
var fileDescriptor_b21875a7079a06ed = []byte{
|
||||
// 576 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x94, 0xdd, 0x6e, 0x12, 0x4f,
|
||||
0x14, 0xc0, 0xbb, 0x85, 0xb6, 0x70, 0x68, 0xf2, 0x27, 0x93, 0x7f, 0x74, 0x25, 0x2d, 0xe2, 0x5e,
|
||||
0x18, 0x6e, 0x84, 0x04, 0xbd, 0x35, 0xb1, 0x55, 0x6c, 0xa3, 0xc1, 0x90, 0xa9, 0x37, 0x7a, 0x37,
|
||||
0x1d, 0x0e, 0x30, 0x76, 0x77, 0x66, 0x9c, 0x99, 0xdd, 0x04, 0xbd, 0xf1, 0x3d, 0x7c, 0x00, 0x5f,
|
||||
0xc5, 0x4b, 0x1f, 0xc1, 0xf4, 0x49, 0x0c, 0xb3, 0xbb, 0x40, 0x6c, 0x8b, 0x57, 0x7b, 0x3e, 0x7f,
|
||||
0x7b, 0xbe, 0x32, 0x70, 0xcc, 0x13, 0x6d, 0xd1, 0x64, 0x68, 0xfa, 0x3a, 0x4e, 0x67, 0x42, 0x16,
|
||||
0x9f, 0x9e, 0x36, 0xca, 0x29, 0xb2, 0x9f, 0x6b, 0xad, 0xe1, 0x4c, 0xb8, 0x79, 0x7a, 0xd9, 0xe3,
|
||||
0x2a, 0xe9, 0x33, 0x33, 0x53, 0xda, 0xa8, 0x4f, 0x5e, 0x78, 0xc2, 0x27, 0xfd, 0x6c, 0xd0, 0x37,
|
||||
0xa8, 0x55, 0x81, 0xf1, 0xa2, 0x70, 0xca, 0x2c, 0x36, 0xc4, 0x1c, 0x17, 0x7d, 0x0b, 0xa0, 0x79,
|
||||
0xa2, 0xf5, 0x85, 0x33, 0xc8, 0x12, 0x8a, 0x9f, 0x53, 0xb4, 0x8e, 0x3c, 0x87, 0x5a, 0x82, 0x8e,
|
||||
0x4d, 0x98, 0x63, 0x61, 0xd0, 0x09, 0xba, 0x8d, 0xc1, 0xc3, 0x5e, 0x51, 0xc4, 0x88, 0x49, 0x31,
|
||||
0x45, 0xeb, 0x8a, 0xd0, 0x51, 0x11, 0x76, 0xbe, 0x43, 0x57, 0x29, 0x24, 0x82, 0xea, 0x54, 0xc4,
|
||||
0x18, 0xee, 0xfa, 0xd4, 0xc3, 0x32, 0xf5, 0xb5, 0x88, 0xf1, 0x7c, 0x87, 0x7a, 0xdf, 0x69, 0x1d,
|
||||
0x0e, 0x4c, 0x8e, 0x88, 0x7e, 0x04, 0x70, 0xff, 0x0e, 0x2c, 0x09, 0xe1, 0x80, 0x69, 0xfd, 0x8e,
|
||||
0x25, 0xe8, 0x0b, 0xa9, 0xd3, 0x52, 0x25, 0x6d, 0x00, 0xa6, 0x35, 0xc5, 0x78, 0xcc, 0xdc, 0xdc,
|
||||
0xff, 0xaa, 0x4e, 0x37, 0x2c, 0xa4, 0x05, 0x35, 0x3e, 0x47, 0x7e, 0x65, 0xd3, 0x24, 0xac, 0x78,
|
||||
0xef, 0x4a, 0x27, 0x04, 0xaa, 0x56, 0x7c, 0xc1, 0xb0, 0xda, 0x09, 0xba, 0x15, 0xea, 0x65, 0x12,
|
||||
0x41, 0x05, 0x65, 0x16, 0xee, 0x75, 0x2a, 0xdd, 0xc6, 0xa0, 0x59, 0xd6, 0x3c, 0x94, 0xd9, 0x50,
|
||||
0x3a, 0xb3, 0xa0, 0x4b, 0x67, 0xf4, 0x0c, 0x6a, 0xa5, 0x61, 0xc9, 0x90, 0xeb, 0xb2, 0xbc, 0x4c,
|
||||
0xfe, 0x87, 0xbd, 0x8c, 0xc5, 0x29, 0x16, 0xe5, 0xe4, 0x4a, 0x34, 0x86, 0xe6, 0xba, 0x3d, 0xab,
|
||||
0x95, 0xb4, 0x48, 0x8e, 0xa0, 0x9e, 0x14, 0x36, 0x1b, 0x06, 0x9d, 0x4a, 0xb7, 0x4e, 0xd7, 0x86,
|
||||
0x65, 0x6f, 0x56, 0xa5, 0x86, 0xe3, 0xfb, 0x85, 0x2e, 0x61, 0x1b, 0x96, 0x68, 0x0a, 0x84, 0xae,
|
||||
0x16, 0xb9, 0x62, 0x76, 0xa0, 0x21, 0xec, 0x45, 0xaa, 0xb5, 0x32, 0x0e, 0x27, 0xbe, 0xb0, 0x1a,
|
||||
0xdd, 0x34, 0x91, 0x1e, 0x10, 0x61, 0x5f, 0x09, 0xcb, 0x55, 0x86, 0x66, 0x31, 0x94, 0xec, 0x32,
|
||||
0xc6, 0x89, 0xe7, 0xd7, 0xe8, 0x2d, 0x9e, 0xe8, 0x2b, 0xb4, 0xc7, 0xcc, 0xb0, 0x04, 0x1d, 0x1a,
|
||||
0x7b, 0x22, 0xa5, 0x4a, 0x25, 0xc7, 0x04, 0xe5, 0xba, 0x8f, 0x0f, 0x70, 0x4f, 0x97, 0x11, 0x9b,
|
||||
0x01, 0x79, 0x53, 0x8d, 0xc1, 0xa3, 0xde, 0xc6, 0xc5, 0x8d, 0x6f, 0x8b, 0xa4, 0x77, 0x00, 0xa2,
|
||||
0x23, 0xa8, 0x2e, 0x2f, 0x66, 0x39, 0x54, 0x3e, 0x4f, 0xe5, 0x95, 0x6f, 0xe8, 0x90, 0xe6, 0xca,
|
||||
0xe0, 0xfb, 0x2e, 0x1c, 0xbf, 0x54, 0x72, 0x2a, 0x66, 0x23, 0x26, 0xd9, 0xcc, 0xe7, 0x8c, 0xfd,
|
||||
0xce, 0x2e, 0xd0, 0x64, 0x82, 0x23, 0x79, 0x03, 0xcd, 0x33, 0x94, 0x68, 0x98, 0xc3, 0x72, 0xfc,
|
||||
0x24, 0x2c, 0xf7, 0xfa, 0xf7, 0xc9, 0xb7, 0xc2, 0x9b, 0x07, 0x9e, 0xb7, 0x18, 0xed, 0x74, 0x03,
|
||||
0xf2, 0x16, 0xfe, 0x1b, 0x31, 0xc7, 0xe7, 0xeb, 0xa9, 0x6f, 0x41, 0xb5, 0x4a, 0xcf, 0xcd, 0x1d,
|
||||
0x79, 0x18, 0x83, 0x07, 0x67, 0xe8, 0x6e, 0x1f, 0xec, 0x16, 0xec, 0xe3, 0xd2, 0xb3, 0x7d, 0x25,
|
||||
0xcb, 0x5f, 0x9c, 0xbe, 0xf8, 0x79, 0xdd, 0x0e, 0x7e, 0x5d, 0xb7, 0x83, 0xdf, 0xd7, 0xed, 0xe0,
|
||||
0xe3, 0xe0, 0x1f, 0x4f, 0xc5, 0xfa, 0xc1, 0x61, 0x5a, 0xf0, 0x58, 0xa0, 0x74, 0x97, 0xfb, 0xfe,
|
||||
0x79, 0x78, 0xfa, 0x27, 0x00, 0x00, 0xff, 0xff, 0x23, 0x88, 0x8e, 0xd3, 0x8e, 0x04, 0x00, 0x00,
|
||||
// 650 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x54, 0xc1, 0x6e, 0xd3, 0x4c,
|
||||
0x10, 0x8e, 0x9b, 0xb4, 0x4d, 0x26, 0x95, 0xfe, 0x68, 0xf5, 0x53, 0x4c, 0x68, 0x43, 0xf0, 0x01,
|
||||
0xe5, 0x82, 0x23, 0x85, 0x5e, 0x91, 0x68, 0x4b, 0x68, 0x05, 0x0a, 0x8a, 0xb6, 0x1c, 0x80, 0x03,
|
||||
0xd2, 0xc6, 0x99, 0x24, 0x4b, 0xed, 0xdd, 0x65, 0xbd, 0x8e, 0x14, 0xb8, 0xf0, 0x36, 0xbc, 0x0a,
|
||||
0x47, 0x1e, 0x01, 0xf5, 0x35, 0xb8, 0x20, 0xaf, 0xed, 0x24, 0xa2, 0x69, 0x7b, 0xf2, 0xcc, 0x7c,
|
||||
0xb3, 0xdf, 0x7e, 0xb3, 0x33, 0x63, 0x38, 0x0c, 0x22, 0x15, 0xa3, 0x9e, 0xa3, 0xee, 0xaa, 0x30,
|
||||
0x99, 0x72, 0x91, 0x7f, 0x7c, 0xa5, 0xa5, 0x91, 0x64, 0x27, 0xf3, 0x9a, 0xfd, 0x29, 0x37, 0xb3,
|
||||
0x64, 0xe4, 0x07, 0x32, 0xea, 0x32, 0x3d, 0x95, 0x4a, 0xcb, 0xcf, 0xd6, 0x78, 0x1a, 0x8c, 0xbb,
|
||||
0xf3, 0x5e, 0x57, 0xa3, 0x92, 0x39, 0x8d, 0x35, 0xb9, 0x91, 0x7a, 0xb1, 0x66, 0x66, 0x74, 0xcd,
|
||||
0x87, 0x53, 0x29, 0xa7, 0x21, 0x76, 0xad, 0x37, 0x4a, 0x26, 0x5d, 0x8c, 0x94, 0xc9, 0x41, 0xef,
|
||||
0xbb, 0x03, 0x8d, 0x63, 0xa5, 0x2e, 0x8c, 0x46, 0x16, 0x51, 0xfc, 0x92, 0x60, 0x6c, 0xc8, 0x73,
|
||||
0xa8, 0x46, 0x68, 0xd8, 0x98, 0x19, 0xe6, 0x3a, 0x6d, 0xa7, 0x53, 0xef, 0x3d, 0xf2, 0x73, 0x85,
|
||||
0x03, 0x26, 0xf8, 0x04, 0x63, 0x93, 0xa7, 0x0e, 0xf2, 0xb4, 0xf3, 0x12, 0x5d, 0x1e, 0x21, 0x1e,
|
||||
0x54, 0x26, 0x3c, 0x44, 0x77, 0xcb, 0x1e, 0xdd, 0x2b, 0x8e, 0xbe, 0xe2, 0x21, 0x9e, 0x97, 0xa8,
|
||||
0xc5, 0x4e, 0x6a, 0xb0, 0xab, 0x33, 0x0a, 0xef, 0x87, 0x03, 0xf7, 0x6f, 0xa0, 0x25, 0x2e, 0xec,
|
||||
0x32, 0xa5, 0xde, 0xb2, 0x08, 0xad, 0x90, 0x1a, 0x2d, 0x5c, 0xd2, 0x02, 0x60, 0x4a, 0x51, 0x0c,
|
||||
0x87, 0xcc, 0xcc, 0xec, 0x55, 0x35, 0xba, 0x16, 0x21, 0x4d, 0xa8, 0x06, 0x33, 0x0c, 0x2e, 0xe3,
|
||||
0x24, 0x72, 0xcb, 0x16, 0x5d, 0xfa, 0x84, 0x40, 0x25, 0xe6, 0x5f, 0xd1, 0xad, 0xb4, 0x9d, 0x4e,
|
||||
0x99, 0x5a, 0x9b, 0x78, 0x50, 0x46, 0x31, 0x77, 0xb7, 0xdb, 0xe5, 0x4e, 0xbd, 0xd7, 0x28, 0x34,
|
||||
0xf7, 0xc5, 0xbc, 0x2f, 0x8c, 0x5e, 0xd0, 0x14, 0xf4, 0x8e, 0xa0, 0x5a, 0x04, 0x52, 0x0e, 0xb1,
|
||||
0x92, 0x65, 0x6d, 0xf2, 0x3f, 0x6c, 0xcf, 0x59, 0x98, 0x60, 0x2e, 0x27, 0x73, 0xbc, 0x21, 0x34,
|
||||
0x56, 0xe5, 0xc5, 0x4a, 0x8a, 0x18, 0xc9, 0x01, 0xd4, 0xa2, 0x3c, 0x16, 0xbb, 0x4e, 0xbb, 0xdc,
|
||||
0xa9, 0xd1, 0x55, 0x20, 0xad, 0x2d, 0x96, 0x89, 0x0e, 0xf0, 0xdd, 0x42, 0x15, 0x64, 0x6b, 0x11,
|
||||
0x6f, 0x02, 0x84, 0x2e, 0xbb, 0xbc, 0xe4, 0x6c, 0x43, 0x9d, 0xc7, 0x17, 0x89, 0x52, 0x52, 0x1b,
|
||||
0x1c, 0x5b, 0x61, 0x55, 0xba, 0x1e, 0x22, 0x3e, 0x10, 0x1e, 0xbf, 0xe4, 0x71, 0x20, 0xe7, 0xa8,
|
||||
0x17, 0x7d, 0xc1, 0x46, 0x21, 0x8e, 0x2d, 0x7f, 0x95, 0x6e, 0x40, 0xbc, 0x6f, 0xd0, 0x1a, 0x32,
|
||||
0xcd, 0x22, 0x34, 0xa8, 0xe3, 0x63, 0x21, 0x64, 0x22, 0x02, 0x8c, 0x50, 0xac, 0xea, 0xf8, 0x00,
|
||||
0xfb, 0xaa, 0xc8, 0x58, 0x4f, 0xc8, 0x8a, 0xaa, 0xf7, 0x1e, 0xfb, 0x6b, 0xe3, 0x38, 0xdc, 0x94,
|
||||
0x49, 0x6f, 0x20, 0xf0, 0x0e, 0xa0, 0x92, 0x4e, 0x4c, 0xfa, 0xa8, 0xc1, 0x2c, 0x11, 0x97, 0xb6,
|
||||
0xa0, 0x3d, 0x9a, 0x39, 0xde, 0x7b, 0x68, 0x9f, 0xa6, 0xed, 0x1c, 0xda, 0x3e, 0x9d, 0x4a, 0x31,
|
||||
0xe1, 0xd3, 0x44, 0x33, 0xc3, 0xa5, 0x58, 0x8a, 0x3b, 0x82, 0x7b, 0x6b, 0x45, 0x15, 0x39, 0xcb,
|
||||
0xa7, 0xd9, 0x0c, 0xf6, 0xfe, 0x6c, 0xc1, 0x61, 0xe6, 0x0e, 0x98, 0x60, 0x53, 0xab, 0x26, 0xbb,
|
||||
0xe5, 0x02, 0xf5, 0x9c, 0x07, 0x48, 0x5e, 0x43, 0xe3, 0x0c, 0x05, 0x6a, 0x66, 0xb0, 0x68, 0x2c,
|
||||
0x71, 0x8b, 0x89, 0xf9, 0x77, 0x99, 0x9a, 0xee, 0xf5, 0xd5, 0xc9, 0xf4, 0x79, 0xa5, 0x8e, 0x43,
|
||||
0x3e, 0x81, 0x7b, 0x53, 0x1d, 0x64, 0xdf, 0xcf, 0x36, 0xd7, 0x2f, 0x36, 0xd7, 0xef, 0xa7, 0x9b,
|
||||
0xdb, 0xec, 0x14, 0x8c, 0x77, 0xbd, 0x80, 0x57, 0x22, 0x6f, 0xe0, 0xbf, 0x01, 0x33, 0xc1, 0x6c,
|
||||
0x35, 0x2f, 0xb7, 0x48, 0x6d, 0x16, 0xc8, 0xf5, 0xe9, 0xb2, 0x62, 0x19, 0x3c, 0x38, 0x43, 0xb3,
|
||||
0x79, 0x24, 0x6e, 0xa1, 0x7d, 0x52, 0x20, 0xb7, 0x0f, 0x53, 0x7a, 0xc5, 0xc9, 0x8b, 0x9f, 0x57,
|
||||
0x2d, 0xe7, 0xd7, 0x55, 0xcb, 0xf9, 0x7d, 0xd5, 0x72, 0x3e, 0xf6, 0xee, 0xf8, 0x03, 0xae, 0xfe,
|
||||
0xa3, 0x4c, 0xf1, 0x20, 0xe4, 0x28, 0xcc, 0x68, 0xc7, 0xbe, 0xd6, 0xb3, 0xbf, 0x01, 0x00, 0x00,
|
||||
0xff, 0xff, 0xb5, 0x6b, 0xca, 0xa6, 0x65, 0x05, 0x00, 0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
@@ -534,6 +589,9 @@ type ConfigManagementPluginServiceClient interface {
|
||||
// GenerateManifests receive a stream containing a tgz archive with all required files necessary
|
||||
// to generate manifests
|
||||
GenerateManifest(ctx context.Context, opts ...grpc.CallOption) (ConfigManagementPluginService_GenerateManifestClient, error)
|
||||
// CheckPluginConfiguration is a pre-flight request to check the plugin configuration
|
||||
// without sending the whole repo.
|
||||
CheckPluginConfiguration(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*CheckPluginConfigurationResponse, error)
|
||||
// MatchRepository returns whether or not the given application is supported by the plugin
|
||||
MatchRepository(ctx context.Context, opts ...grpc.CallOption) (ConfigManagementPluginService_MatchRepositoryClient, error)
|
||||
// GetParametersAnnouncement gets a list of parameter announcements for the given app
|
||||
@@ -582,6 +640,15 @@ func (x *configManagementPluginServiceGenerateManifestClient) CloseAndRecv() (*M
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (c *configManagementPluginServiceClient) CheckPluginConfiguration(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*CheckPluginConfigurationResponse, error) {
|
||||
out := new(CheckPluginConfigurationResponse)
|
||||
err := c.cc.Invoke(ctx, "/plugin.ConfigManagementPluginService/CheckPluginConfiguration", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *configManagementPluginServiceClient) MatchRepository(ctx context.Context, opts ...grpc.CallOption) (ConfigManagementPluginService_MatchRepositoryClient, error) {
|
||||
stream, err := c.cc.NewStream(ctx, &_ConfigManagementPluginService_serviceDesc.Streams[1], "/plugin.ConfigManagementPluginService/MatchRepository", opts...)
|
||||
if err != nil {
|
||||
@@ -655,6 +722,9 @@ type ConfigManagementPluginServiceServer interface {
|
||||
// GenerateManifests receive a stream containing a tgz archive with all required files necessary
|
||||
// to generate manifests
|
||||
GenerateManifest(ConfigManagementPluginService_GenerateManifestServer) error
|
||||
// CheckPluginConfiguration is a pre-flight request to check the plugin configuration
|
||||
// without sending the whole repo.
|
||||
CheckPluginConfiguration(context.Context, *emptypb.Empty) (*CheckPluginConfigurationResponse, error)
|
||||
// MatchRepository returns whether or not the given application is supported by the plugin
|
||||
MatchRepository(ConfigManagementPluginService_MatchRepositoryServer) error
|
||||
// GetParametersAnnouncement gets a list of parameter announcements for the given app
|
||||
@@ -668,6 +738,9 @@ type UnimplementedConfigManagementPluginServiceServer struct {
|
||||
func (*UnimplementedConfigManagementPluginServiceServer) GenerateManifest(srv ConfigManagementPluginService_GenerateManifestServer) error {
|
||||
return status.Errorf(codes.Unimplemented, "method GenerateManifest not implemented")
|
||||
}
|
||||
func (*UnimplementedConfigManagementPluginServiceServer) CheckPluginConfiguration(ctx context.Context, req *emptypb.Empty) (*CheckPluginConfigurationResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CheckPluginConfiguration not implemented")
|
||||
}
|
||||
func (*UnimplementedConfigManagementPluginServiceServer) MatchRepository(srv ConfigManagementPluginService_MatchRepositoryServer) error {
|
||||
return status.Errorf(codes.Unimplemented, "method MatchRepository not implemented")
|
||||
}
|
||||
@@ -705,6 +778,24 @@ func (x *configManagementPluginServiceGenerateManifestServer) Recv() (*AppStream
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func _ConfigManagementPluginService_CheckPluginConfiguration_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(emptypb.Empty)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ConfigManagementPluginServiceServer).CheckPluginConfiguration(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/plugin.ConfigManagementPluginService/CheckPluginConfiguration",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ConfigManagementPluginServiceServer).CheckPluginConfiguration(ctx, req.(*emptypb.Empty))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _ConfigManagementPluginService_MatchRepository_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
return srv.(ConfigManagementPluginServiceServer).MatchRepository(&configManagementPluginServiceMatchRepositoryServer{stream})
|
||||
}
|
||||
@@ -760,7 +851,12 @@ func (x *configManagementPluginServiceGetParametersAnnouncementServer) Recv() (*
|
||||
var _ConfigManagementPluginService_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "plugin.ConfigManagementPluginService",
|
||||
HandlerType: (*ConfigManagementPluginServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{},
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "CheckPluginConfiguration",
|
||||
Handler: _ConfigManagementPluginService_CheckPluginConfiguration_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
StreamName: "GenerateManifest",
|
||||
@@ -1132,6 +1228,43 @@ func (m *File) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *CheckPluginConfigurationResponse) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *CheckPluginConfigurationResponse) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *CheckPluginConfigurationResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.XXX_unrecognized != nil {
|
||||
i -= len(m.XXX_unrecognized)
|
||||
copy(dAtA[i:], m.XXX_unrecognized)
|
||||
}
|
||||
if m.IsDiscoveryConfigured {
|
||||
i--
|
||||
if m.IsDiscoveryConfigured {
|
||||
dAtA[i] = 1
|
||||
} else {
|
||||
dAtA[i] = 0
|
||||
}
|
||||
i--
|
||||
dAtA[i] = 0x8
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func encodeVarintPlugin(dAtA []byte, offset int, v uint64) int {
|
||||
offset -= sovPlugin(v)
|
||||
base := offset
|
||||
@@ -1309,6 +1442,21 @@ func (m *File) Size() (n int) {
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *CheckPluginConfigurationResponse) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
if m.IsDiscoveryConfigured {
|
||||
n += 2
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
n += len(m.XXX_unrecognized)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func sovPlugin(x uint64) (n int) {
|
||||
return (math_bits.Len64(x|1) + 6) / 7
|
||||
}
|
||||
@@ -2127,6 +2275,77 @@ func (m *File) Unmarshal(dAtA []byte) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *CheckPluginConfigurationResponse) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowPlugin
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: CheckPluginConfigurationResponse: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: CheckPluginConfigurationResponse: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field IsDiscoveryConfigured", wireType)
|
||||
}
|
||||
var v int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowPlugin
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
v |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
m.IsDiscoveryConfigured = bool(v != 0)
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipPlugin(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLengthPlugin
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func skipPlugin(dAtA []byte) (n int, err error) {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
|
||||
@@ -9,18 +9,18 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
"github.com/argoproj/pkg/rand"
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/cmpserver/apiclient"
|
||||
"github.com/argoproj/argo-cd/v2/common"
|
||||
repoclient "github.com/argoproj/argo-cd/v2/reposerver/apiclient"
|
||||
"github.com/argoproj/argo-cd/v2/util/buffered_context"
|
||||
"github.com/argoproj/argo-cd/v2/util/cmp"
|
||||
argoexec "github.com/argoproj/argo-cd/v2/util/exec"
|
||||
"github.com/argoproj/argo-cd/v2/util/io/files"
|
||||
|
||||
"github.com/argoproj/gitops-engine/pkg/utils/kube"
|
||||
@@ -76,7 +76,7 @@ func runCommand(ctx context.Context, command Command, path string, env []string)
|
||||
}
|
||||
logCtx := log.WithFields(log.Fields{"execID": execId})
|
||||
|
||||
argsToLog := getCommandArgsToLog(cmd)
|
||||
argsToLog := argoexec.GetCommandArgsToLog(cmd)
|
||||
logCtx.WithFields(log.Fields{"dir": cmd.Dir}).Info(argsToLog)
|
||||
|
||||
var stdout bytes.Buffer
|
||||
@@ -135,28 +135,6 @@ func runCommand(ctx context.Context, command Command, path string, env []string)
|
||||
return strings.TrimSuffix(output, "\n"), nil
|
||||
}
|
||||
|
||||
// getCommandArgsToLog represents the given command in a way that we can copy-and-paste into a terminal
|
||||
func getCommandArgsToLog(cmd *exec.Cmd) string {
|
||||
var argsToLog []string
|
||||
for _, arg := range cmd.Args {
|
||||
containsSpace := false
|
||||
for _, r := range arg {
|
||||
if unicode.IsSpace(r) {
|
||||
containsSpace = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if containsSpace {
|
||||
// add quotes and escape any internal quotes
|
||||
argsToLog = append(argsToLog, strconv.Quote(arg))
|
||||
} else {
|
||||
argsToLog = append(argsToLog, arg)
|
||||
}
|
||||
}
|
||||
args := strings.Join(argsToLog, " ")
|
||||
return args
|
||||
}
|
||||
|
||||
type CmdError struct {
|
||||
Args string
|
||||
Stderr string
|
||||
@@ -240,6 +218,9 @@ func (s *Service) generateManifestGeneric(stream GenerateManifestStream) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("error generating manifests: %w", err)
|
||||
}
|
||||
|
||||
log.Tracef("Generated manifests result: %s", response.Manifests)
|
||||
|
||||
err = stream.SendAndClose(response)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error sending manifest response: %w", err)
|
||||
@@ -443,3 +424,15 @@ func getParametersAnnouncement(ctx context.Context, appDir string, announcements
|
||||
}
|
||||
return repoResponse, nil
|
||||
}
|
||||
|
||||
func (s *Service) CheckPluginConfiguration(ctx context.Context, _ *empty.Empty) (*apiclient.CheckPluginConfigurationResponse, error) {
|
||||
isDiscoveryConfigured := s.isDiscoveryConfigured()
|
||||
response := &apiclient.CheckPluginConfigurationResponse{IsDiscoveryConfigured: isDiscoveryConfigured}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (s *Service) isDiscoveryConfigured() (isDiscoveryConfigured bool) {
|
||||
config := s.initConstants.PluginConfig
|
||||
return config.Spec.Discover.FileName != "" || config.Spec.Discover.Find.Glob != "" || len(config.Spec.Discover.Find.Command.Command) > 0
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user