Skip to content

Commit 93d76f9

Browse files
authored
feat: Allow setting custom Git commit messages (#193)
* feat: Support Git commit message templates Signed-off-by: jannfis <[email protected]> * More templating Signed-off-by: jannfis <[email protected]> * Update Signed-off-by: jannfis <[email protected]> * Make TemplateCommitMessage public Signed-off-by: jannfis <[email protected]> * Update Signed-off-by: jannfis <[email protected]> * Update Signed-off-by: jannfis <[email protected]> * Introduce git.CommitOptions{} Signed-off-by: jannfis <[email protected]> * Update documentation for commit message templates Signed-off-by: jannfis <[email protected]> * Add unit tests Signed-off-by: jannfis <[email protected]> * Update manifests Signed-off-by: jannfis <[email protected]> * Fix typo in docs Signed-off-by: jannfis <[email protected]> * Fix linter issues Signed-off-by: jannfis <[email protected]> * Fix linter issues Signed-off-by: jannfis <[email protected]>
1 parent e5ced9d commit 93d76f9

File tree

12 files changed

+430
-157
lines changed

12 files changed

+430
-157
lines changed

cmd/main.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,26 @@ package main
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
7+
"io/ioutil"
68
"os"
79
"path/filepath"
810
"strings"
911
"sync"
12+
"text/template"
1013
"time"
1114

1215
"github.com/argoproj-labs/argocd-image-updater/pkg/argocd"
16+
"github.com/argoproj-labs/argocd-image-updater/pkg/common"
1317
"github.com/argoproj-labs/argocd-image-updater/pkg/env"
1418
"github.com/argoproj-labs/argocd-image-updater/pkg/health"
1519
"github.com/argoproj-labs/argocd-image-updater/pkg/image"
1620
"github.com/argoproj-labs/argocd-image-updater/pkg/kube"
1721
"github.com/argoproj-labs/argocd-image-updater/pkg/log"
1822
"github.com/argoproj-labs/argocd-image-updater/pkg/metrics"
1923
"github.com/argoproj-labs/argocd-image-updater/pkg/registry"
24+
"github.com/argoproj-labs/argocd-image-updater/pkg/tag"
2025
"github.com/argoproj-labs/argocd-image-updater/pkg/version"
2126

2227
"github.com/spf13/cobra"
@@ -31,6 +36,9 @@ const defaultArgoCDServerAddr = "argocd-server.argocd"
3136
// Default path to registry configuration
3237
const defaultRegistriesConfPath = "/app/config/registries.conf"
3338

39+
// Default path to Git commit message template
40+
const defaultCommitTemplatePath = "/app/config/commit.template"
41+
3442
const applicationsAPIKindK8S = "kubernetes"
3543
const applicationsAPIKindArgoCD = "argocd"
3644

@@ -51,6 +59,7 @@ type ImageUpdaterConfig struct {
5159
AppNamePatterns []string
5260
GitCommitUser string
5361
GitCommitMail string
62+
GitCommitMessage *template.Template
5463
DisableKubeEvents bool
5564
}
5665

@@ -155,6 +164,7 @@ func runImageUpdater(cfg *ImageUpdaterConfig, warmUp bool) (argocd.ImageUpdaterR
155164
DryRun: dryRun,
156165
GitCommitUser: cfg.GitCommitUser,
157166
GitCommitEmail: cfg.GitCommitMail,
167+
GitCommitMessage: cfg.GitCommitMessage,
158168
DisableKubeEvents: cfg.DisableKubeEvents,
159169
}
160170
res := argocd.UpdateApplication(upconf, syncState)
@@ -203,6 +213,7 @@ func newRootCommand() error {
203213
rootCmd.AddCommand(newRunCommand())
204214
rootCmd.AddCommand(newVersionCommand())
205215
rootCmd.AddCommand(newTestCommand())
216+
rootCmd.AddCommand(newTemplateCommand())
206217
err := rootCmd.Execute()
207218
return err
208219
}
@@ -231,6 +242,55 @@ func newVersionCommand() *cobra.Command {
231242
return versionCmd
232243
}
233244

245+
func newTemplateCommand() *cobra.Command {
246+
var (
247+
commitMessageTemplatePath string
248+
tplStr string
249+
)
250+
var runCmd = &cobra.Command{
251+
Use: "template [<PATH>]",
252+
Short: "Test & render a commit message template",
253+
Long: `
254+
The template command lets you validate your commit message template. It will
255+
parse the template at given PATH and execute it with a defined set of changes
256+
so that you can see how it looks like when being templated by Image Updater.
257+
258+
If PATH is not given, will show you the default message that is used.
259+
`,
260+
Run: func(cmd *cobra.Command, args []string) {
261+
var tpl *template.Template
262+
var err error
263+
if len(args) != 1 {
264+
tplStr = common.DefaultGitCommitMessage
265+
} else {
266+
commitMessageTemplatePath = args[0]
267+
tplData, err := ioutil.ReadFile(commitMessageTemplatePath)
268+
if err != nil {
269+
log.Fatalf("%v", err)
270+
}
271+
tplStr = string(tplData)
272+
}
273+
if tpl, err = template.New("commitMessage").Parse(tplStr); err != nil {
274+
log.Fatalf("could not parse commit message template: %v", err)
275+
}
276+
chL := []argocd.ChangeEntry{
277+
{
278+
Image: image.NewFromIdentifier("gcr.io/example/example:1.0.0"),
279+
OldTag: tag.NewImageTag("1.0.0", time.Now(), ""),
280+
NewTag: tag.NewImageTag("1.0.1", time.Now(), ""),
281+
},
282+
{
283+
Image: image.NewFromIdentifier("gcr.io/example/updater@sha256:f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2"),
284+
OldTag: tag.NewImageTag("", time.Now(), "sha256:01d09d19c2139a46aebfb577780d123d7396e97201bc7ead210a2ebff8239dee"),
285+
NewTag: tag.NewImageTag("", time.Now(), "sha256:7aa7a5359173d05b63cfd682e3c38487f3cb4f7f1d60659fe59fab1505977d4c"),
286+
},
287+
}
288+
fmt.Printf("%s\n", argocd.TemplateCommitMessage(tpl, "example-app", chL))
289+
},
290+
}
291+
return runCmd
292+
}
293+
234294
func newTestCommand() *cobra.Command {
235295
var (
236296
semverConstraint string
@@ -388,6 +448,8 @@ func newRunCommand() *cobra.Command {
388448
var kubeConfig string
389449
var disableKubernetes bool
390450
var warmUpCache bool = true
451+
var commitMessagePath string
452+
var commitMessageTpl string
391453
var runCmd = &cobra.Command{
392454
Use: "run",
393455
Short: "Runs the argocd-image-updater with a set of options",
@@ -414,6 +476,33 @@ func newRunCommand() *cobra.Command {
414476
getPrintableHealthPort(cfg.HealthPort),
415477
)
416478

479+
// User can specify a path to a template used for Git commit messages
480+
if commitMessagePath != "" {
481+
tpl, err := ioutil.ReadFile(commitMessagePath)
482+
if err != nil {
483+
if errors.Is(err, os.ErrNotExist) {
484+
log.Warnf("commit message template at %s does not exist, using default", commitMessagePath)
485+
commitMessageTpl = common.DefaultGitCommitMessage
486+
} else {
487+
log.Fatalf("could not read commit message template: %v", err)
488+
}
489+
} else {
490+
commitMessageTpl = string(tpl)
491+
}
492+
}
493+
494+
if commitMessageTpl == "" {
495+
log.Infof("Using default Git commit messages")
496+
commitMessageTpl = common.DefaultGitCommitMessage
497+
}
498+
499+
if tpl, err := template.New("commitMessage").Parse(commitMessageTpl); err != nil {
500+
log.Fatalf("could not parse commit message template: %v", err)
501+
} else {
502+
log.Debugf("Successfully parsed commit message template")
503+
cfg.GitCommitMessage = tpl
504+
}
505+
417506
// Load registries configuration early on. We do not consider it a fatal
418507
// error when the file does not exist, but we emit a warning.
419508
if cfg.RegistriesConf != "" {
@@ -548,6 +637,7 @@ func newRunCommand() *cobra.Command {
548637
runCmd.Flags().BoolVar(&warmUpCache, "warmup-cache", true, "whether to perform a cache warm-up on startup")
549638
runCmd.Flags().StringVar(&cfg.GitCommitUser, "git-commit-user", env.GetStringVal("GIT_COMMIT_USER", "argocd-image-updater"), "Username to use for Git commits")
550639
runCmd.Flags().StringVar(&cfg.GitCommitMail, "git-commit-email", env.GetStringVal("GIT_COMMIT_EMAIL", "[email protected]"), "E-Mail address to use for Git commits")
640+
runCmd.Flags().StringVar(&commitMessagePath, "git-commit-message-path", defaultCommitTemplatePath, "Path to a template to use for Git commit messages")
551641
runCmd.Flags().BoolVar(&cfg.DisableKubeEvents, "disable-kube-events", env.GetBoolVal("IMAGE_UPDATER_KUBE_EVENTS", false), "Disable kubernetes events")
552642

553643
return runCmd

docs/configuration/applications.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,3 +224,36 @@ as the author. You can override the author using the
224224
`--git-commit-user` and `--git-commit-email` command line switches or set
225225
`git.user` and `git.email`
226226
in the `argocd-image-updater-config` ConfigMap.
227+
228+
#### Changing the Git commit message
229+
230+
You can change the default commit message used by Argo CD Image Updater to some
231+
message that best suites your processes and regulations. For this, a simple
232+
template can be created (evaluating using the `text/template` Golang package)
233+
and made available through setting the key `git.commit-message-template` in the
234+
`argocd-image-updater-config` ConfigMap to the template's contents, e.g.
235+
236+
```yaml
237+
data:
238+
git.commit-message-template: |
239+
build: automatic update of {{ .AppName }}
240+
241+
{{ range .AppChanges -}}
242+
updates image {{ .Image }} tag '{{ .OldTag }}' to '{{ .NewTag }}'
243+
{{ end -}}
244+
```
245+
246+
Two top-level variables are provided to the template:
247+
248+
* `.AppName` is the name of the application that is being updated
249+
* `.AppChanges` is a list of changes that were performed by the update. Each
250+
entry in this list is a struct providing the following information for
251+
each change:
252+
* `.Image` holds the full name of the image that was updated
253+
* `.OldTag` holds the tag name or SHA digest previous to the update
254+
* `.NewTag` holds the tag name or SHA digest that was updated to
255+
256+
In order to test a template before configuring it for use in Image Updater,
257+
you can store the template you want to use in a temporary file, and then use
258+
the `argocd-image-updater template /path/to/file` command to render the
259+
template using pre-defined data and see its outcome on the terminal.

ext/git/client.go

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,18 @@ type Refs struct {
4545
// heads and remotes are also refs, but are not needed at this time.
4646
}
4747

48+
// CommitOptions holds options for a git commit operation
49+
type CommitOptions struct {
50+
// CommitMessageText holds a short commit message (-m option)
51+
CommitMessageText string
52+
// CommitMessagePath holds the path to a file to be used for the commit message (-F option)
53+
CommitMessagePath string
54+
// SigningKey holds a GnuPG key ID used to sign the commit with (-S option)
55+
SigningKey string
56+
// SignOff specifies whether to sign-off a commit (-s option)
57+
SignOff bool
58+
}
59+
4860
// Client is a generic git client interface
4961
type Client interface {
5062
Root() string
@@ -60,7 +72,7 @@ type Client interface {
6072
RevisionMetadata(revision string) (*RevisionMetadata, error)
6173
VerifyCommitSignature(string) (string, error)
6274
Branch(sourceBranch, targetBranch string) error
63-
Commit(pathSpec string, message string, signingKey string) error
75+
Commit(pathSpec string, opts *CommitOptions) error
6476
Push(remote string, branch string, force bool) error
6577
Add(path string) error
6678
SymRefToBranch(symRef string) (string, error)
@@ -522,17 +534,22 @@ func (m *nativeGitClient) VerifyCommitSignature(revision string) (string, error)
522534
// used as the commit message, otherwise a default commit message will be used.
523535
// If signingKey is not the empty string, commit will be signed with the given
524536
// GPG key.
525-
func (m *nativeGitClient) Commit(pathSpec string, message string, signingKey string) error {
537+
func (m *nativeGitClient) Commit(pathSpec string, opts *CommitOptions) error {
526538
defaultCommitMsg := "Update parameters"
527539
args := []string{"commit"}
528540
if pathSpec == "" || pathSpec == "*" {
529541
args = append(args, "-a")
530542
}
531-
if signingKey != "" {
532-
args = append(args, "-S", signingKey)
543+
if opts.SigningKey != "" {
544+
args = append(args, "-S", opts.SigningKey)
545+
}
546+
if opts.SignOff {
547+
args = append(args, "-s")
533548
}
534-
if message != "" {
535-
args = append(args, "-m", message)
549+
if opts.CommitMessageText != "" {
550+
args = append(args, "-m", opts.CommitMessageText)
551+
} else if opts.CommitMessagePath != "" {
552+
args = append(args, "-F", opts.CommitMessagePath)
536553
} else {
537554
args = append(args, "-m", defaultCommitMsg)
538555
}

ext/git/mocks/Client.go

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/git/mocks/Creds.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

manifests/base/deployment/argocd-image-updater-deployment.yaml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,14 +98,16 @@ spec:
9898
initialDelaySeconds: 3
9999
periodSeconds: 30
100100
volumeMounts:
101-
- name: registries-conf
101+
- name: image-updater-conf
102102
mountPath: /app/config
103103
serviceAccountName: argocd-image-updater
104104
volumes:
105-
- name: registries-conf
105+
- name: image-updater-conf
106106
configMap:
107107
name: argocd-image-updater-config
108108
optional: true
109109
items:
110110
- key: registries.conf
111111
path: registries.conf
112+
- key: git.commit-message-template
113+
path: commit.template

manifests/install.yaml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,13 +174,15 @@ spec:
174174
periodSeconds: 30
175175
volumeMounts:
176176
- mountPath: /app/config
177-
name: registries-conf
177+
name: image-updater-conf
178178
serviceAccountName: argocd-image-updater
179179
volumes:
180180
- configMap:
181181
items:
182182
- key: registries.conf
183183
path: registries.conf
184+
- key: git.commit-message-template
185+
path: commit.template
184186
name: argocd-image-updater-config
185187
optional: true
186-
name: registries-conf
188+
name: image-updater-conf

0 commit comments

Comments
 (0)