diff --git a/cmd/root.go b/cmd/root.go index 60a16f63..c9412fb3 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -101,7 +101,7 @@ func executePhases(cmd cobra.Command) (phases.Progress, error) { } // bitrise.yml - bitriseYML, primaryWorkflow, branch, err := phases.BitriseYML(currentDir) + bitriseYML, primaryWorkflow, branch, err := phases.BitriseYML(currentDir, progress.RegisterSSHKey) if err != nil { return phases.Progress{}, err } diff --git a/go.mod b/go.mod index c3761a75..ae4cba27 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.16 require ( github.com/Microsoft/go-winio v0.5.0 // indirect github.com/bitrise-io/bitrise v0.0.0-20210623145422-513e39485248 - github.com/bitrise-io/bitrise-init v0.0.0-20211201163403-80ed402ddf62 + github.com/bitrise-io/bitrise-init v0.0.0-20220216103435-ee05a81e7191 github.com/bitrise-io/codesigndoc v0.0.0-20210521081848-80756d2c5664 github.com/bitrise-io/envman v0.0.0-20210630102032-df85af51bd1a github.com/bitrise-io/go-steputils v0.0.0-20210527075147-910ce7a105a1 // indirect diff --git a/go.sum b/go.sum index 9a275704..2497b462 100644 --- a/go.sum +++ b/go.sum @@ -64,8 +64,8 @@ github.com/bitrise-io/bitrise v0.0.0-20210519130014-380842fb41c1/go.mod h1:Jqf2P github.com/bitrise-io/bitrise v0.0.0-20210623145422-513e39485248 h1:GfhBF379/Uwu4fmalhwwoJv3RcqlrlEo8+gGEcuXLsw= github.com/bitrise-io/bitrise v0.0.0-20210623145422-513e39485248/go.mod h1:jqk9VdrvlRpRfIqA2DZHVNEMvPycmlpBfpiKxk89R6w= github.com/bitrise-io/bitrise-init v0.0.0-20210520122036-d213de321eb8/go.mod h1:I9KSWJm177/IOBMQHzn6BLgymVLQ0xlv/gMwDCYkWYU= -github.com/bitrise-io/bitrise-init v0.0.0-20211201163403-80ed402ddf62 h1:+odtVYBzY6JfxkF6qLmq9SjW1A3X1fFN1CKkZoQwSME= -github.com/bitrise-io/bitrise-init v0.0.0-20211201163403-80ed402ddf62/go.mod h1:I9KSWJm177/IOBMQHzn6BLgymVLQ0xlv/gMwDCYkWYU= +github.com/bitrise-io/bitrise-init v0.0.0-20220216103435-ee05a81e7191 h1:JORLDNlDVoneF//I31krPFBPZzcl2+Q6x8bWGrzXMjI= +github.com/bitrise-io/bitrise-init v0.0.0-20220216103435-ee05a81e7191/go.mod h1:I9KSWJm177/IOBMQHzn6BLgymVLQ0xlv/gMwDCYkWYU= github.com/bitrise-io/codesigndoc v0.0.0-20210521081848-80756d2c5664 h1:4zk2SY5iKjAqgKmIcAxkAftjrw7pfdoXFSh64pDz5Hw= github.com/bitrise-io/codesigndoc v0.0.0-20210521081848-80756d2c5664/go.mod h1:Eql38Q+rFrTpKe/+E6m1Ecx2NsmPYjbuq6eWcGed6CY= github.com/bitrise-io/colorstring v0.0.0-20180614154802-a8cd70115192/go.mod h1:CIHVcxZUvsG99XUJV6JlR7okNsMMGY81jMvPC20W+O0= diff --git a/phases/bitrise_yml.go b/phases/bitrise_yml.go index 1b34dd8a..757aee0d 100644 --- a/phases/bitrise_yml.go +++ b/phases/bitrise_yml.go @@ -231,7 +231,7 @@ func selectWorkflow(buildBitriseYML models.BitriseDataModel, inputReader io.Read return workflow, nil } -func getBitriseYML(searchDir string, inputReader io.Reader) (models.BitriseDataModel, string, error) { +func getBitriseYML(searchDir string, inputReader io.Reader, isPrivateRepo bool) (models.BitriseDataModel, string, error) { potentialBitriseYMLFilePath := filepath.Join(searchDir, bitriseYMLName) if exist, err := pathutil.IsPathExists(potentialBitriseYMLFilePath); err != nil { return models.BitriseDataModel{}, "", fmt.Errorf("failed to check if file (%s) exists, error: %s", potentialBitriseYMLFilePath, err) @@ -289,7 +289,7 @@ func getBitriseYML(searchDir string, inputReader io.Reader) (models.BitriseDataM fmt.Println() - scanResult, found := scanner.GenerateScanResult(searchDir) + scanResult, found := scanner.GenerateScanResult(searchDir, isPrivateRepo) if !found { log.Infof("Projects not found in repository. Select manual configuration.") scanResult, err = scanner.ManualConfig() @@ -311,10 +311,10 @@ func getBitriseYML(searchDir string, inputReader io.Reader) (models.BitriseDataM } // BitriseYML ... -func BitriseYML(searchDir string) (models.BitriseDataModel, string, string, error) { +func BitriseYML(searchDir string, isPrivateRepo bool) (models.BitriseDataModel, string, string, error) { fmt.Println() log.Infof("SETUP BITRISE.YML") - bitriseYML, branch, err := getBitriseYML(searchDir, os.Stdin) + bitriseYML, branch, err := getBitriseYML(searchDir, os.Stdin, isPrivateRepo) if err != nil { return models.BitriseDataModel{}, "", "", err } diff --git a/vendor/github.com/bitrise-io/bitrise-init/models/configbuilder.go b/vendor/github.com/bitrise-io/bitrise-init/models/configbuilder.go index fcb5ab09..af85ee5c 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/models/configbuilder.go +++ b/vendor/github.com/bitrise-io/bitrise-init/models/configbuilder.go @@ -68,17 +68,7 @@ func (builder *ConfigBuilderModel) Generate(projectType string, appEnvs ...envma workflows[string(workflowID)] = workflowBuilder.generate() } - triggerMap := []bitriseModels.TriggerMapItemModel{ - bitriseModels.TriggerMapItemModel{ - PushBranch: "*", - WorkflowID: string(PrimaryWorkflowID), - }, - bitriseModels.TriggerMapItemModel{ - PullRequestSourceBranch: "*", - WorkflowID: string(PrimaryWorkflowID), - }, - } - + triggerMap := []bitriseModels.TriggerMapItemModel{} app := bitriseModels.AppModel{ Environments: appEnvs, } diff --git a/vendor/github.com/bitrise-io/bitrise-init/scanner/config.go b/vendor/github.com/bitrise-io/bitrise-init/scanner/config.go index 17d63c80..18571ee3 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/scanner/config.go +++ b/vendor/github.com/bitrise-io/bitrise-init/scanner/config.go @@ -87,7 +87,7 @@ func (o *scannerOutput) AddWarnings(tag string, errs ...string) { } // Config ... -func Config(searchDir string) models.ScanResultModel { +func Config(searchDir string, isPrivateRepository bool) models.ScanResultModel { result := models.ScanResultModel{} // @@ -148,7 +148,7 @@ func Config(searchDir string) models.ScanResultModel { // Collect scanner outputs, by scanner name scannerToOutput := map[string]scannerOutput{} { - projectScannerToOutputs := runScanners(scanners.ProjectScanners, searchDir) + projectScannerToOutputs := runScanners(scanners.ProjectScanners, searchDir, isPrivateRepository) detectedProjectTypes := getDetectedScannerNames(projectScannerToOutputs) log.Printf("Detected project types: %s", detectedProjectTypes) fmt.Println() @@ -162,7 +162,7 @@ func Config(searchDir string) models.ScanResultModel { toolScanner.(scanners.AutomationToolScanner).SetDetectedProjectTypes(detectedProjectTypes) } - toolScannerToOutputs := runScanners(scanners.AutomationToolScanners, searchDir) + toolScannerToOutputs := runScanners(scanners.AutomationToolScanners, searchDir, isPrivateRepository) detectedAutomationToolScanners := getDetectedScannerNames(toolScannerToOutputs) log.Printf("Detected automation tools: %s", detectedAutomationToolScanners) fmt.Println() @@ -213,7 +213,7 @@ func Config(searchDir string) models.ScanResultModel { } } -func runScanners(scannerList []scanners.ScannerInterface, searchDir string) map[string]scannerOutput { +func runScanners(scannerList []scanners.ScannerInterface, searchDir string, isPrivateRepository bool) map[string]scannerOutput { scannerOutputs := map[string]scannerOutput{} var excludedScannerNames []string for _, scanner := range scannerList { @@ -226,7 +226,7 @@ func runScanners(scannerList []scanners.ScannerInterface, searchDir string) map[ log.TPrintf("+------------------------------------------------------------------------------+") log.TPrintf("| |") - scannerOutput := runScanner(scanner, searchDir) + scannerOutput := runScanner(scanner, searchDir, isPrivateRepository) log.TPrintf("| |") log.TPrintf("+------------------------------------------------------------------------------+") fmt.Println() @@ -238,7 +238,7 @@ func runScanners(scannerList []scanners.ScannerInterface, searchDir string) map[ } // Collect output of a specific scanner -func runScanner(detector scanners.ScannerInterface, searchDir string) scannerOutput { +func runScanner(detector scanners.ScannerInterface, searchDir string, isPrivateRepository bool) scannerOutput { output := scannerOutput{} if isDetect, err := detector.DetectPlatform(searchDir); err != nil { @@ -275,7 +275,7 @@ func runScanner(detector scanners.ScannerInterface, searchDir string) scannerOut } // Generate configs - configs, err := detector.Configs() + configs, err := detector.Configs(isPrivateRepository) if err != nil { data := detectorErrorData(detector.Name(), err) analytics.LogError(configsFailedTag, data, "%s detector Configs failed", detector.Name()) diff --git a/vendor/github.com/bitrise-io/bitrise-init/scanner/errors.go b/vendor/github.com/bitrise-io/bitrise-init/scanner/errors.go index 33a5e83d..4bc95d14 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/scanner/errors.go +++ b/vendor/github.com/bitrise-io/bitrise-init/scanner/errors.go @@ -69,7 +69,9 @@ func availableScanners() (scannerNames []string) { func newDetectPlatformFailedMatcher() *errormapper.PatternErrorMatcher { return newPatternErrorMatcher( newDetectPlatformFailedGenericDetail, - nil, + map[string]errormapper.DetailedErrorBuilder{ + `No Gradle Wrapper \(gradlew\) found\.`: newGradlewNotFoundDetail, + }, ) } @@ -85,10 +87,9 @@ func newOptionsFailedMatcher() *errormapper.PatternErrorMatcher { return newPatternErrorMatcher( newOptionsFailedGenericDetail, map[string]errormapper.DetailedErrorBuilder{ - `No Gradle Wrapper \(gradlew\) found\.`: newGradlewNotFoundDetail, `app\.json file \((.+)\) missing or empty (.+) entry\nThe app\.json file needs to contain:`: newAppJSONIssueDetail, `app\.json file \((.+)\) missing or empty (.+) entry\nIf the project uses Expo Kit the app.json file needs to contain:`: newExpoAppJSONIssueDetail, - `Cordova config.xml not found.`: newIonicCapacitorNotSupportedIssueDetail, + `Cordova config.xml not found.`: newIonicCapacitorNotSupportedIssueDetail, }, ) } diff --git a/vendor/github.com/bitrise-io/bitrise-init/scanner/result.go b/vendor/github.com/bitrise-io/bitrise-init/scanner/result.go index f761b335..dd5b6a3a 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/scanner/result.go +++ b/vendor/github.com/bitrise-io/bitrise-init/scanner/result.go @@ -6,19 +6,18 @@ import ( "path" "path/filepath" - "github.com/bitrise-io/bitrise-init/errormapper" - "github.com/bitrise-io/go-steputils/step" - "github.com/bitrise-io/bitrise-init/analytics" + "github.com/bitrise-io/bitrise-init/errormapper" "github.com/bitrise-io/bitrise-init/models" "github.com/bitrise-io/bitrise-init/output" + "github.com/bitrise-io/go-steputils/step" "github.com/bitrise-io/go-utils/command" "github.com/bitrise-io/go-utils/log" ) // GenerateScanResult runs the scanner, returns the results and if any platform was detected. -func GenerateScanResult(searchDir string) (models.ScanResultModel, bool) { - scanResult := Config(searchDir) +func GenerateScanResult(searchDir string, isPrivateRepository bool) (models.ScanResultModel, bool) { + scanResult := Config(searchDir, isPrivateRepository) var platforms []string for platform := range scanResult.ScannerToOptionRoot { @@ -43,7 +42,7 @@ func GenerateScanResult(searchDir string) (models.ScanResultModel, bool) { // GenerateAndWriteResults runs the scanner and saves results to the given output dir. func GenerateAndWriteResults(searchDir string, outputDir string, format output.Format) (models.ScanResultModel, error) { - result, detected := GenerateScanResult(searchDir) + result, detected := GenerateScanResult(searchDir, true) // Write output to files log.TInfof("Saving outputs:") diff --git a/vendor/github.com/bitrise-io/bitrise-init/scanners/android/android.go b/vendor/github.com/bitrise-io/bitrise-init/scanners/android/android.go index b7e2e9d4..7f7d6ffa 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/scanners/android/android.go +++ b/vendor/github.com/bitrise-io/bitrise-init/scanners/android/android.go @@ -13,10 +13,7 @@ import ( // Scanner ... type Scanner struct { - SearchDir string - ProjectRoots []string - ExcludeTest bool - ExcludeAppIcon bool + Projects []Project } // NewScanner ... @@ -36,8 +33,14 @@ func (*Scanner) ExcludedScannerNames() []string { // DetectPlatform ... func (scanner *Scanner) DetectPlatform(searchDir string) (_ bool, err error) { - scanner.SearchDir = searchDir + projects, err := detect(searchDir) + scanner.Projects = projects + detected := len(projects) > 0 + return detected, err +} + +func detect(searchDir string) ([]Project, error) { projectFiles := fileGroups{ {"build.gradle", "build.gradle.kts"}, {"settings.gradle", "settings.gradle.kts"}, @@ -46,59 +49,98 @@ func (scanner *Scanner) DetectPlatform(searchDir string) (_ bool, err error) { log.TInfof("Searching for android files") - scanner.ProjectRoots, err = walkMultipleFileGroups(searchDir, projectFiles, skipDirs) + projectRoots, err := walkMultipleFileGroups(searchDir, projectFiles, skipDirs) if err != nil { - return false, fmt.Errorf("failed to search for build.gradle files, error: %s", err) + return nil, fmt.Errorf("failed to search for build.gradle files, error: %s", err) + } + + log.TPrintf("%d android files detected", len(projectRoots)) + for _, file := range projectRoots { + log.TPrintf("- %s", file) } + if len(projectRoots) == 0 { + return nil, nil + } log.TSuccessf("Platform detected") - for _, file := range projectFiles { - log.TPrintf("- %s", file) + projects, err := parseProjects(searchDir, projectRoots) + if err != nil { + return nil, err } - countDetected := len(scanner.ProjectRoots) - log.TPrintf("%d android files detected", countDetected) - nonZeroCount := countDetected > 0 - return nonZeroCount, err + + return projects, nil } -// Options ... -func (scanner *Scanner) Options() (models.OptionNode, models.Warnings, models.Icons, error) { - projectLocationOption := models.NewOption(ProjectLocationInputTitle, ProjectLocationInputSummary, ProjectLocationInputEnvKey, models.TypeSelector) - warnings := models.Warnings{} - appIconsAllProjects := models.Icons{} +func parseProjects(searchDir string, projectRoots []string) ([]Project, error) { + var ( + lastErr error + projects []Project + ) + + for _, projectRoot := range projectRoots { + var warnings models.Warnings + + log.TInfof("Investigating Android project: %s", projectRoot) - foundOptions := false - var lastErr error = nil - for _, projectRoot := range scanner.ProjectRoots { exists, err := containsLocalProperties(projectRoot) if err != nil { lastErr = err + log.TWarnf("%s", err) + continue } if exists { containsLocalPropertiesWarning := fmt.Sprintf("the local.properties file should NOT be checked into Version Control Systems, as it contains information specific to your local configuration, the location of the file is: %s", filepath.Join(projectRoot, "local.properties")) - warnings = append(warnings, containsLocalPropertiesWarning) + warnings = []string{containsLocalPropertiesWarning} } if err := checkGradlew(projectRoot); err != nil { lastErr = err + log.TWarnf("%s", err) + continue } - relProjectRoot, err := filepath.Rel(scanner.SearchDir, projectRoot) + relProjectRoot, err := filepath.Rel(searchDir, projectRoot) if err != nil { lastErr = err + log.TWarnf("%s", err) + continue } - icons, err := LookupIcons(projectRoot, scanner.SearchDir) + icons, err := LookupIcons(projectRoot, searchDir) if err != nil { analytics.LogInfo("android-icon-lookup", analytics.DetectorErrorData("android", err), "Failed to lookup android icon") } - appIconsAllProjects = append(appIconsAllProjects, icons...) - iconIDs := make([]string, len(icons)) - for i, icon := range icons { + + projects = append(projects, Project{ + RelPath: relProjectRoot, + Icons: icons, + Warnings: warnings, + }) + } + + if len(projects) == 0 { + return []Project{}, lastErr + } + + return projects, nil +} + +// Options ... +func (scanner *Scanner) Options() (models.OptionNode, models.Warnings, models.Icons, error) { + projectLocationOption := models.NewOption(ProjectLocationInputTitle, ProjectLocationInputSummary, ProjectLocationInputEnvKey, models.TypeSelector) + warnings := models.Warnings{} + appIconsAllProjects := models.Icons{} + + for _, project := range scanner.Projects { + warnings = append(warnings, project.Warnings...) + appIconsAllProjects = append(appIconsAllProjects, project.Icons...) + + iconIDs := make([]string, len(project.Icons)) + for i, icon := range project.Icons { iconIDs[i] = icon.Filename } @@ -106,13 +148,9 @@ func (scanner *Scanner) Options() (models.OptionNode, models.Warnings, models.Ic moduleOption := models.NewOption(ModuleInputTitle, ModuleInputSummary, ModuleInputEnvKey, models.TypeUserInput) variantOption := models.NewOption(VariantInputTitle, VariantInputSummary, VariantInputEnvKey, models.TypeOptionalUserInput) - projectLocationOption.AddOption(relProjectRoot, moduleOption) + projectLocationOption.AddOption(project.RelPath, moduleOption) moduleOption.AddOption("app", variantOption) variantOption.AddConfig("", configOption) - foundOptions = true - } - if !foundOptions && lastErr != nil { - return models.OptionNode{}, warnings, nil, lastErr } return *projectLocationOption, warnings, appIconsAllProjects, nil @@ -133,8 +171,8 @@ func (scanner *Scanner) DefaultOptions() models.OptionNode { } // Configs ... -func (scanner *Scanner) Configs() (models.BitriseConfigMap, error) { - configBuilder := scanner.generateConfigBuilder() +func (scanner *Scanner) Configs(isPrivateRepository bool) (models.BitriseConfigMap, error) { + configBuilder := scanner.generateConfigBuilder(isPrivateRepository) config, err := configBuilder.Generate(ScannerName) if err != nil { @@ -153,7 +191,7 @@ func (scanner *Scanner) Configs() (models.BitriseConfigMap, error) { // DefaultConfigs ... func (scanner *Scanner) DefaultConfigs() (models.BitriseConfigMap, error) { - configBuilder := scanner.generateConfigBuilder() + configBuilder := scanner.generateConfigBuilder(true) config, err := configBuilder.Generate(ScannerName) if err != nil { diff --git a/vendor/github.com/bitrise-io/bitrise-init/scanners/android/const.go b/vendor/github.com/bitrise-io/bitrise-init/scanners/android/const.go index f5df5aee..0cc8df5e 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/scanners/android/const.go +++ b/vendor/github.com/bitrise-io/bitrise-init/scanners/android/const.go @@ -1,34 +1,16 @@ package android -const deployWorkflowDescription = `## How to get a signed APK +const ( + primaryWorkflowDescription = `Runs tests. -This workflow contains the **Sign APK** step. To sign your APK all you have to do is to: - -1. Click on **Code Signing** tab -1. Find the **ANDROID KEYSTORE FILE** section -1. Click or drop your file on the upload file field -1. Fill the displayed 3 input fields: - 1. **Keystore password** - 1. **Keystore alias** - 1. **Private key password** -1. Click on **[Save metadata]** button - -That's it! From now on, **Sign APK** step will receive your uploaded files. - -## To run this workflow - -If you want to run this workflow manually: - -1. Open the app's build list page -2. Click on **[Start/Schedule a Build]** button -3. Select **deploy** in **Workflow** dropdown input -4. Click **[Start Build]** button - -Or if you need this workflow to be started by a GIT event: +Next steps: +- Check out [Getting started with Android apps](https://devcenter.bitrise.io/en/getting-started/getting-started-with-android-apps.html). +` -1. Click on **Triggers** tab -2. Setup your desired event (push/tag/pull) and select **deploy** workflow -3. Click on **[Done]** and then **[Save]** buttons + deployWorkflowDescription = `Deploys app using [Deploy to bitrise.io Step](https://devcenter.bitrise.io/en/getting-started/getting-started-with-android-apps.html#deploying-an-android-app-to-bitrise-io-53056). -The next change in your repository that matches any of your trigger map event will start **deploy** workflow. +Next steps: +- Check out [Getting started with Android apps](https://devcenter.bitrise.io/en/getting-started/getting-started-with-android-apps.html) for signing and deployment options. +- [Set up code signing with *Android Sign* Step](https://devcenter.bitrise.io/en/code-signing/android-code-signing/android-code-signing-using-the-android-sign-step.html). ` +) diff --git a/vendor/github.com/bitrise-io/bitrise-init/scanners/android/utility.go b/vendor/github.com/bitrise-io/bitrise-init/scanners/android/utility.go index 21df1f61..b53a5bfa 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/scanners/android/utility.go +++ b/vendor/github.com/bitrise-io/bitrise-init/scanners/android/utility.go @@ -42,6 +42,13 @@ const ( GradlewPathInputKey = "gradlew_path" ) +// Project is an Android project on the filesystem +type Project struct { + RelPath string + Icons models.Icons + Warnings models.Warnings +} + func walk(src string, fn func(path string, info os.FileInfo) error) error { return filePathWalk(src, func(path string, info os.FileInfo, err error) error { if err != nil { @@ -131,24 +138,19 @@ that the right Gradle version is installed and used for the build. More info/gui return nil } -func (scanner *Scanner) generateConfigBuilder() models.ConfigBuilderModel { +func (scanner *Scanner) generateConfigBuilder(isPrivateRepository bool) models.ConfigBuilderModel { configBuilder := models.NewDefaultConfigBuilder() projectLocationEnv, gradlewPath, moduleEnv, variantEnv := "$"+ProjectLocationInputEnvKey, "$"+ProjectLocationInputEnvKey+"/gradlew", "$"+ModuleInputEnvKey, "$"+VariantInputEnvKey //-- primary - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultPrepareStepList(true)...) + configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultPrepareStepListV2(steps.PrepareListParams{ + ShouldIncludeCache: true, + ShouldIncludeActivateSSH: isPrivateRepository, + })...) configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.InstallMissingAndroidToolsStepListItem( envmanModels.EnvironmentItemModel{GradlewPathInputKey: gradlewPath}, )) - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.AndroidLintStepListItem( - envmanModels.EnvironmentItemModel{ - ProjectLocationInputKey: projectLocationEnv, - }, - envmanModels.EnvironmentItemModel{ - VariantInputKey: variantEnv, - }, - )) configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.AndroidUnitTestStepListItem( envmanModels.EnvironmentItemModel{ ProjectLocationInputKey: projectLocationEnv, @@ -157,10 +159,14 @@ func (scanner *Scanner) generateConfigBuilder() models.ConfigBuilderModel { VariantInputKey: variantEnv, }, )) - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultDeployStepList(true)...) + configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultDeployStepListV2(true)...) + configBuilder.SetWorkflowDescriptionTo(models.PrimaryWorkflowID, primaryWorkflowDescription) //-- deploy - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultPrepareStepList(true)...) + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultPrepareStepListV2(steps.PrepareListParams{ + ShouldIncludeCache: true, + ShouldIncludeActivateSSH: isPrivateRepository, + })...) configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.InstallMissingAndroidToolsStepListItem( envmanModels.EnvironmentItemModel{GradlewPathInputKey: gradlewPath}, )) @@ -198,7 +204,7 @@ func (scanner *Scanner) generateConfigBuilder() models.ConfigBuilderModel { }, )) configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.SignAPKStepListItem()) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultDeployStepList(true)...) + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultDeployStepListV2(true)...) configBuilder.SetWorkflowDescriptionTo(models.DeployWorkflowID, deployWorkflowDescription) diff --git a/vendor/github.com/bitrise-io/bitrise-init/scanners/cordova/cordova.go b/vendor/github.com/bitrise-io/bitrise-init/scanners/cordova/cordova.go index a0a5bd32..3546ac7c 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/scanners/cordova/cordova.go +++ b/vendor/github.com/bitrise-io/bitrise-init/scanners/cordova/cordova.go @@ -5,16 +5,16 @@ import ( "path/filepath" "strings" - yaml "gopkg.in/yaml.v2" + envmanModels "github.com/bitrise-io/envman/models" "github.com/bitrise-io/bitrise-init/models" "github.com/bitrise-io/bitrise-init/scanners/android" "github.com/bitrise-io/bitrise-init/scanners/ios" "github.com/bitrise-io/bitrise-init/steps" "github.com/bitrise-io/bitrise-init/utility" - envmanModels "github.com/bitrise-io/envman/models" "github.com/bitrise-io/go-utils/log" "github.com/bitrise-io/go-utils/pathutil" + "gopkg.in/yaml.v2" ) // ScannerName ... @@ -282,17 +282,19 @@ func (*Scanner) DefaultOptions() models.OptionNode { } // Configs ... -func (scanner *Scanner) Configs() (models.BitriseConfigMap, error) { +func (scanner *Scanner) Configs(_ bool) (models.BitriseConfigMap, error) { configBuilder := models.NewDefaultConfigBuilder() configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultPrepareStepList(false)...) workdirEnvList := []envmanModels.EnvironmentItemModel{} + workdir := "" if scanner.relCordovaConfigDir != "" { - workdirEnvList = append(workdirEnvList, envmanModels.EnvironmentItemModel{workDirInputKey: "$" + workDirInputEnvKey}) + workdir = "$" + workDirInputEnvKey + workdirEnvList = append(workdirEnvList, envmanModels.EnvironmentItemModel{workDirInputKey: workdir}) } if scanner.hasJasmineTest || scanner.hasKarmaJasmineTest { - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.NpmStepListItem(append(workdirEnvList, envmanModels.EnvironmentItemModel{"command": "install"})...)) + configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.NpmStepListItem("install", workdir)) // CI if scanner.hasKarmaJasmineTest { @@ -306,7 +308,7 @@ func (scanner *Scanner) Configs() (models.BitriseConfigMap, error) { configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultPrepareStepList(false)...) configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.CertificateAndProfileInstallerStepListItem()) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.NpmStepListItem(append(workdirEnvList, envmanModels.EnvironmentItemModel{"command": "install"})...)) + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.NpmStepListItem("install", workdir)) if scanner.hasKarmaJasmineTest { configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.KarmaJasmineTestRunnerStepListItem(workdirEnvList...)) @@ -342,7 +344,7 @@ func (scanner *Scanner) Configs() (models.BitriseConfigMap, error) { } configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.CertificateAndProfileInstallerStepListItem()) - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.NpmStepListItem(append(workdirEnvList, envmanModels.EnvironmentItemModel{"command": "install"})...)) + configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.NpmStepListItem("install", workdir)) configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.GenerateCordovaBuildConfigStepListItem()) @@ -378,9 +380,7 @@ func (*Scanner) DefaultConfigs() (models.BitriseConfigMap, error) { configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.CertificateAndProfileInstallerStepListItem()) - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.NpmStepListItem( - envmanModels.EnvironmentItemModel{"command": "install"}, - envmanModels.EnvironmentItemModel{workDirInputKey: "$" + workDirInputEnvKey})) + configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.NpmStepListItem("install", "$"+workDirInputEnvKey)) configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.GenerateCordovaBuildConfigStepListItem()) diff --git a/vendor/github.com/bitrise-io/bitrise-init/scanners/fastlane/fastlane.go b/vendor/github.com/bitrise-io/bitrise-init/scanners/fastlane/fastlane.go index 388130e6..4c044a97 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/scanners/fastlane/fastlane.go +++ b/vendor/github.com/bitrise-io/bitrise-init/scanners/fastlane/fastlane.go @@ -2,6 +2,7 @@ package fastlane import ( "fmt" + "github.com/bitrise-io/go-utils/pathutil" "gopkg.in/yaml.v2" @@ -186,7 +187,7 @@ func (*Scanner) DefaultOptions() models.OptionNode { } // Configs ... -func (scanner *Scanner) Configs() (models.BitriseConfigMap, error) { +func (scanner *Scanner) Configs(_ bool) (models.BitriseConfigMap, error) { generateConfig := func(isIOS bool) (bitriseModels.BitriseDataModel, error) { configBuilder := models.NewDefaultConfigBuilder() configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultPrepareStepList(false)...) diff --git a/vendor/github.com/bitrise-io/bitrise-init/scanners/flutter/const.go b/vendor/github.com/bitrise-io/bitrise-init/scanners/flutter/const.go new file mode 100644 index 00000000..70fb26bb --- /dev/null +++ b/vendor/github.com/bitrise-io/bitrise-init/scanners/flutter/const.go @@ -0,0 +1,18 @@ +package flutter + +const ( + primaryWorkflowDescription = `Builds project and runs tests. + +Next steps: +- Check out [Getting started with Flutter apps](https://devcenter.bitrise.io/en/getting-started/getting-started-with-flutter-apps.html). +` + + deployWorkflowDescription = `Builds and deploys app using [Deploy to bitrise.io Step](https://devcenter.bitrise.io/en/getting-started/getting-started-with-flutter-apps.html#deploying-a-flutter-app). + +If you build for iOS, make sure to set up code signing secrets on Bitrise for a successful build. + +Next steps: +- Check out [Getting started with Flutter apps](https://devcenter.bitrise.io/en/getting-started/getting-started-with-flutter-apps.html) for signing and deployment options. +- Check out the [Code signing guide](https://devcenter.bitrise.io/en/code-signing.html) for iOS and Android +` +) diff --git a/vendor/github.com/bitrise-io/bitrise-init/scanners/flutter/flutter.go b/vendor/github.com/bitrise-io/bitrise-init/scanners/flutter/flutter.go index 9b03a300..4afc5a7d 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/scanners/flutter/flutter.go +++ b/vendor/github.com/bitrise-io/bitrise-init/scanners/flutter/flutter.go @@ -16,30 +16,26 @@ import ( envmanModels "github.com/bitrise-io/envman/models" "github.com/bitrise-io/go-utils/log" "github.com/bitrise-io/go-xcode/xcodeproject/xcworkspace" - yaml "gopkg.in/yaml.v2" + "gopkg.in/yaml.v2" ) const ( scannerName = "flutter" configName = "flutter-config" projectLocationInputKey = "project_location" - platformInputKey = "platform" - defaultIOSConfiguration = "Release" projectLocationInputEnvKey = "BITRISE_FLUTTER_PROJECT_LOCATION" projectLocationInputTitle = "Project location" - projectTypeInputEnvKey = "BITRISE_FLUTTER_PROJECT_TYPE" - projectTypeInputTitle = "Project Type" - testsInputTitle = "Run tests found in the project" - platformInputTitle = "Platform" projectLocationInputSummary = "The path to your Flutter project, stored as an Environment Variable. In your Workflows, you can specify paths relative to this path. You can change this at any time." - testsInputSummary = "Our Flutter Test Step can run the tests found in your project's repository." + platformInputKey = "platform" + platformInputTitle = "Platform" platformInputSummary = "The target platform for your first build. Your options are iOS, Android, both, or neither. You can change this in your Env Vars at any time." + iosOutputTypeKey = "ios_output_type" + iosOutputTypeArchive = "archive" installerUpdateFlutterKey = "is_update" ) var ( platforms = []string{ - "none", "android", "ios", "both", @@ -249,75 +245,16 @@ func (scanner *Scanner) Options() (models.OptionNode, models.Warnings, models.Ic flutterProjectLocationOption := models.NewOption(projectLocationInputTitle, projectLocationInputSummary, projectLocationInputEnvKey, models.TypeSelector) for _, project := range scanner.projects { + var testKey string if project.hasTest { - flutterProjectHasTestOption := models.NewOption(testsInputTitle, testsInputSummary, "", models.TypeSelector) - flutterProjectLocationOption.AddOption(project.path, flutterProjectHasTestOption) - - for _, v := range []string{"yes", "no"} { - cfg := configName - if v == "yes" { - cfg += "-test" - } - - if project.hasIosProject || project.hasAndroidProject { - if project.hasIosProject { - projectPathOption := models.NewOption(ios.ProjectPathInputTitle, ios.ProjectPathInputSummary, ios.ProjectPathInputEnvKey, models.TypeSelector) - flutterProjectHasTestOption.AddOption(v, projectPathOption) - - for xcodeWorkspacePath, schemes := range project.xcodeProjectPaths { - schemeOption := models.NewOption(ios.SchemeInputTitle, ios.SchemeInputSummary, ios.SchemeInputEnvKey, models.TypeSelector) - projectPathOption.AddOption(xcodeWorkspacePath, schemeOption) - - for _, scheme := range schemes { - distributionMethodOption := models.NewOption(ios.DistributionMethodInputTitle, ios.DistributionMethodInputSummary, ios.DistributionMethodEnvKey, models.TypeSelector) - schemeOption.AddOption(scheme, distributionMethodOption) - - for _, exportMethod := range ios.IosExportMethods { - configOption := models.NewConfigOption(cfg+"-app-"+getBuildablePlatform(project.hasAndroidProject, project.hasIosProject), nil) - distributionMethodOption.AddConfig(exportMethod, configOption) - } - } - } - } else { - configOption := models.NewConfigOption(cfg+"-app-"+getBuildablePlatform(project.hasAndroidProject, project.hasIosProject), nil) - flutterProjectHasTestOption.AddOption(v, configOption) - } - } else { - configOption := models.NewConfigOption(cfg, nil) - flutterProjectHasTestOption.AddOption(v, configOption) - } - } + testKey = "test" } else { - cfg := configName - - if project.hasIosProject || project.hasAndroidProject { - if project.hasIosProject { - projectPathOption := models.NewOption(ios.ProjectPathInputTitle, ios.ProjectPathInputSummary, ios.ProjectPathInputEnvKey, models.TypeSelector) - flutterProjectLocationOption.AddOption(project.path, projectPathOption) - - for xcodeWorkspacePath, schemes := range project.xcodeProjectPaths { - schemeOption := models.NewOption(ios.SchemeInputTitle, ios.SchemeInputSummary, ios.SchemeInputEnvKey, models.TypeSelector) - projectPathOption.AddOption(xcodeWorkspacePath, schemeOption) - - for _, scheme := range schemes { - distributionMethodOption := models.NewOption(ios.DistributionMethodInputTitle, ios.DistributionMethodInputSummary, ios.DistributionMethodEnvKey, models.TypeSelector) - schemeOption.AddOption(scheme, distributionMethodOption) - - for _, exportMethod := range ios.IosExportMethods { - configOption := models.NewConfigOption(cfg+"-app-"+getBuildablePlatform(project.hasAndroidProject, project.hasIosProject), nil) - distributionMethodOption.AddConfig(exportMethod, configOption) - } - } - } - } else { - configOption := models.NewConfigOption(cfg+"-app-"+getBuildablePlatform(project.hasAndroidProject, project.hasIosProject), nil) - flutterProjectLocationOption.AddOption(project.path, configOption) - } - } else { - configOption := models.NewConfigOption(cfg, nil) - flutterProjectLocationOption.AddOption(project.path, configOption) - } + testKey = "notest" } + cfg := configName + "-" + testKey + + configOption := models.NewConfigOption(cfg+"-app-"+getBuildablePlatform(project.hasAndroidProject, project.hasIosProject), nil) + flutterProjectLocationOption.AddOption(project.path, configOption) } return *flutterProjectLocationOption, models.Warnings{}, nil, nil @@ -338,137 +275,107 @@ func getBuildablePlatform(hasAndroidProject, hasIosProject bool) string { func (Scanner) DefaultOptions() models.OptionNode { flutterProjectLocationOption := models.NewOption(projectLocationInputTitle, projectLocationInputSummary, projectLocationInputEnvKey, models.TypeUserInput) - flutterProjectHasTestOption := models.NewOption(testsInputTitle, testsInputSummary, "", models.TypeSelector) - flutterProjectLocationOption.AddOption("", flutterProjectHasTestOption) - - for _, v := range []string{"yes", "no"} { - cfg := configName - if v == "yes" { - cfg += "-test" - } - flutterPlatformOption := models.NewOption(platformInputTitle, platformInputSummary, "", models.TypeSelector) - flutterProjectHasTestOption.AddOption(v, flutterPlatformOption) - - for _, platform := range platforms { - if platform != "none" { - if platform != "android" { - projectPathOption := models.NewOption(ios.ProjectPathInputTitle, ios.ProjectPathInputSummary, ios.ProjectPathInputEnvKey, models.TypeUserInput) - flutterPlatformOption.AddOption(platform, projectPathOption) - - schemeOption := models.NewOption(ios.SchemeInputTitle, ios.SchemeInputSummary, ios.SchemeInputEnvKey, models.TypeUserInput) - projectPathOption.AddOption("", schemeOption) + cfg := configName + "-test" - distributionMethodOption := models.NewOption(ios.DistributionMethodInputTitle, ios.DistributionMethodInputSummary, ios.DistributionMethodEnvKey, models.TypeSelector) - schemeOption.AddOption("", distributionMethodOption) + flutterPlatformOption := models.NewOption(platformInputTitle, platformInputSummary, "", models.TypeSelector) + flutterProjectLocationOption.AddOption("", flutterPlatformOption) - for _, exportMethod := range ios.IosExportMethods { - configOption := models.NewConfigOption(cfg+"-app-"+platform, nil) - distributionMethodOption.AddConfig(exportMethod, configOption) - } - } else { - configOption := models.NewConfigOption(cfg+"-app-"+platform, nil) - flutterPlatformOption.AddConfig(platform, configOption) - } - } else { - configOption := models.NewConfigOption(cfg, nil) - flutterPlatformOption.AddConfig(platform, configOption) - } - } + for _, platform := range platforms { + configOption := models.NewConfigOption(cfg+"-app-"+platform, nil) + flutterPlatformOption.AddConfig(platform, configOption) } return *flutterProjectLocationOption } // Configs ... -func (scanner *Scanner) Configs() (models.BitriseConfigMap, error) { - return scanner.DefaultConfigs() +func (scanner *Scanner) Configs(isPrivateRepository bool) (models.BitriseConfigMap, error) { + return scanner.generateConfigMap(isPrivateRepository) } // DefaultConfigs ... func (scanner Scanner) DefaultConfigs() (models.BitriseConfigMap, error) { + return scanner.generateConfigMap(true) +} + +func (scanner Scanner) generateConfigMap(isPrivateRepository bool) (models.BitriseConfigMap, error) { configs := models.BitriseConfigMap{} for _, variant := range []struct { configID string test bool - deploy bool platform string }{ - {test: false, deploy: false, configID: configName}, - {test: true, deploy: false, configID: configName + "-test"}, - {test: false, deploy: true, platform: "both", configID: configName + "-app-both"}, - {test: true, deploy: true, platform: "both", configID: configName + "-test-app-both"}, - {test: false, deploy: true, platform: "android", configID: configName + "-app-android"}, - {test: true, deploy: true, platform: "android", configID: configName + "-test-app-android"}, - {test: false, deploy: true, platform: "ios", configID: configName + "-app-ios"}, - {test: true, deploy: true, platform: "ios", configID: configName + "-test-app-ios"}, + {test: false, platform: "both", configID: configName + "-notest-app-both"}, + {test: true, platform: "both", configID: configName + "-test-app-both"}, + {test: false, platform: "android", configID: configName + "-notest-app-android"}, + {test: true, platform: "android", configID: configName + "-test-app-android"}, + {test: false, platform: "ios", configID: configName + "-notest-app-ios"}, + {test: true, platform: "ios", configID: configName + "-test-app-ios"}, } { configBuilder := models.NewDefaultConfigBuilder() + // Common steps to all workflows + prepareSteps := steps.DefaultPrepareStepListV2(steps.PrepareListParams{ + ShouldIncludeCache: false, + ShouldIncludeActivateSSH: isPrivateRepository, + }) + flutterInstallStep := steps.FlutterInstallStepListItem( + envmanModels.EnvironmentItemModel{installerUpdateFlutterKey: "false"}, + ) + deploySteps := steps.DefaultDeployStepListV2(true) + // primary + configBuilder.SetWorkflowDescriptionTo(models.PrimaryWorkflowID, primaryWorkflowDescription) - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultPrepareStepList(false)...) + configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, prepareSteps...) - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.FlutterInstallStepListItem( - envmanModels.EnvironmentItemModel{installerUpdateFlutterKey: "false"}, - )) + configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, flutterInstallStep) // cache-pull is after flutter-installer, to prevent removal of pub system cache configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.CachePullStepListItem()) - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.FlutterAnalyzeStepListItem( - envmanModels.EnvironmentItemModel{projectLocationInputKey: "$" + projectLocationInputEnvKey}, - )) - if variant.test { configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.FlutterTestStepListItem( envmanModels.EnvironmentItemModel{projectLocationInputKey: "$" + projectLocationInputEnvKey}, )) } - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultDeployStepList(true)...) + configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, deploySteps...) // deploy + configBuilder.SetWorkflowDescriptionTo(models.DeployWorkflowID, deployWorkflowDescription) - if variant.deploy { - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultPrepareStepList(false)...) + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, prepareSteps...) - if variant.platform != "android" { - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.CertificateAndProfileInstallerStepListItem()) - } + if variant.platform != "android" { + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.CertificateAndProfileInstallerStepListItem()) + } - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.FlutterInstallStepListItem( - envmanModels.EnvironmentItemModel{installerUpdateFlutterKey: "false"}, - )) + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, flutterInstallStep) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.CachePullStepListItem()) + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.CachePullStepListItem()) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.FlutterAnalyzeStepListItem( - envmanModels.EnvironmentItemModel{projectLocationInputKey: "$" + projectLocationInputEnvKey}, - )) - - if variant.test { - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.FlutterTestStepListItem( - envmanModels.EnvironmentItemModel{projectLocationInputKey: "$" + projectLocationInputEnvKey}, - )) - } + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.FlutterAnalyzeStepListItem( + envmanModels.EnvironmentItemModel{projectLocationInputKey: "$" + projectLocationInputEnvKey}, + )) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.FlutterBuildStepListItem( + if variant.test { + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.FlutterTestStepListItem( envmanModels.EnvironmentItemModel{projectLocationInputKey: "$" + projectLocationInputEnvKey}, - envmanModels.EnvironmentItemModel{platformInputKey: variant.platform}, )) + } - if variant.platform != "android" { - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.XcodeArchiveStepListItem( - envmanModels.EnvironmentItemModel{ios.ProjectPathInputKey: "$" + ios.ProjectPathInputEnvKey}, - envmanModels.EnvironmentItemModel{ios.SchemeInputKey: "$" + ios.SchemeInputEnvKey}, - envmanModels.EnvironmentItemModel{ios.DistributionMethodInputKey: "$" + ios.DistributionMethodEnvKey}, - envmanModels.EnvironmentItemModel{ios.ConfigurationInputKey: defaultIOSConfiguration}, - )) - } - - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultDeployStepList(true)...) + flutterBuildInputs := []envmanModels.EnvironmentItemModel{ + {projectLocationInputKey: "$" + projectLocationInputEnvKey}, + {platformInputKey: variant.platform}, + } + if variant.platform != "android" { + flutterBuildInputs = append(flutterBuildInputs, envmanModels.EnvironmentItemModel{iosOutputTypeKey: iosOutputTypeArchive}) } + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.FlutterBuildStepListItem(flutterBuildInputs...)) + + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, deploySteps...) config, err := configBuilder.Generate(scannerName) if err != nil { diff --git a/vendor/github.com/bitrise-io/bitrise-init/scanners/ionic/ionic.go b/vendor/github.com/bitrise-io/bitrise-init/scanners/ionic/ionic.go index 2c22617d..da9726ea 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/scanners/ionic/ionic.go +++ b/vendor/github.com/bitrise-io/bitrise-init/scanners/ionic/ionic.go @@ -276,17 +276,19 @@ func (Scanner) DefaultOptions() models.OptionNode { } // Configs ... -func (scanner *Scanner) Configs() (models.BitriseConfigMap, error) { +func (scanner *Scanner) Configs(_ bool) (models.BitriseConfigMap, error) { configBuilder := models.NewDefaultConfigBuilder() configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultPrepareStepList(false)...) workdirEnvList := []envmanModels.EnvironmentItemModel{} + workdir := "" if scanner.relCordovaConfigDir != "" { - workdirEnvList = append(workdirEnvList, envmanModels.EnvironmentItemModel{workDirInputKey: "$" + workDirInputEnvKey}) + workdir = "$" + workDirInputEnvKey + workdirEnvList = append(workdirEnvList, envmanModels.EnvironmentItemModel{workDirInputKey: workdir}) } if scanner.hasJasmineTest || scanner.hasKarmaJasmineTest { - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.NpmStepListItem(append(workdirEnvList, envmanModels.EnvironmentItemModel{"command": "install"})...)) + configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.NpmStepListItem("install", workdir)) // CI if scanner.hasKarmaJasmineTest { @@ -300,7 +302,7 @@ func (scanner *Scanner) Configs() (models.BitriseConfigMap, error) { configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultPrepareStepList(false)...) configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.CertificateAndProfileInstallerStepListItem()) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.NpmStepListItem(append(workdirEnvList, envmanModels.EnvironmentItemModel{"command": "install"})...)) + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.NpmStepListItem("install", workdir)) if scanner.hasKarmaJasmineTest { configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.KarmaJasmineTestRunnerStepListItem(workdirEnvList...)) @@ -336,7 +338,7 @@ func (scanner *Scanner) Configs() (models.BitriseConfigMap, error) { } configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.CertificateAndProfileInstallerStepListItem()) - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.NpmStepListItem(append(workdirEnvList, envmanModels.EnvironmentItemModel{"command": "install"})...)) + configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.NpmStepListItem("install", workdir)) configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.GenerateCordovaBuildConfigStepListItem()) @@ -372,9 +374,7 @@ func (Scanner) DefaultConfigs() (models.BitriseConfigMap, error) { configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.CertificateAndProfileInstallerStepListItem()) - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.NpmStepListItem( - envmanModels.EnvironmentItemModel{"command": "install"}, - envmanModels.EnvironmentItemModel{workDirInputKey: "$" + workDirInputEnvKey})) + configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.NpmStepListItem("install", "$"+workDirInputEnvKey)) configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.GenerateCordovaBuildConfigStepListItem()) configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.IonicArchiveStepListItem( diff --git a/vendor/github.com/bitrise-io/bitrise-init/scanners/ios/appclip.go b/vendor/github.com/bitrise-io/bitrise-init/scanners/ios/appclip.go new file mode 100644 index 00000000..8577cbe3 --- /dev/null +++ b/vendor/github.com/bitrise-io/bitrise-init/scanners/ios/appclip.go @@ -0,0 +1,36 @@ +package ios + +import ( + "github.com/bitrise-io/bitrise-init/models" + "github.com/bitrise-io/bitrise-init/steps" + envmanModels "github.com/bitrise-io/envman/models" + "github.com/bitrise-io/go-xcode/xcodeproj" +) + +func schemeHasAppClipTarget(scheme xcodeproj.SchemeModel, targets []xcodeproj.TargetModel) bool { + for _, target := range targets { + for _, referenceID := range scheme.BuildableReferenceIDs { + if referenceID == target.ID && target.HasAppClip { + return true + } + } + } + + return false +} + +func shouldAppendExportAppClipStep(hasAppClip bool, exportMethod string) bool { + return hasAppClip && + (exportMethod == "development" || exportMethod == "ad-hoc") +} + +func appendExportAppClipStep(configBuilder *models.ConfigBuilderModel, workflowID models.WorkflowID) { + exportXCArchiveStepInputModels := []envmanModels.EnvironmentItemModel{ + {ProjectPathInputKey: "$" + ProjectPathInputEnvKey}, + {SchemeInputKey: "$" + SchemeInputEnvKey}, + {ExportXCArchiveProductInputKey: ExportXCArchiveProductInputAppClipValue}, + {DistributionMethodInputKey: "$" + DistributionMethodEnvKey}, + {AutomaticCodeSigningKey: AutomaticCodeSigningValue}, + } + configBuilder.AppendStepListItemsTo(workflowID, steps.ExportXCArchiveStepListItem(exportXCArchiveStepInputModels...)) +} diff --git a/vendor/github.com/bitrise-io/bitrise-init/scanners/ios/ios.go b/vendor/github.com/bitrise-io/bitrise-init/scanners/ios/ios.go index 9207664f..caa41e09 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/scanners/ios/ios.go +++ b/vendor/github.com/bitrise-io/bitrise-init/scanners/ios/ios.go @@ -8,8 +8,10 @@ import "github.com/bitrise-io/bitrise-init/models" // Scanner ... type Scanner struct { - SearchDir string - ConfigDescriptors []ConfigDescriptor + DetectResult DetectResult + + ConfigDescriptors []ConfigDescriptor + ExcludeAppIcon bool SuppressPodFileParseError bool } @@ -26,13 +28,13 @@ func (Scanner) Name() string { // DetectPlatform ... func (scanner *Scanner) DetectPlatform(searchDir string) (bool, error) { - scanner.SearchDir = searchDir - - detected, err := Detect(XcodeProjectTypeIOS, searchDir) + result, err := ParseProjects(XcodeProjectTypeIOS, searchDir, scanner.ExcludeAppIcon, scanner.SuppressPodFileParseError) if err != nil { return false, err } + scanner.DetectResult = result + detected := len(result.Projects) > 0 return detected, nil } @@ -43,7 +45,7 @@ func (Scanner) ExcludedScannerNames() []string { // Options ... func (scanner *Scanner) Options() (models.OptionNode, models.Warnings, models.Icons, error) { - options, configDescriptors, icons, warnings, err := GenerateOptions(XcodeProjectTypeIOS, scanner.SearchDir, scanner.ExcludeAppIcon, scanner.SuppressPodFileParseError) + options, configDescriptors, icons, warnings, err := GenerateOptions(XcodeProjectTypeIOS, scanner.DetectResult) if err != nil { return models.OptionNode{}, warnings, nil, err } @@ -59,13 +61,13 @@ func (Scanner) DefaultOptions() models.OptionNode { } // Configs ... -func (scanner *Scanner) Configs() (models.BitriseConfigMap, error) { - return GenerateConfig(XcodeProjectTypeIOS, scanner.ConfigDescriptors, true) +func (scanner *Scanner) Configs(isPrivateRepository bool) (models.BitriseConfigMap, error) { + return GenerateConfig(XcodeProjectTypeIOS, scanner.ConfigDescriptors, isPrivateRepository) } // DefaultConfigs ... func (Scanner) DefaultConfigs() (models.BitriseConfigMap, error) { - return GenerateDefaultConfig(XcodeProjectTypeIOS, true) + return GenerateDefaultConfig(XcodeProjectTypeIOS) } // GetProjectType returns the project_type property used in a bitrise config diff --git a/vendor/github.com/bitrise-io/bitrise-init/scanners/ios/podfile.go b/vendor/github.com/bitrise-io/bitrise-init/scanners/ios/podfile.go index 6d6c2f88..b184d152 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/scanners/ios/podfile.go +++ b/vendor/github.com/bitrise-io/bitrise-init/scanners/ios/podfile.go @@ -65,15 +65,14 @@ end absPodfilePth, err := filepath.Abs(podfileParser.podfilePth) if err != nil { - return map[string]string{}, fmt.Errorf("failed to expand path (%s), error: %s", podfileParser.podfilePth, err) + return map[string]string{}, fmt.Errorf("failed to expand path (%s): %s", podfileParser.podfilePth, err) } envs := []string{fmt.Sprintf("PODFILE_PATH=%s", absPodfilePth)} - podfileDir := filepath.Dir(absPodfilePth) - out, err := runRubyScriptForOutput(rubyScriptContent, gemfileContent, podfileDir, envs) + out, err := runRubyScriptForOutput(rubyScriptContent, gemfileContent, envs) if err != nil { - return map[string]string{}, fmt.Errorf("ruby script failed, error: %s", err) + return map[string]string{}, fmt.Errorf("ruby script failed: %s", err) } if out == "" { @@ -87,11 +86,11 @@ end var targetDefinitionOutput targetDefinitionOutputModel if err := json.Unmarshal([]byte(out), &targetDefinitionOutput); err != nil { - return map[string]string{}, fmt.Errorf("failed to parse target definition output, error: %s", err) + return map[string]string{}, fmt.Errorf("failed to parse target definition output: %s", err) } if podfileParser.shouldRaiseReadDefinitionError(targetDefinitionOutput.Error) { - return map[string]string{}, fmt.Errorf("failed to read target defintion map, error: %s", targetDefinitionOutput.Error) + return map[string]string{}, fmt.Errorf("failed to read target definition map: %s", targetDefinitionOutput.Error) } return targetDefinitionOutput.Data, nil @@ -115,7 +114,7 @@ func (podfileParser podfileParser) shouldRaiseReadDefinitionError(err string) bo func (podfileParser podfileParser) getUserDefinedProjectRelavtivePath(cocoapodsVersion string) (string, error) { targetProjectMap, err := podfileParser.getTargetDefinitionProjectMap(cocoapodsVersion) if err != nil { - return "", fmt.Errorf("failed to get target definition map, error: %s", err) + return "", fmt.Errorf("failed to get target definition map: %s", err) } for target, project := range targetProjectMap { @@ -157,15 +156,14 @@ end ` absPodfilePth, err := filepath.Abs(podfileParser.podfilePth) if err != nil { - return "", fmt.Errorf("failed to expand path (%s), error: %s", podfileParser.podfilePth, err) + return "", fmt.Errorf("failed to expand path (%s): %s", podfileParser.podfilePth, err) } envs := []string{fmt.Sprintf("PODFILE_PATH=%s", absPodfilePth)} - podfileDir := filepath.Dir(absPodfilePth) - out, err := runRubyScriptForOutput(rubyScriptContent, gemfileContent, podfileDir, envs) + out, err := runRubyScriptForOutput(rubyScriptContent, gemfileContent, envs) if err != nil { - return "", fmt.Errorf("ruby script failed, error: %s", err) + return "", fmt.Errorf("ruby script failed: %s", err) } if out == "" { @@ -179,11 +177,11 @@ end var workspacePathOutput workspacePathOutputModel if err := json.Unmarshal([]byte(out), &workspacePathOutput); err != nil { - return "", fmt.Errorf("failed to parse workspace path output, error: %s", err) + return "", fmt.Errorf("failed to parse workspace path output: %s", err) } if podfileParser.shouldRaiseReadDefinitionError(workspacePathOutput.Error) { - return "", fmt.Errorf("failed to read workspace path, error: %s", workspacePathOutput.Error) + return "", fmt.Errorf("failed to read workspace path: %s", workspacePathOutput.Error) } return workspacePathOutput.Data, nil @@ -213,19 +211,19 @@ func (podfileParser podfileParser) GetWorkspaceProjectMap(projects []string) (ma projectRelPth, err := podfileParser.getUserDefinedProjectRelavtivePath(cocoapodsVersion) if err != nil { - return map[string]string{}, fmt.Errorf("failed to get user defined project path, error: %s", err) + return map[string]string{}, fmt.Errorf("failed to get user defined project path: %s", err) } if projectRelPth == "" { projects, err := pathutil.FilterPaths(projects, pathutil.InDirectoryFilter(podfileDir, true)) if err != nil { - return map[string]string{}, fmt.Errorf("failed to filter projects, error: %s", err) + return map[string]string{}, fmt.Errorf("failed to filter projects: %s", err) } if len(projects) == 0 { - return map[string]string{}, errors.New("failed to determin workspace - project mapping: no explicit project specified and no project found in the Podfile's directory") + return map[string]string{}, errors.New("failed to determine workspace - project mapping: no explicit project specified and no project found in the Podfile's directory") } else if len(projects) > 1 { - return map[string]string{}, errors.New("failed to determin workspace - project mapping: no explicit project specified and more than one project found in the Podfile's directory") + return map[string]string{}, errors.New("failed to determine workspace - project mapping: no explicit project specified and more than one project found in the Podfile's directory") } projectRelPth = filepath.Base(projects[0]) @@ -233,14 +231,14 @@ func (podfileParser podfileParser) GetWorkspaceProjectMap(projects []string) (ma projectPth := filepath.Join(podfileDir, projectRelPth) if exist, err := pathutil.IsPathExists(projectPth); err != nil { - return map[string]string{}, fmt.Errorf("failed to check if path (%s) exists, error: %s", projectPth, err) + return map[string]string{}, fmt.Errorf("failed to check if path (%s) exists: %s", projectPth, err) } else if !exist { return map[string]string{}, fmt.Errorf("project not found at: %s", projectPth) } workspaceRelPth, err := podfileParser.getUserDefinedWorkspaceRelativePath(cocoapodsVersion) if err != nil { - return map[string]string{}, fmt.Errorf("failed to get user defined workspace path, error: %s", err) + return map[string]string{}, fmt.Errorf("failed to get user defined workspace path: %s", err) } if workspaceRelPth == "" { @@ -286,7 +284,7 @@ func (podfileParser podfileParser) cocoapodsVersion(podfileLockPth string) (stri func (podfileParser podfileParser) fixPodfileQuotation(podfilePth string) error { podfileContent, err := fileutil.ReadStringFromFile(podfilePth) if err != nil { - return fmt.Errorf("failed to read podfile (%s), error: %s", podfilePth, err) + return fmt.Errorf("failed to read podfile (%s): %s", podfilePth, err) } podfileContent = strings.Replace(podfileContent, `‘`, `'`, -1) @@ -295,7 +293,7 @@ func (podfileParser podfileParser) fixPodfileQuotation(podfilePth string) error podfileContent = strings.Replace(podfileContent, `”`, `"`, -1) if err := fileutil.WriteStringToFile(podfilePth, podfileContent); err != nil { - return fmt.Errorf("failed to apply Podfile quotation fix, error: %s", err) + return fmt.Errorf("failed to apply Podfile quotation fix: %s", err) } return nil diff --git a/vendor/github.com/bitrise-io/bitrise-init/scanners/ios/rubyscript.go b/vendor/github.com/bitrise-io/bitrise-init/scanners/ios/rubyscript.go index 66ed83bb..ef584550 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/scanners/ios/rubyscript.go +++ b/vendor/github.com/bitrise-io/bitrise-init/scanners/ios/rubyscript.go @@ -13,7 +13,7 @@ import ( "github.com/bitrise-io/go-utils/pathutil" ) -func runRubyScriptForOutput(scriptContent, gemfileContent, inDir string, withEnvs []string) (string, error) { +func runRubyScriptForOutput(scriptContent, gemfileContent string, withEnvs []string) (string, error) { tmpDir, err := pathutil.NormalizedOSTempDirPath("__bitrise-init__") if err != nil { return "", err @@ -32,10 +32,7 @@ func runRubyScriptForOutput(scriptContent, gemfileContent, inDir string, withEnv } cmd := command.New("bundle", "install") - - if inDir != "" { - cmd.SetDir(inDir) - } + cmd.SetDir(tmpDir) withEnvs = append(withEnvs, "BUNDLE_GEMFILE="+gemfilePth) cmd.AppendEnvs(withEnvs...) @@ -62,9 +59,9 @@ func runRubyScriptForOutput(scriptContent, gemfileContent, inDir string, withEnv cmd = command.New("ruby", rubyScriptPth) } - if inDir != "" { - cmd.SetDir(inDir) - } + // Set the temp dir as working dir, so the project defined `.ruby-version` does not cause ruby resolution to fail: + // [ ... ] ruby script failed, error: rbenv: version `2.7.4' is not installed (set by /[ ... ]/MyTestApp/.ruby-version) + cmd.SetDir(tmpDir) if len(withEnvs) > 0 { cmd.AppendEnvs(withEnvs...) diff --git a/vendor/github.com/bitrise-io/bitrise-init/scanners/ios/utility.go b/vendor/github.com/bitrise-io/bitrise-init/scanners/ios/utility.go index c2c02d0b..9a76d3f2 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/scanners/ios/utility.go +++ b/vendor/github.com/bitrise-io/bitrise-init/scanners/ios/utility.go @@ -9,8 +9,6 @@ import ( "github.com/bitrise-io/bitrise-init/analytics" "github.com/bitrise-io/bitrise-init/models" - "github.com/bitrise-io/bitrise-init/steps" - envmanModels "github.com/bitrise-io/envman/models" "github.com/bitrise-io/go-utils/fileutil" "github.com/bitrise-io/go-utils/log" "github.com/bitrise-io/go-utils/pathutil" @@ -89,6 +87,13 @@ const ( ConfigurationInputKey = "configuration" ) +const ( + // AutomaticCodeSigningInputKey ... + AutomaticCodeSigningInputKey = "automatic_code_signing" + // AutomaticCodeSigningInputAPIKeyValue ... + AutomaticCodeSigningInputAPIKeyValue = "api-key" +) + const ( // CarthageCommandInputKey ... CarthageCommandInputKey = "carthage_command" @@ -100,6 +105,36 @@ const cartfileResolvedBase = "Cartfile.resolved" // AllowCartfileBaseFilter ... var AllowCartfileBaseFilter = pathutil.BaseFilter(cartfileBase, true) +// Scheme is an Xcode project scheme or target +type Scheme struct { + Name string + Missing bool + HasXCTests bool + HasAppClip bool + + Icons models.Icons +} + +// Project is an Xcode project on the filesystem +type Project struct { + // Is it a standalone project or a workspace? + IsWorkspace bool + IsPodWorkspace bool + + RelPath string + // Carthage command to run: bootstrap/update + CarthageCommand string + Warnings models.Warnings + + Schemes []Scheme +} + +// DetectResult ... +type DetectResult struct { + Projects []Project + Warnings models.Warnings +} + // ConfigDescriptor ... type ConfigDescriptor struct { HasPodfile bool @@ -165,35 +200,6 @@ func HasCartfileResolvedInDirectoryOf(pth string) bool { return exist } -// Detect ... -func Detect(projectType XcodeProjectType, searchDir string) (bool, error) { - fileList, err := pathutil.ListPathInDirSortedByComponents(searchDir, true) - if err != nil { - return false, err - } - - log.TInfof("Filter relevant Xcode project files") - - relevantXcodeprojectFiles, err := FilterRelevantProjectFiles(fileList, projectType) - if err != nil { - return false, err - } - - log.TPrintf("%d Xcode %s project files found", len(relevantXcodeprojectFiles), string(projectType)) - for _, xcodeprojectFile := range relevantXcodeprojectFiles { - log.TPrintf("- %s", xcodeprojectFile) - } - - if len(relevantXcodeprojectFiles) == 0 { - log.TPrintf("platform not detected") - return false, nil - } - - log.TSuccessf("Platform detected") - - return true, nil -} - func fileContains(pth, str string) (bool, error) { content, err := fileutil.ReadStringFromFile(pth) if err != nil { @@ -278,46 +284,57 @@ func projectPathByScheme(projects []xcodeproj.ProjectModel, targetScheme string) return "" } -// GenerateOptions ... -func GenerateOptions(projectType XcodeProjectType, searchDir string, excludeAppIcon, suppressPodFileParseError bool) (models.OptionNode, []ConfigDescriptor, models.Icons, models.Warnings, error) { - warnings := models.Warnings{} +// ParseProjects collects available iOS/macOS projects +func ParseProjects(projectType XcodeProjectType, searchDir string, excludeAppIcon, suppressPodFileParseError bool) (DetectResult, error) { + var ( + projects []Project + warnings models.Warnings + ) + + // While not ideal, the expectation is that the searchDir is the current directory, due to using relative paths. + // Enforcing this to allow unit test to pass. + undoChDir, err := pathutil.RevokableChangeDir(searchDir) + if err != nil { + return DetectResult{}, err + } + defer func() { + if err := undoChDir(); err != nil { + log.TWarnf("failed to restore working dir: %s", err) + } + }() fileList, err := pathutil.ListPathInDirSortedByComponents(searchDir, true) if err != nil { - return models.OptionNode{}, []ConfigDescriptor{}, nil, models.Warnings{}, err + return DetectResult{}, err } - // Separate workspaces and standalon projects + // Separate workspaces and standalone projects + log.TInfof("Filtering relevant Xcode project files") projectFiles, err := FilterRelevantProjectFiles(fileList, projectType) if err != nil { - return models.OptionNode{}, []ConfigDescriptor{}, nil, models.Warnings{}, err + return DetectResult{}, err + } + + log.TPrintf("%d Xcode %s project files found", len(projectFiles), string(projectType)) + for _, xcodeprojectFile := range projectFiles { + log.TPrintf("- %s", xcodeprojectFile) } + if len(projectFiles) == 0 { + log.TPrintf("Platform not detected") + return DetectResult{}, nil + } + + log.TSuccessf("Platform detected") + workspaceFiles, err := FilterRelevantWorkspaceFiles(fileList, projectType) if err != nil { - return models.OptionNode{}, []ConfigDescriptor{}, nil, models.Warnings{}, err + return DetectResult{}, err } standaloneProjects, workspaces, err := CreateStandaloneProjectsAndWorkspaces(projectFiles, workspaceFiles) if err != nil { - return models.OptionNode{}, []ConfigDescriptor{}, nil, models.Warnings{}, err - } - - var exportMethodInputTitle string - var exportMethodInputSummary string - var exportMethodEnvKey string - var exportMethods []string - - if projectType == XcodeProjectTypeIOS { - exportMethodInputTitle = DistributionMethodInputTitle - exportMethodInputSummary = DistributionMethodInputSummary - exportMethodEnvKey = DistributionMethodEnvKey - exportMethods = IosExportMethods - } else { - exportMethodInputTitle = ExportMethodInputTitle - exportMethodInputSummary = ExportMethodInputSummary - exportMethodEnvKey = ExportMethodEnvKey - exportMethods = MacExportMethods + return DetectResult{}, err } // Create cocoapods workspace-project mapping @@ -325,7 +342,7 @@ func GenerateOptions(projectType XcodeProjectType, searchDir string, excludeAppI podfiles, err := FilterRelevantPodfiles(fileList) if err != nil { - return models.OptionNode{}, []ConfigDescriptor{}, nil, models.Warnings{}, err + return DetectResult{}, err } log.TPrintf("%d Podfiles detected", len(podfiles)) @@ -363,7 +380,9 @@ func GenerateOptions(projectType XcodeProjectType, searchDir string, excludeAppI cartfiles, err := FilterRelevantCartFile(fileList) if err != nil { - return models.OptionNode{}, []ConfigDescriptor{}, nil, models.Warnings{}, err + return DetectResult{ + Warnings: warnings, + }, err } log.TPrintf("%d Cartfiles detected", len(cartfiles)) @@ -371,161 +390,132 @@ func GenerateOptions(projectType XcodeProjectType, searchDir string, excludeAppI log.TPrintf("- %s", file) } - // Create config descriptors & options - configDescriptors := []ConfigDescriptor{} - defaultGitignorePth := filepath.Join(searchDir, ".gitignore") - projectPathOption := models.NewOption(ProjectPathInputTitle, ProjectPathInputSummary, ProjectPathInputEnvKey, models.TypeSelector) - - // App icons, merged from every project - iconsForAllProjects := models.Icons{} - // Standalone Projects for _, project := range standaloneProjects { - log.TInfof("Inspecting standalone project file: %s", project.Pth) + var ( + projectWarnings []string + schemes []Scheme + ) - schemeOption := models.NewOption(SchemeInputTitle, SchemeInputSummary, SchemeInputEnvKey, models.TypeSelector) - projectPathOption.AddOption(project.Pth, schemeOption) + log.TInfof("Inspecting standalone project file: %s", project.Pth) projectPath, err := filepath.Abs(filepath.Join(searchDir, project.Pth)) if err != nil { - return models.OptionNode{}, - []ConfigDescriptor{}, - nil, - warnings, - fmt.Errorf("failed to get project path, error: %s", err) + return DetectResult{Warnings: warnings}, fmt.Errorf("failed to get project path, error: %s", err) } carthageCommand, warning := detectCarthageCommand(project.Pth) if warning != "" { - warnings = append(warnings, warning) + projectWarnings = append(projectWarnings, warning) } log.TPrintf("%d shared schemes detected", len(project.SharedSchemes)) - if len(project.SharedSchemes) == 0 { message := printMissingSharedSchemesAndGenerateWarning(project.Pth, defaultGitignorePth, project.Targets) if message != "" { - warnings = append(warnings, message) + projectWarnings = append(projectWarnings, message) } for _, target := range project.Targets { - - exportMethodOption := models.NewOption(exportMethodInputTitle, exportMethodInputSummary, exportMethodEnvKey, models.TypeSelector) - schemeOption.AddOption(target.Name, exportMethodOption) - - iconIDs := []string{} + var icons models.Icons if !excludeAppIcon { - icons, err := lookupIconByTargetName(projectPath, target.Name, searchDir) - if err != nil { + if icons, err = lookupIconByTargetName(projectPath, target.Name, searchDir); err != nil { log.Warnf("could not get icons for app: %s, error: %s", projectPath, err) analytics.LogInfo(iconFailureTag, analytics.DetectorErrorData(string(XcodeProjectTypeIOS), err), "Failed to lookup ios icons") } - iconsForAllProjects = append(iconsForAllProjects, icons...) - for _, icon := range icons { - iconIDs = append(iconIDs, icon.Filename) - } } - for _, exportMethod := range exportMethods { - configDescriptor := NewConfigDescriptor(false, carthageCommand, target.HasXCTest, target.HasAppClip, exportMethod, true) - configDescriptors = append(configDescriptors, configDescriptor) - configOption := models.NewConfigOption(configDescriptor.ConfigName(projectType), iconIDs) - - exportMethodOption.AddConfig(exportMethod, configOption) - } + schemes = append(schemes, Scheme{ + Name: target.Name, + Missing: true, + HasXCTests: target.HasXCTest, + HasAppClip: target.HasAppClip, + Icons: icons, + }) } } else { for _, scheme := range project.SharedSchemes { log.TPrintf("- %s", scheme.Name) - exportMethodOption := models.NewOption(exportMethodInputTitle, exportMethodInputSummary, exportMethodEnvKey, models.TypeSelector) - schemeOption.AddOption(scheme.Name, exportMethodOption) - - iconIDs := []string{} + var icons models.Icons if !excludeAppIcon { - icons, err := lookupIconBySchemeName(projectPath, scheme.Name, searchDir) - if err != nil { + if icons, err = lookupIconBySchemeName(projectPath, scheme.Name, searchDir); err != nil { log.Warnf("could not get icons for app: %s, error: %s", projectPath, err) analytics.LogInfo(iconFailureTag, analytics.DetectorErrorData(string(XcodeProjectTypeIOS), err), "Failed to lookup ios icons") } - iconsForAllProjects = append(iconsForAllProjects, icons...) - for _, icon := range icons { - iconIDs = append(iconIDs, icon.Filename) - } } - for _, exportMethod := range exportMethods { - configDescriptor := NewConfigDescriptor(false, carthageCommand, scheme.HasXCTest, schemeHasAppClipTarget(scheme, project.Targets), exportMethod, false) - configDescriptors = append(configDescriptors, configDescriptor) - configOption := models.NewConfigOption(configDescriptor.ConfigName(projectType), iconIDs) - - exportMethodOption.AddConfig(exportMethod, configOption) - } + schemes = append(schemes, Scheme{ + Name: scheme.Name, + Missing: false, + HasXCTests: scheme.HasXCTest, + HasAppClip: schemeHasAppClipTarget(scheme, project.Targets), + Icons: icons, + }) } } + + projects = append(projects, Project{ + IsWorkspace: false, + IsPodWorkspace: false, + RelPath: project.Pth, + CarthageCommand: carthageCommand, + Warnings: projectWarnings, + Schemes: schemes, + }) } // Workspaces for _, workspace := range workspaces { - log.TInfof("Inspecting workspace file: %s", workspace.Pth) + var ( + projectWarnings []string + schemes []Scheme + ) - schemeOption := models.NewOption(SchemeInputTitle, SchemeInputSummary, SchemeInputEnvKey, models.TypeSelector) - projectPathOption.AddOption(workspace.Pth, schemeOption) + log.TInfof("Inspecting workspace file: %s", workspace.Pth) carthageCommand, warning := detectCarthageCommand(workspace.Pth) if warning != "" { - warnings = append(warnings, warning) + projectWarnings = append(projectWarnings, warning) } - sharedSchemes := workspace.GetSharedSchemes() - log.TPrintf("%d shared schemes detected", len(sharedSchemes)) - - if len(sharedSchemes) == 0 { - targets := workspace.GetTargets() + workspaceSharedSchemes := workspace.GetSharedSchemes() + log.TPrintf("%d shared schemes detected", len(workspaceSharedSchemes)) - message := printMissingSharedSchemesAndGenerateWarning(workspace.Pth, defaultGitignorePth, targets) + if len(workspaceSharedSchemes) == 0 { + message := printMissingSharedSchemesAndGenerateWarning(workspace.Pth, defaultGitignorePth, workspace.GetTargets()) if message != "" { warnings = append(warnings, message) } // Workspace path need not exist as it could be generated by cocoapods - for _, project := range workspace.Projects { // Not reusing targets as project path is needed + for _, project := range workspace.Projects { + // Not using workspace.GetTargets() as project path is needed for _, target := range project.Targets { - exportMethodOption := models.NewOption(exportMethodInputTitle, exportMethodInputSummary, exportMethodEnvKey, models.TypeSelector) - schemeOption.AddOption(target.Name, exportMethodOption) - - iconIDs := []string{} + var icons models.Icons if !excludeAppIcon { - icons, err := lookupIconByTargetName(project.Pth, target.Name, searchDir) - if err != nil { + if icons, err = lookupIconByTargetName(project.Pth, target.Name, searchDir); err != nil { log.Warnf("could not get icons for app: %s, error: %s", project.Pth, err) analytics.LogInfo(iconFailureTag, analytics.DetectorErrorData(string(XcodeProjectTypeIOS), err), "Failed to lookup ios icons") } - iconsForAllProjects = append(iconsForAllProjects, icons...) - for _, icon := range icons { - iconIDs = append(iconIDs, icon.Filename) - } } - for _, exportMethod := range exportMethods { - configDescriptor := NewConfigDescriptor(workspace.IsPodWorkspace, carthageCommand, target.HasXCTest, target.HasAppClip, exportMethod, true) - configDescriptors = append(configDescriptors, configDescriptor) - configOption := models.NewConfigOption(configDescriptor.ConfigName(projectType), iconIDs) - - exportMethodOption.AddConfig(exportMethod, configOption) - } + schemes = append(schemes, Scheme{ + Name: target.Name, + Missing: true, + HasXCTests: target.HasXCTest, + HasAppClip: target.HasAppClip, + Icons: icons, + }) } } } else { - for _, scheme := range sharedSchemes { + for _, scheme := range workspaceSharedSchemes { + var icons models.Icons log.TPrintf("- %s", scheme.Name) - exportMethodOption := models.NewOption(exportMethodInputTitle, exportMethodInputSummary, exportMethodEnvKey, models.TypeSelector) - schemeOption.AddOption(scheme.Name, exportMethodOption) - - iconIDs := []string{} if !excludeAppIcon { // Workspace path need not exist as it could be generated by cocoapods projectPathRel := projectPathByScheme(workspace.Projects, scheme.Name) @@ -544,37 +534,101 @@ func GenerateOptions(projectType XcodeProjectType, searchDir string, excludeAppI continue } - icons, err := lookupIconBySchemeName(projectPath, scheme.Name, searchDir) - if err != nil { + if icons, err = lookupIconBySchemeName(projectPath, scheme.Name, searchDir); err != nil { log.Warnf("could not get icons for app: %s, error: %s", projectPath, err) analytics.LogInfo(iconFailureTag, analytics.DetectorErrorData(string(XcodeProjectTypeIOS), err), "Failed to lookup ios icons") } - iconsForAllProjects = append(iconsForAllProjects, icons...) - for _, icon := range icons { - iconIDs = append(iconIDs, icon.Filename) - } } - for _, exportMethod := range exportMethods { - // only add appclip for development and ad-hoc - configDescriptor := NewConfigDescriptor(workspace.IsPodWorkspace, carthageCommand, scheme.HasXCTest, schemeHasAppClipTarget(scheme, workspace.GetTargets()), exportMethod, false) - configDescriptors = append(configDescriptors, configDescriptor) - configOption := models.NewConfigOption(configDescriptor.ConfigName(projectType), iconIDs) + schemes = append(schemes, Scheme{ + Name: scheme.Name, + Missing: false, + HasXCTests: scheme.HasXCTest, + HasAppClip: schemeHasAppClipTarget(scheme, workspace.GetTargets()), + Icons: icons, + }) + } + } + + projects = append(projects, Project{ + IsWorkspace: true, + IsPodWorkspace: workspace.IsPodWorkspace, + RelPath: workspace.Pth, + Schemes: schemes, + CarthageCommand: carthageCommand, + Warnings: projectWarnings, + }) + } - exportMethodOption.AddConfig(exportMethod, configOption) - } + return DetectResult{ + Projects: projects, + Warnings: warnings, + }, nil +} + +// GenerateOptions ... +func GenerateOptions(projectType XcodeProjectType, result DetectResult) (models.OptionNode, []ConfigDescriptor, models.Icons, models.Warnings, error) { + var ( + exportMethodInputTitle string + exportMethodInputSummary string + exportMethodEnvKey string + exportMethods []string + ) + + if projectType == XcodeProjectTypeIOS { + exportMethodInputTitle = DistributionMethodInputTitle + exportMethodInputSummary = DistributionMethodInputSummary + exportMethodEnvKey = DistributionMethodEnvKey + exportMethods = IosExportMethods + } else { + exportMethodInputTitle = ExportMethodInputTitle + exportMethodInputSummary = ExportMethodInputSummary + exportMethodEnvKey = ExportMethodEnvKey + exportMethods = MacExportMethods + } + + var ( + allWarnings = result.Warnings + iconsForAllProjects models.Icons + configDescriptors []ConfigDescriptor + ) + + projectPathOption := models.NewOption(ProjectPathInputTitle, ProjectPathInputSummary, ProjectPathInputEnvKey, models.TypeSelector) + for _, project := range result.Projects { + allWarnings = append(allWarnings, project.Warnings...) + + schemeOption := models.NewOption(SchemeInputTitle, SchemeInputSummary, SchemeInputEnvKey, models.TypeSelector) + projectPathOption.AddOption(project.RelPath, schemeOption) + + for _, scheme := range project.Schemes { + exportMethodOption := models.NewOption(exportMethodInputTitle, exportMethodInputSummary, exportMethodEnvKey, models.TypeSelector) + schemeOption.AddOption(scheme.Name, exportMethodOption) + + iconsForAllProjects = append(iconsForAllProjects, scheme.Icons...) + + iconIDs := []string{} + for _, icon := range scheme.Icons { + iconIDs = append(iconIDs, icon.Filename) + } + + for _, exportMethod := range exportMethods { + // Whether app-clip export Step is added later depends on the used export method + configDescriptor := NewConfigDescriptor(project.IsPodWorkspace, project.CarthageCommand, scheme.HasXCTests, scheme.HasAppClip, exportMethod, scheme.Missing) + configDescriptors = append(configDescriptors, configDescriptor) + configOption := models.NewConfigOption(configDescriptor.ConfigName(projectType), iconIDs) + + exportMethodOption.AddConfig(exportMethod, configOption) } } } configDescriptors = RemoveDuplicatedConfigDescriptors(configDescriptors, projectType) - if len(configDescriptors) == 0 { log.TErrorf("No valid %s config found", string(projectType)) - return models.OptionNode{}, []ConfigDescriptor{}, nil, warnings, fmt.Errorf("No valid %s config found", string(projectType)) + return models.OptionNode{}, []ConfigDescriptor{}, nil, allWarnings, fmt.Errorf("No valid %s config found", string(projectType)) } - return *projectPathOption, configDescriptors, iconsForAllProjects, warnings, nil + return *projectPathOption, configDescriptors, iconsForAllProjects, allWarnings, nil } // GenerateDefaultOptions ... @@ -615,101 +669,32 @@ func GenerateDefaultOptions(projectType XcodeProjectType) models.OptionNode { // GenerateConfigBuilder ... func GenerateConfigBuilder( projectType XcodeProjectType, + isPrivateRepository, hasPodfile, hasTest, hasAppClip, - missingSharedSchemes bool, - carthageCommand string, - isIncludeCache bool, + missingSharedSchemes, + includeCache bool, + carthageCommand, exportMethod string, ) models.ConfigBuilderModel { configBuilder := models.NewDefaultConfigBuilder() - // CI - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultPrepareStepList(isIncludeCache)...) - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.CertificateAndProfileInstallerStepListItem()) - - if missingSharedSchemes { - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.RecreateUserSchemesStepListItem( - envmanModels.EnvironmentItemModel{ProjectPathInputKey: "$" + ProjectPathInputEnvKey}, - )) + params := workflowSetupParams{ + projectType: projectType, + configBuilder: configBuilder, + isPrivateRepository: isPrivateRepository, + includeCache: includeCache, + missingSharedSchemes: missingSharedSchemes, + hasTests: hasTest, + hasAppClip: hasAppClip, + hasPodfile: hasPodfile, + carthageCommand: carthageCommand, + exportMethod: exportMethod, } - if hasPodfile { - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.CocoapodsInstallStepListItem()) - } - - if carthageCommand != "" { - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.CarthageStepListItem( - envmanModels.EnvironmentItemModel{CarthageCommandInputKey: carthageCommand}, - )) - } - - xcodeStepInputModels := []envmanModels.EnvironmentItemModel{ - {ProjectPathInputKey: "$" + ProjectPathInputEnvKey}, - {SchemeInputKey: "$" + SchemeInputEnvKey}, - } - xcodeArchiveStepInputModels := append(xcodeStepInputModels, envmanModels.EnvironmentItemModel{DistributionMethodInputKey: "$" + DistributionMethodEnvKey}) - xcodeArchiveMacStepInputModels := append(xcodeStepInputModels, envmanModels.EnvironmentItemModel{ExportMethodInputKey: "$" + ExportMethodEnvKey}) - - if hasTest { - switch projectType { - case XcodeProjectTypeIOS: - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.XcodeTestStepListItem(xcodeStepInputModels...)) - case XcodeProjectTypeMacOS: - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.XcodeTestMacStepListItem(xcodeStepInputModels...)) - } - } else { - switch projectType { - case XcodeProjectTypeIOS: - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.XcodeArchiveStepListItem(xcodeArchiveStepInputModels...)) - - if shouldAppendExportAppClipStep(hasAppClip, exportMethod) { - appendExportAppClipStep(configBuilder, models.PrimaryWorkflowID) - } - case XcodeProjectTypeMacOS: - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.XcodeArchiveMacStepListItem(xcodeArchiveMacStepInputModels...)) - } - } - - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultDeployStepList(isIncludeCache)...) - - if hasTest { - // CD - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultPrepareStepList(isIncludeCache)...) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.CertificateAndProfileInstallerStepListItem()) - - if missingSharedSchemes { - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.RecreateUserSchemesStepListItem( - envmanModels.EnvironmentItemModel{ProjectPathInputKey: "$" + ProjectPathInputEnvKey}, - )) - } - - if hasPodfile { - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.CocoapodsInstallStepListItem()) - } - - if carthageCommand != "" { - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.CarthageStepListItem( - envmanModels.EnvironmentItemModel{CarthageCommandInputKey: carthageCommand}, - )) - } - - switch projectType { - case XcodeProjectTypeIOS: - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.XcodeTestStepListItem(xcodeStepInputModels...)) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.XcodeArchiveStepListItem(xcodeArchiveStepInputModels...)) - - if shouldAppendExportAppClipStep(hasAppClip, exportMethod) { - appendExportAppClipStep(configBuilder, models.DeployWorkflowID) - } - case XcodeProjectTypeMacOS: - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.XcodeTestMacStepListItem(xcodeStepInputModels...)) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.XcodeArchiveMacStepListItem(xcodeArchiveMacStepInputModels...)) - } - - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultDeployStepList(isIncludeCache)...) - } + createPrimaryWorkflow(params) + createDeployWorkflow(params) return *configBuilder } @@ -731,17 +716,18 @@ func RemoveDuplicatedConfigDescriptors(configDescriptors []ConfigDescriptor, pro } // GenerateConfig ... -func GenerateConfig(projectType XcodeProjectType, configDescriptors []ConfigDescriptor, isIncludeCache bool) (models.BitriseConfigMap, error) { +func GenerateConfig(projectType XcodeProjectType, configDescriptors []ConfigDescriptor, isPrivateRepository bool) (models.BitriseConfigMap, error) { bitriseDataMap := models.BitriseConfigMap{} for _, descriptor := range configDescriptors { configBuilder := GenerateConfigBuilder( projectType, + isPrivateRepository, descriptor.HasPodfile, descriptor.HasTest, descriptor.HasAppClip, descriptor.MissingSharedSchemes, + true, descriptor.CarthageCommand, - isIncludeCache, descriptor.ExportMethod) config, err := configBuilder.Generate(string(projectType)) @@ -761,52 +747,17 @@ func GenerateConfig(projectType XcodeProjectType, configDescriptors []ConfigDesc } // GenerateDefaultConfig ... -func GenerateDefaultConfig(projectType XcodeProjectType, isIncludeCache bool) (models.BitriseConfigMap, error) { - configBuilder := models.NewDefaultConfigBuilder() - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultPrepareStepList(isIncludeCache)...) - - // CI - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.CertificateAndProfileInstallerStepListItem()) - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.RecreateUserSchemesStepListItem( - envmanModels.EnvironmentItemModel{ProjectPathInputKey: "$" + ProjectPathInputEnvKey}, - )) - - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.CocoapodsInstallStepListItem()) - - xcodeTestStepInputModels := []envmanModels.EnvironmentItemModel{ - {ProjectPathInputKey: "$" + ProjectPathInputEnvKey}, - {SchemeInputKey: "$" + SchemeInputEnvKey}, - } - xcodeArchiveStepInputModels := append(xcodeTestStepInputModels, envmanModels.EnvironmentItemModel{DistributionMethodInputKey: "$" + DistributionMethodEnvKey}) - xcodeArchiveMacStepInputModels := append(xcodeTestStepInputModels, envmanModels.EnvironmentItemModel{ExportMethodInputKey: "$" + ExportMethodEnvKey}) - - switch projectType { - case XcodeProjectTypeIOS: - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.XcodeTestStepListItem(xcodeTestStepInputModels...)) - case XcodeProjectTypeMacOS: - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.XcodeTestMacStepListItem(xcodeTestStepInputModels...)) - } - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultDeployStepList(true)...) - - // CD - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultPrepareStepList(isIncludeCache)...) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.CertificateAndProfileInstallerStepListItem()) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.RecreateUserSchemesStepListItem( - envmanModels.EnvironmentItemModel{ProjectPathInputKey: "$" + ProjectPathInputEnvKey}, - )) - - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.CocoapodsInstallStepListItem()) - - switch projectType { - case XcodeProjectTypeIOS: - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.XcodeTestStepListItem(xcodeTestStepInputModels...)) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.XcodeArchiveStepListItem(xcodeArchiveStepInputModels...)) - case XcodeProjectTypeMacOS: - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.XcodeTestMacStepListItem(xcodeTestStepInputModels...)) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.XcodeArchiveMacStepListItem(xcodeArchiveMacStepInputModels...)) - } - - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultDeployStepList(true)...) +func GenerateDefaultConfig(projectType XcodeProjectType) (models.BitriseConfigMap, error) { + configBuilder := GenerateConfigBuilder( + projectType, + true, + true, + true, + false, + true, + true, + "", + "") config, err := configBuilder.Generate(string(projectType)) if err != nil { @@ -822,28 +773,3 @@ func GenerateDefaultConfig(projectType XcodeProjectType, isIncludeCache bool) (m fmt.Sprintf(defaultConfigNameFormat, string(projectType)): string(data), }, nil } - -func schemeHasAppClipTarget(scheme xcodeproj.SchemeModel, targets []xcodeproj.TargetModel) bool { - for _, target := range targets { - for _, referenceID := range scheme.BuildableReferenceIDs { - if referenceID == target.ID && target.HasAppClip { - return true - } - } - } - - return false -} - -func shouldAppendExportAppClipStep(hasAppClip bool, exportMethod string) bool { - return hasAppClip && - (exportMethod == "development" || exportMethod == "ad-hoc") -} - -func appendExportAppClipStep(configBuilder *models.ConfigBuilderModel, workflowID models.WorkflowID) { - exportXCArchiveStepInputModels := []envmanModels.EnvironmentItemModel{ - {ExportXCArchiveProductInputKey: ExportXCArchiveProductInputAppClipValue}, - {DistributionMethodInputKey: "$" + DistributionMethodEnvKey}, - } - configBuilder.AppendStepListItemsTo(workflowID, steps.ExportXCArchiveStepListItem(exportXCArchiveStepInputModels...)) -} diff --git a/vendor/github.com/bitrise-io/bitrise-init/scanners/ios/workflow.go b/vendor/github.com/bitrise-io/bitrise-init/scanners/ios/workflow.go new file mode 100644 index 00000000..dfb1e268 --- /dev/null +++ b/vendor/github.com/bitrise-io/bitrise-init/scanners/ios/workflow.go @@ -0,0 +1,199 @@ +package ios + +import ( + "github.com/bitrise-io/bitrise-init/models" + "github.com/bitrise-io/bitrise-init/steps" + envmanModels "github.com/bitrise-io/envman/models" +) + +const ( + // TestRepetitionModeKey ... + TestRepetitionModeKey = "test_repetition_mode" + // TestRepetitionModeRetryOnFailureValue ... + TestRepetitionModeRetryOnFailureValue = "retry_on_failure" + // BuildForTestDestinationKey ... + BuildForTestDestinationKey = "destination" + // BuildForTestDestinationValue ... + BuildForTestDestinationValue = "platform=iOS Simulator,name=iPhone 8 Plus,OS=latest" + // AutomaticCodeSigningKey ... + AutomaticCodeSigningKey = "automatic_code_signing" + // AutomaticCodeSigningValue ... + AutomaticCodeSigningValue = "api-key" +) + +const primaryTestDescription = `The workflow executes the tests. The *retry_on_failure* test repetition mode is enabled.` + +const primaryBuildOnlyDescription = `The workflow only builds the project because the project scanner could not find any tests.` + +const primaryCommonDescription = `Next steps: +- Check out [Getting started with iOS apps](https://devcenter.bitrise.io/en/getting-started/getting-started-with-ios-apps.html). +` + +const deployDescription = `The workflow tests, builds and deploys the app using *Deploy to bitrise.io* step. + +For testing the *retry_on_failure* test repetition mode is enabled. + +Next steps: +- Set up [Connecting to an Apple service with API key](https://devcenter.bitrise.io/en/accounts/connecting-to-services/connecting-to-an-apple-service-with-api-key.html##). +- Or further customise code signing following our [iOS code signing](https://devcenter.bitrise.io/en/code-signing/ios-code-signing.html) guide. +` + +type workflowSetupParams struct { + projectType XcodeProjectType + configBuilder *models.ConfigBuilderModel + isPrivateRepository bool + includeCache bool + missingSharedSchemes bool + hasTests bool + hasAppClip bool + hasPodfile bool + carthageCommand string + exportMethod string +} + +func createPrimaryWorkflow(params workflowSetupParams) { + identifier := models.PrimaryWorkflowID + addSharedSetupSteps(identifier, params, false) + + var description string + + if params.hasTests { + description = primaryTestDescription + addTestStep(identifier, params.configBuilder, params.projectType) + } else { + description = primaryBuildOnlyDescription + addBuildStep(identifier, params.configBuilder, params.projectType) + } + + addSharedTeardownSteps(identifier, params.configBuilder, params.includeCache) + addDescription(params.projectType, identifier, params.configBuilder, description+"\n\n"+primaryCommonDescription) +} + +func createDeployWorkflow(params workflowSetupParams) { + identifier := models.DeployWorkflowID + includeCertificateAndProfileInstallStep := params.projectType == XcodeProjectTypeMacOS + addSharedSetupSteps(identifier, params, includeCertificateAndProfileInstallStep) + + if params.hasTests { + addTestStep(identifier, params.configBuilder, params.projectType) + } + + addArchiveStep(identifier, params.configBuilder, params.projectType, params.hasAppClip, params.exportMethod) + addSharedTeardownSteps(identifier, params.configBuilder, params.includeCache) + addDescription(params.projectType, identifier, params.configBuilder, deployDescription) +} + +// Add steps + +func addTestStep(workflow models.WorkflowID, configBuilder *models.ConfigBuilderModel, projectType XcodeProjectType) { + switch projectType { + case XcodeProjectTypeIOS: + configBuilder.AppendStepListItemsTo(workflow, steps.XcodeTestStepListItem(xcodeTestStepInputModels()...)) + case XcodeProjectTypeMacOS: + configBuilder.AppendStepListItemsTo(workflow, steps.XcodeTestMacStepListItem(baseXcodeStepInputModels()...)) + } +} + +func addBuildStep(workflow models.WorkflowID, configBuilder *models.ConfigBuilderModel, projectType XcodeProjectType) { + if projectType != XcodeProjectTypeIOS { + return + } + + configBuilder.AppendStepListItemsTo(workflow, steps.XcodeBuildForTestStepListItem(xcodeBuildForTestStepInputModels()...)) +} + +func addArchiveStep(workflow models.WorkflowID, configBuilder *models.ConfigBuilderModel, projectType XcodeProjectType, hasAppClip bool, exportMethod string) { + inputModels := xcodeArchiveStepInputModels(projectType) + + switch projectType { + case XcodeProjectTypeIOS: + configBuilder.AppendStepListItemsTo(workflow, steps.XcodeArchiveStepListItem(inputModels...)) + + if shouldAppendExportAppClipStep(hasAppClip, exportMethod) { + appendExportAppClipStep(configBuilder, workflow) + } + case XcodeProjectTypeMacOS: + configBuilder.AppendStepListItemsTo(workflow, steps.XcodeArchiveMacStepListItem(inputModels...)) + } +} + +func addSharedSetupSteps(workflow models.WorkflowID, params workflowSetupParams, includeCertificateAndProfileInstallStep bool) { + params.configBuilder.AppendStepListItemsTo(workflow, steps.DefaultPrepareStepListV2(steps.PrepareListParams{ + ShouldIncludeCache: params.includeCache, + ShouldIncludeActivateSSH: params.isPrivateRepository, + })...) + + if includeCertificateAndProfileInstallStep { + params.configBuilder.AppendStepListItemsTo(workflow, steps.CertificateAndProfileInstallerStepListItem()) + } + + if params.missingSharedSchemes { + params.configBuilder.AppendStepListItemsTo(workflow, steps.RecreateUserSchemesStepListItem( + envmanModels.EnvironmentItemModel{ProjectPathInputKey: "$" + ProjectPathInputEnvKey}, + )) + } + + if params.hasPodfile { + params.configBuilder.AppendStepListItemsTo(workflow, steps.CocoapodsInstallStepListItem()) + } + + if params.carthageCommand != "" { + params.configBuilder.AppendStepListItemsTo(workflow, steps.CarthageStepListItem( + envmanModels.EnvironmentItemModel{CarthageCommandInputKey: params.carthageCommand}, + )) + } +} + +func addSharedTeardownSteps(workflow models.WorkflowID, configBuilder *models.ConfigBuilderModel, includeCache bool) { + configBuilder.AppendStepListItemsTo(workflow, steps.DefaultDeployStepListV2(includeCache)...) +} + +func addDescription(projectType XcodeProjectType, workflow models.WorkflowID, configBuilder *models.ConfigBuilderModel, description string) { + if projectType != XcodeProjectTypeIOS { + return + } + + configBuilder.SetWorkflowDescriptionTo(workflow, description) +} + +// Helpers + +func baseXcodeStepInputModels() []envmanModels.EnvironmentItemModel { + return []envmanModels.EnvironmentItemModel{ + {ProjectPathInputKey: "$" + ProjectPathInputEnvKey}, + {SchemeInputKey: "$" + SchemeInputEnvKey}, + } +} + +func xcodeTestStepInputModels() []envmanModels.EnvironmentItemModel { + inputModels := []envmanModels.EnvironmentItemModel{ + {TestRepetitionModeKey: TestRepetitionModeRetryOnFailureValue}, + } + + return append(baseXcodeStepInputModels(), inputModels...) +} + +func xcodeBuildForTestStepInputModels() []envmanModels.EnvironmentItemModel { + inputModels := []envmanModels.EnvironmentItemModel{ + {BuildForTestDestinationKey: BuildForTestDestinationValue}, + } + + return append(baseXcodeStepInputModels(), inputModels...) +} + +func xcodeArchiveStepInputModels(projectType XcodeProjectType) []envmanModels.EnvironmentItemModel { + var inputModels []envmanModels.EnvironmentItemModel + + if projectType == XcodeProjectTypeIOS { + inputModels = append(inputModels, []envmanModels.EnvironmentItemModel{ + {DistributionMethodInputKey: "$" + DistributionMethodEnvKey}, + {AutomaticCodeSigningKey: AutomaticCodeSigningValue}, + }...) + } else { + inputModels = []envmanModels.EnvironmentItemModel{ + {ExportMethodInputKey: "$" + ExportMethodEnvKey}, + } + } + + return append(baseXcodeStepInputModels(), inputModels...) +} diff --git a/vendor/github.com/bitrise-io/bitrise-init/scanners/macos/macos.go b/vendor/github.com/bitrise-io/bitrise-init/scanners/macos/macos.go index 24bd3663..74af4242 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/scanners/macos/macos.go +++ b/vendor/github.com/bitrise-io/bitrise-init/scanners/macos/macos.go @@ -11,7 +11,8 @@ import ( // Scanner ... type Scanner struct { - searchDir string + detectResult ios.DetectResult + configDescriptors []ios.ConfigDescriptor } @@ -27,14 +28,14 @@ func (Scanner) Name() string { // DetectPlatform ... func (scanner *Scanner) DetectPlatform(searchDir string) (bool, error) { - scanner.searchDir = searchDir - - detected, err := ios.Detect(ios.XcodeProjectTypeMacOS, searchDir) + result, err := ios.ParseProjects(ios.XcodeProjectTypeMacOS, searchDir, true, false) if err != nil { return false, err } - return detected, nil + scanner.detectResult = result + detected := len(result.Projects) > 0 + return detected, err } // ExcludedScannerNames ... @@ -44,7 +45,7 @@ func (Scanner) ExcludedScannerNames() []string { // Options ... func (scanner *Scanner) Options() (models.OptionNode, models.Warnings, models.Icons, error) { - options, configDescriptors, _, warnings, err := ios.GenerateOptions(ios.XcodeProjectTypeMacOS, scanner.searchDir, true, false) + options, configDescriptors, _, warnings, err := ios.GenerateOptions(ios.XcodeProjectTypeMacOS, scanner.detectResult) if err != nil { return models.OptionNode{}, warnings, nil, err } @@ -60,11 +61,11 @@ func (Scanner) DefaultOptions() models.OptionNode { } // Configs ... -func (scanner *Scanner) Configs() (models.BitriseConfigMap, error) { - return ios.GenerateConfig(ios.XcodeProjectTypeMacOS, scanner.configDescriptors, true) +func (scanner *Scanner) Configs(isPrivateRepository bool) (models.BitriseConfigMap, error) { + return ios.GenerateConfig(ios.XcodeProjectTypeMacOS, scanner.configDescriptors, isPrivateRepository) } // DefaultConfigs ... func (Scanner) DefaultConfigs() (models.BitriseConfigMap, error) { - return ios.GenerateDefaultConfig(ios.XcodeProjectTypeMacOS, true) + return ios.GenerateDefaultConfig(ios.XcodeProjectTypeMacOS) } diff --git a/vendor/github.com/bitrise-io/bitrise-init/scanners/reactnative/const.go b/vendor/github.com/bitrise-io/bitrise-init/scanners/reactnative/const.go index 50aba05a..2c3475f5 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/scanners/reactnative/const.go +++ b/vendor/github.com/bitrise-io/bitrise-init/scanners/reactnative/const.go @@ -1,59 +1,54 @@ package reactnative -const deployWorkflowDescription = `## Configure Android part of the deploy workflow - -To generate a signed APK: - -1. Open the **Workflow** tab of your project on Bitrise.io -1. Add **Sign APK step right after Android Build step** -1. Click on **Code Signing** tab -1. Find the **ANDROID KEYSTORE FILE** section -1. Click or drop your file on the upload file field -1. Fill the displayed 3 input fields: -1. **Keystore password** -1. **Keystore alias** -1. **Private key password** -1. Click on **[Save metadata]** button - -That's it! From now on, **Sign APK** step will receive your uploaded files. - -## Configure iOS part of the deploy workflow - -To generate IPA: - -1. Open the **Workflow** tab of your project on Bitrise.io -1. Click on **Code Signing** tab -1. Find the **PROVISIONING PROFILE** section -1. Click or drop your file on the upload file field -1. Find the **CODE SIGNING IDENTITY** section -1. Click or drop your file on the upload file field -1. Click on **Workflows** tab -1. Select deploy workflow -1. Select **Xcode Archive & Export for iOS** step -1. Open **Force Build Settings** input group -1. Specify codesign settings -Set **Force code signing with Development Team**, **Force code signing with Code Signing Identity** -and **Force code signing with Provisioning Profile** inputs regarding to the uploaded codesigning files -1. Specify manual codesign style -If the codesigning files, are generated manually on the Apple Developer Portal, -you need to explicitly specify to use manual coedsign settings -(as ejected rn projects have xcode managed codesigning turned on). -To do so, add 'CODE_SIGN_STYLE="Manual"' to 'Additional options for xcodebuild call' input - -## To run this workflow - -If you want to run this workflow manually: - -1. Open the app's build list page -2. Click on **[Start/Schedule a Build]** button -3. Select **deploy** in **Workflow** dropdown input -4. Click **[Start Build]** button - -Or if you need this workflow to be started by a GIT event: - -1. Click on **Triggers** tab -2. Setup your desired event (push/tag/pull) and select **deploy** workflow -3. Click on **[Done]** and then **[Save]** buttons - -The next change in your repository that matches any of your trigger map event will start **deploy** workflow. +const ( + deployWorkflowDescription = `Tests, builds and deploys the app using *Deploy to bitrise.io* Step. + +Next steps: +- Set up an [Apple service with API key](https://devcenter.bitrise.io/en/accounts/connecting-to-services/connecting-to-an-apple-service-with-api-key.html). +- Check out [Getting started with React Native apps](https://devcenter.bitrise.io/en/getting-started/getting-started-with-react-native-apps.html). +` + + primaryWorkflowDescription = `Runs tests. + +Next steps: +- Check out [Getting started with React Native apps](https://devcenter.bitrise.io/en/getting-started/getting-started-with-react-native-apps.html). +` + + primaryWorkflowNoTestsDescription = `Installs dependencies. + +Next steps: +- Add tests to your project and configure the workflow to run them. +- Check out [Getting started with React Native apps](https://devcenter.bitrise.io/en/getting-started/getting-started-with-react-native-apps.html). +` +) + +const ( + expoDeployWorkflowDescription = `Tests the app and runs a build on Expo Application Services (EAS). + +Next steps: +- Configure the ` + "`Run Expo Application Services (EAS) build`" + ` Step's ` + "`Access Token`" + ` input. +- Check out [Getting started with Expo apps](https://devcenter.bitrise.io/en/getting-started/getting-started-with-expo-apps.html). +- For an alternative deploy workflow checkout the [(React Native) Expo: Build using Turtle CLI recipe](https://github.com/bitrise-io/workflow-recipes/blob/main/recipes/rn-expo-turtle-build.md). +` + + expoDeployWorkflowNoTestsDescription = `Runs a build on Expo Application Services (EAS). + +Next steps: +- Configure the ` + "`Run Expo Application Services (EAS) build`" + ` Step's ` + "`Access Token`" + ` input. +- Check out [Getting started with Expo apps](https://devcenter.bitrise.io/en/getting-started/getting-started-with-expo-apps.html). +- For an alternative deploy workflow checkout the [(React Native) Expo: Build using Turtle CLI recipe](https://github.com/bitrise-io/workflow-recipes/blob/main/recipes/rn-expo-turtle-build.md). +` + + expoPrimaryWorkflowDescription = `Runs tests. + +Next steps: +- Check out [Getting started with Expo apps](https://devcenter.bitrise.io/en/getting-started/getting-started-with-expo-apps.html). +` + + expoPrimaryWorkflowNoTestsDescription = `Installs dependencies. + +Next steps: +- Add tests to your project and configure the workflow to run them. +- Check out [Getting started with Expo apps](https://devcenter.bitrise.io/en/getting-started/getting-started-with-expo-apps.html). ` +) diff --git a/vendor/github.com/bitrise-io/bitrise-init/scanners/reactnative/expo.go b/vendor/github.com/bitrise-io/bitrise-init/scanners/reactnative/expo.go index 7a2a813b..d8e23c40 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/scanners/reactnative/expo.go +++ b/vendor/github.com/bitrise-io/bitrise-init/scanners/reactnative/expo.go @@ -1,19 +1,8 @@ package reactnative import ( - "fmt" - "path/filepath" - "regexp" - "strings" - "github.com/bitrise-io/bitrise-init/models" - "github.com/bitrise-io/bitrise-init/scanners/android" - "github.com/bitrise-io/bitrise-init/scanners/ios" "github.com/bitrise-io/bitrise-init/steps" - "github.com/bitrise-io/bitrise-init/utility" - envmanModels "github.com/bitrise-io/envman/models" - "github.com/bitrise-io/go-utils/log" - "github.com/pkg/errors" "gopkg.in/yaml.v2" ) @@ -23,340 +12,69 @@ const ( ) const ( - bareIOSProjectPathInputTitle = "The iOS project path generated by running 'expo eject' locally" - bareIOSprojectPathInputSummary = `Will add the Expo Eject Step to the Workflow to generate the native iOS project, so it can be built and archived. -Run 'expo eject' in a local environment to determine this value. This experiment then can be undone by deleting the ios and android directories. See https://docs.expo.io/bare/customizing/ for more details. -For example: './ios/myproject.xcworkspace'.` -) - -const ( - iosBundleIDInputTitle = "iOS bundle identifier" - iosBundleIDInputSummary = `Key expo/ios/bundleIdentifier not present in 'app.json'. - -Will add the Expo Eject Step to the Workflow to generate the native iOS project, so the IPA can be exported. -For your convenience, define it here temporarily. To set this value permanently run 'expo eject' in a local environment and commit 'app.json' changes. -For example: 'com.sample.myapp'.` - iosBundleIDInputSummaryDefault = `Optional, only needs to be entered if the key expo/ios/bundleIdentifier is not set in 'app.json'. - -Will add the Expo Eject Step to the Workflow to generate the native iOS project, so the IPA can be exported. -For your convenience, define it here temporarily. To set this value permanently run 'expo eject' in a local environment and commit 'app.json' changes. -For example: 'com.sample.myapp'.` - iosBundleIDEnvKey = "EXPO_BARE_IOS_BUNLDE_ID" -) - -const ( - androidPackageInputTitle = "Android package name" - androidPackageInputSummary = `Key expo/android/package not present in 'app.json'. - -Will add the Expo Eject Step to the Workflow to generate the native Android project, so the bundle (AAB) can be built. -For your convenience, define it here temporarily. To set this value permanently run 'expo eject' in a local environment and commit 'app.json' changes. -For example: 'com.sample.myapp'.` - androidPackageInputSummaryDefault = `Optional, only needs to be entered if the key expo/android/package is not set in 'app.json'. - -Will add the Expo Eject Step to the Workflow to generate the native Android project, so the bundle (AAB) can be built. -For your convenience, define it here temporarily. To set this value permanently run 'expo eject' in a local environment and commit 'app.json' changes. -For example: 'com.sample.myapp'.` - androidPackageEnvKey = "EXPO_BARE_ANDROID_PACKAGE" -) - -const ( - iosDevelopmentTeamInputTitle = "iOS Development team ID" - iosDevelopmentTeamInputSummary = `The Apple Development Team that the iOS version of the app belongs to. Will be used to override code signing settings. See https://devcenter.bitrise.io/getting-started/getting-started-with-expo-apps/#signing-and-exporting-your-ios-app-for-deployment for more details. - -Will add the Expo Eject Step to the Workflow to generate the native iOS project, so it can be built and archived. -Run 'expo eject' in a local environment to determine this value. This experiment then can be undone by deleting the ios and android directories. -For example: '1MZX23ABCD4'.` - iosDevelopmentTeamEnv = "BITRISE_IOS_DEVELOPMENT_TEAM" -) - -const ( - projectRootDirInputTitle = "Project root directory" - projectRootDirInputSummary = "The directory of the 'app.json' or 'package.json' file of your React Native project." -) - -const ( - schemeInputTitle = "The iOS native project scheme name" - schemeInputSummary = `An Xcode scheme defines a collection of targets to build, a configuration to use when building, and a collection of tests to execute. You can change the scheme at any time. - -Will add the Expo Eject Step to the Workflow to generate the native iOS project, so it can be built and archived. -Run 'expo eject' in a local environment to determine this value. This experiment then can be undone by deleting the ios and android directories.` -) + expoProjectDirInputTitle = "Expo project directory" + expoProjectDirInputSummary = "Path of the directory containing the project's `package.json` and app configuration file (`app.json`, `app.config.js`, `app.config.ts`)." + expoProjectDirInputEnvKey = "WORKDIR" -const wordirEnv = "WORKDIR" - -const ( - expoBareAddIdentiferScriptTitle = "Set bundleIdentifier, packageName for Expo Eject" - expoAppJSONName = "app.json" + expoPlatformInputTitle = "Platform to build" + expoPlatformInputSummary = "Which platform should be built by the deploy workflow?" + expoPlatformInputEnvKey = "PLATFORM" ) -func expoBareAddIdentifiersScript(appJSONPath, androidEnvKey, iosEnvKey string) string { - return fmt.Sprintf(`#!/usr/bin/env bash -set -ex - -appJson="%s" -tmp="/tmp/app.json" -jq '.expo.android |= if has("package") or env.`+androidEnvKey+` == "" or env.`+androidEnvKey+` == null then . else .package = env.`+androidEnvKey+` end | -.expo.ios |= if has("bundleIdentifier") or env.`+iosEnvKey+` == "" or env.`+iosEnvKey+` == null then . else .bundleIdentifier = env.`+iosEnvKey+` end' <${appJson} >${tmp} -[[ $?==0 ]] && mv -f ${tmp} ${appJson}`, appJSONPath) -} - // expoOptions implements ScannerInterface.Options function for Expo based React Native projects. -func (scanner *Scanner) expoOptions() (models.OptionNode, models.Warnings, error) { - warnings := models.Warnings{} - if scanner.expoSettings == nil { - return models.OptionNode{}, warnings, errors.New("can not generate expo Options, expoSettings is nil") - } - if !scanner.expoSettings.isAndroid && !scanner.expoSettings.isIOS { - return models.OptionNode{}, warnings, errors.New("can not generate expo Option, neither iOS or Android platform detected") - } - - log.TPrintf("Project name: %v", scanner.expoSettings.name) - var iosNode *models.OptionNode - var distributionMethodOption *models.OptionNode - if scanner.expoSettings.isIOS { // ios options - schemeOption := models.NewOption(ios.SchemeInputTitle, ios.SchemeInputSummary, ios.SchemeInputEnvKey, models.TypeOptionalSelector) - - // predict the ejected project name - projectName := strings.ToLower(regexp.MustCompile(`(?i:[^a-z0-9])`).ReplaceAllString(scanner.expoSettings.name, "")) - projectPathOption := models.NewOption(bareIOSProjectPathInputTitle, bareIOSprojectPathInputSummary, ios.ProjectPathInputEnvKey, models.TypeOptionalSelector) - if projectName != "" { - projectPathOption.AddOption(filepath.Join("./", "ios", projectName+".xcworkspace"), schemeOption) - } else { - projectPathOption.AddOption("", schemeOption) - } - - if scanner.expoSettings.bundleIdentifierIOS == "" { // bundle ID Option - iosNode = models.NewOption(iosBundleIDInputTitle, iosBundleIDInputSummary, iosBundleIDEnvKey, models.TypeUserInput) - iosNode.AddOption("", projectPathOption) - } else { - iosNode = projectPathOption - } - - developmentTeamOption := models.NewOption(iosDevelopmentTeamInputTitle, iosDevelopmentTeamInputSummary, iosDevelopmentTeamEnv, models.TypeUserInput) - schemeOption.AddOption(projectName, developmentTeamOption) - - distributionMethodOption = models.NewOption(ios.DistributionMethodInputTitle, ios.DistributionMethodInputSummary, ios.DistributionMethodEnvKey, models.TypeSelector) - developmentTeamOption.AddOption("", distributionMethodOption) - } - - var androidNode *models.OptionNode - var buildVariantOption *models.OptionNode - if scanner.expoSettings.isAndroid { // android options - packageJSONDir := filepath.Dir(scanner.packageJSONPth) - relPackageJSONDir, err := utility.RelPath(scanner.searchDir, packageJSONDir) - if err != nil { - return models.OptionNode{}, warnings, fmt.Errorf("Failed to get relative package.json dir path, error: %s", err) - } - if relPackageJSONDir == "." { - // package.json placed in the search dir, no need to change-dir in the workflows - relPackageJSONDir = "" - } - - var projectSettingNode *models.OptionNode - var moduleOption *models.OptionNode - if relPackageJSONDir == "" { - projectSettingNode = models.NewOption(android.ProjectLocationInputTitle, android.ProjectLocationInputSummary, android.ProjectLocationInputEnvKey, models.TypeSelector) - - moduleOption = models.NewOption(android.ModuleInputTitle, android.ModuleInputSummary, android.ModuleInputEnvKey, models.TypeUserInput) - projectSettingNode.AddOption("./android", moduleOption) - } else { - projectSettingNode = models.NewOption(projectRootDirInputTitle, projectRootDirInputSummary, wordirEnv, models.TypeSelector) - - projectLocationOption := models.NewOption(android.ProjectLocationInputTitle, android.ProjectLocationInputSummary, android.ProjectLocationInputEnvKey, models.TypeSelector) - projectSettingNode.AddOption(relPackageJSONDir, projectLocationOption) - - moduleOption = models.NewOption(android.ModuleInputTitle, android.ModuleInputSummary, android.ModuleInputEnvKey, models.TypeUserInput) - projectLocationOption.AddOption(filepath.Join(relPackageJSONDir, "android"), moduleOption) - } - - if scanner.expoSettings.packageNameAndroid == "" { - androidNode = models.NewOption(androidPackageInputTitle, androidPackageInputSummary, androidPackageEnvKey, models.TypeUserInput) - androidNode.AddOption("", projectSettingNode) - } else { - androidNode = projectSettingNode - } - - buildVariantOption = models.NewOption(android.VariantInputTitle, android.VariantInputSummary, android.VariantInputEnvKey, models.TypeOptionalUserInput) - moduleOption.AddOption("app", buildVariantOption) - } - - rootNode := iosNode - if iosNode != nil { - if androidNode != nil { - for _, exportMethod := range ios.IosExportMethods { - distributionMethodOption.AddOption(exportMethod, androidNode) - } - } - } else { - rootNode = androidNode - } +func (scanner *Scanner) expoOptions() models.OptionNode { + platformOption := models.NewOption(expoPlatformInputTitle, expoPlatformInputSummary, expoPlatformInputEnvKey, models.TypeSelector) + configOption := models.NewConfigOption(expoConfigName, nil) - for _, lastOption := range rootNode.LastChilds() { - lastOption.ChildOptionMap = map[string]*models.OptionNode{} - if androidNode != nil { - // Android buildVariantOption is last - lastOption.AddConfig("Release", models.NewConfigOption(expoConfigName, nil)) - continue - } - - // iOS distributionMethodOption is last - for _, exportMethod := range ios.IosExportMethods { - lastOption.AddConfig(exportMethod, models.NewConfigOption(expoConfigName, nil)) - } + for _, platform := range steps.RunEASBuildPlatforms { + platformOption.AddConfig(platform, configOption) } - return *rootNode, warnings, nil + return *platformOption } // expoConfigs implements ScannerInterface.Configs function for Expo based React Native projects. -func (scanner *Scanner) expoConfigs() (models.BitriseConfigMap, error) { +func (scanner *Scanner) expoConfigs(project project, isPrivateRepo bool) (models.BitriseConfigMap, error) { configMap := models.BitriseConfigMap{} - // determine workdir - packageJSONDir := filepath.Dir(scanner.packageJSONPth) - relPackageJSONDir, err := utility.RelPath(scanner.searchDir, packageJSONDir) - if err != nil { - return models.BitriseConfigMap{}, fmt.Errorf("Failed to get relative package.json dir path, error: %s", err) - } - if relPackageJSONDir == "." { + if project.projectRelDir == "." { // package.json placed in the search dir, no need to change-dir in the workflows - relPackageJSONDir = "" - } - log.TPrintf("Working directory: %v", relPackageJSONDir) - - workdirEnvList := []envmanModels.EnvironmentItemModel{} - if relPackageJSONDir != "" { - workdirEnvList = append(workdirEnvList, envmanModels.EnvironmentItemModel{workDirInputKey: relPackageJSONDir}) - } - - xcodeArchiveStepListItem := steps.XcodeArchiveStepListItem( - envmanModels.EnvironmentItemModel{ios.ProjectPathInputKey: "$" + ios.ProjectPathInputEnvKey}, - envmanModels.EnvironmentItemModel{ios.SchemeInputKey: "$" + ios.SchemeInputEnvKey}, - envmanModels.EnvironmentItemModel{ios.ConfigurationInputKey: "Release"}, - envmanModels.EnvironmentItemModel{ios.DistributionMethodInputKey: "$" + ios.DistributionMethodEnvKey}, - // In case of Expo projects, you do not have the native project in your - // repository. During the build, we ask Expo to generate it (using the - // ExpoDetachStepListItem). The generated native project does not have - // codesigning set up (No valid development team selected). Because of this, we - // ask for the desired development team during the Add New App process and force - // the user-provided Development Team ID using the DEVELOPMENT_TEAM build setting. - envmanModels.EnvironmentItemModel{ios.XCConfigContentInputKey: "COMPILER_INDEX_STORE_ENABLE = NO\n" + - "DEVELOPMENT_TEAM = $BITRISE_IOS_DEVELOPMENT_TEAM"}, - ) - - if !scanner.hasTest { - // if the project has no test script defined, - // we can only provide deploy like workflow, - // so that is going to be the primary workflow - - configBuilder := models.NewDefaultConfigBuilder() - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultPrepareStepList(false)...) - - if scanner.hasYarnLockFile { - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.YarnStepListItem(append(workdirEnvList, envmanModels.EnvironmentItemModel{"command": "install"})...)) - } else { - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.NpmStepListItem(append(workdirEnvList, envmanModels.EnvironmentItemModel{"command": "install"})...)) - } - - projectDir := relPackageJSONDir - if relPackageJSONDir == "" { - projectDir = "./" - } - - if !scanner.expoSettings.isAllIdentifierPresent() { - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.ScriptSteplistItem(expoBareAddIdentiferScriptTitle, - envmanModels.EnvironmentItemModel{"content": expoBareAddIdentifiersScript(filepath.Join(projectDir, expoAppJSONName), androidPackageEnvKey, iosBundleIDEnvKey)}, - )) - } - - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.ExpoDetachStepListItem( - envmanModels.EnvironmentItemModel{"project_path": projectDir}, - )) - - // android build - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.InstallMissingAndroidToolsStepListItem( - envmanModels.EnvironmentItemModel{android.GradlewPathInputKey: "$" + android.ProjectLocationInputEnvKey + "/gradlew"}, - )) - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.AndroidBuildStepListItem( - envmanModels.EnvironmentItemModel{android.ProjectLocationInputKey: "$" + android.ProjectLocationInputEnvKey}, - envmanModels.EnvironmentItemModel{android.ModuleInputKey: "$" + android.ModuleInputEnvKey}, - envmanModels.EnvironmentItemModel{android.VariantInputKey: "$" + android.VariantInputEnvKey}, - )) - - // ios build - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.CertificateAndProfileInstallerStepListItem()) - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, xcodeArchiveStepListItem) - - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultDeployStepList(false)...) - configBuilder.SetWorkflowDescriptionTo(models.PrimaryWorkflowID, deployWorkflowDescription) - - bitriseDataModel, err := configBuilder.Generate(scannerName) - if err != nil { - return models.BitriseConfigMap{}, err - } - - data, err := yaml.Marshal(bitriseDataModel) - if err != nil { - return models.BitriseConfigMap{}, err - } - - configMap[expoConfigName] = string(data) - - return configMap, nil + project.projectRelDir = "" } + testSteps := getTestSteps(project.projectRelDir, project.hasYarnLockFile, project.hasTest) // primary workflow - configBuilder := models.NewDefaultConfigBuilder() - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultPrepareStepList(false)...) - if scanner.hasYarnLockFile { - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.YarnStepListItem(append(workdirEnvList, envmanModels.EnvironmentItemModel{"command": "install"})...)) - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.YarnStepListItem(append(workdirEnvList, envmanModels.EnvironmentItemModel{"command": "test"})...)) - } else { - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.NpmStepListItem(append(workdirEnvList, envmanModels.EnvironmentItemModel{"command": "install"})...)) - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.NpmStepListItem(append(workdirEnvList, envmanModels.EnvironmentItemModel{"command": "test"})...)) - } - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultDeployStepList(false)...) - - // deploy workflow - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultPrepareStepList(false)...) - if scanner.hasYarnLockFile { - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.YarnStepListItem(append(workdirEnvList, envmanModels.EnvironmentItemModel{"command": "install"})...)) - } else { - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.NpmStepListItem(append(workdirEnvList, envmanModels.EnvironmentItemModel{"command": "install"})...)) - } - - projectDir := relPackageJSONDir - if relPackageJSONDir == "" { - projectDir = "./" + primaryDescription := expoPrimaryWorkflowDescription + if !project.hasTest { + primaryDescription = expoPrimaryWorkflowNoTestsDescription } - if !scanner.expoSettings.isAllIdentifierPresent() { - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.ScriptSteplistItem(expoBareAddIdentiferScriptTitle, - envmanModels.EnvironmentItemModel{"content": expoBareAddIdentifiersScript(filepath.Join(projectDir, expoAppJSONName), androidPackageEnvKey, iosBundleIDEnvKey)}, - )) - } - - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.ExpoDetachStepListItem( - envmanModels.EnvironmentItemModel{"project_path": projectDir}, - )) - - // android build - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.InstallMissingAndroidToolsStepListItem( - envmanModels.EnvironmentItemModel{android.GradlewPathInputKey: "$" + android.ProjectLocationInputEnvKey + "/gradlew"}, - )) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.AndroidBuildStepListItem( - envmanModels.EnvironmentItemModel{android.ProjectLocationInputKey: "$" + android.ProjectLocationInputEnvKey}, - envmanModels.EnvironmentItemModel{android.ModuleInputKey: "$" + android.ModuleInputEnvKey}, - envmanModels.EnvironmentItemModel{android.VariantInputKey: "$" + android.VariantInputEnvKey}, - )) + configBuilder := models.NewDefaultConfigBuilder() + configBuilder.SetWorkflowDescriptionTo(models.PrimaryWorkflowID, primaryDescription) + configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultPrepareStepListV2(steps.PrepareListParams{ + ShouldIncludeCache: false, + ShouldIncludeActivateSSH: isPrivateRepo, + })...) + configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, testSteps...) - // ios build - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.CertificateAndProfileInstallerStepListItem()) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, xcodeArchiveStepListItem) + configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultDeployStepListV2(false)...) + // deploy workflow + deployDescription := expoDeployWorkflowDescription + if !project.hasTest { + deployDescription = expoDeployWorkflowNoTestsDescription + } + + configBuilder.SetWorkflowDescriptionTo(models.DeployWorkflowID, deployDescription) + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultPrepareStepListV2(steps.PrepareListParams{ + ShouldIncludeCache: false, + ShouldIncludeActivateSSH: isPrivateRepo, + })...) + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, testSteps...) + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.RunEASBuildStepListItem(project.projectRelDir, "$"+expoPlatformInputEnvKey)) configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultDeployStepList(false)...) - configBuilder.SetWorkflowDescriptionTo(models.DeployWorkflowID, deployWorkflowDescription) + // generate bitrise.yml bitriseDataModel, err := configBuilder.Generate(scannerName) if err != nil { return models.BitriseConfigMap{}, err @@ -374,91 +92,43 @@ func (scanner *Scanner) expoConfigs() (models.BitriseConfigMap, error) { // expoDefaultOptions implements ScannerInterface.DefaultOptions function for Expo based React Native projects. func (Scanner) expoDefaultOptions() models.OptionNode { - // ios options - rootNode := models.NewOption(bareIOSProjectPathInputTitle, bareIOSprojectPathInputSummary, ios.ProjectPathInputEnvKey, models.TypeUserInput) - - bundleIDOption := models.NewOption(iosBundleIDInputTitle, iosBundleIDInputSummaryDefault, iosBundleIDEnvKey, models.TypeUserInput) - rootNode.AddOption("", bundleIDOption) + workDirOption := models.NewOption(expoProjectDirInputTitle, expoProjectDirInputSummary, expoProjectDirInputEnvKey, models.TypeUserInput) + platformOption := models.NewOption(expoPlatformInputTitle, expoPlatformInputSummary, expoPlatformInputEnvKey, models.TypeSelector) + configOption := models.NewConfigOption(expoDefaultConfigName, nil) - schemeOption := models.NewOption(schemeInputTitle, schemeInputSummary, ios.SchemeInputEnvKey, models.TypeUserInput) - bundleIDOption.AddOption("", schemeOption) - - distributionMethodOption := models.NewOption(ios.DistributionMethodInputTitle, ios.DistributionMethodInputSummary, ios.DistributionMethodEnvKey, models.TypeSelector) - schemeOption.AddOption("", distributionMethodOption) - - // android options - androidPackageOption := models.NewOption(androidPackageInputTitle, androidPackageInputSummaryDefault, androidPackageEnvKey, models.TypeOptionalUserInput) - for _, exportMethod := range ios.IosExportMethods { - distributionMethodOption.AddOption(exportMethod, androidPackageOption) + workDirOption.AddConfig("", platformOption) + for _, platform := range steps.RunEASBuildPlatforms { + platformOption.AddConfig(platform, configOption) } - workDirOption := models.NewOption(projectRootDirInputTitle, projectRootDirInputSummary, wordirEnv, models.TypeUserInput) - androidPackageOption.AddOption("", workDirOption) - - projectLocationOption := models.NewOption(android.ProjectLocationInputTitle, android.ProjectLocationInputSummary, android.ProjectLocationInputEnvKey, models.TypeSelector) - workDirOption.AddOption("", projectLocationOption) - - moduleOption := models.NewOption(android.ModuleInputTitle, android.ModuleInputSummary, android.ModuleInputEnvKey, models.TypeUserInput) - projectLocationOption.AddOption("./android", moduleOption) - - buildVariantOption := models.NewOption(android.VariantInputTitle, android.VariantInputSummary, android.VariantInputEnvKey, models.TypeOptionalUserInput) - moduleOption.AddOption("app", buildVariantOption) - - for _, lastOption := range rootNode.LastChilds() { - lastOption.ChildOptionMap = map[string]*models.OptionNode{} - // buildVariantOption is the last Option added - lastOption.AddConfig("Release", models.NewConfigOption(expoDefaultConfigName, nil)) - } - - return *rootNode + return *workDirOption } // expoDefaultConfigs implements ScannerInterface.DefaultConfigs function for Expo based React Native projects. -func (Scanner) expoDefaultConfigs() (models.BitriseConfigMap, error) { +func (scanner Scanner) expoDefaultConfigs() (models.BitriseConfigMap, error) { configMap := models.BitriseConfigMap{} // primary workflow configBuilder := models.NewDefaultConfigBuilder() - - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultPrepareStepList(false)...) - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.YarnStepListItem(envmanModels.EnvironmentItemModel{workDirInputKey: "$WORKDIR"}, envmanModels.EnvironmentItemModel{"command": "install"})) - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.YarnStepListItem(envmanModels.EnvironmentItemModel{workDirInputKey: "$WORKDIR"}, envmanModels.EnvironmentItemModel{"command": "test"})) - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultDeployStepList(false)...) + configBuilder.SetWorkflowDescriptionTo(models.PrimaryWorkflowID, expoPrimaryWorkflowDescription) + configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultPrepareStepListV2(steps.PrepareListParams{ + ShouldIncludeCache: false, + ShouldIncludeActivateSSH: true, + })...) + configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, getTestSteps("$"+expoProjectDirInputEnvKey, true, true)...) + configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultDeployStepListV2(false)...) // deploy workflow - configBuilder.SetWorkflowDescriptionTo(models.DeployWorkflowID, deployWorkflowDescription) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultPrepareStepList(false)...) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.YarnStepListItem(envmanModels.EnvironmentItemModel{workDirInputKey: "$WORKDIR"}, envmanModels.EnvironmentItemModel{"command": "install"})) - - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.ScriptSteplistItem(expoBareAddIdentiferScriptTitle, - envmanModels.EnvironmentItemModel{"content": expoBareAddIdentifiersScript(filepath.Join(".", expoAppJSONName), androidPackageEnvKey, iosBundleIDEnvKey)}, - )) - - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.ExpoDetachStepListItem( - envmanModels.EnvironmentItemModel{"project_path": "$WORKDIR"}, - )) - - // android build - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.InstallMissingAndroidToolsStepListItem( - envmanModels.EnvironmentItemModel{android.GradlewPathInputKey: "$" + android.ProjectLocationInputEnvKey + "/gradlew"}, - )) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.AndroidBuildStepListItem( - envmanModels.EnvironmentItemModel{android.ProjectLocationInputKey: "$" + android.ProjectLocationInputEnvKey}, - envmanModels.EnvironmentItemModel{android.ModuleInputKey: "$" + android.ModuleInputEnvKey}, - envmanModels.EnvironmentItemModel{android.VariantInputKey: "$" + android.VariantInputEnvKey}, - )) - - // ios build - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.CertificateAndProfileInstallerStepListItem()) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.XcodeArchiveStepListItem( - envmanModels.EnvironmentItemModel{ios.ProjectPathInputKey: "$" + ios.ProjectPathInputEnvKey}, - envmanModels.EnvironmentItemModel{ios.SchemeInputKey: "$" + ios.SchemeInputEnvKey}, - envmanModels.EnvironmentItemModel{ios.DistributionMethodInputKey: "$" + ios.DistributionMethodEnvKey}, - envmanModels.EnvironmentItemModel{ios.ConfigurationInputKey: "Release"}, - )) - + configBuilder.SetWorkflowDescriptionTo(models.DeployWorkflowID, expoDeployWorkflowDescription) + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultPrepareStepListV2(steps.PrepareListParams{ + ShouldIncludeCache: false, + ShouldIncludeActivateSSH: true, + })...) + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, getTestSteps("$"+expoProjectDirInputEnvKey, true, true)...) + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.RunEASBuildStepListItem("$"+expoProjectDirInputEnvKey, "$"+expoPlatformInputEnvKey)) configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultDeployStepList(false)...) + // generate bitrise.yml bitriseDataModel, err := configBuilder.Generate(scannerName) if err != nil { return models.BitriseConfigMap{}, err diff --git a/vendor/github.com/bitrise-io/bitrise-init/scanners/reactnative/plain.go b/vendor/github.com/bitrise-io/bitrise-init/scanners/reactnative/plain.go index ea0ffb21..8cbf4c8e 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/scanners/reactnative/plain.go +++ b/vendor/github.com/bitrise-io/bitrise-init/scanners/reactnative/plain.go @@ -1,206 +1,209 @@ package reactnative import ( - "errors" "fmt" - "path/filepath" "github.com/bitrise-io/bitrise-init/models" "github.com/bitrise-io/bitrise-init/scanners/android" "github.com/bitrise-io/bitrise-init/scanners/ios" "github.com/bitrise-io/bitrise-init/steps" - "github.com/bitrise-io/bitrise-init/utility" + bitriseModels "github.com/bitrise-io/bitrise/models" envmanModels "github.com/bitrise-io/envman/models" - "github.com/bitrise-io/go-utils/pathutil" "gopkg.in/yaml.v2" ) const ( defaultConfigName = "default-react-native-config" + + defaultModule = "app" + defaultVariant = "Debug" ) -// configName generates a config name based on the inputs. -func configName(hasAndroidProject, hasIosProject, hasTest bool) string { +type configDescriptor struct { + hasIOS, hasAndroid bool + hasTest bool + hasYarnLockFile bool + ios ios.ConfigDescriptor +} + +func (d configDescriptor) configName() string { name := "react-native" - if hasAndroidProject { + if d.hasAndroid { name += "-android" } - if hasIosProject { + if d.hasIOS { name += "-ios" + if d.ios.MissingSharedSchemes { + name += "-missing-shared-schemes" + } + if d.ios.HasPodfile { + name += "-pod" + } + if d.ios.CarthageCommand != "" { + name += "-carthage" + } } - if hasTest { + if d.hasTest { name += "-test" } + if d.hasYarnLockFile { + name += "-yarn" + } + return name + "-config" } -// options implements ScannerInterface.Options function for plain React Native projects. -func (scanner *Scanner) options() (models.OptionNode, models.Warnings, error) { - warnings := models.Warnings{} - var rootOption models.OptionNode - projectDir := filepath.Dir(scanner.packageJSONPth) - - // android options - var androidOptions *models.OptionNode - androidDir := filepath.Join(projectDir, "android") - if exist, err := pathutil.IsDirExists(androidDir); err != nil { - return models.OptionNode{}, warnings, err - } else if exist { - if detected, err := scanner.androidScanner.DetectPlatform(scanner.searchDir); err != nil { - return models.OptionNode{}, warnings, err - } else if detected { - // only the first match we need - scanner.androidScanner.ExcludeTest = true - scanner.androidScanner.ProjectRoots = []string{scanner.androidScanner.ProjectRoots[0]} - - options, warns, _, err := scanner.androidScanner.Options() - warnings = append(warnings, warns...) - if err != nil { - return models.OptionNode{}, warnings, err - } - - androidOptions = &options - } - } +func generateIOSOptions(result ios.DetectResult, hasAndroid, hasTests, hasYarnLockFile bool) (*models.OptionNode, models.Warnings, []configDescriptor) { + var ( + warnings models.Warnings + descriptors []configDescriptor + ) + + projectPathOption := models.NewOption(ios.ProjectPathInputTitle, ios.ProjectPathInputSummary, ios.ProjectPathInputEnvKey, models.TypeSelector) + for _, project := range result.Projects { + warnings = append(warnings, project.Warnings...) + + schemeOption := models.NewOption(ios.SchemeInputTitle, ios.SchemeInputSummary, ios.SchemeInputEnvKey, models.TypeSelector) + projectPathOption.AddOption(project.RelPath, schemeOption) + + for _, scheme := range project.Schemes { + exportMethodOption := models.NewOption(ios.DistributionMethodInputTitle, ios.DistributionMethodInputSummary, ios.DistributionMethodEnvKey, models.TypeSelector) + schemeOption.AddOption(scheme.Name, exportMethodOption) + + for _, exportMethod := range ios.IosExportMethods { + iosConfig := ios.NewConfigDescriptor(project.IsPodWorkspace, project.CarthageCommand, scheme.HasXCTests, scheme.HasAppClip, exportMethod, scheme.Missing) + descriptor := configDescriptor{ + hasIOS: true, + hasAndroid: hasAndroid, + hasTest: hasTests, + hasYarnLockFile: hasYarnLockFile, + ios: iosConfig, + } + descriptors = append(descriptors, descriptor) - // ios options - var iosOptions *models.OptionNode - iosDir := filepath.Join(projectDir, "ios") - if exist, err := pathutil.IsDirExists(iosDir); err != nil { - return models.OptionNode{}, warnings, err - } else if exist { - if detected, err := scanner.iosScanner.DetectPlatform(scanner.searchDir); err != nil { - return models.OptionNode{}, warnings, err - } else if detected { - scanner.iosScanner.SuppressPodFileParseError = true - options, warns, _, err := scanner.iosScanner.Options() - warnings = append(warnings, warns...) - if err != nil { - return models.OptionNode{}, warnings, err + exportMethodOption.AddConfig(exportMethod, models.NewConfigOption(descriptor.configName(), nil)) } - - iosOptions = &options } } - if androidOptions == nil && iosOptions == nil { - return models.OptionNode{}, warnings, errors.New("no ios nor android project detected") - } - // --- - - if androidOptions != nil { - if iosOptions == nil { - // we only found an android project - // we need to update the config names - lastChilds := androidOptions.LastChilds() - for _, child := range lastChilds { - for _, child := range child.ChildOptionMap { - if child.Config == "" { - return models.OptionNode{}, warnings, fmt.Errorf("no config for option: %s", child.String()) - } - - configName := configName(true, false, scanner.hasTest) - child.Config = configName - } - } - } else { - // we have both ios and android projects - // we need to remove the android option's config names, - // since ios options will hold them - androidOptions.RemoveConfigs() - } + return projectPathOption, warnings, descriptors +} +// options implements ScannerInterface.Options function for plain React Native projects. +func (scanner *Scanner) options(project project) (models.OptionNode, models.Warnings) { + var ( + rootOption models.OptionNode + allDescriptors []configDescriptor + warnings models.Warnings + ) + + // Android + if len(project.androidProjects) > 0 { + androidOptions := models.NewOption(android.ProjectLocationInputTitle, android.ProjectLocationInputSummary, android.ProjectLocationInputEnvKey, models.TypeSelector) rootOption = *androidOptions - } - if iosOptions != nil { - lastChilds := iosOptions.LastChilds() - for _, child := range lastChilds { - for _, child := range child.ChildOptionMap { - if child.Config == "" { - return models.OptionNode{}, warnings, fmt.Errorf("no config for option: %s", child.String()) + for _, androidProject := range project.androidProjects { + warnings = append(warnings, androidProject.Warnings...) + + moduleOption := models.NewOption(android.ModuleInputTitle, android.ModuleInputSummary, android.ModuleInputEnvKey, models.TypeUserInput) + variantOption := models.NewOption(android.VariantInputTitle, android.VariantInputSummary, android.VariantInputEnvKey, models.TypeOptionalUserInput) + + androidOptions.AddOption(androidProject.RelPath, moduleOption) + moduleOption.AddOption(defaultModule, variantOption) + + if len(project.iosProjects.Projects) == 0 { + descriptor := configDescriptor{ + hasAndroid: true, + hasTest: project.hasTest, + hasYarnLockFile: project.hasYarnLockFile, } + allDescriptors = append(allDescriptors, descriptor) + + variantOption.AddConfig(defaultVariant, models.NewConfigOption(descriptor.configName(), nil)) - configName := configName(scanner.androidScanner != nil, true, scanner.hasTest) - child.Config = configName + continue } - } - if androidOptions == nil { - // we only found an ios project - rootOption = *iosOptions - } else { - // we have both ios and android projects - // we attach ios options to the android options - rootOption.AttachToLastChilds(iosOptions) - } + iosOptions, iosWarnings, descriptors := generateIOSOptions(project.iosProjects, true, project.hasTest, project.hasYarnLockFile) + warnings = append(warnings, iosWarnings...) + allDescriptors = append(allDescriptors, descriptors...) + variantOption.AddOption(defaultVariant, iosOptions) + } + } else { + options, iosWarnings, descriptors := generateIOSOptions(project.iosProjects, false, project.hasTest, project.hasYarnLockFile) + rootOption = *options + warnings = append(warnings, iosWarnings...) + allDescriptors = append(allDescriptors, descriptors...) } - return rootOption, warnings, nil + scanner.configDescriptors = removeDuplicatedConfigDescriptors(append(scanner.configDescriptors, allDescriptors...)) + + return rootOption, warnings } // defaultOptions implements ScannerInterface.DefaultOptions function for plain React Native projects. func (scanner *Scanner) defaultOptions() models.OptionNode { - androidOptions := (&android.Scanner{ExcludeTest: true}).DefaultOptions() - androidOptions.RemoveConfigs() + androidOptions := models.NewOption(android.ProjectLocationInputTitle, android.ProjectLocationInputSummary, android.ProjectLocationInputEnvKey, models.TypeUserInput) + moduleOption := models.NewOption(android.ModuleInputTitle, android.ModuleInputSummary, android.ModuleInputEnvKey, models.TypeUserInput) + variantOption := models.NewOption(android.VariantInputTitle, android.VariantInputSummary, android.VariantInputEnvKey, models.TypeOptionalUserInput) - iosOptions := (&ios.Scanner{}).DefaultOptions() - for _, child := range iosOptions.LastChilds() { - for _, child := range child.ChildOptionMap { - child.Config = defaultConfigName - } - } + androidOptions.AddOption("android", moduleOption) + moduleOption.AddOption(defaultModule, variantOption) + + projectPathOption := models.NewOption(ios.ProjectPathInputTitle, ios.ProjectPathInputSummary, ios.ProjectPathInputEnvKey, models.TypeUserInput) + schemeOption := models.NewOption(ios.SchemeInputTitle, ios.SchemeInputSummary, ios.SchemeInputEnvKey, models.TypeUserInput) - androidOptions.AttachToLastChilds(&iosOptions) + variantOption.AddOption(defaultVariant, projectPathOption) + projectPathOption.AddOption("", schemeOption) - return androidOptions + exportMethodOption := models.NewOption(ios.DistributionMethodInputTitle, ios.DistributionMethodInputSummary, ios.DistributionMethodEnvKey, models.TypeSelector) + for _, exportMethod := range ios.IosExportMethods { + schemeOption.AddOption("", exportMethodOption) + + exportMethodOption.AddConfig(exportMethod, models.NewConfigOption(defaultConfigName, nil)) + } + + return *androidOptions } // configs implements ScannerInterface.Configs function for plain React Native projects. -func (scanner *Scanner) configs() (models.BitriseConfigMap, error) { +func (scanner *Scanner) configs(isPrivateRepo bool) (models.BitriseConfigMap, error) { configMap := models.BitriseConfigMap{} - packageJSONDir := filepath.Dir(scanner.packageJSONPth) - relPackageJSONDir, err := utility.RelPath(scanner.searchDir, packageJSONDir) - if err != nil { - return models.BitriseConfigMap{}, fmt.Errorf("Failed to get relative config.xml dir path, error: %s", err) - } - if relPackageJSONDir == "." { - // config.xml placed in the search dir, no need to change-dir in the workflows - relPackageJSONDir = "" - } - - workdirEnvList := []envmanModels.EnvironmentItemModel{} - if relPackageJSONDir != "" { - workdirEnvList = append(workdirEnvList, envmanModels.EnvironmentItemModel{workDirInputKey: relPackageJSONDir}) + if len(scanner.configDescriptors) == 0 { + return models.BitriseConfigMap{}, fmt.Errorf("invalid state, no config descriptors found") } - if scanner.hasTest { + for _, descriptor := range scanner.configDescriptors { configBuilder := models.NewDefaultConfigBuilder() + testSteps := getTestSteps("$"+projectDirInputEnvKey, descriptor.hasYarnLockFile, descriptor.hasTest) // ci - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultPrepareStepList(false)...) - if scanner.hasYarnLockFile { - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.YarnStepListItem(append(workdirEnvList, envmanModels.EnvironmentItemModel{"command": "install"})...)) - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.YarnStepListItem(append(workdirEnvList, envmanModels.EnvironmentItemModel{"command": "test"})...)) - } else { - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.NpmStepListItem(append(workdirEnvList, envmanModels.EnvironmentItemModel{"command": "install"})...)) - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.NpmStepListItem(append(workdirEnvList, envmanModels.EnvironmentItemModel{"command": "test"})...)) + primaryDescription := primaryWorkflowNoTestsDescription + if descriptor.hasTest { + primaryDescription = primaryWorkflowDescription } - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultDeployStepList(false)...) + + configBuilder.SetWorkflowDescriptionTo(models.PrimaryWorkflowID, primaryDescription) + configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultPrepareStepListV2(steps.PrepareListParams{ + ShouldIncludeCache: false, + ShouldIncludeActivateSSH: isPrivateRepo, + })...) + configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, testSteps...) + + configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultDeployStepListV2(false)...) // cd configBuilder.SetWorkflowDescriptionTo(models.DeployWorkflowID, deployWorkflowDescription) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultPrepareStepList(false)...) - if scanner.hasYarnLockFile { - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.YarnStepListItem(append(workdirEnvList, envmanModels.EnvironmentItemModel{"command": "install"})...)) - } else { - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.NpmStepListItem(append(workdirEnvList, envmanModels.EnvironmentItemModel{"command": "install"})...)) - } + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultPrepareStepListV2(steps.PrepareListParams{ + ShouldIncludeCache: false, + ShouldIncludeActivateSSH: isPrivateRepo, + })...) + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, testSteps...) // android cd - if scanner.androidScanner != nil { + if descriptor.hasAndroid { projectLocationEnv := "$" + android.ProjectLocationInputEnvKey configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.InstallMissingAndroidToolsStepListItem( @@ -208,144 +211,51 @@ func (scanner *Scanner) configs() (models.BitriseConfigMap, error) { )) configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.AndroidBuildStepListItem( envmanModels.EnvironmentItemModel{android.ProjectLocationInputKey: projectLocationEnv}, + envmanModels.EnvironmentItemModel{android.ModuleInputKey: "$" + android.ModuleInputEnvKey}, + envmanModels.EnvironmentItemModel{android.VariantInputKey: "$" + android.VariantInputEnvKey}, )) } // ios cd - if scanner.iosScanner != nil { - for _, descriptor := range scanner.iosScanner.ConfigDescriptors { - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.CertificateAndProfileInstallerStepListItem()) - - if descriptor.MissingSharedSchemes { - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.RecreateUserSchemesStepListItem( - envmanModels.EnvironmentItemModel{ios.ProjectPathInputKey: "$" + ios.ProjectPathInputEnvKey}, - )) - } - - if descriptor.HasPodfile { - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.CocoapodsInstallStepListItem()) - } - - if descriptor.CarthageCommand != "" { - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.CarthageStepListItem( - envmanModels.EnvironmentItemModel{ios.CarthageCommandInputKey: descriptor.CarthageCommand}, - )) - } - - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.XcodeArchiveStepListItem( + if descriptor.hasIOS { + if descriptor.ios.MissingSharedSchemes { + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.RecreateUserSchemesStepListItem( envmanModels.EnvironmentItemModel{ios.ProjectPathInputKey: "$" + ios.ProjectPathInputEnvKey}, - envmanModels.EnvironmentItemModel{ios.SchemeInputKey: "$" + ios.SchemeInputEnvKey}, - envmanModels.EnvironmentItemModel{ios.DistributionMethodInputKey: "$" + ios.DistributionMethodEnvKey}, - envmanModels.EnvironmentItemModel{ios.ConfigurationInputKey: "Release"}, )) - - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultDeployStepList(false)...) - - bitriseDataModel, err := configBuilder.Generate(scannerName) - if err != nil { - return models.BitriseConfigMap{}, err - } - - data, err := yaml.Marshal(bitriseDataModel) - if err != nil { - return models.BitriseConfigMap{}, err - } - - configName := configName(scanner.androidScanner != nil, true, true) - configMap[configName] = string(data) } - } else { - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultDeployStepList(false)...) - bitriseDataModel, err := configBuilder.Generate(scannerName) - if err != nil { - return models.BitriseConfigMap{}, err + if descriptor.ios.HasPodfile { + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.CocoapodsInstallStepListItem()) } - data, err := yaml.Marshal(bitriseDataModel) - if err != nil { - return models.BitriseConfigMap{}, err + if descriptor.ios.CarthageCommand != "" { + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.CarthageStepListItem( + envmanModels.EnvironmentItemModel{ios.CarthageCommandInputKey: descriptor.ios.CarthageCommand}, + )) } - configName := configName(scanner.androidScanner != nil, false, true) - configMap[configName] = string(data) - } - } else { - configBuilder := models.NewDefaultConfigBuilder() - configBuilder.SetWorkflowDescriptionTo(models.DeployWorkflowID, deployWorkflowDescription) - - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultPrepareStepList(false)...) - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.NpmStepListItem(append(workdirEnvList, envmanModels.EnvironmentItemModel{"command": "install"})...)) - - if scanner.androidScanner != nil { - projectLocationEnv := "$" + android.ProjectLocationInputEnvKey - - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.InstallMissingAndroidToolsStepListItem( - envmanModels.EnvironmentItemModel{android.GradlewPathInputKey: "$" + android.ProjectLocationInputEnvKey + "/gradlew"}, - )) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.AndroidBuildStepListItem( - envmanModels.EnvironmentItemModel{android.ProjectLocationInputKey: projectLocationEnv}, + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.XcodeArchiveStepListItem( + envmanModels.EnvironmentItemModel{ios.ProjectPathInputKey: "$" + ios.ProjectPathInputEnvKey}, + envmanModels.EnvironmentItemModel{ios.SchemeInputKey: "$" + ios.SchemeInputEnvKey}, + envmanModels.EnvironmentItemModel{ios.DistributionMethodInputKey: "$" + ios.DistributionMethodEnvKey}, + envmanModels.EnvironmentItemModel{ios.ConfigurationInputKey: "Release"}, + envmanModels.EnvironmentItemModel{ios.AutomaticCodeSigningInputKey: ios.AutomaticCodeSigningInputAPIKeyValue}, )) } - if scanner.iosScanner != nil { - for _, descriptor := range scanner.iosScanner.ConfigDescriptors { - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.CertificateAndProfileInstallerStepListItem()) - - if descriptor.MissingSharedSchemes { - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.RecreateUserSchemesStepListItem( - envmanModels.EnvironmentItemModel{ios.ProjectPathInputKey: "$" + ios.ProjectPathInputEnvKey}, - )) - } - - if descriptor.HasPodfile { - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.CocoapodsInstallStepListItem()) - } - - if descriptor.CarthageCommand != "" { - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.CarthageStepListItem( - envmanModels.EnvironmentItemModel{ios.CarthageCommandInputKey: descriptor.CarthageCommand}, - )) - } - - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.XcodeArchiveStepListItem( - envmanModels.EnvironmentItemModel{ios.ProjectPathInputKey: "$" + ios.ProjectPathInputEnvKey}, - envmanModels.EnvironmentItemModel{ios.SchemeInputKey: "$" + ios.SchemeInputEnvKey}, - envmanModels.EnvironmentItemModel{ios.DistributionMethodInputKey: "$" + ios.DistributionMethodEnvKey}, - envmanModels.EnvironmentItemModel{ios.ConfigurationInputKey: "Release"}, - )) - - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultDeployStepList(false)...) + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultDeployStepListV2(false)...) - bitriseDataModel, err := configBuilder.Generate(scannerName) - if err != nil { - return models.BitriseConfigMap{}, err - } - - data, err := yaml.Marshal(bitriseDataModel) - if err != nil { - return models.BitriseConfigMap{}, err - } - - configName := configName(scanner.androidScanner != nil, true, false) - configMap[configName] = string(data) - } - } else { - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultDeployStepList(false)...) - - bitriseDataModel, err := configBuilder.Generate(scannerName) - if err != nil { - return models.BitriseConfigMap{}, err - } - - data, err := yaml.Marshal(bitriseDataModel) - if err != nil { - return models.BitriseConfigMap{}, err - } + bitriseDataModel, err := configBuilder.Generate(scannerName) + if err != nil { + return models.BitriseConfigMap{}, err + } - configName := configName(scanner.androidScanner != nil, false, false) - configMap[configName] = string(data) + data, err := yaml.Marshal(bitriseDataModel) + if err != nil { + return models.BitriseConfigMap{}, err } + + configMap[descriptor.configName()] = string(data) } return configMap, nil @@ -355,16 +265,23 @@ func (scanner *Scanner) configs() (models.BitriseConfigMap, error) { func (scanner *Scanner) defaultConfigs() (models.BitriseConfigMap, error) { configBuilder := models.NewDefaultConfigBuilder() - // ci - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultPrepareStepList(false)...) - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.NpmStepListItem(envmanModels.EnvironmentItemModel{"command": "install"})) - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.NpmStepListItem(envmanModels.EnvironmentItemModel{"command": "test"})) - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultDeployStepList(false)...) - - // cd + // primary + configBuilder.SetWorkflowDescriptionTo(models.PrimaryWorkflowID, primaryWorkflowDescription) + configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultPrepareStepListV2(steps.PrepareListParams{ + ShouldIncludeCache: false, + ShouldIncludeActivateSSH: true, + })...) + // Assuming project uses yarn and has tests + configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, getTestSteps("", true, true)...) + configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultDeployStepListV2(false)...) + + // deploy configBuilder.SetWorkflowDescriptionTo(models.DeployWorkflowID, deployWorkflowDescription) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultPrepareStepList(false)...) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.NpmStepListItem(envmanModels.EnvironmentItemModel{"command": "install"})) + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultPrepareStepListV2(steps.PrepareListParams{ + ShouldIncludeCache: false, + ShouldIncludeActivateSSH: true, + })...) + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, getTestSteps("", true, true)...) // android projectLocationEnv := "$" + android.ProjectLocationInputEnvKey @@ -374,18 +291,20 @@ func (scanner *Scanner) defaultConfigs() (models.BitriseConfigMap, error) { )) configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.AndroidBuildStepListItem( envmanModels.EnvironmentItemModel{android.ProjectLocationInputKey: projectLocationEnv}, + envmanModels.EnvironmentItemModel{android.ModuleInputKey: "$" + android.ModuleInputEnvKey}, + envmanModels.EnvironmentItemModel{android.VariantInputKey: "$" + android.VariantInputEnvKey}, )) // ios - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.CertificateAndProfileInstallerStepListItem()) configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.XcodeArchiveStepListItem( envmanModels.EnvironmentItemModel{ios.ProjectPathInputKey: "$" + ios.ProjectPathInputEnvKey}, envmanModels.EnvironmentItemModel{ios.SchemeInputKey: "$" + ios.SchemeInputEnvKey}, envmanModels.EnvironmentItemModel{ios.DistributionMethodInputKey: "$" + ios.DistributionMethodEnvKey}, envmanModels.EnvironmentItemModel{ios.ConfigurationInputKey: "Release"}, + envmanModels.EnvironmentItemModel{ios.AutomaticCodeSigningInputKey: ios.AutomaticCodeSigningInputAPIKeyValue}, )) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultDeployStepList(false)...) + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultDeployStepListV2(false)...) bitriseDataModel, err := configBuilder.Generate(scannerName) if err != nil { @@ -404,3 +323,36 @@ func (scanner *Scanner) defaultConfigs() (models.BitriseConfigMap, error) { return configMap, nil } + +func getTestSteps(workDir string, hasYarnLockFile, hasTest bool) []bitriseModels.StepListItemModel { + var testSteps []bitriseModels.StepListItemModel + + if hasYarnLockFile { + testSteps = append(testSteps, steps.YarnStepListItem("install", workDir)) + if hasTest { + testSteps = append(testSteps, steps.YarnStepListItem("test", workDir)) + } + } else { + testSteps = append(testSteps, steps.NpmStepListItem("install", workDir)) + if hasTest { + testSteps = append(testSteps, steps.NpmStepListItem("test", workDir)) + } + } + + return testSteps +} + +func removeDuplicatedConfigDescriptors(configDescriptors []configDescriptor) []configDescriptor { + descritorNameMap := map[string]configDescriptor{} + for _, descriptor := range configDescriptors { + name := descriptor.configName() + descritorNameMap[name] = descriptor + } + + descriptors := []configDescriptor{} + for _, descriptor := range descritorNameMap { + descriptors = append(descriptors, descriptor) + } + + return descriptors +} diff --git a/vendor/github.com/bitrise-io/bitrise-init/scanners/reactnative/reactnative.go b/vendor/github.com/bitrise-io/bitrise-init/scanners/reactnative/reactnative.go index b82ff148..c7d70e26 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/scanners/reactnative/reactnative.go +++ b/vendor/github.com/bitrise-io/bitrise-init/scanners/reactnative/reactnative.go @@ -1,7 +1,6 @@ package reactnative import ( - "encoding/json" "fmt" "path/filepath" @@ -9,35 +8,38 @@ import ( "github.com/bitrise-io/bitrise-init/scanners/android" "github.com/bitrise-io/bitrise-init/scanners/ios" "github.com/bitrise-io/bitrise-init/utility" - "github.com/bitrise-io/go-utils/fileutil" "github.com/bitrise-io/go-utils/log" "github.com/bitrise-io/go-utils/pathutil" - "github.com/bitrise-io/go-xcode/xcodeproject/serialized" ) const scannerName = "react-native" const ( - // workDirInputKey is a key of the working directory step input. - workDirInputKey = "workdir" -) + projectDirInputTitle = "React Native project directory" + projectDirInputSummary = "Path of the directory containing the project's `package.json` file." + projectDirInputEnvKey = "WORKDIR" -const ( - isExpoCLIInputTitle = "Was your React Native app created with the Expo CLI and using Managed Workflow?" - isExpoCLIInputSummary = "Will include *Expo Eject** Step if using Expo Managed Workflow (https://docs.expo.io/introduction/managed-vs-bare/). If ios/android native projects are present in the repository, choose No." + isExpoBasedProjectInputTitle = "Is this an [Expo](https://expo.dev)-based React Native project?" + isExpoBasedProjectInputSummary = "Default deploy workflow runs builds on Expo Application Services (EAS) for Expo-based React Native projects.\nOtherwise native iOS and Android build steps will be used." ) -// Scanner implements the project scanner for plain React Native and Expo based projects. -type Scanner struct { - searchDir string - iosScanner *ios.Scanner - androidScanner *android.Scanner +type project struct { + projectRelDir string hasTest bool hasYarnLockFile bool - packageJSONPth string - expoSettings *expoSettings + // non-Expo; native projects + iosProjects ios.DetectResult + androidProjects []android.Project +} + +// Scanner implements the project scanner for plain React Native and Expo based projects. +type Scanner struct { + isExpoBased bool + projects []project + + configDescriptors []configDescriptor } // NewScanner creates a new scanner instance. @@ -50,123 +52,107 @@ func (Scanner) Name() string { return scannerName } -type expoSettings struct { - name string - isIOS, isAndroid bool - bundleIdentifierIOS string - packageNameAndroid string -} - -func (settings *expoSettings) isAllIdentifierPresent() bool { - return !(settings.isAndroid && settings.packageNameAndroid == "" || - settings.isIOS && settings.bundleIdentifierIOS == "") -} - -// parseExpoProjectSettings reports whether a project is Expo based and it's settings, like targeted platforms -func parseExpoProjectSettings(packageJSONPth string) (*expoSettings, error) { +func isExpoBasedProject(packageJSONPth string) (bool, error) { packages, err := utility.ParsePackagesJSON(packageJSONPth) if err != nil { - return nil, fmt.Errorf("failed to parse package json file (%s): %s", packageJSONPth, err) + return false, fmt.Errorf("failed to parse package json file (%s): %s", packageJSONPth, err) } if _, found := packages.Dependencies["expo"]; !found { - return nil, nil + return false, nil } - // app.json file is a required part of an expo projects and should be placed next to the root package.json file - appJSONPth := filepath.Join(filepath.Dir(packageJSONPth), "app.json") - exist, err := pathutil.IsPathExists(appJSONPth) - if err != nil { - return nil, fmt.Errorf("failed to check if app.json file (%s) exist: %s", appJSONPth, err) - } - if !exist { - return nil, nil + expoAppConfigFiles := []string{"app.json", "app.config.js", "app.config.ts"} + for _, base := range expoAppConfigFiles { + expoAppConfigPth := filepath.Join(filepath.Dir(packageJSONPth), base) + exist, err := pathutil.IsPathExists(expoAppConfigPth) + if err != nil { + return false, fmt.Errorf("failed to check if Expo app config exists at: %s: %s", expoAppConfigPth, err) + } + if exist { + return true, nil + } } - appJSON, err := fileutil.ReadStringFromFile(appJSONPth) - if err != nil { - return nil, err - } - var app serialized.Object - if err := json.Unmarshal([]byte(appJSON), &app); err != nil { - return nil, err - } + return false, nil +} - expoObj, err := app.Object("expo") +func hasNativeIOSProject(projectDir string, iosScanner *ios.Scanner) (bool, ios.DetectResult, error) { + absProjectDir, err := pathutil.AbsPath(projectDir) if err != nil { - log.Warnf("%s", fmt.Errorf("app.json file (%s) has no 'expo' entry, not an Expo project", appJSONPth)) - return nil, nil + return false, ios.DetectResult{}, err } - projectName, err := expoObj.String("name") - if err != nil || projectName == "" { - log.Debugf("%s", fmt.Errorf("app.json file (%s) has no 'expo/name' entry, can not guess iOS project path, will ask for it during project configuration", appJSONPth)) + + iosDir := filepath.Join(absProjectDir, "ios") + if exist, err := pathutil.IsDirExists(iosDir); err != nil || !exist { + return false, ios.DetectResult{}, err } - iosObj, err := expoObj.Object("ios") + + detected, err := iosScanner.DetectPlatform(projectDir) + + return detected, iosScanner.DetectResult, err +} + +func hasNativeAndroidProject(projectDir string, androidScanner *android.Scanner) (bool, []android.Project, error) { + absProjectDir, err := pathutil.AbsPath(projectDir) if err != nil { - log.TDebugf("%s", fmt.Errorf("app.json file (%s) has no no 'expo/ios entry', assuming iOS is targeted by Expo", appJSONPth)) - } - bundleID, err := iosObj.String("bundleIdentifier") - if err != nil || bundleID == "" { - log.TDebugf("%s", fmt.Errorf("app.json file (%s) has no no 'expo/ios/bundleIdentifier' entry, will ask for it during project configuration", appJSONPth)) + return false, nil, err } - androidObj, err := expoObj.Object("android") - if err != nil { - log.TDebugf("%s", fmt.Errorf("app.json file (%s) has no 'expo/android' entry, assuming Android is targeted by Expo", appJSONPth)) + + androidDir := filepath.Join(absProjectDir, "android") + if exist, err := pathutil.IsDirExists(androidDir); err != nil || !exist { + return false, nil, err } - packageName, err := androidObj.String("package") - if err != nil || packageName == "" { - log.TDebugf("%s", fmt.Errorf("app.json file (%s) has no no 'expo/android/package' entry, will ask for it during project configuration", appJSONPth)) + + if detected, err := androidScanner.DetectPlatform(projectDir); err != nil || !detected { + return false, nil, err } - // expo/ios and expo/android entry is optional - return &expoSettings{ - name: projectName, - isIOS: true, - isAndroid: true, - packageNameAndroid: packageName, - bundleIdentifierIOS: bundleID, - }, nil + return true, androidScanner.Projects, nil } -// hasNativeProjects reports whether the project directory contains ios and android native project. -func hasNativeProjects(searchDir, projectDir string, iosScanner *ios.Scanner, androidScanner *android.Scanner) (bool, bool, error) { - absProjectDir, err := pathutil.AbsPath(projectDir) +func getNativeProjects(packageJSONPth, relPackageJSONDir string) (ios.DetectResult, []android.Project) { + var ( + iosScanner = ios.NewScanner() + androidScanner = android.NewScanner() + ) + iosScanner.ExcludeAppIcon = true + iosScanner.SuppressPodFileParseError = true + + projectDir := filepath.Dir(packageJSONPth) + isIOSProject, iosProjects, err := hasNativeIOSProject(projectDir, iosScanner) if err != nil { - return false, false, err + log.TWarnf("failed to check native iOS projects: %s", err) } + log.TPrintf("Found native ios project: %v", isIOSProject) - iosProjectDetected := false - iosDir := filepath.Join(absProjectDir, "ios") - if exist, err := pathutil.IsDirExists(iosDir); err != nil { - return false, false, err - } else if exist { - if detected, err := iosScanner.DetectPlatform(searchDir); err != nil { - return false, false, err - } else if detected { - iosProjectDetected = true - } + isAndroidProject, androidProjects, err := hasNativeAndroidProject(projectDir, androidScanner) + if err != nil { + log.TWarnf("failed to check native Android projects: %s", err) } + log.TPrintf("Found native android project: %v", isAndroidProject) - androidProjectDetected := false - androidDir := filepath.Join(absProjectDir, "android") - if exist, err := pathutil.IsDirExists(androidDir); err != nil { - return false, false, err - } else if exist { - if detected, err := androidScanner.DetectPlatform(searchDir); err != nil { - return false, false, err - } else if detected { - androidProjectDetected = true - } + // Update native projects paths relative to search dir (otherwise would be relative to package.json dir). + var newIosProjects []ios.Project + for _, p := range iosProjects.Projects { + p.RelPath = filepath.Join(relPackageJSONDir, p.RelPath) + newIosProjects = append(newIosProjects, p) + } + iosProjects.Projects = newIosProjects + + var newAndroidProjects []android.Project + for _, p := range androidProjects { + p.RelPath = filepath.Join(relPackageJSONDir, p.RelPath) + newAndroidProjects = append(newAndroidProjects, p) } + androidProjects = newAndroidProjects - return iosProjectDetected, androidProjectDetected, nil + return iosProjects, androidProjects } // DetectPlatform implements ScannerInterface.DetectPlatform function. func (scanner *Scanner) DetectPlatform(searchDir string) (bool, error) { - scanner.searchDir = searchDir - - log.TInfof("Collect package.json files") + log.TInfof("Collecting package.json files") packageJSONPths, err := CollectPackageJSONFiles(searchDir) if err != nil { @@ -174,104 +160,110 @@ func (scanner *Scanner) DetectPlatform(searchDir string) (bool, error) { } log.TPrintf("%d package.json file detected", len(packageJSONPths)) - log.TPrintf("Filter relevant package.json files") - - var expoSettings *expoSettings - var packageFile string + for _, path := range packageJSONPths { + log.TPrintf("- %s", path) + } + log.TPrintf("Filtering relevant package.json files") for _, packageJSONPth := range packageJSONPths { log.TPrintf("Checking: %s", packageJSONPth) - expoPrefs, err := parseExpoProjectSettings(packageJSONPth) + isExpoBased, err := isExpoBasedProject(packageJSONPth) if err != nil { - log.TWarnf("failed to check if project uses Expo: %s", err) + log.TWarnf("failed to determine if project is Expo based: %s", err) } - log.TPrintf("Project uses expo: %v", expoPrefs != nil) - if expoPrefs != nil { - log.TPrintf("Expo configuration: %+v", expoPrefs) - } + log.TPrintf("Project uses expo: %v", isExpoBased) - if scanner.iosScanner == nil { - scanner.iosScanner = ios.NewScanner() - scanner.iosScanner.ExcludeAppIcon = true + // determine workdir + packageJSONDir := filepath.Dir(packageJSONPth) + relPackageJSONDir, err := utility.RelPath(searchDir, packageJSONDir) + if err != nil { + return false, fmt.Errorf("failed to get relative package.json dir path: %s", err) } - if scanner.androidScanner == nil { - scanner.androidScanner = android.NewScanner() - scanner.androidScanner.ExcludeAppIcon = true + + var ( + iosProjects ios.DetectResult + androidProjects []android.Project + ) + if !isExpoBased { + iosProjects, androidProjects = getNativeProjects(packageJSONPth, relPackageJSONDir) + if len(iosProjects.Projects) == 0 && len(androidProjects) == 0 { + continue + } } - projectDir := filepath.Dir(packageJSONPth) - ios, android, err := hasNativeProjects(searchDir, projectDir, scanner.iosScanner, scanner.androidScanner) + // determine Js dependency manager + hasYarnLockFile, err := containsYarnLock(filepath.Dir(packageJSONPth)) if err != nil { - log.TWarnf("failed to check native projects: %s", err) - } else { - log.TPrintf("Found native ios project: %v", ios) - log.TPrintf("Found native android project: %v", android) + return false, err } + log.TPrintf("Js dependency manager for %s is yarn: %t", packageJSONPth, hasYarnLockFile) - if expoPrefs != nil { - if !(ios || android) { - expoSettings = expoPrefs - packageFile = packageJSONPth - break - } - log.TPrintf("Native ios/android project present, expo eject step will not be included.") + packages, err := utility.ParsePackagesJSON(packageJSONPth) + if err != nil { + return false, err } - if ios || android { - packageFile = packageJSONPth - break - } - } + _, hasTests := packages.Scripts["test"] + log.TPrintf("Test script found in package.json: %v", hasTests) - if packageFile == "" { - return false, nil - } + result := project{ + projectRelDir: relPackageJSONDir, + hasTest: hasTests, + hasYarnLockFile: hasYarnLockFile, + iosProjects: iosProjects, + androidProjects: androidProjects, + } - scanner.expoSettings = expoSettings - scanner.packageJSONPth = packageFile + if isExpoBased { + scanner.projects = []project{result} + scanner.isExpoBased = true - // determine Js dependency manager - if scanner.hasYarnLockFile, err = containsYarnLock(filepath.Dir(scanner.packageJSONPth)); err != nil { - return false, err - } - log.TPrintf("Js dependency manager for %s is yarn: %t", scanner.packageJSONPth, scanner.hasYarnLockFile) + break + } - packages, err := utility.ParsePackagesJSON(scanner.packageJSONPth) - if err != nil { - return false, err + scanner.projects = append(scanner.projects, result) } - if _, found := packages.Scripts["test"]; found { - scanner.hasTest = true + if len(scanner.projects) == 0 { + return false, nil } - log.TPrintf("Test script found in package.json: %v", scanner.hasTest) return true, nil } // Options implements ScannerInterface.Options function. -func (scanner *Scanner) Options() (options models.OptionNode, warnings models.Warnings, icons models.Icons, err error) { - if scanner.expoSettings != nil { - options, warnings, err = scanner.expoOptions() +func (scanner *Scanner) Options() (options models.OptionNode, allWarnings models.Warnings, icons models.Icons, err error) { + if scanner.isExpoBased { + options = scanner.expoOptions() } else { - options, warnings, err = scanner.options() + projectRootOption := models.NewOption(projectDirInputTitle, projectDirInputSummary, projectDirInputEnvKey, models.TypeSelector) + options = *projectRootOption + + for _, project := range scanner.projects { + options, warnings := scanner.options(project) + allWarnings = append(allWarnings, warnings...) + + projectRootOption.AddOption(project.projectRelDir, &options) + } } + return } // Configs implements ScannerInterface.Configs function. -func (scanner *Scanner) Configs() (models.BitriseConfigMap, error) { - if scanner.expoSettings != nil { - return scanner.expoConfigs() +func (scanner *Scanner) Configs(isPrivateRepo bool) (models.BitriseConfigMap, error) { + if scanner.isExpoBased { + return scanner.expoConfigs(scanner.projects[0], isPrivateRepo) } - return scanner.configs() + + return scanner.configs(isPrivateRepo) } // DefaultOptions implements ScannerInterface.DefaultOptions function. func (scanner *Scanner) DefaultOptions() models.OptionNode { - expoOption := models.NewOption(isExpoCLIInputTitle, isExpoCLIInputSummary, "", models.TypeSelector) + expoOption := models.NewOption(isExpoBasedProjectInputTitle, isExpoBasedProjectInputSummary, "", models.TypeSelector) expoDefaultOptions := scanner.expoDefaultOptions() expoOption.AddOption("yes", &expoDefaultOptions) diff --git a/vendor/github.com/bitrise-io/bitrise-init/scanners/reactnative/utility.go b/vendor/github.com/bitrise-io/bitrise-init/scanners/reactnative/utility.go index a12716c3..2846525e 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/scanners/reactnative/utility.go +++ b/vendor/github.com/bitrise-io/bitrise-init/scanners/reactnative/utility.go @@ -10,7 +10,7 @@ import ( // CollectPackageJSONFiles collects package.json files, with react-native dependency. func CollectPackageJSONFiles(searchDir string) ([]string, error) { - fileList, err := pathutil.ListPathInDirSortedByComponents(searchDir, true) + fileList, err := pathutil.ListPathInDirSortedByComponents(searchDir, false) if err != nil { return nil, err } diff --git a/vendor/github.com/bitrise-io/bitrise-init/scanners/scanners.go b/vendor/github.com/bitrise-io/bitrise-init/scanners/scanners.go index 2562c833..f8f8c85a 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/scanners/scanners.go +++ b/vendor/github.com/bitrise-io/bitrise-init/scanners/scanners.go @@ -53,7 +53,7 @@ type ScannerInterface interface { // Every config's key should be the last option one of the OptionNode branches. // Returns: // - platform BitriseConfigMap - Configs() (models.BitriseConfigMap, error) + Configs(isPrivateRepository bool) (models.BitriseConfigMap, error) // Returns: // - platform default BitriseConfigMap diff --git a/vendor/github.com/bitrise-io/bitrise-init/steps/const.go b/vendor/github.com/bitrise-io/bitrise-init/steps/const.go index 378477d4..dc806bea 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/steps/const.go +++ b/vendor/github.com/bitrise-io/bitrise-init/steps/const.go @@ -90,7 +90,7 @@ const ( // InstallMissingAndroidToolsID ... InstallMissingAndroidToolsID = "install-missing-android-tools" // InstallMissingAndroidToolsVersion ... - InstallMissingAndroidToolsVersion = "2" + InstallMissingAndroidToolsVersion = "3" ) const ( @@ -135,6 +135,13 @@ const ( XcodeTestVersion = "4" ) +const ( + // XcodeBuildForTestID ... + XcodeBuildForTestID = "xcode-build-for-test" + // XcodeBuildForTestVersion ... + XcodeBuildForTestVersion = "1" +) + const ( // XcodeArchiveMacID ... XcodeArchiveMacID = "xcode-archive-mac" @@ -160,7 +167,7 @@ const ( // CordovaArchiveID ... CordovaArchiveID = "cordova-archive" // CordovaArchiveVersion ... - CordovaArchiveVersion = "2" + CordovaArchiveVersion = "3" ) const ( @@ -205,6 +212,16 @@ const ( ExpoDetachVersion = "1" ) +const ( + // RunEASBuildID ... + RunEASBuildID = "run-eas-build" + // RunEASBuildVersion ... + RunEASBuildVersion = "0" +) + +// RunEASBuildPlatforms ... +var RunEASBuildPlatforms = []string{"all", "android", "ios"} + const ( // YarnID ... YarnID = "yarn" diff --git a/vendor/github.com/bitrise-io/bitrise-init/steps/steps.go b/vendor/github.com/bitrise-io/bitrise-init/steps/steps.go index 6e9d97b7..3ddb3cf2 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/steps/steps.go +++ b/vendor/github.com/bitrise-io/bitrise-init/steps/steps.go @@ -7,6 +7,12 @@ import ( stepmanModels "github.com/bitrise-io/stepman/models" ) +// PrepareListParams describes the default prepare Step options. +type PrepareListParams struct { + ShouldIncludeCache bool + ShouldIncludeActivateSSH bool +} + func stepIDComposite(ID, version string) string { if version != "" { return ID + "@" + version @@ -33,8 +39,9 @@ func stepListItem(stepIDComposite, title, runIf string, inputs ...envmanModels.E // DefaultPrepareStepList ... func DefaultPrepareStepList(isIncludeCache bool) []bitriseModels.StepListItemModel { + runIfCondition := `{{getenv "SSH_RSA_PRIVATE_KEY" | ne ""}}` stepList := []bitriseModels.StepListItemModel{ - ActivateSSHKeyStepListItem(), + ActivateSSHKeyStepListItem(runIfCondition), GitCloneStepListItem(), } @@ -45,6 +52,23 @@ func DefaultPrepareStepList(isIncludeCache bool) []bitriseModels.StepListItemMod return append(stepList, ScriptSteplistItem(ScriptDefaultTitle)) } +// DefaultPrepareStepListV2 ... +func DefaultPrepareStepListV2(params PrepareListParams) []bitriseModels.StepListItemModel { + stepList := []bitriseModels.StepListItemModel{} + + if params.ShouldIncludeActivateSSH { + stepList = append(stepList, ActivateSSHKeyStepListItem("")) + } + + stepList = append(stepList, GitCloneStepListItem()) + + if params.ShouldIncludeCache { + stepList = append(stepList, CachePullStepListItem()) + } + + return stepList +} + // DefaultDeployStepList ... func DefaultDeployStepList(isIncludeCache bool) []bitriseModels.StepListItemModel { stepList := []bitriseModels.StepListItemModel{ @@ -58,11 +82,23 @@ func DefaultDeployStepList(isIncludeCache bool) []bitriseModels.StepListItemMode return stepList } +// DefaultDeployStepListV2 ... +func DefaultDeployStepListV2(shouldIncludeCache bool) []bitriseModels.StepListItemModel { + stepList := []bitriseModels.StepListItemModel{} + + if shouldIncludeCache { + stepList = append(stepList, CachePushStepListItem()) + } + + stepList = append(stepList, DeployToBitriseIoStepListItem()) + + return stepList +} + // ActivateSSHKeyStepListItem ... -func ActivateSSHKeyStepListItem() bitriseModels.StepListItemModel { +func ActivateSSHKeyStepListItem(runIfCondition string) bitriseModels.StepListItemModel { stepIDComposite := stepIDComposite(ActivateSSHKeyID, ActivateSSHKeyVersion) - runIf := `{{getenv "SSH_RSA_PRIVATE_KEY" | ne ""}}` - return stepListItem(stepIDComposite, "", runIf) + return stepListItem(stepIDComposite, "", runIfCondition) } // AndroidLintStepListItem ... @@ -167,6 +203,12 @@ func XcodeArchiveStepListItem(inputs ...envmanModels.EnvironmentItemModel) bitri return stepListItem(stepIDComposite, "", "", inputs...) } +// XcodeBuildForTestStepListItem ... +func XcodeBuildForTestStepListItem(inputs ...envmanModels.EnvironmentItemModel) bitriseModels.StepListItemModel { + stepIDComposite := stepIDComposite(XcodeBuildForTestID, XcodeBuildForTestVersion) + return stepListItem(stepIDComposite, "", "", inputs...) +} + // XcodeTestStepListItem ... func XcodeTestStepListItem(inputs ...envmanModels.EnvironmentItemModel) bitriseModels.StepListItemModel { stepIDComposite := stepIDComposite(XcodeTestID, XcodeTestVersion) @@ -222,19 +264,42 @@ func KarmaJasmineTestRunnerStepListItem(inputs ...envmanModels.EnvironmentItemMo } // NpmStepListItem ... -func NpmStepListItem(inputs ...envmanModels.EnvironmentItemModel) bitriseModels.StepListItemModel { +func NpmStepListItem(command, workdir string) bitriseModels.StepListItemModel { + var inputs []envmanModels.EnvironmentItemModel + if workdir != "" { + inputs = append(inputs, envmanModels.EnvironmentItemModel{"workdir": workdir}) + } + if command != "" { + inputs = append(inputs, envmanModels.EnvironmentItemModel{"command": command}) + } + stepIDComposite := stepIDComposite(NpmID, NpmVersion) return stepListItem(stepIDComposite, "", "", inputs...) } -// ExpoDetachStepListItem ... -func ExpoDetachStepListItem(inputs ...envmanModels.EnvironmentItemModel) bitriseModels.StepListItemModel { - stepIDComposite := stepIDComposite(ExpoDetachID, ExpoDetachVersion) +// RunEASBuildStepListItem ... +func RunEASBuildStepListItem(workdir, platform string) bitriseModels.StepListItemModel { + var inputs []envmanModels.EnvironmentItemModel + if platform != "" { + inputs = append(inputs, envmanModels.EnvironmentItemModel{"platform": platform}) + } + if workdir != "" { + inputs = append(inputs, envmanModels.EnvironmentItemModel{"work_dir": workdir}) + } + stepIDComposite := stepIDComposite(RunEASBuildID, RunEASBuildVersion) return stepListItem(stepIDComposite, "", "", inputs...) } // YarnStepListItem ... -func YarnStepListItem(inputs ...envmanModels.EnvironmentItemModel) bitriseModels.StepListItemModel { +func YarnStepListItem(command, workdir string) bitriseModels.StepListItemModel { + var inputs []envmanModels.EnvironmentItemModel + if workdir != "" { + inputs = append(inputs, envmanModels.EnvironmentItemModel{"workdir": workdir}) + } + if command != "" { + inputs = append(inputs, envmanModels.EnvironmentItemModel{"command": command}) + } + stepIDComposite := stepIDComposite(YarnID, YarnVersion) return stepListItem(stepIDComposite, "", "", inputs...) } diff --git a/vendor/modules.txt b/vendor/modules.txt index 7523e6c6..617d2052 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -16,7 +16,7 @@ github.com/bitrise-io/bitrise/tools/filterwriter github.com/bitrise-io/bitrise/tools/timeoutcmd github.com/bitrise-io/bitrise/utils github.com/bitrise-io/bitrise/version -# github.com/bitrise-io/bitrise-init v0.0.0-20211201163403-80ed402ddf62 +# github.com/bitrise-io/bitrise-init v0.0.0-20220216103435-ee05a81e7191 ## explicit github.com/bitrise-io/bitrise-init/analytics github.com/bitrise-io/bitrise-init/errormapper