From 929b8444e41084541d7f439f4eaa4f7ce6d13100 Mon Sep 17 00:00:00 2001 From: Tasos Maschalidis Date: Wed, 1 Oct 2025 00:27:08 +0300 Subject: [PATCH 1/9] Add helper functions isBareGitRepo and checkoutBareGitRepo --- plugins/buildpacks/functions.go | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/plugins/buildpacks/functions.go b/plugins/buildpacks/functions.go index f3545233e..0252e239e 100644 --- a/plugins/buildpacks/functions.go +++ b/plugins/buildpacks/functions.go @@ -63,3 +63,31 @@ func validBuildpackURL(buildpack string) (string, error) { return buildpack, fmt.Errorf("Invalid buildpack specified: %v", buildpack) } + +func isBareGitRepo(directory string) bool { + headFile := filepath.Join(directory, "HEAD") + objectsDir := filepath.Join(directory, "objects") + if common.FileExists(headFile) && common.DirectoryExists(objectsDir) { + return true + } + return false +} + +func checkoutBareGitRepo(sourceWorkDir string) (string, error) { + tmpdir, err := os.MkdirTemp("", "bare-git-checkout") + if err != nil { + return "", fmt.Errorf("Unable to create temporary directory: %s", err.Error()) + } + + result, err := common.CallExecCommand(common.ExecCommandInput{ + Command: "git", + Args: []string{"--git-dir=" + sourceWorkDir, "--work-tree=" + tmpdir, "checkout", "-f"}, + }) + + if err != nil { + os.RemoveAll(tmpdir) + return "", fmt.Errorf("Unable to checkout bare git repository: %s", result.StderrContents()) + } + + return tmpdir, nil +} From d440b4614d02c5455a9c940e13f75bf80bf2ec66 Mon Sep 17 00:00:00 2001 From: Tasos Maschalidis Date: Wed, 1 Oct 2025 00:30:09 +0300 Subject: [PATCH 2/9] Define and register 'detect' subcommand --- plugins/buildpacks/Makefile | 2 +- .../buildpacks/src/subcommands/subcommands.go | 5 ++ plugins/buildpacks/subcommands.go | 46 +++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/plugins/buildpacks/Makefile b/plugins/buildpacks/Makefile index aff09a27a..70ed37a5f 100644 --- a/plugins/buildpacks/Makefile +++ b/plugins/buildpacks/Makefile @@ -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 diff --git a/plugins/buildpacks/src/subcommands/subcommands.go b/plugins/buildpacks/src/subcommands/subcommands.go index f245238f7..d1c596bcc 100644 --- a/plugins/buildpacks/src/subcommands/subcommands.go +++ b/plugins/buildpacks/src/subcommands/subcommands.go @@ -30,6 +30,11 @@ func main() { args.Parse(os.Args[2:]) appName := args.Arg(0) err = buildpacks.CommandClear(appName) + case "detect": + args := flag.NewFlagSet("buildpacks:detect", flag.ExitOnError) + args.Parse(os.Args[2:]) + appName := args.Arg(0) + err = buildpacks.CommandDetect(appName) case "list": args := flag.NewFlagSet("buildpacks:list", flag.ExitOnError) args.Parse(os.Args[2:]) diff --git a/plugins/buildpacks/subcommands.go b/plugins/buildpacks/subcommands.go index 329ed6b9f..4674eb4e8 100644 --- a/plugins/buildpacks/subcommands.go +++ b/plugins/buildpacks/subcommands.go @@ -3,6 +3,7 @@ package buildpacks import ( "errors" "fmt" + "os" "github.com/dokku/dokku/plugins/common" ) @@ -30,6 +31,51 @@ func CommandClear(appName string) error { return common.PropertyDelete("buildpacks", appName, "buildpacks") } +// CommandDetect implements buildpacks:detect +func CommandDetect(appName string) error { + if err := common.VerifyAppName(appName); err != nil { + return err + } + + buildPath := common.AppRoot(appName) + if !common.DirectoryExists(buildPath) { + return fmt.Errorf("App %s does not exist", appName) + } + + workDir := buildPath + if isBareGitRepo(buildPath) { + checkedOutPath, err := checkoutBareGitRepo(buildPath) + if err != nil { + return err + } + workDir = checkedOutPath + defer func() { + if err := os.RemoveAll(checkedOutPath); err != nil { + common.LogWarn(fmt.Sprintf("Failed to remove temporary directory %s: %v", checkedOutPath, err)) + } + }() + } + + appRoot := workDir + + dockerArgs := []string{ + "run", "--rm", + "-v", fmt.Sprintf("%s:/tmp/app", appRoot), + "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(fmt.Sprintf("%s", result.StdoutContents())) + return nil +} + // CommandList implements buildpacks:list func CommandList(appName string) (err error) { if err := common.VerifyAppName(appName); err != nil { From 0c79a2c2fc5ac8d6ea956ad51ddf50f59388c3d8 Mon Sep 17 00:00:00 2001 From: Tasos Maschalidis Date: Wed, 1 Oct 2025 00:30:43 +0300 Subject: [PATCH 3/9] Add detect command in buildpacks helpContent --- plugins/buildpacks/src/commands/commands.go | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/buildpacks/src/commands/commands.go b/plugins/buildpacks/src/commands/commands.go index ecbacbc38..c2238a5a4 100644 --- a/plugins/buildpacks/src/commands/commands.go +++ b/plugins/buildpacks/src/commands/commands.go @@ -20,6 +20,7 @@ Additional commands:` helpContent = ` buildpacks:add [--index 1] , Add new app buildpack while inserting into list of buildpacks if necessary buildpacks:clear , Clear all buildpacks set on the app + buildpacks:detect , Detect the buildpack for an app buildpacks:list , List all buildpacks for an app buildpacks:remove , Remove a buildpack set on the app buildpacks:report [] [], Displays a buildpack report for one or more apps From 4b0c8b3d59a4eab41e977fb2b37ba3c61ed6c26d Mon Sep 17 00:00:00 2001 From: Tasos Maschalidis Date: Wed, 1 Oct 2025 00:46:05 +0300 Subject: [PATCH 4/9] Refactor CommandDetect function --- plugins/buildpacks/subcommands.go | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/plugins/buildpacks/subcommands.go b/plugins/buildpacks/subcommands.go index 4674eb4e8..624a42bb1 100644 --- a/plugins/buildpacks/subcommands.go +++ b/plugins/buildpacks/subcommands.go @@ -37,30 +37,23 @@ func CommandDetect(appName string) error { return err } - buildPath := common.AppRoot(appName) - if !common.DirectoryExists(buildPath) { - return fmt.Errorf("App %s does not exist", appName) - } - - workDir := buildPath - if isBareGitRepo(buildPath) { - checkedOutPath, err := checkoutBareGitRepo(buildPath) + workDir := common.AppRoot(appName) + if isBareGitRepo(workDir) { + checkedOutDir, err := checkoutBareGitRepo(workDir) if err != nil { return err } - workDir = checkedOutPath + workDir = checkedOutDir defer func() { - if err := os.RemoveAll(checkedOutPath); err != nil { - common.LogWarn(fmt.Sprintf("Failed to remove temporary directory %s: %v", checkedOutPath, err)) + if err := os.RemoveAll(checkedOutDir); err != nil { + common.LogWarn(fmt.Sprintf("Failed to remove temporary directory %s: %v", checkedOutDir, err)) } }() } - appRoot := workDir - dockerArgs := []string{ "run", "--rm", - "-v", fmt.Sprintf("%s:/tmp/app", appRoot), + "-v", fmt.Sprintf("%s:/tmp/app", workDir), "gliderlabs/herokuish", "/bin/herokuish", "buildpack", "detect", "/tmp/app", } From 66894bc0c5fd7d5b3b2dedc71a03002d01aaf343 Mon Sep 17 00:00:00 2001 From: Tasos Maschalidis Date: Thu, 16 Oct 2025 17:17:29 +0300 Subject: [PATCH 5/9] Remove redundant function isBareGitRepo --- plugins/buildpacks/functions.go | 9 --------- plugins/buildpacks/subcommands.go | 22 ++++++++++------------ 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/plugins/buildpacks/functions.go b/plugins/buildpacks/functions.go index 0252e239e..1845efae8 100644 --- a/plugins/buildpacks/functions.go +++ b/plugins/buildpacks/functions.go @@ -64,15 +64,6 @@ func validBuildpackURL(buildpack string) (string, error) { return buildpack, fmt.Errorf("Invalid buildpack specified: %v", buildpack) } -func isBareGitRepo(directory string) bool { - headFile := filepath.Join(directory, "HEAD") - objectsDir := filepath.Join(directory, "objects") - if common.FileExists(headFile) && common.DirectoryExists(objectsDir) { - return true - } - return false -} - func checkoutBareGitRepo(sourceWorkDir string) (string, error) { tmpdir, err := os.MkdirTemp("", "bare-git-checkout") if err != nil { diff --git a/plugins/buildpacks/subcommands.go b/plugins/buildpacks/subcommands.go index 624a42bb1..64578012d 100644 --- a/plugins/buildpacks/subcommands.go +++ b/plugins/buildpacks/subcommands.go @@ -38,18 +38,16 @@ func CommandDetect(appName string) error { } workDir := common.AppRoot(appName) - if isBareGitRepo(workDir) { - checkedOutDir, err := checkoutBareGitRepo(workDir) - if err != nil { - return err - } - workDir = checkedOutDir - defer func() { - if err := os.RemoveAll(checkedOutDir); err != nil { - common.LogWarn(fmt.Sprintf("Failed to remove temporary directory %s: %v", checkedOutDir, err)) - } - }() - } + checkedOutDir, err := checkoutBareGitRepo(workDir) + if err != nil { + return err + } + workDir = checkedOutDir + 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", From e234401178477e1243b9ef4002b9c11e0671c300 Mon Sep 17 00:00:00 2001 From: Tasos Maschalidis Date: Thu, 16 Oct 2025 17:19:22 +0300 Subject: [PATCH 6/9] Cleanup output log in CommandDetect function --- plugins/buildpacks/subcommands.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/buildpacks/subcommands.go b/plugins/buildpacks/subcommands.go index 64578012d..86255e628 100644 --- a/plugins/buildpacks/subcommands.go +++ b/plugins/buildpacks/subcommands.go @@ -63,7 +63,7 @@ func CommandDetect(appName string) error { return fmt.Errorf("Buildpack detection failed: %s", result.StderrContents()) } - common.LogVerbose(fmt.Sprintf("%s", result.StdoutContents())) + common.LogVerbose(result.StdoutContents()) return nil } From 65e0fb9037c998b3556467b2f03174e390ebc546 Mon Sep 17 00:00:00 2001 From: Tasos Maschalidis Date: Thu, 16 Oct 2025 18:33:47 +0300 Subject: [PATCH 7/9] Detect buildpacks for specific branch (fall back to deploy-branch to be consistent with deployment behavior) --- plugins/buildpacks/functions.go | 14 ++++++++++++-- plugins/buildpacks/src/commands/commands.go | 2 +- plugins/buildpacks/src/subcommands/subcommands.go | 6 +++++- plugins/buildpacks/subcommands.go | 4 ++-- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/plugins/buildpacks/functions.go b/plugins/buildpacks/functions.go index 1845efae8..47acbbc78 100644 --- a/plugins/buildpacks/functions.go +++ b/plugins/buildpacks/functions.go @@ -64,15 +64,25 @@ func validBuildpackURL(buildpack string) (string, error) { return buildpack, fmt.Errorf("Invalid buildpack specified: %v", buildpack) } -func checkoutBareGitRepo(sourceWorkDir string) (string, error) { +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: []string{"--git-dir=" + sourceWorkDir, "--work-tree=" + tmpdir, "checkout", "-f"}, + Args: args, }) if err != nil { diff --git a/plugins/buildpacks/src/commands/commands.go b/plugins/buildpacks/src/commands/commands.go index c2238a5a4..51eb30a15 100644 --- a/plugins/buildpacks/src/commands/commands.go +++ b/plugins/buildpacks/src/commands/commands.go @@ -20,7 +20,7 @@ Additional commands:` helpContent = ` buildpacks:add [--index 1] , Add new app buildpack while inserting into list of buildpacks if necessary buildpacks:clear , Clear all buildpacks set on the app - buildpacks:detect , Detect the buildpack for an app + buildpacks:detect [--branch ], Detect the buildpack for an app (if not specified, the branch flag defaults to the deploy branch) buildpacks:list , List all buildpacks for an app buildpacks:remove , Remove a buildpack set on the app buildpacks:report [] [], Displays a buildpack report for one or more apps diff --git a/plugins/buildpacks/src/subcommands/subcommands.go b/plugins/buildpacks/src/subcommands/subcommands.go index d1c596bcc..9062e80fa 100644 --- a/plugins/buildpacks/src/subcommands/subcommands.go +++ b/plugins/buildpacks/src/subcommands/subcommands.go @@ -32,9 +32,13 @@ func main() { 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) - err = buildpacks.CommandDetect(appName) + 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:]) diff --git a/plugins/buildpacks/subcommands.go b/plugins/buildpacks/subcommands.go index 86255e628..079de2091 100644 --- a/plugins/buildpacks/subcommands.go +++ b/plugins/buildpacks/subcommands.go @@ -32,13 +32,13 @@ func CommandClear(appName string) error { } // CommandDetect implements buildpacks:detect -func CommandDetect(appName string) error { +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) + checkedOutDir, err := checkoutBareGitRepo(workDir, branch) if err != nil { return err } From f40bcc37aa182fc46ad22a96e3d98e60c09a22a8 Mon Sep 17 00:00:00 2001 From: Tasos Maschalidis Date: Thu, 16 Oct 2025 18:35:02 +0300 Subject: [PATCH 8/9] Bump dependency version for herokuish --- contrib/dependencies.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contrib/dependencies.json b/contrib/dependencies.json index 0a9827f4c..9a10d8e84 100644 --- a/contrib/dependencies.json +++ b/contrib/dependencies.json @@ -86,11 +86,11 @@ }, { "name": "herokuish", - "version": "0.11.3", + "version": "0.11.5", "urls": { - "amd64": "https://github.com/gliderlabs/herokuish/releases/download/v0.11.3/herokuish_0.11.3_linux_x86_64.tgz", - "arm64": "https://github.com/gliderlabs/herokuish/releases/download/v0.11.3/herokuish_0.11.3_linux_x86_64.tgz" + "amd64": "https://github.com/gliderlabs/herokuish/releases/download/v0.11.5/herokuish_0.11.5_linux_x86_64.tgz", + "arm64": "https://github.com/gliderlabs/herokuish/releases/download/v0.11.5/herokuish_0.11.5_linux_x86_64.tgz" } } ] -} \ No newline at end of file +} From ca03ea72f567cc7ed8debffb75edca0f838ef747 Mon Sep 17 00:00:00 2001 From: Tasos Maschalidis Date: Fri, 17 Oct 2025 19:14:08 +0300 Subject: [PATCH 9/9] Remove unnecessary re-assignment of workDir variable --- plugins/buildpacks/subcommands.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/buildpacks/subcommands.go b/plugins/buildpacks/subcommands.go index 079de2091..ffabb5eaa 100644 --- a/plugins/buildpacks/subcommands.go +++ b/plugins/buildpacks/subcommands.go @@ -42,7 +42,6 @@ func CommandDetect(appName string, branch string) (err error) { if err != nil { return err } - workDir = checkedOutDir defer func() { if err := os.RemoveAll(checkedOutDir); err != nil { common.LogWarn(fmt.Sprintf("Failed to remove temporary directory %s: %v", checkedOutDir, err)) @@ -51,7 +50,7 @@ func CommandDetect(appName string, branch string) (err error) { dockerArgs := []string{ "run", "--rm", - "-v", fmt.Sprintf("%s:/tmp/app", workDir), + "-v", fmt.Sprintf("%s:/tmp/app", checkedOutDir), "gliderlabs/herokuish", "/bin/herokuish", "buildpack", "detect", "/tmp/app", }