Compare commits

...

201 Commits

Author SHA1 Message Date
Dan Garfield
37efa1880b Update argocd_appset_generate.md
Signed-off-by: Dan Garfield <dan@codefresh.io>
2025-03-13 11:42:19 -06:00
Matthieu MOREL
83257a9e73 chore: use grpc-middleware interceptors (#22329)
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2025-03-13 15:25:38 +00:00
renovate[bot]
cae840bb13 chore(deps): update dependency gotestyourself/gotestsum to v1.12.1 (#22328)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-13 06:42:34 -07:00
Regina Voloshin
8d12e352f4 docs: document logs RBAC enforcement remediation (#22285)
Signed-off-by: reggie-k <regina.voloshin@codefresh.io>
2025-03-13 09:39:45 -04:00
Michael Crenshaw
d54ae98b20 fix(controller): wrong tracking annotation for malformed resources (#22325)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-03-13 09:34:20 -04:00
renovate[bot]
12928cbdcc chore(deps): update module github.com/golangci/golangci-lint to v1.64.7 (#22306)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-12 16:40:13 -04:00
Alexandre Gaudreault
9c443b6501 fix(cli): improve performance for admin export/import cmd (#22322)
Signed-off-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>
2025-03-12 20:05:39 +00:00
dependabot[bot]
a45f715763 chore(deps): bump chromedriver from 134.0.0 to 134.0.2 in /ui-test (#22307)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: rumstead <37445536+rumstead@users.noreply.github.com>
2025-03-12 15:31:42 +00:00
Alexandre Gaudreault
335b65baf8 chore(config)!: Ignore all .status updates & known high churn changes by default (#21760)
Signed-off-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>
2025-03-12 09:12:47 +02:00
Regina Voloshin
f27515783a docs: Document Helm 3.17.1 breaking changes (#22283)
Signed-off-by: reggie-k <regina.voloshin@codefresh.io>
2025-03-11 17:27:04 -04:00
Michael Crenshaw
2afcb6f107 fix(test): delete CRD between tests, install CRD before syncing CRs (#22299)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-03-11 17:11:26 -04:00
dependabot[bot]
05a9171b42 chore(deps-dev): bump typescript from 5.7.3 to 5.8.2 in /ui-test (#22118)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-11 17:00:17 -04:00
Alexandre Gaudreault
ac50d8e1c1 feat(config)!: exclude known interim resources by default (#20013) (#21635)
Signed-off-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>
2025-03-11 12:57:42 -04:00
Brett Dudo
f775e7bf28 feat(appset): Add values to PR generator (#21557)
Signed-off-by: Brett C. Dudo <brett@dudo.io>
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Tobias Lindberg <tobias.ehlert@gmail.com>
Signed-off-by: Afzal Ansari <afzal442@gmail.com>
Signed-off-by: Revital Barletz <revitalbarletz@gmail.com>
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Signed-off-by: reggie-k <regina.voloshin@codefresh.io>
Signed-off-by: asuforce <owata.sn@gmail.com>
Signed-off-by: Michele Baldessari <michele@acksyn.org>
Signed-off-by: Laurent Lavaud <laurent.lavaud@mirakl.com>
Signed-off-by: Prune <prune@lecentre.net>
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
Signed-off-by: Jacob Colvin <jacobcolvin1@gmail.com>
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
Signed-off-by: Christopher J. Adkins <chris@cjadkins.com>
Signed-off-by: Almo Elda <almogldbh@gmail.com>
Signed-off-by: CI <ci@argoproj.com>
Signed-off-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>
Signed-off-by: Rafal Pelczar <rafal@akuity.io>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Tobias Lindberg <tobias.ehlert@gmail.com>
Co-authored-by: Afzal Ansari <afzal442@gmail.com>
Co-authored-by: Revital Barletz <revitalbarletz@gmail.com>
Co-authored-by: Regina Voloshin <reginakagan@gmail.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Regina Voloshin <regina.voloshin@codefresh.io>
Co-authored-by: Shun Nishitsuji <owata.sn@gmail.com>
Co-authored-by: Michele Baldessari <michele@acksyn.org>
Co-authored-by: Laurent Lavaud <llavaud@users.noreply.github.com>
Co-authored-by: Prune Sebastien THOMAS <prune@lecentre.net>
Co-authored-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
Co-authored-by: Jacob Colvin <jacobcolvin1@gmail.com>
Co-authored-by: Blake Pettersson <blake.pettersson@gmail.com>
Co-authored-by: Matthieu MOREL <matthieu.morel35@gmail.com>
Co-authored-by: Chris Adkins <chris@cjadkins.com>
Co-authored-by: almoelda <42950693+almoelda@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: CI <ci@argoproj.com>
Co-authored-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>
Co-authored-by: Rafal <rafal@akuity.io>
2025-03-11 11:44:20 -04:00
Dillen Padhiar
fa0b5f56ab feat: add force promote actions for Numaplane rollouts (#22141)
Signed-off-by: Dillen Padhiar <dillen_padhiar@intuit.com>
2025-03-11 10:03:51 -04:00
kahou82
43e5941042 fix: Race condition occurs during initial sharding (#22264)
Signed-off-by: Kahou Lei <kahou82@gmail.com>
2025-03-11 01:20:20 -04:00
dependabot[bot]
2168221092 chore(deps): bump library/golang from 1.24.0 to 1.24.1 in /test/remote (#22184)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-11 01:18:44 -04:00
dependabot[bot]
64569e61a1 chore(deps): bump go.opentelemetry.io/otel from 1.34.0 to 1.35.0 (#22217)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-11 01:14:37 -04:00
Alexandre Gaudreault
cca7485917 feat!: update compareoptions default values (#22230)
Signed-off-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>
2025-03-11 01:14:17 -04:00
Keith Chong
74b35322a2 feat: Make certain Status panel items look more 'clickable' (#19698) (#22232)
Signed-off-by: Keith Chong <kykchong@redhat.com>
2025-03-11 01:03:15 -04:00
Atif Ali
0ed7c5618f fix: Unable to edit http repo credentials from ArgoCD UI (#22065)
Signed-off-by: Atif Ali <atali@redhat.com>
Co-authored-by: Dan Garfield <dan@codefresh.io>
2025-03-10 20:16:04 +00:00
Michael Crenshaw
42219fd7b7 chore(lint): fix deep copy informers lint (#22290)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-03-10 15:31:17 -04:00
dependabot[bot]
111cf2ce9f chore(deps-dev): bump @types/node from 22.13.5 to 22.13.10 in /ui-test (#22272)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-10 08:35:36 -07:00
sivchari
d301b40c6b feat: Upgrade notifications engine (#22273)
Signed-off-by: sivchari <shibuuuu5@gmail.com>
2025-03-10 11:02:16 -04:00
rumstead
e3bd56972d feat(server): make deep copies of objects returned by informers (#22173) (#22179)
Signed-off-by: rumstead <37445536+rumstead@users.noreply.github.com>
2025-03-10 14:29:07 +00:00
sivchari
922d080ae5 chore: upgrade Go to 1.24 (#22242)
Signed-off-by: sivchari <shibuuuu5@gmail.com>
2025-03-10 10:14:41 -04:00
Michael Crenshaw
bd1018af5e docs: fix tmp path and document Rancher caveat (#22252)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-03-10 10:10:47 -04:00
Matthieu MOREL
76dbaaa3e0 chore: bump to github.com/grpc-ecosystem/go-grpc-middleware/v2 (#22098)
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2025-03-10 10:06:54 -04:00
Andrii Korotkov
376e8d5260 fix: Update haproxy version to match the chart (#22226) (#22236)
Signed-off-by: Andrii Korotkov <andrii.korotkov@verkada.com>
2025-03-10 10:03:04 -04:00
dependabot[bot]
627da11384 chore(deps): bump github.com/Azure/kubelogin from 0.1.6 to 0.1.8 (#22271)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-10 06:28:41 -07:00
Gahl Peled
75cb7fc42d fix: issue 22206 - fixes overlapping lines in logs by increasing line height (#22207)
Signed-off-by: Gahl_Peled <gahl.peled@talentsystems.com>
2025-03-09 19:59:24 +02:00
Andrii Korotkov
a8f646e430 fix: Notifications on-deployed would now be delivered if sync didn't change the health status of the app in a process (#22203) (#22204)
Signed-off-by: Andrii Korotkov <andrii.korotkov@verkada.com>
2025-03-09 19:58:52 +02:00
Linghao Su
4202168c44 fix(ui): reduce rerender in pod log view (#22241)
Signed-off-by: linghaoSu <linghao.su@daocloud.io>
2025-03-09 19:39:09 +02:00
sivchari
e3b333a860 fix: JSON format (#22237)
Signed-off-by: sivchari <shibuuuu5@gmail.com>
2025-03-09 19:28:58 +02:00
dependabot[bot]
cb135fdd0d chore(deps): bump axios from 1.7.4 to 1.8.2 in /ui-test (#22247)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-09 19:22:27 +02:00
Sven Schliesing
3c3410cf5d docs: fix typo in declarative-setup.md (#22256)
Signed-off-by: Sven Schliesing <muffl0n@raffts.net>
2025-03-09 19:21:12 +02:00
github-actions[bot]
5e9fc55783 [Bot] docs: Update Snyk report (#22263)
Signed-off-by: CI <ci@argoproj.com>
Co-authored-by: CI <ci@argoproj.com>
2025-03-09 19:12:18 +02:00
Andrii Korotkov
9d66e89d14 chore: Remove k8s 1.28 from e2e testing (#22245)
Signed-off-by: Andrii Korotkov <andrii.korotkov@verkada.com>
2025-03-07 13:41:44 -05:00
Andrii Korotkov
14a09be652 chore(deps): Bump utfutil to v1.0.0 (#22228) (#22243)
Signed-off-by: Andrii Korotkov <andrii.korotkov@verkada.com>
2025-03-07 15:52:22 +00:00
sivchari
fbd7f29056 feat: use errors.Join for debuggable (#22235)
Signed-off-by: sivchari <shibuuuu5@gmail.com>
2025-03-07 09:56:15 -05:00
dependabot[bot]
2cefcc5a36 chore(deps): bump chromedriver from 133.0.3 to 134.0.0 in /ui-test (#22218)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-07 06:06:05 -08:00
dependabot[bot]
683e4e0d95 chore(deps): bump selenium-webdriver from 4.27.0 to 4.29.0 in /ui-test (#22117)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ishita Sequeira <46771830+ishitasequeira@users.noreply.github.com>
2025-03-06 18:23:56 -05:00
Andrii Korotkov
8d1aeb58a2 chore: Update some dependencies and add some comments about old libs (#22104) (#22208)
Signed-off-by: Andrii Korotkov <andrii.korotkov@verkada.com>
2025-03-06 16:17:14 -05:00
dependabot[bot]
4c27f73559 chore(deps): bump golang.org/x/oauth2 from 0.27.0 to 0.28.0 (#22211)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-06 15:55:03 -05:00
Dan Garfield
dc3286730a docs: Fix typos and grammar in tls.md (#22229)
Signed-off-by: Dan Garfield <dan@codefresh.io>
2025-03-06 15:54:38 -05:00
Andrii Korotkov
62ec9fef36 fix: Use t.Fatal instead of os.Exit in tests (part 2) (#21003) (#22187)
Signed-off-by: Andrii Korotkov <andrii.korotkov@verkada.com>
2025-03-06 19:24:07 +00:00
dependabot[bot]
a8b76f2951 chore(deps): bump golang.org/x/net from 0.36.0 to 0.37.0 (#22209)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-06 11:13:03 -05:00
Michael Crenshaw
8a752a56d6 docs: document bearerToken in repo example doc (#22195)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-03-06 09:58:39 -05:00
dependabot[bot]
4f179a192d chore(deps): bump jinja2 from 3.1.5 to 3.1.6 in /docs (#22219)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-06 09:51:28 -05:00
dependabot[bot]
270b352cbd chore(deps): bump golang.org/x/time from 0.10.0 to 0.11.0 (#22212)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-06 09:47:00 -05:00
dependabot[bot]
2d994038be chore(deps): bump golang.org/x/sync from 0.11.0 to 0.12.0 (#22216)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-06 09:46:08 -05:00
Nitish Kumar
753f7b6e72 chore: enable parallel helm manifest generation by default (#22224)
Signed-off-by: nitishfy <justnitish06@gmail.com>
2025-03-06 09:43:14 -05:00
Soumya Ghosh Dastidar
6959e54f06 fix: have argocd server pass the appLabelKey for proper caching (#22186)
Signed-off-by: Soumya Ghosh Dastidar <gdsoumya@gmail.com>
2025-03-06 07:28:53 +00:00
Michael Crenshaw
7327093b66 docs: custom resource action UI tweaks (#22202)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-03-05 16:49:07 -05:00
Michael Crenshaw
74582e9965 chore: embed trivial rand string function (#22177)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-03-05 16:34:16 -05:00
Andrii Korotkov
29c69b3601 chore(deps): Bump argoproj repos versions (#22104) (#22198)
Signed-off-by: Andrii Korotkov <andrii.korotkov@verkada.com>
2025-03-05 14:58:32 -05:00
Nitish Kumar
546383a8e5 fix(cli): log correct error message when updating a cluster that is not present (#22190)
Signed-off-by: nitishfy <justnitish06@gmail.com>
2025-03-05 11:48:35 -05:00
dependabot[bot]
0444fcdf37 chore(deps): bump github.com/prometheus/client_golang from 1.21.0 to 1.21.1 (#22180)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-05 11:46:55 -05:00
dependabot[bot]
527ef92c30 chore(deps): bump sigs.k8s.io/structured-merge-diff/v4 from 4.4.4-0.20241211184406-7bf59b3d70ee to 4.6.0 (#22181)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-05 11:46:11 -05:00
dependabot[bot]
2731c3f18d chore(deps): bump google.golang.org/grpc from 1.70.0 to 1.71.0 (#22183)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-05 11:45:22 -05:00
dependabot[bot]
9783c5ea24 chore(deps): bump golang.org/x/net from 0.35.0 to 0.36.0 (#22182)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-05 11:44:34 -05:00
Michael Crenshaw
db82e23ebb chore: use internal errors util instead of pkg's (#22174)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-03-05 11:40:56 -05:00
Regina Voloshin
04a1608643 docs: 3.0 release date on May 06 (#22189)
Signed-off-by: reggie-k <regina.voloshin@codefresh.io>
2025-03-05 10:13:38 -05:00
sivchari
6b002a5106 feat: upgrade to v1.32.2 (#22168)
Signed-off-by: sivchari <shibuuuu5@gmail.com>
2025-03-04 16:39:28 -05:00
Andrii Korotkov
5223ce546a chore: Upgrade Redis from 7.0.15-alpine to 7.2.7-alpine and haproxy (#22108) (#22110)
Signed-off-by: Andrii Korotkov <andrii.korotkov@verkada.com>
2025-03-04 15:59:03 -05:00
renovate[bot]
95a43e0416 chore(deps): update module github.com/golangci/golangci-lint to v1.64.6 (#22115)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-04 15:57:44 -05:00
Michael Crenshaw
c6b00007f2 fix(actions): don't run empty Lua scripts (#22084) (#22161)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-03-04 14:25:36 -05:00
Michael Crenshaw
eb6732ec9e fix(ci): use pinned Helm version for init-release (#22164) (#22165)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-03-04 13:06:01 -05:00
Nitish Kumar
0b0c737af0 chore(deps): bump github.com/go-jose/go-jose/v3 to v4 (#22154)
Signed-off-by: nitishfy <justnitish06@gmail.com>
Co-authored-by: rumstead <37445536+rumstead@users.noreply.github.com>
2025-03-04 12:30:12 -05:00
sivchari
c0b278738c feat: Support kube 1.32 (#21805)
Signed-off-by: sivchari <shibuuuu5@gmail.com>
2025-03-04 11:15:35 -05:00
rumstead
029927b25e feat(appcontroller): store application health status in redis by default (#10312) (#21532)
Signed-off-by: rumstead <37445536+rumstead@users.noreply.github.com>
2025-03-04 11:29:23 +00:00
dependabot[bot]
f2490fccdd chore(deps): bump go.opentelemetry.io/otel/sdk from 1.33.0 to 1.34.0 (#21570)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-03 19:55:58 -05:00
Dag Andersen
898a126f10 docs: Add section on how to lock down/restrict the default project (#21757)
Signed-off-by: Dag Andersen <dagbjerreandersen@gmail.com>
2025-03-03 19:55:47 -05:00
Michael Crenshaw
bfb04ddf3e fix(ui): parameter tab null ref w/ hydrator (#22097) (#22131)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-03-03 16:16:32 -05:00
Andrii Korotkov
416b7d0c32 fix(test): Use t.Fatal instead of os.Exit in tests (part 1) (#21003) (#22114)
Signed-off-by: Andrii Korotkov <andrii.korotkov@verkada.com>
2025-03-03 13:36:13 -05:00
Mike Cutsail
561cbef5cc feat: checking user defined roles and policies for referential integrity (#20825) (#22132)
Signed-off-by: Mike Cutsail <mcutsail15@apple.com>
2025-03-03 10:15:43 -08:00
rumstead
2bcaa19894 revert: add a check for user defined role referential integrity #21065 (#22130)
Signed-off-by: rumstead <37445536+rumstead@users.noreply.github.com>
2025-03-03 22:03:27 +05:30
Soumya Ghosh Dastidar
228b86d3b5 chore: update mockery version (#22126)
Signed-off-by: Soumya Ghosh Dastidar <gdsoumya@gmail.com>
2025-03-03 16:57:20 +02:00
Andrii Korotkov
f542ae5158 fix: Revert "split arrays in yaml to fix ambiguous collapse when array items have nested objects (#21064)" (#22099) (#22128)
Signed-off-by: Andrii Korotkov <andrii.korotkov@verkada.com>
2025-03-03 09:48:41 -05:00
Mike Cutsail
c71dd1a9e6 feat: add a check for user defined role referential integrity (#21065)
Signed-off-by: Mike Cutsail <mcutsail15@apple.com>
2025-03-03 06:09:25 -08:00
dependabot[bot]
f2c5093013 chore(deps): bump @types/selenium-webdriver from 4.1.27 to 4.1.28 in /ui-test (#21414)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-02 18:43:57 -05:00
dependabot[bot]
21ea59d600 chore(deps): bump go.opentelemetry.io/otel from 1.33.0 to 1.34.0 (#21569)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-02 18:35:32 -05:00
Karl Taylor
e2e6faa3b5 fix(ui): prevent parameter editor from resetting when props update (fixes #14351) (#21625)
Signed-off-by: Karl Taylor <16408267+k4r1@users.noreply.github.com>
2025-03-02 18:32:03 -05:00
renovate[bot]
42fa72d499 chore(deps): update dependency pymdown-extensions to v10.14.3 (#21619)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-02 18:25:06 -05:00
Linghao Su
6f9389c2ea feat(log): support match case in pod log search (#21919)
Signed-off-by: linghaoSu <linghao.su@daocloud.io>
Co-authored-by: Dan Garfield <dan@codefresh.io>
2025-03-02 18:21:51 -05:00
dependabot[bot]
98cd061ac9 chore(deps): bump library/golang from 2b1cbf2 to cd0c949 in /test/remote (#22020)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-02 18:04:34 -05:00
Michael Crenshaw
b9131c1802 feat(cmp): pass empty env vars to plugins (#18720) (#22096)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-03-02 18:01:50 -05:00
Blake Pettersson
e6f94f227c fix(appcontroller): selfhealattemptscount needs to be reset at times (#22095)
Signed-off-by: Blake Pettersson <blake.pettersson@gmail.com>
2025-03-02 17:46:39 -05:00
Abhinandh B G
74244323f8 fix: Rephrased sentence to a meaningfull one (#22113)
Signed-off-by: Abhinandh B G <97796199+babugeet@users.noreply.github.com>
2025-03-02 23:33:43 +05:30
github-actions[bot]
e38c7ae00f [Bot] docs: Update Snyk report (#22106)
Signed-off-by: CI <ci@argoproj.com>
Co-authored-by: CI <ci@argoproj.com>
2025-03-02 17:14:06 +00:00
Michael Crenshaw
261137df9d chore(health): report progressing status for AppSets (#22092)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-02-28 18:09:06 -05:00
dependabot[bot]
c47152d017 chore(deps): bump chromedriver from 133.0.2 to 133.0.3 in /ui-test (#22018)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-28 16:50:44 -05:00
BWagenerGenerali
7c7dda0e93 fix(grafanadashboard): add memory units to panels showing memory usage (#22078)
Signed-off-by: BWagenerGenerali <69955643+BWagenerGenerali@users.noreply.github.com>
2025-02-28 16:46:22 -05:00
Michael Crenshaw
806c5f6b6d fix: return cluster URL in error message, not full cluster object (#22094)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-02-28 21:10:00 +00:00
Matthieu MOREL
795bda5dd8 chore: use github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus (#21937)
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2025-02-28 15:44:33 -05:00
Matias Reparaz
499f74dc27 docs: Update USERS.md (#22093)
Signed-off-by: Matias Reparaz <mreparaz@gmail.com>
2025-02-28 15:01:20 -05:00
Mathias Petermann
c4183aad76 docs: Document askpass socket sharing between reposerver and cmp sidecar (#22083)
Signed-off-by: Mathias Petermann <mathias.petermann@gmail.com>
2025-02-28 09:30:20 -07:00
Christian Hernandez
3f74b24c0a docs: Adding Argo CD CLI plugin support proposal (#19624)
Signed-off-by: Christian Hernandez <christian@chernand.io>
Co-authored-by: Blake Pettersson <blake.pettersson@gmail.com>
2025-02-28 11:20:51 -05:00
Dale Haiducek
1905d127a5 fix: Check placement exists before length check (#22060) (#22057)
Signed-off-by: Dale Haiducek <19750917+dhaiducek@users.noreply.github.com>
2025-02-28 10:55:14 -05:00
Andrii Korotkov
07da3d41da chore: Option to disable sync with replace on API Server level (#21427) (#22073)
Signed-off-by: Andrii Korotkov <andrii.korotkov@verkada.com>
2025-02-28 09:43:53 -05:00
dependabot[bot]
cbef55e566 chore(deps): bump github.com/go-git/go-git/v5 from 5.13.2 to 5.14.0 (#22076)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-28 09:27:16 -05:00
Michael Crenshaw
c6757573ae feat(kustomize): support --include-templates for labels (#15283) (#22069)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-02-28 09:26:26 -05:00
Xiaopeng Han
2b1220c600 chore: revise wrong resource customization usage example (#22074)
Signed-off-by: xiaopeng <hanxiaop8@outlook.com>
2025-02-28 09:36:05 +05:30
Peter Jiang
edbce2a524 chore(deps): bump gitops-engine to latest (#22071)
Signed-off-by: Peter Jiang <peterjiang823@gmail.com>
2025-02-27 22:12:15 +00:00
Atif Ali
55f8a434d0 feat(ui): split arrays in yaml to fix ambiguous collapse when array items have nested objects (#21064)
Signed-off-by: Atif Ali <atali@redhat.com>
2025-02-27 15:54:49 -05:00
Michael Crenshaw
8a97c1d138 fix(hydrator): refresh by annotation instead of work queue (#22016)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-02-27 14:22:03 -05:00
Michael Crenshaw
35009a7d1c fix(hydrator): don't use manifest-generate-paths (#22039) (#22015)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-02-27 12:15:45 -05:00
Gergely Fábián
94b34f88ec fix: upgrade x/crypto to v0.35.0 to solve CVE-2025-22869 (#22048)
Signed-off-by: Gergely Fábián <gergo.fb@gmail.com>
2025-02-27 12:07:10 -05:00
Richard Palm
ce819128f9 docs: fix project role docs (#21832)
Signed-off-by: Richard Palm <richard.palm@hellofresh.com>
Co-authored-by: Blake Pettersson <blake.pettersson@gmail.com>
2025-02-27 10:35:18 +01:00
Nitish Kumar
e6e9255216 fix: correct lookup for the kustomization file when applying patches (#22024)
Signed-off-by: nitishfy <justnitish06@gmail.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-02-27 13:39:39 +05:30
Atif Ali
c09e6fa6ad feat: improve StatefulSet immutable field error messages (#21209)
Signed-off-by: Atif Ali <atali@redhat.com>
2025-02-26 23:47:51 +02:00
Michael Crenshaw
3baca9b696 fix(hydrator): don't get cluster or API versions for hydrator (#21985)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-02-26 13:36:48 -05:00
Taeyeop Kim
961147d387 docs: Update sync-kubectl.md - Correct kubectl command for a sample (#22030)
Signed-off-by: Taeyeop Kim <taeyeop.kim1@gmail.com>
2025-02-26 17:23:58 +00:00
Regina Voloshin
686964daaa fix: removed null security context from redis-ha values.yaml to placate helm 3.17.1 (#22035)
Signed-off-by: reggie-k <regina.voloshin@codefresh.io>
2025-02-26 17:16:39 +00:00
Suraj yadav
b88ad57986 fix(ui): Added SSV option to helm type repos (#22006)
Signed-off-by: Surajyadav <harrypotter1108@gmail.com>
2025-02-26 10:56:18 -05:00
Nitish Kumar
975e966e26 docs: add more info on what login --core does (#21487)
Signed-off-by: nitishfy <justnitish06@gmail.com>
Signed-off-by: Nitish Kumar <justnitish06@gmail.com>
Co-authored-by: Blake Pettersson <blake.pettersson@gmail.com>
2025-02-26 20:13:43 +05:30
gussan
49a4b7f14f fix: fetch syncedRevision in UpdateRevisionForPaths (#21014) (#21015)
Signed-off-by: toyamagu2021 <toyamagu2021@gmail.com>
Signed-off-by: toyamagu-2021 <toyamagu2021@gmail.com>
2025-02-26 01:07:31 +05:30
Isaac Gaskin
644af54a7c chore: version bumping helm3 (#22009)
Signed-off-by: Isaac Gaskin <isaac.gaskin@circle.com>
2025-02-25 19:34:38 +00:00
dependabot[bot]
c897e944db chore(deps): bump github.com/go-jose/go-jose/v4 from 4.0.2 to 4.0.5 (#21989)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-25 14:10:35 -05:00
dependabot[bot]
94d3899038 chore(deps): bump golang.org/x/oauth2 from 0.26.0 to 0.27.0 (#21990)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-25 14:09:02 -05:00
Leonardo Luz Almeida
1823d8fcd2 docs: add applicationset controller doc to preserve annotations and labels (#22008)
Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>
2025-02-25 14:08:39 -05:00
Regina Voloshin
402802b089 feat!: Logs rbac enforce by default (#21678)
Signed-off-by: reggie-k <regina.voloshin@codefresh.io>
Signed-off-by: Regina Voloshin <reginakagan@gmail.com>
Signed-off-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>
Co-authored-by: rumstead <37445536+rumstead@users.noreply.github.com>
Co-authored-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>
2025-02-25 18:27:32 +00:00
Alexandre Gaudreault
e784c47667 chore(deps): bump go 1.23.5 & tools (#21748)
Signed-off-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>
2025-02-25 17:04:57 +00:00
rumstead
e44ae96c07 fix(appset): generated app errors should use the default requeue (#21887) (#21936)
Signed-off-by: rumstead <37445536+rumstead@users.noreply.github.com>
Co-authored-by: Ishita Sequeira <46771830+ishitasequeira@users.noreply.github.com>
Co-authored-by: Blake Pettersson <blake.pettersson@gmail.com>
2025-02-25 15:27:32 +00:00
Michael Crenshaw
be293fe9ed chore(hydrator): improve error message (#21987)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-02-24 22:01:01 +00:00
Michael Crenshaw
e18b4d7ac8 chore(deps): switch to new expr package (#21982)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-02-24 23:37:58 +02:00
dependabot[bot]
f32f69f7d2 chore(deps): bump github.com/google/go-cmp from 0.6.0 to 0.7.0 (#21956)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-24 14:32:18 -05:00
Michael Crenshaw
846503bb0e docs: note idle connections issue for cluster namespaces (#21978)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-02-24 18:43:21 +02:00
Michael Crenshaw
f63f5f954e docs: document source hydrator maturity (#21969)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-02-24 10:41:06 -05:00
Regina Voloshin
8044d68492 feat: add bearer token auth (#21462)
Signed-off-by: reggie-k <regina.voloshin@codefresh.io>
Co-authored-by: Pasha Kostohrys <pasha.kostohrys@gmail.com>
2025-02-24 12:44:07 +02:00
dependabot[bot]
33ad0a7ba7 chore(deps-dev): bump @types/node from 22.13.4 to 22.13.5 in /ui-test (#21960)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-24 10:37:47 +02:00
dependabot[bot]
0dddb9e6c8 chore(deps): bump library/busybox from a5d0ce4 to 498a000 in /test/e2e/multiarch-container (#21959)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-24 10:37:34 +02:00
dependabot[bot]
562fa065c6 chore(deps): bump github.com/redis/go-redis/v9 from 9.7.0 to 9.7.1 (#21957)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-24 10:37:22 +02:00
dependabot[bot]
ecee599640 chore(deps): bump github.com/bradleyfalzon/ghinstallation/v2 from 2.13.0 to 2.14.0 (#21955)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-24 10:37:06 +02:00
Suraj yadav
38b0fd5cd4 fix(ui): columns-adjusted for kind and Namespace in sync details. (#21038)
Signed-off-by: Surajyadav <harrypotter1108@gmail.com>
2025-02-23 16:38:57 -05:00
Soumya Ghosh Dastidar
87671f55c5 fix: ignore prune=false resources from PruningRequired count (#21941)
Signed-off-by: Soumya Ghosh Dastidar <gdsoumya@gmail.com>
2025-02-23 16:12:22 -05:00
dependabot[bot]
1f1c33983b chore(deps-dev): bump @types/node from 22.10.10 to 22.13.4 in /ui-test (#21874)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-23 20:43:50 +02:00
dependabot[bot]
ee83eea784 chore(deps): bump library/golang from 1.23.6 to 1.24.0 in /test/remote (#21868)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-23 20:43:08 +02:00
dependabot[bot]
9e6b28b8a2 chore(deps): bump library/golang from 1.23.6 to 1.24.0 in /test/container (#21866)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-23 20:42:41 +02:00
dependabot[bot]
84b49c84ca chore(deps): bump gitpod/workspace-full from bec45eb to a47a68e (#21843)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-23 20:40:28 +02:00
dependabot[bot]
6c64d5ff55 chore(deps): bump chromedriver from 132.0.1 to 133.0.2 in /ui-test (#21916)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-23 20:39:07 +02:00
Andrii Korotkov
7b1ed5218a fix: On deployed trigger must consider race between last transition time and sync finished time (#9070) (#21944)
Signed-off-by: Andrii Korotkov <andrii.korotkov@verkada.com>
2025-02-23 17:44:24 +02:00
Fabián Sellés Rosa
079341c65c fix(applicationset): ApplicationSets with rolling sync stuck in Pending (#20230)
Signed-off-by: Fabián Sellés <fabian.selles@adevinta.com>
Co-authored-by: Thibault Jamet <tjamet@users.noreply.github.com>
Co-authored-by: Carlos Rejano <carlosrejanoromeu@gmail.com>
2025-02-22 09:14:49 -05:00
sivchari
9f81cd4798 fix: Use ARGOCD_SERVER for default value (#21930)
Signed-off-by: sivchari <shibuuuu5@gmail.com>
2025-02-22 12:20:15 +05:30
Matthieu MOREL
37aaeb3dd9 chore: enable usetesting linter (#21935)
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2025-02-21 18:50:55 +00:00
dependabot[bot]
7870200461 chore(deps): bump github.com/prometheus/client_golang from 1.20.5 to 1.21.0 (#21915)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-20 11:46:47 -05:00
Marco Stuurman
167e122eba docs: Fix typo code-gen/codegen contributors-quickstart.md (#21922)
Signed-off-by: Marco Stuurman <marco@fe.ax>
2025-02-20 04:14:25 -10:00
Blake Pettersson
a1431bef4c fix(ui, rbac): project-roles (#21829)
Signed-off-by: wyttime04 <vanessa80332@gmail.com>
Signed-off-by: Blake Pettersson <blake.pettersson@gmail.com>
Co-authored-by: wyttime04 <vanessa80332@gmail.com>
2025-02-20 11:40:15 +01:00
Matthew Bennett
073ccf7c35 fix(#19314, #15700): allow ssh/altssh subdomains in repo URLs to match webhook payload (#21227) 2025-02-20 12:15:29 +05:30
Michael Crenshaw
feb7097fc9 feat(metrics): add more kubectl metrics (#21720)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-02-19 11:21:22 -05:00
appiepollo14
976a8498d4 ci: fixes #21862 Concurrency in pr-title-check (#21863)
Signed-off-by: appiepollo14 <asjer94@live.com>
2025-02-18 14:48:32 -05:00
renovate[bot]
36d563a3c2 chore(deps): update dependency gotestyourself/gotestsum to v1.12.0 (#21900)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-18 12:18:05 -05:00
Nitish Kumar
944f9f7b68 chore: add the Argo CD type definitions and method comments (#21854)
Signed-off-by: nitishfy <justnitish06@gmail.com>
2025-02-18 11:20:52 -05:00
github-actions[bot]
f78c7ee2ba [Bot] docs: Update Snyk report (#21883)
Signed-off-by: CI <ci@argoproj.com>
Co-authored-by: CI <ci@argoproj.com>
2025-02-18 11:03:15 -05:00
Matthieu MOREL
c1b2f78f46 chore: enable var-naming from revive (#21861)
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2025-02-18 11:02:38 -05:00
Takumi Sue
38c2b34da0 chore: update gotestsum automatically (#21828)
Signed-off-by: mikutas <23391543+mikutas@users.noreply.github.com>
2025-02-18 10:53:13 -05:00
renovate[bot]
2e1db11ad9 chore(deps): update module github.com/golangci/golangci-lint to v1.64.5 (#21850)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-18 10:50:07 -05:00
dependabot[bot]
ab05f35507 chore(deps): bump github.com/dlclark/regexp2 from 1.11.4 to 1.11.5 (#21853)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-18 10:49:33 -05:00
dependabot[bot]
b3bf182a65 chore(deps): bump github.com/Azure/azure-sdk-for-go/sdk/azidentity from 1.8.1 to 1.8.2 (#21867)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-18 10:49:04 -05:00
Cheng Fang
563ccb20c7 fix: fix KustomizeImage Match function to pass added unit tests (#21872)
Signed-off-by: Cheng Fang <cfang@redhat.com>
2025-02-18 10:26:12 -05:00
dependabot[bot]
ca9da799d8 chore(deps): bump github.com/spf13/cobra from 1.8.1 to 1.9.1 (#21889)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-18 10:25:28 -05:00
dependabot[bot]
50fb7bcd21 chore(deps): bump golang.org/x/crypto from 0.32.0 to 0.33.0 (#21827)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-18 09:51:23 -05:00
Alexandre Gaudreault
eb6dd46e19 fix(cli): ignored resources should not be pruned during restore (#21894)
Signed-off-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>
2025-02-18 09:36:56 -05:00
Andrii Korotkov
e14d6b7bf9 chore: Update notifications to be less spammy (#20871) (#21884)
Signed-off-by: Andrii Korotkov <andrii.korotkov@verkada.com>
2025-02-18 08:43:39 -05:00
Leonardo Luz Almeida
6daaac5924 chore: add log context to proxy extension requests (#21834) 2025-02-14 03:04:58 +00:00
Dan Garfield
65664ce5f3 docs: clarify wording on cluster secrets (#21865)
Signed-off-by: Dan Garfield <dan@codefresh.io>
2025-02-12 22:52:43 +01:00
Dejan Zele Pejchev
8a447d9ae0 chore: add e2e test for hook finalizer which prevents external resource deletion (#21113)
Signed-off-by: Dejan Zele Pejchev <pejcev.dejan@gmail.com>
Signed-off-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>
Co-authored-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>
2025-02-11 09:28:01 -05:00
Nitish Kumar
951d9d3f17 feat: add the --redis-compress as the global flag to set redis compression. (#21786)
Signed-off-by: nitishfy <justnitish06@gmail.com>
2025-02-10 17:38:20 -08:00
Nitish Kumar
967126860c test: add get cluster info test case (#21831)
Signed-off-by: nitishfy <justnitish06@gmail.com>
2025-02-10 16:02:22 -08:00
Dag Andersen
d19b02dcd0 docs: Ensure Argo CD Hydrator branch prefix consistency (#21836)
Signed-off-by: Dag Andersen <dagbjerreandersen@gmail.com>
2025-02-10 12:43:14 -06:00
ivanscai
d183d9c614 fix: dynamic cluster distribution issue 20965, update the shard… (#21042)
Signed-off-by: caijing <caijing.cai@alibaba-inc.com>
Co-authored-by: Ishita Sequeira <46771830+ishitasequeira@users.noreply.github.com>
2025-02-09 22:25:34 -05:00
Brett Dudo
b600c5ec7d fix: make codegen permissions (#21667)
Signed-off-by: Brett C. Dudo <brett@dudo.io>
Signed-off-by: Brett Dudo <brett@dudo.io>
Co-authored-by: Ishita Sequeira <46771830+ishitasequeira@users.noreply.github.com>
2025-02-09 22:18:12 -05:00
dependabot[bot]
8e91ce9b2b chore(deps): bump library/golang from 1.23.5 to 1.23.6 in /test/remote (#21799)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-09 22:10:40 -05:00
Matthieu MOREL
8507a87bfa chore: define apiextensionsv1 alias with importas (#21823)
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2025-02-09 22:10:15 -05:00
dependabot[bot]
4e2902d972 chore(deps): bump google.golang.org/protobuf from 1.36.4 to 1.36.5 (#21813)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-09 22:07:39 -05:00
Michael Crenshaw
928fd19593 chore(appset): simplify cluster list code (#21820)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-02-09 22:07:21 -05:00
Andrii Korotkov
5b79c34c72 fix: New kube applier for server side diff dry run with refactoring (#21488) (#21749)
Signed-off-by: Andrii Korotkov <andrii.korotkov@verkada.com>
2025-02-07 12:26:03 -05:00
bradkwadsworth
0973409273 feat: Kustomize ignore missing components (#18634) (#21674)
Signed-off-by: Brad Wadsworth <wadsworth.brad@gmail.com>
2025-02-07 16:20:35 +00:00
Blake Pettersson
922dd771e3 fix(appset): improve git generator repo credential fallback (#21167)
Signed-off-by: Blake Pettersson <blake.pettersson@gmail.com>
2025-02-07 10:22:39 -05:00
teddy-wahle
4a1d0f3af5 fix: Switch default logging to JSON (issue: 20897) (#21656)
Signed-off-by: Teddy Wahle <teddy.wahle@verkada.com>
2025-02-06 18:32:26 +00:00
OpenGuidou
d1574c204f fix(rbac): Add rights on applicationsets for the application controller (#20352)
Signed-off-by: OpenGuidou <guillaume.doussin@gmail.com>
2025-02-06 12:10:11 -05:00
wanghonglei5181
4dcabb933e fix: Fix link about http middlewear and add adopter hetao101 (#21802)
Signed-off-by: wanghonglei5181 <wanghonglei5181@163.com>
2025-02-06 03:00:33 -07:00
Anand Francis Joseph
fa747f987c fix(tests): Improved the e2e tests for app sync with impersonation feature (#21792)
Signed-off-by: anandf <anjoseph@redhat.com>
2025-02-05 21:37:48 -05:00
Peter Jiang
71c7700f2e fix(ui): Show error message when max pods to view logs are reached (#21725)
Signed-off-by: Peter Jiang <peterjiang823@gmail.com>
2025-02-05 21:36:05 -05:00
dependabot[bot]
7efd2fe2eb chore(deps): bump library/golang from 1.23.5 to 1.23.6 in /test/container (#21774)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-05 21:27:35 -05:00
Peter Jiang
43822815f7 fix(docs): Fix syntax in e2e test docs (#21796)
Signed-off-by: Peter Jiang <peterjiang823@gmail.com>
2025-02-05 21:03:25 -05:00
Leonardo Luz Almeida
911a9c6776 fix: Add proxy registry key by dest server + name (#21791)
Signed-off-by: Leonardo Luz Almeida <leonardo_almeida@intuit.com>
2025-02-05 14:47:24 -05:00
dependabot[bot]
73c3935031 chore(deps): bump golang.org/x/term from 0.28.0 to 0.29.0 (#21776)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-05 19:43:51 +00:00
dependabot[bot]
4641e802a4 chore(deps): bump golang.org/x/oauth2 from 0.25.0 to 0.26.0 (#21777)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-05 19:05:31 +00:00
dependabot[bot]
4b087089fb chore(deps): bump golang.org/x/sync from 0.10.0 to 0.11.0 (#21778)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-05 13:18:03 -05:00
dependabot[bot]
7d0c10e0d2 chore(deps): bump golang.org/x/time from 0.9.0 to 0.10.0 (#21779)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-05 13:17:42 -05:00
Matthieu MOREL
9843bfbdf8 chore: use testify instead of native testing (#21781)
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2025-02-05 09:46:52 -05:00
Michael Crenshaw
5d147a3ae6 chore(appset)!: always apply nested selectors (#14152) (#21492)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>
2025-02-04 19:55:01 +00:00
rumstead
68d60cd092 fix(docs): update mkdocs for upgrade guide (#21768)
Signed-off-by: rumstead <37445536+rumstead@users.noreply.github.com>
2025-02-04 18:55:14 +00:00
Ashu
99cd3c7650 fix(cli): add flags to admin import for retrying updates on conflicts and skipping resources with specific labels. (#21694)
Signed-off-by: asingh51 <ashutosh_singh@intuit.com>
Co-authored-by: asingh51 <ashutosh_singh@intuit.com>
2025-02-04 06:17:06 +00:00
rumstead
622847bcb5 docs(2.14): use 2.14.1 manifests as remote bases (#21759)
Signed-off-by: rumstead <37445536+rumstead@users.noreply.github.com>
2025-02-03 21:37:23 +00:00
rumstead
ad09b9c744 fix(docs): 2.14 upgrading docs (#21756) 2025-02-03 23:08:19 +02:00
Michael Crenshaw
47bec8b438 chore!: remove legacy repo support (#19768) (#21249)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-02-03 20:15:15 +00:00
github-actions[bot]
95b8a4ab0b [Bot] docs: Update Snyk report (#21733)
Signed-off-by: CI <ci@argoproj.com>
Co-authored-by: CI <ci@argoproj.com>
2025-02-03 13:19:52 -05:00
Michael Crenshaw
c32afb4ee2 docs: endorse secrets operators, caution against plugins (#21629) (#21631)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-02-03 12:18:00 -05:00
adriananeci
c9c40684b7 feat: add AND operator opt-in option for sync windows matches (#16846)
Signed-off-by: Adrian Aneci <aneci@adobe.com>
2025-02-03 16:48:18 +00:00
784 changed files with 42776 additions and 70488 deletions

View File

@@ -14,7 +14,7 @@ on:
env:
# Golang version to use across CI steps
# renovate: datasource=golang-version packageName=golang
GOLANG_VERSION: '1.23.3'
GOLANG_VERSION: '1.24.1'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
@@ -39,7 +39,7 @@ jobs:
files_yaml: |
backend:
- '!ui/**'
- '!**.md'
- '!**.md'
- '!**/*.md'
- '!docs/**'
frontend:
@@ -94,8 +94,8 @@ jobs:
lint-go:
permissions:
contents: read # for actions/checkout to fetch code
pull-requests: read # for golangci/golangci-lint-action to fetch pull requests
contents: read # for actions/checkout to fetch code
pull-requests: read # for golangci/golangci-lint-action to fetch pull requests
name: Lint Go code
if: ${{ needs.changes.outputs.backend == 'true' }}
runs-on: ubuntu-22.04
@@ -112,7 +112,7 @@ jobs:
uses: golangci/golangci-lint-action@971e284b6050e8a5849b72094c50ab08da042db8 # v6.1.1
with:
# renovate: datasource=go packageName=github.com/golangci/golangci-lint versioning=regex:^v(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)?$
version: v1.63.4
version: v1.64.7
args: --verbose
test-go:
@@ -402,30 +402,31 @@ jobs:
strategy:
fail-fast: false
matrix:
# latest: true means that this version mush upload the coverage report to codecov.io
# We designate the latest version because we only collect code coverage for that version.
k3s:
- version: v1.31.0
# We designate the latest version because we only collect code coverage for that version.
- version: v1.32.1
latest: true
- version: v1.31.0
latest: false
- version: v1.30.4
latest: false
- version: v1.29.8
latest: false
- version: v1.28.13
latest: false
needs:
- build-go
- changes
env:
GOPATH: /home/runner/go
ARGOCD_FAKE_IN_CLUSTER: "true"
ARGOCD_SSH_DATA_PATH: "/tmp/argo-e2e/app/config/ssh"
ARGOCD_TLS_DATA_PATH: "/tmp/argo-e2e/app/config/tls"
ARGOCD_E2E_SSH_KNOWN_HOSTS: "../fixture/certs/ssh_known_hosts"
ARGOCD_E2E_K3S: "true"
ARGOCD_IN_CI: "true"
ARGOCD_E2E_APISERVER_PORT: "8088"
ARGOCD_APPLICATION_NAMESPACES: "argocd-e2e-external,argocd-e2e-external-2"
ARGOCD_SERVER: "127.0.0.1:8088"
ARGOCD_FAKE_IN_CLUSTER: 'true'
ARGOCD_SSH_DATA_PATH: '/tmp/argo-e2e/app/config/ssh'
ARGOCD_TLS_DATA_PATH: '/tmp/argo-e2e/app/config/tls'
ARGOCD_E2E_SSH_KNOWN_HOSTS: '../fixture/certs/ssh_known_hosts'
ARGOCD_E2E_K3S: 'true'
ARGOCD_IN_CI: 'true'
ARGOCD_E2E_APISERVER_PORT: '8088'
ARGOCD_APPLICATION_NAMESPACES: 'argocd-e2e-external,argocd-e2e-external-2'
ARGOCD_SERVER: '127.0.0.1:8088'
GITHUB_TOKEN: ${{ secrets.E2E_TEST_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
GITLAB_TOKEN: ${{ secrets.E2E_TEST_GITLAB_TOKEN }}
steps:
@@ -486,7 +487,7 @@ jobs:
run: |
docker pull ghcr.io/dexidp/dex:v2.41.1
docker pull argoproj/argo-cd-ci-builder:v1.0.0
docker pull redis:7.0.15-alpine
docker pull redis:7.2.7-alpine
- name: Create target directory for binaries in the build-process
run: |
mkdir -p dist
@@ -549,4 +550,4 @@ jobs:
exit 0
else
exit 1
fi
fi

View File

@@ -7,7 +7,7 @@ on:
pull_request:
branches:
- master
types: [ labeled, unlabeled, opened, synchronize, reopened ]
types: [labeled, unlabeled, opened, synchronize, reopened]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
@@ -46,14 +46,14 @@ jobs:
needs: [set-vars]
permissions:
contents: read
packages: write # for pushing packages to GHCR, which is used by cd.apps.argoproj.io to avoid polluting Quay with tags
packages: write # for pushing packages to GHCR, which is used by cd.apps.argoproj.io to avoid polluting Quay with tags
id-token: write # for creating OIDC tokens for signing.
if: ${{ github.repository == 'argoproj/argo-cd' && github.event_name != 'push' }}
uses: ./.github/workflows/image-reuse.yaml
with:
# Note: cannot use env variables to set go-version (https://docs.github.com/en/actions/using-workflows/reusing-workflows#limitations)
# renovate: datasource=golang-version packageName=golang
go-version: 1.23.3
go-version: 1.24.1
platforms: ${{ needs.set-vars.outputs.platforms }}
push: false
@@ -61,7 +61,7 @@ jobs:
needs: [set-vars]
permissions:
contents: read
packages: write # for pushing packages to GHCR, which is used by cd.apps.argoproj.io to avoid polluting Quay with tags
packages: write # for pushing packages to GHCR, which is used by cd.apps.argoproj.io to avoid polluting Quay with tags
id-token: write # for creating OIDC tokens for signing.
if: ${{ github.repository == 'argoproj/argo-cd' && github.event_name == 'push' }}
uses: ./.github/workflows/image-reuse.yaml
@@ -70,7 +70,7 @@ jobs:
ghcr_image_name: ghcr.io/argoproj/argo-cd/argocd:${{ needs.set-vars.outputs.image-tag }}
# Note: cannot use env variables to set go-version (https://docs.github.com/en/actions/using-workflows/reusing-workflows#limitations)
# renovate: datasource=golang-version packageName=golang
go-version: 1.23.3
go-version: 1.24.1
platforms: ${{ needs.set-vars.outputs.platforms }}
push: true
secrets:
@@ -101,8 +101,8 @@ jobs:
- build-and-publish
- set-vars
permissions:
contents: write # for git to push upgrade commit if not already deployed
packages: write # for pushing packages to GHCR, which is used by cd.apps.argoproj.io to avoid polluting Quay with tags
contents: write # for git to push upgrade commit if not already deployed
packages: write # for pushing packages to GHCR, which is used by cd.apps.argoproj.io to avoid polluting Quay with tags
if: ${{ github.repository == 'argoproj/argo-cd' && github.event_name == 'push' }}
runs-on: ubuntu-22.04
steps:
@@ -116,4 +116,3 @@ jobs:
git config --global user.name 'CI'
git diff --exit-code && echo 'Already deployed' || (git commit -am 'Upgrade argocd to ${{ needs.set-vars.outputs.image-tag }}' && git push)
working-directory: argoproj-deployments/argocd

View File

@@ -12,8 +12,8 @@ permissions: {}
# workflow being trigger a number of times. This limits it
# to one run per PR.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
group: ${{ github.workflow }}-${{ github.head_ref }}
cancel-in-progress: true
jobs:
validate:

View File

@@ -11,7 +11,7 @@ permissions: {}
env:
# renovate: datasource=golang-version packageName=golang
GOLANG_VERSION: '1.23.3' # Note: go-version must also be set in job argocd-image.with.go-version
GOLANG_VERSION: '1.24.1' # Note: go-version must also be set in job argocd-image.with.go-version
jobs:
argocd-image:
@@ -25,7 +25,7 @@ jobs:
quay_image_name: quay.io/argoproj/argocd:${{ github.ref_name }}
# Note: cannot use env variables to set go-version (https://docs.github.com/en/actions/using-workflows/reusing-workflows#limitations)
# renovate: datasource=golang-version packageName=golang
go-version: 1.23.3
go-version: 1.24.1
platforms: linux/amd64,linux/arm64,linux/s390x,linux/ppc64le
push: true
secrets:
@@ -33,20 +33,20 @@ jobs:
quay_password: ${{ secrets.RELEASE_QUAY_TOKEN }}
argocd-image-provenance:
needs: [argocd-image]
permissions:
actions: read # for detecting the Github Actions environment.
id-token: write # for creating OIDC tokens for signing.
packages: write # for uploading attestations. (https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#known-issues)
# Must be refernced by a tag. https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#referencing-the-slsa-generator
if: github.repository == 'argoproj/argo-cd'
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.0.0
with:
image: quay.io/argoproj/argocd
digest: ${{ needs.argocd-image.outputs.image-digest }}
secrets:
registry-username: ${{ secrets.RELEASE_QUAY_USERNAME }}
registry-password: ${{ secrets.RELEASE_QUAY_TOKEN }}
needs: [argocd-image]
permissions:
actions: read # for detecting the Github Actions environment.
id-token: write # for creating OIDC tokens for signing.
packages: write # for uploading attestations. (https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#known-issues)
# Must be refernced by a tag. https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#referencing-the-slsa-generator
if: github.repository == 'argoproj/argo-cd'
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.0.0
with:
image: quay.io/argoproj/argocd
digest: ${{ needs.argocd-image.outputs.image-digest }}
secrets:
registry-username: ${{ secrets.RELEASE_QUAY_USERNAME }}
registry-password: ${{ secrets.RELEASE_QUAY_TOKEN }}
goreleaser:
needs:
@@ -107,7 +107,7 @@ jobs:
- name: Generate subject for provenance
id: hash
env:
ARTIFACTS: "${{ steps.run-goreleaser.outputs.artifacts }}"
ARTIFACTS: '${{ steps.run-goreleaser.outputs.artifacts }}'
run: |
set -euo pipefail
@@ -128,8 +128,8 @@ jobs:
# Must be refernced by a tag. https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#referencing-the-slsa-generator
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0
with:
base64-subjects: "${{ needs.goreleaser.outputs.hashes }}"
provenance-name: "argocd-cli.intoto.jsonl"
base64-subjects: '${{ needs.goreleaser.outputs.hashes }}'
provenance-name: 'argocd-cli.intoto.jsonl'
upload-assets: true
generate-sbom:
@@ -164,7 +164,7 @@ jobs:
SIGS_BOM_VERSION: v0.2.1
# comma delimited list of project relative folders to inspect for package
# managers (gomod, yarn, npm).
PROJECT_FOLDERS: ".,./ui"
PROJECT_FOLDERS: '.,./ui'
# full qualified name of the docker image to be inspected
DOCKER_IMAGE: quay.io/argoproj/argocd:${{ github.ref_name }}
run: |
@@ -212,8 +212,8 @@ jobs:
# Must be referenced by a tag. https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#referencing-the-slsa-generator
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0
with:
base64-subjects: "${{ needs.generate-sbom.outputs.hashes }}"
provenance-name: "argocd-sbom.intoto.jsonl"
base64-subjects: '${{ needs.generate-sbom.outputs.hashes }}'
provenance-name: 'argocd-sbom.intoto.jsonl'
upload-assets: true
post-release:
@@ -296,7 +296,7 @@ jobs:
uses: peter-evans/create-pull-request@5e914681df9dc83aa4e4905692ca88beb2f9e91f # v7.0.5
with:
commit-message: Bump version in master
title: "chore: Bump version in master"
title: 'chore: Bump version in master'
body: All images built from master should indicate which version we are on track for.
signoff: true
branch: update-version

2
.gitpod.Dockerfile vendored
View File

@@ -1,4 +1,4 @@
FROM gitpod/workspace-full@sha256:bec45ebdcc9b9c5ec28d5c61c16bf599200aa0d2dc1e69e2ed8ab0a424bae6db
FROM gitpod/workspace-full@sha256:a47a68ee7f9da10cd889ccce4661bc73f2c0d5a98d3d087e8bdfc0230b27964c
USER root

View File

@@ -30,6 +30,7 @@ linters:
- unparam
- unused
- usestdlibvars
- usetesting
- whitespace
linters-settings:
gocritic:
@@ -66,6 +67,8 @@ linters-settings:
pkg: k8s.io/api/rbac/v1
- alias: apierrors
pkg: k8s.io/apimachinery/pkg/api/errors
- alias: apiextensionsv1
pkg: k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1
- alias: metav1
pkg: k8s.io/apimachinery/pkg/apis/meta/v1
- alias: informersv1
@@ -138,10 +141,16 @@ linters-settings:
- name: useless-break
- name: var-declaration
- name: var-naming
disabled: true
arguments:
- ["ID"]
- ["VM"]
- - skipPackageNameChecks: true
upperCaseConst: true
testifylint:
enable-all: true
disable:
- go-require
usetesting:
os-mkdir-temp: false
run:
timeout: 50m

View File

@@ -76,4 +76,7 @@ packages:
SessionServiceClient:
github.com/argoproj/argo-cd/v3/pkg/apiclient/cluster:
interfaces:
ClusterServiceServer:
ClusterServiceServer:
github.com/argoproj/argo-cd/v3/pkg/client/clientset/versioned/typed/application/v1alpha1:
interfaces:
AppProjectInterface:

View File

@@ -4,7 +4,7 @@ ARG BASE_IMAGE=docker.io/library/ubuntu:24.04@sha256:80dd3c3b9c6cecb9f1667e9290b
# Initial stage which pulls prepares build dependencies and CLI tooling we need for our final image
# Also used as the image in CI jobs so needs all dependencies
####################################################################################################
FROM docker.io/library/golang:1.23.3@sha256:d56c3e08fe5b27729ee3834854ae8f7015af48fd651cd25d1e3bcf3c19830174 AS builder
FROM docker.io/library/golang:1.24.1@sha256:c5adecdb7b3f8c5ca3c88648a861882849cc8b02fed68ece31e25de88ad13418 AS builder
RUN echo 'deb http://archive.debian.org/debian buster-backports main' >> /etc/apt/sources.list
@@ -101,7 +101,7 @@ RUN HOST_ARCH=$TARGETARCH NODE_ENV='production' NODE_ONLINE_ENV='online' NODE_OP
####################################################################################################
# Argo CD Build stage which performs the actual build of Argo CD binaries
####################################################################################################
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.23.3@sha256:d56c3e08fe5b27729ee3834854ae8f7015af48fd651cd25d1e3bcf3c19830174 AS argocd-build
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.24.1@sha256:c5adecdb7b3f8c5ca3c88648a861882849cc8b02fed68ece31e25de88ad13418 AS argocd-build
WORKDIR /go/src/github.com/argoproj/argo-cd

View File

@@ -30,7 +30,7 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Ant Group](https://www.antgroup.com/)
1. [AppDirect](https://www.appdirect.com)
1. [Arctiq Inc.](https://www.arctiq.ca)
2. [Arturia](https://www.arturia.com)
1. [Arturia](https://www.arturia.com)
1. [ARZ Allgemeines Rechenzentrum GmbH](https://www.arz.at/)
1. [Augury](https://www.augury.com/)
1. [Autodesk](https://www.autodesk.com)
@@ -147,6 +147,7 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Hazelcast](https://hazelcast.com/)
1. [Healy](https://www.healyworld.net)
1. [Helio](https://helio.exchange)
1. [hetao101](https://www.hetao101.com/)
1. [Hetki](https://hetki.ai)
1. [hipages](https://hipages.com.au/)
1. [Hiya](https://hiya.com)
@@ -376,6 +377,7 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Vinted](https://vinted.com/)
1. [Virtuo](https://www.govirtuo.com/)
1. [VISITS Technologies](https://visits.world/en)
1. [Viya](https://viya.me)
1. [Volvo Cars](https://www.volvocars.com/)
1. [Voyager Digital](https://www.investvoyager.com/)
1. [VSHN - The DevOps Company](https://vshn.ch/)
@@ -390,6 +392,7 @@ Currently, the following organizations are **officially** using Argo CD:
1. [WooliesX](https://wooliesx.com.au/)
1. [Woolworths Group](https://www.woolworthsgroup.com.au/)
1. [WSpot](https://www.wspot.com.br/)
1. [X3M ads](https://x3mads.com)
1. [Yieldlab](https://www.yieldlab.de/)
1. [Youverify](https://youverify.co/)
1. [Yubo](https://www.yubo.live/)
@@ -397,3 +400,4 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Zimpler](https://www.zimpler.com/)
1. [ZipRecuiter](https://www.ziprecruiter.com/)
1. [ZOZO](https://corp.zozo.com/)

View File

@@ -155,6 +155,7 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
// desiredApplications is the main list of all expected Applications from all generators in this appset.
desiredApplications, applicationSetReason, err := template.GenerateApplications(logCtx, applicationSetInfo, r.Generators, r.Renderer, r.Client)
if err != nil {
logCtx.Errorf("unable to generate applications: %v", err)
_ = r.setApplicationSetStatusCondition(ctx,
&applicationSetInfo,
argov1alpha1.ApplicationSetCondition{
@@ -164,7 +165,8 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
Status: argov1alpha1.ApplicationSetConditionStatusTrue,
}, parametersGenerated,
)
return ctrl.Result{RequeueAfter: ReconcileRequeueOnValidationError}, err
// In order for the controller SDK to respect RequeueAfter, the error must be nil
return ctrl.Result{RequeueAfter: ReconcileRequeueOnValidationError}, nil
}
parametersGenerated = true
@@ -768,7 +770,7 @@ func (r *ApplicationSetReconciler) deleteInCluster(ctx context.Context, logCtx *
}
// removeFinalizerOnInvalidDestination removes the Argo CD resources finalizer if the application contains an invalid target (eg missing cluster)
func (r *ApplicationSetReconciler) removeFinalizerOnInvalidDestination(ctx context.Context, applicationSet argov1alpha1.ApplicationSet, app *argov1alpha1.Application, clusterList *argov1alpha1.ClusterList, appLog *log.Entry) error {
func (r *ApplicationSetReconciler) removeFinalizerOnInvalidDestination(ctx context.Context, applicationSet argov1alpha1.ApplicationSet, app *argov1alpha1.Application, clusterList []utils.ClusterSpecifier, appLog *log.Entry) error {
// Only check if the finalizers need to be removed IF there are finalizers to remove
if len(app.Finalizers) == 0 {
return nil
@@ -783,7 +785,7 @@ func (r *ApplicationSetReconciler) removeFinalizerOnInvalidDestination(ctx conte
} else {
// Detect if the destination's server field does not match an existing cluster
matchingCluster := false
for _, cluster := range clusterList.Items {
for _, cluster := range clusterList {
if destCluster.Server != cluster.Server {
continue
}
@@ -1052,19 +1054,20 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatus(ctx con
Message: "No Application status found, defaulting status to Waiting.",
Status: "Waiting",
Step: strconv.Itoa(getAppStep(app.Name, appStepMap)),
TargetRevisions: app.Status.GetRevisions(),
}
} else {
// we have an existing AppStatus
currentAppStatus = applicationSet.Status.ApplicationStatus[idx]
// upgrade any existing AppStatus that might have been set by an older argo-cd version
// note: currentAppStatus.TargetRevisions may be set to empty list earlier during migrations,
// to prevent other usage of r.Client.Status().Update to fail before reaching here.
if len(currentAppStatus.TargetRevisions) == 0 {
currentAppStatus.TargetRevisions = app.Status.GetRevisions()
if !reflect.DeepEqual(currentAppStatus.TargetRevisions, app.Status.GetRevisions()) {
currentAppStatus.Message = "Application has pending changes, setting status to Waiting."
}
}
if !reflect.DeepEqual(currentAppStatus.TargetRevisions, app.Status.GetRevisions()) {
currentAppStatus.TargetRevisions = app.Status.GetRevisions()
currentAppStatus.Status = "Waiting"
currentAppStatus.LastTransitionTime = &now
currentAppStatus.Step = strconv.Itoa(getAppStep(currentAppStatus.Application, appStepMap))
}
appOutdated := false
if progressiveSyncsRollingSyncStrategyEnabled(applicationSet) {
@@ -1077,25 +1080,15 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatus(ctx con
currentAppStatus.Status = "Waiting"
currentAppStatus.Message = "Application has pending changes, setting status to Waiting."
currentAppStatus.Step = strconv.Itoa(getAppStep(currentAppStatus.Application, appStepMap))
currentAppStatus.TargetRevisions = app.Status.GetRevisions()
}
if currentAppStatus.Status == "Pending" {
if operationPhaseString == "Succeeded" {
revisions := []string{}
if len(app.Status.OperationState.SyncResult.Revisions) > 0 {
revisions = app.Status.OperationState.SyncResult.Revisions
} else if app.Status.OperationState.SyncResult.Revision != "" {
revisions = append(revisions, app.Status.OperationState.SyncResult.Revision)
}
if reflect.DeepEqual(currentAppStatus.TargetRevisions, revisions) {
logCtx.Infof("Application %v has completed a sync successfully, updating its ApplicationSet status to Progressing", app.Name)
currentAppStatus.LastTransitionTime = &now
currentAppStatus.Status = "Progressing"
currentAppStatus.Message = "Application resource completed a sync successfully, updating status from Pending to Progressing."
currentAppStatus.Step = strconv.Itoa(getAppStep(currentAppStatus.Application, appStepMap))
}
if !appOutdated && operationPhaseString == "Succeeded" {
logCtx.Infof("Application %v has completed a sync successfully, updating its ApplicationSet status to Progressing", app.Name)
currentAppStatus.LastTransitionTime = &now
currentAppStatus.Status = "Progressing"
currentAppStatus.Message = "Application resource completed a sync successfully, updating status from Pending to Progressing."
currentAppStatus.Step = strconv.Itoa(getAppStep(currentAppStatus.Application, appStepMap))
} else if operationPhaseString == "Running" || healthStatusString == "Progressing" {
logCtx.Infof("Application %v has entered Progressing status, updating its ApplicationSet status to Progressing", app.Name)
currentAppStatus.LastTransitionTime = &now

View File

@@ -1,7 +1,6 @@
package controllers
import (
"context"
"encoding/json"
"errors"
"fmt"
@@ -1097,12 +1096,12 @@ func TestCreateOrUpdateInCluster(t *testing.T) {
Metrics: metrics,
}
err = r.createOrUpdateInCluster(context.TODO(), log.NewEntry(log.StandardLogger()), c.appSet, c.desiredApps)
err = r.createOrUpdateInCluster(t.Context(), log.NewEntry(log.StandardLogger()), c.appSet, c.desiredApps)
require.NoError(t, err)
for _, obj := range c.expected {
got := &v1alpha1.Application{}
_ = client.Get(context.Background(), crtclient.ObjectKey{
_ = client.Get(t.Context(), crtclient.ObjectKey{
Namespace: obj.Namespace,
Name: obj.Name,
}, got)
@@ -1198,7 +1197,7 @@ func TestRemoveFinalizerOnInvalidDestination_FinalizerTypes(t *testing.T) {
kubeclientset := kubefake.NewSimpleClientset(objects...)
metrics := appsetmetrics.NewFakeAppsetMetrics()
argodb := db.NewDB("argocd", settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd"), kubeclientset)
argodb := db.NewDB("argocd", settings.NewSettingsManager(t.Context(), kubeclientset, "argocd"), kubeclientset)
r := ApplicationSetReconciler{
Client: client,
@@ -1208,18 +1207,18 @@ func TestRemoveFinalizerOnInvalidDestination_FinalizerTypes(t *testing.T) {
Metrics: metrics,
ArgoDB: argodb,
}
clusterList, err := utils.ListClusters(context.Background(), kubeclientset, "namespace")
clusterList, err := utils.ListClusters(t.Context(), kubeclientset, "namespace")
require.NoError(t, err)
appLog := log.WithFields(log.Fields{"app": app.Name, "appSet": ""})
appInputParam := app.DeepCopy()
err = r.removeFinalizerOnInvalidDestination(context.Background(), appSet, appInputParam, clusterList, appLog)
err = r.removeFinalizerOnInvalidDestination(t.Context(), appSet, appInputParam, clusterList, appLog)
require.NoError(t, err)
retrievedApp := v1alpha1.Application{}
err = client.Get(context.Background(), crtclient.ObjectKeyFromObject(&app), &retrievedApp)
err = client.Get(t.Context(), crtclient.ObjectKeyFromObject(&app), &retrievedApp)
require.NoError(t, err)
// App on the cluster should have the expected finalizers
@@ -1353,7 +1352,7 @@ func TestRemoveFinalizerOnInvalidDestination_DestinationTypes(t *testing.T) {
kubeclientset := getDefaultTestClientSet(secret)
metrics := appsetmetrics.NewFakeAppsetMetrics()
argodb := db.NewDB("argocd", settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd"), kubeclientset)
argodb := db.NewDB("argocd", settings.NewSettingsManager(t.Context(), kubeclientset, "argocd"), kubeclientset)
r := ApplicationSetReconciler{
Client: client,
@@ -1364,18 +1363,18 @@ func TestRemoveFinalizerOnInvalidDestination_DestinationTypes(t *testing.T) {
ArgoDB: argodb,
}
clusterList, err := utils.ListClusters(context.Background(), kubeclientset, "argocd")
clusterList, err := utils.ListClusters(t.Context(), kubeclientset, "argocd")
require.NoError(t, err)
appLog := log.WithFields(log.Fields{"app": app.Name, "appSet": ""})
appInputParam := app.DeepCopy()
err = r.removeFinalizerOnInvalidDestination(context.Background(), appSet, appInputParam, clusterList, appLog)
err = r.removeFinalizerOnInvalidDestination(t.Context(), appSet, appInputParam, clusterList, appLog)
require.NoError(t, err)
retrievedApp := v1alpha1.Application{}
err = client.Get(context.Background(), crtclient.ObjectKeyFromObject(&app), &retrievedApp)
err = client.Get(t.Context(), crtclient.ObjectKeyFromObject(&app), &retrievedApp)
require.NoError(t, err)
finalizerRemoved := len(retrievedApp.Finalizers) == 0
@@ -1448,11 +1447,11 @@ func TestRemoveOwnerReferencesOnDeleteAppSet(t *testing.T) {
Metrics: metrics,
}
err = r.removeOwnerReferencesOnDeleteAppSet(context.Background(), appSet)
err = r.removeOwnerReferencesOnDeleteAppSet(t.Context(), appSet)
require.NoError(t, err)
retrievedApp := v1alpha1.Application{}
err = client.Get(context.Background(), crtclient.ObjectKeyFromObject(&app), &retrievedApp)
err = client.Get(t.Context(), crtclient.ObjectKeyFromObject(&app), &retrievedApp)
require.NoError(t, err)
ownerReferencesRemoved := len(retrievedApp.OwnerReferences) == 0
@@ -1646,12 +1645,12 @@ func TestCreateApplications(t *testing.T) {
Metrics: metrics,
}
err = r.createInCluster(context.TODO(), log.NewEntry(log.StandardLogger()), c.appSet, c.apps)
err = r.createInCluster(t.Context(), log.NewEntry(log.StandardLogger()), c.appSet, c.apps)
require.NoError(t, err)
for _, obj := range c.expected {
got := &v1alpha1.Application{}
_ = client.Get(context.Background(), crtclient.ObjectKey{
_ = client.Get(t.Context(), crtclient.ObjectKey{
Namespace: obj.Namespace,
Name: obj.Name,
}, got)
@@ -1789,13 +1788,13 @@ func TestDeleteInCluster(t *testing.T) {
Metrics: metrics,
}
err = r.deleteInCluster(context.TODO(), log.NewEntry(log.StandardLogger()), c.appSet, c.desiredApps)
err = r.deleteInCluster(t.Context(), log.NewEntry(log.StandardLogger()), c.appSet, c.desiredApps)
require.NoError(t, err)
// For each of the expected objects, verify they exist on the cluster
for _, obj := range c.expected {
got := &v1alpha1.Application{}
_ = client.Get(context.Background(), crtclient.ObjectKey{
_ = client.Get(t.Context(), crtclient.ObjectKey{
Namespace: obj.Namespace,
Name: obj.Name,
}, got)
@@ -1809,7 +1808,7 @@ func TestDeleteInCluster(t *testing.T) {
// Verify each of the unexpected objs cannot be found
for _, obj := range c.notExpected {
got := &v1alpha1.Application{}
err := client.Get(context.Background(), crtclient.ObjectKey{
err := client.Get(t.Context(), crtclient.ObjectKey{
Namespace: obj.Namespace,
Name: obj.Name,
}, got)
@@ -1915,8 +1914,8 @@ func TestRequeueGeneratorFails(t *testing.T) {
},
}
res, err := r.Reconcile(context.Background(), req)
require.Error(t, err)
res, err := r.Reconcile(t.Context(), req)
require.NoError(t, err)
assert.Equal(t, ReconcileRequeueOnValidationError, res.RequeueAfter)
}
@@ -2088,7 +2087,7 @@ func TestValidateGeneratedApplications(t *testing.T) {
kubeclientset := getDefaultTestClientSet(secret)
argodb := db.NewDB("argocd", settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd"), kubeclientset)
argodb := db.NewDB("argocd", settings.NewSettingsManager(t.Context(), kubeclientset, "argocd"), kubeclientset)
r := ApplicationSetReconciler{
Client: client,
@@ -2102,7 +2101,7 @@ func TestValidateGeneratedApplications(t *testing.T) {
}
appSetInfo := v1alpha1.ApplicationSet{}
validationErrors, _ := r.validateGeneratedApplications(context.TODO(), cc.apps, appSetInfo)
validationErrors, _ := r.validateGeneratedApplications(t.Context(), cc.apps, appSetInfo)
assert.Equal(t, cc.validationErrors, validationErrors)
})
}
@@ -2153,7 +2152,7 @@ func TestReconcilerValidationProjectErrorBehaviour(t *testing.T) {
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appSet, &project).WithStatusSubresource(&appSet).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).Build()
metrics := appsetmetrics.NewFakeAppsetMetrics()
argodb := db.NewDB("argocd", settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd"), kubeclientset)
argodb := db.NewDB("argocd", settings.NewSettingsManager(t.Context(), kubeclientset, "argocd"), kubeclientset)
r := ApplicationSetReconciler{
Client: client,
@@ -2178,19 +2177,19 @@ func TestReconcilerValidationProjectErrorBehaviour(t *testing.T) {
}
// Verify that on validation error, no error is returned, but the object is requeued
res, err := r.Reconcile(context.Background(), req)
res, err := r.Reconcile(t.Context(), req)
require.NoError(t, err)
assert.Equal(t, ReconcileRequeueOnValidationError, res.RequeueAfter)
var app v1alpha1.Application
// make sure good app got created
err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "good-project"}, &app)
err = r.Client.Get(t.Context(), crtclient.ObjectKey{Namespace: "argocd", Name: "good-project"}, &app)
require.NoError(t, err)
assert.Equal(t, "good-project", app.Name)
// make sure bad app was not created
err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "bad-project"}, &app)
err = r.Client.Get(t.Context(), crtclient.ObjectKey{Namespace: "argocd", Name: "bad-project"}, &app)
require.Error(t, err)
}
@@ -2352,7 +2351,7 @@ func TestSetApplicationSetStatusCondition(t *testing.T) {
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&testCase.appset).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).WithStatusSubresource(&testCase.appset).Build()
metrics := appsetmetrics.NewFakeAppsetMetrics()
argodb := db.NewDB("argocd", settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd"), kubeclientset)
argodb := db.NewDB("argocd", settings.NewSettingsManager(t.Context(), kubeclientset, "argocd"), kubeclientset)
r := ApplicationSetReconciler{
Client: client,
@@ -2368,7 +2367,7 @@ func TestSetApplicationSetStatusCondition(t *testing.T) {
}
for _, condition := range testCase.conditions {
err = r.setApplicationSetStatusCondition(context.TODO(), &testCase.appset, condition, true)
err = r.setApplicationSetStatusCondition(t.Context(), &testCase.appset, condition, true)
require.NoError(t, err)
}
@@ -2440,7 +2439,7 @@ func applicationsUpdateSyncPolicyTest(t *testing.T, applicationsSyncPolicy v1alp
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appSet, &defaultProject).WithStatusSubresource(&appSet).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).Build()
metrics := appsetmetrics.NewFakeAppsetMetrics()
argodb := db.NewDB("argocd", settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd"), kubeclientset)
argodb := db.NewDB("argocd", settings.NewSettingsManager(t.Context(), kubeclientset, "argocd"), kubeclientset)
r := ApplicationSetReconciler{
Client: client,
@@ -2466,20 +2465,20 @@ func applicationsUpdateSyncPolicyTest(t *testing.T, applicationsSyncPolicy v1alp
}
// Verify that on validation error, no error is returned, but the object is requeued
resCreate, err := r.Reconcile(context.Background(), req)
resCreate, err := r.Reconcile(t.Context(), req)
require.NoErrorf(t, err, "Reconcile failed with error: %v", err)
assert.Equal(t, time.Duration(0), resCreate.RequeueAfter)
var app v1alpha1.Application
// make sure good app got created
err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "good-cluster"}, &app)
err = r.Client.Get(t.Context(), crtclient.ObjectKey{Namespace: "argocd", Name: "good-cluster"}, &app)
require.NoError(t, err)
assert.Equal(t, "good-cluster", app.Name)
// Update resource
var retrievedApplicationSet v1alpha1.ApplicationSet
err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "name"}, &retrievedApplicationSet)
err = r.Client.Get(t.Context(), crtclient.ObjectKey{Namespace: "argocd", Name: "name"}, &retrievedApplicationSet)
require.NoError(t, err)
retrievedApplicationSet.Spec.Template.Annotations = map[string]string{"annotation-key": "annotation-value"}
@@ -2489,13 +2488,13 @@ func applicationsUpdateSyncPolicyTest(t *testing.T, applicationsSyncPolicy v1alp
Values: "global.test: test",
}
err = r.Client.Update(context.TODO(), &retrievedApplicationSet)
err = r.Client.Update(t.Context(), &retrievedApplicationSet)
require.NoError(t, err)
resUpdate, err := r.Reconcile(context.Background(), req)
resUpdate, err := r.Reconcile(t.Context(), req)
require.NoError(t, err)
err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "good-cluster"}, &app)
err = r.Client.Get(t.Context(), crtclient.ObjectKey{Namespace: "argocd", Name: "good-cluster"}, &app)
require.NoError(t, err)
assert.Equal(t, time.Duration(0), resUpdate.RequeueAfter)
assert.Equal(t, "good-cluster", app.Name)
@@ -2615,7 +2614,7 @@ func applicationsDeleteSyncPolicyTest(t *testing.T, applicationsSyncPolicy v1alp
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appSet, &defaultProject).WithStatusSubresource(&appSet).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).Build()
metrics := appsetmetrics.NewFakeAppsetMetrics()
argodb := db.NewDB("argocd", settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd"), kubeclientset)
argodb := db.NewDB("argocd", settings.NewSettingsManager(t.Context(), kubeclientset, "argocd"), kubeclientset)
r := ApplicationSetReconciler{
Client: client,
@@ -2641,20 +2640,20 @@ func applicationsDeleteSyncPolicyTest(t *testing.T, applicationsSyncPolicy v1alp
}
// Verify that on validation error, no error is returned, but the object is requeued
resCreate, err := r.Reconcile(context.Background(), req)
resCreate, err := r.Reconcile(t.Context(), req)
require.NoError(t, err)
assert.Equal(t, time.Duration(0), resCreate.RequeueAfter)
var app v1alpha1.Application
// make sure good app got created
err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "good-cluster"}, &app)
err = r.Client.Get(t.Context(), crtclient.ObjectKey{Namespace: "argocd", Name: "good-cluster"}, &app)
require.NoError(t, err)
assert.Equal(t, "good-cluster", app.Name)
// Update resource
var retrievedApplicationSet v1alpha1.ApplicationSet
err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "name"}, &retrievedApplicationSet)
err = r.Client.Get(t.Context(), crtclient.ObjectKey{Namespace: "argocd", Name: "name"}, &retrievedApplicationSet)
require.NoError(t, err)
retrievedApplicationSet.Spec.Generators = []v1alpha1.ApplicationSetGenerator{
{
@@ -2664,15 +2663,15 @@ func applicationsDeleteSyncPolicyTest(t *testing.T, applicationsSyncPolicy v1alp
},
}
err = r.Client.Update(context.TODO(), &retrievedApplicationSet)
err = r.Client.Update(t.Context(), &retrievedApplicationSet)
require.NoError(t, err)
resUpdate, err := r.Reconcile(context.Background(), req)
resUpdate, err := r.Reconcile(t.Context(), req)
require.NoError(t, err)
var apps v1alpha1.ApplicationList
err = r.Client.List(context.TODO(), &apps)
err = r.Client.List(t.Context(), &apps)
require.NoError(t, err)
assert.Equal(t, time.Duration(0), resUpdate.RequeueAfter)
@@ -2804,7 +2803,7 @@ func TestPolicies(t *testing.T) {
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appSet, &defaultProject).WithStatusSubresource(&appSet).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).Build()
metrics := appsetmetrics.NewFakeAppsetMetrics()
argodb := db.NewDB("argocd", settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd"), kubeclientset)
argodb := db.NewDB("argocd", settings.NewSettingsManager(t.Context(), kubeclientset, "argocd"), kubeclientset)
r := ApplicationSetReconciler{
Client: client,
@@ -2829,25 +2828,25 @@ func TestPolicies(t *testing.T) {
}
// Check if Application is created
res, err := r.Reconcile(context.Background(), req)
res, err := r.Reconcile(t.Context(), req)
require.NoError(t, err)
assert.Equal(t, time.Duration(0), res.RequeueAfter)
var app v1alpha1.Application
err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "my-app"}, &app)
err = r.Client.Get(t.Context(), crtclient.ObjectKey{Namespace: "argocd", Name: "my-app"}, &app)
require.NoError(t, err)
assert.Equal(t, "value", app.Annotations["key"])
// Check if Application is updated
app.Annotations["key"] = "edited"
err = r.Client.Update(context.TODO(), &app)
err = r.Client.Update(t.Context(), &app)
require.NoError(t, err)
res, err = r.Reconcile(context.Background(), req)
res, err = r.Reconcile(t.Context(), req)
require.NoError(t, err)
assert.Equal(t, time.Duration(0), res.RequeueAfter)
err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "my-app"}, &app)
err = r.Client.Get(t.Context(), crtclient.ObjectKey{Namespace: "argocd", Name: "my-app"}, &app)
require.NoError(t, err)
if c.allowedUpdate {
@@ -2857,21 +2856,21 @@ func TestPolicies(t *testing.T) {
}
// Check if Application is deleted
err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "name"}, &appSet)
err = r.Client.Get(t.Context(), crtclient.ObjectKey{Namespace: "argocd", Name: "name"}, &appSet)
require.NoError(t, err)
appSet.Spec.Generators[0] = v1alpha1.ApplicationSetGenerator{
List: &v1alpha1.ListGenerator{
Elements: []apiextensionsv1.JSON{},
},
}
err = r.Client.Update(context.TODO(), &appSet)
err = r.Client.Update(t.Context(), &appSet)
require.NoError(t, err)
res, err = r.Reconcile(context.Background(), req)
res, err = r.Reconcile(t.Context(), req)
require.NoError(t, err)
assert.Equal(t, time.Duration(0), res.RequeueAfter)
err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "my-app"}, &app)
err = r.Client.Get(t.Context(), crtclient.ObjectKey{Namespace: "argocd", Name: "my-app"}, &app)
require.NoError(t, err)
if c.allowedDelete {
assert.NotNil(t, app.DeletionTimestamp)
@@ -2963,7 +2962,7 @@ func TestSetApplicationSetApplicationStatus(t *testing.T) {
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&cc.appSet).WithStatusSubresource(&cc.appSet).Build()
metrics := appsetmetrics.NewFakeAppsetMetrics()
argodb := db.NewDB("argocd", settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd"), kubeclientset)
argodb := db.NewDB("argocd", settings.NewSettingsManager(t.Context(), kubeclientset, "argocd"), kubeclientset)
r := ApplicationSetReconciler{
Client: client,
@@ -2978,7 +2977,7 @@ func TestSetApplicationSetApplicationStatus(t *testing.T) {
Metrics: metrics,
}
err = r.setAppSetApplicationStatus(context.TODO(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.appStatuses)
err = r.setAppSetApplicationStatus(t.Context(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.appStatuses)
require.NoError(t, err)
assert.Equal(t, cc.expectedAppStatuses, cc.appSet.Status.ApplicationStatus)
@@ -3723,7 +3722,7 @@ func TestBuildAppDependencyList(t *testing.T) {
t.Run(cc.name, func(t *testing.T) {
kubeclientset := kubefake.NewSimpleClientset([]runtime.Object{}...)
argodb := db.NewDB("argocd", settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd"), kubeclientset)
argodb := db.NewDB("argocd", settings.NewSettingsManager(t.Context(), kubeclientset, "argocd"), kubeclientset)
r := ApplicationSetReconciler{
Client: client,
@@ -4391,7 +4390,7 @@ func TestBuildAppSyncMap(t *testing.T) {
t.Run(cc.name, func(t *testing.T) {
kubeclientset := kubefake.NewSimpleClientset([]runtime.Object{}...)
argodb := db.NewDB("argocd", settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd"), kubeclientset)
argodb := db.NewDB("argocd", settings.NewSettingsManager(t.Context(), kubeclientset, "argocd"), kubeclientset)
r := ApplicationSetReconciler{
Client: client,
@@ -4749,6 +4748,9 @@ func TestUpdateApplicationSetApplicationStatus(t *testing.T) {
Health: v1alpha1.HealthStatus{
Status: health.HealthStatusProgressing,
},
Sync: v1alpha1.SyncStatus{
Revision: "Next",
},
},
},
},
@@ -4812,7 +4814,8 @@ func TestUpdateApplicationSetApplicationStatus(t *testing.T) {
Phase: common.OperationRunning,
},
Sync: v1alpha1.SyncStatus{
Status: v1alpha1.SyncStatusCodeSynced,
Status: v1alpha1.SyncStatusCodeSynced,
Revision: "Current",
},
},
},
@@ -4877,7 +4880,8 @@ func TestUpdateApplicationSetApplicationStatus(t *testing.T) {
Phase: common.OperationSucceeded,
},
Sync: v1alpha1.SyncStatus{
Status: v1alpha1.SyncStatusCodeSynced,
Status: v1alpha1.SyncStatusCodeSynced,
Revision: "Next",
},
},
},
@@ -4942,7 +4946,8 @@ func TestUpdateApplicationSetApplicationStatus(t *testing.T) {
Phase: common.OperationSucceeded,
},
Sync: v1alpha1.SyncStatus{
Status: v1alpha1.SyncStatusCodeSynced,
Revision: "Current",
Status: v1alpha1.SyncStatusCodeSynced,
},
},
},
@@ -5181,86 +5186,6 @@ func TestUpdateApplicationSetApplicationStatus(t *testing.T) {
},
},
},
{
name: "does not progresses a pending application with a successful sync triggered by controller with invalid revision to progressing",
appSet: v1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "name",
Namespace: "argocd",
},
Spec: v1alpha1.ApplicationSetSpec{
Strategy: &v1alpha1.ApplicationSetStrategy{
Type: "RollingSync",
RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{
Steps: []v1alpha1.ApplicationSetRolloutStep{
{
MatchExpressions: []v1alpha1.ApplicationMatchExpression{},
},
{
MatchExpressions: []v1alpha1.ApplicationMatchExpression{},
},
},
},
},
},
Status: v1alpha1.ApplicationSetStatus{
ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{
{
Application: "app1",
LastTransitionTime: &metav1.Time{
Time: time.Now().Add(time.Duration(-1) * time.Minute),
},
Message: "",
Status: "Pending",
Step: "1",
TargetRevisions: []string{"Next"},
},
},
},
},
apps: []v1alpha1.Application{
{
ObjectMeta: metav1.ObjectMeta{
Name: "app1",
},
Status: v1alpha1.ApplicationStatus{
Health: v1alpha1.HealthStatus{
Status: health.HealthStatusDegraded,
},
OperationState: &v1alpha1.OperationState{
Phase: common.OperationSucceeded,
StartedAt: metav1.Time{
Time: time.Now(),
},
Operation: v1alpha1.Operation{
InitiatedBy: v1alpha1.OperationInitiator{
Username: "applicationset-controller",
Automated: true,
},
},
SyncResult: &v1alpha1.SyncOperationResult{
Revision: "Previous",
},
},
Sync: v1alpha1.SyncStatus{
Status: v1alpha1.SyncStatusCodeSynced,
},
},
},
},
appStepMap: map[string]int{
"app1": 0,
},
expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{
{
Application: "app1",
Message: "",
Status: "Pending",
Step: "1",
TargetRevisions: []string{"Next"},
},
},
},
{
name: "removes the appStatus for applications that no longer exist",
appSet: v1alpha1.ApplicationSet{
@@ -5315,7 +5240,77 @@ func TestUpdateApplicationSetApplicationStatus(t *testing.T) {
Phase: common.OperationSucceeded,
},
Sync: v1alpha1.SyncStatus{
Status: v1alpha1.SyncStatusCodeSynced,
Status: v1alpha1.SyncStatusCodeSynced,
Revision: "Current",
},
},
},
},
appStepMap: map[string]int{
"app1": 0,
},
expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{
{
Application: "app1",
Message: "Application resource is already Healthy, updating status from Waiting to Healthy.",
Status: "Healthy",
Step: "1",
TargetRevisions: []string{"Current"},
},
},
},
{
name: "progresses a pending synced application with an old revision to progressing with the Current one",
appSet: v1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "name",
Namespace: "argocd",
},
Spec: v1alpha1.ApplicationSetSpec{
Strategy: &v1alpha1.ApplicationSetStrategy{
Type: "RollingSync",
RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{
Steps: []v1alpha1.ApplicationSetRolloutStep{
{
MatchExpressions: []v1alpha1.ApplicationMatchExpression{},
},
{
MatchExpressions: []v1alpha1.ApplicationMatchExpression{},
},
},
},
},
},
Status: v1alpha1.ApplicationSetStatus{
ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{
{
Application: "app1",
Message: "",
Status: "Pending",
Step: "1",
TargetRevisions: []string{"Old"},
},
},
},
},
apps: []v1alpha1.Application{
{
ObjectMeta: metav1.ObjectMeta{
Name: "app1",
},
Status: v1alpha1.ApplicationStatus{
Health: v1alpha1.HealthStatus{
Status: health.HealthStatusHealthy,
},
OperationState: &v1alpha1.OperationState{
Phase: common.OperationSucceeded,
SyncResult: &v1alpha1.SyncOperationResult{
Revision: "Current",
},
},
Sync: v1alpha1.SyncStatus{
Status: v1alpha1.SyncStatusCodeSynced,
Revisions: []string{"Current"},
},
},
},
@@ -5340,7 +5335,7 @@ func TestUpdateApplicationSetApplicationStatus(t *testing.T) {
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&cc.appSet).WithStatusSubresource(&cc.appSet).Build()
metrics := appsetmetrics.NewFakeAppsetMetrics()
argodb := db.NewDB("argocd", settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd"), kubeclientset)
argodb := db.NewDB("argocd", settings.NewSettingsManager(t.Context(), kubeclientset, "argocd"), kubeclientset)
r := ApplicationSetReconciler{
Client: client,
@@ -5352,7 +5347,7 @@ func TestUpdateApplicationSetApplicationStatus(t *testing.T) {
Metrics: metrics,
}
appStatuses, err := r.updateApplicationSetApplicationStatus(context.TODO(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.apps, cc.appStepMap)
appStatuses, err := r.updateApplicationSetApplicationStatus(t.Context(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.apps, cc.appStepMap)
// opt out of testing the LastTransitionTime is accurate
for i := range appStatuses {
@@ -6090,7 +6085,7 @@ func TestUpdateApplicationSetApplicationStatusProgress(t *testing.T) {
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&cc.appSet).WithStatusSubresource(&cc.appSet).Build()
metrics := appsetmetrics.NewFakeAppsetMetrics()
argodb := db.NewDB("argocd", settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd"), kubeclientset)
argodb := db.NewDB("argocd", settings.NewSettingsManager(t.Context(), kubeclientset, "argocd"), kubeclientset)
r := ApplicationSetReconciler{
Client: client,
@@ -6102,7 +6097,7 @@ func TestUpdateApplicationSetApplicationStatusProgress(t *testing.T) {
Metrics: metrics,
}
appStatuses, err := r.updateApplicationSetApplicationStatusProgress(context.TODO(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.appSyncMap, cc.appStepMap)
appStatuses, err := r.updateApplicationSetApplicationStatusProgress(t.Context(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.appSyncMap, cc.appStepMap)
// opt out of testing the LastTransitionTime is accurate
for i := range appStatuses {
@@ -6302,7 +6297,7 @@ func TestUpdateResourceStatus(t *testing.T) {
client := fake.NewClientBuilder().WithScheme(scheme).WithStatusSubresource(&cc.appSet).WithObjects(&cc.appSet).Build()
metrics := appsetmetrics.NewFakeAppsetMetrics()
argodb := db.NewDB("argocd", settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd"), kubeclientset)
argodb := db.NewDB("argocd", settings.NewSettingsManager(t.Context(), kubeclientset, "argocd"), kubeclientset)
r := ApplicationSetReconciler{
Client: client,
@@ -6314,7 +6309,7 @@ func TestUpdateResourceStatus(t *testing.T) {
Metrics: metrics,
}
err := r.updateResourcesStatus(context.TODO(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.apps)
err := r.updateResourcesStatus(t.Context(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.apps)
require.NoError(t, err, "expected no errors, but errors occurred")
assert.Equal(t, cc.expectedResources, cc.appSet.Status.Resources, "expected resources did not match actual")
@@ -6393,7 +6388,7 @@ func TestResourceStatusAreOrdered(t *testing.T) {
client := fake.NewClientBuilder().WithScheme(scheme).WithStatusSubresource(&cc.appSet).WithObjects(&cc.appSet).Build()
metrics := appsetmetrics.NewFakeAppsetMetrics()
argodb := db.NewDB("argocd", settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd"), kubeclientset)
argodb := db.NewDB("argocd", settings.NewSettingsManager(t.Context(), kubeclientset, "argocd"), kubeclientset)
r := ApplicationSetReconciler{
Client: client,
@@ -6405,13 +6400,13 @@ func TestResourceStatusAreOrdered(t *testing.T) {
Metrics: metrics,
}
err := r.updateResourcesStatus(context.TODO(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.apps)
err := r.updateResourcesStatus(t.Context(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.apps)
require.NoError(t, err, "expected no errors, but errors occurred")
err = r.updateResourcesStatus(context.TODO(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.apps)
err = r.updateResourcesStatus(t.Context(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.apps)
require.NoError(t, err, "expected no errors, but errors occurred")
err = r.updateResourcesStatus(context.TODO(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.apps)
err = r.updateResourcesStatus(t.Context(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.apps)
require.NoError(t, err, "expected no errors, but errors occurred")
assert.Equal(t, cc.expectedResources, cc.appSet.Status.Resources, "expected resources did not match actual")
@@ -6675,7 +6670,7 @@ func TestMigrateStatus(t *testing.T) {
Client: client,
}
err := r.migrateStatus(context.Background(), &tc.appset)
err := r.migrateStatus(t.Context(), &tc.appset)
require.NoError(t, err)
assert.Equal(t, tc.expectedStatus, tc.appset.Status)
})

View File

@@ -1,7 +1,6 @@
package controllers
import (
"context"
"testing"
argocommon "github.com/argoproj/argo-cd/v3/common"
@@ -550,7 +549,7 @@ func TestClusterEventHandler(t *testing.T) {
mockAddRateLimitingInterface := mockAddRateLimitingInterface{}
handler.queueRelatedAppGenerators(context.Background(), &mockAddRateLimitingInterface, &test.secret)
handler.queueRelatedAppGenerators(t.Context(), &mockAddRateLimitingInterface, &test.secret)
assert.ElementsMatch(t, mockAddRateLimitingInterface.addedItems, test.expectedRequests)
})

View File

@@ -1,7 +1,6 @@
package controllers
import (
"context"
"testing"
"time"
@@ -24,7 +23,7 @@ import (
func TestRequeueAfter(t *testing.T) {
mockServer := &mocks.Repos{}
ctx := context.Background()
ctx := t.Context()
scheme := runtime.NewScheme()
err := argov1alpha1.AddToScheme(scheme)
require.NoError(t, err)

View File

@@ -70,7 +70,7 @@ func (g *ClusterGenerator) GenerateParams(appSetGenerator *argoappsetv1alpha1.Ap
// - Since local clusters do not have secrets, they do not have labels to match against
ignoreLocalClusters := len(appSetGenerator.Clusters.Selector.MatchExpressions) > 0 || len(appSetGenerator.Clusters.Selector.MatchLabels) > 0
// ListCluster from Argo CD's util/db package will include the local cluster in the list of clusters
// ListCluster will include the local cluster in the list of clusters
clustersFromArgoCD, err := utils.ListClusters(g.ctx, g.clientset, g.namespace)
if err != nil {
return nil, fmt.Errorf("error listing clusters: %w", err)
@@ -93,7 +93,7 @@ func (g *ClusterGenerator) GenerateParams(appSetGenerator *argoappsetv1alpha1.Ap
logCtx.Debugf("Using flat mode = %t for cluster generator", isFlatMode)
clustersParams := make([]map[string]any, 0)
for _, cluster := range clustersFromArgoCD.Items {
for _, cluster := range clustersFromArgoCD {
// If there is a secret for this cluster, then it's a non-local cluster, so it will be
// handled by the next step.
if secretForCluster, exists := clusterSecrets[cluster.Name]; exists {

View File

@@ -315,7 +315,7 @@ func TestGenerateParams(t *testing.T) {
testCase.clientError,
}
clusterGenerator := NewClusterGenerator(context.Background(), cl, appClientset, "namespace")
clusterGenerator := NewClusterGenerator(t.Context(), cl, appClientset, "namespace")
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
@@ -853,7 +853,7 @@ func TestGenerateParamsGoTemplate(t *testing.T) {
testCase.clientError,
}
clusterGenerator := NewClusterGenerator(context.Background(), cl, appClientset, "namespace")
clusterGenerator := NewClusterGenerator(t.Context(), cl, appClientset, "namespace")
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{

View File

@@ -165,9 +165,6 @@ func (g *DuckTypeGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.A
}
log.Infof("Number of decisions found: %v", len(clusterDecisions))
// Read this outside the loop to improve performance
argoClusters := clustersFromArgoCD.Items
if len(clusterDecisions) == 0 {
log.Warningf("clusterDecisionResource status.%s missing", statusListKey)
return nil, nil
@@ -188,7 +185,7 @@ func (g *DuckTypeGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.A
found := false
for _, argoCluster := range argoClusters {
for _, argoCluster := range clustersFromArgoCD {
if argoCluster.Name == strMatchValue {
log.WithField(matchKey, argoCluster.Name).Info("matched cluster in ArgoCD")
params["name"] = argoCluster.Name

View File

@@ -1,7 +1,6 @@
package generators
import (
"context"
"errors"
"testing"
@@ -20,7 +19,7 @@ import (
)
const (
resourceApiVersion = "mallard.io/v1"
resourceAPIVersion = "mallard.io/v1"
resourceKind = "ducks"
resourceName = "quak"
)
@@ -79,7 +78,7 @@ func TestGenerateParamsForDuckType(t *testing.T) {
duckType := &unstructured.Unstructured{
Object: map[string]any{
"apiVersion": resourceApiVersion,
"apiVersion": resourceAPIVersion,
"kind": "Duck",
"metadata": map[string]any{
"name": resourceName,
@@ -101,7 +100,7 @@ func TestGenerateParamsForDuckType(t *testing.T) {
duckTypeProdOnly := &unstructured.Unstructured{
Object: map[string]any{
"apiVersion": resourceApiVersion,
"apiVersion": resourceAPIVersion,
"kind": "Duck",
"metadata": map[string]any{
"name": resourceName,
@@ -120,7 +119,7 @@ func TestGenerateParamsForDuckType(t *testing.T) {
duckTypeEmpty := &unstructured.Unstructured{
Object: map[string]any{
"apiVersion": resourceApiVersion,
"apiVersion": resourceAPIVersion,
"kind": "Duck",
"metadata": map[string]any{
"name": resourceName,
@@ -137,7 +136,7 @@ func TestGenerateParamsForDuckType(t *testing.T) {
Namespace: "namespace",
},
Data: map[string]string{
"apiVersion": resourceApiVersion,
"apiVersion": resourceAPIVersion,
"kind": resourceKind,
"statusListKey": "decisions",
"matchKey": "clusterName",
@@ -293,7 +292,7 @@ func TestGenerateParamsForDuckType(t *testing.T) {
fakeDynClient := dynfake.NewSimpleDynamicClientWithCustomListKinds(runtime.NewScheme(), gvrToListKind, testCase.resource)
duckTypeGenerator := NewDuckTypeGenerator(context.Background(), fakeDynClient, appClientset, "namespace")
duckTypeGenerator := NewDuckTypeGenerator(t.Context(), fakeDynClient, appClientset, "namespace")
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
@@ -375,7 +374,7 @@ func TestGenerateParamsForDuckTypeGoTemplate(t *testing.T) {
duckType := &unstructured.Unstructured{
Object: map[string]any{
"apiVersion": resourceApiVersion,
"apiVersion": resourceAPIVersion,
"kind": "Duck",
"metadata": map[string]any{
"name": resourceName,
@@ -397,7 +396,7 @@ func TestGenerateParamsForDuckTypeGoTemplate(t *testing.T) {
duckTypeProdOnly := &unstructured.Unstructured{
Object: map[string]any{
"apiVersion": resourceApiVersion,
"apiVersion": resourceAPIVersion,
"kind": "Duck",
"metadata": map[string]any{
"name": resourceName,
@@ -416,7 +415,7 @@ func TestGenerateParamsForDuckTypeGoTemplate(t *testing.T) {
duckTypeEmpty := &unstructured.Unstructured{
Object: map[string]any{
"apiVersion": resourceApiVersion,
"apiVersion": resourceAPIVersion,
"kind": "Duck",
"metadata": map[string]any{
"name": resourceName,
@@ -433,7 +432,7 @@ func TestGenerateParamsForDuckTypeGoTemplate(t *testing.T) {
Namespace: "namespace",
},
Data: map[string]string{
"apiVersion": resourceApiVersion,
"apiVersion": resourceAPIVersion,
"kind": resourceKind,
"statusListKey": "decisions",
"matchKey": "clusterName",
@@ -589,7 +588,7 @@ func TestGenerateParamsForDuckTypeGoTemplate(t *testing.T) {
fakeDynClient := dynfake.NewSimpleDynamicClientWithCustomListKinds(runtime.NewScheme(), gvrToListKind, testCase.resource)
duckTypeGenerator := NewDuckTypeGenerator(context.Background(), fakeDynClient, appClientset, "namespace")
duckTypeGenerator := NewDuckTypeGenerator(t.Context(), fakeDynClient, appClientset, "namespace")
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{

View File

@@ -159,16 +159,3 @@ func InterpolateGenerator(requestedGenerator *argoprojiov1alpha1.ApplicationSetG
return *interpolatedGenerator, nil
}
// Fixes https://github.com/argoproj/argo-cd/issues/11982 while ensuring backwards compatibility.
// This is only a short-term solution and should be removed in a future major version.
func dropDisabledNestedSelectors(generators []argoprojiov1alpha1.ApplicationSetNestedGenerator) bool {
var foundSelector bool
for i := range generators {
if generators[i].Selector != nil {
foundSelector = true
generators[i].Selector = nil
}
}
return foundSelector
}

View File

@@ -81,13 +81,17 @@ func (g *GitGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.Applic
verifyCommit = len(appProject.Spec.SignatureKeys) > 0 && gpg.IsGPGEnabled()
}
// If the project field is templated, we cannot resolve the project name, so we pass an empty string to the repo-server.
// This means only "globally-scoped" repo credentials can be used for such appsets.
project := resolveProjectName(appSet.Spec.Template.Spec.Project)
var err error
var res []map[string]any
switch {
case len(appSetGenerator.Git.Directories) != 0:
res, err = g.generateParamsForGitDirectories(appSetGenerator, noRevisionCache, verifyCommit, appSet.Spec.GoTemplate, appSet.Spec.GoTemplateOptions)
res, err = g.generateParamsForGitDirectories(appSetGenerator, noRevisionCache, verifyCommit, appSet.Spec.GoTemplate, project, appSet.Spec.GoTemplateOptions)
case len(appSetGenerator.Git.Files) != 0:
res, err = g.generateParamsForGitFiles(appSetGenerator, noRevisionCache, verifyCommit, appSet.Spec.GoTemplate, appSet.Spec.GoTemplateOptions)
res, err = g.generateParamsForGitFiles(appSetGenerator, noRevisionCache, verifyCommit, appSet.Spec.GoTemplate, project, appSet.Spec.GoTemplateOptions)
default:
return nil, EmptyAppSetGeneratorError
}
@@ -98,9 +102,9 @@ func (g *GitGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.Applic
return res, nil
}
func (g *GitGenerator) generateParamsForGitDirectories(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, noRevisionCache, verifyCommit bool, useGoTemplate bool, goTemplateOptions []string) ([]map[string]any, error) {
func (g *GitGenerator) generateParamsForGitDirectories(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, noRevisionCache, verifyCommit, useGoTemplate bool, project string, goTemplateOptions []string) ([]map[string]any, error) {
// Directories, not files
allPaths, err := g.repos.GetDirectories(context.TODO(), appSetGenerator.Git.RepoURL, appSetGenerator.Git.Revision, noRevisionCache, verifyCommit)
allPaths, err := g.repos.GetDirectories(context.TODO(), appSetGenerator.Git.RepoURL, appSetGenerator.Git.Revision, project, noRevisionCache, verifyCommit)
if err != nil {
return nil, fmt.Errorf("error getting directories from repo: %w", err)
}
@@ -123,11 +127,11 @@ func (g *GitGenerator) generateParamsForGitDirectories(appSetGenerator *argoproj
return res, nil
}
func (g *GitGenerator) generateParamsForGitFiles(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, noRevisionCache, verifyCommit bool, useGoTemplate bool, goTemplateOptions []string) ([]map[string]any, error) {
func (g *GitGenerator) generateParamsForGitFiles(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, noRevisionCache, verifyCommit, useGoTemplate bool, project string, goTemplateOptions []string) ([]map[string]any, error) {
// Get all files that match the requested path string, removing duplicates
allFiles := make(map[string][]byte)
for _, requestedPath := range appSetGenerator.Git.Files {
files, err := g.repos.GetFiles(context.TODO(), appSetGenerator.Git.RepoURL, appSetGenerator.Git.Revision, requestedPath.Path, noRevisionCache, verifyCommit)
files, err := g.repos.GetFiles(context.TODO(), appSetGenerator.Git.RepoURL, appSetGenerator.Git.Revision, project, requestedPath.Path, noRevisionCache, verifyCommit)
if err != nil {
return nil, err
}
@@ -303,3 +307,11 @@ func (g *GitGenerator) generateParamsFromApps(requestedApps []string, appSetGene
return res, nil
}
func resolveProjectName(project string) string {
if strings.Contains(project, "{{") {
return ""
}
return project
}

View File

@@ -10,6 +10,7 @@ import (
"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/utils/ptr"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
"github.com/argoproj/argo-cd/v3/applicationset/services/mocks"
@@ -169,11 +170,12 @@ foo:
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
params, err := (*GitGenerator)(nil).generateParamsFromGitFile(tt.args.filePath, tt.args.fileContent, tt.args.values, tt.args.useGoTemplate, tt.args.goTemplateOptions, tt.args.pathParamPrefix)
if (err != nil) != tt.wantErr {
t.Errorf("GitGenerator.generateParamsFromGitFile() error = %v, wantErr %v", err, tt.wantErr)
return
if tt.wantErr {
assert.Error(t, err, "GitGenerator.generateParamsFromGitFile()")
} else {
require.NoError(t, err)
assert.Equal(t, tt.want, params)
}
assert.Equal(t, tt.want, params)
})
}
}
@@ -198,7 +200,6 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) {
"app_3",
"p1/app4",
},
repoError: nil,
expected: []map[string]any{
{"path": "app1", "path.basename": "app1", "path.basenameNormalized": "app1", "path[0]": "app1"},
{"path": "app2", "path.basename": "app2", "path.basenameNormalized": "app2", "path[0]": "app2"},
@@ -233,7 +234,6 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) {
"p1/p2/app3",
"p1/p2/p3/app4",
},
repoError: nil,
expected: []map[string]any{
{"path": "p1/app2", "path.basename": "app2", "path[0]": "p1", "path[1]": "app2", "path.basenameNormalized": "app2"},
{"path": "p1/p2/app3", "path.basename": "app3", "path[0]": "p1", "path[1]": "p2", "path[2]": "app3", "path.basenameNormalized": "app3"},
@@ -321,7 +321,7 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) {
argoCDServiceMock := mocks.Repos{}
argoCDServiceMock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError)
argoCDServiceMock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError)
gitGenerator := NewGitGenerator(&argoCDServiceMock, "")
applicationSetInfo := v1alpha1.ApplicationSet{
@@ -622,7 +622,7 @@ func TestGitGenerateParamsFromDirectoriesGoTemplate(t *testing.T) {
argoCDServiceMock := mocks.Repos{}
argoCDServiceMock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError)
argoCDServiceMock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError)
gitGenerator := NewGitGenerator(&argoCDServiceMock, "")
applicationSetInfo := v1alpha1.ApplicationSet{
@@ -986,7 +986,7 @@ cluster:
t.Parallel()
argoCDServiceMock := mocks.Repos{}
argoCDServiceMock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).
argoCDServiceMock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).
Return(testCaseCopy.repoFileContents, testCaseCopy.repoPathsError)
gitGenerator := NewGitGenerator(&argoCDServiceMock, "")
@@ -1342,7 +1342,7 @@ cluster:
t.Parallel()
argoCDServiceMock := mocks.Repos{}
argoCDServiceMock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).
argoCDServiceMock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).
Return(testCaseCopy.repoFileContents, testCaseCopy.repoPathsError)
gitGenerator := NewGitGenerator(&argoCDServiceMock, "")
@@ -1387,6 +1387,7 @@ cluster:
func TestGitGenerator_GenerateParams(t *testing.T) {
cases := []struct {
name string
appProject v1alpha1.AppProject
directories []v1alpha1.GitDirectoryGeneratorItem
pathParamPrefix string
repoApps []string
@@ -1395,6 +1396,7 @@ func TestGitGenerator_GenerateParams(t *testing.T) {
values map[string]string
expected []map[string]any
expectedError error
expectedProject *string
appset v1alpha1.ApplicationSet
callGetDirectories bool
}{
@@ -1466,21 +1468,102 @@ func TestGitGenerator_GenerateParams(t *testing.T) {
expected: []map[string]any{{"path": "app1", "path.basename": "app1", "path.basenameNormalized": "app1", "path[0]": "app1", "values.foo": "bar"}},
expectedError: errors.New("error getting project project: appprojects.argoproj.io \"project\" not found"),
},
{
name: "Project field is not templated - verify that project is passed through to repo-server as-is",
repoApps: []string{
"app1",
},
callGetDirectories: true,
appProject: v1alpha1.AppProject{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{
Name: "project",
Namespace: "argocd",
},
},
appset: v1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "set",
Namespace: "namespace",
},
Spec: v1alpha1.ApplicationSetSpec{
Generators: []v1alpha1.ApplicationSetGenerator{{
Git: &v1alpha1.GitGenerator{
RepoURL: "RepoURL",
Revision: "Revision",
Directories: []v1alpha1.GitDirectoryGeneratorItem{{Path: "*"}},
PathParamPrefix: "",
Values: map[string]string{
"foo": "bar",
},
},
}},
Template: v1alpha1.ApplicationSetTemplate{
Spec: v1alpha1.ApplicationSpec{
Project: "project",
},
},
},
},
expected: []map[string]any{{"path": "app1", "path.basename": "app1", "path.basenameNormalized": "app1", "path[0]": "app1", "values.foo": "bar"}},
expectedProject: ptr.To("project"),
expectedError: nil,
},
{
name: "Project field is templated - verify that project is passed through to repo-server as empty string",
repoApps: []string{
"app1",
},
callGetDirectories: true,
appset: v1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "set",
Namespace: "namespace",
},
Spec: v1alpha1.ApplicationSetSpec{
Generators: []v1alpha1.ApplicationSetGenerator{{
Git: &v1alpha1.GitGenerator{
RepoURL: "RepoURL",
Revision: "Revision",
Directories: []v1alpha1.GitDirectoryGeneratorItem{{Path: "*"}},
PathParamPrefix: "",
Values: map[string]string{
"foo": "bar",
},
},
}},
Template: v1alpha1.ApplicationSetTemplate{
Spec: v1alpha1.ApplicationSpec{
Project: "{{.project}}",
},
},
},
},
expected: []map[string]any{{"path": "app1", "path.basename": "app1", "path.basenameNormalized": "app1", "path[0]": "app1", "values.foo": "bar"}},
expectedProject: ptr.To(""),
expectedError: nil,
},
}
for _, testCase := range cases {
argoCDServiceMock := mocks.Repos{}
if testCase.callGetDirectories {
argoCDServiceMock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(testCase.repoApps, testCase.repoPathsError)
var project any
if testCase.expectedProject != nil {
project = *testCase.expectedProject
} else {
project = mock.Anything
}
argoCDServiceMock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything, project, mock.Anything, mock.Anything).Return(testCase.repoApps, testCase.repoPathsError)
}
gitGenerator := NewGitGenerator(&argoCDServiceMock, "namespace")
gitGenerator := NewGitGenerator(&argoCDServiceMock, "argocd")
scheme := runtime.NewScheme()
err := v1alpha1.AddToScheme(scheme)
require.NoError(t, err)
appProject := v1alpha1.AppProject{}
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appProject).Build()
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&testCase.appProject).Build()
got, err := gitGenerator.GenerateParams(&testCase.appset.Spec.Generators[0], &testCase.appset, client)

View File

@@ -10,8 +10,6 @@ import (
"github.com/argoproj/argo-cd/v3/applicationset/utils"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
log "github.com/sirupsen/logrus"
)
var _ Generator = (*MatrixGenerator)(nil)
@@ -86,22 +84,10 @@ func (m *MatrixGenerator) getParams(appSetBaseGenerator argoprojiov1alpha1.Appli
if err != nil {
return nil, err
}
if matrixGen != nil && !appSet.Spec.ApplyNestedSelectors {
foundSelector := dropDisabledNestedSelectors(matrixGen.Generators)
if foundSelector {
log.Warnf("AppSet '%v' defines selector on nested matrix generator's generator without enabling them via 'spec.applyNestedSelectors', ignoring nested selectors", appSet.Name)
}
}
mergeGen, err := getMergeGenerator(appSetBaseGenerator)
if err != nil {
return nil, fmt.Errorf("error retrieving merge generator: %w", err)
}
if mergeGen != nil && !appSet.Spec.ApplyNestedSelectors {
foundSelector := dropDisabledNestedSelectors(mergeGen.Generators)
if foundSelector {
log.Warnf("AppSet '%v' defines selector on nested merge generator's generator without enabling them via 'spec.applyNestedSelectors', ignoring nested selectors", appSet.Name)
}
}
t, err := Transform(
argoprojiov1alpha1.ApplicationSetGenerator{

View File

@@ -1,7 +1,6 @@
package generators
import (
"context"
"testing"
"time"
@@ -644,7 +643,7 @@ func TestInterpolatedMatrixGenerate(t *testing.T) {
fakeClient,
testCase.clientError,
}
clusterGenerator := NewClusterGenerator(context.Background(), cl, appClientset, "namespace")
clusterGenerator := NewClusterGenerator(t.Context(), cl, appClientset, "namespace")
for _, g := range testCaseCopy.baseGenerators {
gitGeneratorSpec := v1alpha1.ApplicationSetGenerator{
@@ -827,7 +826,7 @@ func TestInterpolatedMatrixGenerateGoTemplate(t *testing.T) {
fakeClient,
testCase.clientError,
}
clusterGenerator := NewClusterGenerator(context.Background(), cl, appClientset, "namespace")
clusterGenerator := NewClusterGenerator(t.Context(), cl, appClientset, "namespace")
for _, g := range testCaseCopy.baseGenerators {
gitGeneratorSpec := v1alpha1.ApplicationSetGenerator{
@@ -1087,7 +1086,7 @@ func TestGitGenerator_GenerateParams_list_x_git_matrix_generator(t *testing.T) {
}
repoServiceMock := &mocks.Repos{}
repoServiceMock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(map[string][]byte{
repoServiceMock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(map[string][]byte{
"some/path.json": []byte("test: content"),
}, nil)
gitGenerator := NewGitGenerator(repoServiceMock, "")

View File

@@ -11,8 +11,6 @@ import (
"github.com/argoproj/argo-cd/v3/applicationset/utils"
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
log "github.com/sirupsen/logrus"
)
var _ Generator = (*MergeGenerator)(nil)
@@ -124,11 +122,11 @@ func getParamSetsByMergeKey(mergeKeys []string, paramSets []map[string]any) (map
for mergeKey := range deDuplicatedMergeKeys {
paramSetKey[mergeKey] = paramSet[mergeKey]
}
paramSetKeyJson, err := json.Marshal(paramSetKey)
paramSetKeyJSON, err := json.Marshal(paramSetKey)
if err != nil {
return nil, fmt.Errorf("error marshalling param set key json: %w", err)
}
paramSetKeyString := string(paramSetKeyJson)
paramSetKeyString := string(paramSetKeyJSON)
if _, exists := paramSetsByMergeKey[paramSetKeyString]; exists {
return nil, fmt.Errorf("%w. Duplicate key was %s", ErrNonUniqueParamSets, paramSetKeyString)
}
@@ -144,22 +142,10 @@ func (m *MergeGenerator) getParams(appSetBaseGenerator argoprojiov1alpha1.Applic
if err != nil {
return nil, err
}
if matrixGen != nil && !appSet.Spec.ApplyNestedSelectors {
foundSelector := dropDisabledNestedSelectors(matrixGen.Generators)
if foundSelector {
log.Warnf("AppSet '%v' defines selector on nested matrix generator's generator without enabling them via 'spec.applyNestedSelectors', ignoring nested selector", appSet.Name)
}
}
mergeGen, err := getMergeGenerator(appSetBaseGenerator)
if err != nil {
return nil, err
}
if mergeGen != nil && !appSet.Spec.ApplyNestedSelectors {
foundSelector := dropDisabledNestedSelectors(mergeGen.Generators)
if foundSelector {
log.Warnf("AppSet '%v' defines selector on nested merge generator's generator without enabling them via 'spec.applyNestedSelectors', ignoring nested selector", appSet.Name)
}
}
t, err := Transform(
argoprojiov1alpha1.ApplicationSetGenerator{

View File

@@ -39,12 +39,12 @@ func getTerminalListGeneratorMultiple(jsons []string) argoprojiov1alpha1.Applica
func listOfMapsToSet(maps []map[string]any) (map[string]bool, error) {
set := make(map[string]bool, len(maps))
for _, paramMap := range maps {
paramMapAsJson, err := json.Marshal(paramMap)
paramMapAsJSON, err := json.Marshal(paramMap)
if err != nil {
return nil, err
}
set[string(paramMapAsJson)] = false
set[string(paramMapAsJSON)] = false
}
return set, nil
}

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.43.2. DO NOT EDIT.
// Code generated by mockery v2.52.4. DO NOT EDIT.
package mocks

View File

@@ -193,8 +193,8 @@ func (g *PluginGenerator) getConfigMap(ctx context.Context, configMapRef string)
return nil, err
}
baseUrl, ok := cm.Data["baseUrl"]
if !ok || baseUrl == "" {
baseURL, ok := cm.Data["baseUrl"]
if !ok || baseURL == "" {
return nil, errors.New("baseUrl not found in ConfigMap")
}

View File

@@ -1,7 +1,6 @@
package generators
import (
"context"
"encoding/json"
"errors"
"fmt"
@@ -629,7 +628,7 @@ func TestPluginGenerateParams(t *testing.T) {
},
}
ctx := context.Background()
ctx := t.Context()
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
@@ -691,11 +690,11 @@ func TestPluginGenerateParams(t *testing.T) {
require.EqualError(t, err, testCase.expectedError.Error())
} else {
require.NoError(t, err)
expectedJson, err := json.Marshal(testCase.expected)
expectedJSON, err := json.Marshal(testCase.expected)
require.NoError(t, err)
gotJson, err := json.Marshal(got)
gotJSON, err := json.Marshal(got)
require.NoError(t, err)
assert.JSONEq(t, string(expectedJson), string(gotJson))
assert.JSONEq(t, string(expectedJSON), string(gotJSON))
}
})
}

View File

@@ -109,6 +109,11 @@ func (g *PullRequestGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha
"author": pull.Author,
}
err := appendTemplatedValues(appSetGenerator.PullRequest.Values, paramMap, applicationSetInfo.Spec.GoTemplate, applicationSetInfo.Spec.GoTemplateOptions)
if err != nil {
return nil, fmt.Errorf("failed to append templated values: %w", err)
}
// PR lables will only be supported for Go Template appsets, since fasttemplate will be deprecated.
if applicationSetInfo != nil && applicationSetInfo.Spec.GoTemplate {
paramMap["labels"] = pull.Labels

View File

@@ -14,9 +14,10 @@ import (
)
func TestPullRequestGithubGenerateParams(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
cases := []struct {
selectFunc func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error)
values map[string]string
expected []map[string]any
expectedErr error
applicationSet argoprojiov1alpha1.ApplicationSet
@@ -120,6 +121,45 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
},
expectedErr: nil,
},
{
selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) {
return pullrequest.NewFakeService(
ctx,
[]*pullrequest.PullRequest{
{
Number: 1,
Title: "title1",
Branch: "my_branch",
TargetBranch: "master",
HeadSHA: "abcd",
Author: "testName",
},
},
nil,
)
},
values: map[string]string{
"foo": "bar",
"pr_branch": "{{ branch }}",
},
expected: []map[string]any{
{
"number": "1",
"title": "title1",
"branch": "my_branch",
"branch_slug": "my-branch",
"target_branch": "master",
"target_branch_slug": "master",
"head_sha": "abcd",
"head_short_sha": "abcd",
"head_short_sha_7": "abcd",
"author": "testName",
"values.foo": "bar",
"values.pr_branch": "my_branch",
},
},
expectedErr: nil,
},
{
selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) {
return pullrequest.NewFakeService(
@@ -219,12 +259,14 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
selectServiceProviderFunc: c.selectFunc,
}
generatorConfig := argoprojiov1alpha1.ApplicationSetGenerator{
PullRequest: &argoprojiov1alpha1.PullRequestGenerator{},
PullRequest: &argoprojiov1alpha1.PullRequestGenerator{
Values: c.values,
},
}
got, gotErr := gen.GenerateParams(&generatorConfig, &c.applicationSet, nil)
if c.expectedErr != nil {
assert.Equal(t, c.expectedErr.Error(), gotErr.Error())
require.EqualError(t, gotErr, c.expectedErr.Error())
} else {
require.NoError(t, gotErr)
}

View File

@@ -1,5 +1,5 @@
package generators
type SCMGeneratorWithCustomApiUrl interface {
type SCMGeneratorWithCustomApiUrl interface { //nolint:revive //FIXME(var-naming)
CustomApiUrl() string
}

View File

@@ -10,6 +10,7 @@ import (
argoappv1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
applisters "github.com/argoproj/argo-cd/v3/pkg/client/listers/application/v1alpha1"
metricsutil "github.com/argoproj/argo-cd/v3/util/metrics"
"github.com/argoproj/argo-cd/v3/util/metrics/kubectl"
)
var (
@@ -57,6 +58,10 @@ func NewApplicationsetMetrics(appsetLister applisters.ApplicationSetLister, apps
metrics.Registry.MustRegister(reconcileHistogram)
metrics.Registry.MustRegister(appsetCollector)
kubectlMetricsServer := kubectl.NewKubectlMetrics()
kubectlMetricsServer.RegisterWithClientGo()
kubectl.RegisterWithPrometheus(metrics.Registry)
return ApplicationsetMetrics{
reconcileHistogram: reconcileHistogram,
}

View File

@@ -2,7 +2,6 @@ package http
import (
"bytes"
"context"
"errors"
"fmt"
"io"
@@ -118,7 +117,7 @@ func TestClientDo(t *testing.T) {
client, err := NewClient(cc.fakeServer.URL, cc.clientOptionFns...)
require.NoError(t, err, "NewClient returned unexpected error")
req, err := client.NewRequestWithContext(context.Background(), http.MethodPost, "", cc.params)
req, err := client.NewRequestWithContext(t.Context(), http.MethodPost, "", cc.params)
require.NoError(t, err, "NewRequest returned unexpected error")
var data []map[string]any

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.43.2. DO NOT EDIT.
// Code generated by mockery v2.52.4. DO NOT EDIT.
package mocks
@@ -13,9 +13,9 @@ type Repos struct {
mock.Mock
}
// GetDirectories provides a mock function with given fields: ctx, repoURL, revision, noRevisionCache, verifyCommit
func (_m *Repos) GetDirectories(ctx context.Context, repoURL string, revision string, noRevisionCache bool, verifyCommit bool) ([]string, error) {
ret := _m.Called(ctx, repoURL, revision, noRevisionCache, verifyCommit)
// GetDirectories provides a mock function with given fields: ctx, repoURL, revision, project, noRevisionCache, verifyCommit
func (_m *Repos) GetDirectories(ctx context.Context, repoURL string, revision string, project string, noRevisionCache bool, verifyCommit bool) ([]string, error) {
ret := _m.Called(ctx, repoURL, revision, project, noRevisionCache, verifyCommit)
if len(ret) == 0 {
panic("no return value specified for GetDirectories")
@@ -23,19 +23,19 @@ func (_m *Repos) GetDirectories(ctx context.Context, repoURL string, revision st
var r0 []string
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string, string, bool, bool) ([]string, error)); ok {
return rf(ctx, repoURL, revision, noRevisionCache, verifyCommit)
if rf, ok := ret.Get(0).(func(context.Context, string, string, string, bool, bool) ([]string, error)); ok {
return rf(ctx, repoURL, revision, project, noRevisionCache, verifyCommit)
}
if rf, ok := ret.Get(0).(func(context.Context, string, string, bool, bool) []string); ok {
r0 = rf(ctx, repoURL, revision, noRevisionCache, verifyCommit)
if rf, ok := ret.Get(0).(func(context.Context, string, string, string, bool, bool) []string); ok {
r0 = rf(ctx, repoURL, revision, project, noRevisionCache, verifyCommit)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]string)
}
}
if rf, ok := ret.Get(1).(func(context.Context, string, string, bool, bool) error); ok {
r1 = rf(ctx, repoURL, revision, noRevisionCache, verifyCommit)
if rf, ok := ret.Get(1).(func(context.Context, string, string, string, bool, bool) error); ok {
r1 = rf(ctx, repoURL, revision, project, noRevisionCache, verifyCommit)
} else {
r1 = ret.Error(1)
}
@@ -43,9 +43,9 @@ func (_m *Repos) GetDirectories(ctx context.Context, repoURL string, revision st
return r0, r1
}
// GetFiles provides a mock function with given fields: ctx, repoURL, revision, pattern, noRevisionCache, verifyCommit
func (_m *Repos) GetFiles(ctx context.Context, repoURL string, revision string, pattern string, noRevisionCache bool, verifyCommit bool) (map[string][]byte, error) {
ret := _m.Called(ctx, repoURL, revision, pattern, noRevisionCache, verifyCommit)
// GetFiles provides a mock function with given fields: ctx, repoURL, revision, project, pattern, noRevisionCache, verifyCommit
func (_m *Repos) GetFiles(ctx context.Context, repoURL string, revision string, project string, pattern string, noRevisionCache bool, verifyCommit bool) (map[string][]byte, error) {
ret := _m.Called(ctx, repoURL, revision, project, pattern, noRevisionCache, verifyCommit)
if len(ret) == 0 {
panic("no return value specified for GetFiles")
@@ -53,19 +53,19 @@ func (_m *Repos) GetFiles(ctx context.Context, repoURL string, revision string,
var r0 map[string][]byte
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string, string, string, bool, bool) (map[string][]byte, error)); ok {
return rf(ctx, repoURL, revision, pattern, noRevisionCache, verifyCommit)
if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, bool, bool) (map[string][]byte, error)); ok {
return rf(ctx, repoURL, revision, project, pattern, noRevisionCache, verifyCommit)
}
if rf, ok := ret.Get(0).(func(context.Context, string, string, string, bool, bool) map[string][]byte); ok {
r0 = rf(ctx, repoURL, revision, pattern, noRevisionCache, verifyCommit)
if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, bool, bool) map[string][]byte); ok {
r0 = rf(ctx, repoURL, revision, project, pattern, noRevisionCache, verifyCommit)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(map[string][]byte)
}
}
if rf, ok := ret.Get(1).(func(context.Context, string, string, string, bool, bool) error); ok {
r1 = rf(ctx, repoURL, revision, pattern, noRevisionCache, verifyCommit)
if rf, ok := ret.Get(1).(func(context.Context, string, string, string, string, bool, bool) error); ok {
r1 = rf(ctx, repoURL, revision, project, pattern, noRevisionCache, verifyCommit)
} else {
r1 = ret.Error(1)
}

View File

@@ -1,7 +1,6 @@
package plugin
import (
"context"
"encoding/json"
"fmt"
"net/http"
@@ -34,7 +33,7 @@ func TestPlugin(t *testing.T) {
client, err := NewPluginService("plugin-test", ts.URL, token, 0)
require.NoError(t, err)
data, err := client.List(context.Background(), nil)
data, err := client.List(t.Context(), nil)
require.NoError(t, err)
var expectedData ServiceResponse

View File

@@ -42,13 +42,13 @@ var (
)
func NewAzureDevOpsService(token, url, organization, project, repo string, labels []string) (PullRequestService, error) {
organizationUrl := buildURL(url, organization)
organizationURL := buildURL(url, organization)
var connection *azuredevops.Connection
if token == "" {
connection = azuredevops.NewAnonymousConnection(organizationUrl)
connection = azuredevops.NewAnonymousConnection(organizationURL)
} else {
connection = azuredevops.NewPatConnection(organizationUrl, token)
connection = azuredevops.NewPatConnection(organizationURL, token)
}
return &AzureDevOpsService{

View File

@@ -61,20 +61,20 @@ func (m *AzureClientFactoryMock) GetClient(ctx context.Context) (git.Client, err
func TestListPullRequest(t *testing.T) {
teamProject := "myorg_project"
repoName := "myorg_project_repo"
pr_id := 123
pr_title := "feat(123)"
pr_head_sha := "cd4973d9d14a08ffe6b641a89a68891d6aac8056"
ctx := context.Background()
prID := 123
prTitle := "feat(123)"
prHeadSha := "cd4973d9d14a08ffe6b641a89a68891d6aac8056"
ctx := t.Context()
uniqueName := "testName"
pullRequestMock := []git.GitPullRequest{
{
PullRequestId: createIntPtr(pr_id),
Title: createStringPtr(pr_title),
PullRequestId: createIntPtr(prID),
Title: createStringPtr(prTitle),
SourceRefName: createStringPtr("refs/heads/feature-branch"),
TargetRefName: createStringPtr("refs/heads/main"),
LastMergeSourceCommit: &git.GitCommitRef{
CommitId: createStringPtr(pr_head_sha),
CommitId: createStringPtr(prHeadSha),
},
Labels: &[]core.WebApiTagDefinition{},
Repository: &git.GitRepository{
@@ -108,9 +108,9 @@ func TestListPullRequest(t *testing.T) {
assert.Len(t, list, 1)
assert.Equal(t, "feature-branch", list[0].Branch)
assert.Equal(t, "main", list[0].TargetBranch)
assert.Equal(t, pr_head_sha, list[0].HeadSHA)
assert.Equal(t, prHeadSha, list[0].HeadSHA)
assert.Equal(t, "feat(123)", list[0].Title)
assert.Equal(t, pr_id, list[0].Number)
assert.Equal(t, prID, list[0].Number)
assert.Equal(t, uniqueName, list[0].Author)
}

View File

@@ -52,7 +52,7 @@ type PullRequestResponse struct {
var _ PullRequestService = (*BitbucketCloudService)(nil)
func parseUrl(uri string) (*url.URL, error) {
func parseURL(uri string) (*url.URL, error) {
if uri == "" {
uri = "https://api.bitbucket.org/2.0"
}
@@ -65,10 +65,10 @@ func parseUrl(uri string) (*url.URL, error) {
return url, nil
}
func NewBitbucketCloudServiceBasicAuth(baseUrl, username, password, owner, repositorySlug string) (PullRequestService, error) {
url, err := parseUrl(baseUrl)
func NewBitbucketCloudServiceBasicAuth(baseURL, username, password, owner, repositorySlug string) (PullRequestService, error) {
url, err := parseURL(baseURL)
if err != nil {
return nil, fmt.Errorf("error parsing base url of %s for %s/%s: %w", baseUrl, owner, repositorySlug, err)
return nil, fmt.Errorf("error parsing base url of %s for %s/%s: %w", baseURL, owner, repositorySlug, err)
}
bitbucketClient := bitbucket.NewBasicAuth(username, password)
@@ -81,10 +81,10 @@ func NewBitbucketCloudServiceBasicAuth(baseUrl, username, password, owner, repos
}, nil
}
func NewBitbucketCloudServiceBearerToken(baseUrl, bearerToken, owner, repositorySlug string) (PullRequestService, error) {
url, err := parseUrl(baseUrl)
func NewBitbucketCloudServiceBearerToken(baseURL, bearerToken, owner, repositorySlug string) (PullRequestService, error) {
url, err := parseURL(baseURL)
if err != nil {
return nil, fmt.Errorf("error parsing base url of %s for %s/%s: %w", baseUrl, owner, repositorySlug, err)
return nil, fmt.Errorf("error parsing base url of %s for %s/%s: %w", baseURL, owner, repositorySlug, err)
}
bitbucketClient := bitbucket.NewOAuthbearerToken(bearerToken)
@@ -97,9 +97,9 @@ func NewBitbucketCloudServiceBearerToken(baseUrl, bearerToken, owner, repository
}, nil
}
func NewBitbucketCloudServiceNoAuth(baseUrl, owner, repositorySlug string) (PullRequestService, error) {
func NewBitbucketCloudServiceNoAuth(baseURL, owner, repositorySlug string) (PullRequestService, error) {
// There is currently no method to explicitly not require auth
return NewBitbucketCloudServiceBearerToken(baseUrl, "", owner, repositorySlug)
return NewBitbucketCloudServiceBearerToken(baseURL, "", owner, repositorySlug)
}
func (b *BitbucketCloudService) List(_ context.Context) ([]*PullRequest, error) {

View File

@@ -1,7 +1,6 @@
package pull_request
import (
"context"
"fmt"
"io"
"net/http"
@@ -54,11 +53,11 @@ func defaultHandlerCloud(t *testing.T) func(http.ResponseWriter, *http.Request)
}
func TestParseUrlEmptyUrl(t *testing.T) {
url, err := parseUrl("")
bitbucketUrl, _ := url.Parse("https://api.bitbucket.org/2.0")
url, err := parseURL("")
bitbucketURL, _ := url.Parse("https://api.bitbucket.org/2.0")
require.NoError(t, err)
assert.Equal(t, bitbucketUrl, url)
assert.Equal(t, bitbucketURL, url)
}
func TestInvalidBaseUrlBasicAuthCloud(t *testing.T) {
@@ -87,7 +86,7 @@ func TestListPullRequestBearerTokenCloud(t *testing.T) {
defer ts.Close()
svc, err := NewBitbucketCloudServiceBearerToken(ts.URL, "TOKEN", "OWNER", "REPO")
require.NoError(t, err)
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
require.NoError(t, err)
assert.Len(t, pullRequests, 1)
assert.Equal(t, 101, pullRequests[0].Number)
@@ -105,7 +104,7 @@ func TestListPullRequestNoAuthCloud(t *testing.T) {
defer ts.Close()
svc, err := NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO")
require.NoError(t, err)
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
require.NoError(t, err)
assert.Len(t, pullRequests, 1)
assert.Equal(t, 101, pullRequests[0].Number)
@@ -123,7 +122,7 @@ func TestListPullRequestBasicAuthCloud(t *testing.T) {
defer ts.Close()
svc, err := NewBitbucketCloudServiceBasicAuth(ts.URL, "user", "password", "OWNER", "REPO")
require.NoError(t, err)
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
require.NoError(t, err)
assert.Len(t, pullRequests, 1)
assert.Equal(t, 101, pullRequests[0].Number)
@@ -214,7 +213,7 @@ func TestListPullRequestPaginationCloud(t *testing.T) {
defer ts.Close()
svc, err := NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO")
require.NoError(t, err)
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
require.NoError(t, err)
assert.Len(t, pullRequests, 3)
assert.Equal(t, PullRequest{
@@ -246,7 +245,7 @@ func TestListResponseErrorCloud(t *testing.T) {
}))
defer ts.Close()
svc, _ := NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO")
_, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
_, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
require.Error(t, err)
}
@@ -270,7 +269,7 @@ func TestListResponseMalformedCloud(t *testing.T) {
}))
defer ts.Close()
svc, _ := NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO")
_, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
_, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
require.Error(t, err)
}
@@ -294,7 +293,7 @@ func TestListResponseMalformedValuesCloud(t *testing.T) {
}))
defer ts.Close()
svc, _ := NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO")
_, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
_, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
require.Error(t, err)
}
@@ -319,7 +318,7 @@ func TestListResponseEmptyCloud(t *testing.T) {
defer ts.Close()
svc, err := NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO")
require.NoError(t, err)
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
require.NoError(t, err)
assert.Empty(t, pullRequests)
}
@@ -406,7 +405,7 @@ func TestListPullRequestBranchMatchCloud(t *testing.T) {
regexp := `feature-1[\d]{2}`
svc, err := NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO")
require.NoError(t, err)
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{
pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{
{
BranchMatch: &regexp,
},
@@ -431,7 +430,7 @@ func TestListPullRequestBranchMatchCloud(t *testing.T) {
regexp = `.*2$`
svc, err = NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO")
require.NoError(t, err)
pullRequests, err = ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{
pullRequests, err = ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{
{
BranchMatch: &regexp,
},
@@ -449,7 +448,7 @@ func TestListPullRequestBranchMatchCloud(t *testing.T) {
regexp = `[\d{2}`
svc, err = NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO")
require.NoError(t, err)
_, err = ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{
_, err = ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{
{
BranchMatch: &regexp,
},

View File

@@ -1,7 +1,6 @@
package pull_request
import (
"context"
"crypto/x509"
"encoding/pem"
"io"
@@ -64,9 +63,9 @@ func TestListPullRequestNoAuth(t *testing.T) {
defaultHandler(t)(w, r)
}))
defer ts.Close()
svc, err := NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO", "", false, nil)
svc, err := NewBitbucketServiceNoAuth(t.Context(), ts.URL, "PROJECT", "REPO", "", false, nil)
require.NoError(t, err)
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
require.NoError(t, err)
assert.Len(t, pullRequests, 1)
assert.Equal(t, 101, pullRequests[0].Number)
@@ -165,9 +164,9 @@ func TestListPullRequestPagination(t *testing.T) {
}
}))
defer ts.Close()
svc, err := NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO", "", false, nil)
svc, err := NewBitbucketServiceNoAuth(t.Context(), ts.URL, "PROJECT", "REPO", "", false, nil)
require.NoError(t, err)
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
require.NoError(t, err)
assert.Len(t, pullRequests, 3)
assert.Equal(t, PullRequest{
@@ -207,9 +206,9 @@ func TestListPullRequestBasicAuth(t *testing.T) {
defaultHandler(t)(w, r)
}))
defer ts.Close()
svc, err := NewBitbucketServiceBasicAuth(context.Background(), "user", "password", ts.URL, "PROJECT", "REPO", "", false, nil)
svc, err := NewBitbucketServiceBasicAuth(t.Context(), "user", "password", ts.URL, "PROJECT", "REPO", "", false, nil)
require.NoError(t, err)
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
require.NoError(t, err)
assert.Len(t, pullRequests, 1)
assert.Equal(t, 101, pullRequests[0].Number)
@@ -224,9 +223,9 @@ func TestListPullRequestBearerAuth(t *testing.T) {
defaultHandler(t)(w, r)
}))
defer ts.Close()
svc, err := NewBitbucketServiceBearerToken(context.Background(), "tolkien", ts.URL, "PROJECT", "REPO", "", false, nil)
svc, err := NewBitbucketServiceBearerToken(t.Context(), "tolkien", ts.URL, "PROJECT", "REPO", "", false, nil)
require.NoError(t, err)
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
require.NoError(t, err)
assert.Len(t, pullRequests, 1)
assert.Equal(t, 101, pullRequests[0].Number)
@@ -290,9 +289,9 @@ func TestListPullRequestTLS(t *testing.T) {
}
}
svc, err := NewBitbucketServiceBasicAuth(context.Background(), "user", "password", ts.URL, "PROJECT", "REPO", "", test.tlsInsecure, certs)
svc, err := NewBitbucketServiceBasicAuth(t.Context(), "user", "password", ts.URL, "PROJECT", "REPO", "", test.tlsInsecure, certs)
require.NoError(t, err)
_, err = ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
_, err = ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
if test.requireErr {
require.Error(t, err)
} else {
@@ -307,8 +306,8 @@ func TestListResponseError(t *testing.T) {
w.WriteHeader(http.StatusInternalServerError)
}))
defer ts.Close()
svc, _ := NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO", "", false, nil)
_, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
svc, _ := NewBitbucketServiceNoAuth(t.Context(), ts.URL, "PROJECT", "REPO", "", false, nil)
_, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
require.Error(t, err)
}
@@ -332,8 +331,8 @@ func TestListResponseMalformed(t *testing.T) {
}
}))
defer ts.Close()
svc, _ := NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO", "", false, nil)
_, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
svc, _ := NewBitbucketServiceNoAuth(t.Context(), ts.URL, "PROJECT", "REPO", "", false, nil)
_, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
require.Error(t, err)
}
@@ -357,9 +356,9 @@ func TestListResponseEmpty(t *testing.T) {
}
}))
defer ts.Close()
svc, err := NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO", "", false, nil)
svc, err := NewBitbucketServiceNoAuth(t.Context(), ts.URL, "PROJECT", "REPO", "", false, nil)
require.NoError(t, err)
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{})
pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{})
require.NoError(t, err)
assert.Empty(t, pullRequests)
}
@@ -453,9 +452,9 @@ func TestListPullRequestBranchMatch(t *testing.T) {
}))
defer ts.Close()
regexp := `feature-1[\d]{2}`
svc, err := NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO", "", false, nil)
svc, err := NewBitbucketServiceNoAuth(t.Context(), ts.URL, "PROJECT", "REPO", "", false, nil)
require.NoError(t, err)
pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{
pullRequests, err := ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{
{
BranchMatch: &regexp,
},
@@ -482,9 +481,9 @@ func TestListPullRequestBranchMatch(t *testing.T) {
}, *pullRequests[1])
regexp = `.*2$`
svc, err = NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO", "", false, nil)
svc, err = NewBitbucketServiceNoAuth(t.Context(), ts.URL, "PROJECT", "REPO", "", false, nil)
require.NoError(t, err)
pullRequests, err = ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{
pullRequests, err = ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{
{
BranchMatch: &regexp,
},
@@ -502,9 +501,9 @@ func TestListPullRequestBranchMatch(t *testing.T) {
}, *pullRequests[0])
regexp = `[\d{2}`
svc, err = NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO", "", false, nil)
svc, err = NewBitbucketServiceNoAuth(t.Context(), ts.URL, "PROJECT", "REPO", "", false, nil)
require.NoError(t, err)
_, err = ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{
_, err = ListPullRequests(t.Context(), svc, []v1alpha1.PullRequestGeneratorFilter{
{
BranchMatch: &regexp,
},

View File

@@ -1,7 +1,6 @@
package pull_request
import (
"context"
"fmt"
"io"
"net/http"
@@ -253,7 +252,7 @@ func TestGiteaList(t *testing.T) {
}))
host, err := NewGiteaService("", ts.URL, "test-argocd", "pr-test", false)
require.NoError(t, err)
prs, err := host.List(context.Background())
prs, err := host.List(t.Context())
require.NoError(t, err)
assert.Len(t, prs, 1)
assert.Equal(t, 1, prs[0].Number)

View File

@@ -1,7 +1,6 @@
package pull_request
import (
"context"
"crypto/x509"
"encoding/pem"
"io"
@@ -38,7 +37,7 @@ func TestGitLabServiceCustomBaseURL(t *testing.T) {
svc, err := NewGitLabService("", server.URL, "278964", nil, "", "", false, nil)
require.NoError(t, err)
_, err = svc.List(context.Background())
_, err = svc.List(t.Context())
require.NoError(t, err)
}
@@ -57,7 +56,7 @@ func TestGitLabServiceToken(t *testing.T) {
svc, err := NewGitLabService("token-123", server.URL, "278964", nil, "", "", false, nil)
require.NoError(t, err)
_, err = svc.List(context.Background())
_, err = svc.List(t.Context())
require.NoError(t, err)
}
@@ -76,7 +75,7 @@ func TestList(t *testing.T) {
svc, err := NewGitLabService("", server.URL, "278964", []string{}, "", "", false, nil)
require.NoError(t, err)
prs, err := svc.List(context.Background())
prs, err := svc.List(t.Context())
require.NoError(t, err)
assert.Len(t, prs, 1)
assert.Equal(t, 15442, prs[0].Number)
@@ -102,7 +101,7 @@ func TestListWithLabels(t *testing.T) {
svc, err := NewGitLabService("", server.URL, "278964", []string{"feature", "ready"}, "", "", false, nil)
require.NoError(t, err)
_, err = svc.List(context.Background())
_, err = svc.List(t.Context())
require.NoError(t, err)
}
@@ -121,7 +120,7 @@ func TestListWithState(t *testing.T) {
svc, err := NewGitLabService("", server.URL, "278964", []string{}, "opened", "", false, nil)
require.NoError(t, err)
_, err = svc.List(context.Background())
_, err = svc.List(t.Context())
require.NoError(t, err)
}
@@ -183,7 +182,7 @@ func TestListWithStateTLS(t *testing.T) {
svc, err := NewGitLabService("", ts.URL, "278964", []string{}, "opened", "", test.tlsInsecure, certs)
require.NoError(t, err)
_, err = svc.List(context.Background())
_, err = svc.List(t.Context())
if test.requireErr {
require.Error(t, err)
} else {

View File

@@ -1,7 +1,6 @@
package pull_request
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
@@ -16,7 +15,7 @@ func strp(s string) *string {
func TestFilterBranchMatchBadRegexp(t *testing.T) {
provider, _ := NewFakeService(
context.Background(),
t.Context(),
[]*PullRequest{
{
Number: 1,
@@ -34,13 +33,13 @@ func TestFilterBranchMatchBadRegexp(t *testing.T) {
BranchMatch: strp("("),
},
}
_, err := ListPullRequests(context.Background(), provider, filters)
_, err := ListPullRequests(t.Context(), provider, filters)
require.Error(t, err)
}
func TestFilterBranchMatch(t *testing.T) {
provider, _ := NewFakeService(
context.Background(),
t.Context(),
[]*PullRequest{
{
Number: 1,
@@ -82,7 +81,7 @@ func TestFilterBranchMatch(t *testing.T) {
BranchMatch: strp("w"),
},
}
pullRequests, err := ListPullRequests(context.Background(), provider, filters)
pullRequests, err := ListPullRequests(t.Context(), provider, filters)
require.NoError(t, err)
assert.Len(t, pullRequests, 1)
assert.Equal(t, "two", pullRequests[0].Branch)
@@ -90,7 +89,7 @@ func TestFilterBranchMatch(t *testing.T) {
func TestFilterTargetBranchMatch(t *testing.T) {
provider, _ := NewFakeService(
context.Background(),
t.Context(),
[]*PullRequest{
{
Number: 1,
@@ -132,7 +131,7 @@ func TestFilterTargetBranchMatch(t *testing.T) {
TargetBranchMatch: strp("1"),
},
}
pullRequests, err := ListPullRequests(context.Background(), provider, filters)
pullRequests, err := ListPullRequests(t.Context(), provider, filters)
require.NoError(t, err)
assert.Len(t, pullRequests, 1)
assert.Equal(t, "two", pullRequests[0].Branch)
@@ -140,7 +139,7 @@ func TestFilterTargetBranchMatch(t *testing.T) {
func TestMultiFilterOr(t *testing.T) {
provider, _ := NewFakeService(
context.Background(),
t.Context(),
[]*PullRequest{
{
Number: 1,
@@ -185,7 +184,7 @@ func TestMultiFilterOr(t *testing.T) {
BranchMatch: strp("r"),
},
}
pullRequests, err := ListPullRequests(context.Background(), provider, filters)
pullRequests, err := ListPullRequests(t.Context(), provider, filters)
require.NoError(t, err)
assert.Len(t, pullRequests, 3)
assert.Equal(t, "two", pullRequests[0].Branch)
@@ -195,7 +194,7 @@ func TestMultiFilterOr(t *testing.T) {
func TestMultiFilterOrWithTargetBranchFilter(t *testing.T) {
provider, _ := NewFakeService(
context.Background(),
t.Context(),
[]*PullRequest{
{
Number: 1,
@@ -242,7 +241,7 @@ func TestMultiFilterOrWithTargetBranchFilter(t *testing.T) {
TargetBranchMatch: strp("3"),
},
}
pullRequests, err := ListPullRequests(context.Background(), provider, filters)
pullRequests, err := ListPullRequests(t.Context(), provider, filters)
require.NoError(t, err)
assert.Len(t, pullRequests, 2)
assert.Equal(t, "two", pullRequests[0].Branch)
@@ -251,7 +250,7 @@ func TestMultiFilterOrWithTargetBranchFilter(t *testing.T) {
func TestNoFilters(t *testing.T) {
provider, _ := NewFakeService(
context.Background(),
t.Context(),
[]*PullRequest{
{
Number: 1,
@@ -273,7 +272,7 @@ func TestNoFilters(t *testing.T) {
nil,
)
filters := []argoprojiov1alpha1.PullRequestGeneratorFilter{}
repos, err := ListPullRequests(context.Background(), provider, filters)
repos, err := ListPullRequests(t.Context(), provider, filters)
require.NoError(t, err)
assert.Len(t, repos, 2)
assert.Equal(t, "one", repos[0].Branch)

View File

@@ -6,37 +6,52 @@ import (
"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/v3/reposerver/apiclient"
"github.com/argoproj/argo-cd/v3/util/git"
"github.com/argoproj/argo-cd/v3/util/db"
"github.com/argoproj/argo-cd/v3/util/io"
)
type argoCDService struct {
getRepository func(ctx context.Context, url, project string) (*v1alpha1.Repository, error)
storecreds git.CredsStore
submoduleEnabled bool
repoServerClientSet apiclient.Clientset
newFileGlobbingEnabled bool
getRepository func(ctx context.Context, url, project string) (*v1alpha1.Repository, error)
submoduleEnabled bool
newFileGlobbingEnabled bool
getGitFilesFromRepoServer func(ctx context.Context, req *apiclient.GitFilesRequest) (*apiclient.GitFilesResponse, error)
getGitDirectoriesFromRepoServer func(ctx context.Context, req *apiclient.GitDirectoriesRequest) (*apiclient.GitDirectoriesResponse, error)
}
type Repos interface {
// GetFiles returns content of files (not directories) within the target repo
GetFiles(ctx context.Context, repoURL string, revision string, pattern string, noRevisionCache, verifyCommit bool) (map[string][]byte, error)
GetFiles(ctx context.Context, repoURL, revision, project, pattern string, noRevisionCache, verifyCommit bool) (map[string][]byte, error)
// GetDirectories returns a list of directories (not files) within the target repo
GetDirectories(ctx context.Context, repoURL string, revision string, noRevisionCache, verifyCommit bool) ([]string, error)
GetDirectories(ctx context.Context, repoURL, revision, project string, noRevisionCache, verifyCommit bool) ([]string, error)
}
func NewArgoCDService(getRepository func(ctx context.Context, url, project string) (*v1alpha1.Repository, error), submoduleEnabled bool, repoClientset apiclient.Clientset, newFileGlobbingEnabled bool) (Repos, error) {
func NewArgoCDService(db db.ArgoDB, submoduleEnabled bool, repoClientset apiclient.Clientset, newFileGlobbingEnabled bool) Repos {
return &argoCDService{
getRepository: getRepository,
getRepository: db.GetRepository,
submoduleEnabled: submoduleEnabled,
repoServerClientSet: repoClientset,
newFileGlobbingEnabled: newFileGlobbingEnabled,
}, nil
getGitFilesFromRepoServer: func(ctx context.Context, fileRequest *apiclient.GitFilesRequest) (*apiclient.GitFilesResponse, error) {
closer, client, err := repoClientset.NewRepoServerClient()
if err != nil {
return nil, fmt.Errorf("error initializing new repo server client: %w", err)
}
defer io.Close(closer)
return client.GetGitFiles(ctx, fileRequest)
},
getGitDirectoriesFromRepoServer: func(ctx context.Context, dirRequest *apiclient.GitDirectoriesRequest) (*apiclient.GitDirectoriesResponse, error) {
closer, client, err := repoClientset.NewRepoServerClient()
if err != nil {
return nil, fmt.Errorf("error initialising new repo server client: %w", err)
}
defer io.Close(closer)
return client.GetGitDirectories(ctx, dirRequest)
},
}
}
func (a *argoCDService) GetFiles(ctx context.Context, repoURL string, revision string, pattern string, noRevisionCache, verifyCommit bool) (map[string][]byte, error) {
repo, err := a.getRepository(ctx, repoURL, "")
func (a *argoCDService) GetFiles(ctx context.Context, repoURL, revision, project, pattern string, noRevisionCache, verifyCommit bool) (map[string][]byte, error) {
repo, err := a.getRepository(ctx, repoURL, project)
if err != nil {
return nil, fmt.Errorf("error in GetRepository: %w", err)
}
@@ -50,21 +65,15 @@ func (a *argoCDService) GetFiles(ctx context.Context, repoURL string, revision s
NoRevisionCache: noRevisionCache,
VerifyCommit: verifyCommit,
}
closer, client, err := a.repoServerClientSet.NewRepoServerClient()
if err != nil {
return nil, fmt.Errorf("error initialising new repo server client: %w", err)
}
defer io.Close(closer)
fileResponse, err := client.GetGitFiles(ctx, fileRequest)
fileResponse, err := a.getGitFilesFromRepoServer(ctx, fileRequest)
if err != nil {
return nil, fmt.Errorf("error retrieving Git files: %w", err)
}
return fileResponse.GetMap(), nil
}
func (a *argoCDService) GetDirectories(ctx context.Context, repoURL string, revision string, noRevisionCache, verifyCommit bool) ([]string, error) {
repo, err := a.getRepository(ctx, repoURL, "")
func (a *argoCDService) GetDirectories(ctx context.Context, repoURL, revision, project string, noRevisionCache, verifyCommit bool) ([]string, error) {
repo, err := a.getRepository(ctx, repoURL, project)
if err != nil {
return nil, fmt.Errorf("error in GetRepository: %w", err)
}
@@ -77,13 +86,7 @@ func (a *argoCDService) GetDirectories(ctx context.Context, repoURL string, revi
VerifyCommit: verifyCommit,
}
closer, client, err := a.repoServerClientSet.NewRepoServerClient()
if err != nil {
return nil, fmt.Errorf("error initialising new repo server client: %w", err)
}
defer io.Close(closer)
dirResponse, err := client.GetGitDirectories(ctx, dirRequest)
dirResponse, err := a.getGitDirectoriesFromRepoServer(ctx, dirRequest)
if err != nil {
return nil, fmt.Errorf("error retrieving Git Directories: %w", err)
}

View File

@@ -7,22 +7,21 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"k8s.io/client-go/kubernetes/fake"
"github.com/argoproj/argo-cd/v3/reposerver/apiclient"
repo_mocks "github.com/argoproj/argo-cd/v3/reposerver/apiclient/mocks"
"github.com/argoproj/argo-cd/v3/util/git"
"github.com/argoproj/argo-cd/v3/util/db"
"github.com/argoproj/argo-cd/v3/util/settings"
"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
)
func TestGetDirectories(t *testing.T) {
type fields struct {
storecreds git.CredsStore
submoduleEnabled bool
getRepository func(ctx context.Context, url, project string) (*v1alpha1.Repository, error)
repoServerClientFuncs []func(*repo_mocks.RepoServerServiceClient)
submoduleEnabled bool
getRepository func(ctx context.Context, url, project string) (*v1alpha1.Repository, error)
getGitDirectories func(ctx context.Context, req *apiclient.GitDirectoriesRequest) (*apiclient.GitDirectoriesResponse, error)
}
type args struct {
ctx context.Context
@@ -47,50 +46,41 @@ func TestGetDirectories(t *testing.T) {
getRepository: func(_ context.Context, _, _ string) (*v1alpha1.Repository, error) {
return &v1alpha1.Repository{}, nil
},
repoServerClientFuncs: []func(*repo_mocks.RepoServerServiceClient){
func(client *repo_mocks.RepoServerServiceClient) {
client.On("GetGitDirectories", mock.Anything, mock.Anything).Return(nil, errors.New("unable to get dirs"))
},
getGitDirectories: func(_ context.Context, _ *apiclient.GitDirectoriesRequest) (*apiclient.GitDirectoriesResponse, error) {
return nil, errors.New("unable to get dirs")
},
}, args: args{}, want: nil, wantErr: assert.Error},
{name: "HappyCase", fields: fields{
getRepository: func(_ context.Context, _, _ string) (*v1alpha1.Repository, error) {
return &v1alpha1.Repository{}, nil
return &v1alpha1.Repository{
Repo: "foo",
}, nil
},
repoServerClientFuncs: []func(*repo_mocks.RepoServerServiceClient){
func(client *repo_mocks.RepoServerServiceClient) {
client.On("GetGitDirectories", mock.Anything, mock.Anything).Return(&apiclient.GitDirectoriesResponse{
Paths: []string{"foo", "foo/bar", "bar/foo"},
}, nil)
},
getGitDirectories: func(_ context.Context, _ *apiclient.GitDirectoriesRequest) (*apiclient.GitDirectoriesResponse, error) {
return &apiclient.GitDirectoriesResponse{
Paths: []string{"foo", "foo/bar", "bar/foo"},
}, nil
},
}, args: args{}, want: []string{"foo", "foo/bar", "bar/foo"}, wantErr: assert.NoError},
}, args: args{
repoURL: "foo",
}, want: []string{"foo", "foo/bar", "bar/foo"}, wantErr: assert.NoError},
{name: "ErrorVerifyingCommit", fields: fields{
getRepository: func(_ context.Context, _, _ string) (*v1alpha1.Repository, error) {
return &v1alpha1.Repository{}, nil
},
repoServerClientFuncs: []func(*repo_mocks.RepoServerServiceClient){
func(client *repo_mocks.RepoServerServiceClient) {
client.On("GetGitDirectories", mock.Anything, mock.Anything).Return(nil, errors.New("revision HEAD is not signed"))
},
getGitDirectories: func(_ context.Context, _ *apiclient.GitDirectoriesRequest) (*apiclient.GitDirectoriesResponse, error) {
return nil, errors.New("revision HEAD is not signed")
},
}, args: args{}, want: nil, wantErr: assert.Error},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mockRepoClient := &repo_mocks.RepoServerServiceClient{}
// decorate the mocks
for i := range tt.fields.repoServerClientFuncs {
tt.fields.repoServerClientFuncs[i](mockRepoClient)
}
a := &argoCDService{
getRepository: tt.fields.getRepository,
storecreds: tt.fields.storecreds,
submoduleEnabled: tt.fields.submoduleEnabled,
repoServerClientSet: &repo_mocks.Clientset{RepoServerServiceClient: mockRepoClient},
getRepository: tt.fields.getRepository,
submoduleEnabled: tt.fields.submoduleEnabled,
getGitDirectoriesFromRepoServer: tt.fields.getGitDirectories,
}
got, err := a.GetDirectories(tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.noRevisionCache, tt.args.verifyCommit)
got, err := a.GetDirectories(tt.args.ctx, tt.args.repoURL, tt.args.revision, "", tt.args.noRevisionCache, tt.args.verifyCommit)
if !tt.wantErr(t, err, fmt.Sprintf("GetDirectories(%v, %v, %v, %v)", tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.noRevisionCache)) {
return
}
@@ -101,10 +91,9 @@ func TestGetDirectories(t *testing.T) {
func TestGetFiles(t *testing.T) {
type fields struct {
storecreds git.CredsStore
submoduleEnabled bool
repoServerClientFuncs []func(*repo_mocks.RepoServerServiceClient)
getRepository func(ctx context.Context, url, project string) (*v1alpha1.Repository, error)
submoduleEnabled bool
getRepository func(ctx context.Context, url, project string) (*v1alpha1.Repository, error)
getGitFiles func(ctx context.Context, req *apiclient.GitFilesRequest) (*apiclient.GitFilesResponse, error)
}
type args struct {
ctx context.Context
@@ -130,27 +119,27 @@ func TestGetFiles(t *testing.T) {
getRepository: func(_ context.Context, _, _ string) (*v1alpha1.Repository, error) {
return &v1alpha1.Repository{}, nil
},
repoServerClientFuncs: []func(*repo_mocks.RepoServerServiceClient){
func(client *repo_mocks.RepoServerServiceClient) {
client.On("GetGitFiles", mock.Anything, mock.Anything).Return(nil, errors.New("unable to get files"))
},
getGitFiles: func(_ context.Context, _ *apiclient.GitFilesRequest) (*apiclient.GitFilesResponse, error) {
return nil, errors.New("unable to get files")
},
}, args: args{}, want: nil, wantErr: assert.Error},
{name: "HappyCase", fields: fields{
getRepository: func(_ context.Context, _, _ string) (*v1alpha1.Repository, error) {
return &v1alpha1.Repository{}, nil
return &v1alpha1.Repository{
Repo: "foo",
}, nil
},
repoServerClientFuncs: []func(*repo_mocks.RepoServerServiceClient){
func(client *repo_mocks.RepoServerServiceClient) {
client.On("GetGitFiles", mock.Anything, mock.Anything).Return(&apiclient.GitFilesResponse{
Map: map[string][]byte{
"foo.json": []byte("hello: world!"),
"bar.yaml": []byte("yay: appsets"),
},
}, nil)
},
getGitFiles: func(_ context.Context, _ *apiclient.GitFilesRequest) (*apiclient.GitFilesResponse, error) {
return &apiclient.GitFilesResponse{
Map: map[string][]byte{
"foo.json": []byte("hello: world!"),
"bar.yaml": []byte("yay: appsets"),
},
}, nil
},
}, args: args{}, want: map[string][]byte{
}, args: args{
repoURL: "foo",
}, want: map[string][]byte{
"foo.json": []byte("hello: world!"),
"bar.yaml": []byte("yay: appsets"),
}, wantErr: assert.NoError},
@@ -158,28 +147,19 @@ func TestGetFiles(t *testing.T) {
getRepository: func(_ context.Context, _, _ string) (*v1alpha1.Repository, error) {
return &v1alpha1.Repository{}, nil
},
repoServerClientFuncs: []func(*repo_mocks.RepoServerServiceClient){
func(client *repo_mocks.RepoServerServiceClient) {
client.On("GetGitFiles", mock.Anything, mock.Anything).Return(nil, errors.New("revision HEAD is not signed"))
},
getGitFiles: func(_ context.Context, _ *apiclient.GitFilesRequest) (*apiclient.GitFilesResponse, error) {
return nil, errors.New("revision HEAD is not signed")
},
}, args: args{}, want: nil, wantErr: assert.Error},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mockRepoClient := &repo_mocks.RepoServerServiceClient{}
// decorate the mocks
for i := range tt.fields.repoServerClientFuncs {
tt.fields.repoServerClientFuncs[i](mockRepoClient)
}
a := &argoCDService{
getRepository: tt.fields.getRepository,
storecreds: tt.fields.storecreds,
submoduleEnabled: tt.fields.submoduleEnabled,
repoServerClientSet: &repo_mocks.Clientset{RepoServerServiceClient: mockRepoClient},
getRepository: tt.fields.getRepository,
submoduleEnabled: tt.fields.submoduleEnabled,
getGitFilesFromRepoServer: tt.fields.getGitFiles,
}
got, err := a.GetFiles(tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.pattern, tt.args.noRevisionCache, tt.args.verifyCommit)
got, err := a.GetFiles(tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.pattern, "", tt.args.noRevisionCache, tt.args.verifyCommit)
if !tt.wantErr(t, err, fmt.Sprintf("GetFiles(%v, %v, %v, %v, %v)", tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.pattern, tt.args.noRevisionCache)) {
return
}
@@ -189,9 +169,9 @@ func TestGetFiles(t *testing.T) {
}
func TestNewArgoCDService(t *testing.T) {
service, err := NewArgoCDService(func(_ context.Context, _, _ string) (*v1alpha1.Repository, error) {
return &v1alpha1.Repository{}, nil
}, false, &repo_mocks.Clientset{}, false)
require.NoError(t, err)
testNamespace := "test"
clientset := fake.NewClientset()
testDB := db.NewDB(testNamespace, settings.NewSettingsManager(t.Context(), clientset, testNamespace), clientset)
service := NewArgoCDService(testDB, false, &repo_mocks.Clientset{}, false)
assert.NotNil(t, service)
}

View File

@@ -26,8 +26,8 @@ import (
const (
resourceTypeCodeCommitRepository = "codecommit:repository"
prefixGitUrlHttps = "https://git-codecommit."
prefixGitUrlHttpsFIPS = "https://git-codecommit-fips."
prefixGitURLHTTPS = "https://git-codecommit."
prefixGitURLHTTPSFIPS = "https://git-codecommit-fips."
)
// AWSCodeCommitClient is a lean facade to the codecommitiface.CodeCommitAPI
@@ -315,16 +315,16 @@ func getCodeCommitRepoName(repoArn string) (string, error) {
// getCodeCommitFIPSEndpoint transforms provided https:// codecommit URL to a FIPS-compliant endpoint.
// note that the specified region must support FIPS, otherwise the returned URL won't be reachable
// see: https://docs.aws.amazon.com/codecommit/latest/userguide/regions.html#regions-git
func getCodeCommitFIPSEndpoint(repoUrl string) (string, error) {
if strings.HasPrefix(repoUrl, prefixGitUrlHttpsFIPS) {
log.Debugf("provided repoUrl %s is already a fips endpoint", repoUrl)
return repoUrl, nil
func getCodeCommitFIPSEndpoint(repoURL string) (string, error) {
if strings.HasPrefix(repoURL, prefixGitURLHTTPSFIPS) {
log.Debugf("provided repoUrl %s is already a fips endpoint", repoURL)
return repoURL, nil
}
if !strings.HasPrefix(repoUrl, prefixGitUrlHttps) {
return "", fmt.Errorf("the provided https endpoint isn't recognized, cannot be transformed to FIPS endpoint: %s", repoUrl)
if !strings.HasPrefix(repoURL, prefixGitURLHTTPS) {
return "", fmt.Errorf("the provided https endpoint isn't recognized, cannot be transformed to FIPS endpoint: %s", repoURL)
}
// we already have the prefix, so we guarantee to replace exactly the prefix only.
return strings.Replace(repoUrl, prefixGitUrlHttps, prefixGitUrlHttpsFIPS, 1), nil
return strings.Replace(repoURL, prefixGitURLHTTPS, prefixGitURLHTTPSFIPS, 1), nil
}
func hasAwsError(err error, codes ...string) bool {

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.43.2. DO NOT EDIT.
// Code generated by mockery v2.52.4. DO NOT EDIT.
package mocks

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.43.2. DO NOT EDIT.
// Code generated by mockery v2.52.4. DO NOT EDIT.
package mocks

View File

@@ -1,7 +1,6 @@
package scm_provider
import (
"context"
"errors"
"sort"
"testing"
@@ -23,7 +22,7 @@ type awsCodeCommitTestRepository struct {
arn string
accountId string
defaultBranch string
expectedCloneUrl string
expectedCloneURL string
getRepositoryError error
getRepositoryNilMetadata bool
valid bool
@@ -49,7 +48,7 @@ func TestAWSCodeCommitListRepos(t *testing.T) {
id: "8235624d-d248-4df9-a983-2558b01dbe83",
arn: "arn:aws:codecommit:us-east-1:111111111111:repo1",
defaultBranch: "main",
expectedCloneUrl: "https://git-codecommit.us-east-1.amazonaws.com/v1/repos/repo1",
expectedCloneURL: "https://git-codecommit.us-east-1.amazonaws.com/v1/repos/repo1",
valid: true,
},
},
@@ -74,7 +73,7 @@ func TestAWSCodeCommitListRepos(t *testing.T) {
id: "8235624d-d248-4df9-a983-2558b01dbe83",
arn: "arn:aws:codecommit:us-east-1:111111111111:repo1",
defaultBranch: "main",
expectedCloneUrl: "https://git-codecommit-fips.us-east-1.amazonaws.com/v1/repos/repo1",
expectedCloneURL: "https://git-codecommit-fips.us-east-1.amazonaws.com/v1/repos/repo1",
valid: true,
},
},
@@ -96,7 +95,7 @@ func TestAWSCodeCommitListRepos(t *testing.T) {
id: "8235624d-d248-4df9-a983-2558b01dbe83",
arn: "arn:aws:codecommit:us-east-1:111111111111:repo1",
defaultBranch: "main",
expectedCloneUrl: "ssh://git-codecommit.us-east-1.amazonaws.com/v1/repos/repo1",
expectedCloneURL: "ssh://git-codecommit.us-east-1.amazonaws.com/v1/repos/repo1",
valid: true,
},
{
@@ -160,7 +159,7 @@ func TestAWSCodeCommitListRepos(t *testing.T) {
t.Run(testCase.name, func(t *testing.T) {
codeCommitClient := mocks.NewAWSCodeCommitClient(t)
taggingClient := mocks.NewAWSTaggingClient(t)
ctx := context.Background()
ctx := t.Context()
codecommitRepoNameIdPairs := make([]*codecommit.RepositoryNameIdPair, 0)
resourceTaggings := make([]*resourcegroupstaggingapi.ResourceTagMapping, 0)
validRepositories := make([]*awsCodeCommitTestRepository, 0)
@@ -226,7 +225,7 @@ func TestAWSCodeCommitListRepos(t *testing.T) {
assert.Equal(t, originRepo.name, repo.Repository)
assert.Equal(t, originRepo.id, repo.RepositoryId)
assert.Equal(t, originRepo.defaultBranch, repo.Branch)
assert.Equal(t, originRepo.expectedCloneUrl, repo.URL)
assert.Equal(t, originRepo.expectedCloneURL, repo.URL)
assert.Empty(t, repo.SHA, "SHA is always empty")
}
}
@@ -349,7 +348,7 @@ func TestAWSCodeCommitRepoHasPath(t *testing.T) {
t.Run(testCase.name, func(t *testing.T) {
codeCommitClient := mocks.NewAWSCodeCommitClient(t)
taggingClient := mocks.NewAWSTaggingClient(t)
ctx := context.Background()
ctx := t.Context()
if testCase.expectedGetFolderPath != "" {
codeCommitClient.
On("GetFolderWithContext", ctx, &codecommit.GetFolderInput{
@@ -382,7 +381,7 @@ func TestAWSCodeCommitGetBranches(t *testing.T) {
id := "1a64adc4-2fb5-4abd-afe7-127984ba83c0"
defaultBranch := "main"
organization := "111111111111"
cloneUrl := "https://git-codecommit.us-east-1.amazonaws.com/v1/repos/repo1"
cloneURL := "https://git-codecommit.us-east-1.amazonaws.com/v1/repos/repo1"
testCases := []struct {
name string
@@ -422,7 +421,7 @@ func TestAWSCodeCommitGetBranches(t *testing.T) {
t.Run(testCase.name, func(t *testing.T) {
codeCommitClient := mocks.NewAWSCodeCommitClient(t)
taggingClient := mocks.NewAWSTaggingClient(t)
ctx := context.Background()
ctx := t.Context()
if testCase.allBranches {
codeCommitClient.
On("ListBranchesWithContext", ctx, &codecommit.ListBranchesInput{
@@ -445,7 +444,7 @@ func TestAWSCodeCommitGetBranches(t *testing.T) {
actual, err := provider.GetBranches(ctx, &Repository{
Organization: organization,
Repository: name,
URL: cloneUrl,
URL: cloneURL,
RepositoryId: id,
})
if testCase.expectOverallError {
@@ -454,7 +453,7 @@ func TestAWSCodeCommitGetBranches(t *testing.T) {
assertCopiedProperties := func(repo *Repository) {
assert.Equal(t, id, repo.RepositoryId)
assert.Equal(t, name, repo.Repository)
assert.Equal(t, cloneUrl, repo.URL)
assert.Equal(t, cloneURL, repo.URL)
assert.Equal(t, organization, repo.Organization)
assert.Empty(t, repo.SHA)
}

View File

@@ -107,7 +107,7 @@ func (g *AzureDevOpsProvider) RepoHasPath(ctx context.Context, repo *Repository,
}
var repoId string
if uuid, isUuid := repo.RepositoryId.(uuid.UUID); isUuid { // most likely an UUID, but do type-safe check anyway. Do %v fallback if not expected type.
if uuid, isUUID := repo.RepositoryId.(uuid.UUID); isUUID { // most likely an UUID, but do type-safe check anyway. Do %v fallback if not expected type.
repoId = uuid.String()
} else {
repoId = fmt.Sprintf("%v", repo.RepositoryId)

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.43.2. DO NOT EDIT.
// Code generated by mockery v2.52.4. DO NOT EDIT.
package mocks

View File

@@ -29,7 +29,7 @@ func TestAzureDevopsRepoHasPath(t *testing.T) {
path := "dir/subdir/item.yaml"
branchName := "my/featurebranch"
ctx := context.Background()
ctx := t.Context()
uuid := uuid.New().String()
testCases := []struct {
@@ -115,7 +115,7 @@ func TestGetDefaultBranchOnDisabledRepo(t *testing.T) {
repoName := "myorg_project_repo"
defaultBranch := "main"
ctx := context.Background()
ctx := t.Context()
testCases := []struct {
name string
@@ -174,7 +174,7 @@ func TestGetAllBranchesOnDisabledRepo(t *testing.T) {
repoName := "myorg_project_repo"
defaultBranch := "main"
ctx := context.Background()
ctx := t.Context()
testCases := []struct {
name string
@@ -233,7 +233,7 @@ func TestAzureDevOpsGetDefaultBranchStripsRefsName(t *testing.T) {
teamProject := "myorg_project"
repoName := "myorg_project_repo"
ctx := context.Background()
ctx := t.Context()
uuid := uuid.New().String()
strippedBranchName := "somebranch"
defaultBranch := fmt.Sprintf("refs/heads/%v", strippedBranchName)
@@ -264,7 +264,7 @@ func TestAzureDevOpsGetBranchesDefultBranchOnly(t *testing.T) {
teamProject := "myorg_project"
repoName := "myorg_project_repo"
ctx := context.Background()
ctx := t.Context()
uuid := uuid.New().String()
defaultBranch := "main"
@@ -272,7 +272,7 @@ func TestAzureDevOpsGetBranchesDefultBranchOnly(t *testing.T) {
testCases := []struct {
name string
expectedBranch *azureGit.GitBranchStats
getBranchesApiError error
getBranchesAPIError error
clientError error
}{
{
@@ -281,7 +281,7 @@ func TestAzureDevOpsGetBranchesDefultBranchOnly(t *testing.T) {
},
{
name: "GetBranches AllBranches false when request fails returns error and empty result",
getBranchesApiError: errors.New("Remote Azure Devops GetBranches error"),
getBranchesAPIError: errors.New("Remote Azure Devops GetBranches error"),
},
{
name: "GetBranches AllBranches false when Azure DevOps client fails returns error",
@@ -300,7 +300,7 @@ func TestAzureDevOpsGetBranchesDefultBranchOnly(t *testing.T) {
clientFactoryMock := &AzureClientFactoryMock{mock: &mock.Mock{}}
clientFactoryMock.mock.On("GetClient", mock.Anything).Return(&gitClientMock, testCase.clientError)
gitClientMock.On("GetBranch", ctx, azureGit.GetBranchArgs{RepositoryId: &repoName, Project: &teamProject, Name: &defaultBranch}).Return(testCase.expectedBranch, testCase.getBranchesApiError)
gitClientMock.On("GetBranch", ctx, azureGit.GetBranchArgs{RepositoryId: &repoName, Project: &teamProject, Name: &defaultBranch}).Return(testCase.expectedBranch, testCase.getBranchesAPIError)
repo := &Repository{Organization: organization, Repository: repoName, RepositoryId: uuid, Branch: defaultBranch}
@@ -314,9 +314,9 @@ func TestAzureDevOpsGetBranchesDefultBranchOnly(t *testing.T) {
return
}
if testCase.getBranchesApiError != nil {
if testCase.getBranchesAPIError != nil {
assert.Empty(t, branches)
require.ErrorContains(t, err, testCase.getBranchesApiError.Error())
require.ErrorContains(t, err, testCase.getBranchesAPIError.Error())
} else {
if testCase.expectedBranch != nil {
assert.NotEmpty(t, branches)
@@ -335,13 +335,13 @@ func TestAzureDevopsGetBranches(t *testing.T) {
teamProject := "myorg_project"
repoName := "myorg_project_repo"
ctx := context.Background()
ctx := t.Context()
uuid := uuid.New().String()
testCases := []struct {
name string
expectedBranches *[]azureGit.GitBranchStats
getBranchesApiError error
getBranchesAPIError error
clientError error
allBranches bool
expectedProcessingErrorMsg string
@@ -353,7 +353,7 @@ func TestAzureDevopsGetBranches(t *testing.T) {
},
{
name: "GetBranches when Azure DevOps request fails returns error and empty result",
getBranchesApiError: errors.New("Remote Azure Devops GetBranches error"),
getBranchesAPIError: errors.New("Remote Azure Devops GetBranches error"),
allBranches: true,
},
{
@@ -384,7 +384,7 @@ func TestAzureDevopsGetBranches(t *testing.T) {
clientFactoryMock := &AzureClientFactoryMock{mock: &mock.Mock{}}
clientFactoryMock.mock.On("GetClient", mock.Anything).Return(&gitClientMock, testCase.clientError)
gitClientMock.On("GetBranches", ctx, azureGit.GetBranchesArgs{RepositoryId: &repoName, Project: &teamProject}).Return(testCase.expectedBranches, testCase.getBranchesApiError)
gitClientMock.On("GetBranches", ctx, azureGit.GetBranchesArgs{RepositoryId: &repoName, Project: &teamProject}).Return(testCase.expectedBranches, testCase.getBranchesAPIError)
repo := &Repository{Organization: organization, Repository: repoName, RepositoryId: uuid}
@@ -403,9 +403,9 @@ func TestAzureDevopsGetBranches(t *testing.T) {
return
}
if testCase.getBranchesApiError != nil {
if testCase.getBranchesAPIError != nil {
assert.Empty(t, branches)
require.ErrorContains(t, err, testCase.getBranchesApiError.Error())
require.ErrorContains(t, err, testCase.getBranchesAPIError.Error())
} else {
if len(*testCase.expectedBranches) > 0 {
assert.NotEmpty(t, branches)
@@ -427,7 +427,7 @@ func TestGetAzureDevopsRepositories(t *testing.T) {
teamProject := "myorg_project"
uuid := uuid.New()
ctx := context.Background()
ctx := t.Context()
repoId := &uuid

View File

@@ -101,7 +101,7 @@ func (g *BitBucketCloudProvider) ListRepos(_ context.Context, cloneProtocol stri
return nil, fmt.Errorf("error listing repositories for %s: %w", g.owner, err)
}
for _, bitBucketRepo := range accountReposResp.Items {
cloneUrl, err := findCloneURL(cloneProtocol, &bitBucketRepo)
cloneURL, err := findCloneURL(cloneProtocol, &bitBucketRepo)
if err != nil {
return nil, fmt.Errorf("error fetching clone url for repo %s: %w", bitBucketRepo.Slug, err)
}
@@ -109,7 +109,7 @@ func (g *BitBucketCloudProvider) ListRepos(_ context.Context, cloneProtocol stri
Organization: g.owner,
Repository: bitBucketRepo.Slug,
Branch: bitBucketRepo.Mainbranch.Name,
URL: *cloneUrl,
URL: *cloneURL,
Labels: []string{},
RepositoryId: bitBucketRepo.Uuid,
})

View File

@@ -1,7 +1,6 @@
package scm_provider
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
@@ -94,7 +93,7 @@ func TestBitbucketHasRepo(t *testing.T) {
SHA: c.sha,
Branch: "main",
}
hasPath, err := provider.RepoHasPath(context.Background(), repo, c.path)
hasPath, err := provider.RepoHasPath(t.Context(), repo, c.path)
if err != nil {
require.Error(t, fmt.Errorf("Error in test %w", err))
}
@@ -488,7 +487,7 @@ func TestBitbucketListRepos(t *testing.T) {
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
provider, _ := NewBitBucketCloudProvider(c.owner, "user", "password", c.allBranches)
rawRepos, err := ListRepos(context.Background(), provider, c.filters, c.proto)
rawRepos, err := ListRepos(t.Context(), provider, c.filters, c.proto)
if c.hasError {
require.Error(t, err)
} else {

View File

@@ -1,7 +1,6 @@
package scm_provider
import (
"context"
"crypto/x509"
"encoding/pem"
"io"
@@ -103,9 +102,9 @@ func TestListReposNoAuth(t *testing.T) {
defaultHandler(t)(w, r)
}))
defer ts.Close()
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true, "", false, nil)
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", true, "", false, nil)
require.NoError(t, err)
repos, err := provider.ListRepos(context.Background(), "ssh")
repos, err := provider.ListRepos(t.Context(), "ssh")
verifyDefaultRepo(t, err, repos)
}
@@ -195,9 +194,9 @@ func TestListReposPagination(t *testing.T) {
}
}))
defer ts.Close()
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true, "", false, nil)
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", true, "", false, nil)
require.NoError(t, err)
repos, err := provider.ListRepos(context.Background(), "ssh")
repos, err := provider.ListRepos(t.Context(), "ssh")
require.NoError(t, err)
assert.Len(t, repos, 2)
assert.Equal(t, Repository{
@@ -272,9 +271,9 @@ func TestGetBranchesBranchPagination(t *testing.T) {
defaultHandler(t)(w, r)
}))
defer ts.Close()
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true, "", false, nil)
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", true, "", false, nil)
require.NoError(t, err)
repos, err := provider.GetBranches(context.Background(), &Repository{
repos, err := provider.GetBranches(t.Context(), &Repository{
Organization: "PROJECT",
Repository: "REPO",
URL: "ssh://git@mycompany.bitbucket.org/PROJECT/REPO.git",
@@ -324,9 +323,9 @@ func TestGetBranchesDefaultOnly(t *testing.T) {
defaultHandler(t)(w, r)
}))
defer ts.Close()
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false, "", false, nil)
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", false, "", false, nil)
require.NoError(t, err)
repos, err := provider.GetBranches(context.Background(), &Repository{
repos, err := provider.GetBranches(t.Context(), &Repository{
Organization: "PROJECT",
Repository: "REPO",
URL: "ssh://git@mycompany.bitbucket.org/PROJECT/REPO.git",
@@ -355,9 +354,9 @@ func TestGetBranchesMissingDefault(t *testing.T) {
defaultHandler(t)(w, r)
}))
defer ts.Close()
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false, "", false, nil)
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", false, "", false, nil)
require.NoError(t, err)
repos, err := provider.GetBranches(context.Background(), &Repository{
repos, err := provider.GetBranches(t.Context(), &Repository{
Organization: "PROJECT",
Repository: "REPO",
URL: "ssh://git@mycompany.bitbucket.org/PROJECT/REPO.git",
@@ -376,9 +375,9 @@ func TestGetBranchesEmptyRepo(t *testing.T) {
}
}))
defer ts.Close()
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false, "", false, nil)
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", false, "", false, nil)
require.NoError(t, err)
repos, err := provider.GetBranches(context.Background(), &Repository{
repos, err := provider.GetBranches(t.Context(), &Repository{
Organization: "PROJECT",
Repository: "REPO",
URL: "ssh://git@mycompany.bitbucket.org/PROJECT/REPO.git",
@@ -398,9 +397,9 @@ func TestGetBranchesErrorDefaultBranch(t *testing.T) {
defaultHandler(t)(w, r)
}))
defer ts.Close()
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false, "", false, nil)
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", false, "", false, nil)
require.NoError(t, err)
_, err = provider.GetBranches(context.Background(), &Repository{
_, err = provider.GetBranches(t.Context(), &Repository{
Organization: "PROJECT",
Repository: "REPO",
URL: "ssh://git@mycompany.bitbucket.org/PROJECT/REPO.git",
@@ -465,9 +464,9 @@ func TestListReposTLS(t *testing.T) {
}
}
provider, err := NewBitbucketServerProviderBasicAuth(context.Background(), "user", "password", ts.URL, "PROJECT", true, "", test.tlsInsecure, certs)
provider, err := NewBitbucketServerProviderBasicAuth(t.Context(), "user", "password", ts.URL, "PROJECT", true, "", test.tlsInsecure, certs)
require.NoError(t, err)
_, err = provider.ListRepos(context.Background(), "ssh")
_, err = provider.ListRepos(t.Context(), "ssh")
if test.requireErr {
require.Error(t, err)
} else {
@@ -484,9 +483,9 @@ func TestListReposBasicAuth(t *testing.T) {
defaultHandler(t)(w, r)
}))
defer ts.Close()
provider, err := NewBitbucketServerProviderBasicAuth(context.Background(), "user", "password", ts.URL, "PROJECT", true, "", false, nil)
provider, err := NewBitbucketServerProviderBasicAuth(t.Context(), "user", "password", ts.URL, "PROJECT", true, "", false, nil)
require.NoError(t, err)
repos, err := provider.ListRepos(context.Background(), "ssh")
repos, err := provider.ListRepos(t.Context(), "ssh")
verifyDefaultRepo(t, err, repos)
}
@@ -497,9 +496,9 @@ func TestListReposBearerAuth(t *testing.T) {
defaultHandler(t)(w, r)
}))
defer ts.Close()
provider, err := NewBitbucketServerProviderBearerToken(context.Background(), "tolkien", ts.URL, "PROJECT", true, "", false, nil)
provider, err := NewBitbucketServerProviderBearerToken(t.Context(), "tolkien", ts.URL, "PROJECT", true, "", false, nil)
require.NoError(t, err)
repos, err := provider.ListRepos(context.Background(), "ssh")
repos, err := provider.ListRepos(t.Context(), "ssh")
verifyDefaultRepo(t, err, repos)
}
@@ -523,9 +522,9 @@ func TestListReposDefaultBranch(t *testing.T) {
defaultHandler(t)(w, r)
}))
defer ts.Close()
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false, "", false, nil)
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", false, "", false, nil)
require.NoError(t, err)
repos, err := provider.ListRepos(context.Background(), "ssh")
repos, err := provider.ListRepos(t.Context(), "ssh")
require.NoError(t, err)
assert.Len(t, repos, 1)
assert.Equal(t, Repository{
@@ -548,9 +547,9 @@ func TestListReposMissingDefaultBranch(t *testing.T) {
defaultHandler(t)(w, r)
}))
defer ts.Close()
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false, "", false, nil)
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", false, "", false, nil)
require.NoError(t, err)
repos, err := provider.ListRepos(context.Background(), "ssh")
repos, err := provider.ListRepos(t.Context(), "ssh")
require.NoError(t, err)
assert.Empty(t, repos)
}
@@ -564,9 +563,9 @@ func TestListReposErrorDefaultBranch(t *testing.T) {
defaultHandler(t)(w, r)
}))
defer ts.Close()
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false, "", false, nil)
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", false, "", false, nil)
require.NoError(t, err)
_, err = provider.ListRepos(context.Background(), "ssh")
_, err = provider.ListRepos(t.Context(), "ssh")
require.Error(t, err)
}
@@ -576,9 +575,9 @@ func TestListReposCloneProtocol(t *testing.T) {
defaultHandler(t)(w, r)
}))
defer ts.Close()
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true, "", false, nil)
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", true, "", false, nil)
require.NoError(t, err)
repos, err := provider.ListRepos(context.Background(), "https")
repos, err := provider.ListRepos(t.Context(), "https")
require.NoError(t, err)
assert.Len(t, repos, 1)
assert.Equal(t, Repository{
@@ -598,9 +597,9 @@ func TestListReposUnknownProtocol(t *testing.T) {
defaultHandler(t)(w, r)
}))
defer ts.Close()
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true, "", false, nil)
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", true, "", false, nil)
require.NoError(t, err)
_, errProtocol := provider.ListRepos(context.Background(), "http")
_, errProtocol := provider.ListRepos(t.Context(), "http")
require.Error(t, errProtocol)
}
@@ -636,37 +635,37 @@ func TestBitbucketServerHasPath(t *testing.T) {
}
}))
defer ts.Close()
provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", true, "", false, nil)
provider, err := NewBitbucketServerProviderNoAuth(t.Context(), ts.URL, "PROJECT", true, "", false, nil)
require.NoError(t, err)
repo := &Repository{
Organization: "PROJECT",
Repository: "REPO",
Branch: "main",
}
ok, err := provider.RepoHasPath(context.Background(), repo, "pkg")
ok, err := provider.RepoHasPath(t.Context(), repo, "pkg")
require.NoError(t, err)
assert.True(t, ok)
ok, err = provider.RepoHasPath(context.Background(), repo, "pkg/")
ok, err = provider.RepoHasPath(t.Context(), repo, "pkg/")
require.NoError(t, err)
assert.True(t, ok)
ok, err = provider.RepoHasPath(context.Background(), repo, "anotherpkg/file.txt")
ok, err = provider.RepoHasPath(t.Context(), repo, "anotherpkg/file.txt")
require.NoError(t, err)
assert.True(t, ok)
ok, err = provider.RepoHasPath(context.Background(), repo, "anotherpkg/missing.txt")
ok, err = provider.RepoHasPath(t.Context(), repo, "anotherpkg/missing.txt")
require.NoError(t, err)
assert.False(t, ok)
ok, err = provider.RepoHasPath(context.Background(), repo, "notathing")
ok, err = provider.RepoHasPath(t.Context(), repo, "notathing")
require.NoError(t, err)
assert.False(t, ok)
ok, err = provider.RepoHasPath(context.Background(), repo, "return-redirect")
ok, err = provider.RepoHasPath(t.Context(), repo, "return-redirect")
require.NoError(t, err)
assert.True(t, ok)
_, err = provider.RepoHasPath(context.Background(), repo, "unauthorized-response")
_, err = provider.RepoHasPath(t.Context(), repo, "unauthorized-response")
require.Error(t, err)
}

View File

@@ -1,7 +1,6 @@
package scm_provider
import (
"context"
"io"
"net/http"
"net/http/httptest"
@@ -305,7 +304,7 @@ func TestGiteaListRepos(t *testing.T) {
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
provider, _ := NewGiteaProvider("test-argocd", "", ts.URL, c.allBranches, false)
rawRepos, err := ListRepos(context.Background(), provider, c.filters, c.proto)
rawRepos, err := ListRepos(t.Context(), provider, c.filters, c.proto)
if c.hasError {
require.Error(t, err)
} else {
@@ -342,19 +341,19 @@ func TestGiteaHasPath(t *testing.T) {
}
t.Run("file exists", func(t *testing.T) {
ok, err := host.RepoHasPath(context.Background(), repo, "README.md")
ok, err := host.RepoHasPath(t.Context(), repo, "README.md")
require.NoError(t, err)
assert.True(t, ok)
})
t.Run("directory exists", func(t *testing.T) {
ok, err := host.RepoHasPath(context.Background(), repo, "gitea")
ok, err := host.RepoHasPath(t.Context(), repo, "gitea")
require.NoError(t, err)
assert.True(t, ok)
})
t.Run("does not exists", func(t *testing.T) {
ok, err := host.RepoHasPath(context.Background(), repo, "notathing")
ok, err := host.RepoHasPath(t.Context(), repo, "notathing")
require.NoError(t, err)
assert.False(t, ok)
})

View File

@@ -1,7 +1,6 @@
package scm_provider
import (
"context"
"io"
"net/http"
"net/http/httptest"
@@ -244,7 +243,7 @@ func TestGithubListRepos(t *testing.T) {
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
provider, _ := NewGithubProvider("argoproj", "", ts.URL, c.allBranches)
rawRepos, err := ListRepos(context.Background(), provider, c.filters, c.proto)
rawRepos, err := ListRepos(t.Context(), provider, c.filters, c.proto)
if c.hasError {
require.Error(t, err)
} else {
@@ -279,11 +278,11 @@ func TestGithubHasPath(t *testing.T) {
Repository: "argo-cd",
Branch: "master",
}
ok, err := host.RepoHasPath(context.Background(), repo, "pkg/")
ok, err := host.RepoHasPath(t.Context(), repo, "pkg/")
require.NoError(t, err)
assert.True(t, ok)
ok, err = host.RepoHasPath(context.Background(), repo, "notathing/")
ok, err = host.RepoHasPath(t.Context(), repo, "notathing/")
require.NoError(t, err)
assert.False(t, ok)
}
@@ -299,7 +298,7 @@ func TestGithubGetBranches(t *testing.T) {
Repository: "argo-cd",
Branch: "master",
}
repos, err := host.GetBranches(context.Background(), repo)
repos, err := host.GetBranches(t.Context(), repo)
if err != nil {
require.NoError(t, err)
} else {
@@ -311,12 +310,12 @@ func TestGithubGetBranches(t *testing.T) {
Repository: "applicationset",
Branch: "main",
}
_, err = host.GetBranches(context.Background(), repo2)
_, err = host.GetBranches(t.Context(), repo2)
require.NoError(t, err)
// Get all branches
host.allBranches = true
repos, err = host.GetBranches(context.Background(), repo)
repos, err = host.GetBranches(t.Context(), repo)
if err != nil {
require.NoError(t, err)
} else {

View File

@@ -1,7 +1,6 @@
package scm_provider
import (
"context"
"crypto/x509"
"encoding/pem"
"fmt"
@@ -1152,7 +1151,7 @@ func TestGitlabListRepos(t *testing.T) {
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
provider, _ := NewGitlabProvider("test-argocd-proton", "", ts.URL, c.allBranches, c.includeSubgroups, c.includeSharedProjects, c.insecure, "", c.topic, nil)
rawRepos, err := ListRepos(context.Background(), provider, c.filters, c.proto)
rawRepos, err := ListRepos(t.Context(), provider, c.filters, c.proto)
if c.hasError {
require.Error(t, err)
} else {
@@ -1235,7 +1234,7 @@ func TestGitlabHasPath(t *testing.T) {
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
ok, err := host.RepoHasPath(context.Background(), repo, c.path)
ok, err := host.RepoHasPath(t.Context(), repo, c.path)
require.NoError(t, err)
assert.Equal(t, c.exists, ok)
})
@@ -1253,7 +1252,7 @@ func TestGitlabGetBranches(t *testing.T) {
Branch: "master",
}
t.Run("branch exists", func(t *testing.T) {
repos, err := host.GetBranches(context.Background(), repo)
repos, err := host.GetBranches(t.Context(), repo)
require.NoError(t, err)
assert.Equal(t, "master", repos[0].Branch)
})
@@ -1263,7 +1262,7 @@ func TestGitlabGetBranches(t *testing.T) {
Branch: "foo",
}
t.Run("unknown branch", func(t *testing.T) {
_, err := host.GetBranches(context.Background(), repo2)
_, err := host.GetBranches(t.Context(), repo2)
require.NoError(t, err)
})
}
@@ -1329,7 +1328,7 @@ func TestGetBranchesTLS(t *testing.T) {
RepositoryId: 27084533,
Branch: "master",
}
_, err = host.GetBranches(context.Background(), repo)
_, err = host.GetBranches(t.Context(), repo)
if test.requireErr {
require.Error(t, err)
} else {

View File

@@ -1,7 +1,6 @@
package scm_provider
import (
"context"
"regexp"
"testing"
@@ -37,7 +36,7 @@ func TestFilterRepoMatch(t *testing.T) {
RepositoryMatch: strp("n|hr"),
},
}
repos, err := ListRepos(context.Background(), provider, filters, "")
repos, err := ListRepos(t.Context(), provider, filters, "")
require.NoError(t, err)
assert.Len(t, repos, 2)
assert.Equal(t, "one", repos[0].Repository)
@@ -66,7 +65,7 @@ func TestFilterLabelMatch(t *testing.T) {
LabelMatch: strp("^prod-.*$"),
},
}
repos, err := ListRepos(context.Background(), provider, filters, "")
repos, err := ListRepos(t.Context(), provider, filters, "")
require.NoError(t, err)
assert.Len(t, repos, 2)
assert.Equal(t, "one", repos[0].Repository)
@@ -92,7 +91,7 @@ func TestFilterPathExists(t *testing.T) {
PathsExist: []string{"two"},
},
}
repos, err := ListRepos(context.Background(), provider, filters, "")
repos, err := ListRepos(t.Context(), provider, filters, "")
require.NoError(t, err)
assert.Len(t, repos, 1)
assert.Equal(t, "two", repos[0].Repository)
@@ -117,7 +116,7 @@ func TestFilterPathDoesntExists(t *testing.T) {
PathsDoNotExist: []string{"two"},
},
}
repos, err := ListRepos(context.Background(), provider, filters, "")
repos, err := ListRepos(t.Context(), provider, filters, "")
require.NoError(t, err)
assert.Len(t, repos, 2)
}
@@ -135,7 +134,7 @@ func TestFilterRepoMatchBadRegexp(t *testing.T) {
RepositoryMatch: strp("("),
},
}
_, err := ListRepos(context.Background(), provider, filters, "")
_, err := ListRepos(t.Context(), provider, filters, "")
require.Error(t, err)
}
@@ -152,7 +151,7 @@ func TestFilterLabelMatchBadRegexp(t *testing.T) {
LabelMatch: strp("("),
},
}
_, err := ListRepos(context.Background(), provider, filters, "")
_, err := ListRepos(t.Context(), provider, filters, "")
require.Error(t, err)
}
@@ -186,7 +185,7 @@ func TestFilterBranchMatch(t *testing.T) {
BranchMatch: strp("w"),
},
}
repos, err := ListRepos(context.Background(), provider, filters, "")
repos, err := ListRepos(t.Context(), provider, filters, "")
require.NoError(t, err)
assert.Len(t, repos, 2)
assert.Equal(t, "one", repos[0].Repository)
@@ -218,7 +217,7 @@ func TestMultiFilterAnd(t *testing.T) {
LabelMatch: strp("^prod-.*$"),
},
}
repos, err := ListRepos(context.Background(), provider, filters, "")
repos, err := ListRepos(t.Context(), provider, filters, "")
require.NoError(t, err)
assert.Len(t, repos, 1)
assert.Equal(t, "two", repos[0].Repository)
@@ -249,7 +248,7 @@ func TestMultiFilterOr(t *testing.T) {
LabelMatch: strp("^prod-.*$"),
},
}
repos, err := ListRepos(context.Background(), provider, filters, "")
repos, err := ListRepos(t.Context(), provider, filters, "")
require.NoError(t, err)
assert.Len(t, repos, 3)
assert.Equal(t, "one", repos[0].Repository)
@@ -275,7 +274,7 @@ func TestNoFilters(t *testing.T) {
},
}
filters := []argoprojiov1alpha1.SCMProviderGeneratorFilter{}
repos, err := ListRepos(context.Background(), provider, filters, "")
repos, err := ListRepos(t.Context(), provider, filters, "")
require.NoError(t, err)
assert.Len(t, repos, 3)
assert.Equal(t, "one", repos[0].Repository)

View File

@@ -7,31 +7,17 @@ import (
func BuildResourceStatus(statusMap map[string]argov1alpha1.ResourceStatus, apps []argov1alpha1.Application) map[string]argov1alpha1.ResourceStatus {
appMap := map[string]argov1alpha1.Application{}
for _, app := range apps {
appCopy := app
appMap[app.Name] = app
gvk := app.GroupVersionKind()
// Create status if it does not exist
status, ok := statusMap[app.Name]
if !ok {
status = argov1alpha1.ResourceStatus{
Group: gvk.Group,
Version: gvk.Version,
Kind: gvk.Kind,
Name: app.Name,
Namespace: app.Namespace,
Status: app.Status.Sync.Status,
Health: &appCopy.Status.Health,
}
}
var status argov1alpha1.ResourceStatus
status.Group = gvk.Group
status.Version = gvk.Version
status.Kind = gvk.Kind
status.Name = app.Name
status.Namespace = app.Namespace
status.Status = app.Status.Sync.Status
status.Health = &appCopy.Status.Health
status.Health = app.Status.Health.DeepCopy()
statusMap[app.Name] = status
}

View File

@@ -3,7 +3,6 @@ package utils
import (
"context"
"fmt"
"sync"
"github.com/argoproj/argo-cd/v3/common"
appv1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
@@ -13,16 +12,14 @@ import (
"k8s.io/client-go/kubernetes"
)
var (
localCluster = appv1.Cluster{
Name: "in-cluster",
Server: appv1.KubernetesInternalAPIServerAddr,
ConnectionState: appv1.ConnectionState{Status: appv1.ConnectionStatusSuccessful},
}
initLocalCluster sync.Once
)
// ClusterSpecifier contains only the name and server URL of a cluster. We use this struct to avoid partially-populating
// the full Cluster struct, which would be misleading.
type ClusterSpecifier struct {
Name string
Server string
}
func ListClusters(ctx context.Context, clientset kubernetes.Interface, namespace string) (*appv1.ClusterList, error) {
func ListClusters(ctx context.Context, clientset kubernetes.Interface, namespace string) ([]ClusterSpecifier, error) {
clusterSecretsList, err := clientset.CoreV1().Secrets(namespace).List(ctx,
metav1.ListOptions{LabelSelector: common.LabelKeySecretType + "=" + common.LabelValueSecretTypeCluster})
if err != nil {
@@ -35,54 +32,29 @@ func ListClusters(ctx context.Context, clientset kubernetes.Interface, namespace
clusterSecrets := clusterSecretsList.Items
clusterList := appv1.ClusterList{
Items: make([]appv1.Cluster, len(clusterSecrets)),
}
clusterList := make([]ClusterSpecifier, len(clusterSecrets))
hasInClusterCredentials := false
for i, clusterSecret := range clusterSecrets {
// This line has changed from the original Argo CD code: now receives an error, and handles it
cluster, err := db.SecretToCluster(&clusterSecret)
if err != nil || cluster == nil {
return nil, fmt.Errorf("unable to convert cluster secret to cluster object '%s': %w", clusterSecret.Name, err)
}
// db.SecretToCluster populates these, but they're not meant to be available to the caller.
cluster.Labels = nil
cluster.Annotations = nil
clusterList.Items[i] = *cluster
clusterList[i] = ClusterSpecifier{
Name: cluster.Name,
Server: cluster.Server,
}
if cluster.Server == appv1.KubernetesInternalAPIServerAddr {
hasInClusterCredentials = true
}
}
if !hasInClusterCredentials {
localCluster := getLocalCluster(clientset)
if localCluster != nil {
clusterList.Items = append(clusterList.Items, *localCluster)
}
// There was no secret for the in-cluster config, so we add it here. We don't fully-populate the Cluster struct,
// since only the name and server fields are used by the generator.
clusterList = append(clusterList, ClusterSpecifier{
Name: "in-cluster",
Server: appv1.KubernetesInternalAPIServerAddr,
})
}
return &clusterList, nil
}
func getLocalCluster(clientset kubernetes.Interface) *appv1.Cluster {
initLocalCluster.Do(func() {
info, err := clientset.Discovery().ServerVersion()
if err == nil {
//nolint:staticcheck
localCluster.ServerVersion = fmt.Sprintf("%s.%s", info.Major, info.Minor)
//nolint:staticcheck
localCluster.ConnectionState = appv1.ConnectionState{Status: appv1.ConnectionStatusSuccessful}
} else {
//nolint:staticcheck
localCluster.ConnectionState = appv1.ConnectionState{
Status: appv1.ConnectionStatusFailed,
Message: err.Error(),
}
}
})
cluster := localCluster.DeepCopy()
now := metav1.Now()
//nolint:staticcheck
cluster.ConnectionState.ModifiedAt = &now
return cluster
return clusterList, nil
}

View File

@@ -163,12 +163,12 @@ func applyIgnoreDifferences(applicationSetIgnoreDifferences argov1alpha1.Applica
if len(result.Lives) != 1 {
return fmt.Errorf("expected 1 normalized application, got %d", len(result.Lives))
}
foundJsonNormalized, err := json.Marshal(result.Lives[0].Object)
foundJSONNormalized, err := json.Marshal(result.Lives[0].Object)
if err != nil {
return fmt.Errorf("failed to marshal normalized app to json: %w", err)
}
foundNormalized := &argov1alpha1.Application{}
err = json.Unmarshal(foundJsonNormalized, &foundNormalized)
err = json.Unmarshal(foundJSONNormalized, &foundNormalized)
if err != nil {
return fmt.Errorf("failed to unmarshal normalized app to json: %w", err)
}
@@ -176,12 +176,12 @@ func applyIgnoreDifferences(applicationSetIgnoreDifferences argov1alpha1.Applica
return fmt.Errorf("expected 1 normalized application, got %d", len(result.Targets))
}
foundNormalized.DeepCopyInto(found)
generatedJsonNormalized, err := json.Marshal(result.Targets[0].Object)
generatedJSONNormalized, err := json.Marshal(result.Targets[0].Object)
if err != nil {
return fmt.Errorf("failed to marshal normalized app to json: %w", err)
}
generatedAppNormalized := &argov1alpha1.Application{}
err = json.Unmarshal(generatedJsonNormalized, &generatedAppNormalized)
err = json.Unmarshal(generatedJSONNormalized, &generatedAppNormalized)
if err != nil {
return fmt.Errorf("failed to unmarshal normalized app json to structured app: %w", err)
}

View File

@@ -1,7 +1,6 @@
package utils
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
@@ -21,7 +20,7 @@ func TestGetSecretRef(t *testing.T) {
},
}
client := fake.NewClientBuilder().WithObjects(secret).Build()
ctx := context.Background()
ctx := t.Context()
cases := []struct {
name, namespace, token string
@@ -86,7 +85,7 @@ func TestGetConfigMapData(t *testing.T) {
},
}
client := fake.NewClientBuilder().WithObjects(configMap).Build()
ctx := context.Background()
ctx := t.Context()
cases := []struct {
name, namespace, data string

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.43.2. DO NOT EDIT.
// Code generated by mockery v2.52.4. DO NOT EDIT.
package mocks

View File

@@ -139,11 +139,11 @@ func (r *Render) deeplyReplace(copy, original reflect.Value, replaceMap map[stri
} else if currentType == "Raw.k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" || currentType == "Raw.k8s.io/apimachinery/pkg/runtime" {
var unmarshaled any
originalBytes := original.Field(i).Bytes()
convertedToJson, err := ConvertYAMLToJSON(string(originalBytes))
convertedToJSON, err := ConvertYAMLToJSON(string(originalBytes))
if err != nil {
return fmt.Errorf("error while converting template to json %q: %w", convertedToJson, err)
return fmt.Errorf("error while converting template to json %q: %w", convertedToJSON, err)
}
err = json.Unmarshal([]byte(convertedToJson), &unmarshaled)
err = json.Unmarshal([]byte(convertedToJSON), &unmarshaled)
if err != nil {
return fmt.Errorf("failed to unmarshal JSON field: %w", err)
}
@@ -489,7 +489,7 @@ func SlugifyName(args ...any) string {
return urlSlug
}
func getTlsConfigWithCACert(scmRootCAPath string, caCerts []byte) *tls.Config {
func getTLSConfigWithCACert(scmRootCAPath string, caCerts []byte) *tls.Config {
tlsConfig := &tls.Config{}
if scmRootCAPath != "" {
@@ -518,8 +518,8 @@ func getTlsConfigWithCACert(scmRootCAPath string, caCerts []byte) *tls.Config {
return tlsConfig
}
func GetTlsConfig(scmRootCAPath string, insecure bool, caCerts []byte) *tls.Config {
tlsConfig := getTlsConfigWithCACert(scmRootCAPath, caCerts)
func GetTlsConfig(scmRootCAPath string, insecure bool, caCerts []byte) *tls.Config { //nolint:revive //FIXME(var-naming)
tlsConfig := getTLSConfigWithCACert(scmRootCAPath, caCerts)
if insecure {
tlsConfig.InsecureSkipVerify = true

View File

@@ -1331,42 +1331,42 @@ WkBKOclmOV2xlTVuPw==
scmRootCAPath string
insecure bool
caCerts []byte
validateCertInTlsConfig bool
validateCertInTLSConfig bool
}{
{
name: "Insecure mode configured, SCM Root CA Path not set",
scmRootCAPath: "",
insecure: true,
caCerts: nil,
validateCertInTlsConfig: false,
validateCertInTLSConfig: false,
},
{
name: "SCM Root CA Path set, Insecure mode set to false",
scmRootCAPath: rootCAPath,
insecure: false,
caCerts: nil,
validateCertInTlsConfig: true,
validateCertInTLSConfig: true,
},
{
name: "SCM Root CA Path set, Insecure mode set to true",
scmRootCAPath: rootCAPath,
insecure: true,
caCerts: nil,
validateCertInTlsConfig: true,
validateCertInTLSConfig: true,
},
{
name: "Cert passed, Insecure mode set to false",
scmRootCAPath: "",
insecure: false,
caCerts: []byte(certFromCM),
validateCertInTlsConfig: true,
validateCertInTLSConfig: true,
},
{
name: "SCM Root CA Path set, cert passed, Insecure mode set to false",
scmRootCAPath: rootCAPath,
insecure: false,
caCerts: []byte(certFromCM),
validateCertInTlsConfig: true,
validateCertInTLSConfig: true,
},
}
@@ -1384,7 +1384,7 @@ WkBKOclmOV2xlTVuPw==
assert.True(t, ok)
}
assert.NotNil(t, tlsConfig)
if testCase.validateCertInTlsConfig {
if testCase.validateCertInTLSConfig {
assert.True(t, tlsConfig.RootCAs.Equal(certPool))
}
})

View File

@@ -1,65 +1,65 @@
{
"object_kind": "push",
"event_name": "push",
"before": "e5ba5f6c13b64670048daa88e4c053d60b0e115a",
"after": "bb0748feaa336d841c251017e4e374c22d0c8a98",
"ref": "refs/heads/master",
"checkout_sha": "bb0748feaa336d841c251017e4e374c22d0c8a98",
"message": null,
"user_id": 1,
"user_name": "name",
"user_username": "username",
"user_email": "",
"user_avatar": "",
"project_id": 1,
"project": {
"id": 1,
"name": "project",
"description": "",
"web_url": "https://gitlab/group/name",
"avatar_url": null,
"git_ssh_url": "ssh://git@gitlab:2222/group/name.git",
"git_http_url": "https://gitlab/group/name.git",
"namespace": "group",
"visibility_level": 1,
"path_with_namespace": "group/name",
"default_branch": "master",
"ci_config_path": null,
"homepage": "https://gitlab/group/name",
"url": "ssh://git@gitlab:2222/group/name.git",
"ssh_url": "ssh://git@gitlab:2222/group/name.git",
"http_url": "https://gitlab/group/name.git"
},
"commits": [
{
"id": "bb0748feaa336d841c251017e4e374c22d0c8a98",
"message": "Test commit message\n",
"timestamp": "2020-01-06T03:47:55Z",
"url": "https://gitlab/group/name/commit/bb0748feaa336d841c251017e4e374c22d0c8a98",
"author": {
"name": "User",
"email": "user@example.com"
},
"added": [
"file.yaml"
],
"modified": [
],
"removed": [
]
}
],
"total_commits_count": 1,
"push_options": {
},
"repository": {
"name": "name",
"url": "ssh://git@gitlab:2222/group/name.git",
"description": "",
"homepage": "https://gitlab/group/name",
"git_http_url": "https://gitlab/group/name.git",
"git_ssh_url": "ssh://git@gitlab:2222/group/name.git",
"visibility_level": 10
"object_kind": "push",
"event_name": "push",
"before": "e5ba5f6c13b64670048daa88e4c053d60b0e115a",
"after": "bb0748feaa336d841c251017e4e374c22d0c8a98",
"ref": "refs/heads/master",
"checkout_sha": "bb0748feaa336d841c251017e4e374c22d0c8a98",
"message": null,
"user_id": 1,
"user_name": "name",
"user_username": "username",
"user_email": "",
"user_avatar": "",
"project_id": 1,
"project": {
"id": 1,
"name": "project",
"description": "",
"web_url": "https://gitlab.com/group/name",
"avatar_url": null,
"git_ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
"git_http_url": "https://gitlab.com/group/name.git",
"namespace": "group",
"visibility_level": 1,
"path_with_namespace": "group/name",
"default_branch": "master",
"ci_config_path": null,
"homepage": "https://gitlab.com/group/name",
"url": "ssh://git@gitlab.com:2222/group/name.git",
"ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
"http_url": "https://gitlab.com/group/name.git"
},
"commits": [
{
"id": "bb0748feaa336d841c251017e4e374c22d0c8a98",
"message": "Test commit message\n",
"timestamp": "2020-01-06T03:47:55Z",
"url": "https://gitlab.com/group/name/commit/bb0748feaa336d841c251017e4e374c22d0c8a98",
"author": {
"name": "User",
"email": "user@example.com"
},
"added": [
"file.yaml"
],
"modified": [
],
"removed": [
]
}
}
],
"total_commits_count": 1,
"push_options": {
},
"repository": {
"name": "name",
"url": "ssh://git@gitlab.com:2222/group/name.git",
"description": "",
"homepage": "https://gitlab.com/group/name",
"git_http_url": "https://gitlab.com/group/name.git",
"git_ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
"visibility_level": 10
}
}

View File

@@ -14,7 +14,7 @@
"description": "",
"web_url": "https://gitlab.com/group/name",
"avatar_url": null,
"git_ssh_url": "ssh://git@gitlab:2222/group/name.git",
"git_ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
"git_http_url": "https://gitlab.com/group/name.git",
"namespace": "group",
"visibility_level": 1,
@@ -22,17 +22,17 @@
"default_branch": "master",
"ci_config_path": null,
"homepage": "https://gitlab.com/group/name",
"url": "ssh://git@gitlab:2222/group/name.git",
"ssh_url": "ssh://git@gitlab:2222/group/name.git",
"url": "ssh://git@gitlab.com:2222/group/name.git",
"ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
"http_url": "https://gitlab.com/group/name.git"
},
"repository": {
"name": "name",
"url": "ssh://git@gitlab:2222/group/name.git",
"url": "ssh://git@gitlab.com:2222/group/name.git",
"description": "",
"homepage": "https://gitlab.com/group/name",
"git_http_url": "https://gitlab.com/group/name.git",
"git_ssh_url": "ssh://git@gitlab:2222/group/name.git",
"git_ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
"visibility_level": 10
},
"object_attributes": {
@@ -60,7 +60,7 @@
"description": "Aut reprehenderit ut est.",
"web_url": "https://gitlab.com/group/name",
"avatar_url": null,
"git_ssh_url": "ssh://git@gitlab:2222/group/name.git",
"git_ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
"git_http_url": "https://gitlab.com/group/name.git",
"namespace": "Awesome Space",
"visibility_level": 20,
@@ -68,7 +68,7 @@
"default_branch": "master",
"homepage": "https://gitlab.com/group/name",
"url": "https://gitlab.com/group/name.git",
"ssh_url": "ssh://git@gitlab:2222/group/name.git",
"ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
"http_url": "https://gitlab.com/group/name.git"
},
"target": {
@@ -76,7 +76,7 @@
"description": "Aut reprehenderit ut est.",
"web_url": "https://gitlab.com/group/name",
"avatar_url": null,
"git_ssh_url": "ssh://git@gitlab:2222/group/name.git",
"git_ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
"git_http_url": "https://gitlab.com/group/name.git",
"namespace": "Awesome Space",
"visibility_level": 20,
@@ -84,7 +84,7 @@
"default_branch": "master",
"homepage": "https://gitlab.com/group/name",
"url": "https://gitlab.com/group/name.git",
"ssh_url": "ssh://git@gitlab:2222/group/name.git",
"ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
"http_url": "https://gitlab.com/group/name.git"
},
"last_commit": {

View File

@@ -14,7 +14,7 @@
"description": "",
"web_url": "https://gitlab.com/group/name",
"avatar_url": null,
"git_ssh_url": "ssh://git@gitlab:2222/group/name.git",
"git_ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
"git_http_url": "https://gitlab.com/group/name.git",
"namespace": "group",
"visibility_level": 1,
@@ -22,17 +22,17 @@
"default_branch": "master",
"ci_config_path": null,
"homepage": "https://gitlab.com/group/name",
"url": "ssh://git@gitlab:2222/group/name.git",
"ssh_url": "ssh://git@gitlab:2222/group/name.git",
"url": "ssh://git@gitlab.com:2222/group/name.git",
"ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
"http_url": "https://gitlab.com/group/name.git"
},
"repository": {
"name": "name",
"url": "ssh://git@gitlab:2222/group/name.git",
"url": "ssh://git@gitlab.com:2222/group/name.git",
"description": "",
"homepage": "https://gitlab.com/group/name",
"git_http_url": "https://gitlab.com/group/name.git",
"git_ssh_url": "ssh://git@gitlab:2222/group/name.git",
"git_ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
"visibility_level": 10
},
"object_attributes": {
@@ -60,7 +60,7 @@
"description": "Aut reprehenderit ut est.",
"web_url": "https://gitlab.com/group/name",
"avatar_url": null,
"git_ssh_url": "ssh://git@gitlab:2222/group/name.git",
"git_ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
"git_http_url": "https://gitlab.com/group/name.git",
"namespace": "Awesome Space",
"visibility_level": 20,
@@ -68,7 +68,7 @@
"default_branch": "master",
"homepage": "https://gitlab.com/group/name",
"url": "https://gitlab.com/group/name.git",
"ssh_url": "ssh://git@gitlab:2222/group/name.git",
"ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
"http_url": "https://gitlab.com/group/name.git"
},
"target": {
@@ -76,7 +76,7 @@
"description": "Aut reprehenderit ut est.",
"web_url": "https://gitlab.com/group/name",
"avatar_url": null,
"git_ssh_url": "ssh://git@gitlab:2222/group/name.git",
"git_ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
"git_http_url": "https://gitlab.com/group/name.git",
"namespace": "Awesome Space",
"visibility_level": 20,
@@ -84,7 +84,7 @@
"default_branch": "master",
"homepage": "https://gitlab.com/group/name",
"url": "https://gitlab.com/group/name.git",
"ssh_url": "ssh://git@gitlab:2222/group/name.git",
"ssh_url": "ssh://git@gitlab.com:2222/group/name.git",
"http_url": "https://gitlab.com/group/name.git"
},
"last_commit": {

View File

@@ -217,13 +217,7 @@ func getGitGeneratorInfo(payload any) *gitGeneratorInfo {
}
log.Infof("Received push event repo: %s, revision: %s, touchedHead: %v", webURL, revision, touchedHead)
urlObj, err := url.Parse(webURL)
if err != nil {
log.Errorf("Failed to parse repoURL '%s'", webURL)
return nil
}
regexpStr := `(?i)(http://|https://|\w+@|ssh://(\w+@)?)` + urlObj.Hostname() + "(:[0-9]+|)[:/]" + urlObj.Path[1:] + "(\\.git)?$"
repoRegexp, err := regexp.Compile(regexpStr)
repoRegexp, err := webhook.GetWebURLRegex(webURL)
if err != nil {
log.Errorf("Failed to compile regexp for repoURL '%s'", webURL)
return nil
@@ -245,13 +239,7 @@ func getPRGeneratorInfo(payload any) *prGeneratorInfo {
}
apiURL := payload.Repository.URL
urlObj, err := url.Parse(apiURL)
if err != nil {
log.Errorf("Failed to parse repoURL '%s'", apiURL)
return nil
}
regexpStr := `(?i)(http://|https://|\w+@|ssh://(\w+@)?)` + urlObj.Hostname() + "(:[0-9]+|)[:/]"
apiRegexp, err := regexp.Compile(regexpStr)
apiRegexp, err := webhook.GetAPIURLRegex(apiURL)
if err != nil {
log.Errorf("Failed to compile regexp for repoURL '%s'", apiURL)
return nil

View File

@@ -2,7 +2,6 @@ package webhook
import (
"bytes"
"context"
"fmt"
"io"
"net/http"
@@ -63,7 +62,7 @@ func TestWebhookHandler(t *testing.T) {
headerKey: "X-GitHub-Event",
headerValue: "push",
payloadFile: "github-commit-event.json",
effectedAppSets: []string{"git-github", "matrix-git-github", "merge-git-github", "matrix-scm-git-github", "matrix-nested-git-github", "merge-nested-git-github", "plugin", "matrix-pull-request-github-plugin"},
effectedAppSets: []string{"git-github", "git-github-ssh", "git-github-alt-ssh", "matrix-git-github", "merge-git-github", "matrix-scm-git-github", "matrix-nested-git-github", "merge-nested-git-github", "plugin", "matrix-pull-request-github-plugin"},
expectedStatusCode: http.StatusOK,
expectedRefresh: true,
},
@@ -81,7 +80,7 @@ func TestWebhookHandler(t *testing.T) {
headerKey: "X-GitHub-Event",
headerValue: "push",
payloadFile: "github-commit-branch-event.json",
effectedAppSets: []string{"git-github", "plugin", "matrix-pull-request-github-plugin"},
effectedAppSets: []string{"git-github", "git-github-ssh", "git-github-alt-ssh", "plugin", "matrix-pull-request-github-plugin"},
expectedStatusCode: http.StatusOK,
expectedRefresh: true,
},
@@ -90,7 +89,7 @@ func TestWebhookHandler(t *testing.T) {
headerKey: "X-GitHub-Event",
headerValue: "ping",
payloadFile: "github-ping-event.json",
effectedAppSets: []string{"git-github", "plugin"},
effectedAppSets: []string{"git-github", "git-github-ssh", "git-github-alt-ssh", "plugin"},
expectedStatusCode: http.StatusOK,
expectedRefresh: false,
},
@@ -99,7 +98,7 @@ func TestWebhookHandler(t *testing.T) {
headerKey: "X-Gitlab-Event",
headerValue: "Push Hook",
payloadFile: "gitlab-event.json",
effectedAppSets: []string{"git-gitlab", "plugin", "matrix-pull-request-github-plugin"},
effectedAppSets: []string{"git-gitlab", "git-gitlab-ssh", "git-gitlab-alt-ssh", "plugin", "matrix-pull-request-github-plugin"},
expectedStatusCode: http.StatusOK,
expectedRefresh: true,
},
@@ -108,7 +107,7 @@ func TestWebhookHandler(t *testing.T) {
headerKey: "X-Gitlab-Event",
headerValue: "System Hook",
payloadFile: "gitlab-event.json",
effectedAppSets: []string{"git-gitlab", "plugin", "matrix-pull-request-github-plugin"},
effectedAppSets: []string{"git-gitlab", "git-gitlab-ssh", "git-gitlab-alt-ssh", "plugin", "matrix-pull-request-github-plugin"},
expectedStatusCode: http.StatusOK,
expectedRefresh: true,
},
@@ -117,7 +116,7 @@ func TestWebhookHandler(t *testing.T) {
headerKey: "X-Random-Event",
headerValue: "Push Hook",
payloadFile: "gitlab-event.json",
effectedAppSets: []string{"git-gitlab", "plugin"},
effectedAppSets: []string{"git-gitlab", "git-gitlab-ssh", "git-gitlab-alt-ssh", "plugin"},
expectedStatusCode: http.StatusBadRequest,
expectedRefresh: false,
},
@@ -126,7 +125,7 @@ func TestWebhookHandler(t *testing.T) {
headerKey: "X-Random-Event",
headerValue: "Push Hook",
payloadFile: "invalid-event.json",
effectedAppSets: []string{"git-gitlab", "plugin"},
effectedAppSets: []string{"git-gitlab", "git-gitlab-ssh", "git-gitlab-alt-ssh", "plugin"},
expectedStatusCode: http.StatusBadRequest,
expectedRefresh: false,
},
@@ -209,7 +208,11 @@ func TestWebhookHandler(t *testing.T) {
fc := fake.NewClientBuilder().WithScheme(scheme).WithObjects(
fakeAppWithGitGenerator("git-github", namespace, "https://github.com/org/repo"),
fakeAppWithGitGenerator("git-github-copy", namespace, "https://github.com/org/repo-copy"),
fakeAppWithGitGenerator("git-gitlab", namespace, "https://gitlab/group/name"),
fakeAppWithGitGenerator("git-github-ssh", namespace, "ssh://git@github.com/org/repo"),
fakeAppWithGitGenerator("git-github-alt-ssh", namespace, "ssh://git@ssh.github.com:443/org/repo"),
fakeAppWithGitGenerator("git-gitlab", namespace, "https://gitlab.com/group/name"),
fakeAppWithGitGenerator("git-gitlab-ssh", namespace, "ssh://git@gitlab.com/group/name"),
fakeAppWithGitGenerator("git-gitlab-alt-ssh", namespace, "ssh://git@altssh.gitlab.com:443/group/name"),
fakeAppWithGitGenerator("git-azure-devops", namespace, "https://dev.azure.com/fabrikam-fiber-inc/DefaultCollection/_git/Fabrikam-Fiber-Git"),
fakeAppWithGitGeneratorWithRevision("github-shorthand", namespace, "https://github.com/org/repo", "env/dev"),
fakeAppWithGithubPullRequestGenerator("pull-request-github", namespace, "CodErTOcat", "Hello-World"),
@@ -226,7 +229,7 @@ func TestWebhookHandler(t *testing.T) {
fakeAppWithMergeAndPullRequestGenerator("merge-pull-request-github", namespace, "Codertocat", "Hello-World"),
fakeAppWithMergeAndNestedGitGenerator("merge-nested-git-github", namespace, "https://github.com/org/repo"),
).Build()
set := argosettings.NewSettingsManager(context.TODO(), fakeClient, namespace)
set := argosettings.NewSettingsManager(t.Context(), fakeClient, namespace)
h, err := NewWebhookHandler(namespace, webhookParallelism, set, fc, mockGenerators())
require.NoError(t, err)
@@ -243,7 +246,7 @@ func TestWebhookHandler(t *testing.T) {
assert.Equal(t, test.expectedStatusCode, w.Code)
list := &v1alpha1.ApplicationSetList{}
err = fc.List(context.TODO(), list)
err = fc.List(t.Context(), list)
require.NoError(t, err)
effectedAppSetsAsExpected := make(map[string]bool)
for _, appSetName := range test.effectedAppSets {

156
assets/swagger.json generated
View File

@@ -920,6 +920,11 @@
"type": "string",
"name": "project",
"in": "query"
},
{
"type": "boolean",
"name": "matchCase",
"in": "query"
}
],
"responses": {
@@ -1153,6 +1158,11 @@
"type": "string",
"name": "project",
"in": "query"
},
{
"type": "boolean",
"name": "matchCase",
"in": "query"
}
],
"responses": {
@@ -3777,6 +3787,12 @@
"description": "Whether to use azure workload identity for authentication.",
"name": "useAzureWorkloadIdentity",
"in": "query"
},
{
"type": "string",
"description": "BearerToken contains the bearer token used for Git auth at the repo server.",
"name": "bearerToken",
"in": "query"
}
],
"responses": {
@@ -4609,6 +4625,12 @@
"description": "Whether to use azure workload identity for authentication.",
"name": "useAzureWorkloadIdentity",
"in": "query"
},
{
"type": "string",
"description": "BearerToken contains the bearer token used for Git auth at the repo server.",
"name": "bearerToken",
"in": "query"
}
],
"responses": {
@@ -5079,41 +5101,51 @@
}
},
"applicationv1alpha1ResourceStatus": {
"description": "ResourceStatus holds the current synchronization and health status of a Kubernetes resource.",
"type": "object",
"title": "ResourceStatus holds the current sync and health status of a resource\nTODO: describe members of this type",
"properties": {
"group": {
"description": "Group represents the API group of the resource (e.g., \"apps\" for Deployments).",
"type": "string"
},
"health": {
"$ref": "#/definitions/v1alpha1HealthStatus"
},
"hook": {
"description": "Hook is true if the resource is used as a lifecycle hook in an Argo CD application.",
"type": "boolean"
},
"kind": {
"description": "Kind specifies the type of the resource (e.g., \"Deployment\", \"Service\").",
"type": "string"
},
"name": {
"description": "Name is the unique name of the resource within the namespace.",
"type": "string"
},
"namespace": {
"description": "Namespace defines the Kubernetes namespace where the resource is located.",
"type": "string"
},
"requiresDeletionConfirmation": {
"description": "RequiresDeletionConfirmation is true if the resource requires explicit user confirmation before deletion.",
"type": "boolean"
},
"requiresPruning": {
"description": "RequiresPruning is true if the resource needs to be pruned (deleted) as part of synchronization.",
"type": "boolean"
},
"status": {
"description": "Status represents the synchronization state of the resource (e.g., Synced, OutOfSync).",
"type": "string"
},
"syncWave": {
"description": "SyncWave determines the order in which resources are applied during a sync operation.\nLower values are applied first.",
"type": "integer",
"format": "int64"
},
"version": {
"description": "Version indicates the API version of the resource (e.g., \"v1\", \"v1beta1\").",
"type": "string"
}
}
@@ -6407,6 +6439,7 @@
},
"v1PortStatus": {
"type": "object",
"title": "PortStatus represents the error condition of a service port",
"properties": {
"error": {
"type": "string",
@@ -6916,8 +6949,8 @@
"type": "object",
"properties": {
"applyNestedSelectors": {
"type": "boolean",
"title": "ApplyNestedSelectors enables selectors defined within the generators of two level-nested matrix or merge generators"
"description": "ApplyNestedSelectors enables selectors defined within the generators of two level-nested matrix or merge generators\nDeprecated: This field is ignored, and the behavior is always enabled. The field will be removed in a future\nversion of the ApplicationSet CRD.",
"type": "boolean"
},
"generators": {
"type": "array",
@@ -7275,6 +7308,10 @@
"type": "boolean",
"title": "ForceCommonLabels specifies whether to force applying common labels to resources for Kustomize apps"
},
"ignoreMissingComponents": {
"type": "boolean",
"title": "IgnoreMissingComponents prevents kustomize from failing when components do not exist locally by not appending them to kustomization file"
},
"images": {
"type": "array",
"title": "Images is a list of Kustomize image override specifications",
@@ -7286,6 +7323,10 @@
"description": "KubeVersion specifies the Kubernetes API version to pass to Helm when templating manifests. By default, Argo CD\nuses the Kubernetes version of the target cluster.",
"type": "string"
},
"labelIncludeTemplates": {
"type": "boolean",
"title": "LabelIncludeTemplates specifies whether to apply common labels to resource templates or not"
},
"labelWithoutSelector": {
"type": "boolean",
"title": "LabelWithoutSelector specifies whether to apply common labels to resource selectors or not"
@@ -7506,34 +7547,34 @@
}
},
"v1alpha1ApplicationTree": {
"description": "ApplicationTree represents the hierarchical structure of resources associated with an Argo CD application.",
"type": "object",
"title": "ApplicationTree holds nodes which belongs to the application\nTODO: describe purpose of this type",
"properties": {
"hosts": {
"description": "Hosts provides a list of Kubernetes nodes that are running pods related to the application.",
"type": "array",
"title": "Hosts holds list of Kubernetes nodes that run application related pods",
"items": {
"$ref": "#/definitions/v1alpha1HostInfo"
}
},
"nodes": {
"description": "Nodes contains list of nodes which either directly managed by the application and children of directly managed nodes.",
"description": "Nodes contains a list of resources that are either directly managed by the application\nor are children of directly managed resources.",
"type": "array",
"items": {
"$ref": "#/definitions/v1alpha1ResourceNode"
}
},
"orphanedNodes": {
"description": "OrphanedNodes contains if or orphaned nodes: nodes which are not managed by the app but in the same namespace. List is populated only if orphaned resources enabled in app project.",
"description": "OrphanedNodes contains resources that exist in the same namespace as the application\nbut are not managed by it. This list is populated only if orphaned resource tracking\nis enabled in the application's project settings.",
"type": "array",
"items": {
"$ref": "#/definitions/v1alpha1ResourceNode"
}
},
"shardsCount": {
"description": "ShardsCount represents the total number of shards the application tree is split into.\nThis is used to distribute resource processing across multiple shards.",
"type": "integer",
"format": "int64",
"title": "ShardsCount contains total number of shards the application tree is split into"
"format": "int64"
}
}
},
@@ -8127,13 +8168,15 @@
}
},
"v1alpha1HostInfo": {
"description": "HostInfo holds metadata and resource usage metrics for a specific host in the cluster.",
"type": "object",
"title": "HostInfo holds host name and resources metrics\nTODO: describe purpose of this type\nTODO: describe members of this type",
"properties": {
"name": {
"description": "Name is the hostname or node name in the Kubernetes cluster.",
"type": "string"
},
"resourcesInfo": {
"description": "ResourcesInfo provides a list of resource usage details for different resource types on this host.",
"type": "array",
"items": {
"$ref": "#/definitions/v1alpha1HostResourceInfo"
@@ -8145,22 +8188,26 @@
}
},
"v1alpha1HostResourceInfo": {
"description": "HostResourceInfo represents resource usage details for a specific resource type on a host.",
"type": "object",
"title": "TODO: describe this type",
"properties": {
"capacity": {
"description": "Capacity represents the total available capacity of this resource on the host.",
"type": "integer",
"format": "int64"
},
"requestedByApp": {
"description": "RequestedByApp indicates the total amount of this resource requested by the application running on the host.",
"type": "integer",
"format": "int64"
},
"requestedByNeighbors": {
"description": "RequestedByNeighbors indicates the total amount of this resource requested by other workloads on the same host.",
"type": "integer",
"format": "int64"
},
"resourceName": {
"description": "ResourceName specifies the type of resource (e.g., CPU, memory, storage).",
"type": "string"
}
}
@@ -8276,13 +8323,15 @@
}
},
"v1alpha1KnownTypeField": {
"description": "KnownTypeField contains a mapping between a Custom Resource Definition (CRD) field\nand a well-known Kubernetes type. This mapping is primarily used for unit conversions\nin resources where the type is not explicitly defined (e.g., converting \"0.1\" to \"100m\" for CPU requests).",
"type": "object",
"title": "KnownTypeField contains mapping between CRD field and known Kubernetes type.\nThis is mainly used for unit conversion in unknown resources (e.g. 0.1 == 100mi)\nTODO: Describe the members of this type",
"properties": {
"field": {
"type": "string"
"type": "string",
"title": "Field represents the JSON path to the specific field in the CRD that requires type conversion.\nExample: \"spec.resources.requests.cpu\""
},
"type": {
"description": "Type specifies the expected Kubernetes type for the field, such as \"cpu\" or \"memory\".\nThis helps in converting values between different formats (e.g., \"0.1\" to \"100m\" for CPU).",
"type": "string"
}
}
@@ -8692,6 +8741,13 @@
},
"template": {
"$ref": "#/definitions/v1alpha1ApplicationSetTemplate"
},
"values": {
"type": "object",
"title": "Values contains key/value pairs which are passed directly as parameters to the template",
"additionalProperties": {
"type": "string"
}
}
}
},
@@ -8890,6 +8946,10 @@
"type": "object",
"title": "RepoCreds holds the definition for repository credentials",
"properties": {
"bearerToken": {
"type": "string",
"title": "BearerToken contains the bearer token used for Git BitBucket Data Center auth at the repo server"
},
"enableOCI": {
"type": "boolean",
"title": "EnableOCI specifies whether helm-oci support should be enabled for this repo"
@@ -8981,6 +9041,10 @@
"type": "object",
"title": "Repository is a repository holding application configurations",
"properties": {
"bearerToken": {
"type": "string",
"title": "BearerToken contains the bearer token used for Git BitBucket Data Center auth at the repo server"
},
"connectionState": {
"$ref": "#/definitions/v1alpha1ConnectionState"
},
@@ -9139,22 +9203,27 @@
}
},
"v1alpha1ResourceAction": {
"description": "ResourceAction represents an individual action that can be performed on a resource.\nIt includes parameters, an optional disabled flag, an icon for display, and a name for the action.",
"type": "object",
"title": "TODO: describe this type\nTODO: describe members of this type",
"properties": {
"disabled": {
"description": "Disabled indicates whether the action is disabled.",
"type": "boolean"
},
"displayName": {
"description": "DisplayName provides a user-friendly name for the action.",
"type": "string"
},
"iconClass": {
"description": "IconClass specifies the CSS class for the action's icon.",
"type": "string"
},
"name": {
"description": "Name is the name or identifier for the action.",
"type": "string"
},
"params": {
"description": "Params contains the parameters required to execute the action.",
"type": "array",
"items": {
"$ref": "#/definitions/v1alpha1ResourceActionParam"
@@ -9163,67 +9232,78 @@
}
},
"v1alpha1ResourceActionParam": {
"description": "ResourceActionParam represents a parameter for a resource action.\nIt includes a name, value, type, and an optional default value for the parameter.",
"type": "object",
"title": "TODO: describe this type\nTODO: describe members of this type",
"properties": {
"default": {
"description": "Default is the default value of the parameter, if any.",
"type": "string"
},
"name": {
"description": "Name is the name of the parameter.",
"type": "string"
},
"type": {
"description": "Type is the type of the parameter (e.g., string, integer).",
"type": "string"
},
"value": {
"description": "Value is the value of the parameter.",
"type": "string"
}
}
},
"v1alpha1ResourceDiff": {
"description": "ResourceDiff holds the diff between a live and target resource object in Argo CD.\nIt is used to compare the desired state (from Git/Helm) with the actual state in the cluster.",
"type": "object",
"title": "ResourceDiff holds the diff of a live and target resource object\nTODO: describe members of this type",
"properties": {
"diff": {
"type": "string",
"title": "Diff contains the JSON patch between target and live resource\nDeprecated: use NormalizedLiveState and PredictedLiveState to render the difference"
"description": "Diff contains the JSON patch representing the difference between the live and target resource.\nDeprecated: Use NormalizedLiveState and PredictedLiveState instead to compute differences.",
"type": "string"
},
"group": {
"description": "Group represents the API group of the resource (e.g., \"apps\" for Deployments).",
"type": "string"
},
"hook": {
"description": "Hook indicates whether this resource is a hook resource (e.g., pre-sync or post-sync hooks).",
"type": "boolean"
},
"kind": {
"description": "Kind represents the Kubernetes resource kind (e.g., \"Deployment\", \"Service\").",
"type": "string"
},
"liveState": {
"type": "string",
"title": "TargetState contains the JSON live resource manifest"
"description": "LiveState contains the JSON-serialized resource manifest of the resource currently running in the cluster.",
"type": "string"
},
"modified": {
"description": "Modified indicates whether the live resource has changes compared to the target resource.",
"type": "boolean"
},
"name": {
"description": "Name is the name of the resource.",
"type": "string"
},
"namespace": {
"description": "Namespace specifies the namespace where the resource exists.",
"type": "string"
},
"normalizedLiveState": {
"type": "string",
"title": "NormalizedLiveState contains JSON serialized live resource state with applied normalizations"
"description": "NormalizedLiveState contains the JSON-serialized live resource state after applying normalizations.\nNormalizations may include ignoring irrelevant fields like timestamps or defaults applied by Kubernetes.",
"type": "string"
},
"predictedLiveState": {
"type": "string",
"title": "PredictedLiveState contains JSON serialized resource state that is calculated based on normalized and target resource state"
"description": "PredictedLiveState contains the JSON-serialized resource state that Argo CD predicts based on the\ncombination of the normalized live state and the desired target state.",
"type": "string"
},
"resourceVersion": {
"description": "ResourceVersion is the Kubernetes resource version, which helps in tracking changes.",
"type": "string"
},
"targetState": {
"type": "string",
"title": "TargetState contains the JSON serialized resource manifest defined in the Git/Helm"
"description": "TargetState contains the JSON-serialized resource manifest as defined in the Git/Helm repository.",
"type": "string"
}
}
},
@@ -9265,35 +9345,39 @@
}
},
"v1alpha1ResourceNetworkingInfo": {
"description": "ResourceNetworkingInfo holds networking-related information for a resource.",
"type": "object",
"title": "ResourceNetworkingInfo holds networking resource related information\nTODO: describe members of this type",
"properties": {
"externalURLs": {
"description": "ExternalURLs holds list of URLs which should be available externally. List is populated for ingress resources using rules hostnames.",
"description": "ExternalURLs holds a list of URLs that should be accessible externally.\nThis field is typically populated for Ingress resources based on their hostname rules.",
"type": "array",
"items": {
"type": "string"
}
},
"ingress": {
"description": "Ingress provides information about external access points (e.g., load balancer ingress) for this resource.",
"type": "array",
"items": {
"$ref": "#/definitions/v1LoadBalancerIngress"
}
},
"labels": {
"description": "Labels holds the labels associated with this networking resource.",
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"targetLabels": {
"description": "TargetLabels represents labels associated with the target resources that this resource communicates with.",
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"targetRefs": {
"description": "TargetRefs contains references to other resources that this resource interacts with, such as Services or Pods.",
"type": "array",
"items": {
"$ref": "#/definitions/v1alpha1ResourceRef"
@@ -9302,8 +9386,8 @@
}
},
"v1alpha1ResourceNode": {
"description": "ResourceNode contains information about a live Kubernetes resource and its relationships with other resources.",
"type": "object",
"title": "ResourceNode contains information about live resource and its children\nTODO: describe members of this type",
"properties": {
"createdAt": {
"$ref": "#/definitions/v1Time"
@@ -9312,12 +9396,14 @@
"$ref": "#/definitions/v1alpha1HealthStatus"
},
"images": {
"description": "Images lists container images associated with the resource.\nThis is primarily useful for pods and other workload resources.",
"type": "array",
"items": {
"type": "string"
}
},
"info": {
"description": "Info provides additional metadata or annotations about the resource.",
"type": "array",
"items": {
"$ref": "#/definitions/v1alpha1InfoItem"
@@ -9327,12 +9413,14 @@
"$ref": "#/definitions/v1alpha1ResourceNetworkingInfo"
},
"parentRefs": {
"description": "ParentRefs lists the parent resources that reference this resource.\nThis helps in understanding ownership and hierarchical relationships.",
"type": "array",
"items": {
"$ref": "#/definitions/v1alpha1ResourceRef"
}
},
"resourceVersion": {
"description": "ResourceVersion indicates the version of the resource, used to track changes.",
"type": "string"
}
},
@@ -9344,12 +9432,14 @@
},
"v1alpha1ResourceOverride": {
"type": "object",
"title": "ResourceOverride holds configuration to customize resource diffing and health assessment\nTODO: describe the members of this type",
"title": "ResourceOverride holds configuration to customize resource diffing and health assessment",
"properties": {
"actions": {
"description": "Actions defines the set of actions that can be performed on the resource, as a Lua script.",
"type": "string"
},
"healthLua": {
"description": "HealthLua contains a Lua script that defines custom health checks for the resource.",
"type": "string"
},
"ignoreDifferences": {
@@ -9359,12 +9449,14 @@
"$ref": "#/definitions/v1alpha1OverrideIgnoreDiff"
},
"knownTypeFields": {
"description": "KnownTypeFields lists fields for which unit conversions should be applied.",
"type": "array",
"items": {
"$ref": "#/definitions/v1alpha1KnownTypeField"
}
},
"useOpenLibs": {
"description": "UseOpenLibs indicates whether to use open-source libraries for the resource.",
"type": "boolean"
}
}
@@ -10097,6 +10189,10 @@
"type": "object",
"title": "SyncWindow contains the kind, time, duration and attributes that are used to assign the syncWindows to apps",
"properties": {
"andOperator": {
"type": "boolean",
"title": "UseAndOperator use AND operator for matching applications, namespaces and clusters instead of the default OR operator"
},
"applications": {
"type": "array",
"title": "Applications contains a list of applications that the window will apply to",

View File

@@ -259,7 +259,7 @@ func NewCommand() *cobra.Command {
command.Flags().StringVar(&commitServerAddress, "commit-server", env.StringFromEnv("ARGOCD_APPLICATION_CONTROLLER_COMMIT_SERVER", common.DefaultCommitServerAddr), "Commit server address.")
command.Flags().IntVar(&statusProcessors, "status-processors", env.ParseNumFromEnv("ARGOCD_APPLICATION_CONTROLLER_STATUS_PROCESSORS", 20, 0, math.MaxInt32), "Number of application status processors")
command.Flags().IntVar(&operationProcessors, "operation-processors", env.ParseNumFromEnv("ARGOCD_APPLICATION_CONTROLLER_OPERATION_PROCESSORS", 10, 0, math.MaxInt32), "Number of application operation processors")
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_APPLICATION_CONTROLLER_LOGFORMAT", "text"), "Set the logging format. One of: text|json")
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_APPLICATION_CONTROLLER_LOGFORMAT", "json"), "Set the logging format. One of: json|text")
command.Flags().StringVar(&cmdutil.LogLevel, "loglevel", env.StringFromEnv("ARGOCD_APPLICATION_CONTROLLER_LOGLEVEL", "info"), "Set the logging level. One of: debug|info|warn|error")
command.Flags().IntVar(&glogLevel, "gloglevel", 0, "Set the glog logging level")
command.Flags().IntVar(&metricsPort, "metrics-port", common.DefaultPortArgoCDMetrics, "Start metrics server on given port")
@@ -280,7 +280,7 @@ func NewCommand() *cobra.Command {
command.Flags().StringToStringVar(&otlpHeaders, "otlp-headers", env.ParseStringToStringFromEnv("ARGOCD_APPLICATION_CONTROLLER_OTLP_HEADERS", map[string]string{}, ","), "List of OpenTelemetry collector extra headers sent with traces, headers are comma-separated key-value pairs(e.g. key1=value1,key2=value2)")
command.Flags().StringSliceVar(&otlpAttrs, "otlp-attrs", env.StringsFromEnv("ARGOCD_APPLICATION_CONTROLLER_OTLP_ATTRS", []string{}, ","), "List of OpenTelemetry collector extra attrs when send traces, each attribute is separated by a colon(e.g. key:value)")
command.Flags().StringSliceVar(&applicationNamespaces, "application-namespaces", env.StringsFromEnv("ARGOCD_APPLICATION_NAMESPACES", []string{}, ","), "List of additional namespaces that applications are allowed to be reconciled from")
command.Flags().BoolVar(&persistResourceHealth, "persist-resource-health", env.ParseBoolFromEnv("ARGOCD_APPLICATION_CONTROLLER_PERSIST_RESOURCE_HEALTH", true), "Enables storing the managed resources health in the Application CRD")
command.Flags().BoolVar(&persistResourceHealth, "persist-resource-health", env.ParseBoolFromEnv("ARGOCD_APPLICATION_CONTROLLER_PERSIST_RESOURCE_HEALTH", false), "Enables storing the managed resources health in the Application CRD")
command.Flags().StringVar(&shardingAlgorithm, "sharding-method", env.StringFromEnv(common.EnvControllerShardingAlgorithm, common.DefaultShardingAlgorithm), "Enables choice of sharding method. Supported sharding methods are : [legacy, round-robin, consistent-hashing] ")
// global queue rate limit config
command.Flags().Int64Var(&workqueueRateLimit.BucketSize, "wq-bucket-size", env.ParseInt64FromEnv("WORKQUEUE_BUCKET_SIZE", 500, 1, math.MaxInt64), "Set Workqueue Rate Limiter Bucket Size, default 500")

View File

@@ -188,8 +188,7 @@ func NewCommand() *cobra.Command {
}
repoClientset := apiclient.NewRepoServerClientset(argocdRepoServer, repoServerTimeoutSeconds, tlsConfig)
argoCDService, err := services.NewArgoCDService(argoCDDB.GetRepository, gitSubmoduleEnabled, repoClientset, enableNewGitFileGlobbing)
errors.CheckError(err)
argoCDService := services.NewArgoCDService(argoCDDB, gitSubmoduleEnabled, repoClientset, enableNewGitFileGlobbing)
topLevelGenerators := generators.GetGenerators(ctx, mgr.GetClient(), k8sClient, namespace, argoCDService, dynamicClient, scmConfig)
@@ -252,7 +251,7 @@ func NewCommand() *cobra.Command {
command.Flags().StringVar(&policy, "policy", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_POLICY", ""), "Modify how application is synced between the generator and the cluster. Default is '' (empty), which means AppSets default to 'sync', but they may override that default. Setting an explicit value prevents AppSet-level overrides, unless --allow-policy-override is enabled. Explicit options are: 'sync' (create & update & delete), 'create-only', 'create-update' (no deletion), 'create-delete' (no update)")
command.Flags().BoolVar(&enablePolicyOverride, "enable-policy-override", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_POLICY_OVERRIDE", policy == ""), "For security reason if 'policy' is set, it is not possible to override it at applicationSet level. 'allow-policy-override' allows user to define their own policy")
command.Flags().BoolVar(&debugLog, "debug", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_DEBUG", false), "Print debug logs. Takes precedence over loglevel")
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_LOGFORMAT", "text"), "Set the logging format. One of: text|json")
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_LOGFORMAT", "json"), "Set the logging format. One of: json|text")
command.Flags().StringVar(&cmdutil.LogLevel, "loglevel", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_LOGLEVEL", "info"), "Set the logging level. One of: debug|info|warn|error")
command.Flags().StringSliceVar(&allowedScmProviders, "allowed-scm-providers", env.StringsFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_ALLOWED_SCM_PROVIDERS", []string{}, ","), "The list of allowed custom SCM provider API URLs. This restriction does not apply to SCM or PR generators which do not accept a custom API URL. (Default: Empty = all)")
command.Flags().BoolVar(&enableScmProviders, "enable-scm-providers", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_SCM_PROVIDERS", true), "Enable retrieving information from SCM providers, used by the SCM and PR generators (Default: true)")

View File

@@ -89,7 +89,7 @@ func NewCommand() *cobra.Command {
},
}
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_CMP_SERVER_LOGFORMAT", "text"), "Set the logging format. One of: text|json")
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_CMP_SERVER_LOGFORMAT", "json"), "Set the logging format. One of: json|text")
command.Flags().StringVar(&cmdutil.LogLevel, "loglevel", env.StringFromEnv("ARGOCD_CMP_SERVER_LOGLEVEL", "info"), "Set the logging level. One of: trace|debug|info|warn|error")
command.Flags().StringVar(&configFilePath, "config-dir-path", common.DefaultPluginConfigFilePath, "Config management plugin configuration file location, Default is '/home/argocd/cmp-server/config/'")
command.Flags().StringVar(&otlpAddress, "otlp-address", env.StringFromEnv("ARGOCD_CMP_SERVER_OTLP_ADDRESS", ""), "OpenTelemetry collector address to send traces to")

View File

@@ -106,7 +106,7 @@ func NewCommand() *cobra.Command {
return nil
},
}
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_COMMIT_SERVER_LOGFORMAT", "text"), "Set the logging format. One of: text|json")
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_COMMIT_SERVER_LOGFORMAT", "json"), "Set the logging format. One of: json|text")
command.Flags().StringVar(&cmdutil.LogLevel, "loglevel", env.StringFromEnv("ARGOCD_COMMIT_SERVER_LOGLEVEL", "info"), "Set the logging level. One of: debug|info|warn|error")
command.Flags().StringVar(&listenHost, "address", env.StringFromEnv("ARGOCD_COMMIT_SERVER_LISTEN_ADDRESS", common.DefaultAddressCommitServer), "Listen on given address for incoming connections")
command.Flags().IntVar(&listenPort, "port", common.DefaultPortCommitServer, "Listen on given port for incoming connections")

View File

@@ -144,7 +144,7 @@ func NewRunDexCommand() *cobra.Command {
}
clientConfig = cli.AddKubectlFlagsToCmd(&command)
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_DEX_SERVER_LOGFORMAT", "text"), "Set the logging format. One of: text|json")
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_DEX_SERVER_LOGFORMAT", "json"), "Set the logging format. One of: json|text")
command.Flags().StringVar(&cmdutil.LogLevel, "loglevel", env.StringFromEnv("ARGOCD_DEX_SERVER_LOGLEVEL", "info"), "Set the logging level. One of: debug|info|warn|error")
command.Flags().BoolVar(&disableTLS, "disable-tls", env.ParseBoolFromEnv("ARGOCD_DEX_SERVER_DISABLE_TLS", false), "Disable TLS on the HTTP endpoint")
return &command
@@ -212,7 +212,7 @@ func NewGenDexConfigCommand() *cobra.Command {
}
clientConfig = cli.AddKubectlFlagsToCmd(&command)
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_DEX_SERVER_LOGFORMAT", "text"), "Set the logging format. One of: text|json")
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_DEX_SERVER_LOGFORMAT", "json"), "Set the logging format. One of: json|text")
command.Flags().StringVar(&cmdutil.LogLevel, "loglevel", env.StringFromEnv("ARGOCD_DEX_SERVER_LOGLEVEL", "info"), "Set the logging level. One of: debug|info|warn|error")
command.Flags().StringVarP(&out, "out", "o", "", "Output to the specified file instead of stdout")
command.Flags().BoolVar(&disableTLS, "disable-tls", env.ParseBoolFromEnv("ARGOCD_DEX_SERVER_DISABLE_TLS", false), "Disable TLS on the HTTP endpoint")

View File

@@ -1,7 +1,6 @@
package commands
import (
"context"
"errors"
"testing"
"time"
@@ -11,7 +10,7 @@ import (
)
func TestGetSignedRequestWithRetry(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
t.Run("will return signed request on first attempt", func(t *testing.T) {
// given

View File

@@ -180,7 +180,7 @@ func NewCommand() *cobra.Command {
command.Flags().StringVar(&appLabelSelector, "app-label-selector", "", "App label selector.")
command.Flags().StringVar(&namespace, "namespace", "", "Namespace which controller handles. Current namespace if empty.")
command.Flags().StringVar(&logLevel, "loglevel", env.StringFromEnv("ARGOCD_NOTIFICATIONS_CONTROLLER_LOGLEVEL", "info"), "Set the logging level. One of: debug|info|warn|error")
command.Flags().StringVar(&logFormat, "logformat", env.StringFromEnv("ARGOCD_NOTIFICATIONS_CONTROLLER_LOGFORMAT", "text"), "Set the logging format. One of: text|json")
command.Flags().StringVar(&logFormat, "logformat", env.StringFromEnv("ARGOCD_NOTIFICATIONS_CONTROLLER_LOGFORMAT", "json"), "Set the logging format. One of: json|text")
command.Flags().IntVar(&metricsPort, "metrics-port", defaultMetricsPort, "Metrics port")
command.Flags().StringVar(&argocdRepoServer, "argocd-repo-server", common.DefaultRepoServerAddr, "Argo CD repo server address")
command.Flags().BoolVar(&argocdRepoServerPlaintext, "argocd-repo-server-plaintext", env.ParseBoolFromEnv("ARGOCD_NOTIFICATION_CONTROLLER_REPO_SERVER_PLAINTEXT", false), "Use a plaintext client (non-TLS) to connect to repository server")

View File

@@ -230,7 +230,7 @@ func NewCommand() *cobra.Command {
return nil
},
}
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_REPO_SERVER_LOGFORMAT", "text"), "Set the logging format. One of: text|json")
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_REPO_SERVER_LOGFORMAT", "json"), "Set the logging format. One of: json|text")
command.Flags().StringVar(&cmdutil.LogLevel, "loglevel", env.StringFromEnv("ARGOCD_REPO_SERVER_LOGLEVEL", "info"), "Set the logging level. One of: debug|info|warn|error")
command.Flags().Int64Var(&parallelismLimit, "parallelismlimit", int64(env.ParseNumFromEnv("ARGOCD_REPO_SERVER_PARALLELISM_LIMIT", 0, 0, math.MaxInt32)), "Limit on number of concurrent manifests generate requests. Any value less the 1 means no limit.")
command.Flags().StringVar(&listenHost, "address", env.StringFromEnv("ARGOCD_REPO_SERVER_LISTEN_ADDRESS", common.DefaultAddressRepoServer), "Listen on given address for incoming connections")

View File

@@ -88,6 +88,7 @@ func NewCommand() *cobra.Command {
enableProxyExtension bool
webhookParallelism int
hydratorEnabled bool
syncWithReplaceAllowed bool
// ApplicationSet
enableNewGitFileGlobbing bool
@@ -179,7 +180,7 @@ func NewCommand() *cobra.Command {
tlsConfig.Certificates = pool
}
dexTlsConfig := &dex.DexTLSConfig{
dexTLSConfig := &dex.DexTLSConfig{
DisableTLS: dexServerPlaintext,
StrictValidation: dexServerStrictTLS,
}
@@ -191,14 +192,14 @@ func NewCommand() *cobra.Command {
if err != nil {
log.Fatalf("%v", err)
}
dexTlsConfig.RootCAs = pool
dexTLSConfig.RootCAs = pool
cert, err := tls.LoadX509Cert(
env.StringFromEnv(common.EnvAppConfigPath, common.DefaultAppConfigPath) + "/dex/tls/tls.crt",
)
if err != nil {
log.Fatalf("%v", err)
}
dexTlsConfig.Certificate = cert.Raw
dexTLSConfig.Certificate = cert.Raw
}
repoclientset := apiclient.NewRepoServerClientset(repoServerAddress, repoServerTimeoutSeconds, tlsConfig)
@@ -229,7 +230,7 @@ func NewCommand() *cobra.Command {
AppClientset: appClientSet,
RepoClientset: repoclientset,
DexServerAddr: dexServerAddress,
DexTLSConfig: dexTlsConfig,
DexTLSConfig: dexTLSConfig,
DisableAuth: disableAuth,
ContentTypes: contentTypesList,
EnableGZip: enableGZip,
@@ -245,6 +246,7 @@ func NewCommand() *cobra.Command {
WebhookParallelism: webhookParallelism,
EnableK8sEvent: enableK8sEvent,
HydratorEnabled: hydratorEnabled,
SyncWithReplaceAllowed: syncWithReplaceAllowed,
}
appsetOpts := server.ApplicationSetOpts{
@@ -295,7 +297,7 @@ func NewCommand() *cobra.Command {
command.Flags().StringVar(&staticAssetsDir, "staticassets", env.StringFromEnv("ARGOCD_SERVER_STATIC_ASSETS", "/shared/app"), "Directory path that contains additional static assets")
command.Flags().StringVar(&baseHRef, "basehref", env.StringFromEnv("ARGOCD_SERVER_BASEHREF", "/"), "Value for base href in index.html. Used if Argo CD is running behind reverse proxy under subpath different from /")
command.Flags().StringVar(&rootPath, "rootpath", env.StringFromEnv("ARGOCD_SERVER_ROOTPATH", ""), "Used if Argo CD is running behind reverse proxy under subpath different from /")
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_SERVER_LOGFORMAT", "text"), "Set the logging format. One of: text|json")
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_SERVER_LOGFORMAT", "json"), "Set the logging format. One of: json|text")
command.Flags().StringVar(&cmdutil.LogLevel, "loglevel", env.StringFromEnv("ARGOCD_SERVER_LOG_LEVEL", "info"), "Set the logging level. One of: debug|info|warn|error")
command.Flags().IntVar(&glogLevel, "gloglevel", 0, "Set the glog logging level")
command.Flags().StringVar(&repoServerAddress, "repo-server", env.StringFromEnv("ARGOCD_SERVER_REPO_SERVER", common.DefaultRepoServerAddr), "Repo server address")
@@ -324,6 +326,7 @@ func NewCommand() *cobra.Command {
command.Flags().IntVar(&webhookParallelism, "webhook-parallelism-limit", env.ParseNumFromEnv("ARGOCD_SERVER_WEBHOOK_PARALLELISM_LIMIT", 50, 1, 1000), "Number of webhook requests processed concurrently")
command.Flags().StringSliceVar(&enableK8sEvent, "enable-k8s-event", env.StringsFromEnv("ARGOCD_ENABLE_K8S_EVENT", argo.DefaultEnableEventList(), ","), "Enable ArgoCD to use k8s event. For disabling all events, set the value as `none`. (e.g --enable-k8s-event=none), For enabling specific events, set the value as `event reason`. (e.g --enable-k8s-event=StatusRefreshed,ResourceCreated)")
command.Flags().BoolVar(&hydratorEnabled, "hydrator-enabled", env.ParseBoolFromEnv("ARGOCD_HYDRATOR_ENABLED", false), "Feature flag to enable Hydrator. Default (\"false\")")
command.Flags().BoolVar(&syncWithReplaceAllowed, "sync-with-replace-allowed", env.ParseBoolFromEnv("ARGOCD_SYNC_WITH_REPLACE_ALLOWED", true), "Whether to allow users to select replace for syncs from UI/CLI")
// Flags related to the applicationSet component.
command.Flags().StringVar(&scmRootCAPath, "appset-scm-root-ca-path", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_SCM_ROOT_CA_PATH", ""), "Provide Root CA Path for self-signed TLS Certificates")

View File

@@ -16,12 +16,13 @@ import (
"golang.org/x/term"
"sigs.k8s.io/yaml"
"github.com/argoproj/argo-cd/v3/util/rbac"
"github.com/argoproj/argo-cd/v3/cmd/argocd/commands/headless"
"github.com/argoproj/argo-cd/v3/cmd/argocd/commands/utils"
argocdclient "github.com/argoproj/argo-cd/v3/pkg/apiclient"
accountpkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/account"
"github.com/argoproj/argo-cd/v3/pkg/apiclient/session"
"github.com/argoproj/argo-cd/v3/server/rbacpolicy"
"github.com/argoproj/argo-cd/v3/util/cli"
"github.com/argoproj/argo-cd/v3/util/errors"
"github.com/argoproj/argo-cd/v3/util/io"
@@ -218,7 +219,7 @@ argocd account can-i create clusters '*'
Actions: %v
Resources: %v
`, rbacpolicy.Actions, rbacpolicy.Resources),
`, rbac.Actions, rbac.Resources),
Run: func(c *cobra.Command, args []string) {
ctx := c.Context()

View File

@@ -14,20 +14,20 @@ import (
"k8s.io/client-go/dynamic"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"sigs.k8s.io/yaml"
cmdutil "github.com/argoproj/argo-cd/v3/cmd/util"
"github.com/argoproj/argo-cd/v3/common"
argocdclient "github.com/argoproj/argo-cd/v3/pkg/apiclient"
"github.com/argoproj/argo-cd/v3/util/errors"
"github.com/argoproj/argo-cd/v3/util/settings"
"github.com/argoproj/argo-cd/v3/pkg/apis/application"
"github.com/argoproj/argo-cd/v3/util/errors"
)
const (
// YamlSeparator separates sections of a YAML file
yamlSeparator = "---\n"
applicationsetNamespacesCmdParamsKey = "applicationsetcontroller.namespaces"
applicationNamespacesCmdParamsKey = "application.namespaces"
)
var (
@@ -38,6 +38,19 @@ var (
appplicationSetResource = schema.GroupVersionResource{Group: application.Group, Version: "v1alpha1", Resource: application.ApplicationSetPlural}
)
type argocdAdditionalNamespaces struct {
applicationNamespaces []string
applicationsetNamespaces []string
}
type argoCDClientsets struct {
configMaps dynamic.ResourceInterface
secrets dynamic.ResourceInterface
applications dynamic.ResourceInterface
projects dynamic.ResourceInterface
applicationSets dynamic.ResourceInterface
}
// NewAdminCommand returns a new instance of an argocd command
func NewAdminCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
pathOpts := clientcmd.NewDefaultPathOptions()
@@ -69,102 +82,31 @@ $ argocd admin initial-password reset
command.AddCommand(NewInitialPasswordCommand())
command.AddCommand(NewRedisInitialPasswordCommand())
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", "text", "Set the logging format. One of: text|json")
command.Flags().StringVar(&cmdutil.LogFormat, "logformat", "json", "Set the logging format. One of: json|text")
command.Flags().StringVar(&cmdutil.LogLevel, "loglevel", "info", "Set the logging level. One of: debug|info|warn|error")
return command
}
type argoCDClientsets struct {
configMaps dynamic.ResourceInterface
secrets dynamic.ResourceInterface
applications dynamic.ResourceInterface
projects dynamic.ResourceInterface
applicationSets dynamic.ResourceInterface
}
func newArgoCDClientsets(config *rest.Config, namespace string) *argoCDClientsets {
dynamicIf, err := dynamic.NewForConfig(config)
errors.CheckError(err)
return &argoCDClientsets{
configMaps: dynamicIf.Resource(configMapResource).Namespace(namespace),
secrets: dynamicIf.Resource(secretResource).Namespace(namespace),
// To support applications and applicationsets in any namespace we will watch all namespaces and filter them afterwards
applications: dynamicIf.Resource(applicationsResource),
configMaps: dynamicIf.Resource(configMapResource).Namespace(namespace),
secrets: dynamicIf.Resource(secretResource).Namespace(namespace),
applications: dynamicIf.Resource(applicationsResource).Namespace(namespace),
projects: dynamicIf.Resource(appprojectsResource).Namespace(namespace),
applicationSets: dynamicIf.Resource(appplicationSetResource),
applicationSets: dynamicIf.Resource(appplicationSetResource).Namespace(namespace),
}
}
// getReferencedSecrets examines the argocd-cm config for any referenced repo secrets and returns a
// map of all referenced secrets.
func getReferencedSecrets(un unstructured.Unstructured) map[string]bool {
var cm corev1.ConfigMap
err := runtime.DefaultUnstructuredConverter.FromUnstructured(un.Object, &cm)
errors.CheckError(err)
referencedSecrets := make(map[string]bool)
// Referenced repository secrets
if reposRAW, ok := cm.Data["repositories"]; ok {
repos := make([]settings.Repository, 0)
err := yaml.Unmarshal([]byte(reposRAW), &repos)
errors.CheckError(err)
for _, cred := range repos {
if cred.PasswordSecret != nil {
referencedSecrets[cred.PasswordSecret.Name] = true
}
if cred.SSHPrivateKeySecret != nil {
referencedSecrets[cred.SSHPrivateKeySecret.Name] = true
}
if cred.UsernameSecret != nil {
referencedSecrets[cred.UsernameSecret.Name] = true
}
if cred.TLSClientCertDataSecret != nil {
referencedSecrets[cred.TLSClientCertDataSecret.Name] = true
}
if cred.TLSClientCertKeySecret != nil {
referencedSecrets[cred.TLSClientCertKeySecret.Name] = true
}
}
}
// Referenced repository credentials secrets
if reposRAW, ok := cm.Data["repository.credentials"]; ok {
creds := make([]settings.RepositoryCredentials, 0)
err := yaml.Unmarshal([]byte(reposRAW), &creds)
errors.CheckError(err)
for _, cred := range creds {
if cred.PasswordSecret != nil {
referencedSecrets[cred.PasswordSecret.Name] = true
}
if cred.SSHPrivateKeySecret != nil {
referencedSecrets[cred.SSHPrivateKeySecret.Name] = true
}
if cred.UsernameSecret != nil {
referencedSecrets[cred.UsernameSecret.Name] = true
}
if cred.TLSClientCertDataSecret != nil {
referencedSecrets[cred.TLSClientCertDataSecret.Name] = true
}
if cred.TLSClientCertKeySecret != nil {
referencedSecrets[cred.TLSClientCertKeySecret.Name] = true
}
}
}
return referencedSecrets
}
// isArgoCDSecret returns whether or not the given secret is a part of Argo CD configuration
// (e.g. argocd-secret, repo credentials, or cluster credentials)
func isArgoCDSecret(repoSecretRefs map[string]bool, un unstructured.Unstructured) bool {
func isArgoCDSecret(un unstructured.Unstructured) bool {
secretName := un.GetName()
if secretName == common.ArgoCDSecretName {
return true
}
if repoSecretRefs != nil {
if _, ok := repoSecretRefs[secretName]; ok {
return true
}
}
if labels := un.GetLabels(); labels != nil {
if _, ok := labels[common.LabelKeySecretType]; ok {
return true
@@ -227,22 +169,12 @@ func specsEqual(left, right unstructured.Unstructured) bool {
return false
}
type argocdAdditonalNamespaces struct {
applicationNamespaces []string
applicationsetNamespaces []string
}
const (
applicationsetNamespacesCmdParamsKey = "applicationsetcontroller.namespaces"
applicationNamespacesCmdParamsKey = "application.namespaces"
)
// Get additional namespaces from argocd-cmd-params
func getAdditionalNamespaces(ctx context.Context, argocdClientsets *argoCDClientsets) *argocdAdditonalNamespaces {
func getAdditionalNamespaces(ctx context.Context, configMapsClient dynamic.ResourceInterface) *argocdAdditionalNamespaces {
applicationNamespaces := make([]string, 0)
applicationsetNamespaces := make([]string, 0)
un, err := argocdClientsets.configMaps.Get(ctx, common.ArgoCDCmdParamsConfigMapName, metav1.GetOptions{})
un, err := configMapsClient.Get(ctx, common.ArgoCDCmdParamsConfigMapName, metav1.GetOptions{})
errors.CheckError(err)
var cm corev1.ConfigMap
err = runtime.DefaultUnstructuredConverter.FromUnstructured(un.Object, &cm)
@@ -270,7 +202,7 @@ func getAdditionalNamespaces(ctx context.Context, argocdClientsets *argoCDClient
applicationsetNamespaces = namespacesListFromString(strNamespaces)
}
return &argocdAdditonalNamespaces{
return &argocdAdditionalNamespaces{
applicationNamespaces: applicationNamespaces,
applicationsetNamespaces: applicationsetNamespaces,
}

View File

@@ -1,13 +1,11 @@
package admin
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
dynfake "k8s.io/client-go/dynamic/fake"
)
@@ -28,33 +26,33 @@ func TestGetAdditionalNamespaces(t *testing.T) {
testCases := []struct {
CmdParamsKeys map[string]any
expected argocdAdditonalNamespaces
expected argocdAdditionalNamespaces
description string
}{
{
description: "empty configmap should return no additional namespaces",
CmdParamsKeys: map[string]any{},
expected: argocdAdditonalNamespaces{applicationNamespaces: []string{}, applicationsetNamespaces: []string{}},
expected: argocdAdditionalNamespaces{applicationNamespaces: []string{}, applicationsetNamespaces: []string{}},
},
{
description: "empty strings in respective keys in cm shoud return empty namespace list",
CmdParamsKeys: map[string]any{applicationsetNamespacesCmdParamsKey: "", applicationNamespacesCmdParamsKey: ""},
expected: argocdAdditonalNamespaces{applicationNamespaces: []string{}, applicationsetNamespaces: []string{}},
expected: argocdAdditionalNamespaces{applicationNamespaces: []string{}, applicationsetNamespaces: []string{}},
},
{
description: "when only one of the keys in the cm is set only correct respective list of namespaces should be returned",
CmdParamsKeys: map[string]any{applicationNamespacesCmdParamsKey: "foo, bar*"},
expected: argocdAdditonalNamespaces{applicationsetNamespaces: []string{}, applicationNamespaces: []string{"foo", "bar*"}},
expected: argocdAdditionalNamespaces{applicationsetNamespaces: []string{}, applicationNamespaces: []string{"foo", "bar*"}},
},
{
description: "when only one of the keys in the cm is set only correct respective list of namespaces should be returned",
CmdParamsKeys: map[string]any{applicationsetNamespacesCmdParamsKey: "foo, bar*"},
expected: argocdAdditonalNamespaces{applicationNamespaces: []string{}, applicationsetNamespaces: []string{"foo", "bar*"}},
expected: argocdAdditionalNamespaces{applicationNamespaces: []string{}, applicationsetNamespaces: []string{"foo", "bar*"}},
},
{
description: "whitespaces are removed for both multiple and single namespace",
CmdParamsKeys: map[string]any{applicationNamespacesCmdParamsKey: " bar ", applicationsetNamespacesCmdParamsKey: " foo , bar* "},
expected: argocdAdditonalNamespaces{applicationNamespaces: []string{"bar"}, applicationsetNamespaces: []string{"foo", "bar*"}},
expected: argocdAdditionalNamespaces{applicationNamespaces: []string{"bar"}, applicationsetNamespaces: []string{"foo", "bar*"}},
},
}
@@ -62,14 +60,10 @@ func TestGetAdditionalNamespaces(t *testing.T) {
fakeDynClient := dynfake.NewSimpleDynamicClient(runtime.NewScheme(), createArgoCDCmdCMWithKeys(c.CmdParamsKeys))
argoCDClientsets := &argoCDClientsets{
configMaps: fakeDynClient.Resource(configMapResource).Namespace("argocd"),
applications: fakeDynClient.Resource(schema.GroupVersionResource{}),
applicationSets: fakeDynClient.Resource(schema.GroupVersionResource{}),
secrets: fakeDynClient.Resource(schema.GroupVersionResource{}),
projects: fakeDynClient.Resource(schema.GroupVersionResource{}),
configMaps: fakeDynClient.Resource(configMapResource).Namespace("argocd"),
}
result := getAdditionalNamespaces(context.TODO(), argoCDClientsets)
result := getAdditionalNamespaces(t.Context(), argoCDClientsets.configMaps)
assert.Equal(t, c.expected, *result)
}
}

View File

@@ -10,6 +10,7 @@ import (
"sort"
"time"
"github.com/argoproj/gitops-engine/pkg/utils/kube"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -403,7 +404,26 @@ func reconcileApplications(
)
appStateManager := controller.NewAppStateManager(
argoDB, appClientset, repoServerClient, namespace, kubeutil.NewKubectl(), settingsMgr, stateCache, projInformer, server, cache, time.Second, argo.NewResourceTracking(), false, 0, serverSideDiff, ignoreNormalizerOpts)
argoDB,
appClientset,
repoServerClient,
namespace,
kubeutil.NewKubectl(),
func(_ string) (kube.CleanupFunc, error) {
return func() {}, nil
},
settingsMgr,
stateCache,
projInformer,
server,
cache,
time.Second,
argo.NewResourceTracking(),
false,
0,
serverSideDiff,
ignoreNormalizerOpts,
)
appsList, err := appClientset.ArgoprojV1alpha1().Applications(namespace).List(ctx, metav1.ListOptions{LabelSelector: selector})
if err != nil {

View File

@@ -1,7 +1,6 @@
package admin
import (
"context"
"testing"
clustermocks "github.com/argoproj/gitops-engine/pkg/cache/mocks"
@@ -31,7 +30,7 @@ import (
)
func TestGetReconcileResults(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
appClientset := appfake.NewSimpleClientset(&v1alpha1.Application{
ObjectMeta: metav1.ObjectMeta{
@@ -56,7 +55,7 @@ func TestGetReconcileResults(t *testing.T) {
}
func TestGetReconcileResults_Refresh(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
argoCM := &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{

View File

@@ -5,6 +5,8 @@ import (
"fmt"
"io"
"os"
"strings"
"time"
"github.com/argoproj/gitops-engine/pkg/utils/kube"
log "github.com/sirupsen/logrus"
@@ -14,6 +16,8 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/retry"
"sigs.k8s.io/yaml"
"github.com/argoproj/argo-cd/v3/cmd/argocd/commands/utils"
@@ -41,8 +45,11 @@ func NewExportCommand() *cobra.Command {
config, err := clientConfig.ClientConfig()
errors.CheckError(err)
client, err := dynamic.NewForConfig(config)
errors.CheckError(err)
namespace, _, err := clientConfig.Namespace()
errors.CheckError(err)
acdClients := newArgoCDClientsets(config, namespace)
var writer io.Writer
if out == "-" {
@@ -60,7 +67,23 @@ func NewExportCommand() *cobra.Command {
}()
}
acdClients := newArgoCDClientsets(config, namespace)
if len(applicationNamespaces) == 0 || len(applicationsetNamespaces) == 0 {
defaultNs := getAdditionalNamespaces(ctx, acdClients.configMaps)
if len(applicationNamespaces) == 0 {
applicationNamespaces = defaultNs.applicationNamespaces
}
if len(applicationsetNamespaces) == 0 {
applicationsetNamespaces = defaultNs.applicationsetNamespaces
}
}
// To support applications and applicationsets in any namespace, we must list ALL namespaces and filter them afterwards
if len(applicationNamespaces) > 0 {
acdClients.applications = client.Resource(applicationsResource)
}
if len(applicationsetNamespaces) > 0 {
acdClients.applicationSets = client.Resource(appplicationSetResource)
}
acdConfigMap, err := acdClients.configMaps.Get(ctx, common.ArgoCDConfigMapName, metav1.GetOptions{})
errors.CheckError(err)
export(writer, *acdConfigMap, namespace)
@@ -74,29 +97,20 @@ func NewExportCommand() *cobra.Command {
errors.CheckError(err)
export(writer, *acdTLSCertsConfigMap, namespace)
referencedSecrets := getReferencedSecrets(*acdConfigMap)
secrets, err := acdClients.secrets.List(ctx, metav1.ListOptions{})
errors.CheckError(err)
for _, secret := range secrets.Items {
if isArgoCDSecret(referencedSecrets, secret) {
if isArgoCDSecret(secret) {
export(writer, secret, namespace)
}
}
projects, err := acdClients.projects.List(ctx, metav1.ListOptions{})
errors.CheckError(err)
for _, proj := range projects.Items {
export(writer, proj, namespace)
}
additionalNamespaces := getAdditionalNamespaces(ctx, acdClients)
if len(applicationNamespaces) == 0 {
applicationNamespaces = additionalNamespaces.applicationNamespaces
}
if len(applicationsetNamespaces) == 0 {
applicationsetNamespaces = additionalNamespaces.applicationsetNamespaces
}
applications, err := acdClients.applications.List(ctx, metav1.ListOptions{})
errors.CheckError(err)
for _, app := range applications.Items {
@@ -125,8 +139,8 @@ func NewExportCommand() *cobra.Command {
clientConfig = cli.AddKubectlFlagsToCmd(&command)
command.Flags().StringVarP(&out, "out", "o", "-", "Output to the specified file instead of stdout")
command.Flags().StringSliceVarP(&applicationNamespaces, "application-namespaces", "", []string{}, fmt.Sprintf("Comma separated list of namespace globs to export applications from. If not provided value from '%s' in %s will be used,if it's not defined only applications from Argo CD namespace will be exported", applicationNamespacesCmdParamsKey, common.ArgoCDCmdParamsConfigMapName))
command.Flags().StringSliceVarP(&applicationsetNamespaces, "applicationset-namespaces", "", []string{}, fmt.Sprintf("Comma separated list of namespace globs to export applicationsets from. If not provided value from '%s' in %s will be used,if it's not defined only applicationsets from Argo CD namespace will be exported", applicationsetNamespacesCmdParamsKey, common.ArgoCDCmdParamsConfigMapName))
command.Flags().StringSliceVarP(&applicationNamespaces, "application-namespaces", "", []string{}, fmt.Sprintf("Comma separated list of namespace globs to export applications from. If not provided value from '%s' in %s will be used. If it's not defined, only applications from Argo CD namespace will be exported", applicationNamespacesCmdParamsKey, common.ArgoCDCmdParamsConfigMapName))
command.Flags().StringSliceVarP(&applicationsetNamespaces, "applicationset-namespaces", "", []string{}, fmt.Sprintf("Comma separated list of namespace globs to export applicationsets from. If not provided value from '%s' in %s will be used. If it's not defined, only applicationsets from Argo CD namespace will be exported", applicationsetNamespacesCmdParamsKey, common.ArgoCDCmdParamsConfigMapName))
return &command
}
@@ -139,7 +153,9 @@ func NewImportCommand() *cobra.Command {
verbose bool
stopOperation bool
ignoreTracking bool
overrideOnConflict bool
promptsEnabled bool
skipResourcesWithLabel string
applicationNamespaces []string
applicationsetNamespaces []string
)
@@ -162,7 +178,8 @@ func NewImportCommand() *cobra.Command {
acdClients := newArgoCDClientsets(config, namespace)
client, err := dynamic.NewForConfig(config)
errors.CheckError(err)
fmt.Printf("import process started %s\n", namespace)
tt := time.Now()
var input []byte
if in := args[0]; in == "-" {
input, err = io.ReadAll(os.Stdin)
@@ -175,37 +192,40 @@ func NewImportCommand() *cobra.Command {
dryRunMsg = " (dry run)"
}
additionalNamespaces := getAdditionalNamespaces(ctx, acdClients)
if len(applicationNamespaces) == 0 {
applicationNamespaces = additionalNamespaces.applicationNamespaces
if len(applicationNamespaces) == 0 || len(applicationsetNamespaces) == 0 {
defaultNs := getAdditionalNamespaces(ctx, acdClients.configMaps)
if len(applicationNamespaces) == 0 {
applicationNamespaces = defaultNs.applicationNamespaces
}
if len(applicationsetNamespaces) == 0 {
applicationsetNamespaces = defaultNs.applicationsetNamespaces
}
}
if len(applicationsetNamespaces) == 0 {
applicationsetNamespaces = additionalNamespaces.applicationsetNamespaces
// To support applications and applicationsets in any namespace, we must list ALL namespaces and filter them afterwards
if len(applicationNamespaces) > 0 {
acdClients.applications = client.Resource(applicationsResource)
}
if len(applicationsetNamespaces) > 0 {
acdClients.applicationSets = client.Resource(appplicationSetResource)
}
// pruneObjects tracks live objects and it's current resource version. any remaining
// pruneObjects tracks live objects, and it's current resource version. any remaining
// items in this map indicates the resource should be pruned since it no longer appears
// in the backup
pruneObjects := make(map[kube.ResourceKey]unstructured.Unstructured)
configMaps, err := acdClients.configMaps.List(ctx, metav1.ListOptions{})
errors.CheckError(err)
// referencedSecrets holds any secrets referenced in the argocd-cm configmap. These
// secrets need to be imported too
var referencedSecrets map[string]bool
for _, cm := range configMaps.Items {
if isArgoCDConfigMap(cm.GetName()) {
pruneObjects[kube.ResourceKey{Group: "", Kind: "ConfigMap", Name: cm.GetName(), Namespace: cm.GetNamespace()}] = cm
}
if cm.GetName() == common.ArgoCDConfigMapName {
referencedSecrets = getReferencedSecrets(cm)
}
}
secrets, err := acdClients.secrets.List(ctx, metav1.ListOptions{})
errors.CheckError(err)
for _, secret := range secrets.Items {
if isArgoCDSecret(referencedSecrets, secret) {
if isArgoCDSecret(secret) {
pruneObjects[kube.ResourceKey{Group: "", Kind: "Secret", Name: secret.GetName(), Namespace: secret.GetNamespace()}] = secret
}
}
@@ -234,9 +254,9 @@ func NewImportCommand() *cobra.Command {
}
}
}
// Create or replace existing object
backupObjects, err := kube.SplitYAML(input)
errors.CheckError(err)
for _, bakObj := range backupObjects {
gvk := bakObj.GroupVersionKind()
@@ -247,6 +267,13 @@ func NewImportCommand() *cobra.Command {
key := kube.ResourceKey{Group: gvk.Group, Kind: gvk.Kind, Name: bakObj.GetName(), Namespace: bakObj.GetNamespace()}
liveObj, exists := pruneObjects[key]
delete(pruneObjects, key)
// If the resource in backup matches the skip label, do not import it
if isSkipLabelMatches(bakObj, skipResourcesWithLabel) {
fmt.Printf("Skipping %s/%s %s in namespace %s\n", bakObj.GroupVersionKind().Group, bakObj.GroupVersionKind().Kind, bakObj.GetName(), bakObj.GetNamespace())
continue
}
var dynClient dynamic.ResourceInterface
switch bakObj.GetKind() {
case "Secret":
@@ -256,17 +283,17 @@ func NewImportCommand() *cobra.Command {
case application.AppProjectKind:
dynClient = client.Resource(appprojectsResource).Namespace(bakObj.GetNamespace())
case application.ApplicationKind:
dynClient = client.Resource(applicationsResource).Namespace(bakObj.GetNamespace())
// If application is not in one of the allowed namespaces do not import it
if !secutil.IsNamespaceEnabled(bakObj.GetNamespace(), namespace, applicationNamespaces) {
continue
}
dynClient = client.Resource(applicationsResource).Namespace(bakObj.GetNamespace())
case application.ApplicationSetKind:
dynClient = client.Resource(appplicationSetResource).Namespace(bakObj.GetNamespace())
// If applicationset is not in one of the allowed namespaces do not import it
if !secutil.IsNamespaceEnabled(bakObj.GetNamespace(), namespace, applicationsetNamespaces) {
continue
}
dynClient = client.Resource(appplicationSetResource).Namespace(bakObj.GetNamespace())
}
// If there is a live object, remove the tracking annotations/label that might conflict
@@ -299,6 +326,21 @@ func NewImportCommand() *cobra.Command {
if !dryRun {
newLive := updateLive(bakObj, &liveObj, stopOperation)
_, err = dynClient.Update(ctx, newLive, metav1.UpdateOptions{})
if apierrors.IsConflict(err) {
fmt.Printf("Failed to update %s/%s %s in namespace %s: %v\n", gvk.Group, gvk.Kind, bakObj.GetName(), bakObj.GetNamespace(), err)
if overrideOnConflict {
err = retry.RetryOnConflict(retry.DefaultRetry, func() error {
fmt.Printf("Resource conflict: retrying update for Group: %s, Kind: %s, Name: %s, Namespace: %s\n", gvk.Group, gvk.Kind, bakObj.GetName(), bakObj.GetNamespace())
liveObj, getErr := dynClient.Get(ctx, newLive.GetName(), metav1.GetOptions{})
if getErr != nil {
errors.CheckError(getErr)
}
newLive.SetResourceVersion(liveObj.GetResourceVersion())
_, err = dynClient.Update(ctx, newLive, metav1.UpdateOptions{})
return err
})
}
}
if apierrors.IsForbidden(err) || apierrors.IsNotFound(err) {
isForbidden = true
log.Warnf("%s/%s %s: %v", gvk.Group, gvk.Kind, bakObj.GetName(), err)
@@ -316,6 +358,12 @@ func NewImportCommand() *cobra.Command {
// Delete objects not in backup
for key, liveObj := range pruneObjects {
// If a live resource has a label to skip the import, it should never be pruned
if isSkipLabelMatches(&liveObj, skipResourcesWithLabel) {
fmt.Printf("Skipping pruning of %s/%s %s in namespace %s\n", key.Group, key.Kind, liveObj.GetName(), liveObj.GetNamespace())
continue
}
if prune {
var dynClient dynamic.ResourceInterface
switch key.Kind {
@@ -363,6 +411,8 @@ func NewImportCommand() *cobra.Command {
fmt.Printf("%s/%s %s needs pruning\n", key.Group, key.Kind, key.Name)
}
}
duration := time.Since(tt)
fmt.Printf("Import process completed successfully in namespace %s at %s, duration: %s\n", namespace, time.Now().Format(time.RFC3339), duration)
},
}
@@ -370,12 +420,13 @@ func NewImportCommand() *cobra.Command {
command.Flags().BoolVar(&dryRun, "dry-run", false, "Print what will be performed")
command.Flags().BoolVar(&prune, "prune", false, "Prune secrets, applications and projects which do not appear in the backup")
command.Flags().BoolVar(&ignoreTracking, "ignore-tracking", false, "Do not update the tracking annotation if the resource is already tracked")
command.Flags().BoolVar(&overrideOnConflict, "override-on-conflict", false, "Override the resource on conflict when updating resources")
command.Flags().BoolVar(&verbose, "verbose", false, "Verbose output (versus only changed output)")
command.Flags().BoolVar(&stopOperation, "stop-operation", false, "Stop any existing operations")
command.Flags().StringSliceVarP(&applicationNamespaces, "application-namespaces", "", []string{}, fmt.Sprintf("Comma separated list of namespace globs to which import of applications is allowed. If not provided value from '%s' in %s will be used,if it's not defined only applications without an explicit namespace will be imported to the Argo CD namespace", applicationNamespacesCmdParamsKey, common.ArgoCDCmdParamsConfigMapName))
command.Flags().StringSliceVarP(&applicationsetNamespaces, "applicationset-namespaces", "", []string{}, fmt.Sprintf("Comma separated list of namespace globs which import of applicationsets is allowed. If not provided value from '%s' in %s will be used,if it's not defined only applicationsets without an explicit namespace will be imported to the Argo CD namespace", applicationsetNamespacesCmdParamsKey, common.ArgoCDCmdParamsConfigMapName))
command.Flags().StringVarP(&skipResourcesWithLabel, "skip-resources-with-label", "", "", "Skip importing resources based on the label e.g. '--skip-resources-with-label my-label/example.io=true'")
command.Flags().StringSliceVarP(&applicationNamespaces, "application-namespaces", "", []string{}, fmt.Sprintf("Comma separated list of namespace globs to which import of applications is allowed. If not provided, value from '%s' in %s will be used. If it's not defined, only applications without an explicit namespace will be imported to the Argo CD namespace", applicationNamespacesCmdParamsKey, common.ArgoCDCmdParamsConfigMapName))
command.Flags().StringSliceVarP(&applicationsetNamespaces, "applicationset-namespaces", "", []string{}, fmt.Sprintf("Comma separated list of namespace globs which import of applicationsets is allowed. If not provided, value from '%s' in %s will be used. If it's not defined, only applicationsets without an explicit namespace will be imported to the Argo CD namespace", applicationsetNamespacesCmdParamsKey, common.ArgoCDCmdParamsConfigMapName))
command.PersistentFlags().BoolVar(&promptsEnabled, "prompts-enabled", localconfig.GetPromptsEnabled(true), "Force optional interactive prompts to be enabled or disabled, overriding local configuration. If not specified, the local configuration value will be used, which is false by default.")
return &command
}
@@ -407,6 +458,7 @@ func export(w io.Writer, un unstructured.Unstructured, argocdNamespace string) {
un.SetLabels(labels)
un.SetAnnotations(annotations)
if namespace != argocdNamespace {
// Explicitly add the namespace for appset and apps in any namespace
un.SetNamespace(namespace)
}
data, err := yaml.Marshal(un.Object)
@@ -472,3 +524,19 @@ func updateTracking(bak, live *unstructured.Unstructured) {
}
}
}
// isSkipLabelMatches return if the resource should be skipped based on the labels
func isSkipLabelMatches(obj *unstructured.Unstructured, skipResourcesWithLabel string) bool {
if skipResourcesWithLabel == "" {
return false
}
parts := strings.SplitN(skipResourcesWithLabel, "=", 2)
if len(parts) != 2 || parts[0] == "" || parts[1] == "" {
return false
}
key, value := parts[0], parts[1]
if val, ok := obj.GetLabels()[key]; ok && val == value {
return true
}
return false
}

View File

@@ -85,3 +85,76 @@ func Test_updateTracking(t *testing.T) {
})
}
}
func TestIsSkipLabelMatches(t *testing.T) {
tests := []struct {
name string
obj *unstructured.Unstructured
skipLabels string
expected bool
}{
{
name: "Label matches",
obj: &unstructured.Unstructured{
Object: map[string]any{
"metadata": map[string]any{
"labels": map[string]any{
"test-label": "value",
},
},
},
},
skipLabels: "test-label=value",
expected: true,
},
{
name: "Label does not match",
obj: &unstructured.Unstructured{
Object: map[string]any{
"metadata": map[string]any{
"labels": map[string]any{
"different-label": "value",
},
},
},
},
skipLabels: "test-label=value",
expected: false,
},
{
name: "Empty skip labels",
obj: &unstructured.Unstructured{
Object: map[string]any{
"metadata": map[string]any{
"labels": map[string]any{
"test-label": "value",
},
},
},
},
skipLabels: "",
expected: false,
},
{
name: "No labels value",
obj: &unstructured.Unstructured{
Object: map[string]any{
"metadata": map[string]any{
"labels": map[string]any{
"test-label": "value",
"another-label": "value2",
},
},
},
},
skipLabels: "test-label",
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := isSkipLabelMatches(tt.obj, tt.skipLabels)
assert.Equal(t, tt.expected, result)
})
}
}

View File

@@ -180,13 +180,12 @@ func getControllerReplicas(ctx context.Context, kubeClient *kubernetes.Clientset
func NewClusterShardsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var (
shard int
replicas int
shardingAlgorithm string
clientConfig clientcmd.ClientConfig
cacheSrc func() (*appstatecache.Cache, error)
portForwardRedis bool
redisCompressionStr string
shard int
replicas int
shardingAlgorithm string
clientConfig clientcmd.ClientConfig
cacheSrc func() (*appstatecache.Cache, error)
portForwardRedis bool
)
command := cobra.Command{
Use: "shards",
@@ -210,7 +209,7 @@ func NewClusterShardsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comm
if replicas == 0 {
return
}
clusters, err := loadClusters(ctx, kubeClient, appClient, replicas, shardingAlgorithm, namespace, portForwardRedis, cacheSrc, shard, clientOpts.RedisName, clientOpts.RedisHaProxyName, redisCompressionStr)
clusters, err := loadClusters(ctx, kubeClient, appClient, replicas, shardingAlgorithm, namespace, portForwardRedis, cacheSrc, shard, clientOpts.RedisName, clientOpts.RedisHaProxyName, clientOpts.RedisCompression)
errors.CheckError(err)
if len(clusters) == 0 {
return
@@ -231,7 +230,6 @@ func NewClusterShardsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comm
// we can ignore unchecked error here as the command will be parsed again and checked when command.Execute() is run later
//nolint:errcheck
command.ParseFlags(os.Args[1:])
redisCompressionStr, _ = command.Flags().GetString(cacheutil.CLIFlagRedisCompress)
return &command
}
@@ -461,13 +459,12 @@ func NewClusterDisableNamespacedMode() *cobra.Command {
func NewClusterStatsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var (
shard int
replicas int
shardingAlgorithm string
clientConfig clientcmd.ClientConfig
cacheSrc func() (*appstatecache.Cache, error)
portForwardRedis bool
redisCompressionStr string
shard int
replicas int
shardingAlgorithm string
clientConfig clientcmd.ClientConfig
cacheSrc func() (*appstatecache.Cache, error)
portForwardRedis bool
)
command := cobra.Command{
Use: "stats",
@@ -497,7 +494,7 @@ argocd admin cluster stats target-cluster`,
replicas, err = getControllerReplicas(ctx, kubeClient, namespace, clientOpts.AppControllerName)
errors.CheckError(err)
}
clusters, err := loadClusters(ctx, kubeClient, appClient, replicas, shardingAlgorithm, namespace, portForwardRedis, cacheSrc, shard, clientOpts.RedisName, clientOpts.RedisHaProxyName, redisCompressionStr)
clusters, err := loadClusters(ctx, kubeClient, appClient, replicas, shardingAlgorithm, namespace, portForwardRedis, cacheSrc, shard, clientOpts.RedisName, clientOpts.RedisHaProxyName, clientOpts.RedisCompression)
errors.CheckError(err)
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
@@ -519,7 +516,6 @@ argocd admin cluster stats target-cluster`,
// we can ignore unchecked error here as the command will be parsed again and checked when command.Execute() is run later
//nolint:errcheck
command.ParseFlags(os.Args[1:])
redisCompressionStr, _ = command.Flags().GetString(cacheutil.CLIFlagRedisCompress)
return &command
}
@@ -549,7 +545,7 @@ argocd admin cluster kubeconfig https://cluster-api-url:6443 /path/to/output/kub
c.HelpFunc()(c, args)
os.Exit(1)
}
serverUrl := args[0]
serverURL := args[0]
output := args[1]
conf, err := clientConfig.ClientConfig()
errors.CheckError(err)
@@ -558,7 +554,7 @@ argocd admin cluster kubeconfig https://cluster-api-url:6443 /path/to/output/kub
kubeclientset, err := kubernetes.NewForConfig(conf)
errors.CheckError(err)
cluster, err := db.NewDB(namespace, settings.NewSettingsManager(ctx, kubeclientset, namespace), kubeclientset).GetCluster(ctx, serverUrl)
cluster, err := db.NewDB(namespace, settings.NewSettingsManager(ctx, kubeclientset, namespace), kubeclientset).GetCluster(ctx, serverURL)
errors.CheckError(err)
rawConfig, err := cluster.RawRestConfig()
errors.CheckError(err)

View File

@@ -1,7 +1,6 @@
package admin
import (
"context"
"testing"
"time"
@@ -51,7 +50,7 @@ func Test_loadClusters(t *testing.T) {
},
},
}
ctx := context.Background()
ctx := t.Context()
kubeClient := fake.NewClientset(argoCDCM, argoCDSecret)
appClient := fakeapps.NewSimpleClientset(app)
cacheSrc := func() (*appstate.Cache, error) {

View File

@@ -12,17 +12,14 @@ import (
"github.com/argoproj/argo-cd/v3/cmd/argocd/commands/initialize"
"github.com/argoproj/argo-cd/v3/common"
argocdclient "github.com/argoproj/argo-cd/v3/pkg/apiclient"
"github.com/argoproj/argo-cd/v3/util/cache"
"github.com/argoproj/argo-cd/v3/util/env"
"github.com/argoproj/argo-cd/v3/util/errors"
)
func NewDashboardCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var (
port int
address string
compressionStr string
clientConfig clientcmd.ClientConfig
port int
address string
clientConfig clientcmd.ClientConfig
)
cmd := &cobra.Command{
Use: "dashboard",
@@ -30,10 +27,8 @@ func NewDashboardCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command
Run: func(cmd *cobra.Command, _ []string) {
ctx := cmd.Context()
compression, err := cache.CompressionTypeFromString(compressionStr)
errors.CheckError(err)
clientOpts.Core = true
errors.CheckError(headless.MaybeStartLocalServer(ctx, clientOpts, initialize.RetrieveContextIfChanged(cmd.Flag("context")), &port, &address, compression, clientConfig))
errors.CheckError(headless.MaybeStartLocalServer(ctx, clientOpts, initialize.RetrieveContextIfChanged(cmd.Flag("context")), &port, &address, clientConfig))
println(fmt.Sprintf("Argo CD UI is available at http://%s:%d", address, port))
<-ctx.Done()
},
@@ -50,6 +45,5 @@ $ argocd admin dashboard --redis-compress gzip
clientConfig = cli.AddKubectlFlagsToSet(cmd.Flags())
cmd.Flags().IntVar(&port, "port", common.DefaultPortAPIServer, "Listen on given port")
cmd.Flags().StringVar(&address, "address", common.DefaultAddressAdminDashboard, "Listen on given address")
cmd.Flags().StringVar(&compressionStr, "redis-compress", env.StringFromEnv("REDIS_COMPRESSION", string(cache.RedisCompressionGZip)), "Enable this if the application controller is configured with redis compression enabled. (possible values: gzip, none)")
return cmd
}

View File

@@ -136,17 +136,17 @@ func generateProjectAllowList(serverResources []*metav1.APIResourceList, cluster
continue
}
ruleApiGroup := rule.APIGroups[0]
ruleAPIGroup := rule.APIGroups[0]
for _, ruleResource := range rule.Resources {
for _, apiResourcesList := range serverResources {
gv, err := schema.ParseGroupVersion(apiResourcesList.GroupVersion)
if err != nil {
gv = schema.GroupVersion{}
}
if ruleApiGroup == gv.Group {
if ruleAPIGroup == gv.Group {
for _, apiResource := range apiResourcesList.APIResources {
if apiResource.Name == ruleResource {
resourceList = append(resourceList, metav1.GroupKind{Group: ruleApiGroup, Kind: apiResource.Kind})
resourceList = append(resourceList, metav1.GroupKind{Group: ruleAPIGroup, Kind: apiResource.Kind})
}
}
}

View File

@@ -1,7 +1,6 @@
package admin
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
@@ -30,7 +29,7 @@ func newProj(name string, roleNames ...string) *v1alpha1.AppProject {
}
func TestUpdateProjects_FindMatchingProject(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
clientset := fake.NewSimpleClientset(newProj("foo", "test"), newProj("bar", "test"))
@@ -49,7 +48,7 @@ func TestUpdateProjects_FindMatchingProject(t *testing.T) {
}
func TestUpdateProjects_FindMatchingRole(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
clientset := fake.NewSimpleClientset(newProj("proj", "foo", "bar"))

View File

@@ -54,6 +54,9 @@ func NewGenRepoSpecCommand() *cobra.Command {
# Add a private Git repository via HTTPS using username/password and TLS client certificates:
argocd admin repo generate-spec https://git.example.com/repos/repo --username git --password secret --tls-client-cert-path ~/mycert.crt --tls-client-cert-key-path ~/mycert.key
# Add a private Git BitBucket Data Center repository via HTTPS using bearer token:
argocd admin repo generate-spec https://bitbucket.example.com/scm/proj/repo --bearer-token secret-token
# Add a private Git repository via HTTPS using username/password without verifying the server's TLS certificate
argocd admin repo generate-spec https://git.example.com/repos/repo --username git --password secret --insecure-skip-server-verification
@@ -138,6 +141,13 @@ func NewGenRepoSpecCommand() *cobra.Command {
repoOpts.Repo.Password = cli.PromptPassword(repoOpts.Repo.Password)
}
err := cmdutil.ValidateBearerTokenAndPasswordCombo(repoOpts.Repo.BearerToken, repoOpts.Repo.Password)
errors.CheckError(err)
err = cmdutil.ValidateBearerTokenForHTTPSRepoOnly(repoOpts.Repo.BearerToken, git.IsHTTPSURL(repoOpts.Repo.Repo))
errors.CheckError(err)
err = cmdutil.ValidateBearerTokenForGitOnly(repoOpts.Repo.BearerToken, repoOpts.Repo.Type)
errors.CheckError(err)
argoCDCM := &corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{
Kind: "ConfigMap",
@@ -155,7 +165,7 @@ func NewGenRepoSpecCommand() *cobra.Command {
settingsMgr := settings.NewSettingsManager(ctx, kubeClientset, ArgoCDNamespace)
argoDB := db.NewDB(ArgoCDNamespace, settingsMgr, kubeClientset)
_, err := argoDB.CreateRepository(ctx, &repoOpts.Repo)
_, err = argoDB.CreateRepository(ctx, &repoOpts.Repo)
errors.CheckError(err)
secret, err := kubeClientset.CoreV1().Secrets(ArgoCDNamespace).Get(ctx, db.RepoURLToSecretName(repoSecretPrefix, repoOpts.Repo.Repo, repoOpts.Repo.Project), metav1.GetOptions{})

View File

@@ -162,7 +162,7 @@ func NewSettingsCommand() *cobra.Command {
command.AddCommand(NewValidateSettingsCommand(&opts))
command.AddCommand(NewResourceOverridesCommand(&opts))
command.AddCommand(NewRBACCommand(&opts))
command.AddCommand(NewRBACCommand())
opts.clientConfig = cli.AddKubectlFlagsToCmd(command)
command.PersistentFlags().StringVar(&opts.argocdCMPath, "argocd-cm-path", "", "Path to local argocd-cm.yaml file")
@@ -247,19 +247,6 @@ var validatorsByGroup = map[string]settingValidator{
}
return summary, err
},
"repositories": joinValidators(func(manager *settings.SettingsManager) (string, error) {
repos, err := manager.GetRepositories()
if err != nil {
return "", err
}
return fmt.Sprintf("%d repositories", len(repos)), nil
}, func(manager *settings.SettingsManager) (string, error) {
creds, err := manager.GetRepositoryCredentials()
if err != nil {
return "", err
}
return fmt.Sprintf("%d repository credentials", len(creds)), nil
}),
"accounts": func(manager *settings.SettingsManager) (string, error) {
accounts, err := manager.GetAccounts()
if err != nil {

View File

@@ -15,10 +15,8 @@ import (
"sigs.k8s.io/yaml"
"github.com/argoproj/argo-cd/v3/common"
"github.com/argoproj/argo-cd/v3/server/rbacpolicy"
"github.com/argoproj/argo-cd/v3/util/assets"
"github.com/argoproj/argo-cd/v3/util/cli"
"github.com/argoproj/argo-cd/v3/util/errors"
"github.com/argoproj/argo-cd/v3/util/rbac"
)
@@ -28,98 +26,89 @@ type rbacTrait struct {
allowPath bool
}
// Provide a mapping of short-hand resource names to their RBAC counterparts
// Provide a mapping of shorthand resource names to their RBAC counterparts
var resourceMap = map[string]string{
"account": rbacpolicy.ResourceAccounts,
"app": rbacpolicy.ResourceApplications,
"apps": rbacpolicy.ResourceApplications,
"application": rbacpolicy.ResourceApplications,
"applicationsets": rbacpolicy.ResourceApplicationSets,
"cert": rbacpolicy.ResourceCertificates,
"certs": rbacpolicy.ResourceCertificates,
"certificate": rbacpolicy.ResourceCertificates,
"cluster": rbacpolicy.ResourceClusters,
"extension": rbacpolicy.ResourceExtensions,
"gpgkey": rbacpolicy.ResourceGPGKeys,
"key": rbacpolicy.ResourceGPGKeys,
"log": rbacpolicy.ResourceLogs,
"logs": rbacpolicy.ResourceLogs,
"exec": rbacpolicy.ResourceExec,
"proj": rbacpolicy.ResourceProjects,
"projs": rbacpolicy.ResourceProjects,
"project": rbacpolicy.ResourceProjects,
"repo": rbacpolicy.ResourceRepositories,
"repos": rbacpolicy.ResourceRepositories,
"repository": rbacpolicy.ResourceRepositories,
}
var projectScoped = map[string]bool{
rbacpolicy.ResourceApplications: true,
rbacpolicy.ResourceApplicationSets: true,
rbacpolicy.ResourceLogs: true,
rbacpolicy.ResourceExec: true,
rbacpolicy.ResourceClusters: true,
rbacpolicy.ResourceRepositories: true,
"account": rbac.ResourceAccounts,
"app": rbac.ResourceApplications,
"apps": rbac.ResourceApplications,
"application": rbac.ResourceApplications,
"applicationsets": rbac.ResourceApplicationSets,
"cert": rbac.ResourceCertificates,
"certs": rbac.ResourceCertificates,
"certificate": rbac.ResourceCertificates,
"cluster": rbac.ResourceClusters,
"extension": rbac.ResourceExtensions,
"gpgkey": rbac.ResourceGPGKeys,
"key": rbac.ResourceGPGKeys,
"log": rbac.ResourceLogs,
"logs": rbac.ResourceLogs,
"exec": rbac.ResourceExec,
"proj": rbac.ResourceProjects,
"projs": rbac.ResourceProjects,
"project": rbac.ResourceProjects,
"repo": rbac.ResourceRepositories,
"repos": rbac.ResourceRepositories,
"repository": rbac.ResourceRepositories,
}
// List of allowed RBAC resources
var validRBACResourcesActions = map[string]actionTraitMap{
rbacpolicy.ResourceAccounts: accountsActions,
rbacpolicy.ResourceApplications: applicationsActions,
rbacpolicy.ResourceApplicationSets: defaultCRUDActions,
rbacpolicy.ResourceCertificates: defaultCRDActions,
rbacpolicy.ResourceClusters: defaultCRUDActions,
rbacpolicy.ResourceExtensions: extensionActions,
rbacpolicy.ResourceGPGKeys: defaultCRDActions,
rbacpolicy.ResourceLogs: logsActions,
rbacpolicy.ResourceExec: execActions,
rbacpolicy.ResourceProjects: defaultCRUDActions,
rbacpolicy.ResourceRepositories: defaultCRUDActions,
rbac.ResourceAccounts: accountsActions,
rbac.ResourceApplications: applicationsActions,
rbac.ResourceApplicationSets: defaultCRUDActions,
rbac.ResourceCertificates: defaultCRDActions,
rbac.ResourceClusters: defaultCRUDActions,
rbac.ResourceExtensions: extensionActions,
rbac.ResourceGPGKeys: defaultCRDActions,
rbac.ResourceLogs: logsActions,
rbac.ResourceExec: execActions,
rbac.ResourceProjects: defaultCRUDActions,
rbac.ResourceRepositories: defaultCRUDActions,
}
// List of allowed RBAC actions
var defaultCRUDActions = actionTraitMap{
rbacpolicy.ActionCreate: rbacTrait{},
rbacpolicy.ActionGet: rbacTrait{},
rbacpolicy.ActionUpdate: rbacTrait{},
rbacpolicy.ActionDelete: rbacTrait{},
rbac.ActionCreate: rbacTrait{},
rbac.ActionGet: rbacTrait{},
rbac.ActionUpdate: rbacTrait{},
rbac.ActionDelete: rbacTrait{},
}
var defaultCRDActions = actionTraitMap{
rbacpolicy.ActionCreate: rbacTrait{},
rbacpolicy.ActionGet: rbacTrait{},
rbacpolicy.ActionDelete: rbacTrait{},
rbac.ActionCreate: rbacTrait{},
rbac.ActionGet: rbacTrait{},
rbac.ActionDelete: rbacTrait{},
}
var applicationsActions = actionTraitMap{
rbacpolicy.ActionCreate: rbacTrait{},
rbacpolicy.ActionGet: rbacTrait{},
rbacpolicy.ActionUpdate: rbacTrait{allowPath: true},
rbacpolicy.ActionDelete: rbacTrait{allowPath: true},
rbacpolicy.ActionAction: rbacTrait{allowPath: true},
rbacpolicy.ActionOverride: rbacTrait{},
rbacpolicy.ActionSync: rbacTrait{},
rbac.ActionCreate: rbacTrait{},
rbac.ActionGet: rbacTrait{},
rbac.ActionUpdate: rbacTrait{allowPath: true},
rbac.ActionDelete: rbacTrait{allowPath: true},
rbac.ActionAction: rbacTrait{allowPath: true},
rbac.ActionOverride: rbacTrait{},
rbac.ActionSync: rbacTrait{},
}
var accountsActions = actionTraitMap{
rbacpolicy.ActionCreate: rbacTrait{},
rbacpolicy.ActionUpdate: rbacTrait{},
rbac.ActionCreate: rbacTrait{},
rbac.ActionUpdate: rbacTrait{},
}
var execActions = actionTraitMap{
rbacpolicy.ActionCreate: rbacTrait{},
rbac.ActionCreate: rbacTrait{},
}
var logsActions = actionTraitMap{
rbacpolicy.ActionGet: rbacTrait{},
rbac.ActionGet: rbacTrait{},
}
var extensionActions = actionTraitMap{
rbacpolicy.ActionInvoke: rbacTrait{},
rbac.ActionInvoke: rbacTrait{},
}
// NewRBACCommand is the command for 'rbac'
func NewRBACCommand(cmdCtx commandContext) *cobra.Command {
func NewRBACCommand() *cobra.Command {
command := &cobra.Command{
Use: "rbac",
Short: "Validate and test RBAC configuration",
@@ -127,13 +116,13 @@ func NewRBACCommand(cmdCtx commandContext) *cobra.Command {
c.HelpFunc()(c, args)
},
}
command.AddCommand(NewRBACCanCommand(cmdCtx))
command.AddCommand(NewRBACCanCommand())
command.AddCommand(NewRBACValidateCommand())
return command
}
// NewRBACCanCommand is the command for 'rbac can'
func NewRBACCanCommand(cmdCtx commandContext) *cobra.Command {
func NewRBACCanCommand() *cobra.Command {
var (
policyFile string
defaultRole string
@@ -219,30 +208,7 @@ argocd admin settings rbac can someuser create application 'default/app' --defau
defaultRole = newDefaultRole
}
// Logs RBAC will be enforced only if an internal var serverRBACLogEnforceEnable
// (representing server.rbac.log.enforce.enable env var in argocd-cm)
// is defined and has a "true" value
// Otherwise, no RBAC enforcement for logs will take place (meaning, 'can' request on a logs resource will result in "yes",
// even if there is no explicit RBAC allow, or if there is an explicit RBAC deny)
var isLogRbacEnforced func() bool
if nsOverride && policyFile == "" {
if resolveRBACResourceName(resource) == rbacpolicy.ResourceLogs {
isLogRbacEnforced = func() bool {
if opts, ok := cmdCtx.(*settingsOpts); ok {
opts.loadClusterSettings = true
opts.clientConfig = clientConfig
settingsMgr, err := opts.createSettingsManager(ctx)
errors.CheckError(err)
logEnforceEnable, err := settingsMgr.GetServerRBACLogEnforceEnable()
errors.CheckError(err)
return logEnforceEnable
}
return false
}
}
}
res := checkPolicy(subject, action, resource, subResource, builtinPolicy, userPolicy, defaultRole, matchMode, strict, isLogRbacEnforced)
res := checkPolicy(subject, action, resource, subResource, builtinPolicy, userPolicy, defaultRole, matchMode, strict)
if res {
if !quiet {
fmt.Println("Yes")
@@ -408,7 +374,7 @@ func getPolicyConfigMap(ctx context.Context, client kubernetes.Interface, namesp
// checkPolicy checks whether given subject is allowed to execute specified
// action against specified resource
func checkPolicy(subject, action, resource, subResource, builtinPolicy, userPolicy, defaultRole, matchMode string, strict bool, isLogRbacEnforced func() bool) bool {
func checkPolicy(subject, action, resource, subResource, builtinPolicy, userPolicy, defaultRole, matchMode string, strict bool) bool {
enf := rbac.NewEnforcer(nil, "argocd", "argocd-rbac-cm", nil)
enf.SetDefaultRole(defaultRole)
enf.SetMatchMode(matchMode)
@@ -445,16 +411,11 @@ func checkPolicy(subject, action, resource, subResource, builtinPolicy, userPoli
// Some project scoped resources have a special notation - for simplicity's sake,
// if user gives no sub-resource (or specifies simple '*'), we construct
// the required notation by setting subresource to '*/*'.
if projectScoped[realResource] {
if rbac.ProjectScoped[realResource] {
if subResource == "*" || subResource == "" {
subResource = "*/*"
}
}
if realResource == rbacpolicy.ResourceLogs {
if isLogRbacEnforced != nil && !isLogRbacEnforced() {
return true
}
}
return enf.Enforce(subject, realResource, action, subResource)
}

View File

@@ -1,7 +1,6 @@
package admin
import (
"context"
"os"
"testing"
@@ -14,7 +13,8 @@ import (
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"github.com/argoproj/argo-cd/v3/server/rbacpolicy"
"github.com/argoproj/argo-cd/v3/util/rbac"
"github.com/argoproj/argo-cd/v3/util/assets"
)
@@ -56,8 +56,8 @@ func Test_validateRBACResourceAction(t *testing.T) {
{
name: "Test valid resource and action",
args: args{
resource: rbacpolicy.ResourceApplications,
action: rbacpolicy.ActionCreate,
resource: rbac.ResourceApplications,
action: rbac.ActionCreate,
},
valid: true,
},
@@ -71,7 +71,7 @@ func Test_validateRBACResourceAction(t *testing.T) {
{
name: "Test invalid action",
args: args{
resource: rbacpolicy.ResourceApplications,
resource: rbac.ResourceApplications,
action: "invalid",
},
valid: false,
@@ -79,24 +79,24 @@ func Test_validateRBACResourceAction(t *testing.T) {
{
name: "Test invalid action for resource",
args: args{
resource: rbacpolicy.ResourceLogs,
action: rbacpolicy.ActionCreate,
resource: rbac.ResourceLogs,
action: rbac.ActionCreate,
},
valid: false,
},
{
name: "Test valid action with path",
args: args{
resource: rbacpolicy.ResourceApplications,
action: rbacpolicy.ActionAction + "/apps/Deployment/restart",
resource: rbac.ResourceApplications,
action: rbac.ActionAction + "/apps/Deployment/restart",
},
valid: true,
},
{
name: "Test invalid action with path",
args: args{
resource: rbacpolicy.ResourceApplications,
action: rbacpolicy.ActionGet + "/apps/Deployment/restart",
resource: rbac.ResourceApplications,
action: rbac.ActionGet + "/apps/Deployment/restart",
},
valid: false,
},
@@ -115,7 +115,7 @@ func Test_validateRBACResourceAction(t *testing.T) {
}
func Test_PolicyFromCSV(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
uPol, dRole, matchMode := getPolicy(ctx, "testdata/rbac/policy.csv", nil, "")
require.NotEmpty(t, uPol)
@@ -124,27 +124,19 @@ func Test_PolicyFromCSV(t *testing.T) {
}
func Test_PolicyFromYAML(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
uPol, dRole, matchMode := getPolicy(ctx, "testdata/rbac/argocd-rbac-cm.yaml", nil, "")
require.NotEmpty(t, uPol)
require.Equal(t, "role:unknown", dRole)
require.Empty(t, matchMode)
require.True(t, checkPolicy("my-org:team-qa", "update", "project", "foo",
"", uPol, dRole, matchMode, true, nil))
}
func trueLogRbacEnforce() bool {
return true
}
func falseLogRbacEnforce() bool {
return false
"", uPol, dRole, matchMode, true))
}
func Test_PolicyFromK8s(t *testing.T) {
data, err := os.ReadFile("testdata/rbac/policy.csv")
ctx := context.Background()
ctx := t.Context()
require.NoError(t, err)
kubeclientset := fake.NewClientset(&corev1.ConfigMap{
@@ -163,111 +155,69 @@ func Test_PolicyFromK8s(t *testing.T) {
require.Equal(t, "", matchMode)
t.Run("get applications", func(t *testing.T) {
ok := checkPolicy("role:user", "get", "applications", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, nil)
ok := checkPolicy("role:user", "get", "applications", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true)
require.True(t, ok)
})
t.Run("get clusters", func(t *testing.T) {
ok := checkPolicy("role:user", "get", "clusters", "*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, nil)
ok := checkPolicy("role:user", "get", "clusters", "*", assets.BuiltinPolicyCSV, uPol, dRole, "", true)
require.True(t, ok)
})
t.Run("get certificates", func(t *testing.T) {
ok := checkPolicy("role:user", "get", "certificates", "*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, nil)
ok := checkPolicy("role:user", "get", "certificates", "*", assets.BuiltinPolicyCSV, uPol, dRole, "", true)
require.False(t, ok)
})
t.Run("get certificates by default role", func(t *testing.T) {
ok := checkPolicy("role:user", "get", "certificates", "*", assets.BuiltinPolicyCSV, uPol, "role:readonly", "glob", true, nil)
ok := checkPolicy("role:user", "get", "certificates", "*", assets.BuiltinPolicyCSV, uPol, "role:readonly", "glob", true)
require.True(t, ok)
})
t.Run("get certificates by default role without builtin policy", func(t *testing.T) {
ok := checkPolicy("role:user", "get", "certificates", "*", "", uPol, "role:readonly", "glob", true, nil)
ok := checkPolicy("role:user", "get", "certificates", "*", "", uPol, "role:readonly", "glob", true)
require.False(t, ok)
})
t.Run("use regex match mode instead of glob", func(t *testing.T) {
ok := checkPolicy("role:user", "get", "certificates", ".*", assets.BuiltinPolicyCSV, uPol, "role:readonly", "regex", true, nil)
ok := checkPolicy("role:user", "get", "certificates", ".*", assets.BuiltinPolicyCSV, uPol, "role:readonly", "regex", true)
require.False(t, ok)
})
t.Run("get logs", func(t *testing.T) {
ok := checkPolicy("role:test", "get", "logs", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, nil)
ok := checkPolicy("role:test", "get", "logs", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true)
require.True(t, ok)
})
// no function is provided to check if logs rbac is enforced or not, so the policy permissions are queried to determine if no-such-user can get logs
t.Run("no-such-user get logs", func(t *testing.T) {
ok := checkPolicy("no-such-user", "get", "logs", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, nil)
ok := checkPolicy("no-such-user", "get", "logs", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true)
require.False(t, ok)
})
// logs rbac policy is enforced, and no-such-user is not granted logs permission in user policy, so the result should be false (cannot get logs)
t.Run("no-such-user get logs rbac enforced", func(t *testing.T) {
ok := checkPolicy("no-such-user", "get", "logs", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, trueLogRbacEnforce)
require.False(t, ok)
})
// no-such-user is not granted logs permission in user policy, but logs rbac policy is not enforced, so logs permission is open to all
t.Run("no-such-user get logs rbac not enforced", func(t *testing.T) {
ok := checkPolicy("no-such-user", "get", "logs", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, falseLogRbacEnforce)
require.True(t, ok)
})
// no function is provided to check if logs rbac is enforced or not, so the policy permissions are queried to determine if log-deny-user can get logs
t.Run("log-deny-user get logs", func(t *testing.T) {
ok := checkPolicy("log-deny-user", "get", "logs", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, nil)
ok := checkPolicy("log-deny-user", "get", "logs", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true)
require.False(t, ok)
})
// logs rbac policy is enforced, and log-deny-user is denied logs permission in user policy, so the result should be false (cannot get logs)
t.Run("log-deny-user get logs rbac enforced", func(t *testing.T) {
ok := checkPolicy("log-deny-user", "get", "logs", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, trueLogRbacEnforce)
require.False(t, ok)
})
// log-deny-user is denied logs permission in user policy, but logs rbac policy is not enforced, so logs permission is open to all
t.Run("log-deny-user get logs rbac not enforced", func(t *testing.T) {
ok := checkPolicy("log-deny-user", "get", "logs", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, falseLogRbacEnforce)
require.True(t, ok)
})
// no function is provided to check if logs rbac is enforced or not, so the policy permissions are queried to determine if log-allow-user can get logs
t.Run("log-allow-user get logs", func(t *testing.T) {
ok := checkPolicy("log-allow-user", "get", "logs", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, nil)
require.True(t, ok)
})
// logs rbac policy is enforced, and log-allow-user is granted logs permission in user policy, so the result should be true (can get logs)
t.Run("log-allow-user get logs rbac enforced", func(t *testing.T) {
ok := checkPolicy("log-allow-user", "get", "logs", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, trueLogRbacEnforce)
require.True(t, ok)
})
// log-allow-user is granted logs permission in user policy, and logs rbac policy is not enforced, so logs permission is open to all
t.Run("log-allow-user get logs rbac not enforced", func(t *testing.T) {
ok := checkPolicy("log-allow-user", "get", "logs", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, falseLogRbacEnforce)
ok := checkPolicy("log-allow-user", "get", "logs", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true)
require.True(t, ok)
})
t.Run("get logs", func(t *testing.T) {
ok := checkPolicy("role:test", "get", "logs", "*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, nil)
ok := checkPolicy("role:test", "get", "logs", "*", assets.BuiltinPolicyCSV, uPol, dRole, "", true)
require.True(t, ok)
})
t.Run("get logs", func(t *testing.T) {
ok := checkPolicy("role:test", "get", "logs", "", assets.BuiltinPolicyCSV, uPol, dRole, "", true, nil)
ok := checkPolicy("role:test", "get", "logs", "", assets.BuiltinPolicyCSV, uPol, dRole, "", true)
require.True(t, ok)
})
t.Run("create exec", func(t *testing.T) {
ok := checkPolicy("role:test", "create", "exec", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, nil)
ok := checkPolicy("role:test", "create", "exec", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true)
require.True(t, ok)
})
t.Run("create applicationsets", func(t *testing.T) {
ok := checkPolicy("role:user", "create", "applicationsets", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, nil)
require.True(t, ok)
})
// trueLogRbacEnforce or falseLogRbacEnforce should not affect non-logs resources
t.Run("create applicationsets with trueLogRbacEnforce", func(t *testing.T) {
ok := checkPolicy("role:user", "create", "applicationsets", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, trueLogRbacEnforce)
require.True(t, ok)
})
t.Run("create applicationsets with falseLogRbacEnforce", func(t *testing.T) {
ok := checkPolicy("role:user", "create", "applicationsets", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, trueLogRbacEnforce)
ok := checkPolicy("role:user", "create", "applicationsets", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true)
require.True(t, ok)
})
t.Run("delete applicationsets", func(t *testing.T) {
ok := checkPolicy("role:user", "delete", "applicationsets", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true, nil)
ok := checkPolicy("role:user", "delete", "applicationsets", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true)
require.True(t, ok)
})
}
func Test_PolicyFromK8sUsingRegex(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
policy := `
p, role:user, clusters, get, .+, allow
@@ -301,49 +251,49 @@ p, role:readonly, certificates, get, .*, allow
p, role:, certificates, get, .*, allow`
t.Run("get applications", func(t *testing.T) {
ok := checkPolicy("role:user", "get", "applications", ".*/.*", builtInPolicy, uPol, dRole, "regex", true, nil)
ok := checkPolicy("role:user", "get", "applications", ".*/.*", builtInPolicy, uPol, dRole, "regex", true)
require.True(t, ok)
})
t.Run("get clusters", func(t *testing.T) {
ok := checkPolicy("role:user", "get", "clusters", ".*", builtInPolicy, uPol, dRole, "regex", true, nil)
ok := checkPolicy("role:user", "get", "clusters", ".*", builtInPolicy, uPol, dRole, "regex", true)
require.True(t, ok)
})
t.Run("get certificates", func(t *testing.T) {
ok := checkPolicy("role:user", "get", "certificates", ".*", builtInPolicy, uPol, dRole, "regex", true, nil)
ok := checkPolicy("role:user", "get", "certificates", ".*", builtInPolicy, uPol, dRole, "regex", true)
require.False(t, ok)
})
t.Run("get certificates by default role", func(t *testing.T) {
ok := checkPolicy("role:user", "get", "certificates", ".*", builtInPolicy, uPol, "role:readonly", "regex", true, nil)
ok := checkPolicy("role:user", "get", "certificates", ".*", builtInPolicy, uPol, "role:readonly", "regex", true)
require.True(t, ok)
})
t.Run("get certificates by default role without builtin policy", func(t *testing.T) {
ok := checkPolicy("role:user", "get", "certificates", ".*", "", uPol, "role:readonly", "regex", true, nil)
ok := checkPolicy("role:user", "get", "certificates", ".*", "", uPol, "role:readonly", "regex", true)
require.False(t, ok)
})
t.Run("use glob match mode instead of regex", func(t *testing.T) {
ok := checkPolicy("role:user", "get", "certificates", ".+", builtInPolicy, uPol, dRole, "glob", true, nil)
ok := checkPolicy("role:user", "get", "certificates", ".+", builtInPolicy, uPol, dRole, "glob", true)
require.False(t, ok)
})
t.Run("get logs via glob match mode", func(t *testing.T) {
ok := checkPolicy("role:user", "get", "logs", ".*/.*", builtInPolicy, uPol, dRole, "glob", true, nil)
ok := checkPolicy("role:user", "get", "logs", ".*/.*", builtInPolicy, uPol, dRole, "glob", true)
require.True(t, ok)
})
t.Run("create exec", func(t *testing.T) {
ok := checkPolicy("role:user", "create", "exec", ".*/.*", builtInPolicy, uPol, dRole, "regex", true, nil)
ok := checkPolicy("role:user", "create", "exec", ".*/.*", builtInPolicy, uPol, dRole, "regex", true)
require.True(t, ok)
})
t.Run("create applicationsets", func(t *testing.T) {
ok := checkPolicy("role:user", "create", "applicationsets", ".*/.*", builtInPolicy, uPol, dRole, "regex", true, nil)
ok := checkPolicy("role:user", "create", "applicationsets", ".*/.*", builtInPolicy, uPol, dRole, "regex", true)
require.True(t, ok)
})
t.Run("delete applicationsets", func(t *testing.T) {
ok := checkPolicy("role:user", "delete", "applicationsets", ".*/.*", builtInPolicy, uPol, dRole, "regex", true, nil)
ok := checkPolicy("role:user", "delete", "applicationsets", ".*/.*", builtInPolicy, uPol, dRole, "regex", true)
require.True(t, ok)
})
}
func TestNewRBACCanCommand(t *testing.T) {
command := NewRBACCanCommand(&settingsOpts{})
command := NewRBACCanCommand()
require.NotNil(t, command)
assert.Equal(t, "can", command.Name())

View File

@@ -88,7 +88,7 @@ type validatorTestCase struct {
}
func TestCreateSettingsManager(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
f, closer, err := tempFile(`apiVersion: v1
kind: ConfigMap
@@ -157,15 +157,6 @@ clientSecret: aaaabbbbccccddddeee`,
},
containsSummary: "updated-options",
},
"Repositories": {
validator: "repositories",
data: map[string]string{
"repositories": `
- url: https://github.com/argoproj/my-private-repository1
- url: https://github.com/argoproj/my-private-repository2`,
},
containsSummary: "2 repositories",
},
"Accounts": {
validator: "accounts",
data: map[string]string{

View File

@@ -21,7 +21,7 @@ import (
"github.com/argoproj/gitops-engine/pkg/sync/hook"
"github.com/argoproj/gitops-engine/pkg/sync/ignore"
"github.com/argoproj/gitops-engine/pkg/utils/kube"
grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/retry"
grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/retry"
"github.com/mattn/go-isatty"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -276,7 +276,7 @@ func hasAppChanged(appReq, appRes *argoappv1.Application, upsert bool) bool {
}
func parentChildDetails(ctx context.Context, appIf application.ApplicationServiceClient, appName string, appNs string) (map[string]argoappv1.ResourceNode, map[string][]string, map[string]struct{}) {
mapUidToNode := make(map[string]argoappv1.ResourceNode)
mapUIDToNode := make(map[string]argoappv1.ResourceNode)
mapParentToChild := make(map[string][]string)
parentNode := make(map[string]struct{})
@@ -284,7 +284,7 @@ func parentChildDetails(ctx context.Context, appIf application.ApplicationServic
errors.CheckError(err)
for _, node := range resourceTree.Nodes {
mapUidToNode[node.UID] = node
mapUIDToNode[node.UID] = node
if len(node.ParentRefs) > 0 {
_, ok := mapParentToChild[node.ParentRefs[0].UID]
@@ -297,7 +297,7 @@ func parentChildDetails(ctx context.Context, appIf application.ApplicationServic
parentNode[node.UID] = struct{}{}
}
}
return mapUidToNode, mapParentToChild, parentNode
return mapUIDToNode, mapParentToChild, parentNode
}
func printHeader(ctx context.Context, acdClient argocdclient.Client, app *argoappv1.Application, windows *argoappv1.SyncWindows, showOperation bool, showParams bool, sourcePosition int) {
@@ -444,17 +444,17 @@ func NewApplicationGetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Com
}
case "tree":
printHeader(ctx, acdClient, app, windows, showOperation, showParams, sourcePosition)
mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState := resourceParentChild(ctx, acdClient, appName, appNs)
if len(mapUidToNode) > 0 {
mapUIDToNode, mapParentToChild, parentNode, mapNodeNameToResourceState := resourceParentChild(ctx, acdClient, appName, appNs)
if len(mapUIDToNode) > 0 {
fmt.Println()
printTreeView(mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState)
printTreeView(mapUIDToNode, mapParentToChild, parentNode, mapNodeNameToResourceState)
}
case "tree=detailed":
printHeader(ctx, acdClient, app, windows, showOperation, showParams, sourcePosition)
mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState := resourceParentChild(ctx, acdClient, appName, appNs)
if len(mapUidToNode) > 0 {
mapUIDToNode, mapParentToChild, parentNode, mapNodeNameToResourceState := resourceParentChild(ctx, acdClient, appName, appNs)
if len(mapUIDToNode) > 0 {
fmt.Println()
printTreeViewDetailed(mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState)
printTreeViewDetailed(mapUIDToNode, mapParentToChild, parentNode, mapNodeNameToResourceState)
}
default:
errors.CheckError(fmt.Errorf("unknown output format: %s", output))
@@ -486,6 +486,7 @@ func NewApplicationLogsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
filter string
container string
previous bool
matchCase bool
)
command := &cobra.Command{
Use: "logs APPNAME",
@@ -521,6 +522,9 @@ func NewApplicationLogsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
# Filter logs to show only those containing a specific string
argocd app logs my-app --filter "error"
# Filter logs to show only those containing a specific string and match case
argocd app logs my-app --filter "error" --match-case
# Get logs for a specific container within the pods
argocd app logs my-app -c my-container
@@ -554,6 +558,7 @@ func NewApplicationLogsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
SinceSeconds: ptr.To(sinceSeconds),
UntilTime: &untilTime,
Filter: &filter,
MatchCase: ptr.To(matchCase),
Container: ptr.To(container),
Previous: ptr.To(previous),
AppNamespace: &appNs,
@@ -598,6 +603,7 @@ func NewApplicationLogsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
command.Flags().StringVar(&filter, "filter", "", "Show logs contain this string")
command.Flags().StringVarP(&container, "container", "c", "", "Optional container name")
command.Flags().BoolVarP(&previous, "previous", "p", false, "Specify if the previously terminated container logs should be returned")
command.Flags().BoolVarP(&matchCase, "match-case", "m", false, "Specify if the filter should be case-sensitive")
return command
}
@@ -887,6 +893,7 @@ type unsetOpts struct {
kustomizeNamespace bool
kustomizeImages []string
kustomizeReplicas []string
ignoreMissingComponents bool
parameters []string
valuesFiles []string
valuesLiteral bool
@@ -903,6 +910,7 @@ func (o *unsetOpts) KustomizeIsZero() bool {
!o.nameSuffix &&
!o.kustomizeVersion &&
!o.kustomizeNamespace &&
!o.ignoreMissingComponents &&
len(o.kustomizeImages) == 0 &&
len(o.kustomizeReplicas) == 0
}
@@ -1008,6 +1016,7 @@ func NewApplicationUnsetCommand(clientOpts *argocdclient.ClientOptions) *cobra.C
command.Flags().BoolVar(&opts.kustomizeNamespace, "kustomize-namespace", false, "Kustomize namespace")
command.Flags().StringArrayVar(&opts.kustomizeImages, "kustomize-image", []string{}, "Kustomize images name (e.g. --kustomize-image node --kustomize-image mysql)")
command.Flags().StringArrayVar(&opts.kustomizeReplicas, "kustomize-replica", []string{}, "Kustomize replicas name (e.g. --kustomize-replica my-deployment --kustomize-replica my-statefulset)")
command.Flags().BoolVar(&opts.ignoreMissingComponents, "ignore-missing-components", false, "Unset the kustomize ignore-missing-components option (revert to false)")
command.Flags().StringArrayVar(&opts.pluginEnvs, "plugin-env", []string{}, "Unset plugin env variables (e.g --plugin-env name)")
command.Flags().BoolVar(&opts.passCredentials, "pass-credentials", false, "Unset passCredentials")
command.Flags().BoolVar(&opts.ref, "ref", false, "Unset ref on the source")
@@ -1048,6 +1057,11 @@ func unset(source *argoappv1.ApplicationSource, opts unsetOpts) (updated bool, n
source.Kustomize.Namespace = ""
}
if opts.ignoreMissingComponents && source.Kustomize.IgnoreMissingComponents {
source.Kustomize.IgnoreMissingComponents = false
updated = true
}
for _, kustomizeImage := range opts.kustomizeImages {
for i, item := range source.Kustomize.Images {
if argoappv1.KustomizeImage(kustomizeImage).Match(item) {
@@ -2492,14 +2506,14 @@ func checkResourceStatus(watch watchOpts, healthStatus string, syncStatus string
// constructs the necessary data structures to print the app as a tree.
func resourceParentChild(ctx context.Context, acdClient argocdclient.Client, appName string, appNs string) (map[string]argoappv1.ResourceNode, map[string][]string, map[string]struct{}, map[string]*resourceState) {
_, appIf := acdClient.NewApplicationClientOrDie()
mapUidToNode, mapParentToChild, parentNode := parentChildDetails(ctx, appIf, appName, appNs)
mapUIDToNode, mapParentToChild, parentNode := parentChildDetails(ctx, appIf, appName, appNs)
app, err := appIf.Get(ctx, &application.ApplicationQuery{Name: ptr.To(appName), AppNamespace: ptr.To(appNs)})
errors.CheckError(err)
mapNodeNameToResourceState := make(map[string]*resourceState)
for _, res := range getResourceStates(app, nil) {
mapNodeNameToResourceState[res.Kind+"/"+res.Name] = res
}
return mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState
return mapUIDToNode, mapParentToChild, parentNode, mapNodeNameToResourceState
}
const waitFormatString = "%s\t%5s\t%10s\t%10s\t%20s\t%8s\t%7s\t%10s\t%s\n"
@@ -2557,16 +2571,17 @@ func waitOnApplicationStatus(ctx context.Context, acdClient argocdclient.Client,
_ = w.Flush()
}
case "tree":
mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState := resourceParentChild(ctx, acdClient, appRealName, appNs)
if len(mapUidToNode) > 0 {
mapUIDToNode, mapParentToChild, parentNode, mapNodeNameToResourceState := resourceParentChild(ctx, acdClient, appRealName, appNs)
if len(mapUIDToNode) > 0 {
fmt.Println()
printTreeView(mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState)
printTreeView(mapUIDToNode, mapParentToChild, parentNode, mapNodeNameToResourceState)
}
case "tree=detailed":
mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState := resourceParentChild(ctx, acdClient, appRealName, appNs)
if len(mapUidToNode) > 0 {
mapUIDToNode, mapParentToChild, parentNode, mapNodeNameToResourceState := resourceParentChild(ctx, acdClient, appRealName, appNs)
if len(mapUIDToNode) > 0 {
fmt.Println()
printTreeViewDetailed(mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState)
printTreeViewDetailed(mapUIDToNode, mapParentToChild, parentNode, mapNodeNameToResourceState)
}
default:
errors.CheckError(fmt.Errorf("unknown output format: %s", output))
@@ -2733,7 +2748,7 @@ func setParameterOverrides(app *argoappv1.Application, parameters []string, sour
}
// Print list of history ID's for an application.
func printApplicationHistoryIds(revHistory []argoappv1.RevisionHistory) {
func printApplicationHistoryIDs(revHistory []argoappv1.RevisionHistory) {
for _, depInfo := range revHistory {
fmt.Println(depInfo.ID)
}
@@ -2741,7 +2756,7 @@ func printApplicationHistoryIds(revHistory []argoappv1.RevisionHistory) {
// Print a history table for an application.
func printApplicationHistoryTable(revHistory []argoappv1.RevisionHistory) {
MAX_ALLOWED_REVISIONS := 7
maxAllowedRevisions := 7
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
type history struct {
id int64
@@ -2754,8 +2769,8 @@ func printApplicationHistoryTable(revHistory []argoappv1.RevisionHistory) {
if depInfo.Sources != nil {
for i, sourceInfo := range depInfo.Sources {
rev := sourceInfo.TargetRevision
if len(depInfo.Revisions) == len(depInfo.Sources) && len(depInfo.Revisions[i]) >= MAX_ALLOWED_REVISIONS {
rev = fmt.Sprintf("%s (%s)", rev, depInfo.Revisions[i][0:MAX_ALLOWED_REVISIONS])
if len(depInfo.Revisions) == len(depInfo.Sources) && len(depInfo.Revisions[i]) >= maxAllowedRevisions {
rev = fmt.Sprintf("%s (%s)", rev, depInfo.Revisions[i][0:maxAllowedRevisions])
}
if _, ok := varHistory[sourceInfo.RepoURL]; !ok {
varHistoryKeys = append(varHistoryKeys, sourceInfo.RepoURL)
@@ -2768,8 +2783,8 @@ func printApplicationHistoryTable(revHistory []argoappv1.RevisionHistory) {
}
} else {
rev := depInfo.Source.TargetRevision
if len(depInfo.Revision) >= MAX_ALLOWED_REVISIONS {
rev = fmt.Sprintf("%s (%s)", rev, depInfo.Revision[0:MAX_ALLOWED_REVISIONS])
if len(depInfo.Revision) >= maxAllowedRevisions {
rev = fmt.Sprintf("%s (%s)", rev, depInfo.Revision[0:maxAllowedRevisions])
}
if _, ok := varHistory[depInfo.Source.RepoURL]; !ok {
varHistoryKeys = append(varHistoryKeys, depInfo.Source.RepoURL)
@@ -2821,7 +2836,7 @@ func NewApplicationHistoryCommand(clientOpts *argocdclient.ClientOptions) *cobra
errors.CheckError(err)
if output == "id" {
printApplicationHistoryIds(app.Status.History)
printApplicationHistoryIDs(app.Status.History)
} else {
printApplicationHistoryTable(app.Status.History)
}

View File

@@ -164,12 +164,12 @@ func NewApplicationDeleteResourceCommand(clientOpts *argocdclient.ClientOptions)
}
func parentChildInfo(nodes []v1alpha1.ResourceNode) (map[string]v1alpha1.ResourceNode, map[string][]string, map[string]struct{}) {
mapUidToNode := make(map[string]v1alpha1.ResourceNode)
mapUIDToNode := make(map[string]v1alpha1.ResourceNode)
mapParentToChild := make(map[string][]string)
parentNode := make(map[string]struct{})
for _, node := range nodes {
mapUidToNode[node.UID] = node
mapUIDToNode[node.UID] = node
if len(node.ParentRefs) > 0 {
_, ok := mapParentToChild[node.ParentRefs[0].UID]
@@ -182,7 +182,7 @@ func parentChildInfo(nodes []v1alpha1.ResourceNode) (map[string]v1alpha1.Resourc
parentNode[node.UID] = struct{}{}
}
}
return mapUidToNode, mapParentToChild, parentNode
return mapUIDToNode, mapParentToChild, parentNode
}
func printDetailedTreeViewAppResourcesNotOrphaned(nodeMapping map[string]v1alpha1.ResourceNode, parentChildMapping map[string][]string, parentNodes map[string]struct{}, w *tabwriter.Writer) {
@@ -216,25 +216,25 @@ func printResources(listAll bool, orphaned bool, appResourceTree *v1alpha1.Appli
fmt.Fprintf(w, "GROUP\tKIND\tNAMESPACE\tNAME\tORPHANED\tAGE\tHEALTH\tREASON\n")
if !orphaned || listAll {
mapUidToNode, mapParentToChild, parentNode := parentChildInfo(appResourceTree.Nodes)
printDetailedTreeViewAppResourcesNotOrphaned(mapUidToNode, mapParentToChild, parentNode, w)
mapUIDToNode, mapParentToChild, parentNode := parentChildInfo(appResourceTree.Nodes)
printDetailedTreeViewAppResourcesNotOrphaned(mapUIDToNode, mapParentToChild, parentNode, w)
}
if orphaned || listAll {
mapUidToNode, mapParentToChild, parentNode := parentChildInfo(appResourceTree.OrphanedNodes)
printDetailedTreeViewAppResourcesOrphaned(mapUidToNode, mapParentToChild, parentNode, w)
mapUIDToNode, mapParentToChild, parentNode := parentChildInfo(appResourceTree.OrphanedNodes)
printDetailedTreeViewAppResourcesOrphaned(mapUIDToNode, mapParentToChild, parentNode, w)
}
case "tree":
fmt.Fprintf(w, "GROUP\tKIND\tNAMESPACE\tNAME\tORPHANED\n")
if !orphaned || listAll {
mapUidToNode, mapParentToChild, parentNode := parentChildInfo(appResourceTree.Nodes)
printTreeViewAppResourcesNotOrphaned(mapUidToNode, mapParentToChild, parentNode, w)
mapUIDToNode, mapParentToChild, parentNode := parentChildInfo(appResourceTree.Nodes)
printTreeViewAppResourcesNotOrphaned(mapUIDToNode, mapParentToChild, parentNode, w)
}
if orphaned || listAll {
mapUidToNode, mapParentToChild, parentNode := parentChildInfo(appResourceTree.OrphanedNodes)
printTreeViewAppResourcesOrphaned(mapUidToNode, mapParentToChild, parentNode, w)
mapUIDToNode, mapParentToChild, parentNode := parentChildInfo(appResourceTree.OrphanedNodes)
printTreeViewAppResourcesOrphaned(mapUIDToNode, mapParentToChild, parentNode, w)
}
default:
headers := []any{"GROUP", "KIND", "NAMESPACE", "NAME", "ORPHANED"}

View File

@@ -1029,11 +1029,10 @@ func TestTargetObjects_invalid(t *testing.T) {
assert.Error(t, err)
}
func TestCheckForDeleteEvent(_ *testing.T) {
ctx := context.Background()
func TestCheckForDeleteEvent(t *testing.T) {
fakeClient := new(fakeAcdClient)
checkForDeleteEvent(ctx, fakeClient, "testApp")
checkForDeleteEvent(t.Context(), fakeClient, "testApp")
}
func TestPrintApplicationNames(t *testing.T) {
@@ -1053,9 +1052,10 @@ func TestPrintApplicationNames(t *testing.T) {
func Test_unset(t *testing.T) {
kustomizeSource := &v1alpha1.ApplicationSource{
Kustomize: &v1alpha1.ApplicationSourceKustomize{
NamePrefix: "some-prefix",
NameSuffix: "some-suffix",
Version: "123",
IgnoreMissingComponents: true,
NamePrefix: "some-prefix",
NameSuffix: "some-suffix",
Version: "123",
Images: v1alpha1.KustomizeImages{
"old1=new:tag",
"old2=new:tag",
@@ -1155,6 +1155,15 @@ func Test_unset(t *testing.T) {
assert.False(t, updated)
assert.False(t, nothingToUnset)
assert.True(t, kustomizeSource.Kustomize.IgnoreMissingComponents)
updated, nothingToUnset = unset(kustomizeSource, unsetOpts{ignoreMissingComponents: true})
assert.False(t, kustomizeSource.Kustomize.IgnoreMissingComponents)
assert.True(t, updated)
assert.False(t, nothingToUnset)
updated, nothingToUnset = unset(kustomizeSource, unsetOpts{ignoreMissingComponents: true})
assert.False(t, updated)
assert.False(t, nothingToUnset)
assert.Len(t, helmSource.Helm.Parameters, 2)
updated, nothingToUnset = unset(helmSource, unsetOpts{parameters: []string{"name-1"}})
assert.Len(t, helmSource.Helm.Parameters, 1)
@@ -1862,7 +1871,7 @@ func testApp(name, project string, labels map[string]string, annotations map[str
func TestWaitOnApplicationStatus_JSON_YAML_WideOutput(t *testing.T) {
acdClient := &customAcdClient{&fakeAcdClient{}}
ctx := context.Background()
ctx := t.Context()
var selectResource []*v1alpha1.SyncOperationResource
watch := watchOpts{
sync: false,

Some files were not shown because too many files have changed in this diff Show More