Skip to content

Commit e89e786

Browse files
flozzonejessebye
authored andcommitted
feat: Add possibility to specify write-back GIT repository as annotation (argoproj-labs#424)
* Add possibility to specify write-back GIT repository as annotation. Signed-off-by: flozzone <[email protected]> * Update golangci-lint to 1.52.2. Signed-off-by: flozzone <[email protected]> * Replace deprecated golangci linters with 'unused' linter. Signed-off-by: flozzone <[email protected]> * Fix Goimport issues. Signed-off-by: flozzone <[email protected]> --------- Signed-off-by: flozzone <[email protected]> Signed-off-by: Jesse Bye <[email protected]>
1 parent 7a871ee commit e89e786

File tree

8 files changed

+81
-15
lines changed

8 files changed

+81
-15
lines changed

.golangci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@ linters-settings:
1616
goimports:
1717
local-prefixes: github.com/argoproj-labs/argocd-image-updater
1818
service:
19-
golangci-lint-version: 1.26.0
19+
golangci-lint-version: 1.52.2

docs/basics/update-methods.md

+16
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,22 @@ kubectl -n argocd-image-updater create secret generic git-creds \
144144
--from-file=sshPrivateKey=~/.ssh/id_rsa
145145
```
146146

147+
### <a name="method-git-repository"></a>Specifying a repository when using a Helm repository in repoURL
148+
149+
By default, Argo CD Image Updater will use the value found in the Application
150+
spec at `.spec.source.repoURL` as Git repository to checkout. But when using
151+
a Helm repository as `.spec.source.repoURL` GIT will simply fail. To manually
152+
specify the repository to push the changes, specify the
153+
annotation `argocd-image-updater.argoproj.io/git-repository` on the Application
154+
manifest.
155+
156+
The value of this annotation will define the Git repository to use, for example the
157+
following would use a GitHub's repository:
158+
159+
```yaml
160+
argocd-image-updater.argoproj.io/git-repository: [email protected]:example/example.git
161+
```
162+
147163
### <a name="method-git-branch"></a>Specifying a branch to commit to
148164

149165
By default, Argo CD Image Updater will use the value found in the Application

ext/git/mocks/Client.go

+2-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/argocd/git.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ func commitChangesGit(app *v1alpha1.Application, wbc *WriteBackConfig, changeLis
131131
logCtx := log.WithContext().AddField("application", app.GetName())
132132
creds, err := wbc.GetCreds(app)
133133
if err != nil {
134-
return fmt.Errorf("could not get creds for repo '%s': %v", app.Spec.Source.RepoURL, err)
134+
return fmt.Errorf("could not get creds for repo '%s': %v", wbc.GitRepo, err)
135135
}
136136
var gitC git.Client
137137
if wbc.GitClient == nil {
@@ -145,7 +145,7 @@ func commitChangesGit(app *v1alpha1.Application, wbc *WriteBackConfig, changeLis
145145
logCtx.Errorf("could not remove temp dir: %v", err)
146146
}
147147
}()
148-
gitC, err = git.NewClientExt(app.Spec.Source.RepoURL, tempRoot, creds, false, false, "")
148+
gitC, err = git.NewClientExt(wbc.GitRepo, tempRoot, creds, false, false, "")
149149
if err != nil {
150150
return err
151151
}

pkg/argocd/gitcreds.go

+9-9
Original file line numberDiff line numberDiff line change
@@ -14,39 +14,39 @@ import (
1414
)
1515

1616
// getGitCredsSource returns git credentials source that loads credentials from the secret or from Argo CD settings
17-
func getGitCredsSource(creds string, kubeClient *kube.KubernetesClient) (GitCredsSource, error) {
17+
func getGitCredsSource(creds string, kubeClient *kube.KubernetesClient, wbc *WriteBackConfig) (GitCredsSource, error) {
1818
switch {
1919
case creds == "repocreds":
2020
return func(app *v1alpha1.Application) (git.Creds, error) {
21-
return getCredsFromArgoCD(app, kubeClient)
21+
return getCredsFromArgoCD(wbc, kubeClient)
2222
}, nil
2323
case strings.HasPrefix(creds, "secret:"):
2424
return func(app *v1alpha1.Application) (git.Creds, error) {
25-
return getCredsFromSecret(app, creds[len("secret:"):], kubeClient)
25+
return getCredsFromSecret(wbc, creds[len("secret:"):], kubeClient)
2626
}, nil
2727
}
2828
return nil, fmt.Errorf("unexpected credentials format. Expected 'repocreds' or 'secret:<namespace>/<secret>' but got '%s'", creds)
2929
}
3030

3131
// getCredsFromArgoCD loads repository credentials from Argo CD settings
32-
func getCredsFromArgoCD(app *v1alpha1.Application, kubeClient *kube.KubernetesClient) (git.Creds, error) {
32+
func getCredsFromArgoCD(wbc *WriteBackConfig, kubeClient *kube.KubernetesClient) (git.Creds, error) {
3333
ctx, cancel := context.WithCancel(context.Background())
3434
defer cancel()
3535

3636
settingsMgr := settings.NewSettingsManager(ctx, kubeClient.Clientset, kubeClient.Namespace)
3737
argocdDB := db.NewDB(kubeClient.Namespace, settingsMgr, kubeClient.Clientset)
38-
repo, err := argocdDB.GetRepository(ctx, app.Spec.Source.RepoURL)
38+
repo, err := argocdDB.GetRepository(ctx, wbc.GitRepo)
3939
if err != nil {
4040
return nil, err
4141
}
4242
if !repo.HasCredentials() {
43-
return nil, fmt.Errorf("credentials for '%s' are not configured in Argo CD settings", app.Spec.Source.RepoURL)
43+
return nil, fmt.Errorf("credentials for '%s' are not configured in Argo CD settings", wbc.GitRepo)
4444
}
4545
return repo.GetGitCreds(nil), nil
4646
}
4747

4848
// getCredsFromSecret loads repository credentials from secret
49-
func getCredsFromSecret(app *v1alpha1.Application, credentialsSecret string, kubeClient *kube.KubernetesClient) (git.Creds, error) {
49+
func getCredsFromSecret(wbc *WriteBackConfig, credentialsSecret string, kubeClient *kube.KubernetesClient) (git.Creds, error) {
5050
var credentials map[string][]byte
5151
var err error
5252
s := strings.SplitN(credentialsSecret, "/", 2)
@@ -59,13 +59,13 @@ func getCredsFromSecret(app *v1alpha1.Application, credentialsSecret string, kub
5959
return nil, fmt.Errorf("secret ref must be in format 'namespace/name', but is '%s'", credentialsSecret)
6060
}
6161

62-
if ok, _ := git.IsSSHURL(app.Spec.Source.RepoURL); ok {
62+
if ok, _ := git.IsSSHURL(wbc.GitRepo); ok {
6363
var sshPrivateKey []byte
6464
if sshPrivateKey, ok = credentials["sshPrivateKey"]; !ok {
6565
return nil, fmt.Errorf("invalid secret %s: does not contain field sshPrivateKey", credentialsSecret)
6666
}
6767
return git.NewSSHCreds(string(sshPrivateKey), "", true), nil
68-
} else if git.IsHTTPSURL(app.Spec.Source.RepoURL) {
68+
} else if git.IsHTTPSURL(wbc.GitRepo) {
6969
var username, password []byte
7070
if username, ok = credentials["username"]; !ok {
7171
return nil, fmt.Errorf("invalid secret %s: does not contain field username", credentialsSecret)

pkg/argocd/update.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ type WriteBackConfig struct {
7070
GitCommitMessage string
7171
KustomizeBase string
7272
Target string
73+
GitRepo string
7374
}
7475

7576
// The following are helper structs to only marshal the fields we require
@@ -525,7 +526,12 @@ func parseGitConfig(app *v1alpha1.Application, kubeClient *kube.KubernetesClient
525526
wbc.GitWriteBranch = branches[1]
526527
}
527528
}
528-
credsSource, err := getGitCredsSource(creds, kubeClient)
529+
wbc.GitRepo = app.Spec.Source.RepoURL
530+
repo, ok := app.Annotations[common.GitRepositoryAnnotation]
531+
if ok {
532+
wbc.GitRepo = repo
533+
}
534+
credsSource, err := getGitCredsSource(creds, kubeClient, wbc)
529535
if err != nil {
530536
return fmt.Errorf("invalid git credentials source: %v", err)
531537
}
@@ -535,7 +541,7 @@ func parseGitConfig(app *v1alpha1.Application, kubeClient *kube.KubernetesClient
535541

536542
func commitChangesLocked(app *v1alpha1.Application, wbc *WriteBackConfig, state *SyncIterationState, changeList []ChangeEntry) error {
537543
if wbc.RequiresLocking() {
538-
lock := state.GetRepositoryLock(app.Spec.Source.RepoURL)
544+
lock := state.GetRepositoryLock(wbc.GitRepo)
539545
lock.Lock()
540546
defer lock.Unlock()
541547
}

pkg/argocd/update_test.go

+42
Original file line numberDiff line numberDiff line change
@@ -1718,6 +1718,48 @@ func Test_GetGitCreds(t *testing.T) {
17181718
require.Error(t, err)
17191719
require.Nil(t, creds)
17201720
})
1721+
1722+
t.Run("SSH creds from Argo CD settings with Helm Chart repoURL", func(t *testing.T) {
1723+
argoClient := argomock.ArgoCD{}
1724+
argoClient.On("UpdateSpec", mock.Anything, mock.Anything).Return(nil, nil)
1725+
secret := fixture.NewSecret("argocd-image-updater", "git-creds", map[string][]byte{
1726+
"sshPrivateKey": []byte("foo"),
1727+
})
1728+
kubeClient := kube.KubernetesClient{
1729+
Clientset: fake.NewFakeClientsetWithResources(secret),
1730+
}
1731+
1732+
app := v1alpha1.Application{
1733+
ObjectMeta: v1.ObjectMeta{
1734+
Name: "testapp",
1735+
Annotations: map[string]string{
1736+
"argocd-image-updater.argoproj.io/image-list": "nginx",
1737+
"argocd-image-updater.argoproj.io/write-back-method": "git:secret:argocd-image-updater/git-creds",
1738+
"argocd-image-updater.argoproj.io/git-repository": "[email protected]:example/example.git",
1739+
},
1740+
},
1741+
Spec: v1alpha1.ApplicationSpec{
1742+
Source: v1alpha1.ApplicationSource{
1743+
RepoURL: "https://example-helm-repo.com/example",
1744+
TargetRevision: "main",
1745+
},
1746+
},
1747+
Status: v1alpha1.ApplicationStatus{
1748+
SourceType: v1alpha1.ApplicationSourceTypeKustomize,
1749+
},
1750+
}
1751+
1752+
wbc, err := getWriteBackConfig(&app, &kubeClient, &argoClient)
1753+
require.NoError(t, err)
1754+
require.Equal(t, wbc.GitRepo, "[email protected]:example/example.git")
1755+
1756+
creds, err := wbc.GetCreds(&app)
1757+
require.NoError(t, err)
1758+
require.NotNil(t, creds)
1759+
// Must have SSH creds
1760+
_, ok := creds.(git.SSHCreds)
1761+
require.True(t, ok)
1762+
})
17211763
}
17221764

17231765
func Test_CommitUpdates(t *testing.T) {

pkg/common/constants.go

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ const (
5050
const (
5151
WriteBackMethodAnnotation = ImageUpdaterAnnotationPrefix + "/write-back-method"
5252
GitBranchAnnotation = ImageUpdaterAnnotationPrefix + "/git-branch"
53+
GitRepositoryAnnotation = ImageUpdaterAnnotationPrefix + "/git-repository"
5354
WriteBackTargetAnnotation = ImageUpdaterAnnotationPrefix + "/write-back-target"
5455
KustomizationPrefix = "kustomization"
5556
)

0 commit comments

Comments
 (0)