diff --git a/docs/advanced-usage/registry-management.md b/docs/advanced-usage/registry-management.md index b749246b7..808b1390e 100644 --- a/docs/advanced-usage/registry-management.md +++ b/docs/advanced-usage/registry-management.md @@ -102,6 +102,16 @@ Setting the property value to an empty string will reset the value to the system dokku registry:set node-js-app image-repo ``` +### Templating the image repository name + +Instead of setting the image repository name on a per-app basis, it can be set via a template globally with the `image-repo-template` property: + +```shell +dokku registry:set --global image-repo-template "my-awesome-prefix/{{ .AppName }}" +``` + +Dokku uses a Golang template and has access to the `AppName` variable as shown above. + ### Pushing images on build To push the image on release, set the `push-on-release` property to `true` via the `registry:set` command. The default value for this property is `false`. Setting the property to `true` will result in the image being tagged with an ID that is incremented with every release. This tag will be what is used for running app code. diff --git a/plugins/registry/functions.go b/plugins/registry/functions.go index e95c89acd..d5cd64c1d 100644 --- a/plugins/registry/functions.go +++ b/plugins/registry/functions.go @@ -1,16 +1,42 @@ package registry import ( + "bytes" "errors" "fmt" "os" "strconv" "strings" + "text/template" "github.com/codeskyblue/go-sh" "github.com/dokku/dokku/plugins/common" ) +func getImageRepoFromTemplate(appName string) (string, error) { + imageRepoTemplate := common.PropertyGet("registry", "--global", "image-repo-template") + if imageRepoTemplate == "" { + return "", nil + } + + tmpl, err := template.New("template").Parse(imageRepoTemplate) + if err != nil { + return "", fmt.Errorf("Unable to parse image-repo-template: %w", err) + } + + type templateData struct { + AppName string + } + data := templateData{AppName: appName} + + var doc bytes.Buffer + if err := tmpl.Execute(&doc, data); err != nil { + return "", fmt.Errorf("Unable to execute image-repo-template: %w", err) + } + + return strings.TrimSpace(doc.String()), nil +} + func getRegistryServerForApp(appName string) string { value := common.PropertyGet("registry", appName, "server") if value == "" { diff --git a/plugins/registry/registry.go b/plugins/registry/registry.go index 9472faefb..abea76773 100644 --- a/plugins/registry/registry.go +++ b/plugins/registry/registry.go @@ -10,7 +10,8 @@ var ( // GlobalProperties is a map of all valid global registry properties GlobalProperties = map[string]bool{ - "push-on-release": true, - "server": true, + "image-repo-template": true, + "push-on-release": true, + "server": true, } ) diff --git a/plugins/registry/report.go b/plugins/registry/report.go index 80a3693b7..710719f32 100644 --- a/plugins/registry/report.go +++ b/plugins/registry/report.go @@ -13,15 +13,16 @@ func ReportSingleApp(appName string, format string, infoFlag string) error { } flags := map[string]common.ReportFunc{ - "--registry-computed-image-repo": reportComputedImageRepo, - "--registry-image-repo": reportImageRepo, - "--registry-computed-push-on-release": reportComputedPushOnRelease, - "--registry-global-push-on-release": reportGlobalPushOnRelease, - "--registry-push-on-release": reportPushOnRelease, - "--registry-computed-server": reportComputedServer, - "--registry-global-server": reportGlobalServer, - "--registry-server": reportServer, - "--registry-tag-version": reportTagVersion, + "--registry-computed-image-repo": reportComputedImageRepo, + "--registry-image-repo": reportImageRepo, + "--registry-computed-push-on-release": reportComputedPushOnRelease, + "--registry-global-push-on-release": reportGlobalPushOnRelease, + "--registry-push-on-release": reportPushOnRelease, + "--registry-computed-server": reportComputedServer, + "--registry-global-server": reportGlobalServer, + "--registry-global-image-repo-template": reportGlobalImageRepoTemplate, + "--registry-server": reportServer, + "--registry-tag-version": reportTagVersion, } flagKeys := []string{} @@ -36,8 +37,11 @@ func ReportSingleApp(appName string, format string, infoFlag string) error { } func reportComputedImageRepo(appName string) string { - imageRepo := reportImageRepo(appName) - imageRepo = strings.TrimSpace(imageRepo) + imageRepo := strings.TrimSpace(reportImageRepo(appName)) + if imageRepo == "" { + imageRepo, _ = getImageRepoFromTemplate(appName) + } + if imageRepo == "" { imageRepo = common.GetAppImageRepo(appName) } @@ -76,6 +80,10 @@ func reportComputedServer(appName string) string { return strings.TrimSpace(server) } +func reportGlobalImageRepoTemplate(appName string) string { + return common.PropertyGet("registry", "--global", "image-repo-template") +} + func reportGlobalServer(appName string) string { return common.PropertyGet("registry", "--global", "server") } diff --git a/plugins/registry/triggers.go b/plugins/registry/triggers.go index 172b0a239..fa8cb5f07 100644 --- a/plugins/registry/triggers.go +++ b/plugins/registry/triggers.go @@ -10,8 +10,15 @@ import ( // TriggerDeployedAppImageRepo outputs the associated image repo to stdout func TriggerDeployedAppImageRepo(appName string) error { - imageRepo := common.PropertyGet("registry", appName, "image-repo") - imageRepo = strings.TrimSpace(imageRepo) + imageRepo := strings.TrimSpace(reportImageRepo(appName)) + if imageRepo == "" { + var err error + imageRepo, err = getImageRepoFromTemplate(appName) + if err != nil { + return fmt.Errorf("Unable to determine image repo from template: %w", err) + } + } + if imageRepo == "" { imageRepo = common.GetAppImageRepo(appName) }