Merge branch 'master' into cn

* master: (427 commits)
  chore(deps): bump gunicorn from 25.0.2 to 25.1.0 in /tests/apps/multi
  chore(deps): bump flask from 3.1.2 to 3.1.3 in /tests/apps/multi
  chore(deps): bump python in /docs/_build
  chore(deps): bump google.golang.org/grpc in /tests/apps/gogrpc
  chore(deps): bump qs from 6.14.1 to 6.14.2 in /tests/apps/checks-root
  chore(deps): bump rack from 3.2.4 to 3.2.5 in /tests/apps/ruby
  fix: call correct function for limiting letsencrypt to certain domains
  chore(deps): bump gunicorn in /tests/apps/python-flask
  chore(deps): bump whitenoise in /tests/apps/dockerfile-release
  chore(deps): bump phusion/baseimage from noble-1.0.2 to noble-1.0.3
  chore(deps): bump actions/upload-artifact from 6 to 7
  chore(deps): bump actions/download-artifact from 7 to 8
  chore(deps): bump github.com/traefik/traefik/v2
  chore(deps): bump gunicorn in /tests/apps/dockerfile-release
  chore(deps): bump flask from 3.1.2 to 3.1.3 in /tests/apps/python-flask
  chore(deps): bump traefik from 3.6.7 to 3.6.9 in /plugins/traefik-vhosts
  chore(deps): bump mkdocs-material from 9.7.1 to 9.7.3 in /docs/_build
  chore(deps): bump byjg/easy-haproxy in /plugins/haproxy-vhosts
  chore(deps): bump dj-database-url in /tests/apps/dockerfile-release
  chore(deps): bump werkzeug in /tests/apps/python-flask
  ...

# Conflicts:
#	common.mk
#	contrib/dependencies.json
This commit is contained in:
apple
2026-03-02 16:41:58 +08:00
416 changed files with 10609 additions and 2298 deletions

View File

@@ -1,4 +1,4 @@
[plugin]
description = "dokku core standard plugin"
version = "0.36.8"
version = "0.37.6"
[plugin.config]

View File

@@ -1,4 +1,4 @@
[plugin]
description = "dokku core events logging plugin"
version = "0.36.8"
version = "0.37.6"
[plugin.config]

View File

@@ -8,6 +8,7 @@ import (
"strings"
"github.com/dokku/dokku/plugins/common"
"github.com/tailscale/hujson"
"k8s.io/utils/ptr"
)
@@ -25,8 +26,8 @@ var (
// AppJSON is a struct that represents an app.json file as understood by Dokku
type AppJSON struct {
// Cron is a list of cron commands to execute
Cron []CronCommand `json:"cron"`
// Cron is a list of cron tasks to execute
Cron []CronTask `json:"cron"`
// Formation is a map of process types to scale
Formation map[string]Formation `json:"formation"`
@@ -50,13 +51,19 @@ type AppJSON struct {
} `json:"scripts"`
}
// CronCommand is a struct that represents a single cron command from an app.json file
type CronCommand struct {
// CronTask is a struct that represents a single cron task from an app.json file
type CronTask struct {
// Command is the command to execute
Command string `json:"command"`
// Maintenance is whether or not the cron task is in maintenance mode
Maintenance bool `json:"maintenance"`
// Schedule is the cron schedule to execute the command on
Schedule string `json:"schedule"`
// ConcurrencyPolicy is the concurrency policy for the cron command
ConcurrencyPolicy string `json:"concurrency_policy"`
}
// Formation is a struct that represents the scale for a process from an app.json file
@@ -69,6 +76,16 @@ type Formation struct {
// MaxParallel is the maximum number of processes to start in parallel
MaxParallel *int `json:"max_parallel"`
// Service is a struct that represents how to expose the process to the network
// This only applies to non-web processes
Service *FormationService `json:"service"`
}
// FormationService is a struct that represents how to expose a process to the network
type FormationService struct {
// Exposed is whether or not the process is exposed as a service
Exposed bool `json:"exposed"`
}
// FormationAutoscaling is a struct that represents the autoscaling configuration for a process from an app.json file
@@ -256,8 +273,14 @@ func ReadAppJSON(path string) (AppJSON, error) {
return AppJSON{}, nil
}
ast, err := hujson.Parse(b)
if err != nil {
return AppJSON{}, fmt.Errorf("Cannot parse app.json as jsonc: %v", err)
}
ast.Standardize()
var appJSON AppJSON
if err = json.Unmarshal(b, &appJSON); err != nil {
if err = json.Unmarshal(ast.Pack(), &appJSON); err != nil {
return AppJSON{}, fmt.Errorf("Cannot parse app.json: %v", err)
}

View File

@@ -133,11 +133,7 @@ func cleanupDeploymentContainer(containerID string, phase string) error {
}
func executeScript(appName string, image string, imageTag string, phase string) error {
phaseName := phase
if phase == "heroku.postdeploy" {
phaseName = "first deploy postdeploy"
}
common.LogInfo1(fmt.Sprintf("Checking for %s task", phaseName))
common.LogInfo1(fmt.Sprintf("Checking for %s task", phase))
command := ""
phaseSource := ""
if phase == "release" {
@@ -152,14 +148,14 @@ func executeScript(appName string, image string, imageTag string, phase string)
}
if command == "" {
common.LogVerbose(fmt.Sprintf("No %s task found, skipping", phaseName))
common.LogVerbose(fmt.Sprintf("No %s task found, skipping", phase))
return nil
}
if phase == "predeploy" {
common.LogVerbose(fmt.Sprintf("Executing %s task from %s: %s", phaseName, phaseSource, command))
common.LogVerbose(fmt.Sprintf("Executing %s task from %s: %s", phase, phaseSource, command))
} else {
common.LogVerbose(fmt.Sprintf("Executing %s task from %s in ephemeral container: %s", phaseName, phaseSource, command))
common.LogVerbose(fmt.Sprintf("Executing %s task from %s in ephemeral container: %s", phase, phaseSource, command))
}
isHerokuishImage := common.IsImageHerokuishBased(image, appName)
@@ -271,15 +267,15 @@ func executeScript(appName string, image string, imageTag string, phase string)
defer cleanupDeploymentContainer(containerID, phase)
if !waitForExecution(containerID) {
common.LogInfo2Quiet(fmt.Sprintf("Start of %s %s task (%s) output", appName, phaseName, containerID[0:9]))
common.LogInfo2Quiet(fmt.Sprintf("Start of %s %s task (%s) output", appName, phase, containerID[0:9]))
common.LogVerboseQuietContainerLogs(containerID)
common.LogInfo2Quiet(fmt.Sprintf("End of %s %s task (%s) output", appName, phaseName, containerID[0:9]))
return fmt.Errorf("Execution of %s task failed: %s", phaseName, command)
common.LogInfo2Quiet(fmt.Sprintf("End of %s %s task (%s) output", appName, phase, containerID[0:9]))
return fmt.Errorf("Execution of %s task failed: %s", phase, command)
}
common.LogInfo2Quiet(fmt.Sprintf("Start of %s %s task (%s) output", appName, phaseName, containerID[0:9]))
common.LogInfo2Quiet(fmt.Sprintf("Start of %s %s task (%s) output", appName, phase, containerID[0:9]))
common.LogVerboseQuietContainerLogs(containerID)
common.LogInfo2Quiet(fmt.Sprintf("End of %s %s task (%s) output", appName, phaseName, containerID[0:9]))
common.LogInfo2Quiet(fmt.Sprintf("End of %s %s task (%s) output", appName, phase, containerID[0:9]))
if phase != "predeploy" {
return nil

View File

@@ -1,11 +1,12 @@
module github.com/dokku/dokku/plugins/app-json
go 1.25.1
go 1.25.5
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/spf13/pflag v1.0.10
github.com/tailscale/hujson v0.0.0-20250605163823-992244df8c5a
k8s.io/utils v0.0.0-20240102154912-e7106e64919e
)
@@ -23,9 +24,10 @@ require (
github.com/pkg/errors v0.9.1 // indirect
github.com/pkg/sftp v1.13.5 // indirect
github.com/ryanuber/columnize v2.1.2+incompatible // indirect
golang.org/x/crypto v0.43.0 // indirect
golang.org/x/sync v0.17.0 // indirect
golang.org/x/sys v0.37.0 // indirect
github.com/stretchr/testify v1.8.4 // indirect
golang.org/x/crypto v0.46.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.39.0 // indirect
)
replace github.com/dokku/dokku/plugins/common => ../common

View File

@@ -22,8 +22,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/melbahja/goph v1.4.0 h1:z0PgDbBFe66lRYl3v5dGb9aFgPy0kotuQ37QOwSQFqs=
github.com/melbahja/goph v1.4.0/go.mod h1:uG+VfK2Dlhk+O32zFrRlc3kYKTlV6+BtvPWd/kK7U68=
github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k=
github.com/onsi/gomega v1.39.0 h1:y2ROC3hKFmQZJNFeGAMeHZKkjBL65mIZcvrLQBF9k6Q=
github.com/onsi/gomega v1.39.0/go.mod h1:ZCU1pkQcXDO5Sl9/VVEGlDyp+zm0m1cmeG5TOzLgdh4=
github.com/otiai10/copy v1.14.1 h1:5/7E6qsUMBaH5AnQ0sSLzzTg1oTECmcCmT6lvF45Na8=
github.com/otiai10/copy v1.14.1/go.mod h1:oQwrEDDOci3IM8dJF0d8+jnbfPDllW6vUjNc3DoZm9I=
github.com/otiai10/mint v1.6.3 h1:87qsV/aw1F5as1eH1zS/yqHY85ANKVMgkDrf9rcxbQs=
@@ -39,8 +39,11 @@ github.com/ryanuber/columnize v2.1.2+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFo
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/tailscale/hujson v0.0.0-20250605163823-992244df8c5a h1:a6TNDN9CgG+cYjaeN8l2mc4kSz2iMiCDQxPEyltUV/I=
github.com/tailscale/hujson v0.0.0-20250605163823-992244df8c5a/go.mod h1:EbW0wDK/qEUYI0A5bqq0C2kF8JTQwWONmGDBbzsxxHo=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
@@ -48,20 +51,20 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM=
golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -72,20 +75,20 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=

View File

@@ -1,4 +1,4 @@
[plugin]
description = "dokku core app-json plugin"
version = "0.36.8"
version = "0.37.6"
[plugin.config]

View File

@@ -1,9 +1,9 @@
package appjson
import (
"encoding/json"
"errors"
"fmt"
"os"
"strings"
"github.com/dokku/dokku/plugins/common"
@@ -42,18 +42,17 @@ func TriggerAppJSONGetContent(appName string) error {
return nil
}
b, err := os.ReadFile(getProcessSpecificAppJSONPath(appName))
appJSON, err := ReadAppJSON(getProcessSpecificAppJSONPath(appName))
if err != nil {
return fmt.Errorf("Cannot read app.json file: %v", err)
return err
}
content := strings.TrimSpace(string(b))
if content == "" {
fmt.Print("{}")
return nil
content, err := json.Marshal(appJSON)
if err != nil {
return err
}
fmt.Print(content)
fmt.Print(string(content))
return nil
}

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/apps
go 1.25.1
go 1.25.5
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000
@@ -21,9 +21,9 @@ require (
github.com/pkg/errors v0.9.1 // indirect
github.com/pkg/sftp v1.13.5 // indirect
github.com/ryanuber/columnize v2.1.2+incompatible // indirect
golang.org/x/crypto v0.43.0 // indirect
golang.org/x/sync v0.17.0 // indirect
golang.org/x/sys v0.37.0 // indirect
golang.org/x/crypto v0.46.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.39.0 // indirect
)
replace github.com/dokku/dokku/plugins/common => ../common

View File

@@ -19,8 +19,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/melbahja/goph v1.4.0 h1:z0PgDbBFe66lRYl3v5dGb9aFgPy0kotuQ37QOwSQFqs=
github.com/melbahja/goph v1.4.0/go.mod h1:uG+VfK2Dlhk+O32zFrRlc3kYKTlV6+BtvPWd/kK7U68=
github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k=
github.com/onsi/gomega v1.39.0 h1:y2ROC3hKFmQZJNFeGAMeHZKkjBL65mIZcvrLQBF9k6Q=
github.com/onsi/gomega v1.39.0/go.mod h1:ZCU1pkQcXDO5Sl9/VVEGlDyp+zm0m1cmeG5TOzLgdh4=
github.com/otiai10/copy v1.14.1 h1:5/7E6qsUMBaH5AnQ0sSLzzTg1oTECmcCmT6lvF45Na8=
github.com/otiai10/copy v1.14.1/go.mod h1:oQwrEDDOci3IM8dJF0d8+jnbfPDllW6vUjNc3DoZm9I=
github.com/otiai10/mint v1.6.3 h1:87qsV/aw1F5as1eH1zS/yqHY85ANKVMgkDrf9rcxbQs=
@@ -45,20 +45,20 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM=
golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -69,20 +69,20 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=

View File

@@ -1,4 +1,4 @@
[plugin]
description = "dokku core apps plugin"
version = "0.36.8"
version = "0.37.6"
[plugin.config]

View File

@@ -1,6 +1,7 @@
package apps
import (
"errors"
"fmt"
"os"
"time"
@@ -48,7 +49,7 @@ func TriggerInstall() error {
}
apps, err := common.UnfilteredDokkuApps()
if err != nil {
if err != nil && !errors.Is(err, common.NoAppsExist) {
return nil
}

View File

@@ -17,9 +17,7 @@ trigger-builder-dockerfile-builder-build() {
dokku_log_info1 "Building $APP from Dockerfile"
local IMAGE=$(get_app_image_name "$APP")
local DOKKU_DOCKERFILE_CACHE_BUILD=$(config_get "$APP" "DOKKU_DOCKERFILE_CACHE_BUILD")
local DOKKU_DOCKER_BUILD_OPTS=$(config_get "$APP" "DOKKU_DOCKER_BUILD_OPTS")
local DOCKER_BUILD_LABEL_ARGS=("--label=dokku" "--label=org.label-schema.schema-version=1.0" "--label=org.label-schema.vendor=dokku" "--label=com.dokku.image-stage=build" "--label=com.dokku.builder-type=dockerfile" "--label=com.dokku.app-name=$APP")
local DOCKER_BUILD_LABEL_ARGS=("--label=org.label-schema.schema-version=1.0" "--label=org.label-schema.vendor=dokku" "--label=com.dokku.image-stage=build" "--label=com.dokku.builder-type=dockerfile" "--label=com.dokku.app-name=$APP" "--label=dokku")
pushd "$SOURCECODE_WORK_DIR" &>/dev/null
@@ -34,17 +32,224 @@ trigger-builder-dockerfile-builder-build() {
fi
plugn trigger pre-build "$BUILDER_TYPE" "$APP" "$SOURCECODE_WORK_DIR"
[[ "$DOKKU_DOCKERFILE_CACHE_BUILD" == "false" ]] && DOKKU_DOCKER_BUILD_OPTS="$DOKKU_DOCKER_BUILD_OPTS --no-cache"
local DOCKER_ARGS=$(: | plugn trigger docker-args-build "$APP" "$BUILDER_TYPE")
DOCKER_ARGS+=$(: | plugn trigger docker-args-process-build "$APP" "$BUILDER_TYPE")
DOCKER_ARGS+=" $DOKKU_GLOBAL_BUILD_ARGS"
# strip --link, --volume and -v args from DOCKER_ARGS
local DOCKER_ARGS=$(sed -e "s/^--link=[[:graph:]]\+[[:blank:]]\?//g" -e "s/^--link[[:blank:]]\?[[:graph:]]\+[[:blank:]]\?//g" -e "s/^--volume=[[:graph:]]\+[[:blank:]]\?//g" -e "s/^--volume[[:blank:]]\?[[:graph:]]\+[[:blank:]]\?//g" -e "s/^-v[[:blank:]]\?[[:graph:]]\+[[:blank:]]\?//g" <<<"$DOCKER_ARGS")
declare -a ARG_ARRAY
eval "ARG_ARRAY=($DOCKER_ARGS)"
DOCKER_ARGS=" $DOCKER_ARGS "
eval set -- "$DOCKER_ARGS"
declare -a DOCKERFILE_ARGS
while true; do
case "$1" in
--add-host)
DOCKERFILE_ARGS+=("--add-host")
DOCKERFILE_ARGS+=("$2")
shift 2
;;
--add-host=*)
DOCKERFILE_ARGS+=("--add-host" "${1#--add-host=}")
shift 1
;;
--allow)
DOCKERFILE_ARGS+=("--allow")
DOCKERFILE_ARGS+=("$2")
shift 2
;;
--allow=*)
DOCKERFILE_ARGS+=("--allow" "${1#--allow=}")
shift 1
;;
--annotation)
DOCKERFILE_ARGS+=("--annotation")
DOCKERFILE_ARGS+=("$2")
shift 2
;;
--annotation=*)
DOCKERFILE_ARGS+=("--annotation" "${1#--annotation=}")
shift 1
;;
--attest)
DOCKERFILE_ARGS+=("--attest")
DOCKERFILE_ARGS+=("$2")
shift 2
;;
--attest=*)
DOCKERFILE_ARGS+=("--attest" "${1#--attest=}")
shift 1
;;
--build-arg)
DOCKERFILE_ARGS+=("--build-arg")
DOCKERFILE_ARGS+=("$2")
shift 2
;;
--build-arg=*)
DOCKERFILE_ARGS+=("--build-arg" "${1#--build-arg=}")
shift 1
;;
--builder)
DOCKERFILE_ARGS+=("--builder")
DOCKERFILE_ARGS+=("$2")
shift 2
;;
--builder=*)
DOCKERFILE_ARGS+=("--builder" "${1#--builder=}")
shift 1
;;
--cache-from)
DOCKERFILE_ARGS+=("--cache-from")
DOCKERFILE_ARGS+=("$2")
shift 2
;;
--cache-from=*)
DOCKERFILE_ARGS+=("--cache-from" "${1#--cache-from=}")
shift 1
;;
--cache-to)
DOCKERFILE_ARGS+=("--cache-to")
DOCKERFILE_ARGS+=("$2")
shift 2
;;
--cache-to=*)
DOCKERFILE_ARGS+=("--cache-to" "${1#--cache-to=}")
shift 1
;;
--call)
DOCKERFILE_ARGS+=("--call")
DOCKERFILE_ARGS+=("$2")
shift 2
;;
--call=*)
DOCKERFILE_ARGS+=("--call" "${1#--call=}")
shift 1
;;
--cgroup-parent)
DOCKERFILE_ARGS+=("--cgroup-parent")
DOCKERFILE_ARGS+=("$2")
shift 2
;;
--cgroup-parent=*)
DOCKERFILE_ARGS+=("--cgroup-parent" "${1#--cgroup-parent=}")
shift 1
;;
--label)
DOCKERFILE_ARGS+=("--label")
DOCKERFILE_ARGS+=("$2")
shift 2
;;
--label=*)
DOCKERFILE_ARGS+=("--label" "${1#--label=}")
shift 1
;;
--network)
DOCKERFILE_ARGS+=("--network")
DOCKERFILE_ARGS+=("$2")
shift 2
;;
--network=*)
DOCKERFILE_ARGS+=("--network" "${1#--network=}")
shift 1
;;
--platform)
DOCKERFILE_ARGS+=("--platform")
DOCKERFILE_ARGS+=("$2")
shift 2
;;
--platform=*)
DOCKERFILE_ARGS+=("--platform" "${1#--platform=}")
shift 1
;;
--progress)
DOCKERFILE_ARGS+=("--progress")
DOCKERFILE_ARGS+=("$2")
shift 2
;;
--progress=*)
DOCKERFILE_ARGS+=("--progress" "${1#--progress=}")
shift 1
;;
--provenance)
DOCKERFILE_ARGS+=("--provenance")
DOCKERFILE_ARGS+=("$2")
shift 2
;;
--provenance=*)
DOCKERFILE_ARGS+=("--provenance" "${1#--provenance=}")
shift 1
;;
--sbom)
DOCKERFILE_ARGS+=("--sbom")
DOCKERFILE_ARGS+=("$2")
shift 2
;;
--sbom=*)
DOCKERFILE_ARGS+=("--sbom" "${1#--sbom=}")
shift 1
;;
--secret)
DOCKERFILE_ARGS+=("--secret")
DOCKERFILE_ARGS+=("$2")
shift 2
;;
--secret=*)
DOCKERFILE_ARGS+=("--secret" "${1#--secret=}")
shift 1
;;
--shm-size)
DOCKERFILE_ARGS+=("--shm-size")
DOCKERFILE_ARGS+=("$2")
shift 2
;;
--shm-size=*)
DOCKERFILE_ARGS+=("--shm-size" "${1#--shm-size=}")
shift 1
;;
--ssh)
DOCKERFILE_ARGS+=("--platform")
DOCKERFILE_ARGS+=("$2")
shift 2
;;
--ssh=*)
DOCKERFILE_ARGS+=("--ssh" "${1#--ssh=}")
shift 1
;;
--target)
DOCKERFILE_ARGS+=("--target")
DOCKERFILE_ARGS+=("$2")
shift 2
;;
--target=*)
DOCKERFILE_ARGS+=("--target" "${1#--target=}")
shift 1
;;
--ulimit)
DOCKERFILE_ARGS+=("--tag")
DOCKERFILE_ARGS+=("$2")
shift 2
;;
--tag=*)
DOCKERFILE_ARGS+=("--tag" "${1#--tag=}")
shift 1
;;
--check | -D | --debug | --no-cache)
DOCKERFILE_ARGS+=("$1")
shift 1
;;
*)
if [[ -n "$1" ]]; then
shift
continue
fi
break
;;
esac
done
eval "$(config_export app "$APP")"
"$DOCKER_BIN" image build "${DOCKER_BUILD_LABEL_ARGS[@]}" $DOKKU_GLOBAL_BUILD_ARGS "${ARG_ARRAY[@]}" ${DOKKU_DOCKER_BUILD_OPTS} -t $IMAGE .
local DOCKER_CONFIG
DOCKER_CONFIG="$(fn-registry-docker-config-dir "$APP")"
[[ -n "$DOCKER_CONFIG" ]] && export DOCKER_CONFIG
"$DOCKER_BIN" image build "${DOCKER_BUILD_LABEL_ARGS[@]}" "${DOCKERFILE_ARGS[@]}" --tag $IMAGE .
plugn trigger ports-set-detected "$APP" "$(fn-builder-dockerfile-get-detect-port-map "$APP" "$IMAGE" "$SOURCECODE_WORK_DIR/Dockerfile")"
if fn-plugn-trigger-exists "post-build-dockerfile"; then

View File

@@ -29,6 +29,9 @@ trigger-builder-dockerfile-builder-release() {
DOCKER_BUILD_ARGS+=("--platform=linux/amd64")
fi
local DOCKER_CONFIG
DOCKER_CONFIG="$(fn-registry-docker-config-dir "$APP")"
[[ -n "$DOCKER_CONFIG" ]] && export DOCKER_CONFIG
if ! suppress_output "$DOCKER_BIN" image build "${DOCKER_BUILD_ARGS[@]}" $DOKKU_GLOBAL_BUILD_ARGS -f "$PLUGIN_AVAILABLE_PATH/builder-dockerfile/dockerfiles/builder-release.Dockerfile" --build-arg APP_IMAGE="$IMAGE" -t "$IMAGE" "$TMP_WORK_DIR"; then
dokku_log_warn "Failure injecting docker labels on image"
return 1

View File

@@ -1,4 +1,4 @@
[plugin]
description = "dokku core builder-dockerfile plugin"
version = "0.36.8"
version = "0.37.6"
[plugin.config]

View File

@@ -1,6 +1,7 @@
#!/usr/bin/env bash
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
source "$PLUGIN_AVAILABLE_PATH/config/functions"
fn-builder-herokuish-ensure-cache() {
@@ -45,7 +46,10 @@ trigger-builder-herokuish-builder-build() {
NEW_DOKKU_IMAGE=$(plugn trigger builder-dokku-image "$BUILDER_TYPE" "$APP" "$SOURCECODE_WORK_DIR" "$DOKKU_IMAGE")
[[ -n "$NEW_DOKKU_IMAGE" ]] && DOKKU_IMAGE="$NEW_DOKKU_IMAGE"
local DOCKER_BUILD_LABEL_ARGS="--label=org.label-schema.schema-version=1.0 --label=org.label-schema.vendor=dokku --label=com.dokku.app-name=$APP"
local DOCKER_BUILD_LABEL_ARGS=("--label=org.label-schema.schema-version=1.0" "--label=org.label-schema.vendor=dokku" "--label=com.dokku.image-stage=build" "--label=com.dokku.builder-type=herokuish" "--label=com.dokku.app-name=$APP" "--label=dokku")
local DOCKER_CONFIG
DOCKER_CONFIG="$(fn-registry-docker-config-dir "$APP")"
[[ -n "$DOCKER_CONFIG" ]] && export DOCKER_CONFIG
DOKKU_APP_USER=$(config_get "$APP" DOKKU_APP_USER || true)
DOKKU_APP_USER=${DOKKU_APP_USER:="herokuishuser"}
if ! suppress_output "$DOCKER_BIN" image build "${DOCKER_BUILD_LABEL_ARGS[@]}" $DOKKU_GLOBAL_BUILD_ARGS -f "$PLUGIN_AVAILABLE_PATH/builder-herokuish/dockerfiles/copy-source.Dockerfile" --build-arg APP_IMAGE="$DOKKU_IMAGE" --build-arg "DOKKU_APP_USER=$DOKKU_APP_USER" --build-arg "TRACE=$DOKKU_TRACE" -t $IMAGE "$SOURCECODE_WORK_DIR"; then
@@ -61,7 +65,10 @@ trigger-builder-herokuish-builder-build() {
plugn trigger pre-build "$BUILDER_TYPE" "$APP" "$SOURCECODE_WORK_DIR"
local DOCKER_ARGS=$(: | plugn trigger docker-args-build "$APP" "$BUILDER_TYPE")
[[ "$DOKKU_TRACE" ]] && DOCKER_ARGS+=" --env=TRACE=true "
if [[ -n "$DOKKU_TRACE" ]]; then
DOCKER_ARGS+=" --env=TRACE=true "
DOCKER_ARGS+=" --env=BUILDPACK_XTRACE=1 "
fi
DOCKER_ARGS+=$(: | plugn trigger docker-args-process-build "$APP" "$BUILDER_TYPE")
declare -a ARG_ARRAY

View File

@@ -30,6 +30,10 @@ trigger-builder-herokuish-builder-release() {
DOKKU_APP_USER=$(config_get "$APP" DOKKU_APP_USER || true)
DOKKU_APP_USER=${DOKKU_APP_USER:="herokuishuser"}
local DOCKER_CONFIG
DOCKER_CONFIG="$(fn-registry-docker-config-dir "$APP")"
[[ -n "$DOCKER_CONFIG" ]] && export DOCKER_CONFIG
if ! suppress_output "$DOCKER_BIN" image build "${DOCKER_BUILD_ARGS[@]}" $DOKKU_GLOBAL_BUILD_ARGS -f "$PLUGIN_AVAILABLE_PATH/builder-herokuish/dockerfiles/builder-pre-release.Dockerfile" --build-arg APP_IMAGE="$IMAGE" --build-arg "DOKKU_APP_USER=$DOKKU_APP_USER" -t "$IMAGE" "$TMP_WORK_DIR"; then
dokku_log_warn "Failure injecting environment variables"
return 1

View File

@@ -1,4 +1,4 @@
[plugin]
description = "dokku core builder-herokuish plugin"
version = "0.36.8"
version = "0.37.6"
[plugin.config]

View File

@@ -14,7 +14,7 @@ trigger-builder-herokuish-pre-build-buildpack() {
return
fi
local DOCKER_BUILD_LABEL_ARGS="--label=org.label-schema.schema-version=1.0 --label=org.label-schema.vendor=dokku --label=com.dokku.app-name=$APP"
local DOCKER_BUILD_LABEL_ARGS=("--label=org.label-schema.schema-version=1.0" "--label=org.label-schema.vendor=dokku" "--label=com.dokku.image-stage=build" "--label=com.dokku.builder-type=herokuish" "--label=com.dokku.app-name=$APP" "--label=dokku")
IMAGE=$(get_app_image_name "$APP")
@@ -41,6 +41,9 @@ trigger-builder-herokuish-pre-build-buildpack() {
DOKKU_APP_USER=$(config_get "$APP" DOKKU_APP_USER || true)
DOKKU_APP_USER=${DOKKU_APP_USER:="herokuishuser"}
local DOCKER_CONFIG
DOCKER_CONFIG="$(fn-registry-docker-config-dir "$APP")"
[[ -n "$DOCKER_CONFIG" ]] && export DOCKER_CONFIG
if ! suppress_output "$DOCKER_BIN" image build "${DOCKER_BUILD_LABEL_ARGS[@]}" $DOKKU_GLOBAL_BUILD_ARGS -f "$PLUGIN_AVAILABLE_PATH/builder-herokuish/dockerfiles/pre-build.Dockerfile" --build-arg APP_IMAGE="$IMAGE" --build-arg "DOKKU_APP_USER=$DOKKU_APP_USER" -t $IMAGE "$TMP_WORK_DIR"; then
dokku_log_warn "Failure injecting BUILD_ENV into build environment"
return 1

View File

@@ -24,6 +24,9 @@ trigger-builder-lambda-builder-build() {
fi
plugn trigger pre-build "$BUILDER_TYPE" "$APP" "$SOURCECODE_WORK_DIR"
local DOCKER_CONFIG
DOCKER_CONFIG="$(fn-registry-docker-config-dir "$APP")"
[[ -n "$DOCKER_CONFIG" ]] && export DOCKER_CONFIG
lambda-builder build --generate-image --write-procfile --image-env=DOCKER_LAMBDA_STAY_OPEN=1 --label=org.label-schema.schema-version=1.0 --label=org.label-schema.vendor=dokku --label=com.dokku.image-stage=build --label=com.dokku.builder-type=lambda "--label=com.dokku.app-name=$APP" $DOKKU_GLOBAL_BUILD_ARGS --port 5000 --tag "$IMAGE" --working-directory "$SOURCECODE_WORK_DIR"
if [[ ! -f "$SOURCECODE_WORK_DIR/lambda.zip" ]]; then
dokku_log_warn "Compressed lambda.zip not detected, failed to build lambda function"

View File

@@ -22,7 +22,10 @@ trigger-builder-lambda-builder-release() {
TMP_WORK_DIR="$(mktemp -d "/tmp/dokku-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX")"
trap "rm -rf '$TMP_WORK_DIR' >/dev/null" RETURN INT TERM EXIT
local DOCKER_BUILD_LABEL_ARGS="--label=org.label-schema.schema-version=1.0 --label=org.label-schema.vendor=dokku --label=com.dokku.app-name=$APP --label=com.dokku.image-stage=release --label=dokku"
local DOCKER_BUILD_LABEL_ARGS=("--label=org.label-schema.schema-version=1.0" "--label=org.label-schema.vendor=dokku" "--label=com.dokku.image-stage=release" "--label=com.dokku.builder-type=lambda" "--label=com.dokku.app-name=$APP" "--label=dokku")
local DOCKER_CONFIG
DOCKER_CONFIG="$(fn-registry-docker-config-dir "$APP")"
[[ -n "$DOCKER_CONFIG" ]] && export DOCKER_CONFIG
if ! suppress_output "$DOCKER_BIN" image build "${DOCKER_BUILD_LABEL_ARGS[@]}" $DOKKU_GLOBAL_BUILD_ARGS -f "$PLUGIN_AVAILABLE_PATH/builder-lambda/dockerfiles/builder-release.Dockerfile" --build-arg APP_IMAGE="$IMAGE" -t "$IMAGE" "$TMP_WORK_DIR"; then
dokku_log_warn "Failure injecting docker labels on image"
return 1

View File

@@ -1,4 +1,4 @@
[plugin]
description = "dokku core builder-lambda plugin"
version = "0.36.8"
version = "0.37.6"
[plugin.config]

View File

@@ -21,36 +21,233 @@ trigger-builder-nixpacks-builder-build() {
fi
local IMAGE=$(get_app_image_name "$APP")
local DOCKER_BUILD_LABEL_ARGS=("--label=dokku" "--label=org.label-schema.schema-version=1.0" "--label=org.label-schema.vendor=dokku" "--label=com.dokku.image-stage=build" "--label=com.dokku.builder-type=nixpacks" "--label=com.dokku.app-name=$APP")
local DOCKER_BUILD_LABEL_ARGS=("--label=org.label-schema.schema-version=1.0" "--label=org.label-schema.vendor=dokku" "--label=com.dokku.image-stage=build" "--label=com.dokku.builder-type=nixpacks" "--label=com.dokku.app-name=$APP" "--label=dokku")
pushd "$SOURCECODE_WORK_DIR" &>/dev/null
plugn trigger pre-build "$BUILDER_TYPE" "$APP" "$SOURCECODE_WORK_DIR"
no_cache="$(fn-builder-nixpacks-computed-no-cache "$APP")"
NIXPACKS_ARGS=""
if [[ "$no_cache" == "true" ]]; then
NIXPACKS_ARGS="$NIXPACKS_ARGS --no-cache"
fi
local DOCKER_ARGS=$(: | plugn trigger docker-args-build "$APP" "$BUILDER_TYPE")
DOCKER_ARGS+=$(: | plugn trigger docker-args-process-build "$APP" "$BUILDER_TYPE")
# strip --link, --volume and -v args from DOCKER_ARGS
local DOCKER_ARGS=$(sed -e "s/^--link=[[:graph:]]\+[[:blank:]]\?//g" -e "s/^--link[[:blank:]]\?[[:graph:]]\+[[:blank:]]\?//g" -e "s/^--volume=[[:graph:]]\+[[:blank:]]\?//g" -e "s/^--volume[[:blank:]]\?[[:graph:]]\+[[:blank:]]\?//g" -e "s/^-v[[:blank:]]\?[[:graph:]]\+[[:blank:]]\?//g" <<<"$DOCKER_ARGS")
declare -a ARG_ARRAY
eval "ARG_ARRAY=($DOCKER_ARGS)"
eval "$(config_export app "$APP" --merged)"
if [[ -f "$SOURCECODE_WORK_DIR/Procfile" ]]; then
if procfile-util exists --process-type release; then
procfile-util delete --process-type release
fi
fi
# shellcheck disable=SC2086
if ! nixpacks build "${DOCKER_BUILD_LABEL_ARGS[@]}" $DOKKU_GLOBAL_BUILD_ARGS "${ARG_ARRAY[@]}" $NIXPACKS_ARGS --name "$IMAGE" "$SOURCECODE_WORK_DIR"; then
local DOCKER_ARGS=$(: | plugn trigger docker-args-build "$APP" "$BUILDER_TYPE")
DOCKER_ARGS+=$(: | plugn trigger docker-args-process-build "$APP" "$BUILDER_TYPE")
DOCKER_ARGS+=" $DOKKU_GLOBAL_BUILD_ARGS"
DOCKER_ARGS=" $DOCKER_ARGS "
eval set -- "$DOCKER_ARGS"
declare -a NIXPACKS_ARGS
while true; do
case "$1" in
-t | --tag)
NIXPACKS_ARGS+=("--tag")
NIXPACKS_ARGS+=("$2")
shift 2
;;
-t=* | --tag=*)
if [[ "$1" == "--tag=*" ]]; then
NIXPACKS_ARGS+=("--tag" "${1#--tag=}")
elif [[ "$1" == "-t=*" ]]; then
NIXPACKS_ARGS+=("--tag" "${1#-t=}")
fi
shift 1
;;
-i | --install-cmd)
NIXPACKS_ARGS+=("--install-cmd")
NIXPACKS_ARGS+=("$2")
shift 2
;;
-i=* | --install-cmd=*)
if [[ "$1" == "--install-cmd=*" ]]; then
NIXPACKS_ARGS+=("--install-cmd" "${1#--install-cmd=}")
elif [[ "$1" == "-i=*" ]]; then
NIXPACKS_ARGS+=("--install-cmd" "${1#-i=}")
fi
shift 1
;;
-l | --label)
NIXPACKS_ARGS+=("--label")
NIXPACKS_ARGS+=("$2")
shift 2
;;
-l=* | --label=*)
if [[ "$1" == "--label=*" ]]; then
NIXPACKS_ARGS+=("--label" "${1#--label=}")
elif [[ "$1" == "-l=*" ]]; then
NIXPACKS_ARGS+=("--label" "${1#-l=}")
fi
shift 1
;;
-b | --build-cmd)
NIXPACKS_ARGS+=("--build-cmd")
NIXPACKS_ARGS+=("$2")
shift 2
;;
-b=* | --build-cmd=*)
if [[ "$1" == "--build-cmd=*" ]]; then
NIXPACKS_ARGS+=("--build-cmd" "${1#--build-cmd=}")
elif [[ "$1" == "-b=*" ]]; then
NIXPACKS_ARGS+=("--build-cmd" "${1#-b=}")
fi
shift 1
;;
-s | --start-cmd)
NIXPACKS_ARGS+=("--start-cmd")
NIXPACKS_ARGS+=("$2")
shift 2
;;
-s=* | --start-cmd=*)
if [[ "$1" == "--start-cmd=*" ]]; then
NIXPACKS_ARGS+=("--start-cmd" "${1#--start-cmd=}")
elif [[ "$1" == "-s=*" ]]; then
NIXPACKS_ARGS+=("--start-cmd" "${1#-s=}")
fi
shift 1
;;
-p | --pkgs)
NIXPACKS_ARGS+=("--pkgs")
NIXPACKS_ARGS+=("$2")
shift 2
;;
-p=* | --pkgs=*)
if [[ "$1" == "--pkgs=*" ]]; then
NIXPACKS_ARGS+=("--pkgs" "${1#--pkgs=}")
elif [[ "$1" == "-p=*" ]]; then
NIXPACKS_ARGS+=("--pkgs" "${1#-p=}")
fi
shift 1
;;
-a | --apt)
NIXPACKS_ARGS+=("--apt")
NIXPACKS_ARGS+=("$2")
shift 2
;;
-a=* | --apt=*)
if [[ "$1" == "--apt=*" ]]; then
NIXPACKS_ARGS+=("--apt" "${1#--apt=}")
elif [[ "$1" == "-a=*" ]]; then
NIXPACKS_ARGS+=("--apt" "${1#-a=}")
fi
shift 1
;;
-e | --env)
NIXPACKS_ARGS+=("--env")
NIXPACKS_ARGS+=("$2")
shift 2
;;
-e=* | --env=*)
if [[ "$1" == "--env=*" ]]; then
NIXPACKS_ARGS+=("--env" "${1#--env=}")
elif [[ "$1" == "-e=*" ]]; then
NIXPACKS_ARGS+=("--env" "${1#-e=}")
fi
shift 1
;;
--platform)
NIXPACKS_ARGS+=("$1")
NIXPACKS_ARGS+=("$2")
shift 2
;;
--platform=*)
NIXPACKS_ARGS+=("$1")
NIXPACKS_ARGS+=("$2")
shift 2
;;
--cache-key)
NIXPACKS_ARGS+=("$1")
NIXPACKS_ARGS+=("$2")
shift 2
;;
--cache-key=*)
NIXPACKS_ARGS+=("$1")
NIXPACKS_ARGS+=("$2")
shift 2
;;
--incremental-cache-image)
NIXPACKS_ARGS+=("$1")
NIXPACKS_ARGS+=("$2")
shift 2
;;
--incremental-cache-image=*)
NIXPACKS_ARGS+=("$1")
NIXPACKS_ARGS+=("$2")
shift 2
;;
--libs)
NIXPACKS_ARGS+=("$1")
NIXPACKS_ARGS+=("$2")
shift 2
;;
--libs=*)
NIXPACKS_ARGS+=("$1")
NIXPACKS_ARGS+=("$2")
shift 2
;;
--cache-from)
NIXPACKS_ARGS+=("$1")
NIXPACKS_ARGS+=("$2")
shift 2
;;
--cache-from=*)
NIXPACKS_ARGS+=("$1")
NIXPACKS_ARGS+=("$2")
shift 2
;;
--docker-host)
NIXPACKS_ARGS+=("$1")
NIXPACKS_ARGS+=("$2")
shift 2
;;
--docker-host=*)
NIXPACKS_ARGS+=("$1")
NIXPACKS_ARGS+=("$2")
shift 2
;;
--add-host)
NIXPACKS_ARGS+=("$1")
NIXPACKS_ARGS+=("$2")
shift 2
;;
--add-host=*)
NIXPACKS_ARGS+=("$1")
NIXPACKS_ARGS+=("$2")
shift 2
;;
--docker-tls-verify)
NIXPACKS_ARGS+=("$1")
NIXPACKS_ARGS+=("$2")
shift 2
;;
--docker-tls-verify=*)
NIXPACKS_ARGS+=("$1")
NIXPACKS_ARGS+=("$2")
shift 2
;;
--no-cache | --inline-cache | --no-error-without-start)
NIXPACKS_ARGS+=("$1")
shift 1
;;
*)
if [[ -n "$1" ]]; then
shift
continue
fi
break
;;
esac
done
eval "$(config_export app "$APP" --merged)"
local DOCKER_CONFIG
DOCKER_CONFIG="$(fn-registry-docker-config-dir "$APP")"
[[ -n "$DOCKER_CONFIG" ]] && export DOCKER_CONFIG
if ! nixpacks build "${DOCKER_BUILD_LABEL_ARGS[@]}" "${NIXPACKS_ARGS[@]}" --name "$IMAGE" "$SOURCECODE_WORK_DIR"; then
dokku_log_warn "Failure building image"
return 1
fi

View File

@@ -18,7 +18,10 @@ trigger-builder-nixpacks-builder-release() {
TMP_WORK_DIR="$(mktemp -d "/tmp/dokku-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX")"
trap "rm -rf '$TMP_WORK_DIR' >/dev/null" RETURN INT TERM EXIT
local DOCKER_BUILD_LABEL_ARGS="--label=org.label-schema.schema-version=1.0 --label=org.label-schema.vendor=dokku --label=com.dokku.app-name=$APP --label=com.dokku.image-stage=release --label=dokku"
local DOCKER_BUILD_LABEL_ARGS=("--label=org.label-schema.schema-version=1.0" "--label=org.label-schema.vendor=dokku" "--label=com.dokku.image-stage=release" "--label=com.dokku.builder-type=nixpacks" "--label=com.dokku.app-name=$APP" "--label=dokku")
local DOCKER_CONFIG
DOCKER_CONFIG="$(fn-registry-docker-config-dir "$APP")"
[[ -n "$DOCKER_CONFIG" ]] && export DOCKER_CONFIG
if ! suppress_output "$DOCKER_BIN" image build "${DOCKER_BUILD_LABEL_ARGS[@]}" $DOKKU_GLOBAL_BUILD_ARGS -f "$PLUGIN_AVAILABLE_PATH/builder-nixpacks/dockerfiles/builder-release.Dockerfile" --build-arg APP_IMAGE="$IMAGE" -t "$IMAGE" "$TMP_WORK_DIR"; then
dokku_log_warn "Failure injecting docker labels on image"
return 1

View File

@@ -38,9 +38,6 @@ cmd-builder-nixpacks-report-single() {
"--builder-nixpacks-computed-nixpackstoml-path: $(fn-builder-nixpacks-computed-nixpackstoml-path "$APP")"
"--builder-nixpacks-global-nixpackstoml-path: $(fn-builder-nixpacks-global-nixpackstoml-path "$APP")"
"--builder-nixpacks-nixpackstoml-path: $(fn-builder-nixpacks-nixpackstoml-path "$APP")"
"--builder-nixpacks-computed-no-cache: $(fn-builder-nixpacks-computed-no-cache "$APP")"
"--builder-nixpacks-global-no-cache: $(fn-builder-nixpacks-global-no-cache "$APP")"
"--builder-nixpacks-no-cache: $(fn-builder-nixpacks-no-cache "$APP")"
)
if [[ -z "$INFO_FLAG" ]]; then
@@ -91,26 +88,3 @@ fn-builder-nixpacks-nixpackstoml-path() {
fn-plugin-property-get "builder-nixpacks" "$APP" "nixpackstoml-path" ""
}
fn-builder-nixpacks-computed-no-cache() {
declare APP="$1"
file="$(fn-builder-nixpacks-no-cache "$APP")"
if [[ "$file" == "" ]]; then
file="$(fn-builder-nixpacks-global-no-cache "$APP")"
fi
echo "$file"
}
fn-builder-nixpacks-global-no-cache() {
declare APP="$1"
fn-plugin-property-get "builder-nixpacks" "--global" "no-cache" "false"
}
fn-builder-nixpacks-no-cache() {
declare APP="$1"
fn-plugin-property-get "builder-nixpacks" "$APP" "no-cache" ""
}

View File

@@ -1,4 +1,4 @@
[plugin]
description = "dokku core builder-nixpacks plugin"
version = "0.36.8"
version = "0.37.6"
[plugin.config]

View File

@@ -9,13 +9,13 @@ cmd-builder-nixpacks-set() {
declare cmd="builder-nixpacks:set"
[[ "$1" == "$cmd" ]] && shift 1
declare APP="$1" KEY="$2" VALUE="$3"
local VALID_KEYS=("nixpackstoml-path" "no-cache")
local VALID_KEYS=("nixpackstoml-path")
[[ "$APP" == "--global" ]] || verify_app_name "$APP"
[[ -z "$KEY" ]] && dokku_log_fail "No key specified"
if ! fn-in-array "$KEY" "${VALID_KEYS[@]}"; then
dokku_log_fail "Invalid key specified, valid keys include: nixpackstoml-path, no-cache"
dokku_log_fail "Invalid key specified, valid keys include: nixpackstoml-path"
fi
if [[ -n "$VALUE" ]]; then

View File

@@ -1,4 +1,4 @@
[plugin]
description = "dokku core builder-null plugin"
version = "0.36.8"
version = "0.37.6"
[plugin.config]

View File

@@ -38,33 +38,264 @@ trigger-builder-pack-builder-build() {
plugn trigger pre-build "$BUILDER_TYPE" "$APP" "$SOURCECODE_WORK_DIR"
local DOCKER_ARGS=$(: | plugn trigger docker-args-build "$APP" "$BUILDER_TYPE")
[[ "$DOKKU_TRACE" ]] && DOCKER_ARGS+=" --env=TRACE=true "
DOCKER_ARGS+=$(: | plugn trigger docker-args-process-build "$APP" "$BUILDER_TYPE")
[[ "$DOKKU_TRACE" ]] && DOCKER_ARGS+=" --env=TRACE=true "
DOCKER_ARGS=" $DOCKER_ARGS "
declare -a ARG_ARRAY
eval "ARG_ARRAY=($DOCKER_ARGS)"
eval set -- "$DOCKER_ARGS"
declare -a PACK_ARGS
while true; do
case "$1" in
--volume=* | -v=*)
PACK_ARGS+=("$1")
shift
-b | --buildpack)
PACK_ARGS+=("--buildpack")
PACK_ARGS+=("$2")
shift 2
;;
-b=* | --buildpack=*)
if [[ "$1" == "--buildpack=*" ]]; then
PACK_ARGS+=("--buildpack" "${1#--buildpack=}")
elif [[ "$1" == "-b=*" ]]; then
PACK_ARGS+=("--buildpack" "${1#-b=}")
fi
shift 1
;;
-r | --buildpack-registry)
PACK_ARGS+=("--buildpack-registry")
PACK_ARGS+=("$2")
shift 2
;;
-r=* | --buildpack-registry=*)
if [[ "$1" == "--buildpack-registry=*" ]]; then
PACK_ARGS+=("--buildpack-registry" "${1#--buildpack-registry=}")
elif [[ "$1" == "-r=*" ]]; then
PACK_ARGS+=("--buildpack-registry" "${1#-r=}")
fi
shift 2
;;
-e | --env)
PACK_ARGS+=("--env")
PACK_ARGS+=("$2")
shift 2
;;
-e=* | --env=*)
if [[ "$1" == "--env=*" ]]; then
PACK_ARGS+=("--env" "${1#--env=}")
elif [[ "$1" == "-e=*" ]]; then
PACK_ARGS+=("--env" "${1#-e=}")
fi
shift 1
;;
-t | --tag)
PACK_ARGS+=("--tag")
PACK_ARGS+=("$2")
shift 2
;;
-t=* | --tag=*)
if [[ "$1" == "--tag=*" ]]; then
PACK_ARGS+=("--tag" "${1#--tag=}")
elif [[ "$1" == "-t=*" ]]; then
PACK_ARGS+=("--tag" "${1#-t=}")
fi
shift 1
;;
--volume | -v)
PACK_ARGS+=("--volume")
PACK_ARGS+=("$2")
shift 2
;;
--volume=* | -v=*)
if [[ "$1" == "--volume=*" ]]; then
PACK_ARGS+=("--volume" "${1#--volume=}")
elif [[ "$1" == "-v=*" ]]; then
PACK_ARGS+=("--volume" "${1#-v=}")
fi
shift 1
;;
--cache)
PACK_ARGS+=("--cache")
PACK_ARGS+=("$2")
shift 2
;;
--cache=*)
PACK_ARGS+=("--cache" "${1#--cache=}")
shift 1
;;
--cache-image)
PACK_ARGS+=("--cache-image")
PACK_ARGS+=("$2")
shift 2
;;
--cache-image=*)
PACK_ARGS+=("--cache-image" "${1#--cache-image=}")
shift 1
;;
--creation-time)
PACK_ARGS+=("--creation-time")
PACK_ARGS+=("$2")
shift 2
;;
--creation-time=*)
PACK_ARGS+=("--creation-time" "${1#--creation-time=}")
shift 1
;;
--env-file)
PACK_ARGS+=("--env-file")
PACK_ARGS+=("$2")
shift 2
;;
--env-file=*)
PACK_ARGS+=("--env-file" "${1#--env-file=}")
shift 1
;;
--extension)
PACK_ARGS+=("--extension")
PACK_ARGS+=("$2")
shift 2
;;
--extension=*)
PACK_ARGS+=("--extension" "${1#--extension=}")
shift 1
;;
--gid)
PACK_ARGS+=("--gid")
PACK_ARGS+=("$2")
shift 2
;;
--gid=*)
PACK_ARGS+=("--gid" "${1#--gid=}")
shift 1
;;
--insecure-registry)
PACK_ARGS+=("--insecure-registry")
PACK_ARGS+=("$2")
shift 2
;;
--insecure-registry=*)
PACK_ARGS+=("--insecure-registry" "${1#--insecure-registry=}")
shift 1
;;
--lifecycle-image)
PACK_ARGS+=("--lifecycle-image")
PACK_ARGS+=("$2")
shift 2
;;
--lifecycle-image=*)
PACK_ARGS+=("--lifecycle-image" "${1#--lifecycle-image=}")
shift 1
;;
--network)
PACK_ARGS+=("--network")
PACK_ARGS+=("$2")
shift 2
;;
--network=*)
PACK_ARGS+=("--network" "${1#--network=}")
shift 1
;;
--platform)
PACK_ARGS+=("--platform")
PACK_ARGS+=("$2")
shift 2
;;
--platform=*)
PACK_ARGS+=("--platform" "${1#--platform=}")
shift 1
;;
--post-buildpack)
PACK_ARGS+=("--post-buildpack")
PACK_ARGS+=("$2")
shift 2
;;
--post-buildpack=*)
PACK_ARGS+=("--post-buildpack" "${1#--post-buildpack=}")
shift 1
;;
--pre-buildpack)
PACK_ARGS+=("--pre-buildpack")
PACK_ARGS+=("$2")
shift 2
;;
--pre-buildpack=*)
PACK_ARGS+=("--pre-buildpack" "${1#--pre-buildpack=}")
shift 1
;;
--previous-image)
PACK_ARGS+=("--previous-image")
PACK_ARGS+=("$2")
shift 2
;;
--previous-image=*)
PACK_ARGS+=("--previous-image" "${1#--previous-image=}")
shift 1
;;
--pull-policy)
PACK_ARGS+=("--pull-policy")
PACK_ARGS+=("$2")
shift 2
;;
--pull-policy=*)
PACK_ARGS+=("--pull-policy" "${1#--pull-policy=}")
shift 1
;;
--run-image)
PACK_ARGS+=("--run-image")
PACK_ARGS+=("$2")
shift 2
;;
--run-image=*)
PACK_ARGS+=("--run-image" "${1#--run-image=}")
shift 1
;;
--uid)
PACK_ARGS+=("--uid")
PACK_ARGS+=("$2")
shift 2
;;
--uid=*)
PACK_ARGS+=("--uid" "${1#--uid=}")
shift 1
;;
--workspace)
PACK_ARGS+=("--workspace")
PACK_ARGS+=("$2")
shift 2
;;
--workspace=*)
PACK_ARGS+=("--workspace" "${1#--workspace=}")
shift 1
;;
--clear-cache | --disable-system-buildpacks | --publish | --trust-builder | --trust-extra-buildpacks | --userns-host)
PACK_ARGS+=("$1")
shift 1
;;
*)
if [[ -n "$1" ]]; then
shift
continue
fi
break
;;
esac
done
if [ -n "$BUILDPACK_URL" ]; then
PACK_ARGS+=("--builder")
PACK_ARGS+=("$BUILDPACK_URL")
elif [ -f "$SOURCECODE_WORK_DIR/.buildpacks" ]; then
while read -r buildpack; do
if [ -z "$buildpack" ]; then
continue
fi
PACK_ARGS+=("--builder")
PACK_ARGS+=("$buildpack")
done <"$SOURCECODE_WORK_DIR/.buildpacks"
fi
local DOCKER_CONFIG
DOCKER_CONFIG="$(fn-registry-docker-config-dir "$APP")"
[[ -n "$DOCKER_CONFIG" ]] && export DOCKER_CONFIG
pack build "$IMAGE" --builder "$DOKKU_CNB_BUILDER" --path "$SOURCECODE_WORK_DIR" --default-process web "${PACK_ARGS[@]}" "${ENV_ARGS[@]}"
docker-image-labeler relabel --label=dokku --label=org.label-schema.schema-version=1.0 --label=org.label-schema.vendor=dokku --label=com.dokku.image-stage=build --label=com.dokku.builder-type=pack --label=com.dokku.app-name=$APP "$IMAGE"

View File

@@ -12,11 +12,6 @@ trigger-builder-pack-builder-detect() {
echo "pack"
return
fi
if [[ "$(config_get "$APP" DOKKU_CNB_EXPERIMENTAL || true)" == "1" ]]; then
echo "pack"
return
fi
}
trigger-builder-pack-builder-detect "$@"

View File

@@ -1,4 +1,4 @@
[plugin]
description = "dokku core builder-pack plugin"
version = "0.36.8"
version = "0.37.6"
[plugin.config]

View File

@@ -0,0 +1,149 @@
#!/usr/bin/env bash
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
source "$PLUGIN_AVAILABLE_PATH/builder-railpack/internal-functions"
source "$PLUGIN_AVAILABLE_PATH/config/functions"
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
trigger-builder-railpack-builder-build() {
declare desc="builder-railpack builder-build plugin trigger"
declare trigger="builder-build"
declare BUILDER_TYPE="$1" APP="$2" SOURCECODE_WORK_DIR="$3"
if [[ "$BUILDER_TYPE" != "railpack" ]]; then
return
fi
dokku_log_info1 "Building $APP from railpack"
if ! command -v "railpack" &>/dev/null; then
dokku_log_fail "Missing railpack, install it"
fi
local IMAGE=$(get_app_image_name "$APP")
local DOCKER_BUILD_LABEL_ARGS=("--label=org.label-schema.schema-version=1.0" "--label=org.label-schema.vendor=dokku" "--label=com.dokku.image-stage=build" "--label=com.dokku.builder-type=railpack" "--label=com.dokku.app-name=$APP" "--label=dokku")
pushd "$SOURCECODE_WORK_DIR" &>/dev/null
plugn trigger pre-build "$BUILDER_TYPE" "$APP" "$SOURCECODE_WORK_DIR"
if [[ -f "$SOURCECODE_WORK_DIR/Procfile" ]]; then
if procfile-util exists --process-type release; then
procfile-util delete --process-type release
fi
fi
local DOCKER_ARGS=$(: | plugn trigger docker-args-build "$APP" "$BUILDER_TYPE")
DOCKER_ARGS+=$(: | plugn trigger docker-args-process-build "$APP" "$BUILDER_TYPE")
DOCKER_ARGS=" $DOCKER_ARGS "
eval set -- "$DOCKER_ARGS"
declare -a RAILPACK_ARGS
while true; do
case "$1" in
--platform)
RAILPACK_ARGS+=("--platform")
RAILPACK_ARGS+=("$2")
shift 2
;;
--platform=*)
RAILPACK_ARGS+=("--platform" "${1#--platform=}")
shift 1
;;
--progress)
RAILPACK_ARGS+=("--progress")
RAILPACK_ARGS+=("$2")
shift 2
;;
--progress=*)
RAILPACK_ARGS+=("--progress" "${1#--progress=}")
shift 1
;;
--cache-key)
RAILPACK_ARGS+=("--cache-key")
RAILPACK_ARGS+=("$2")
shift 2
;;
--cache-key=*)
RAILPACK_ARGS+=("--cache-key" "${1#--cache-key=}")
shift 1
;;
-e | --env)
RAILPACK_ARGS+=("--env")
RAILPACK_ARGS+=("$2")
shift 2
;;
-e=* | --env=*)
if [[ "$1" == "--env=*" ]]; then
RAILPACK_ARGS+=("--env" "${1#--env=}")
elif [[ "$1" == "--e=*" ]]; then
RAILPACK_ARGS+=("--env" "${1#-e=}")
fi
shift 1
;;
--previous)
RAILPACK_ARGS+=("--previous")
RAILPACK_ARGS+=("$2")
shift 2
;;
--previous=*)
RAILPACK_ARGS+=("--previous" "${1#--previous=}")
shift 1
;;
--build-cmd)
RAILPACK_ARGS+=("--build-cmd")
RAILPACK_ARGS+=("$2")
shift 2
;;
--build-cmd=*)
RAILPACK_ARGS+=("--build-cmd" "${1#--build-cmd=}")
shift 1
;;
--start-cmd)
RAILPACK_ARGS+=("--start-cmd")
RAILPACK_ARGS+=("$2")
shift 2
;;
--start-cmd=*)
RAILPACK_ARGS+=("--start-cmd" "${1#--start-cmd=}")
shift 1
;;
---show-plan | --error-missing-start)
RAILPACK_ARGS+=("$1")
shift 1
;;
*)
if [[ -n "$1" ]]; then
shift
continue
fi
break
;;
esac
done
eval "$(config_export app "$APP" --merged)"
local DOCKER_CONFIG
DOCKER_CONFIG="$(fn-registry-docker-config-dir "$APP")"
[[ -n "$DOCKER_CONFIG" ]] && export DOCKER_CONFIG
if ! railpack build "${RAILPACK_ARGS[@]}" --name "$IMAGE-build" "$SOURCECODE_WORK_DIR"; then
dokku_log_warn "Failure building image"
return 1
fi
if ! suppress_output "$DOCKER_BIN" image build -f "$PLUGIN_AVAILABLE_PATH/builder-railpack/dockerfiles/builder-build.Dockerfile" --build-arg APP_IMAGE="$IMAGE-build" "${DOCKER_BUILD_LABEL_ARGS[@]}" $DOKKU_GLOBAL_BUILD_ARGS -t "$IMAGE" "$SOURCECODE_WORK_DIR"; then
"$DOCKER_BIN" image remove "$IMAGE-build"
dokku_log_warn "Failure injecting docker labels and custom entrypoint on image"
return 1
fi
"$DOCKER_BIN" image remove "$IMAGE-build"
plugn trigger post-build "$BUILDER_TYPE" "$APP" "$SOURCECODE_WORK_DIR"
popd &>/dev/null || pushd "/tmp" >/dev/null
}
trigger-builder-railpack-builder-build "$@"

View File

@@ -0,0 +1,17 @@
#!/usr/bin/env bash
source "$PLUGIN_AVAILABLE_PATH/config/functions"
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
trigger-builder-railpack-builder-detect() {
declare desc="builder-railpack builder-detect plugin trigger"
declare trigger="builder-detect"
declare APP="$1" SOURCECODE_WORK_DIR="$2"
if [[ -f "$SOURCECODE_WORK_DIR/railpack.json" ]]; then
echo "railpack"
return
fi
}
trigger-builder-railpack-builder-detect "$@"

View File

@@ -0,0 +1,33 @@
#!/usr/bin/env bash
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
trigger-builder-railpack-builder-release() {
declare desc="builder-railpack builder-release plugin trigger"
declare trigger="builder-release"
declare BUILDER_TYPE="$1" APP="$2" IMAGE_TAG="$3"
if [[ "$BUILDER_TYPE" != "railpack" ]]; then
return
fi
local IMAGE=$(get_app_image_name "$APP" "$IMAGE_TAG")
plugn trigger pre-release-builder "$BUILDER_TYPE" "$APP" "$IMAGE"
TMP_WORK_DIR="$(mktemp -d "/tmp/dokku-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX")"
trap "rm -rf '$TMP_WORK_DIR' >/dev/null" RETURN INT TERM EXIT
local DOCKER_BUILD_LABEL_ARGS=("--label=org.label-schema.schema-version=1.0" "--label=org.label-schema.vendor=dokku" "--label=com.dokku.image-stage=release" "--label=com.dokku.builder-type=railpack" "--label=com.dokku.app-name=$APP" "--label=dokku")
local DOCKER_CONFIG
DOCKER_CONFIG="$(fn-registry-docker-config-dir "$APP")"
[[ -n "$DOCKER_CONFIG" ]] && export DOCKER_CONFIG
if ! suppress_output "$DOCKER_BIN" image build "${DOCKER_BUILD_LABEL_ARGS[@]}" $DOKKU_GLOBAL_BUILD_ARGS -f "$PLUGIN_AVAILABLE_PATH/builder-railpack/dockerfiles/builder-release.Dockerfile" --build-arg APP_IMAGE="$IMAGE" -t "$IMAGE" "$TMP_WORK_DIR"; then
dokku_log_warn "Failure injecting docker labels on image"
return 1
fi
plugn trigger post-release-builder "$BUILDER_TYPE" "$APP" "$IMAGE"
}
trigger-builder-railpack-builder-release "$@"

View File

@@ -0,0 +1,15 @@
#!/usr/bin/env bash
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
source "$PLUGIN_AVAILABLE_PATH/builder-railpack/help-functions"
case "$1" in
help | builder-railpack:help)
cmd-builder-railpack-help "$@"
;;
*)
exit "$DOKKU_NOT_IMPLEMENTED_EXIT"
;;
esac

View File

@@ -0,0 +1,30 @@
#!/usr/bin/env bash
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
source "$PLUGIN_AVAILABLE_PATH/builder-railpack/internal-functions"
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
trigger-builder-railpack-core-post-extract() {
declare desc="builder-railpack post-extract plugin trigger"
declare trigger="post-extract"
declare APP="$1" SOURCECODE_WORK_DIR="$2"
local NEW_RAILPACK_JSON="$(fn-builder-railpack-computed-railpackjson-path "$APP")"
pushd "$TMP_WORK_DIR" >/dev/null
if [[ -z "$NEW_RAILPACK_JSON" ]]; then
return
fi
if [[ ! -f "$NEW_RAILPACK_JSON" ]]; then
rm -f railpack.json
return
fi
if [[ "$NEW_RAILPACK_JSON" != "railpack.json" ]]; then
mv "$NEW_RAILPACK_JSON" railpack.json
fi
popd &>/dev/null || pushd "/tmp" >/dev/null
}
trigger-builder-railpack-core-post-extract "$@"

View File

@@ -0,0 +1,4 @@
ARG APP_IMAGE
FROM $APP_IMAGE
ENTRYPOINT []

View File

@@ -0,0 +1,2 @@
ARG APP_IMAGE
FROM $APP_IMAGE

View File

@@ -2,11 +2,11 @@
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
cmd-storage-help() {
cmd-builder-railpack-help() {
declare desc="help command"
declare CMD="$1"
local plugin_name="storage"
local plugin_description="Manage mounted volumes"
local plugin_name="builder-railpack"
local plugin_description="Manage the railpack builder integration for an app"
if [[ "$CMD" == "${plugin_name}:help" ]]; then
echo -e "Usage: dokku ${plugin_name}[:COMMAND]"
@@ -27,10 +27,7 @@ help_desc
fn-help-content() {
declare desc="return help content"
cat <<help_content
storage:ensure-directory [--chown option] <directory>, Creates a persistent storage directory in the recommended storage path
storage:list <app> [--format text|json], List bind mounts for app's container(s) (host:container)
storage:mount <app> <host-dir:container-dir>, Create a new bind mount
storage:report [<app>] [<flag>], Displays a checks report for one or more apps
storage:unmount <app> <host-dir:container-dir>, Remove an existing bind mount
builder-railpack:report [<app>] [<flag>], Displays a builder-railpack report for one or more apps
builder-railpack:set <app> <property> (<value>), Set or clear a builder-railpack property for an app
help_content
}

View File

@@ -0,0 +1,16 @@
#!/usr/bin/env bash
source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions"
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
trigger-builder-railpack-install() {
declare desc="installs the builder-railpack plugin"
declare trigger="install"
fn-plugin-property-setup "builder-railpack"
mkdir -p "${DOKKU_LIB_ROOT}/data/builder-railpack"
chown -R "${DOKKU_SYSTEM_USER}:${DOKKU_SYSTEM_GROUP}" "${DOKKU_LIB_ROOT}/data/builder-railpack"
}
trigger-builder-railpack-install "$@"

View File

@@ -0,0 +1,90 @@
#!/usr/bin/env bash
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions"
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
cmd-builder-railpack-report() {
declare desc="displays a builder-railpack report for one or more apps"
declare cmd="builder-railpack:report"
[[ "$1" == "$cmd" ]] && shift 1
declare APP="$1" INFO_FLAG="$2"
if [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then
INFO_FLAG="$APP"
APP=""
fi
if [[ -z "$APP" ]] && [[ -z "$INFO_FLAG" ]]; then
INFO_FLAG="true"
fi
if [[ -z "$APP" ]]; then
for app in $(dokku_apps); do
cmd-builder-railpack-report-single "$app" "$INFO_FLAG" | tee || true
done
else
cmd-builder-railpack-report-single "$APP" "$INFO_FLAG"
fi
}
cmd-builder-railpack-report-single() {
declare APP="$1" INFO_FLAG="$2"
if [[ "$INFO_FLAG" == "true" ]]; then
INFO_FLAG=""
fi
verify_app_name "$APP"
local flag_map=(
"--builder-railpack-computed-railpackjson-path: $(fn-builder-railpack-computed-railpackjson-path "$APP")"
"--builder-railpack-global-railpackjson-path: $(fn-builder-railpack-global-railpackjson-path "$APP")"
"--builder-railpack-railpackjson-path: $(fn-builder-railpack-railpackjson-path "$APP")"
)
if [[ -z "$INFO_FLAG" ]]; then
dokku_log_info2_quiet "${APP} builder-railpack information"
for flag in "${flag_map[@]}"; do
key="$(echo "${flag#--}" | cut -f1 -d' ' | tr - ' ')"
dokku_log_verbose "$(printf "%-30s %-25s" "${key^}" "${flag#*: }")"
done
else
local match=false
local value_exists=false
for flag in "${flag_map[@]}"; do
valid_flags="${valid_flags} $(echo "$flag" | cut -d':' -f1)"
if [[ "$flag" == "${INFO_FLAG}:"* ]]; then
value=${flag#*: }
size="${#value}"
if [[ "$size" -ne 0 ]]; then
echo "$value" && match=true && value_exists=true
else
match=true
fi
fi
done
[[ "$match" == "true" ]] || dokku_log_fail "Invalid flag passed, valid flags:${valid_flags}"
[[ "$value_exists" == "true" ]] || dokku_log_fail "not deployed"
fi
}
fn-builder-railpack-computed-railpackjson-path() {
declare APP="$1"
file="$(fn-builder-railpack-railpackjson-path "$APP")"
if [[ "$file" == "" ]]; then
file="$(fn-builder-railpack-global-railpackjson-path "$APP")"
fi
echo "$file"
}
fn-builder-railpack-global-railpackjson-path() {
declare APP="$1"
fn-plugin-property-get "builder-railpack" "--global" "railpackjson-path" "railpack.json"
}
fn-builder-railpack-railpackjson-path() {
declare APP="$1"
fn-plugin-property-get "builder-railpack" "$APP" "railpackjson-path" ""
}

View File

@@ -0,0 +1,4 @@
[plugin]
description = "dokku core builder-railpack plugin"
version = "0.37.6"
[plugin.config]

View File

@@ -0,0 +1,14 @@
#!/usr/bin/env bash
source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions"
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
trigger-builder-railpack-post-app-clone-setup() {
declare desc="sets up properties for new app"
declare trigger="post-app-clone-setup"
declare OLD_APP="$1" NEW_APP="$2"
fn-plugin-property-clone "builder-railpack" "$OLD_APP" "$NEW_APP"
}
trigger-builder-railpack-post-app-clone-setup "$@"

View File

@@ -0,0 +1,15 @@
#!/usr/bin/env bash
source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions"
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
trigger-builder-railpack-post-app-rename-setup() {
declare desc="updates settings for new app"
declare trigger="post-app-rename-setup"
declare OLD_APP="$1" NEW_APP="$2"
fn-plugin-property-clone "builder-railpack" "$OLD_APP" "$NEW_APP"
fn-plugin-property-destroy "builder-railpack" "$OLD_APP"
}
trigger-builder-railpack-post-app-rename-setup "$@"

View File

@@ -0,0 +1,15 @@
#!/usr/bin/env bash
source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions"
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
trigger-builder-railpack-post-delete() {
declare desc="destroys the builder-railpack properties for a given app"
declare trigger="post-delete"
declare APP="$1"
fn-plugin-property-destroy "builder-railpack" "$APP"
rm -rf "${DOKKU_LIB_ROOT}/data/builder-railpack/$APP"
}
trigger-builder-railpack-post-delete "$@"

View File

@@ -0,0 +1,6 @@
#!/usr/bin/env bash
source "$PLUGIN_AVAILABLE_PATH/builder-railpack/internal-functions"
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
cmd-builder-railpack-report-single "$@"

View File

@@ -0,0 +1,6 @@
#!/usr/bin/env bash
source "$PLUGIN_AVAILABLE_PATH/builder-railpack/help-functions"
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
cmd-builder-railpack-help "builder-railpack:help"

View File

@@ -0,0 +1,6 @@
#!/usr/bin/env bash
source "$PLUGIN_AVAILABLE_PATH/builder-railpack/internal-functions"
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
cmd-builder-railpack-report "$@"

View File

@@ -0,0 +1,30 @@
#!/usr/bin/env bash
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions"
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
cmd-builder-railpack-set() {
declare desc="set or clear a builder-railpack property for an app"
declare cmd="builder-railpack:set"
[[ "$1" == "$cmd" ]] && shift 1
declare APP="$1" KEY="$2" VALUE="$3"
local VALID_KEYS=("railpackjson-path")
[[ "$APP" == "--global" ]] || verify_app_name "$APP"
[[ -z "$KEY" ]] && dokku_log_fail "No key specified"
if ! fn-in-array "$KEY" "${VALID_KEYS[@]}"; then
dokku_log_fail "Invalid key specified, valid keys include: railpackjson-path"
fi
if [[ -n "$VALUE" ]]; then
dokku_log_info2_quiet "Setting ${KEY} to ${VALUE}"
fn-plugin-property-write "builder-railpack" "$APP" "$KEY" "$VALUE"
else
dokku_log_info2_quiet "Unsetting ${KEY}"
fn-plugin-property-delete "builder-railpack" "$APP" "$KEY"
fi
}
cmd-builder-railpack-set "$@"

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/builder
go 1.25.1
go 1.25.5
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000
@@ -21,9 +21,9 @@ require (
github.com/pkg/errors v0.9.1 // indirect
github.com/pkg/sftp v1.13.5 // indirect
github.com/ryanuber/columnize v2.1.2+incompatible // indirect
golang.org/x/crypto v0.43.0 // indirect
golang.org/x/sync v0.17.0 // indirect
golang.org/x/sys v0.37.0 // indirect
golang.org/x/crypto v0.46.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.39.0 // indirect
)
replace github.com/dokku/dokku/plugins/common => ../common

View File

@@ -19,8 +19,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/melbahja/goph v1.4.0 h1:z0PgDbBFe66lRYl3v5dGb9aFgPy0kotuQ37QOwSQFqs=
github.com/melbahja/goph v1.4.0/go.mod h1:uG+VfK2Dlhk+O32zFrRlc3kYKTlV6+BtvPWd/kK7U68=
github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k=
github.com/onsi/gomega v1.39.0 h1:y2ROC3hKFmQZJNFeGAMeHZKkjBL65mIZcvrLQBF9k6Q=
github.com/onsi/gomega v1.39.0/go.mod h1:ZCU1pkQcXDO5Sl9/VVEGlDyp+zm0m1cmeG5TOzLgdh4=
github.com/otiai10/copy v1.14.1 h1:5/7E6qsUMBaH5AnQ0sSLzzTg1oTECmcCmT6lvF45Na8=
github.com/otiai10/copy v1.14.1/go.mod h1:oQwrEDDOci3IM8dJF0d8+jnbfPDllW6vUjNc3DoZm9I=
github.com/otiai10/mint v1.6.3 h1:87qsV/aw1F5as1eH1zS/yqHY85ANKVMgkDrf9rcxbQs=
@@ -45,20 +45,20 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM=
golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -69,20 +69,20 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=

View File

@@ -1,4 +1,4 @@
[plugin]
description = "dokku core builder plugin"
version = "0.36.8"
version = "0.37.6"
[plugin.config]

View File

@@ -109,7 +109,7 @@ func TriggerInstall() error {
}
apps, err := common.UnfilteredDokkuApps()
if err != nil {
if err != nil && !errors.Is(err, common.NoAppsExist) {
return nil
}

View File

@@ -1,4 +1,4 @@
SUBCOMMANDS = subcommands/add subcommands/clear subcommands/list subcommands/remove subcommands/report subcommands/set subcommands/set-property
SUBCOMMANDS = subcommands/add subcommands/clear subcommands/detect subcommands/list subcommands/remove subcommands/report subcommands/set subcommands/set-property
TRIGGERS = triggers/buildpack-stack-name triggers/install triggers/post-app-clone-setup triggers/post-app-rename-setup triggers/post-delete triggers/post-extract triggers/report
BUILD = commands subcommands triggers
PLUGIN_NAME = buildpacks

View File

@@ -63,3 +63,32 @@ func validBuildpackURL(buildpack string) (string, error) {
return buildpack, fmt.Errorf("Invalid buildpack specified: %v", buildpack)
}
func checkoutBareGitRepo(sourceWorkDir string, branch string) (string, error) {
tmpdir, err := os.MkdirTemp("", "bare-git-checkout")
if err != nil {
return "", fmt.Errorf("Unable to create temporary directory: %s", err.Error())
}
args := []string{
"--git-dir=" + sourceWorkDir,
"--work-tree=" + tmpdir,
"checkout", "-f",
}
if branch != "" {
args = append(args, branch)
}
result, err := common.CallExecCommand(common.ExecCommandInput{
Command: "git",
Args: args,
})
if err != nil {
os.RemoveAll(tmpdir)
return "", fmt.Errorf("Unable to checkout bare git repository: %s", result.StderrContents())
}
return tmpdir, nil
}

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/buildpacks
go 1.25.1
go 1.25.5
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000
@@ -21,9 +21,9 @@ require (
github.com/pkg/errors v0.9.1 // indirect
github.com/pkg/sftp v1.13.5 // indirect
github.com/ryanuber/columnize v2.1.2+incompatible // indirect
golang.org/x/crypto v0.43.0 // indirect
golang.org/x/sync v0.17.0 // indirect
golang.org/x/sys v0.37.0 // indirect
golang.org/x/crypto v0.46.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.39.0 // indirect
)
replace github.com/dokku/dokku/plugins/common => ../common

View File

@@ -19,8 +19,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/melbahja/goph v1.4.0 h1:z0PgDbBFe66lRYl3v5dGb9aFgPy0kotuQ37QOwSQFqs=
github.com/melbahja/goph v1.4.0/go.mod h1:uG+VfK2Dlhk+O32zFrRlc3kYKTlV6+BtvPWd/kK7U68=
github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k=
github.com/onsi/gomega v1.39.0 h1:y2ROC3hKFmQZJNFeGAMeHZKkjBL65mIZcvrLQBF9k6Q=
github.com/onsi/gomega v1.39.0/go.mod h1:ZCU1pkQcXDO5Sl9/VVEGlDyp+zm0m1cmeG5TOzLgdh4=
github.com/otiai10/copy v1.14.1 h1:5/7E6qsUMBaH5AnQ0sSLzzTg1oTECmcCmT6lvF45Na8=
github.com/otiai10/copy v1.14.1/go.mod h1:oQwrEDDOci3IM8dJF0d8+jnbfPDllW6vUjNc3DoZm9I=
github.com/otiai10/mint v1.6.3 h1:87qsV/aw1F5as1eH1zS/yqHY85ANKVMgkDrf9rcxbQs=
@@ -45,20 +45,20 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM=
golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -69,20 +69,20 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=

View File

@@ -1,4 +1,4 @@
[plugin]
description = "dokku core buildpacks plugin"
version = "0.36.8"
version = "0.37.6"
[plugin.config]

View File

@@ -20,6 +20,7 @@ Additional commands:`
helpContent = `
buildpacks:add [--index 1] <app> <buildpack>, Add new app buildpack while inserting into list of buildpacks if necessary
buildpacks:clear <app>, Clear all buildpacks set on the app
buildpacks:detect <app> [--branch <branch-name>], Detect the buildpack for an app (if not specified, the branch flag defaults to the deploy branch)
buildpacks:list <app>, List all buildpacks for an app
buildpacks:remove <app> <buildpack>, Remove a buildpack set on the app
buildpacks:report [<app>] [<flag>], Displays a buildpack report for one or more apps

View File

@@ -30,6 +30,15 @@ func main() {
args.Parse(os.Args[2:])
appName := args.Arg(0)
err = buildpacks.CommandClear(appName)
case "detect":
args := flag.NewFlagSet("buildpacks:detect", flag.ExitOnError)
branch := args.String("branch", "", "--branch: the branch to detect against (defaults to the deploy branch)")
args.Parse(os.Args[2:])
appName := args.Arg(0)
if *branch == "" {
*branch = common.PropertyGet("git", appName, "deploy-branch")
}
err = buildpacks.CommandDetect(appName, *branch)
case "list":
args := flag.NewFlagSet("buildpacks:list", flag.ExitOnError)
args.Parse(os.Args[2:])

View File

@@ -3,6 +3,7 @@ package buildpacks
import (
"errors"
"fmt"
"os"
"github.com/dokku/dokku/plugins/common"
)
@@ -30,6 +31,41 @@ func CommandClear(appName string) error {
return common.PropertyDelete("buildpacks", appName, "buildpacks")
}
// CommandDetect implements buildpacks:detect
func CommandDetect(appName string, branch string) (err error) {
if err := common.VerifyAppName(appName); err != nil {
return err
}
workDir := common.AppRoot(appName)
checkedOutDir, err := checkoutBareGitRepo(workDir, branch)
if err != nil {
return err
}
defer func() {
if err := os.RemoveAll(checkedOutDir); err != nil {
common.LogWarn(fmt.Sprintf("Failed to remove temporary directory %s: %v", checkedOutDir, err))
}
}()
dockerArgs := []string{
"run", "--rm",
"-v", fmt.Sprintf("%s:/tmp/app", checkedOutDir),
"gliderlabs/herokuish", "/bin/herokuish", "buildpack", "detect", "/tmp/app",
}
result, err := common.CallExecCommand(common.ExecCommandInput{
Command: common.DockerBin(),
Args: dockerArgs,
})
if err != nil {
return fmt.Errorf("Buildpack detection failed: %s", result.StderrContents())
}
common.LogVerbose(result.StdoutContents())
return nil
}
// CommandList implements buildpacks:list
func CommandList(appName string) (err error) {
if err := common.VerifyAppName(appName); err != nil {

View File

@@ -1,9 +1,34 @@
#!/usr/bin/env bash
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
source "$PLUGIN_AVAILABLE_PATH/proxy/command-functions"
source "$PLUGIN_AVAILABLE_PATH/caddy-vhosts/internal-functions"
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
cmd-caddy-labels-add() {
declare desc="adds container label to app for specified proxy"
declare cmd="caddy:labels:add"
[[ "$1" == "$cmd" ]] && shift 1
cmd-proxy-labels-add "proxy:labels:add" "caddy" "$@"
}
cmd-caddy-labels-remove() {
declare desc="removes container label from app for specified proxy"
declare cmd="caddy:labels:remove"
[[ "$1" == "$cmd" ]] && shift 1
cmd-proxy-labels-remove "proxy:labels:remove" "caddy" "$@"
}
cmd-caddy-labels-show() {
declare desc="shows container labels for app for specified proxy"
declare cmd="caddy:labels:show"
[[ "$1" == "$cmd" ]] && shift 1
cmd-proxy-labels-show "proxy:labels:show" "caddy" "$@"
}
cmd-caddy-report() {
declare desc="displays a caddy report for one or more apps"
declare cmd="caddy:report"

View File

@@ -1,6 +1,7 @@
#!/usr/bin/env bash
[[ " caddy:help help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT"
[[ " caddy:help caddy:labels:add caddy:labels:remove caddy:labels:show help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT"
source "$PLUGIN_AVAILABLE_PATH/caddy-vhosts/help-functions"
source "$PLUGIN_AVAILABLE_PATH/caddy-vhosts/command-functions"
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
@@ -9,6 +10,18 @@ case "$1" in
cmd-caddy-help "$@"
;;
caddy:labels:add)
cmd-caddy-labels-add "$@"
;;
caddy:labels:remove)
cmd-caddy-labels-remove "$@"
;;
caddy:labels:show)
cmd-caddy-labels-show "$@"
;;
*)
exit "$DOKKU_NOT_IMPLEMENTED_EXIT"
;;

View File

@@ -1,5 +1,6 @@
#!/usr/bin/env bash
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
source "$PLUGIN_AVAILABLE_PATH/proxy/functions"
source "$PLUGIN_AVAILABLE_PATH/caddy-vhosts/internal-functions"
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
@@ -8,7 +9,7 @@ trigger-caddy-vhosts-docker-args-process-deploy() {
declare desc="nginx-vhosts core-post-deploy plugin trigger"
declare trigger="docker-args-process-deploy"
declare APP="$1" IMAGE_SOURCE_TYPE="$2" IMAGE_TAG="$3" PROC_TYPE="$4" CONTAINER_INDEX="$5"
local app_domains caddy_domains is_app_listening letsencrypt_email output proxy_container_port proxy_host_port port_map proxy_scheme proxy_schemes scheme tls_internal label_key
local app_domains caddy_domains is_app_listening letsencrypt_email output proxy_container_port proxy_host_port port_map proxy_scheme proxy_schemes scheme tls_internal
local proxy_container_http_port proxy_container_http_port_candidate proxy_host_http_port_candidate
local proxy_container_https_port proxy_container_https_port_candidate proxy_host_https_port_candidate
local STDIN=$(cat)
@@ -88,14 +89,13 @@ trigger-caddy-vhosts-docker-args-process-deploy() {
if [[ -n "$is_app_listening" ]] && [[ -n "$caddy_domains" ]]; then
has_443_mapping=false
tls_internal="$(fn-caddy-tls-internal)"
label_key="$(fn-caddy-label-key "$APP")"
if [[ -n "$proxy_container_https_port" ]] || [[ -n "$proxy_container_https_port_candidate" ]]; then
has_443_mapping=true
fi
ssl_warning_mapping="https:443"
if [[ "$tls_internal" == "true" ]]; then
output="--label ${label_key}.tls=internal"
output="--label caddy.tls=internal"
if [[ "$has_443_mapping" == "false" ]]; then
ssl_warning_mapping="http:80"
proxy_host_https_port_candidate="$proxy_host_http_port_candidate"
@@ -106,7 +106,7 @@ trigger-caddy-vhosts-docker-args-process-deploy() {
scheme="http"
if [[ -n "$letsencrypt_email" ]] && [[ "$has_443_mapping" == "true" ]]; then
output="--label '${label_key}=${caddy_domains}'"
output="--label 'caddy=${caddy_domains}'"
scheme="https"
if [[ -z "$proxy_container_https_port" ]]; then
warning_scheme="$(awk -F ':' '{ print $1 }' <<<"$ssl_warning_mapping")"
@@ -115,20 +115,28 @@ trigger-caddy-vhosts-docker-args-process-deploy() {
proxy_container_https_port="$proxy_container_https_port_candidate"
fi
output="$output --label \"${label_key}.reverse_proxy={{ upstreams $proxy_container_https_port }}\""
output="$output --label \"caddy.reverse_proxy={{ upstreams $proxy_container_https_port }}\""
elif [[ -n "$proxy_container_http_port" ]] || [[ -n "$proxy_container_http_port_candidate" ]]; then
caddy_domains="${caddy_domains//, /:80, }"
output="--label '${label_key}=${caddy_domains}:80'"
output="--label 'caddy=${caddy_domains}:80'"
if [[ -z "$proxy_container_http_port" ]]; then
dokku_log_warn "Warning: http:80 port mapping not found"
dokku_log_warn "Utilizing first http port mapping, http:$proxy_host_http_port_candidate:$proxy_container_http_port_candidate"
proxy_container_http_port="$proxy_container_http_port_candidate"
fi
output="$output --label \"${label_key}.reverse_proxy={{ upstreams $proxy_container_http_port }}\""
output="$output --label \"caddy.reverse_proxy={{ upstreams $proxy_container_http_port }}\""
fi
fi
local proxy_labels_file_path=$(fn-proxy-get-labels-file-path "caddy" "$APP")
if [[ -f "$proxy_labels_file_path" ]]; then
while read -r line; do
[[ -z "$line" ]] && continue
output="$output --label '$line'"
done <"$proxy_labels_file_path"
fi
echo -n "$STDIN$output"
}

View File

@@ -30,6 +30,9 @@ fn-help-content() {
caddy:report [<app>] [<flag>], Displays an caddy report for one or more apps
caddy:set <app> <property> (<value>), Set or clear an caddy property for an app
caddy:show-config <app>, Display caddy compose config
caddy:labels:add <app> <label> <value>, Add a label to an caddy app
caddy:labels:remove <app> <label>, Remove a label from an caddy app
caddy:labels:show <app> [<label>], Show labels for an caddy app
caddy:start, Starts the caddy server
caddy:stop, Stops the caddy server
help_content

View File

@@ -71,8 +71,3 @@ fn-caddy-tls-internal() {
declare APP="$1"
fn-plugin-property-get-default "caddy" "$APP" "tls-internal" "false"
}
fn-caddy-label-key() {
declare APP="$1"
fn-plugin-property-get-default "caddy" "$APP" "label-key" "caddy"
}

View File

@@ -1,4 +1,4 @@
[plugin]
description = "dokku core caddy-vhosts plugin"
version = "0.36.8"
version = "0.37.6"
[plugin.config]

View File

@@ -0,0 +1,14 @@
#!/usr/bin/env bash
source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions"
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
trigger-caddy-vhosts-post-create() {
declare desc="caddy-vhosts post-create trigger"
declare trigger="post-create"
declare APP="$1"
fn-plugin-property-setup-app "caddy" "$APP"
}
trigger-caddy-vhosts-post-create "$@"

View File

@@ -9,13 +9,13 @@ cmd-caddy-set() {
declare cmd="caddy:set"
[[ "$1" == "$cmd" ]] && shift 1
declare APP="$1" KEY="$2" VALUE="$3"
local VALID_KEYS=("image" "letsencrypt-email" "letsencrypt-server" "log-level" "polling-interval" "label-key" "tls-internal")
local VALID_KEYS=("image" "letsencrypt-email" "letsencrypt-server" "log-level" "polling-interval" "tls-internal")
local GLOBAL_KEYS=("image" "letsencrypt-email" "letsencrypt-server" "log-level" "polling-interval")
[[ -z "$KEY" ]] && dokku_log_fail "No key specified"
if ! fn-in-array "$KEY" "${VALID_KEYS[@]}"; then
dokku_log_fail "Invalid key specified, valid keys include: image letsencrypt-email letsencrypt-server log-level polling-interval label-key tls-internal"
dokku_log_fail "Invalid key specified, valid keys include: image letsencrypt-email letsencrypt-server log-level polling-interval tls-internal"
fi
if ! fn-in-array "$KEY" "${GLOBAL_KEYS[@]}"; then

24
plugins/certs/certs-get Executable file
View File

@@ -0,0 +1,24 @@
#!/usr/bin/env bash
source "$PLUGIN_AVAILABLE_PATH/certs/functions"
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
trigger-certs-certs-get() {
declare desc="returns certificate or key content"
declare trigger="certs-get"
declare APP="$1" KEY_TYPE="$2"
local APP_SSL_PATH="$DOKKU_ROOT/$APP/tls"
if [[ "$KEY_TYPE" != "key" ]] && [[ "$KEY_TYPE" != "crt" ]]; then
return 1
fi
if ! is_ssl_enabled "$APP"; then
return 1
fi
cat "$APP_SSL_PATH/server.$KEY_TYPE"
}
trigger-certs-certs-get "$@"

View File

@@ -1,4 +1,4 @@
[plugin]
description = "dokku core certificate management plugin"
version = "0.36.8"
version = "0.37.6"
[plugin.config]

View File

@@ -1,4 +1,4 @@
[plugin]
description = "dokku core checks plugin"
version = "0.36.8"
version = "0.37.6"
[plugin.config]

View File

@@ -123,6 +123,19 @@ func CorePostDeploy(input CorePostDeployInput) error {
return fmt.Errorf("Missing required Destination in CorePostDeploy for plugin %v", input.PluginName)
}
if !DirectoryExists(input.Destination) {
if err := os.MkdirAll(input.Destination, 0755); err != nil {
return fmt.Errorf("Unable to create destination directory %v: %s", input.Destination, err.Error())
}
if err := SetPermissions(SetPermissionInput{
Filename: input.Destination,
Mode: 0755,
}); err != nil {
return fmt.Errorf("Unable to set destination directory permissions %v: %s", input.Destination, err.Error())
}
}
for i, extractedPath := range input.ExtractedPaths {
if extractedPath.Path == "" {
return fmt.Errorf("Missing required Name in CorePostDeploy for index %v for plugin %v", i, input.PluginName)
@@ -250,6 +263,19 @@ func CorePostExtract(input CorePostExtractInput) error {
})
sourceImage := results.StdoutContents()
if !DirectoryExists(input.Destination) {
if err := os.MkdirAll(input.Destination, 0755); err != nil {
return fmt.Errorf("Unable to create destination directory %v: %s", input.Destination, err.Error())
}
if err := SetPermissions(SetPermissionInput{
Filename: input.Destination,
Mode: 0755,
}); err != nil {
return fmt.Errorf("Unable to set destination directory permissions %v: %s", input.Destination, err.Error())
}
}
for i, toExtract := range input.ToExtract {
if toExtract.Name == "" {
return fmt.Errorf("Name is required for index %v in CorePostExtract for plugin %v", i, input.PluginName)

View File

@@ -1,6 +1,7 @@
package common
import (
"errors"
"fmt"
"os"
"path/filepath"
@@ -78,7 +79,7 @@ func SetupAppData(pluginName string) error {
}
apps, err := UnfilteredDokkuApps()
if err != nil {
if err != nil && !errors.Is(err, NoAppsExist) {
return nil
}

View File

@@ -29,6 +29,9 @@ type ExecCommandInput struct {
// Env is the environment variables to pass to the command
Env map[string]string
// PrintCommand prints the command before executing
PrintCommand bool
// Stdin is the stdin of the command
Stdin io.Reader
@@ -141,7 +144,7 @@ func CallExecCommandWithContext(ctx context.Context, input ExecCommandInput) (Ex
cmd.Cwd = input.WorkingDirectory
}
if os.Getenv("DOKKU_TRACE") == "1" {
if input.PrintCommand || os.Getenv("DOKKU_TRACE") == "1" {
argsSt := ""
if len(cmd.Args) > 0 {
argsSt = strings.Join(cmd.Args, " ")

View File

@@ -665,11 +665,6 @@ dokku_receive() {
docker_cleanup "$APP"
local DOKKU_CNB_EXPERIMENTAL="$(config_get "$APP" DOKKU_CNB_EXPERIMENTAL || true)"
if [[ "$DOKKU_CNB_EXPERIMENTAL" == "1" ]]; then
IMAGE_SOURCE_TYPE="pack"
fi
plugn trigger builder-set-property "$APP" "detected" "$IMAGE_SOURCE_TYPE"
if ! dokku_build "$APP" "$IMAGE_SOURCE_TYPE" "$TMP_WORK_DIR"; then
return 1
@@ -952,3 +947,14 @@ fn-migrate-config-to-property() {
fi
done
}
fn-registry-docker-config-dir() {
declare desc="returns docker config file path if per-app registry credentials exist"
declare APP="$1"
local config_dir="/var/lib/dokku/config/registry/$APP"
local config_file="$config_dir/config.json"
if [[ -f "$config_file" ]] && [[ "$(jq -r '.auths | length' "$config_file" 2>/dev/null)" != "0" ]]; then
echo "$config_dir"
fi
}

View File

@@ -1,18 +1,18 @@
module github.com/dokku/dokku/plugins/common
go 1.25.1
go 1.25.5
require (
github.com/alexellis/go-execute/v2 v2.2.1
github.com/fatih/color v1.18.0
github.com/hashicorp/go-multierror v1.1.1
github.com/melbahja/goph v1.4.0
github.com/onsi/gomega v1.38.2
github.com/onsi/gomega v1.39.0
github.com/otiai10/copy v1.14.1
github.com/ryanuber/columnize v2.1.2+incompatible
github.com/spf13/pflag v1.0.10
golang.org/x/crypto v0.43.0
golang.org/x/sync v0.17.0
golang.org/x/crypto v0.46.0
golang.org/x/sync v0.19.0
)
require (
@@ -25,8 +25,8 @@ require (
github.com/pkg/errors v0.9.1 // indirect
github.com/pkg/sftp v1.13.5 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/net v0.45.0 // indirect
golang.org/x/sys v0.37.0 // indirect
golang.org/x/text v0.30.0 // indirect
golang.org/x/net v0.47.0 // indirect
golang.org/x/sys v0.39.0 // indirect
golang.org/x/text v0.32.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@@ -27,10 +27,10 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/melbahja/goph v1.4.0 h1:z0PgDbBFe66lRYl3v5dGb9aFgPy0kotuQ37QOwSQFqs=
github.com/melbahja/goph v1.4.0/go.mod h1:uG+VfK2Dlhk+O32zFrRlc3kYKTlV6+BtvPWd/kK7U68=
github.com/onsi/ginkgo/v2 v2.25.1 h1:Fwp6crTREKM+oA6Cz4MsO8RhKQzs2/gOIVOUscMAfZY=
github.com/onsi/ginkgo/v2 v2.25.1/go.mod h1:ppTWQ1dh9KM/F1XgpeRqelR+zHVwV81DGRSDnFxK7Sk=
github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k=
github.com/onsi/ginkgo/v2 v2.25.3 h1:Ty8+Yi/ayDAGtk4XxmmfUy4GabvM+MegeB4cDLRi6nw=
github.com/onsi/ginkgo/v2 v2.25.3/go.mod h1:43uiyQC4Ed2tkOzLsEYm7hnrb7UJTWHYNsuy3bG/snE=
github.com/onsi/gomega v1.39.0 h1:y2ROC3hKFmQZJNFeGAMeHZKkjBL65mIZcvrLQBF9k6Q=
github.com/onsi/gomega v1.39.0/go.mod h1:ZCU1pkQcXDO5Sl9/VVEGlDyp+zm0m1cmeG5TOzLgdh4=
github.com/otiai10/copy v1.14.1 h1:5/7E6qsUMBaH5AnQ0sSLzzTg1oTECmcCmT6lvF45Na8=
github.com/otiai10/copy v1.14.1/go.mod h1:oQwrEDDOci3IM8dJF0d8+jnbfPDllW6vUjNc3DoZm9I=
github.com/otiai10/mint v1.6.3 h1:87qsV/aw1F5as1eH1zS/yqHY85ANKVMgkDrf9rcxbQs=
@@ -57,20 +57,20 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM=
golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -81,25 +81,25 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@@ -90,7 +90,9 @@ func LogFailWithError(err error) {
fmt.Fprintf(os.Stderr, " ! %s\n", e.Error())
}
} else {
fmt.Fprintf(os.Stderr, " ! %s\n", err.Error())
if err.Error() != "" {
fmt.Fprintf(os.Stderr, " ! %s\n", err.Error())
}
}
if errExit, ok := err.(ErrWithExitCode); ok {
os.Exit(errExit.ExitCode())

View File

@@ -1,4 +1,4 @@
[plugin]
description = "dokku core common plugin"
version = "0.36.8"
version = "0.37.6"
[plugin.config]

View File

@@ -19,6 +19,9 @@ type PlugnTriggerInput struct {
// Env is the environment variables to pass to the trigger
Env map[string]string
// PrintCommand prints the command before executing
PrintCommand bool
// Stdin is the stdin of the command
Stdin io.Reader
@@ -55,7 +58,7 @@ func CallPlugnTriggerWithContext(ctx context.Context, input PlugnTriggerInput) (
StreamStderr: input.StreamStderr,
})
if os.Getenv("DOKKU_TRACE") == "1" {
if input.PrintCommand || os.Getenv("DOKKU_TRACE") == "1" {
for _, line := range strings.Split(result.Stderr, "\n") {
LogDebug(fmt.Sprintf("plugn trigger %s stderr: %s", input.Trigger, line))
}

View File

@@ -12,27 +12,27 @@ import (
)
// CommandPropertySet is a generic function that will set a property for a given plugin/app combination
func CommandPropertySet(pluginName, appName, property, value string, properties map[string]string, globalProperties map[string]bool) {
func CommandPropertySet(pluginName, appName, property, value string, validProperties map[string]string, validGlobalProperties map[string]bool) {
if appName != "--global" {
if err := VerifyAppName(appName); err != nil {
LogFailWithError(err)
}
}
if appName == "--global" && !globalProperties[property] {
if appName == "--global" && !validGlobalProperties[property] {
LogFail("Property cannot be specified globally")
}
if property == "" {
LogFail("No property specified")
}
for k := range globalProperties {
if _, ok := properties[k]; !ok {
properties[k] = ""
for k := range validGlobalProperties {
if _, ok := validProperties[k]; !ok {
validProperties[k] = ""
}
}
if _, ok := properties[property]; !ok {
properties := reflect.ValueOf(properties).MapKeys()
if _, ok := validProperties[property]; !ok {
properties := reflect.ValueOf(validProperties).MapKeys()
validPropertyList := make([]string, len(properties))
for i := 0; i < len(properties); i++ {
validPropertyList[i] = properties[i].String()
@@ -540,6 +540,14 @@ func PropertySetup(pluginName string) error {
})
}
func PropertySetupApp(pluginName string, appName string) error {
if err := makePluginAppPropertyPath(pluginName, appName); err != nil {
return fmt.Errorf("Unable to create %s config directory for %s: %s", pluginName, appName, err.Error())
}
return nil
}
func getPropertyPath(pluginName string, appName string, property string) string {
pluginAppConfigRoot := getPluginAppPropertyPath(pluginName, appName)
return filepath.Join(pluginAppConfigRoot, property)

View File

@@ -39,6 +39,12 @@ fn-plugin-property-get-all() {
"$PLUGIN_CORE_AVAILABLE_PATH/common/prop" "get-all" "$PLUGIN" "$APP"
}
fn-plugin-property-get-all-by-prefix() {
declare desc="returns a map of all properties for a given app with a specified prefix"
declare PLUGIN="$1" APP="$2" PREFIX="$3"
"$PLUGIN_CORE_AVAILABLE_PATH/common/prop" "get-all-by-prefix" "$PLUGIN" "$APP" "$PREFIX"
}
fn-plugin-property-get-default() {
declare desc="returns the value for a given property with a specified default value"
declare PLUGIN="$1" APP="$2" KEY="$3" DEFAULT="$4"
@@ -104,3 +110,9 @@ fn-plugin-property-setup() {
declare PLUGIN="$1"
"$PLUGIN_CORE_AVAILABLE_PATH/common/prop" "setup" "$PLUGIN"
}
fn-plugin-property-setup-app() {
declare desc="setup the properties for an app"
declare PLUGIN="$1" APP="$2"
"$PLUGIN_CORE_AVAILABLE_PATH/common/prop" "setup-app" "$PLUGIN" "$APP"
}

View File

@@ -219,7 +219,7 @@ func (task SftpCopyTask) Execute(ctx context.Context) (SftpCopyResult, error) {
}, ctx.Err()
}
if task.PrintCommand {
if task.PrintCommand || os.Getenv("DOKKU_TRACE") == "1" {
LogDebug(fmt.Sprintf("ssh %s@%s cp %s %v", task.Username, task.Hostname, task.SourcePath, task.DestinationPath))
}

View File

@@ -78,6 +78,19 @@ func main() {
os.Exit(1)
}
for key, value := range values {
fmt.Println(fmt.Sprintf("%s %s", key, strings.TrimSuffix(value, "\n")))
}
case "get-all-by-prefix":
appName := flag.Arg(2)
prefix := flag.Arg(3)
values, err := common.PropertyGetAllByPrefix(pluginName, appName, prefix)
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}
for key, value := range values {
fmt.Println(fmt.Sprintf("%s %s", key, strings.TrimSuffix(value, "\n")))
}
@@ -194,5 +207,12 @@ func main() {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}
case "setup-app":
appName := flag.Arg(2)
err := common.PropertySetupApp(pluginName, appName)
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}
}
}

View File

@@ -203,6 +203,7 @@ type SshTask struct {
// PrintCommand prints the command before executing
PrintCommand bool
// StreamStdio prints stdout and stderr directly to os.Stdout/err as
// the command runs.
StreamStdio bool
@@ -334,7 +335,7 @@ func (task SshTask) Execute(ctx context.Context) (SshResult, error) {
command = "sudo"
}
if task.PrintCommand {
if task.PrintCommand || os.Getenv("DOKKU_TRACE") == "1" {
LogDebug(fmt.Sprintf("ssh %s@%s %s %v", task.Username, task.Hostname, command, commandArgs))
}

View File

@@ -1,6 +1,7 @@
package common
import (
"errors"
"fmt"
)
@@ -34,7 +35,7 @@ func TriggerInstall() error {
}
apps, err := UnfilteredDokkuApps()
if err != nil {
if err != nil && !errors.Is(err, NoAppsExist) {
return nil
}

View File

@@ -1,5 +1,5 @@
GOARCH ?= amd64
SUBCOMMANDS = subcommands/bundle subcommands/clear subcommands/export subcommands/get subcommands/keys subcommands/show subcommands/set subcommands/unset
SUBCOMMANDS = subcommands/bundle subcommands/clear subcommands/export subcommands/get subcommands/import subcommands/keys subcommands/show subcommands/set subcommands/unset
TRIGGERS = triggers/config-export triggers/config-get triggers/config-get-global triggers/config-unset triggers/post-app-clone-setup triggers/post-app-rename-setup
BUILD = commands config_sub subcommands triggers
PLUGIN_NAME = config

View File

@@ -30,7 +30,7 @@ func GetWithDefault(appName string, key string, defaultValue string) (value stri
}
// SetMany variables in the environment. If appName is empty the global config is used. If restart is true the app is restarted.
func SetMany(appName string, entries map[string]string, restart bool) (err error) {
func SetMany(appName string, entries map[string]string, replace bool, restart bool) (err error) {
global := appName == "" || appName == "--global"
env, err := loadAppOrGlobalEnv(appName)
if err != nil {
@@ -42,6 +42,10 @@ func SetMany(appName string, entries map[string]string, restart bool) (err error
return
}
}
if replace {
env.Clear()
}
for k, v := range entries {
env.Set(k, v)
keys = append(keys, k)
@@ -128,6 +132,10 @@ func UnsetAll(appName string, restart bool) (err error) {
}
func triggerRestart(appName string) {
if !common.IsDeployed(appName) {
return
}
common.LogInfo1(fmt.Sprintf("Restarting app %s", appName))
_, err := common.CallPlugnTrigger(common.PlugnTriggerInput{
Trigger: "release-and-deploy",

View File

@@ -128,6 +128,82 @@ func TestConfigUnsetMany(t *testing.T) {
Expect(CommandUnset(testAppName+"does-not-exist", keys, false, true)).ToNot(Succeed())
}
func TestConfigImport(t *testing.T) {
RegisterTestingT(t)
Expect(setupTests()).To(Succeed())
Expect(setupTestApp()).To(Succeed())
defer teardownTestApp()
tempFile, err := os.CreateTemp("", "test-config-import-*.env")
Expect(err).To(Succeed())
defer os.Remove(tempFile.Name())
content := `
testKey=TESTING-updated1
testKey2=TESTING-updated2
`
_, err = tempFile.WriteString(content)
Expect(err).To(Succeed())
tempFile.Close()
Expect(CommandImport(testAppName, false, false, true, "envfile", tempFile.Name())).To(Succeed())
expectValue(testAppName, "testKey", "TESTING-updated1")
expectValue(testAppName, "testKey2", "TESTING-updated2")
env, err := LoadAppEnv(testAppName)
Expect(err).To(Succeed())
env.Set("testKey", "TESTING-original1")
env.Set("testKey2", "TESTING-original2")
env.Set("testKey3", "TESTING-original3")
env.Write()
Expect(CommandImport(testAppName, false, false, true, "envfile", tempFile.Name())).To(Succeed())
expectValue(testAppName, "testKey", "TESTING-updated1")
expectValue(testAppName, "testKey2", "TESTING-updated2")
expectValue(testAppName, "testKey3", "TESTING-original3")
Expect(CommandImport(testAppName, false, true, true, "envfile", tempFile.Name())).To(Succeed())
expectValue(testAppName, "testKey", "TESTING-updated1")
expectValue(testAppName, "testKey2", "TESTING-updated2")
expectNoValue(testAppName, "testKey3")
}
func TestConfigImportJSON(t *testing.T) {
RegisterTestingT(t)
Expect(setupTests()).To(Succeed())
Expect(setupTestApp()).To(Succeed())
defer teardownTestApp()
tempFile, err := os.CreateTemp("", "test-config-import-*.json")
Expect(err).To(Succeed())
defer os.Remove(tempFile.Name())
content := `{"testKey": "TESTING-updated1", "testKey2": "TESTING-updated2"}`
_, err = tempFile.WriteString(content)
Expect(err).To(Succeed())
tempFile.Close()
Expect(CommandImport(testAppName, false, false, true, "json", tempFile.Name())).To(Succeed())
expectValue(testAppName, "testKey", "TESTING-updated1")
expectValue(testAppName, "testKey2", "TESTING-updated2")
env, err := LoadAppEnv(testAppName)
Expect(err).To(Succeed())
env.Set("testKey", "TESTING-original1")
env.Set("testKey2", "TESTING-original2")
env.Set("testKey3", "TESTING-original3")
env.Write()
Expect(CommandImport(testAppName, false, false, true, "json", tempFile.Name())).To(Succeed())
expectValue(testAppName, "testKey", "TESTING-updated1")
expectValue(testAppName, "testKey2", "TESTING-updated2")
expectValue(testAppName, "testKey3", "TESTING-original3")
Expect(CommandImport(testAppName, false, true, true, "json", tempFile.Name())).To(Succeed())
expectValue(testAppName, "testKey", "TESTING-updated1")
expectValue(testAppName, "testKey2", "TESTING-updated2")
expectNoValue(testAppName, "testKey3")
}
func TestEnvironmentLoading(t *testing.T) {
RegisterTestingT(t)
Expect(setupTests()).To(Succeed())
@@ -161,12 +237,13 @@ func TestInvalidKeys(t *testing.T) {
invalidKeys := []string{"0invalidKey", "invalid:key", "invalid=Key", "!invalidKey"}
for _, key := range invalidKeys {
Expect(SetMany(testAppName, map[string]string{key: "value"}, false)).NotTo(Succeed())
Expect(SetMany(testAppName, map[string]string{key: "value"}, false, false)).NotTo(Succeed())
Expect(UnsetMany(testAppName, []string{key}, false)).NotTo(Succeed())
value, ok := Get(testAppName, key)
Expect(ok).To(Equal(false))
value = GetWithDefault(testAppName, key, "default")
Expect(value).To(Equal("default"))
Expect(value).To(Equal(""))
value2 := GetWithDefault(testAppName, key, "default")
Expect(value2).To(Equal("default"))
}
}

View File

@@ -88,6 +88,11 @@ func LoadGlobalEnv() (*Env, error) {
return loadFromFile("<global>", getGlobalFile())
}
// Clear clears the environment
func (e *Env) Clear() {
e.env = make(map[string]string)
}
// Filename returns the full path on disk to the file holding the env vars
func (e *Env) Filename() string {
return e.filename
@@ -326,8 +331,17 @@ func prettyPrintEnvEntries(prefix string, entries map[string]string) string {
func loadFromFile(name string, filename string) (env *Env, err error) {
envMap := make(map[string]string)
if filename == "-" {
envMap, err = godotenv.Parse(os.Stdin)
if err != nil {
return nil, err
}
}
if _, err := os.Stat(filename); err == nil {
envMap, err = godotenv.Read(filename)
if err != nil {
return nil, err
}
}
dirty := false
@@ -352,6 +366,31 @@ func loadFromFile(name string, filename string) (env *Env, err error) {
return
}
func loadFromFileJSON(name string, filename string) (env *Env, err error) {
envMap := make(map[string]string)
if filename == "-" {
err = json.NewDecoder(os.Stdin).Decode(&envMap)
if err != nil {
return nil, err
}
} else {
file, err := os.Open(filename)
if err != nil {
return nil, err
}
defer file.Close()
err = json.NewDecoder(file).Decode(&envMap)
if err != nil {
return nil, err
}
}
return &Env{
name: name,
filename: "",
env: envMap,
}, nil
}
func getAppFile(appName string) (string, error) {
return filepath.Join(common.MustGetEnv("DOKKU_ROOT"), appName, "ENV"), nil
}

View File

@@ -82,6 +82,44 @@ func SubGet(appName string, keys []string, quoted bool) error {
return nil
}
// SubImport imports environment variables from a file
func SubImport(appName string, replace bool, noRestart bool, format string, filename string) error {
if filename == "-" {
common.LogInfo1Quiet("Reading config vars from stdin")
}
if format == "" {
format = "envfile"
}
var env *Env
var err error
switch format {
case "envfile":
env, err = loadFromFile(appName, filename)
if err != nil {
return err
}
case "json":
env, err = loadFromFileJSON(appName, filename)
if err != nil {
return err
}
default:
return fmt.Errorf("Unknown format: %s", format)
}
if len(env.Map()) == 0 {
return errors.New("No config vars to set")
}
for k, v := range env.Map() {
common.LogInfo1Quiet(fmt.Sprintf("Setting config var %s=%s", k, v))
}
return SetMany(appName, env.Map(), replace, !noRestart)
}
// SubKeys implements the logic for config:keys without app name validation
func SubKeys(appName string, merged bool) error {
env := getEnvironment(appName, merged)
@@ -115,7 +153,7 @@ func SubSet(appName string, pairs []string, noRestart bool, encoded bool) error
updated[key] = value
}
return SetMany(appName, updated, !noRestart)
return SetMany(appName, updated, false, !noRestart)
}
// SubShow implements the logic for config:show without app name validation

View File

@@ -1,11 +1,11 @@
module github.com/dokku/dokku/plugins/config
go 1.25.1
go 1.25.5
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000
github.com/joho/godotenv v1.2.0
github.com/onsi/gomega v1.38.2
github.com/onsi/gomega v1.39.0
github.com/ryanuber/columnize v2.1.2+incompatible
github.com/spf13/pflag v1.0.10
)
@@ -25,11 +25,11 @@ require (
github.com/pkg/errors v0.9.1 // indirect
github.com/pkg/sftp v1.13.5 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/crypto v0.43.0 // indirect
golang.org/x/net v0.45.0 // indirect
golang.org/x/sync v0.17.0 // indirect
golang.org/x/sys v0.37.0 // indirect
golang.org/x/text v0.30.0 // indirect
golang.org/x/crypto v0.46.0 // indirect
golang.org/x/net v0.47.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.39.0 // indirect
golang.org/x/text v0.32.0 // indirect
)
replace github.com/dokku/dokku/plugins/common => ../common

View File

@@ -29,10 +29,10 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/melbahja/goph v1.4.0 h1:z0PgDbBFe66lRYl3v5dGb9aFgPy0kotuQ37QOwSQFqs=
github.com/melbahja/goph v1.4.0/go.mod h1:uG+VfK2Dlhk+O32zFrRlc3kYKTlV6+BtvPWd/kK7U68=
github.com/onsi/ginkgo/v2 v2.25.1 h1:Fwp6crTREKM+oA6Cz4MsO8RhKQzs2/gOIVOUscMAfZY=
github.com/onsi/ginkgo/v2 v2.25.1/go.mod h1:ppTWQ1dh9KM/F1XgpeRqelR+zHVwV81DGRSDnFxK7Sk=
github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k=
github.com/onsi/ginkgo/v2 v2.25.3 h1:Ty8+Yi/ayDAGtk4XxmmfUy4GabvM+MegeB4cDLRi6nw=
github.com/onsi/ginkgo/v2 v2.25.3/go.mod h1:43uiyQC4Ed2tkOzLsEYm7hnrb7UJTWHYNsuy3bG/snE=
github.com/onsi/gomega v1.39.0 h1:y2ROC3hKFmQZJNFeGAMeHZKkjBL65mIZcvrLQBF9k6Q=
github.com/onsi/gomega v1.39.0/go.mod h1:ZCU1pkQcXDO5Sl9/VVEGlDyp+zm0m1cmeG5TOzLgdh4=
github.com/otiai10/copy v1.14.1 h1:5/7E6qsUMBaH5AnQ0sSLzzTg1oTECmcCmT6lvF45Na8=
github.com/otiai10/copy v1.14.1/go.mod h1:oQwrEDDOci3IM8dJF0d8+jnbfPDllW6vUjNc3DoZm9I=
github.com/otiai10/mint v1.6.3 h1:87qsV/aw1F5as1eH1zS/yqHY85ANKVMgkDrf9rcxbQs=
@@ -59,20 +59,20 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM=
golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -83,25 +83,25 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@@ -1,4 +1,4 @@
[plugin]
description = "dokku core config plugin"
version = "0.36.8"
version = "0.37.6"
[plugin.config]

View File

@@ -24,6 +24,7 @@ Additional commands:`
config:clear [--no-restart] (<app>|--global), Clears environment variables
config:export [--format=FORMAT] [--merged] (<app>|--global), Export a global or app environment
config:get [--quoted] (<app>|--global) KEY, Display a global or app-specific config value
config:import [--no-restart] [--replace] (<app>|--global) [FILE|-], Import environment from file
config:keys [--merged] (<app>|--global), Show keys set in environment
config:show [--merged] (<app>|--global), Show keys set in environment
config:set [--encoded] [--no-restart] (<app>|--global) KEY1=VALUE1 [KEY2=VALUE2 ...], Set one or more config vars

View File

@@ -65,6 +65,22 @@ func main() {
}
keys := getKeys(args.Args(), *global)
err = config.CommandGet(appName, keys, *global, *quoted)
case "import":
args := flag.NewFlagSet("config:import", flag.ExitOnError)
global := args.Bool("global", false, "--global: use the global environment")
noRestart := args.Bool("no-restart", false, "--no-restart: no restart")
replace := args.Bool("replace", false, "--replace: replace existing config vars")
format := args.String("format", "envfile", "--format: [ envfile | json ] which format to export as)")
args.Parse(os.Args[2:])
var filename string
if !*global {
appName = args.Arg(0)
filename = args.Arg(1)
} else {
filename = args.Arg(0)
}
err = config.CommandImport(appName, *global, *replace, *noRestart, *format, filename)
case "keys":
args := flag.NewFlagSet("config:keys", flag.ExitOnError)
global := args.Bool("global", false, "--global: use the global environment")

View File

@@ -42,6 +42,16 @@ func CommandGet(appName string, keys []string, global bool, quoted bool) error {
return SubGet(appName, keys, quoted)
}
// CommandImport imports environment variables from a file
func CommandImport(appName string, global bool, replace bool, noRestart bool, format string, filename string) error {
appName, err := getAppNameOrGlobal(appName, global)
if err != nil {
return err
}
return SubImport(appName, replace, noRestart, format, filename)
}
// CommandKeys shows the keys set for the specified environment
func CommandKeys(appName string, global bool, merged bool) error {
appName, err := getAppNameOrGlobal(appName, global)

View File

@@ -1,4 +1,4 @@
SUBCOMMANDS = subcommands/list subcommands/report subcommands/run subcommands/set
SUBCOMMANDS = subcommands/list subcommands/report subcommands/resume subcommands/run subcommands/set subcommands/suspend
TRIGGERS = triggers/app-json-is-valid triggers/cron-get-property triggers/install triggers/post-app-clone-setup triggers/post-app-rename-setup triggers/post-delete triggers/scheduler-stop
BUILD = commands subcommands triggers
PLUGIN_NAME = cron

View File

@@ -2,6 +2,7 @@ package cron
import (
"fmt"
"strconv"
"strings"
appjson "github.com/dokku/dokku/plugins/app-json"
@@ -27,35 +28,46 @@ var (
}
)
// TemplateCommand is a struct that represents a cron command
type TemplateCommand struct {
// ID is a unique identifier for the cron command
const MaintenancePropertyPrefix = "maintenance."
// CronTask is a struct that represents a cron task
type CronTask struct {
// ID is a unique identifier for the cron task
ID string `json:"id"`
// App is the app the cron command belongs to
// App is the app the cron task belongs to
App string `json:"app,omitempty"`
// Command is the command to run
Command string `json:"command"`
// Global is whether the cron command is global
// Global is whether the cron task is global
Global bool `json:"global,omitempty"`
// Schedule is the cron schedule
Schedule string `json:"schedule"`
// ConcurrencyPolicy is the concurrency policy for the cron command
ConcurrencyPolicy string `json:"concurrency_policy"`
// AltCommand is an alternate command to run
AltCommand string `json:"-"`
// LogFile is the log file to write to
LogFile string `json:"-"`
// Maintenance is whether the cron command is in maintenance mode
// AppInMaintenance is whether the app's cron is in maintenance mode
AppInMaintenance bool `json:"app-in-maintenance"`
// Maintenance is whether the cron task is in maintenance mode
TaskInMaintenance bool `json:"task-in-maintenance"`
// Maintenance is whether the cron task is in maintenance mode
Maintenance bool `json:"maintenance"`
}
// CronCommand returns the command to run for a given cron command
func (t TemplateCommand) CronCommand() string {
// DokkuRunCommand returns the dokku run command to execute for a given cron task
func (t CronTask) DokkuRunCommand() string {
if t.AltCommand != "" {
if t.LogFile != "" {
return fmt.Sprintf("%s &>> %s", t.AltCommand, t.LogFile)
@@ -63,48 +75,57 @@ func (t TemplateCommand) CronCommand() string {
return t.AltCommand
}
return fmt.Sprintf("dokku run --cron-id %s %s %s", t.ID, t.App, t.Command)
return fmt.Sprintf("dokku run --concurrency-policy %s --cron-id %s %s %s", t.ConcurrencyPolicy, t.ID, t.App, t.Command)
}
// FetchCronEntriesInput is the input for the FetchCronEntries function
type FetchCronEntriesInput struct {
// FetchCronTasksInput is the input for the FetchCronTasks function
type FetchCronTasksInput struct {
AppName string
AppJSON *appjson.AppJSON
WarnToFailure bool
}
// FetchCronEntries returns a list of cron commands for a given app
func FetchCronEntries(input FetchCronEntriesInput) ([]TemplateCommand, error) {
// FetchCronTasks returns a list of cron tasks for a given app
func FetchCronTasks(input FetchCronTasksInput) ([]CronTask, error) {
appName := input.AppName
commands := []TemplateCommand{}
isMaintenance := reportComputedMaintenance(appName) == "true"
tasks := []CronTask{}
isAppCronInMaintenance := reportComputedMaintenance(appName) == "true"
if input.AppJSON == nil && input.AppName == "" {
return tasks, fmt.Errorf("Missing app name or app.json")
}
if input.AppJSON == nil {
appJSON, err := appjson.GetAppJSON(appName)
if err != nil {
return commands, fmt.Errorf("Unable to fetch app.json for app %s: %s", appName, err.Error())
return tasks, fmt.Errorf("Unable to fetch app.json for app %s: %s", appName, err.Error())
}
input.AppJSON = &appJSON
}
if input.AppJSON.Cron == nil {
return commands, nil
return tasks, nil
}
properties, err := common.PropertyGetAllByPrefix("cron", appName, MaintenancePropertyPrefix)
if err != nil {
return tasks, fmt.Errorf("Error getting maintenance properties: %w", err)
}
for i, c := range input.AppJSON.Cron {
if c.Command == "" {
if input.WarnToFailure {
return commands, fmt.Errorf("Missing cron command for app %s (index %d)", appName, i)
return tasks, fmt.Errorf("Missing cron task command for app %s (index %d)", appName, i)
}
common.LogWarn(fmt.Sprintf("Missing cron command for app %s (index %d)", appName, i))
common.LogWarn(fmt.Sprintf("Missing cron task command for app %s (index %d)", appName, i))
continue
}
if c.Schedule == "" {
if input.WarnToFailure {
return commands, fmt.Errorf("Missing cron schedule for app %s (index %d)", appName, i)
return tasks, fmt.Errorf("Missing cron schedule for app %s (index %d)", appName, i)
}
common.LogWarn(fmt.Sprintf("Missing cron schedule for app %s (index %d)", appName, i))
@@ -114,26 +135,49 @@ func FetchCronEntries(input FetchCronEntriesInput) ([]TemplateCommand, error) {
parser := cronparser.NewParser(cronparser.Minute | cronparser.Hour | cronparser.Dom | cronparser.Month | cronparser.Dow | cronparser.Descriptor)
_, err := parser.Parse(c.Schedule)
if err != nil {
return commands, fmt.Errorf("Invalid cron schedule for app %s (schedule %s): %s", appName, c.Schedule, err.Error())
return tasks, fmt.Errorf("Invalid cron schedule for app %s (schedule %s): %s", appName, c.Schedule, err.Error())
}
commands = append(commands, TemplateCommand{
App: appName,
Command: c.Command,
Schedule: c.Schedule,
ID: GenerateCommandID(appName, c),
Maintenance: isMaintenance,
cronID := GenerateCommandID(appName, c)
maintenance := c.Maintenance
if value, ok := properties[MaintenancePropertyPrefix+cronID]; ok {
boolValue, err := strconv.ParseBool(value)
if err != nil {
return tasks, fmt.Errorf("Invalid maintenance property for app %s (schedule %s): %s", appName, c.Schedule, err.Error())
}
// only override the maintenance value if the property is set to true
if boolValue {
maintenance = boolValue
}
}
if c.ConcurrencyPolicy == "" {
c.ConcurrencyPolicy = "allow"
}
if c.ConcurrencyPolicy != "allow" && c.ConcurrencyPolicy != "forbid" && c.ConcurrencyPolicy != "replace" {
return tasks, fmt.Errorf("Invalid cron concurrency policy for app %s (schedule %s): %s", appName, c.Schedule, c.ConcurrencyPolicy)
}
tasks = append(tasks, CronTask{
App: appName,
Command: c.Command,
Schedule: c.Schedule,
ID: cronID,
ConcurrencyPolicy: c.ConcurrencyPolicy,
Maintenance: isAppCronInMaintenance || maintenance,
AppInMaintenance: isAppCronInMaintenance,
TaskInMaintenance: maintenance,
})
}
return commands, nil
return tasks, nil
}
// FetchGlobalCronEntries returns a list of global cron commands
// FetchGlobalCronTasks returns a list of global cron tasks
// This function should only be used for the cron:list --global command
// and not internally by the cron plugin
func FetchGlobalCronEntries() ([]TemplateCommand, error) {
commands := []TemplateCommand{}
func FetchGlobalCronTasks() ([]CronTask, error) {
tasks := []CronTask{}
response, _ := common.CallPlugnTrigger(common.PlugnTriggerInput{
Trigger: "cron-entries",
Args: []string{"docker-local"},
@@ -150,23 +194,25 @@ func FetchGlobalCronEntries() ([]TemplateCommand, error) {
}
id := base36.EncodeToStringLc([]byte(strings.Join(parts, ";;;")))
command := TemplateCommand{
ID: id,
Schedule: parts[0],
Command: parts[1],
AltCommand: parts[1],
Maintenance: false,
Global: true,
task := CronTask{
ID: id,
Schedule: parts[0],
Command: parts[1],
AltCommand: parts[1],
Global: true,
Maintenance: false,
TaskInMaintenance: false,
AppInMaintenance: false,
}
if len(parts) == 3 {
command.LogFile = parts[2]
task.LogFile = parts[2]
}
commands = append(commands, command)
tasks = append(tasks, task)
}
return commands, nil
return tasks, nil
}
// GenerateCommandID creates a unique ID for a given app/command/schedule combination
func GenerateCommandID(appName string, c appjson.CronCommand) string {
func GenerateCommandID(appName string, c appjson.CronTask) string {
return base36.EncodeToStringLc([]byte(appName + "===" + c.Command + "===" + c.Schedule))
}

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