// GetStepFromNewSteplib ... func GetStepFromNewSteplib(stepID, stepLibGitURI string) (stepmanModels.StepModel, string, error) { // Activate step - get step.yml tempStepCloneDirPath, err := pathutil.NormalizedOSTempDirPath("step_clone") if err != nil { return stepmanModels.StepModel{}, "", err } tempStepYMLDirPath, err := pathutil.NormalizedOSTempDirPath("step_yml") if err != nil { return stepmanModels.StepModel{}, "", err } tempStepYMLFilePath := path.Join(tempStepYMLDirPath, "step.yml") // Stepman if err := bitrise.StepmanSetup(stepLibGitURI); err != nil { return stepmanModels.StepModel{}, "", err } stepInfo, err := bitrise.StepmanStepInfo(stepLibGitURI, stepID, "") if err != nil { // May StepLib should be updated log.Info("Step info not found in StepLib (%s) -- Updating ...") if err := bitrise.StepmanUpdate(stepLibGitURI); err != nil { return stepmanModels.StepModel{}, "", err } stepInfo, err = bitrise.StepmanStepInfo(stepLibGitURI, stepID, "") if err != nil { return stepmanModels.StepModel{}, "", err } } stepVersion := stepInfo.StepVersion if err := bitrise.StepmanActivate(stepLibGitURI, stepID, "", tempStepCloneDirPath, tempStepYMLFilePath); err != nil { return stepmanModels.StepModel{}, "", err } specStep, err := ReadSpecStep(tempStepYMLFilePath) if err != nil { return stepmanModels.StepModel{}, "", err } // Cleanup if err := cmdex.RemoveDir(tempStepCloneDirPath); err != nil { return stepmanModels.StepModel{}, "", errors.New(fmt.Sprint("Failed to remove step clone dir: ", err)) } if err := cmdex.RemoveDir(tempStepYMLDirPath); err != nil { return stepmanModels.StepModel{}, "", errors.New(fmt.Sprint("Failed to remove step clone dir: ", err)) } return specStep, stepVersion, nil }
func TestClonePluginSrc(t *testing.T) { t.Log("example plugin - latest version") { pluginSource := examplePluginGitURL versionTag := "" destinationDir, err := pathutil.NormalizedOSTempDirPath("TestClonePluginSrc") require.NoError(t, err) exist, err := pathutil.IsPathExists(destinationDir) require.NoError(t, err) if exist { err := os.RemoveAll(destinationDir) require.NoError(t, err) } version, hash, err := clonePluginSrc(pluginSource, versionTag, destinationDir) require.NoError(t, err) require.NotNil(t, version) require.NotEmpty(t, hash) exist, err = pathutil.IsPathExists(destinationDir) require.NoError(t, err) require.Equal(t, true, exist) } t.Log("example plugin - 0.9.0 version") { pluginSource := examplePluginGitURL versionTag := "0.9.0" destinationDir, err := pathutil.NormalizedOSTempDirPath("TestClonePluginSrc") require.NoError(t, err) exist, err := pathutil.IsPathExists(destinationDir) require.NoError(t, err) if exist { err := os.RemoveAll(destinationDir) require.NoError(t, err) } version, hash, err := clonePluginSrc(pluginSource, versionTag, destinationDir) require.NoError(t, err) require.NotNil(t, version) require.Equal(t, "0.9.0", version.String()) require.NotEmpty(t, hash) exist, err = pathutil.IsPathExists(destinationDir) require.NoError(t, err) require.Equal(t, true, exist) } }
func TestDownloadPluginBin(t *testing.T) { t.Log("example plugin bin - ") { pluginBinURL := analyticsPluginBinURL destinationDir, err := pathutil.NormalizedOSTempDirPath("TestDownloadPluginBin") require.NoError(t, err) exist, err := pathutil.IsPathExists(destinationDir) require.NoError(t, err) if exist { err := os.RemoveAll(destinationDir) require.NoError(t, err) } require.NoError(t, os.MkdirAll(destinationDir, 0777)) destinationPth := filepath.Join(destinationDir, "example") require.NoError(t, downloadPluginBin(pluginBinURL, destinationPth)) exist, err = pathutil.IsPathExists(destinationPth) require.NoError(t, err) require.Equal(t, true, exist) } }
func saveRawOutputToLogFile(rawXcodebuildOutput string, isRunSuccess bool) error { tmpDir, err := pathutil.NormalizedOSTempDirPath("xcodebuild-output") if err != nil { return fmt.Errorf("Failed to create temp dir, error: %s", err) } logFileName := "raw-xcodebuild-output.log" logPth := filepath.Join(tmpDir, logFileName) if err := fileutil.WriteStringToFile(logPth, rawXcodebuildOutput); err != nil { return fmt.Errorf("Failed to write xcodebuild output to file, error: %s", err) } if !isRunSuccess { deployDir := os.Getenv("BITRISE_DEPLOY_DIR") if deployDir == "" { return errors.New("No BITRISE_DEPLOY_DIR found") } deployPth := filepath.Join(deployDir, logFileName) if err := cmdex.CopyFile(logPth, deployPth); err != nil { return fmt.Errorf("Failed to copy xcodebuild output log file from (%s) to (%s), error: %s", logPth, deployPth, err) } logPth = deployPth } if err := cmd.ExportEnvironmentWithEnvman("BITRISE_XCODE_RAW_TEST_RESULT_TEXT_PATH", logPth); err != nil { log.Warn("Failed to export: BITRISE_XCODE_RAW_TEST_RESULT_TEXT_PATH, error: %s", err) } return nil }
func auditStepModelBeforeSharePullRequest(step models.StepModel, stepID, version string) error { if err := step.Audit(); err != nil { return fmt.Errorf("Failed to audit step infos, error: %s", err) } pth, err := pathutil.NormalizedOSTempDirPath(stepID + version) if err != nil { return fmt.Errorf("Failed to create a temporary directory for the step's audit, error: %s", err) } if step.Source == nil { return fmt.Errorf("Missing Source porperty") } err = retry.Times(2).Wait(3 * time.Second).Try(func(attempt uint) error { return cmdex.GitCloneTag(step.Source.Git, pth, version) }) if err != nil { return fmt.Errorf("Failed to git-clone the step (url: %s) version (%s), error: %s", step.Source.Git, version, err) } latestCommit, err := cmdex.GitGetLatestCommitHashOnHead(pth) if err != nil { return fmt.Errorf("Failed to get git-latest-commit-hash, error: %s", err) } if latestCommit != step.Source.Commit { return fmt.Errorf("Step commit hash (%s) should be the latest commit hash (%s) on git tag", step.Source.Commit, latestCommit) } return nil }
func initBitriseWorkPaths() error { bitriseWorkDirPath, err := pathutil.NormalizedOSTempDirPath("bitrise") if err != nil { return err } if exist, err := pathutil.IsPathExists(bitriseWorkDirPath); err != nil { return err } else if !exist { if err := os.MkdirAll(bitriseWorkDirPath, 0777); err != nil { return err } } BitriseWorkDirPath = bitriseWorkDirPath bitriseWorkStepsDirPath, err := filepath.Abs(filepath.Join(BitriseWorkDirPath, "step_src")) if err != nil { return err } if exist, err := pathutil.IsPathExists(bitriseWorkStepsDirPath); err != nil { return err } else if !exist { if err := os.MkdirAll(bitriseWorkStepsDirPath, 0777); err != nil { return err } } BitriseWorkStepsDirPath = bitriseWorkStepsDirPath return nil }
func goBuildInIsolation(packageName, srcPath, outputBinPath string) error { log.Debugf("=> Installing package (%s) to path (%s) ...", packageName, srcPath) workspaceRootPath, err := pathutil.NormalizedOSTempDirPath("bitrise-go-toolkit") if err != nil { return fmt.Errorf("Failed to create root directory of isolated workspace, error: %s", err) } log.Debugln("=> Using sandboxed workspace:", workspaceRootPath) // origGOPATH := os.Getenv("GOPATH") // if origGOPATH == "" { // return fmt.Errorf("You don't have a GOPATH environment - please set it; GOPATH/bin will be symlinked") // } // log.Debugln("=> Symlink GOPATH/bin into sandbox ...") // if err := gows.CreateGopathBinSymlink(origGOPATH, workspaceRootPath); err != nil { // return fmt.Errorf("Failed to create GOPATH/bin symlink, error: %s", err) // } // log.Debugln(" [DONE]") fullPackageWorkspacePath := filepath.Join(workspaceRootPath, "src", packageName) log.Debugf("=> Creating Symlink: (%s) -> (%s)", srcPath, fullPackageWorkspacePath) if err := gows.CreateOrUpdateSymlink(srcPath, fullPackageWorkspacePath); err != nil { return fmt.Errorf("Failed to create Project->Workspace symlink, error: %s", err) } log.Debugf(" [DONE] Symlink is in place") log.Debugln("=> Building package " + packageName + " ...") { isInstallRequired, _, goConfig, err := selectGoConfiguration() if err != nil { return fmt.Errorf("Failed to select an appropriate Go installation for compiling the step, error: %s", err) } if isInstallRequired { return fmt.Errorf("Failed to select an appropriate Go installation for compiling the step, error: %s", "Found Go version is older than required. Please run 'bitrise setup' to check and install the required version") } cmd := gows.CreateCommand(workspaceRootPath, workspaceRootPath, goConfig.GoBinaryPath, "build", "-o", outputBinPath, packageName) cmd.Env = append(cmd.Env, "GOROOT="+goConfig.GOROOT) if err := cmd.Run(); err != nil { return fmt.Errorf("Failed to install package, error: %s", err) } } log.Debugln(" [DONE] Package successfully installed") log.Debugln("=> Delete isolated workspace ...") { if err := os.RemoveAll(workspaceRootPath); err != nil { return fmt.Errorf("Failed to delete temporary isolated workspace, error: %s", err) } } log.Debugln(" [DONE]") return nil }
// WritePlistToTmpFile ... func WritePlistToTmpFile(options map[string]interface{}) (string, error) { tmpDir, err := pathutil.NormalizedOSTempDirPath("output") if err != nil { return "", fmt.Errorf("failed to create temp dir, error: %s", err) } pth := filepath.Join(tmpDir, "exportOptions.plist") if err := WritePlistToFile(options, pth); err != nil { return "", fmt.Errorf("failed to write to file options, error: %s", err) } return pth, nil }
func TestEnvmanJSONPrint(t *testing.T) { // Initialized envstore -- Err should empty, output filled testDirPth, err := pathutil.NormalizedOSTempDirPath("test_env_store") require.Equal(t, nil, err) envstorePth := path.Join(testDirPth, "envstore.yml") require.Equal(t, nil, EnvmanInitAtPath(envstorePth)) outStr, err := EnvmanJSONPrint(envstorePth) require.Equal(t, nil, err) require.NotEqual(t, "", outStr) // Not initialized envstore -- Err should filled, output empty testDirPth, err = pathutil.NormalizedOSTempDirPath("test_env_store") require.Equal(t, nil, err) envstorePth = path.Join("test_env_store", "envstore.yml") outStr, err = EnvmanJSONPrint(envstorePth) require.NotEqual(t, nil, err) require.Equal(t, "", outStr) }
// InitPaths ... func InitPaths() error { if err := initBitriseWorkPaths(); err != nil { return fmt.Errorf("Failed to init bitrise paths: %s", err) } inputEnvstorePath, err := filepath.Abs(path.Join(BitriseWorkDirPath, "input_envstore.yml")) if err != nil { return fmt.Errorf("Failed to set envstore path: %s", err) } InputEnvstorePath = inputEnvstorePath outputEnvstorePath, err := filepath.Abs(path.Join(BitriseWorkDirPath, "output_envstore.yml")) if err != nil { return fmt.Errorf("Failed to set envstore path: %s", err) } OutputEnvstorePath = outputEnvstorePath formoutPath, err := filepath.Abs(path.Join(BitriseWorkDirPath, "formatted_output.md")) if err != nil { return fmt.Errorf("Failed to set formatted output path: %s", err) } FormattedOutputPath = formoutPath currentDir, err := filepath.Abs("./") if err != nil { return fmt.Errorf("Failed to set current dir: %s", err) } CurrentDir = currentDir // BITRISE_SOURCE_DIR if os.Getenv(BitriseSourceDirEnvKey) == "" { if err := os.Setenv(BitriseSourceDirEnvKey, currentDir); err != nil { return fmt.Errorf("Failed to set BITRISE_SOURCE_DIR: %s", err) } } // BITRISE_DEPLOY_DIR if os.Getenv(BitriseDeployDirEnvKey) == "" { deployDir, err := pathutil.NormalizedOSTempDirPath("deploy") if err != nil { return fmt.Errorf("Failed to set deploy dir: %s", err) } if err := os.Setenv(BitriseDeployDirEnvKey, deployDir); err != nil { return fmt.Errorf("Failed to set BITRISE_DEPLOY_DIR: %s", err) } } return nil }
// ExportOutputDirAsZip ... func ExportOutputDirAsZip(sourceDirPth, destinationPth, envKey string) error { tmpDir, err := pathutil.NormalizedOSTempDirPath("__export_tmp_dir__") if err != nil { return err } base := filepath.Base(sourceDirPth) tmpZipFilePth := filepath.Join(tmpDir, base+".zip") if err := zip(sourceDirPth, tmpZipFilePth); err != nil { return err } return ExportOutputFile(tmpZipFilePth, destinationPth, envKey) }
func TestNewHelper(t *testing.T) { t.Log("it fails if destinationDir empty") { helper, err := NewHelper("", "https://github.com/bitrise-samples/git-clone-test.git", false) require.Error(t, err) require.Equal(t, "", helper.destinationDir) require.Equal(t, "", helper.remoteURI) } t.Log("it fails if remote URI empty") { helper, err := NewHelper("./", "", false) require.Error(t, err) require.Equal(t, "", helper.destinationDir) require.Equal(t, "", helper.remoteURI) } t.Log("it fails if remote URI empty") { helper, err := NewHelper("./", "", false) require.Error(t, err) require.Equal(t, "", helper.destinationDir) require.Equal(t, "", helper.remoteURI) } t.Log("it creates destination dir if not exist") { tmpDir, err := pathutil.NormalizedOSTempDirPath("__test__") require.NoError(t, err) destinationDir := filepath.Join(tmpDir, "dst") exist, err := pathutil.IsDirExists(destinationDir) require.NoError(t, err) require.Equal(t, false, exist) helper, err := NewHelper(destinationDir, "https://github.com/bitrise-samples/git-clone-test.git", false) require.NoError(t, err) require.Equal(t, destinationDir, helper.destinationDir) require.Equal(t, "https://github.com/bitrise-samples/git-clone-test.git", helper.remoteURI) exist, err = pathutil.IsDirExists(destinationDir) require.NoError(t, err) require.Equal(t, true, exist) require.NoError(t, os.RemoveAll(tmpDir)) } }
func Test_ValidateTestJSON(t *testing.T) { tmpDir, err := pathutil.NormalizedOSTempDirPath("__validate_test__") require.NoError(t, err) defer func() { require.NoError(t, os.RemoveAll(tmpDir)) }() t.Log("valid bitrise.yml") { cmd := cmdex.NewCommand(binPath(), "validate", "-c", "trigger_params_test_bitrise.yml", "--format", "json") out, err := cmd.RunAndReturnTrimmedCombinedOutput() require.NoError(t, err) require.Equal(t, "{\"data\":{\"config\":{\"is_valid\":true}}}", out) } t.Log("valid - warning test - `-p` flag is deprecated") { cmd := cmdex.NewCommand(binPath(), "validate", "-p", "trigger_params_test_bitrise.yml", "--format", "json") out, err := cmd.RunAndReturnTrimmedCombinedOutput() require.NoError(t, err) require.Equal(t, "{\"data\":{\"config\":{\"is_valid\":true}},\"warnings\":[\"'path' key is deprecated, use 'config' instead!\"]}", out) } t.Log("valid - invalid workflow id") { configPth := filepath.Join(tmpDir, "bitrise.yml") require.NoError(t, fileutil.WriteStringToFile(configPth, invalidWorkflowIDBitriseYML)) cmd := cmdex.NewCommand(binPath(), "validate", "-c", configPth, "--format", "json") out, err := cmd.RunAndReturnTrimmedCombinedOutput() require.NoError(t, err) expected := "{\"data\":{\"config\":{\"is_valid\":true,\"warnings\":[\"invalid workflow ID (invalid:id): doesn't conform to: [A-Za-z0-9-_.]\"]}}}" require.Equal(t, expected, out) } t.Log("invalid - empty bitrise.yml") { configPth := filepath.Join(tmpDir, "bitrise.yml") require.NoError(t, fileutil.WriteStringToFile(configPth, emptyBitriseYML)) cmd := cmdex.NewCommand(binPath(), "validate", "-c", configPth, "--format", "json") out, err := cmd.RunAndReturnTrimmedCombinedOutput() require.Error(t, err, out) expected := fmt.Sprintf("{\"data\":{\"config\":{\"is_valid\":false,\"error\":\"Config (path:%s) is not valid: empty config\"}}}", configPth) require.Equal(t, expected, out) } }
func Test_ValidateTest(t *testing.T) { tmpDir, err := pathutil.NormalizedOSTempDirPath("__validate_test__") require.NoError(t, err) defer func() { require.NoError(t, os.RemoveAll(tmpDir)) }() t.Log("valid bitrise.yml") { cmd := cmdex.NewCommand(binPath(), "validate", "-c", "trigger_params_test_bitrise.yml") out, err := cmd.RunAndReturnTrimmedCombinedOutput() require.NoError(t, err) require.Equal(t, "Config is valid: \x1b[32;1mtrue\x1b[0m", out) } t.Log("valid - warning test - `-p` flag is deprecated") { cmd := cmdex.NewCommand(binPath(), "validate", "-p", "trigger_params_test_bitrise.yml") out, err := cmd.RunAndReturnTrimmedCombinedOutput() require.NoError(t, err) require.Equal(t, "Config is valid: \x1b[32;1mtrue\x1b[0m\nWarning(s):\n- 'path' key is deprecated, use 'config' instead!", out) } t.Log("valid - invalid workflow id") { configPth := filepath.Join(tmpDir, "bitrise.yml") require.NoError(t, fileutil.WriteStringToFile(configPth, invalidWorkflowIDBitriseYML)) cmd := cmdex.NewCommand(binPath(), "validate", "-c", configPth) out, err := cmd.RunAndReturnTrimmedCombinedOutput() require.NoError(t, err) expected := "Config is valid: \x1b[32;1mtrue\x1b[0m\nWarning(s):\n- invalid workflow ID (invalid:id): doesn't conform to: [A-Za-z0-9-_.]" require.Equal(t, expected, out) } t.Log("invalid - empty bitrise.yml") { configPth := filepath.Join(tmpDir, "bitrise.yml") require.NoError(t, fileutil.WriteStringToFile(configPth, emptyBitriseYML)) cmd := cmdex.NewCommand(binPath(), "validate", "-c", configPth) out, err := cmd.RunAndReturnTrimmedCombinedOutput() require.Error(t, err, out) expected := fmt.Sprintf("Config is valid: \x1b[31;1mfalse\x1b[0m\nError: \x1b[31;1mConfig (path:%s) is not valid: empty config\x1b[0m", configPth) require.Equal(t, expected, out) } }
func TestSetupForVersionChecks(t *testing.T) { fakeHomePth, err := pathutil.NormalizedOSTempDirPath("_FAKE_HOME") require.Equal(t, nil, err) originalHome := os.Getenv("HOME") defer func() { require.Equal(t, nil, os.Setenv("HOME", originalHome)) require.Equal(t, nil, os.RemoveAll(fakeHomePth)) }() require.Equal(t, nil, os.Setenv("HOME", fakeHomePth)) require.Equal(t, false, CheckIsSetupWasDoneForVersion("0.9.7")) require.Equal(t, nil, SaveSetupSuccessForVersion("0.9.7")) require.Equal(t, true, CheckIsSetupWasDoneForVersion("0.9.7")) require.Equal(t, false, CheckIsSetupWasDoneForVersion("0.9.8")) }
func TestGetConfigs(t *testing.T) { // fake home, to save the configs into fakeHomePth, err := pathutil.NormalizedOSTempDirPath("_FAKE_HOME") t.Logf("fakeHomePth: %s", fakeHomePth) require.NoError(t, err) originalHome := os.Getenv("HOME") defer func() { require.NoError(t, os.Setenv("HOME", originalHome)) require.NoError(t, os.RemoveAll(fakeHomePth)) }() require.Equal(t, nil, os.Setenv("HOME", fakeHomePth)) configPth := getEnvmanConfigsFilePath() t.Logf("configPth: %s", configPth) // --- TESTING baseConf, err := GetConfigs() t.Logf("baseConf: %#v", baseConf) require.NoError(t, err) require.Equal(t, defaultEnvBytesLimitInKB, baseConf.EnvBytesLimitInKB) require.Equal(t, defaultEnvListBytesLimitInKB, baseConf.EnvListBytesLimitInKB) // modify it baseConf.EnvBytesLimitInKB = 123 baseConf.EnvListBytesLimitInKB = 321 // save to file require.NoError(t, saveConfigs(baseConf)) // read it back configs, err := GetConfigs() t.Logf("configs: %#v", configs) require.NoError(t, err) require.Equal(t, configs, baseConf) require.Equal(t, 123, configs.EnvBytesLimitInKB) require.Equal(t, 321, configs.EnvListBytesLimitInKB) // delete the tmp config file require.NoError(t, os.Remove(configPth)) }
// DownloadAndUnZIP ... func DownloadAndUnZIP(url, pth string) error { tmpDir, err := pathutil.NormalizedOSTempDirPath("") if err != nil { return err } srcFilePath := tmpDir + "/target.zip" srcFile, err := os.Create(srcFilePath) if err != nil { return err } defer func() { if err := srcFile.Close(); err != nil { log.Fatal("Failed to close srcFile:", err) } if err := os.Remove(srcFilePath); err != nil { log.Fatal("Failed to remove srcFile:", err) } }() response, err := http.Get(url) if err != nil { return err } defer func() { if err := response.Body.Close(); err != nil { log.Fatal("Failed to close response body:", err) } }() if response.StatusCode != http.StatusOK { errorMsg := "Failed to download target from: " + url return errors.New(errorMsg) } if _, err := io.Copy(srcFile, response.Body); err != nil { return err } return UnZIP(srcFilePath, pth) }
func Test_SecretValidateTestJSON(t *testing.T) { tmpDir, err := pathutil.NormalizedOSTempDirPath("__validate_test__") require.NoError(t, err) defer func() { require.NoError(t, os.RemoveAll(tmpDir)) }() t.Log("valid secret") { cmd := cmdex.NewCommand(binPath(), "validate", "-i", "global_flag_test_secrets.yml", "--format", "json") out, err := cmd.RunAndReturnTrimmedCombinedOutput() require.NoError(t, err) require.Equal(t, "{\"data\":{\"secrets\":{\"is_valid\":true}}}", out) } t.Log("invalid - empty config") { secretsPth := filepath.Join(tmpDir, "secrets.yml") require.NoError(t, fileutil.WriteStringToFile(secretsPth, emptySecret)) cmd := cmdex.NewCommand(binPath(), "validate", "-i", secretsPth, "--format", "json") out, err := cmd.RunAndReturnTrimmedCombinedOutput() require.Error(t, err, out) expected := "{\"data\":{\"secrets\":{\"is_valid\":false,\"error\":\"empty config\"}}}" require.Equal(t, expected, out) } t.Log("invalid - invalid secret model") { secretsPth := filepath.Join(tmpDir, "secrets.yml") require.NoError(t, fileutil.WriteStringToFile(secretsPth, invalidSecret)) cmd := cmdex.NewCommand(binPath(), "validate", "-i", secretsPth, "--format", "json") out, err := cmd.RunAndReturnTrimmedCombinedOutput() require.Error(t, err, out) expected := "{\"data\":{\"secrets\":{\"is_valid\":false,\"error\":\"Invalid invetory format: yaml: unmarshal errors:\\n line 1: cannot unmarshal !!seq into models.EnvsYMLModel\"}}}" require.Equal(t, expected, out) } }
func Test_SecretValidateTest(t *testing.T) { tmpDir, err := pathutil.NormalizedOSTempDirPath("__validate_test__") require.NoError(t, err) defer func() { require.NoError(t, os.RemoveAll(tmpDir)) }() t.Log("valid secret") { cmd := cmdex.NewCommand(binPath(), "validate", "-i", "global_flag_test_secrets.yml") out, err := cmd.RunAndReturnTrimmedCombinedOutput() require.NoError(t, err) require.Equal(t, "Secret is valid: \x1b[32;1mtrue\x1b[0m", out) } t.Log("invalid - empty secret") { secretsPth := filepath.Join(tmpDir, "secrets.yml") require.NoError(t, fileutil.WriteStringToFile(secretsPth, emptySecret)) cmd := cmdex.NewCommand(binPath(), "validate", "-i", secretsPth) out, err := cmd.RunAndReturnTrimmedCombinedOutput() require.Error(t, err, out) expected := "Secret is valid: \x1b[31;1mfalse\x1b[0m\nError: \x1b[31;1mempty config\x1b[0m" require.Equal(t, expected, out) } t.Log("invalid - invalid secret model") { secretsPth := filepath.Join(tmpDir, "secrets.yml") require.NoError(t, fileutil.WriteStringToFile(secretsPth, invalidSecret)) cmd := cmdex.NewCommand(binPath(), "validate", "-i", secretsPth) out, err := cmd.RunAndReturnTrimmedCombinedOutput() require.Error(t, err, out) expected := "Secret is valid: \x1b[31;1mfalse\x1b[0m\nError: \x1b[31;1mInvalid invetory format: yaml: unmarshal errors:\n line 1: cannot unmarshal !!seq into models.EnvsYMLModel\x1b[0m" require.Equal(t, expected, out) } }
func auditStepModelBeforeSharePullRequest(step models.StepModel, stepID, version string) error { if err := step.Audit(); err != nil { return err } pth, err := pathutil.NormalizedOSTempDirPath(stepID + version) if err != nil { return err } if err := cmdex.GitCloneTag(step.Source.Git, pth, version); err != nil { return err } latestCommit, err := cmdex.GitGetLatestCommitHashOnHead(pth) if err != nil { return err } if latestCommit != step.Source.Commit { return fmt.Errorf("Step commit hash (%s) should be the latest commit hash (%s) on git tag", step.Source.Commit, latestCommit) } return nil }
// InstallFromURL ... func InstallFromURL(toolBinName, downloadURL string) error { if len(toolBinName) < 1 { return fmt.Errorf("no Tool (bin) Name provided! URL was: %s", downloadURL) } tmpDir, err := pathutil.NormalizedOSTempDirPath("__tmp_download_dest__") if err != nil { return fmt.Errorf("failed to create tmp dir for download destination") } tmpDestinationPth := filepath.Join(tmpDir, toolBinName) if err := DownloadFile(downloadURL, tmpDestinationPth); err != nil { return fmt.Errorf("failed to download, error: %s", err) } bitriseToolsDirPath := configs.GetBitriseToolsDirPath() destinationPth := filepath.Join(bitriseToolsDirPath, toolBinName) if exist, err := pathutil.IsPathExists(destinationPth); err != nil { return fmt.Errorf("failed to check if file exist (%s), error: %s", destinationPth, err) } else if exist { if err := os.Remove(destinationPth); err != nil { return fmt.Errorf("failed to remove file (%s), error: %s", destinationPth, err) } } if err := os.Rename(tmpDestinationPth, destinationPth); err != nil { return fmt.Errorf("failed to copy (%s) to (%s), error: %s", tmpDestinationPth, destinationPth, err) } if err := os.Chmod(destinationPth, 0755); err != nil { return fmt.Errorf("failed to make file (%s) executable, error: %s", destinationPth, err) } return nil }
func main() { configs := createConfigsModelFromEnvs() fmt.Println() configs.print() if err := configs.validate(); err != nil { fmt.Println() log.Error("Issue with input: %s", err) os.Exit(1) } // // Create client fmt.Println() log.Info("Authenticateing") jwtConfig := new(jwt.Config) if configs.JSONKeyPath != "" { jsonKeyPth := "" if strings.HasPrefix(configs.JSONKeyPath, "file://") { jsonKeyPth = strings.TrimPrefix(configs.JSONKeyPath, "file://") } else { tmpDir, err := pathutil.NormalizedOSTempDirPath("__google-play-deploy__") if err != nil { log.Error("Failed to create tmp dir, error: %s", err) os.Exit(1) } jsonKeyPth = filepath.Join(tmpDir, "key.json") if err := downloadFile(configs.JSONKeyPath, jsonKeyPth); err != nil { log.Error("Failed to download json key file, error: %s", err) os.Exit(1) } } authConfig, err := jwtConfigFromJSONKeyFile(jsonKeyPth) if err != nil { log.Error("Failed to create auth config from json key file, error: %s", err) os.Exit(1) } jwtConfig = authConfig } else { p12KeyPath := "" if strings.HasPrefix(configs.P12KeyPath, "file://") { p12KeyPath = strings.TrimPrefix(configs.P12KeyPath, "file://") } else { tmpDir, err := pathutil.NormalizedOSTempDirPath("__google-play-deploy__") if err != nil { log.Error("Failed to create tmp dir, error: %s", err) os.Exit(1) } p12KeyPath = filepath.Join(tmpDir, "key.p12") if err := downloadFile(configs.P12KeyPath, p12KeyPath); err != nil { log.Error("Failed to download p12 key file, error: %s", err) os.Exit(1) } } authConfig, err := jwtConfigFromP12KeyFile(p12KeyPath, configs.ServiceAccountEmail) if err != nil { log.Error("Failed to create auth config from p12 key file, error: %s", err) os.Exit(1) } jwtConfig = authConfig } client := jwtConfig.Client(oauth2.NoContext) service, err := androidpublisher.New(client) if err != nil { log.Error("Failed to create publisher service, error: %s", err) os.Exit(1) } log.Done("Authenticated client created") // --- // // Create insert edit fmt.Println() log.Info("Create new edit") editsService := androidpublisher.NewEditsService(service) editsInsertCall := editsService.Insert(configs.PackageName, nil) appEdit, err := editsInsertCall.Do() if err != nil { log.Error("Failed to perform edit insert call, error: %s", err) os.Exit(1) } log.Detail(" editID: %s", appEdit.Id) // --- // // Upload APKs fmt.Println() log.Info("Upload apks") versionCodes := []int64{} apkPaths := strings.Split(configs.ApkPath, "|") for _, apkPath := range apkPaths { apkFile, err := os.Open(apkPath) if err != nil { log.Error("Failed to read apk (%s), error: %s", apkPath, err) os.Exit(1) } editsApksService := androidpublisher.NewEditsApksService(service) editsApksUloadCall := editsApksService.Upload(configs.PackageName, appEdit.Id) editsApksUloadCall.Media(apkFile, googleapi.ContentType("application/vnd.android.package-archive")) apk, err := editsApksUloadCall.Do() if err != nil { log.Error("Failed to upload apk, error: %s", err) os.Exit(1) } log.Detail(" uploaded apk version: %d", apk.VersionCode) versionCodes = append(versionCodes, apk.VersionCode) } // --- // // Update track fmt.Println() log.Info("Update track") editsTracksService := androidpublisher.NewEditsTracksService(service) newTrack := androidpublisher.Track{ Track: configs.Track, VersionCodes: versionCodes, } if configs.Track == "rollout" { userFraction, err := strconv.ParseFloat(configs.UserFraction, 64) if err != nil { log.Error("Failed to parse user fraction, error: %s", err) os.Exit(1) } newTrack.UserFraction = userFraction } editsTracksUpdateCall := editsTracksService.Update(configs.PackageName, appEdit.Id, configs.Track, &newTrack) track, err := editsTracksUpdateCall.Do() if err != nil { log.Error("Failed to update track, error: %s", err) os.Exit(1) } log.Detail(" updated track: %s", track.Track) log.Detail(" assigned apk versions: %v", track.VersionCodes) // --- // // Update listing if configs.WhatsnewsDir != "" { fmt.Println() log.Info("Update listing") recentChangesMap, err := readLocalisedRecentChanges(configs.WhatsnewsDir) if err != nil { log.Error("Failed to read whatsnews, error: %s", err) os.Exit(1) } editsApklistingsService := androidpublisher.NewEditsApklistingsService(service) for _, versionCode := range versionCodes { log.Detail(" updating recent changes for version: %d", versionCode) for language, recentChanges := range recentChangesMap { newApkListing := androidpublisher.ApkListing{ Language: language, RecentChanges: recentChanges, } editsApkListingsCall := editsApklistingsService.Update(configs.PackageName, appEdit.Id, versionCode, language, &newApkListing) apkListing, err := editsApkListingsCall.Do() if err != nil { log.Error("Failed to update listing, error: %s", err) os.Exit(1) } log.Detail(" - language: %s", apkListing.Language) } } } // --- // // Validate edit fmt.Println() log.Info("Validating edit") editsValidateCall := editsService.Validate(configs.PackageName, appEdit.Id) if _, err := editsValidateCall.Do(); err != nil { log.Error("Failed to validate edit, error: %s", err) os.Exit(1) } log.Done("Edit is valid") // --- // // Commit edit fmt.Println() log.Info("Committing edit") editsCommitCall := editsService.Commit(configs.PackageName, appEdit.Id) if _, err := editsCommitCall.Do(); err != nil { log.Error("Failed to commit edit, error: %s", err) os.Exit(1) } log.Done("Edit committed") // --- }
func main() { configs := createConfigsModelFromEnvs() fmt.Println() configs.print() if err := configs.validate(); err != nil { log.Error("Issue with input: %s", err) os.Exit(1) } nugetPth := "/Library/Frameworks/Mono.framework/Versions/Current/bin/nuget" nugetRestoreCmdArgs := []string{nugetPth} if configs.NugetVersion == "latest" { fmt.Println() log.Info("Updating Nuget to latest version...") // "sudo $nuget update -self" cmdArgs := []string{"sudo", nugetPth, "update", "-self"} cmd, err := cmdex.NewCommandFromSlice(cmdArgs) if err != nil { log.Error("Failed to create command from args (%v), error: %s", cmdArgs, err) os.Exit(1) } cmd.SetStdout(os.Stdout) cmd.SetStderr(os.Stderr) log.Done("$ %s", cmdex.PrintableCommandArgs(false, cmdArgs)) if err := cmd.Run(); err != nil { log.Error("Failed to update nuget, error: %s", err) os.Exit(1) } } else if configs.NugetVersion != "" { fmt.Println() log.Info("Downloading Nuget %s version...", configs.NugetVersion) tmpDir, err := pathutil.NormalizedOSTempDirPath("__nuget__") if err != nil { log.Error("Failed to create tmp dir, error: %s", err) os.Exit(1) } downloadPth := filepath.Join(tmpDir, "nuget.exe") // https://dist.nuget.org/win-x86-commandline/v3.3.0/nuget.exe nugetURL := fmt.Sprintf("https://dist.nuget.org/win-x86-commandline/v%s/nuget.exe", configs.NugetVersion) log.Detail("Download URL: %s", nugetURL) if err := DownloadFile(nugetURL, downloadPth); err != nil { log.Warn("Download failed, error: %s", err) // https://dist.nuget.org/win-x86-commandline/v3.4.4/NuGet.exe nugetURL = fmt.Sprintf("https://dist.nuget.org/win-x86-commandline/v%s/NuGet.exe", configs.NugetVersion) log.Detail("Retry download URl: %s", nugetURL) if err := DownloadFile(nugetURL, downloadPth); err != nil { log.Error("Failed to download nuget, error: %s", err) os.Exit(1) } } nugetRestoreCmdArgs = []string{constants.MonoPath, downloadPth} } fmt.Println() log.Info("Restoring Nuget packages...") nugetRestoreCmdArgs = append(nugetRestoreCmdArgs, "restore", configs.XamarinSolution) if err := retry.Times(1).Try(func(attempt uint) error { if attempt > 0 { log.Warn("Attempt %d failed, retrying...", attempt) } log.Done("$ %s", cmdex.PrintableCommandArgs(false, nugetRestoreCmdArgs)) cmd, err := cmdex.NewCommandFromSlice(nugetRestoreCmdArgs) if err != nil { log.Error("Failed to create Nuget command, error: %s", err) os.Exit(1) } cmd.SetStdout(os.Stdout) cmd.SetStderr(os.Stderr) if err := cmd.Run(); err != nil { log.Error("Restore failed, error: %s", err) return err } return nil }); err != nil { log.Error("Nuget restore failed, error: %s", err) os.Exit(1) } }
func create(c *cli.Context) error { toolMode := c.Bool(ToolMode) share, err := ReadShareSteplibFromFile() if err != nil { log.Error(err) log.Fatalln("You have to start sharing with `stepman share start`, or you can read instructions with `stepman share`") } // Input validation tag := c.String(TagKey) if tag == "" { log.Fatalln("No Step tag specified") } gitURI := c.String(GitKey) if gitURI == "" { log.Fatalln("No Step url specified") } stepID := c.String(StepIDKEy) if stepID == "" { stepID = getStepIDFromGit(gitURI) } if stepID == "" { log.Fatalln("No Step id specified") } r := regexp.MustCompile(`[a-z0-9-]+`) if find := r.FindString(stepID); find != stepID { log.Fatalln("StepID doesn't conforms to: [a-z0-9-]") } route, found := stepman.ReadRoute(share.Collection) if !found { log.Fatalf("No route found for collectionURI (%s)", share.Collection) } stepDirInSteplib := stepman.GetStepCollectionDirPath(route, stepID, tag) stepYMLPathInSteplib := path.Join(stepDirInSteplib, "step.yml") if exist, err := pathutil.IsPathExists(stepYMLPathInSteplib); err != nil { log.Fatalf("Failed to check step.yml path in steplib, err: %s", err) } else if exist { log.Warnf("Step already exist in path: %s.", stepDirInSteplib) if val, err := goinp.AskForBool("Would you like to overwrite local version of Step?"); err != nil { log.Fatalf("Failed to get bool, err: %s", err) } else { if !val { log.Errorln("Unfortunately we can't continue with sharing without an overwrite exist step.yml.") log.Fatalln("Please finish your changes, run this command again and allow it to overwrite the exist step.yml!") } } } // Clone Step to tmp dir tmp, err := pathutil.NormalizedOSTempDirPath("") if err != nil { log.Fatalf("Failed to get temp directory, err: %s", err) } log.Infof("Cloning Step from (%s) with tag (%s) to temporary path (%s)", gitURI, tag, tmp) if err := cmdex.GitCloneTag(gitURI, tmp, tag); err != nil { log.Fatalf("Git clone failed, err: %s", err) } // Update step.yml tmpStepYMLPath := path.Join(tmp, "step.yml") bytes, err := fileutil.ReadBytesFromFile(tmpStepYMLPath) if err != nil { log.Fatalf("Failed to read Step from file, err: %s", err) } var stepModel models.StepModel if err := yaml.Unmarshal(bytes, &stepModel); err != nil { log.Fatalf("Failed to unmarchal Step, err: %s", err) } commit, err := cmdex.GitGetCommitHashOfHEAD(tmp) if err != nil { log.Fatalf("Failed to get commit hash, err: %s", err) } stepModel.Source = &models.StepSourceModel{ Git: gitURI, Commit: commit, } stepModel.PublishedAt = pointers.NewTimePtr(time.Now()) // Validate step-yml if err := stepModel.Audit(); err != nil { log.Fatalf("Failed to validate Step, err: %s", err) } for _, input := range stepModel.Inputs { key, value, err := input.GetKeyValuePair() if err != nil { log.Fatalf("Failed to get Step input key-value pair, err: %s", err) } options, err := input.GetOptions() if err != nil { log.Fatalf("Failed to get Step input (%s) options, err: %s", key, err) } if len(options.ValueOptions) > 0 && value == "" { log.Warn("Step input with 'value_options', should contain default value!") log.Fatalf("Missing default value for Step input (%s).", key) } } if strings.Contains(*stepModel.Summary, "\n") { log.Warningln("Step summary should be one line!") } if utf8.RuneCountInString(*stepModel.Summary) > maxSummaryLength { log.Warningf("Step summary should contains maximum (%d) characters, actual: (%d)!", maxSummaryLength, utf8.RuneCountInString(*stepModel.Summary)) } // Copy step.yml to steplib share.StepID = stepID share.StepTag = tag if err := WriteShareSteplibToFile(share); err != nil { log.Fatalf("Failed to save share steplib to file, err: %s", err) } log.Info("Step dir in collection:", stepDirInSteplib) if exist, err := pathutil.IsPathExists(stepDirInSteplib); err != nil { log.Fatalf("Failed to check path (%s), err: %s", stepDirInSteplib, err) } else if !exist { if err := os.MkdirAll(stepDirInSteplib, 0777); err != nil { log.Fatalf("Failed to create path (%s), err: %s", stepDirInSteplib, err) } } log.Infof("Checkout branch: %s", share.ShareBranchName()) collectionDir := stepman.GetCollectionBaseDirPath(route) if err := cmdex.GitCheckout(collectionDir, share.ShareBranchName()); err != nil { if err := cmdex.GitCreateAndCheckoutBranch(collectionDir, share.ShareBranchName()); err != nil { log.Fatalf("Git failed to create and checkout branch, err: %s", err) } } stepBytes, err := yaml.Marshal(stepModel) if err != nil { log.Fatalf("Failed to marcshal Step model, err: %s", err) } if err := fileutil.WriteBytesToFile(stepYMLPathInSteplib, stepBytes); err != nil { log.Fatalf("Failed to write Step to file, err: %s", err) } // Update spec.json if err := stepman.ReGenerateStepSpec(route); err != nil { log.Fatalf("Failed to re-create steplib, err: %s", err) } printFinishCreate(share, stepDirInSteplib, toolMode) return nil }
func runPlugin(plugin Plugin, args []string, pluginInput PluginInput) error { if !configs.IsCIMode && configs.CheckIsPluginUpdateCheckRequired() { // Check for new version log.Infof("Checking for plugin (%s) new version...", plugin.Name) if newVersion, err := CheckForNewVersion(plugin); err != nil { log.Warnf("") log.Warnf("Failed to check for plugin (%s) new version, error: %s", plugin.Name, err) } else if newVersion != "" { log.Warnf("") log.Warnf("New version (%s) of plugin (%s) available", newVersion, plugin.Name) route, found, err := ReadPluginRoute(plugin.Name) if err != nil { return err } if !found { return fmt.Errorf("no route found for already loaded plugin (%s)", plugin.Name) } route.LatestAvailableVersion = newVersion if err := AddPluginRoute(route); err != nil { return fmt.Errorf("failed to register available plugin (%s) update (%s), error: %s", plugin.Name, newVersion, err) } } else { log.Debugf("No new version of plugin (%s) available", plugin.Name) } if err := configs.SavePluginUpdateCheck(); err != nil { return err } fmt.Println() } else { route, found, err := ReadPluginRoute(plugin.Name) if err != nil { return err } if !found { return fmt.Errorf("no route found for already loaded plugin (%s)", plugin.Name) } if route.LatestAvailableVersion != "" { log.Warnf("") log.Warnf("New version (%s) of plugin (%s) available", route.LatestAvailableVersion, plugin.Name) } } // Append common data to plugin iputs bitriseVersion, err := version.BitriseCliVersion() if err != nil { return err } pluginInput[pluginInputBitriseVersionKey] = bitriseVersion.String() pluginInput[pluginInputDataDirKey] = GetPluginDataDir(plugin.Name) // Prepare plugin envstore pluginWorkDir, err := pathutil.NormalizedOSTempDirPath("plugin-work-dir") if err != nil { return err } defer func() { if err := os.RemoveAll(pluginWorkDir); err != nil { log.Warnf("Failed to remove path (%s)", pluginWorkDir) } }() pluginEnvstorePath := filepath.Join(pluginWorkDir, "envstore.yml") if err := tools.EnvmanInitAtPath(pluginEnvstorePath); err != nil { return err } if err := tools.EnvmanAdd(pluginEnvstorePath, configs.EnvstorePathEnvKey, pluginEnvstorePath, false, false); err != nil { return err } log.Debugf("plugin evstore path (%s)", pluginEnvstorePath) // Add plugin inputs for key, value := range pluginInput { if err := tools.EnvmanAdd(pluginEnvstorePath, key, value, false, false); err != nil { return err } } // Run plugin executable pluginExecutable, isBin, err := GetPluginExecutablePath(plugin.Name) if err != nil { return err } cmd := []string{} if isBin { log.Debugf("Run plugin binary (%s)", pluginExecutable) cmd = append([]string{pluginExecutable}, args...) } else { log.Debugf("Run plugin sh (%s)", pluginExecutable) cmd = append([]string{"bash", pluginExecutable}, args...) } exitCode, err := tools.EnvmanRun(pluginEnvstorePath, "", cmd) log.Debugf("Plugin run finished with exit code (%d)", exitCode) if err != nil { return err } // Read plugin output outStr, err := tools.EnvmanJSONPrint(pluginEnvstorePath) if err != nil { return err } envList, err := envmanModels.NewEnvJSONList(outStr) if err != nil { return err } pluginOutputStr, found := envList[bitrisePluginOutputEnvKey] if found { log.Debugf("Plugin output: %s", pluginOutputStr) } return nil }
// DownloadPluginFromURL .... func DownloadPluginFromURL(URL, dst string) error { url, err := url.Parse(URL) if err != nil { return err } scheme := url.Scheme tokens := strings.Split(URL, "/") fileName := tokens[len(tokens)-1] tmpDstFilePath := "" if scheme != "file" { OS, arch, err := getOsAndArch() if err != nil { return err } urlWithSuffix := URL urlSuffix := fmt.Sprintf("-%s-%s", OS, arch) if !strings.HasSuffix(URL, urlSuffix) { urlWithSuffix = urlWithSuffix + urlSuffix } urls := []string{urlWithSuffix, URL} tmpDir, err := pathutil.NormalizedOSTempDirPath("plugin") if err != nil { return err } tmpDst := path.Join(tmpDir, fileName) output, err := os.Create(tmpDst) if err != nil { return err } defer func() { if err := output.Close(); err != nil { log.Errorf("Failed to close file, err: %s", err) } }() success := false var response *http.Response for _, aURL := range urls { response, err = http.Get(aURL) if response != nil { defer func() { if err := response.Body.Close(); err != nil { log.Errorf("Failed to close response body, err: %s", err) } }() } if err != nil { log.Errorf("%s", err) } else { success = true break } } if !success { return err } if _, err := io.Copy(output, response.Body); err != nil { return err } tmpDstFilePath = output.Name() } else { tmpDstFilePath = strings.Replace(URL, scheme+"://", "", -1) } if err := cmdex.CopyFile(tmpDstFilePath, dst); err != nil { return err } return nil }
// InitPaths ... func InitPaths() error { if err := initBitriseWorkPaths(); err != nil { return fmt.Errorf("Failed to init bitrise paths, error: %s", err) } // --- Bitrise TOOLS bitriseToolsDirPth := GetBitriseToolsDirPath() if err := pathutil.EnsureDirExist(bitriseToolsDirPth); err != nil { return err } pthWithBitriseTools := generatePATHEnvString(os.Getenv("PATH"), bitriseToolsDirPth) if err := os.Setenv("PATH", pthWithBitriseTools); err != nil { return fmt.Errorf("Failed to set PATH to include BITRISE_HOME/tools! Error: %s", err) } inputEnvstorePath, err := filepath.Abs(filepath.Join(BitriseWorkDirPath, "input_envstore.yml")) if err != nil { return fmt.Errorf("Failed to set input envstore path, error: %s", err) } InputEnvstorePath = inputEnvstorePath outputEnvstorePath, err := filepath.Abs(filepath.Join(BitriseWorkDirPath, "output_envstore.yml")) if err != nil { return fmt.Errorf("Failed to set output envstore path, error: %s", err) } OutputEnvstorePath = outputEnvstorePath formoutPath, err := filepath.Abs(filepath.Join(BitriseWorkDirPath, "formatted_output.md")) if err != nil { return fmt.Errorf("Failed to set formatted output path, error: %s", err) } FormattedOutputPath = formoutPath currentDir, err := filepath.Abs("./") if err != nil { return fmt.Errorf("Failed to set current dir, error: %s", err) } CurrentDir = currentDir // BITRISE_SOURCE_DIR if os.Getenv(BitriseSourceDirEnvKey) == "" { if err := os.Setenv(BitriseSourceDirEnvKey, currentDir); err != nil { return fmt.Errorf("Failed to set BITRISE_SOURCE_DIR, error: %s", err) } } // BITRISE_DEPLOY_DIR if os.Getenv(BitriseDeployDirEnvKey) == "" { deployDir, err := pathutil.NormalizedOSTempDirPath("deploy") if err != nil { return fmt.Errorf("Failed to set deploy dir, error: %s", err) } if err := os.Setenv(BitriseDeployDirEnvKey, deployDir); err != nil { return fmt.Errorf("Failed to set BITRISE_DEPLOY_DIR, error: %s", err) } } // BITRISE_CACHE_DIR if os.Getenv(BitriseCacheDirEnvKey) == "" { cacheDir, err := pathutil.NormalizedOSTempDirPath("cache") if err != nil { return fmt.Errorf("Failed to set cache dir, error: %s", err) } if err := os.Setenv(BitriseCacheDirEnvKey, cacheDir); err != nil { return fmt.Errorf("Failed to set BITRISE_CACHE_DIR, error: %s", err) } } return nil }
func TestBitriseSourceDir(t *testing.T) { currPth, err := pathutil.NormalizedOSTempDirPath("bitrise_source_dir_test") require.NoError(t, err) testPths := []string{} for i := 0; i < 4; i++ { testPth := filepath.Join(currPth, fmt.Sprintf("_test%d", i)) require.NoError(t, os.RemoveAll(testPth)) require.NoError(t, os.Mkdir(testPth, 0777)) // eval symlinks: the Go generated temp folder on OS X is a symlink // from /var/ to /private/var/ testPth, err = filepath.EvalSymlinks(testPth) require.NoError(t, err) defer func() { require.NoError(t, os.RemoveAll(testPth)) }() testPths = append(testPths, testPth) } t.Log("BITRISE_SOURCE_DIR defined in Secret") { inventoryStr := ` envs: - BITRISE_SOURCE_DIR: "` + testPths[0] + `" ` inventory, err := bitrise.InventoryModelFromYAMLBytes([]byte(inventoryStr)) require.NoError(t, err) configStr := ` format_version: 1.3.0 default_step_lib_source: "https://github.com/bitrise-io/bitrise-steplib.git" workflows: test: steps: - script: inputs: - content: | #!/bin/bash set -v echo "BITRISE_SOURCE_DIR: $BITRISE_SOURCE_DIR" if [[ "$BITRISE_SOURCE_DIR" != "` + testPths[0] + `" ]] ; then exit 1 fi ` require.NoError(t, configs.InitPaths()) config, warnings, err := bitrise.ConfigModelFromYAMLBytes([]byte(configStr)) require.NoError(t, err) require.Equal(t, 0, len(warnings)) _, err = runWorkflowWithConfiguration(time.Now(), "test", config, inventory.Envs) require.NoError(t, err) } t.Log("BITRISE_SOURCE_DIR defined in Secret, and in App") { inventoryStr := ` envs: - BITRISE_SOURCE_DIR: "` + testPths[0] + `" ` inventory, err := bitrise.InventoryModelFromYAMLBytes([]byte(inventoryStr)) require.NoError(t, err) configStr := ` format_version: 1.3.0 default_step_lib_source: "https://github.com/bitrise-io/bitrise-steplib.git" app: envs: - BITRISE_SOURCE_DIR: "` + testPths[1] + `" workflows: test: steps: - script: inputs: - content: | #!/bin/bash set -v echo "BITRISE_SOURCE_DIR: $BITRISE_SOURCE_DIR" if [[ "$BITRISE_SOURCE_DIR" != "` + testPths[1] + `" ]] ; then exit 1 fi ` require.NoError(t, configs.InitPaths()) config, warnings, err := bitrise.ConfigModelFromYAMLBytes([]byte(configStr)) require.NoError(t, err) require.Equal(t, 0, len(warnings)) _, err = runWorkflowWithConfiguration(time.Now(), "test", config, inventory.Envs) require.NoError(t, err) } t.Log("BITRISE_SOURCE_DIR defined in Secret, App and Workflow") { inventoryStr := ` envs: - BITRISE_SOURCE_DIR: "` + testPths[0] + `" ` inventory, err := bitrise.InventoryModelFromYAMLBytes([]byte(inventoryStr)) require.NoError(t, err) configStr := ` format_version: 1.3.0 default_step_lib_source: "https://github.com/bitrise-io/bitrise-steplib.git" app: envs: - BITRISE_SOURCE_DIR: "` + testPths[1] + `" workflows: test: envs: - BITRISE_SOURCE_DIR: "` + testPths[2] + `" steps: - script: inputs: - content: | #!/bin/bash set -v echo "BITRISE_SOURCE_DIR: $BITRISE_SOURCE_DIR" if [[ "$BITRISE_SOURCE_DIR" != "` + testPths[2] + `" ]] ; then exit 1 fi ` require.NoError(t, configs.InitPaths()) config, warnings, err := bitrise.ConfigModelFromYAMLBytes([]byte(configStr)) require.NoError(t, err) require.Equal(t, 0, len(warnings)) _, err = runWorkflowWithConfiguration(time.Now(), "test", config, inventory.Envs) require.NoError(t, err) } t.Log("BITRISE_SOURCE_DIR defined in secret, App, Workflow and Step") { inventoryStr := ` envs: - BITRISE_SOURCE_DIR: "` + testPths[0] + `" ` inventory, err := bitrise.InventoryModelFromYAMLBytes([]byte(inventoryStr)) require.NoError(t, err) configStr := ` format_version: 1.3.0 default_step_lib_source: "https://github.com/bitrise-io/bitrise-steplib.git" app: envs: - BITRISE_SOURCE_DIR: "` + testPths[1] + `" workflows: test: envs: - BITRISE_SOURCE_DIR: "` + testPths[2] + `" steps: - script: inputs: - content: | #!/bin/bash set -v envman add --key BITRISE_SOURCE_DIR --value ` + testPths[3] + ` - script: inputs: - content: | #!/bin/bash set -v echo "BITRISE_SOURCE_DIR: $BITRISE_SOURCE_DIR" if [[ "$BITRISE_SOURCE_DIR" != "` + testPths[3] + `" ]] ; then exit 1 fi ` require.NoError(t, configs.InitPaths()) config, warnings, err := bitrise.ConfigModelFromYAMLBytes([]byte(configStr)) require.NoError(t, err) require.Equal(t, 0, len(warnings)) _, err = runWorkflowWithConfiguration(time.Now(), "test", config, inventory.Envs) require.NoError(t, err) } }
func removeStepDefaultsAndFillStepOutputs(stepListItem *models.StepListItemModel, defaultStepLibSource string) error { // Create stepIDData compositeStepIDStr, workflowStep, err := models.GetStepIDStepDataPair(*stepListItem) if err != nil { return err } stepIDData, err := models.CreateStepIDDataFromString(compositeStepIDStr, defaultStepLibSource) if err != nil { return err } // Activate step - get step.yml tempStepCloneDirPath, err := pathutil.NormalizedOSTempDirPath("step_clone") if err != nil { return err } tempStepYMLDirPath, err := pathutil.NormalizedOSTempDirPath("step_yml") if err != nil { return err } tempStepYMLFilePath := filepath.Join(tempStepYMLDirPath, "step.yml") if stepIDData.SteplibSource == "path" { stepAbsLocalPth, err := pathutil.AbsPath(stepIDData.IDorURI) if err != nil { return err } if err := cmdex.CopyFile(filepath.Join(stepAbsLocalPth, "step.yml"), tempStepYMLFilePath); err != nil { return err } } else if stepIDData.SteplibSource == "git" { if err := cmdex.GitCloneTagOrBranch(stepIDData.IDorURI, tempStepCloneDirPath, stepIDData.Version); err != nil { return err } if err := cmdex.CopyFile(filepath.Join(tempStepCloneDirPath, "step.yml"), tempStepYMLFilePath); err != nil { return err } } else if stepIDData.SteplibSource == "_" { // Steplib independent steps are completly defined in workflow tempStepYMLFilePath = "" } else if stepIDData.SteplibSource != "" { if err := tools.StepmanSetup(stepIDData.SteplibSource); err != nil { return err } if err := tools.StepmanActivate(stepIDData.SteplibSource, stepIDData.IDorURI, stepIDData.Version, tempStepCloneDirPath, tempStepYMLFilePath); err != nil { return err } } else { return errors.New("Failed to fill step ouputs: unkown SteplibSource") } // Fill outputs if tempStepYMLFilePath != "" { specStep, err := ReadSpecStep(tempStepYMLFilePath) if err != nil { return err } if workflowStep.Title != nil && specStep.Title != nil && *workflowStep.Title == *specStep.Title { workflowStep.Title = nil } if workflowStep.Description != nil && specStep.Description != nil && *workflowStep.Description == *specStep.Description { workflowStep.Description = nil } if workflowStep.Summary != nil && specStep.Summary != nil && *workflowStep.Summary == *specStep.Summary { workflowStep.Summary = nil } if workflowStep.Website != nil && specStep.Website != nil && *workflowStep.Website == *specStep.Website { workflowStep.Website = nil } if workflowStep.SourceCodeURL != nil && specStep.SourceCodeURL != nil && *workflowStep.SourceCodeURL == *specStep.SourceCodeURL { workflowStep.SourceCodeURL = nil } if workflowStep.SupportURL != nil && specStep.SupportURL != nil && *workflowStep.SupportURL == *specStep.SupportURL { workflowStep.SupportURL = nil } workflowStep.PublishedAt = nil if workflowStep.Source != nil && specStep.Source != nil { if workflowStep.Source.Git == specStep.Source.Git { workflowStep.Source.Git = "" } if workflowStep.Source.Commit == specStep.Source.Commit { workflowStep.Source.Commit = "" } } if isStringSliceWithSameElements(workflowStep.HostOsTags, specStep.HostOsTags) { workflowStep.HostOsTags = []string{} } if isStringSliceWithSameElements(workflowStep.ProjectTypeTags, specStep.ProjectTypeTags) { workflowStep.ProjectTypeTags = []string{} } if isStringSliceWithSameElements(workflowStep.TypeTags, specStep.TypeTags) { workflowStep.TypeTags = []string{} } if isDependencySliceWithSameElements(workflowStep.Dependencies, specStep.Dependencies) { workflowStep.Dependencies = []stepmanModels.DependencyModel{} } if workflowStep.IsRequiresAdminUser != nil && specStep.IsRequiresAdminUser != nil && *workflowStep.IsRequiresAdminUser == *specStep.IsRequiresAdminUser { workflowStep.IsRequiresAdminUser = nil } if workflowStep.IsAlwaysRun != nil && specStep.IsAlwaysRun != nil && *workflowStep.IsAlwaysRun == *specStep.IsAlwaysRun { workflowStep.IsAlwaysRun = nil } if workflowStep.IsSkippable != nil && specStep.IsSkippable != nil && *workflowStep.IsSkippable == *specStep.IsSkippable { workflowStep.IsSkippable = nil } if workflowStep.RunIf != nil && specStep.RunIf != nil && *workflowStep.RunIf == *specStep.RunIf { workflowStep.RunIf = nil } inputs := []envmanModels.EnvironmentItemModel{} for _, input := range workflowStep.Inputs { sameValue := false wfKey, wfValue, err := input.GetKeyValuePair() if err != nil { return err } wfOptions, err := input.GetOptions() if err != nil { return err } sInput, err := getInputByKey(specStep.Inputs, wfKey) if err != nil { return err } _, sValue, err := sInput.GetKeyValuePair() if err != nil { return err } if wfValue == sValue { sameValue = true } sOptions, err := sInput.GetOptions() if err != nil { return err } hasOptions := false if wfOptions.Title != nil && sOptions.Title != nil && *wfOptions.Title == *sOptions.Title { wfOptions.Title = nil } else { hasOptions = true } if wfOptions.Description != nil && sOptions.Description != nil && *wfOptions.Description == *sOptions.Description { wfOptions.Description = nil } else { hasOptions = true } if wfOptions.Summary != nil && sOptions.Summary != nil && *wfOptions.Summary == *sOptions.Summary { wfOptions.Summary = nil } else { hasOptions = true } if isStringSliceWithSameElements(wfOptions.ValueOptions, sOptions.ValueOptions) { wfOptions.ValueOptions = []string{} } else { hasOptions = true } if wfOptions.IsRequired != nil && sOptions.IsRequired != nil && *wfOptions.IsRequired == *sOptions.IsRequired { wfOptions.IsRequired = nil } else { hasOptions = true } if wfOptions.IsExpand != nil && sOptions.IsExpand != nil && *wfOptions.IsExpand == *sOptions.IsExpand { wfOptions.IsExpand = nil } else { hasOptions = true } if wfOptions.IsDontChangeValue != nil && sOptions.IsDontChangeValue != nil && *wfOptions.IsDontChangeValue == *sOptions.IsDontChangeValue { wfOptions.IsDontChangeValue = nil } else { hasOptions = true } if !hasOptions && sameValue { // default env } else { if hasOptions { input[envmanModels.OptionsKey] = wfOptions } else { delete(input, envmanModels.OptionsKey) } inputs = append(inputs, input) } } workflowStep.Inputs = inputs // We need only key-value and title from spec outputs outputs := []envmanModels.EnvironmentItemModel{} for _, output := range specStep.Outputs { sKey, sValue, err := output.GetKeyValuePair() if err != nil { return err } sOptions, err := output.GetOptions() if err != nil { return err } newOutput := envmanModels.EnvironmentItemModel{ sKey: sValue, envmanModels.OptionsKey: envmanModels.EnvironmentItemOptionsModel{ Title: sOptions.Title, }, } outputs = append(outputs, newOutput) } workflowStep.Outputs = outputs (*stepListItem)[compositeStepIDStr] = workflowStep } // Cleanup if err := cmdex.RemoveDir(tempStepCloneDirPath); err != nil { return errors.New(fmt.Sprint("Failed to remove step clone dir: ", err)) } if err := cmdex.RemoveDir(tempStepYMLDirPath); err != nil { return errors.New(fmt.Sprint("Failed to remove step clone dir: ", err)) } return nil }
func TestBitriseSourceDir(t *testing.T) { currPth, err := pathutil.NormalizedOSTempDirPath("bitrise_source_dir_test") if err != nil { t.Fatal("Failed to get curr abs path: ", err) } testPths := []string{} for i := 0; i < 4; i++ { testPth := path.Join(currPth, fmt.Sprintf("_test%d", i)) if err := os.RemoveAll(testPth); err != nil { t.Fatalf("Failed to remove %s, err: %s: ", testPth, err) } err := os.Mkdir(testPth, 0777) if err != nil { t.Fatalf("Failed to create %s, err: %s: ", testPth, err) } // eval symlinks: the Go generated temp folder on OS X is a symlink // from /var/ to /private/var/ testPth, err = filepath.EvalSymlinks(testPth) if err != nil { t.Fatalf("Failed to EvalSymlinks for (path:%s), err: %s", testPth, err) } defer func() { err := os.RemoveAll(testPth) if err != nil { t.Fatalf("Failed to remove %s, err: %s: ", testPth, err) } }() testPths = append(testPths, testPth) } // // BITRISE_SOURCE_DIR defined in Secret inventoryStr := ` envs: - BITRISE_SOURCE_DIR: "` + testPths[0] + `" ` inventory, err := bitrise.InventoryModelFromYAMLBytes([]byte(inventoryStr)) require.Equal(t, nil, err) configStr := ` format_version: 1.0.0 default_step_lib_source: "https://github.com/bitrise-io/bitrise-steplib.git" workflows: test: steps: - script: inputs: - content: | #!/bin/bash set -v echo "BITRISE_SOURCE_DIR: $BITRISE_SOURCE_DIR" if [[ "$BITRISE_SOURCE_DIR" != "` + testPths[0] + `" ]] ; then exit 1 fi ` config, err := bitrise.ConfigModelFromYAMLBytes([]byte(configStr)) require.Equal(t, nil, err) _, err = runWorkflowWithConfiguration(time.Now(), "test", config, inventory.Envs) require.Equal(t, nil, err) // // BITRISE_SOURCE_DIR defined in Secret, and in App inventoryStr = ` envs: - BITRISE_SOURCE_DIR: "` + testPths[0] + `" ` inventory, err = bitrise.InventoryModelFromYAMLBytes([]byte(inventoryStr)) require.Equal(t, nil, err) configStr = ` format_version: 1.0.0 default_step_lib_source: "https://github.com/bitrise-io/bitrise-steplib.git" app: envs: - BITRISE_SOURCE_DIR: "` + testPths[1] + `" workflows: test: steps: - script: inputs: - content: | #!/bin/bash set -v echo "BITRISE_SOURCE_DIR: $BITRISE_SOURCE_DIR" if [[ "$BITRISE_SOURCE_DIR" != "` + testPths[1] + `" ]] ; then exit 1 fi ` config, err = bitrise.ConfigModelFromYAMLBytes([]byte(configStr)) require.Equal(t, nil, err) _, err = runWorkflowWithConfiguration(time.Now(), "test", config, inventory.Envs) require.Equal(t, nil, err) // // BITRISE_SOURCE_DIR defined in Secret, App and Workflow inventoryStr = ` envs: - BITRISE_SOURCE_DIR: "` + testPths[0] + `" ` inventory, err = bitrise.InventoryModelFromYAMLBytes([]byte(inventoryStr)) require.Equal(t, nil, err) configStr = ` format_version: 1.0.0 default_step_lib_source: "https://github.com/bitrise-io/bitrise-steplib.git" app: envs: - BITRISE_SOURCE_DIR: "` + testPths[1] + `" workflows: test: envs: - BITRISE_SOURCE_DIR: "` + testPths[2] + `" steps: - script: inputs: - content: | #!/bin/bash set -v echo "BITRISE_SOURCE_DIR: $BITRISE_SOURCE_DIR" if [[ "$BITRISE_SOURCE_DIR" != "` + testPths[2] + `" ]] ; then exit 1 fi ` config, err = bitrise.ConfigModelFromYAMLBytes([]byte(configStr)) require.Equal(t, nil, err) _, err = runWorkflowWithConfiguration(time.Now(), "test", config, inventory.Envs) require.Equal(t, nil, err) // // BITRISE_SOURCE_DIR defined in Secret, App and Workflow // BUT the value is empty in Workflow and App Envs - Secrets should be used! inventoryStr = ` envs: - BITRISE_SOURCE_DIR: "` + testPths[0] + `" ` inventory, err = bitrise.InventoryModelFromYAMLBytes([]byte(inventoryStr)) require.Equal(t, nil, err) configStr = ` format_version: 1.0.0 default_step_lib_source: "https://github.com/bitrise-io/bitrise-steplib.git" app: envs: - BITRISE_SOURCE_DIR: workflows: test: envs: - BITRISE_SOURCE_DIR: "" steps: - script: inputs: - content: | #!/bin/bash set -v echo "BITRISE_SOURCE_DIR: $BITRISE_SOURCE_DIR" if [[ "$BITRISE_SOURCE_DIR" != "` + testPths[0] + `" ]] ; then echo "-> BITRISE_SOURCE_DIR missmatch!" exit 1 fi curr_pwd="$(pwd)" if [[ "${curr_pwd}" != "` + testPths[0] + `" ]] ; then echo "-> pwd missmatch! : curr_pwd : ${curr_pwd}" exit 1 fi ` config, err = bitrise.ConfigModelFromYAMLBytes([]byte(configStr)) require.Equal(t, nil, err) _, err = runWorkflowWithConfiguration(time.Now(), "test", config, inventory.Envs) require.Equal(t, nil, err) // // BITRISE_SOURCE_DIR defined in secret, App, Workflow and Step inventoryStr = ` envs: - BITRISE_SOURCE_DIR: "` + testPths[0] + `" ` inventory, err = bitrise.InventoryModelFromYAMLBytes([]byte(inventoryStr)) require.Equal(t, nil, err) configStr = ` format_version: 1.0.0 default_step_lib_source: "https://github.com/bitrise-io/bitrise-steplib.git" app: envs: - BITRISE_SOURCE_DIR: "` + testPths[1] + `" workflows: test: envs: - BITRISE_SOURCE_DIR: "` + testPths[2] + `" steps: - script: inputs: - content: | #!/bin/bash set -v envman add --key BITRISE_SOURCE_DIR --value ` + testPths[3] + ` - script: inputs: - content: | #!/bin/bash set -v echo "BITRISE_SOURCE_DIR: $BITRISE_SOURCE_DIR" if [[ "$BITRISE_SOURCE_DIR" != "` + testPths[3] + `" ]] ; then exit 1 fi ` config, err = bitrise.ConfigModelFromYAMLBytes([]byte(configStr)) require.Equal(t, nil, err) _, err = runWorkflowWithConfiguration(time.Now(), "test", config, inventory.Envs) require.Equal(t, nil, err) }