Skip to content

Commit

Permalink
Replace export -p with a dedicated agent command for printing env
Browse files Browse the repository at this point in the history
  • Loading branch information
moskyb committed Oct 13, 2022
1 parent 00f2048 commit a5c79cd
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 12 deletions.
65 changes: 65 additions & 0 deletions clicommand/env.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package clicommand

import (
"encoding/json"
"fmt"
"os"
"strings"

"github.com/urfave/cli"
)

const envDescription = `Usage:
buildkite-agent env [options]
Description:
Prints out the environment of the current process as a JSON object, easily parsable by other programs. Used when
executing hooks to discover changes that hooks make to the environment.
Example:
$ buildkite-agent env
Prints the environment passed into the process
`

var EnvCommand = cli.Command{
Name: "env",
Usage: "Prints out the environment of the current process as a JSON object",
Description: envDescription,
Flags: []cli.Flag{
cli.BoolFlag{
Name: "pretty",
Usage: "Pretty print the JSON output",
EnvVar: "BUILDKITE_AGENT_ENV_PRETTY",
},
},
Action: func(c *cli.Context) error {
env := os.Environ()
envMap := make(map[string]string, len(env))

for _, e := range env {
k, v, _ := strings.Cut(e, "=")
envMap[k] = v
}

var (
envJSON []byte
err error
)

if c.Bool("pretty") {
envJSON, err = json.MarshalIndent(envMap, "", " ")
} else {
envJSON, err = json.Marshal(envMap)
}

if err != nil {
fmt.Printf("Error marshalling JSON: %v\n", err)
os.Exit(1)
}

fmt.Println(string(envJSON))

return nil
},
}
35 changes: 23 additions & 12 deletions hook/scriptwrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package hook

import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"runtime"
Expand All @@ -20,26 +20,26 @@ const (

batchScript = `@echo off
SETLOCAL ENABLEDELAYEDEXPANSION
SET > "{{.BeforeEnvFileName}}"
buildkite-agent env > "{{.BeforeEnvFileName}}"
CALL "{{.PathToHook}}"
SET BUILDKITE_HOOK_EXIT_STATUS=!ERRORLEVEL!
SET BUILDKITE_HOOK_WORKING_DIR=%CD%
SET > "{{.AfterEnvFileName}}"
buildkite-agent env > "{{.AfterEnvFileName}}"
EXIT %BUILDKITE_HOOK_EXIT_STATUS%`

powershellScript = `$ErrorActionPreference = "STOP"
Get-ChildItem Env: | Foreach-Object {"$($_.Name)=$($_.Value)"} | Set-Content "{{.BeforeEnvFileName}}"
buildkite-agent env | Set-Content "{{.BeforeEnvFileName}}"
{{.PathToHook}}
if ($LASTEXITCODE -eq $null) {$Env:BUILDKITE_HOOK_EXIT_STATUS = 0} else {$Env:BUILDKITE_HOOK_EXIT_STATUS = $LASTEXITCODE}
$Env:BUILDKITE_HOOK_WORKING_DIR = $PWD | Select-Object -ExpandProperty Path
Get-ChildItem Env: | Foreach-Object {"$($_.Name)=$($_.Value)"} | Set-Content "{{.AfterEnvFileName}}"
buildkite-agent env | Set-Content "{{.AfterEnvFileName}}"
exit $Env:BUILDKITE_HOOK_EXIT_STATUS`

bashScript = `export -p > "{{.BeforeEnvFileName}}"
bashScript = `buildkite-agent env > "{{.BeforeEnvFileName}}"
. "{{.PathToHook}}"
export BUILDKITE_HOOK_EXIT_STATUS=$?
export BUILDKITE_HOOK_WORKING_DIR=$PWD
export -p > "{{.AfterEnvFileName}}"
buildkite-agent env > "{{.AfterEnvFileName}}"
exit $BUILDKITE_HOOK_EXIT_STATUS`
)

Expand Down Expand Up @@ -220,18 +220,29 @@ func (wrap *ScriptWrapper) Close() {

// Changes returns the changes in the environment and working dir after the hook script runs
func (wrap *ScriptWrapper) Changes() (HookScriptChanges, error) {
beforeEnvContents, err := ioutil.ReadFile(wrap.beforeEnvFile.Name())
beforeEnvContents, err := os.ReadFile(wrap.beforeEnvFile.Name())
if err != nil {
return HookScriptChanges{}, fmt.Errorf("Failed to read \"%s\" (%s)", wrap.beforeEnvFile.Name(), err)
}

afterEnvContents, err := ioutil.ReadFile(wrap.afterEnvFile.Name())
afterEnvContents, err := os.ReadFile(wrap.afterEnvFile.Name())
if err != nil {
return HookScriptChanges{}, fmt.Errorf("Failed to read \"%s\" (%s)", wrap.afterEnvFile.Name(), err)
}

beforeEnv := env.FromExport(string(beforeEnvContents))
afterEnv := env.FromExport(string(afterEnvContents))
var (
beforeEnv env.Environment
afterEnv env.Environment
)
err = json.Unmarshal(beforeEnvContents, &beforeEnv)
if err != nil {
return HookScriptChanges{}, fmt.Errorf("failed to unmarshal before env file: %w, file contents: %q", err, string(beforeEnvContents))
}

err = json.Unmarshal(afterEnvContents, &afterEnv)
if err != nil {
return HookScriptChanges{}, fmt.Errorf("failed to unmarshal after env file: %w, file contents: %q", err, string(afterEnvContents))
}

if afterEnv.Length() == 0 {
return HookScriptChanges{}, &HookExitError{hookPath: wrap.hookPath}
Expand All @@ -242,7 +253,7 @@ func (wrap *ScriptWrapper) Changes() (HookScriptChanges, error) {
// Pluck the after wd from the diff before removing the key from the diff
afterWd := ""
if afterWd == "" {
afterWd, _ = diff.Added[hookWorkingDirEnv]
afterWd = diff.Added[hookWorkingDirEnv]
}
if afterWd == "" {
if change, ok := diff.Changed[hookWorkingDirEnv]; ok {
Expand Down
1 change: 1 addition & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ func main() {
clicommand.StepUpdateCommand,
},
},
clicommand.EnvCommand,
clicommand.BootstrapCommand,
}

Expand Down

0 comments on commit a5c79cd

Please sign in to comment.