Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apply dir overrides from agent config #894

Merged
merged 9 commits into from
Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions _tests/integration/agent-config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
bitrise_dirs:
BITRISE_DATA_HOME_DIR: $INTEGRATION_TEST_BINARY_PATH/../agent
BITRISE_SOURCE_DIR: $INTEGRATION_TEST_BINARY_PATH/../agent/workspace/$BITRISE_APP_SLUG
BITRISE_DEPLOY_DIR: $INTEGRATION_TEST_BINARY_PATH/../agent/$BITRISE_APP_SLUG/$BITRISE_BUILD_SLUG/artifacts
BITRISE_TEST_DEPLOY_DIR: $INTEGRATION_TEST_BINARY_PATH/../agent/$BITRISE_APP_SLUG/$BITRISE_BUILD_SLUG/test_results

hooks:
cleanup_on_workflow_start:
- $BITRISE_DEPLOY_DIR

cleanup_on_workflow_end:
- $BITRISE_TEST_DEPLOY_DIR
31 changes: 31 additions & 0 deletions _tests/integration/agent_config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package integration

import (
"os"
"testing"

"github.com/bitrise-io/go-utils/command"
"github.com/bitrise-io/go-utils/pathutil"
"github.com/stretchr/testify/require"
)

func Test_AgentConfigTest(t *testing.T) {
cfg, err := os.ReadFile("agent-config.yml")
require.NoError(t, err)

absPath, err := pathutil.AbsPath("$HOME/.bitrise/agent-config.yml")
require.NoError(t, err)

err = os.WriteFile(absPath, cfg, 0644)
require.NoError(t, err)
defer func () {
os.Remove(absPath)
}()

t.Setenv("BITRISE_APP_SLUG", "ef7a9665e8b6408b")
t.Setenv("BITRISE_BUILD_SLUG", "80b66786-d011-430f-9c68-00e9416a7325")

cmd := command.New(binPath(), "run", "test", "--config", "agent_config_test_bitrise.yml")
out, err := cmd.RunAndReturnTrimmedCombinedOutput()
require.NoError(t, err, out)
}
37 changes: 37 additions & 0 deletions _tests/integration/agent_config_test_bitrise.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
format_version: 13
default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git

workflows:
test:
steps:
- script:
inputs:
- content: |
set -ex
if [[ "$BITRISE_DATA_HOME_DIR" != $(dirname $INTEGRATION_TEST_BINARY_PATH)/agent ]]; then
echo "BITRISE_DATA_HOME_DIR does not point to the expected directory"
exit 1
fi

ls $BITRISE_DATA_HOME_DIR

if [[ "$BITRISE_SOURCE_DIR" != $(dirname $INTEGRATION_TEST_BINARY_PATH)/agent/workspace/$BITRISE_APP_SLUG ]]; then
echo "BITRISE_SOURCE_DIR does not point to the expected directory"
exit 1
fi

ls $BITRISE_SOURCE_DIR

if [[ "$BITRISE_DEPLOY_DIR" != $(dirname $INTEGRATION_TEST_BINARY_PATH)/agent/$BITRISE_APP_SLUG/$BITRISE_BUILD_SLUG/artifacts ]]; then
echo "BITRISE_DEPLOY_DIR does not point to the expected directory"
exit 1
fi

ls $BITRISE_DEPLOY_DIR

if [[ "$BITRISE_TEST_DEPLOY_DIR" != $(dirname $INTEGRATION_TEST_BINARY_PATH)/agent/$BITRISE_APP_SLUG/$BITRISE_BUILD_SLUG/test_results ]]; then
echo "BITRISE_TEST_DEPLOY_DIR does not point to the expected directory"
exit 1
fi

ls $BITRISE_TEST_DEPLOY_DIR
6 changes: 5 additions & 1 deletion _tests/integration/log_format_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"regexp"
"strings"
"testing"
"time"

"github.com/bitrise-io/bitrise/log"
"github.com/bitrise-io/bitrise/models"
Expand Down Expand Up @@ -133,7 +134,7 @@ func convertBitriseStartedEventLog(line []byte) (string, error) {
}

var buf bytes.Buffer
logger := log.NewLogger(log.LoggerOpts{LoggerType: log.ConsoleLogger, Writer: &buf})
logger := log.NewLogger(log.LoggerOpts{LoggerType: log.ConsoleLogger, Writer: &buf, TimeProvider: time.Now})
logger.PrintBitriseStartedEvent(eventLog.Content)

return buf.String(), nil
Expand Down Expand Up @@ -260,5 +261,8 @@ func replaceVariableParts(line string) string {
totalRunTimeRegexp := regexp.MustCompile(`(\| Total runtime: .+ \|)`)
line = totalRunTimeRegexp.ReplaceAllString(line, "[REPLACED]")

invocationStartRegexp := regexp.MustCompile(`Invocation started at .+`)
line = invocationStartRegexp.ReplaceAllString(line, "[REPLACED]")

return line
}
4 changes: 4 additions & 0 deletions cli/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,10 @@ func (r WorkflowRunner) runWorkflows(tracker analytics.Tracker) (models.BuildRun

buildIDProperties := coreanalytics.Properties{analytics.BuildExecutionID: uuid.Must(uuid.NewV4()).String()}

if err := configs.RegisterAgentOverrides(); err != nil {
return models.BuildRunResultsModel{}, fmt.Errorf("apply agent config: %s", err)
}
Comment on lines +225 to +227
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now this checks happens in the workflow execution process but to me this seems like not directly linked to it. If we can then I would put this somewhere earlier in the chain. Like as high level as we can put it. Maybe before this line:

runner := NewWorkflowRunner(*config)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting, my mental model is that all of these agent-specific modifications are only relevant to the bitrise run subcommand. Do you think it should apply to other subcommands too?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I agree with you that this is bitrise run specific. The code I linked is in the run.go file which is hosting the bitrise run subcommand:

bitrise/cli/run.go

Lines 50 to 71 in cbfa1bb

var runCommand = cli.Command{
Name: "run",
Aliases: []string{"r"},
Usage: "Runs a specified Workflow.",
Action: run,
Flags: []cli.Flag{
// cli params
cli.StringFlag{Name: WorkflowKey, Usage: "workflow id to run."},
cli.StringFlag{Name: ConfigKey + ", " + configShortKey, Usage: "Path where the workflow config file is located."},
cli.StringFlag{Name: InventoryKey + ", " + inventoryShortKey, Usage: "Path of the inventory file."},
cli.BoolFlag{Name: secretFilteringFlag, Usage: "Hide secret values from the log."},
// cli params used in CI mode
cli.StringFlag{Name: JSONParamsKey, Usage: "Specify command flags with json string-string hash."},
cli.StringFlag{Name: JSONParamsBase64Key, Usage: "Specify command flags with base64 encoded json string-string hash."},
cli.StringFlag{Name: OutputFormatKey, Usage: "Log format. Available values: json, console"},
// should deprecate
cli.StringFlag{Name: ConfigBase64Key, Usage: "base64 encoded config data."},
cli.StringFlag{Name: InventoryBase64Key, Usage: "base64 encoded inventory data."},
},
}

What I was referring to is that where this logic is now is a place where the actual execution flow is calculated inside the WorkflowRunner struct. This agent dir override seemed like something this runner should not be even aware and that is why I thought moving it out to the very beginning of the run subcommand execution could make sense.


log.PrintBitriseStartedEvent(plan)

// Run workflows
Expand Down
2 changes: 0 additions & 2 deletions cli/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ var setupCommand = cli.Command{
}

func setup(c *cli.Context) error {
log.PrintBitriseASCIIArt()

fullMode := c.Bool("full")
cleanMode := c.Bool("clean")

Expand Down
98 changes: 80 additions & 18 deletions configs/agent_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import (
"os"
"path/filepath"

"github.com/bitrise-io/bitrise/log"
"github.com/bitrise-io/go-utils/pathutil"
"gopkg.in/yaml.v2"
)

const agentConfigFileName = "agent-config.yml"
const defaultSourceDir = "workspace"
const defaultDeployDir = "$BITRISE_APP_SLUG/$BITRISE_BUILD_SLUG/artifacts"
const defaultTestDeployDir = "$BITRISE_APP_SLUG/$BITRISE_BUILD_SLUG/test_results"
Expand Down Expand Up @@ -53,6 +55,62 @@ type AgentHooks struct {
DoOnWorkflowEnd string `yaml:"do_on_workflow_end"`
}

func RegisterAgentOverrides() error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to closely look at and compare all of 4 sections of the dir handling sections inside this function to discover that they are exactly the same. This made me wonder if it would be good to group them and create a single logic with multiple input parameters for them to indicate that they are the same.

Something like

params := []struct {
	name   string
	dir    string
	envKey string
}{
	{
		name:   "BITRISE_DATA_HOME_DIR",
		dir:    config.BitriseDirs.BitriseDataHomeDir,
		envKey: BitriseDataHomeDirEnvKey,
	},
	{
		name:   "BITRISE_SOURCE_DIR",
		dir:    config.BitriseDirs.SourceDir,
		envKey: BitriseSourceDirEnvKey,
	},
	{
		name:   "BITRISE_DEPLOY_DIR",
		dir:    config.BitriseDirs.DeployDir,
		envKey: BitriseDeployDirEnvKey,
	},
	{
		name:   "BITRISE_TEST_DEPLOY_DIR",
		dir:    config.BitriseDirs.TestDeployDir,
		envKey: BitriseTestDeployDirEnvKey,
	},
}
for _, param := range params {
	err = pathutil.EnsureDirExist(param.dir)
	if err != nil {
		return fmt.Errorf("can't create %s: %w", param.name, err)
	}
	err = os.Setenv(param.envKey, param.dir)
	if err != nil {
		return fmt.Errorf("set %s: %w", param.name, err)
	}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, I fully agree, please take a look now

if !hasAgentConfigFile() {
return nil
}

file := filepath.Join(GetBitriseHomeDirPath(), agentConfigFileName)

log.Print("")
log.Info("Running in agent mode")
log.Printf("Config file: %s", file)

config, err := readAgentConfig(file)
if err != nil {
return fmt.Errorf("agent config file: %w", err)
}

params := []struct {
dir string
envKey string
}{
{
dir: config.BitriseDirs.BitriseDataHomeDir,
envKey: BitriseDataHomeDirEnvKey,
},
{
dir: config.BitriseDirs.SourceDir,
envKey: BitriseSourceDirEnvKey,
},
{
dir: config.BitriseDirs.DeployDir,
envKey: BitriseDeployDirEnvKey,
},
{
dir: config.BitriseDirs.TestDeployDir,
envKey: BitriseTestDeployDirEnvKey,
},
}
for _, param := range params {
err = pathutil.EnsureDirExist(param.dir)
if err != nil {
return fmt.Errorf("can't create %s: %w", param.envKey, err)
}
err = os.Setenv(param.envKey, param.dir)
if err != nil {
return fmt.Errorf("set %s: %w", param.envKey, err)
}
}

return nil
}

func hasAgentConfigFile() bool {
exists, _ := pathutil.IsPathExists(filepath.Join(GetBitriseHomeDirPath(), agentConfigFileName))
return exists
}

func readAgentConfig(configFile string) (AgentConfig, error) {
fileContent, err := os.ReadFile(configFile)
if err != nil {
Expand All @@ -65,76 +123,80 @@ func readAgentConfig(configFile string) (AgentConfig, error) {
return AgentConfig{}, err
}

expandedBitriseDataHomeDir, err := expandPath(config.BitriseDirs.BitriseDataHomeDir)
dataHomeDir, err := normalizePath(config.BitriseDirs.BitriseDataHomeDir)
if err != nil {
return AgentConfig{}, fmt.Errorf("expand BITRISE_DATA_HOME_DIR value: %s", err)
}
config.BitriseDirs.BitriseDataHomeDir = expandedBitriseDataHomeDir
config.BitriseDirs.BitriseDataHomeDir = dataHomeDir

// BITRISE_SOURCE_DIR
if config.BitriseDirs.SourceDir == "" {
config.BitriseDirs.SourceDir = filepath.Join(config.BitriseDirs.BitriseDataHomeDir, defaultSourceDir)
}
expandedSourceDir, err := expandPath(config.BitriseDirs.SourceDir)
sourceDir, err := normalizePath(config.BitriseDirs.SourceDir)
if err != nil {
return AgentConfig{}, fmt.Errorf("expand BITRISE_SOURCE_DIR value: %s", err)
}
config.BitriseDirs.SourceDir = expandedSourceDir
config.BitriseDirs.SourceDir = sourceDir

// BITRISE_DEPLOY_DIR
if config.BitriseDirs.DeployDir == "" {
config.BitriseDirs.DeployDir = filepath.Join(config.BitriseDirs.BitriseDataHomeDir, defaultDeployDir)
}
expandedDeployDir, err := expandPath(config.BitriseDirs.DeployDir)
deployDir, err := normalizePath(config.BitriseDirs.DeployDir)
if err != nil {
return AgentConfig{}, fmt.Errorf("expand BITRISE_DEPLOY_DIR value: %s", err)
}
config.BitriseDirs.DeployDir = expandedDeployDir
config.BitriseDirs.DeployDir = deployDir

// BITRISE_TEST_DEPLOY_DIR
if config.BitriseDirs.TestDeployDir == "" {
config.BitriseDirs.TestDeployDir = filepath.Join(config.BitriseDirs.BitriseDataHomeDir, defaultTestDeployDir)
}
expandedTestDeployDir, err := expandPath(config.BitriseDirs.TestDeployDir)
testDeployDir, err := normalizePath(config.BitriseDirs.TestDeployDir)
if err != nil {
return AgentConfig{}, fmt.Errorf("expand BITRISE_TEST_DEPLOY_DIR value: %s", err)
}
config.BitriseDirs.TestDeployDir = expandedTestDeployDir
config.BitriseDirs.TestDeployDir = testDeployDir

// Hooks
if config.Hooks.DoOnWorkflowStart != "" {
expandedDoOnWorkflowStart, err := expandPath(config.Hooks.DoOnWorkflowStart)
doOnWorkflowStart, err := normalizePath(config.Hooks.DoOnWorkflowStart)
if err != nil {
return AgentConfig{}, fmt.Errorf("expand do_on_workflow_start value: %s", err)
}
doOnWorkflowStartExists, err := pathutil.IsPathExists(expandedDoOnWorkflowStart)
doOnWorkflowStartExists, err := pathutil.IsPathExists(doOnWorkflowStart)
if err != nil {
return AgentConfig{}, err
}
if !doOnWorkflowStartExists {
return AgentConfig{}, fmt.Errorf("do_on_workflow_start path does not exist: %s", expandedDoOnWorkflowStart)
return AgentConfig{}, fmt.Errorf("do_on_workflow_start path does not exist: %s", doOnWorkflowStart)
}
config.Hooks.DoOnWorkflowStart = expandedDoOnWorkflowStart
config.Hooks.DoOnWorkflowStart = doOnWorkflowStart
}

if config.Hooks.DoOnWorkflowEnd != "" {
expandedDoOnWorkflowEnd, err := expandPath(config.Hooks.DoOnWorkflowEnd)
doOnWorkflowEnd, err := normalizePath(config.Hooks.DoOnWorkflowEnd)
if err != nil {
return AgentConfig{}, fmt.Errorf("expand do_on_workflow_end value: %s", err)
}
doOnWorkflowEndExists, err := pathutil.IsPathExists(expandedDoOnWorkflowEnd)
doOnWorkflowEndExists, err := pathutil.IsPathExists(doOnWorkflowEnd)
if err != nil {
return AgentConfig{}, err
}
if !doOnWorkflowEndExists {
return AgentConfig{}, fmt.Errorf("do_on_workflow_end path does not exist: %s", expandedDoOnWorkflowEnd)
return AgentConfig{}, fmt.Errorf("do_on_workflow_end path does not exist: %s", doOnWorkflowEnd)
}
config.Hooks.DoOnWorkflowEnd = expandedDoOnWorkflowEnd
config.Hooks.DoOnWorkflowEnd = doOnWorkflowEnd
}

return config, nil
}

func expandPath(path string) (string, error) {
return pathutil.ExpandTilde(os.ExpandEnv(path))
func normalizePath(path string) (string, error) {
expanded, err := pathutil.ExpandTilde(os.ExpandEnv(path))
if err != nil {
return "", err
}
return pathutil.AbsPath(expanded)
}
8 changes: 0 additions & 8 deletions configs/configs.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,19 +108,16 @@ func saveBitriseConfig(config ConfigModel) error {
return fileutil.WriteBytesToFile(configPth, bytes)
}

// DeleteBitriseConfigDir ...
func DeleteBitriseConfigDir() error {
confDirPth := GetBitriseHomeDirPath()
return os.RemoveAll(confDirPth)
}

// EnsureBitriseConfigDirExists ...
func EnsureBitriseConfigDirExists() error {
confDirPth := GetBitriseHomeDirPath()
return pathutil.EnsureDirExist(confDirPth)
}

// CheckIsCLIUpdateCheckRequired ...
func CheckIsCLIUpdateCheckRequired() bool {
config, err := loadBitriseConfig()
if err != nil {
Expand All @@ -135,7 +132,6 @@ func CheckIsCLIUpdateCheckRequired() bool {
return false
}

// SaveCLIUpdateCheck ...
func SaveCLIUpdateCheck() error {
config, err := loadBitriseConfig()
if err != nil {
Expand All @@ -147,7 +143,6 @@ func SaveCLIUpdateCheck() error {
return saveBitriseConfig(config)
}

// CheckIsPluginUpdateCheckRequired ...
func CheckIsPluginUpdateCheckRequired(plugin string) bool {
config, err := loadBitriseConfig()
if err != nil {
Expand All @@ -162,7 +157,6 @@ func CheckIsPluginUpdateCheckRequired(plugin string) bool {
return false
}

// SavePluginUpdateCheck ...
func SavePluginUpdateCheck(plugin string) error {
config, err := loadBitriseConfig()
if err != nil {
Expand All @@ -178,7 +172,6 @@ func SavePluginUpdateCheck(plugin string) error {
return saveBitriseConfig(config)
}

// CheckIsSetupWasDoneForVersion ...
func CheckIsSetupWasDoneForVersion(ver string) bool {
config, err := loadBitriseConfig()
if err != nil {
Expand All @@ -187,7 +180,6 @@ func CheckIsSetupWasDoneForVersion(ver string) bool {
return (config.SetupVersion == ver)
}

// SaveSetupSuccessForVersion ...
func SaveSetupSuccessForVersion(ver string) error {
config, err := loadBitriseConfig()
if err != nil {
Expand Down
Loading