From c721a153904622281ea5a4bf1c586437f15c8dc1 Mon Sep 17 00:00:00 2001 From: Laszlo Pusok Date: Fri, 11 Feb 2022 13:40:20 +0100 Subject: [PATCH 1/9] Redo ios react-native options generation --- scanners/reactnative/plain.go | 276 ++++++++++++++-------------- scanners/reactnative/reactnative.go | 32 ++-- 2 files changed, 156 insertions(+), 152 deletions(-) diff --git a/scanners/reactnative/plain.go b/scanners/reactnative/plain.go index d0eb3faa..c88278e1 100644 --- a/scanners/reactnative/plain.go +++ b/scanners/reactnative/plain.go @@ -12,7 +12,6 @@ import ( "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" ) @@ -20,119 +19,124 @@ const ( defaultConfigName = "default-react-native-config" ) -// configName generates a config name based on the inputs. -func configName(hasAndroidProject, hasIosProject, hasTest bool) string { +type configDescriptor struct { + hasIOS, hasAndroid bool + hasTest 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" } + 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) + var ( + rootOption models.OptionNode + androidOptions, iosOptions *models.OptionNode + allDescriptors []configDescriptor + ) + + // iOS + generateIOSOptions := func(hasAndroid, hasTests bool) (*models.OptionNode, []configDescriptor) { + var descriptors []configDescriptor + + projectPathOption := models.NewOption(ios.ProjectPathInputTitle, ios.ProjectPathInputSummary, ios.ProjectPathInputEnvKey, models.TypeSelector) + for _, project := range scanner.iosProjects.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) - // android options - var androidOptions *models.OptionNode + 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, + ios: iosConfig, + } + descriptors = append(descriptors, descriptor) + + exportMethodOption.AddConfig(exportMethod, models.NewConfigOption(descriptor.configName(), nil)) + } + } + } + + return projectPathOption, descriptors + } + + // Android if len(scanner.androidProjects) > 0 { androidOptions = models.NewOption(android.ProjectLocationInputTitle, android.ProjectLocationInputSummary, android.ProjectLocationInputEnvKey, models.TypeSelector) for _, project := range scanner.androidProjects { warnings = append(warnings, project.Warnings...) - // This config option is removed when merging with ios config. This way no change is needed for the working options merging. - configOption := models.NewConfigOption("glue-only", nil) moduleOption := models.NewOption(android.ModuleInputTitle, android.ModuleInputSummary, android.ModuleInputEnvKey, models.TypeUserInput) variantOption := models.NewOption(android.VariantInputTitle, android.VariantInputSummary, android.VariantInputEnvKey, models.TypeOptionalUserInput) androidOptions.AddOption(project.RelPath, moduleOption) moduleOption.AddOption("app", variantOption) - variantOption.AddConfig("", configOption) - } - } - // 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 { - scanner.iosScanner.SuppressPodFileParseError = true - if detected, err := scanner.iosScanner.DetectPlatform(scanner.searchDir); err != nil { - return models.OptionNode{}, warnings, err - } else if detected { - options, warns, _, err := scanner.iosScanner.Options() - warnings = append(warnings, warns...) - if err != nil { - return models.OptionNode{}, warnings, err + if len(scanner.iosProjects.Projects) == 0 { + descriptor := configDescriptor{ + hasAndroid: true, + hasTest: scanner.hasTest, + } + allDescriptors = append(allDescriptors, descriptor) + + variantOption.AddConfig("", models.NewConfigOption(descriptor.configName(), nil)) + + continue } - iosOptions = &options + var descriptors []configDescriptor + iosOptions, descriptors = generateIOSOptions(true, scanner.hasTest) + allDescriptors = append(allDescriptors, descriptors...) + + variantOption.AddOption("", iosOptions) } + } else { + iosOptions, allDescriptors = generateIOSOptions(false, scanner.hasTest) } + scanner.configDescriptors = removeDuplicatedConfigDescriptors(allDescriptors) + 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() - } + if androidOptions == nil { + rootOption = *iosOptions + } else { 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()) - } - - configName := configName(androidOptions != nil, true, scanner.hasTest) - child.Config = configName - } - } - - 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) - } - - } - return rootOption, warnings, nil } @@ -167,60 +171,59 @@ func (scanner *Scanner) configs(isPrivateRepo bool) (models.BitriseConfigMap, er relPackageJSONDir = "" } - configBuilder := models.NewDefaultConfigBuilder() - - // ci - primaryDescription := primaryWorkflowNoTestsDescription - if scanner.hasTest { - primaryDescription = primaryWorkflowDescription - } - - configBuilder.SetWorkflowDescriptionTo(models.PrimaryWorkflowID, primaryDescription) - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultPrepareStepListV2(steps.PrepareListParams{ - ShouldIncludeCache: false, - ShouldIncludeActivateSSH: isPrivateRepo, - })...) - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, scanner.getTestSteps(relPackageJSONDir)...) + for _, descriptor := range scanner.configDescriptors { + configBuilder := models.NewDefaultConfigBuilder() - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultDeployStepListV2(false)...) + // ci + primaryDescription := primaryWorkflowNoTestsDescription + if descriptor.hasTest { + primaryDescription = primaryWorkflowDescription + } - // cd - configBuilder.SetWorkflowDescriptionTo(models.DeployWorkflowID, deployWorkflowDescription) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultPrepareStepListV2(steps.PrepareListParams{ - ShouldIncludeCache: false, - ShouldIncludeActivateSSH: isPrivateRepo, - })...) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, scanner.getTestSteps(relPackageJSONDir)...) - - // android cd - hasAndroidProject := len(scanner.androidProjects) > 0 - if hasAndroidProject { - projectLocationEnv := "$" + android.ProjectLocationInputEnvKey - - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.InstallMissingAndroidToolsStepListItem( - envmanModels.EnvironmentItemModel{android.GradlewPathInputKey: "$" + android.ProjectLocationInputEnvKey + "/gradlew"}, - )) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.AndroidBuildStepListItem( - envmanModels.EnvironmentItemModel{android.ProjectLocationInputKey: projectLocationEnv}, - )) - } + configBuilder.SetWorkflowDescriptionTo(models.PrimaryWorkflowID, primaryDescription) + configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultPrepareStepListV2(steps.PrepareListParams{ + ShouldIncludeCache: false, + ShouldIncludeActivateSSH: isPrivateRepo, + })...) + configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, scanner.getTestSteps(relPackageJSONDir)...) + + configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultDeployStepListV2(false)...) + + // cd + configBuilder.SetWorkflowDescriptionTo(models.DeployWorkflowID, deployWorkflowDescription) + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultPrepareStepListV2(steps.PrepareListParams{ + ShouldIncludeCache: false, + ShouldIncludeActivateSSH: isPrivateRepo, + })...) + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, scanner.getTestSteps(relPackageJSONDir)...) + + // android cd + if descriptor.hasAndroid { + projectLocationEnv := "$" + android.ProjectLocationInputEnvKey + + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.InstallMissingAndroidToolsStepListItem( + envmanModels.EnvironmentItemModel{android.GradlewPathInputKey: "$" + android.ProjectLocationInputEnvKey + "/gradlew"}, + )) + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.AndroidBuildStepListItem( + envmanModels.EnvironmentItemModel{android.ProjectLocationInputKey: projectLocationEnv}, + )) + } - // ios cd - if scanner.iosScanner != nil { - for _, descriptor := range scanner.iosScanner.ConfigDescriptors { - if descriptor.MissingSharedSchemes { + // ios cd + if descriptor.hasIOS { + if descriptor.ios.MissingSharedSchemes { configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.RecreateUserSchemesStepListItem( envmanModels.EnvironmentItemModel{ios.ProjectPathInputKey: "$" + ios.ProjectPathInputEnvKey}, )) } - if descriptor.HasPodfile { + if descriptor.ios.HasPodfile { configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.CocoapodsInstallStepListItem()) } - if descriptor.CarthageCommand != "" { + if descriptor.ios.CarthageCommand != "" { configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.CarthageStepListItem( - envmanModels.EnvironmentItemModel{ios.CarthageCommandInputKey: descriptor.CarthageCommand}, + envmanModels.EnvironmentItemModel{ios.CarthageCommandInputKey: descriptor.ios.CarthageCommand}, )) } @@ -231,23 +234,8 @@ func (scanner *Scanner) configs(isPrivateRepo bool) (models.BitriseConfigMap, er envmanModels.EnvironmentItemModel{ios.ConfigurationInputKey: "Release"}, envmanModels.EnvironmentItemModel{ios.AutomaticCodeSigningInputKey: ios.AutomaticCodeSigningInputAPIKeyValue}, )) - - 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(hasAndroidProject, true, scanner.hasTest) - configMap[configName] = string(data) } - } else { + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultDeployStepListV2(false)...) bitriseDataModel, err := configBuilder.Generate(scannerName) @@ -260,8 +248,7 @@ func (scanner *Scanner) configs(isPrivateRepo bool) (models.BitriseConfigMap, er return models.BitriseConfigMap{}, err } - configName := configName(hasAndroidProject, false, scanner.hasTest) - configMap[configName] = string(data) + configMap[descriptor.configName()] = string(data) } return configMap, nil @@ -349,3 +336,18 @@ func getTestSteps(workDir string, hasYarnLockFile, hasTest bool) []bitriseModels func (scanner *Scanner) getTestSteps(workDir string) []bitriseModels.StepListItemModel { return getTestSteps(workDir, scanner.hasYarnLockFile, scanner.hasTest) } + +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/scanners/reactnative/reactnative.go b/scanners/reactnative/reactnative.go index 7c0ddd7c..1e7a5f91 100644 --- a/scanners/reactnative/reactnative.go +++ b/scanners/reactnative/reactnative.go @@ -27,9 +27,11 @@ const ( // Scanner implements the project scanner for plain React Native and Expo based projects. type Scanner struct { searchDir string - iosScanner *ios.Scanner + iosProjects ios.DetectResult androidProjects []android.Project + configDescriptors []configDescriptor + hasTest bool hasYarnLockFile bool packageJSONPth string @@ -72,18 +74,20 @@ func isExpoBasedProject(packageJSONPth string) (bool, error) { return false, nil } -func hasNativeIOSProject(searchDir, projectDir string, iosScanner *ios.Scanner) (bool, error) { +func hasNativeIOSProject(searchDir, projectDir string, iosScanner *ios.Scanner) (bool, ios.DetectResult, error) { absProjectDir, err := pathutil.AbsPath(projectDir) if err != nil { - return false, err + return false, ios.DetectResult{}, err } iosDir := filepath.Join(absProjectDir, "ios") if exist, err := pathutil.IsDirExists(iosDir); err != nil || !exist { - return false, err + return false, ios.DetectResult{}, err } - return iosScanner.DetectPlatform(searchDir) + detected, err := iosScanner.DetectPlatform(searchDir) + + return detected, iosScanner.DetectResult, err } func hasNativeAndroidProject(searchDir, projectDir string, androidScanner *android.Scanner) (bool, []android.Project, error) { @@ -137,21 +141,20 @@ func (scanner *Scanner) DetectPlatform(searchDir string) (bool, error) { log.TPrintf("Project uses expo: %v", expoBased) - if scanner.iosScanner == nil { - scanner.iosScanner = ios.NewScanner() - scanner.iosScanner.ExcludeAppIcon = true - } - androidScanner := android.NewScanner() + var ( + iosScanner = ios.NewScanner() + androidScanner = android.NewScanner() + ) + iosScanner.ExcludeAppIcon = true + iosScanner.SuppressPodFileParseError = true projectDir := filepath.Dir(packageJSONPth) - isIOSProject, err := hasNativeIOSProject(searchDir, projectDir, scanner.iosScanner) + isIOSProject, iosProjects, err := hasNativeIOSProject(searchDir, projectDir, iosScanner) if err != nil { log.TWarnf("failed to check native iOS projects: %s", err) } log.TPrintf("Found native ios project: %v", isIOSProject) - if !isIOSProject { - scanner.iosScanner = nil - } + scanner.iosProjects = iosProjects isAndroidProject, androidProjects, err := hasNativeAndroidProject(searchDir, projectDir, androidScanner) if err != nil { @@ -161,7 +164,6 @@ func (scanner *Scanner) DetectPlatform(searchDir string) (bool, error) { scanner.androidProjects = androidProjects if isIOSProject || isAndroidProject { - // Treating the project as a plain React Native project packageFile = packageJSONPth break } From 25115676e04423f331d2fe519fdc0ed1b29900fc Mon Sep 17 00:00:00 2001 From: Laszlo Pusok Date: Fri, 11 Feb 2022 16:15:33 +0100 Subject: [PATCH 2/9] Extract ios options --- scanners/reactnative/plain.go | 74 +++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 34 deletions(-) diff --git a/scanners/reactnative/plain.go b/scanners/reactnative/plain.go index c88278e1..bad2c436 100644 --- a/scanners/reactnative/plain.go +++ b/scanners/reactnative/plain.go @@ -49,48 +49,50 @@ func (d configDescriptor) configName() string { 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{} +func generateIOSOptions(result ios.DetectResult, hasAndroid, hasTests bool) (*models.OptionNode, models.Warnings, []configDescriptor) { var ( - rootOption models.OptionNode - androidOptions, iosOptions *models.OptionNode - allDescriptors []configDescriptor + warnings models.Warnings + descriptors []configDescriptor ) - // iOS - generateIOSOptions := func(hasAndroid, hasTests bool) (*models.OptionNode, []configDescriptor) { - var descriptors []configDescriptor + projectPathOption := models.NewOption(ios.ProjectPathInputTitle, ios.ProjectPathInputSummary, ios.ProjectPathInputEnvKey, models.TypeSelector) + for _, project := range result.Projects { + warnings = append(warnings, project.Warnings...) - projectPathOption := models.NewOption(ios.ProjectPathInputTitle, ios.ProjectPathInputSummary, ios.ProjectPathInputEnvKey, models.TypeSelector) - for _, project := range scanner.iosProjects.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) + schemeOption := models.NewOption(ios.SchemeInputTitle, ios.SchemeInputSummary, ios.SchemeInputEnvKey, models.TypeSelector) + projectPathOption.AddOption(project.RelPath, schemeOption) - 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, - ios: iosConfig, - } - descriptors = append(descriptors, descriptor) + for _, scheme := range project.Schemes { + exportMethodOption := models.NewOption(ios.DistributionMethodInputTitle, ios.DistributionMethodInputSummary, ios.DistributionMethodEnvKey, models.TypeSelector) + schemeOption.AddOption(scheme.Name, exportMethodOption) - exportMethodOption.AddConfig(exportMethod, models.NewConfigOption(descriptor.configName(), nil)) + 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, + ios: iosConfig, } + descriptors = append(descriptors, descriptor) + + exportMethodOption.AddConfig(exportMethod, models.NewConfigOption(descriptor.configName(), nil)) } } - - return projectPathOption, descriptors } + return projectPathOption, warnings, descriptors +} + +// options implements ScannerInterface.Options function for plain React Native projects. +func (scanner *Scanner) options() (models.OptionNode, models.Warnings, error) { + var ( + rootOption models.OptionNode + androidOptions, iosOptions *models.OptionNode + allDescriptors []configDescriptor + ) + warnings := models.Warnings{} + // Android if len(scanner.androidProjects) > 0 { androidOptions = models.NewOption(android.ProjectLocationInputTitle, android.ProjectLocationInputSummary, android.ProjectLocationInputEnvKey, models.TypeSelector) @@ -115,14 +117,18 @@ func (scanner *Scanner) options() (models.OptionNode, models.Warnings, error) { continue } - var descriptors []configDescriptor - iosOptions, descriptors = generateIOSOptions(true, scanner.hasTest) + options, iosWarnings, descriptors := generateIOSOptions(scanner.iosProjects, true, scanner.hasTest) + iosOptions = options + warnings = append(warnings, iosWarnings...) allDescriptors = append(allDescriptors, descriptors...) variantOption.AddOption("", iosOptions) } } else { - iosOptions, allDescriptors = generateIOSOptions(false, scanner.hasTest) + options, iosWarnings, descriptors := generateIOSOptions(scanner.iosProjects, false, scanner.hasTest) + iosOptions = options + warnings = append(warnings, iosWarnings...) + allDescriptors = descriptors } scanner.configDescriptors = removeDuplicatedConfigDescriptors(allDescriptors) From fbf7659837b182baf54fdb0987ca3ff6eb274162 Mon Sep 17 00:00:00 2001 From: Laszlo Pusok Date: Fri, 11 Feb 2022 16:34:11 +0100 Subject: [PATCH 3/9] Added react e2e test for project with multiple schemes --- _tests/integration/reactnative_test.go | 189 +++++++++++++++++++++++++ 1 file changed, 189 insertions(+) diff --git a/_tests/integration/reactnative_test.go b/_tests/integration/reactnative_test.go index a3f92ce4..8859132e 100644 --- a/_tests/integration/reactnative_test.go +++ b/_tests/integration/reactnative_test.go @@ -45,6 +45,21 @@ func TestReactNative(t *testing.T) { const simpleSample = "https://github.com/bitrise-samples/sample-apps-react-native-ios-and-android.git" + t.Log("joplin") + { + sampleAppDir := filepath.Join(tmpDir, "joplin") + gitClone(t, sampleAppDir, "https://github.com/bitrise-io/joplin.git") + + cmd := command.New(binPath(), "--ci", "config", "--dir", sampleAppDir, "--output-dir", sampleAppDir) + out, err := cmd.RunAndReturnTrimmedCombinedOutput() + require.NoError(t, err, out) + scanResultPth := filepath.Join(sampleAppDir, "result.yml") + result, err := fileutil.ReadStringFromFile(scanResultPth) + require.NoError(t, err) + + validateConfigExpectation(t, "joplin", strings.TrimSpace(sampleAppsReactNativeJoplinResultYML), strings.TrimSpace(result)) + } + t.Log("sample-apps-react-native-ios-and-android") { sampleAppDir := filepath.Join(tmpDir, "sample-apps-react-native-ios-and-android") @@ -762,3 +777,177 @@ warnings: warnings_with_recommendations: react-native: [] `, sampleAppsReactNativeIosAndAndroidYarnVersions...) + +var sampleAppsReactNativeJoplinVersions = []interface{}{ + models.FormatVersion, + + steps.ActivateSSHKeyVersion, + steps.GitCloneVersion, + steps.NpmVersion, + steps.InstallMissingAndroidToolsVersion, + steps.AndroidBuildVersion, + steps.CocoapodsInstallVersion, + steps.XcodeArchiveVersion, + steps.DeployToBitriseIoVersion, + + steps.ActivateSSHKeyVersion, + steps.GitCloneVersion, + steps.NpmVersion, + steps.DeployToBitriseIoVersion, +} + +var sampleAppsReactNativeJoplinResultYML = fmt.Sprintf(`options: + react-native: + title: The root directory of an Android project + summary: The root directory of your Android project, stored as an Environment + Variable. In your Workflows, you can specify paths relative to this path. You + can change this at any time. + env_key: PROJECT_LOCATION + type: selector + value_map: + packages/app-mobile/android: + title: Module + summary: Modules provide a container for your Android project's source code, + resource files, and app level settings, such as the module-level build file + and Android manifest file. Each module can be independently built, tested, + and debugged. You can add new modules to your Bitrise builds at any time. + env_key: MODULE + type: user_input + value_map: + app: + title: Variant + summary: Your Android build variant. You can add variants at any time, + as well as further configure your existing variants later. + env_key: VARIANT + type: user_input_optional + value_map: + "": + title: Project or Workspace path + summary: The location of your Xcode project or Xcode workspace files, + stored as an Environment Variable. In your Workflows, you can specify + paths relative to this path. + env_key: BITRISE_PROJECT_PATH + type: selector + value_map: + packages/app-mobile/ios/Joplin.xcworkspace: + title: Scheme name + summary: An Xcode scheme defines a collection of targets to build, + a configuration to use when building, and a collection of tests + to execute. Only shared schemes are detected automatically but + you can use any scheme as a target on Bitrise. You can change + the scheme at any time in your Env Vars. + env_key: BITRISE_SCHEME + type: selector + value_map: + Joplin: + title: Distribution method + summary: The export method used to create an .ipa file in + your builds, stored as an Environment Variable. You can + change this at any time, or even create several .ipa files + with different export methods in the same build. + env_key: BITRISE_DISTRIBUTION_METHOD + type: selector + value_map: + ad-hoc: + config: react-native-android-ios-pod-config + app-store: + config: react-native-android-ios-pod-config + development: + config: react-native-android-ios-pod-config + enterprise: + config: react-native-android-ios-pod-config + Joplin-tvOS: + title: Distribution method + summary: The export method used to create an .ipa file in + your builds, stored as an Environment Variable. You can + change this at any time, or even create several .ipa files + with different export methods in the same build. + env_key: BITRISE_DISTRIBUTION_METHOD + type: selector + value_map: + ad-hoc: + config: react-native-android-ios-pod-config + app-store: + config: react-native-android-ios-pod-config + development: + config: react-native-android-ios-pod-config + enterprise: + config: react-native-android-ios-pod-config + ShareExtension: + title: Distribution method + summary: The export method used to create an .ipa file in + your builds, stored as an Environment Variable. You can + change this at any time, or even create several .ipa files + with different export methods in the same build. + env_key: BITRISE_DISTRIBUTION_METHOD + type: selector + value_map: + ad-hoc: + config: react-native-android-ios-pod-config + app-store: + config: react-native-android-ios-pod-config + development: + config: react-native-android-ios-pod-config + enterprise: + config: react-native-android-ios-pod-config +configs: + react-native: + react-native-android-ios-pod-config: | + format_version: "%s" + default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git + project_type: react-native + trigger_map: + - push_branch: '*' + workflow: primary + - pull_request_source_branch: '*' + workflow: primary + workflows: + deploy: + description: | + 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). + steps: + - activate-ssh-key@%s: {} + - git-clone@%s: {} + - npm@%s: + inputs: + - workdir: packages/app-mobile + - command: install + - install-missing-android-tools@%s: + inputs: + - gradlew_path: $PROJECT_LOCATION/gradlew + - android-build@%s: + inputs: + - project_location: $PROJECT_LOCATION + - cocoapods-install@%s: {} + - xcode-archive@%s: + inputs: + - project_path: $BITRISE_PROJECT_PATH + - scheme: $BITRISE_SCHEME + - distribution_method: $BITRISE_DISTRIBUTION_METHOD + - configuration: Release + - automatic_code_signing: api-key + - deploy-to-bitrise-io@%s: {} + primary: + description: | + 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). + steps: + - activate-ssh-key@%s: {} + - git-clone@%s: {} + - npm@%s: + inputs: + - workdir: packages/app-mobile + - command: install + - deploy-to-bitrise-io@%s: {} +warnings: + react-native: [] +warnings_with_recommendations: + react-native: [] +`, sampleAppsReactNativeJoplinVersions...) From 66c2678738e99ca1d2872b09be9ebb9cd7887e07 Mon Sep 17 00:00:00 2001 From: Laszlo Pusok Date: Fri, 11 Feb 2022 20:57:22 +0100 Subject: [PATCH 4/9] Simplify react-native options --- scanners/reactnative/plain.go | 31 ++++++++++------------------- scanners/reactnative/reactnative.go | 2 +- 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/scanners/reactnative/plain.go b/scanners/reactnative/plain.go index bad2c436..39d54b3f 100644 --- a/scanners/reactnative/plain.go +++ b/scanners/reactnative/plain.go @@ -1,7 +1,6 @@ package reactnative import ( - "errors" "fmt" "path/filepath" @@ -85,17 +84,18 @@ func generateIOSOptions(result ios.DetectResult, hasAndroid, hasTests bool) (*mo } // options implements ScannerInterface.Options function for plain React Native projects. -func (scanner *Scanner) options() (models.OptionNode, models.Warnings, error) { +func (scanner *Scanner) options() (models.OptionNode, models.Warnings) { var ( - rootOption models.OptionNode - androidOptions, iosOptions *models.OptionNode - allDescriptors []configDescriptor + rootOption models.OptionNode + allDescriptors []configDescriptor + warnings = models.Warnings{} ) - warnings := models.Warnings{} // Android if len(scanner.androidProjects) > 0 { - androidOptions = models.NewOption(android.ProjectLocationInputTitle, android.ProjectLocationInputSummary, android.ProjectLocationInputEnvKey, models.TypeSelector) + androidOptions := models.NewOption(android.ProjectLocationInputTitle, android.ProjectLocationInputSummary, android.ProjectLocationInputEnvKey, models.TypeSelector) + rootOption = *androidOptions + for _, project := range scanner.androidProjects { warnings = append(warnings, project.Warnings...) @@ -117,8 +117,7 @@ func (scanner *Scanner) options() (models.OptionNode, models.Warnings, error) { continue } - options, iosWarnings, descriptors := generateIOSOptions(scanner.iosProjects, true, scanner.hasTest) - iosOptions = options + iosOptions, iosWarnings, descriptors := generateIOSOptions(scanner.iosProjects, true, scanner.hasTest) warnings = append(warnings, iosWarnings...) allDescriptors = append(allDescriptors, descriptors...) @@ -126,24 +125,14 @@ func (scanner *Scanner) options() (models.OptionNode, models.Warnings, error) { } } else { options, iosWarnings, descriptors := generateIOSOptions(scanner.iosProjects, false, scanner.hasTest) - iosOptions = options + rootOption = *options warnings = append(warnings, iosWarnings...) allDescriptors = descriptors } scanner.configDescriptors = removeDuplicatedConfigDescriptors(allDescriptors) - if androidOptions == nil && iosOptions == nil { - return models.OptionNode{}, warnings, errors.New("no ios nor android project detected") - } - - if androidOptions == nil { - rootOption = *iosOptions - } else { - rootOption = *androidOptions - } - - return rootOption, warnings, nil + return rootOption, warnings } // defaultOptions implements ScannerInterface.DefaultOptions function for plain React Native projects. diff --git a/scanners/reactnative/reactnative.go b/scanners/reactnative/reactnative.go index 1e7a5f91..68fc0f58 100644 --- a/scanners/reactnative/reactnative.go +++ b/scanners/reactnative/reactnative.go @@ -200,7 +200,7 @@ func (scanner *Scanner) Options() (options models.OptionNode, warnings models.Wa if scanner.isExpoBased { options, warnings, err = scanner.expoOptions() } else { - options, warnings, err = scanner.options() + options, warnings = scanner.options() } return From 8a273c54a96d09d832cfc36719a8c1dd8fe11745 Mon Sep 17 00:00:00 2001 From: Laszlo Pusok Date: Sat, 12 Feb 2022 00:16:41 +0100 Subject: [PATCH 5/9] Adds support for multiple react-native projects Multiple plrojects working Use absolute path, fixes for multiple package.jsons Fix missing config Fix for native projects relative path Fix for yarn lock --- scanners/reactnative/expo.go | 34 ++--- scanners/reactnative/plain.go | 61 ++++----- scanners/reactnative/reactnative.go | 190 ++++++++++++++++++---------- scanners/reactnative/utility.go | 2 +- 4 files changed, 159 insertions(+), 128 deletions(-) diff --git a/scanners/reactnative/expo.go b/scanners/reactnative/expo.go index 8288486f..8ad08c01 100644 --- a/scanners/reactnative/expo.go +++ b/scanners/reactnative/expo.go @@ -1,13 +1,8 @@ package reactnative import ( - "fmt" - "path/filepath" - "github.com/bitrise-io/bitrise-init/models" "github.com/bitrise-io/bitrise-init/steps" - "github.com/bitrise-io/bitrise-init/utility" - "github.com/bitrise-io/go-utils/log" "gopkg.in/yaml.v2" ) @@ -27,7 +22,7 @@ const ( ) // expoOptions implements ScannerInterface.Options function for Expo based React Native projects. -func (scanner *Scanner) expoOptions() (models.OptionNode, models.Warnings, error) { +func (scanner *Scanner) expoOptions() (models.OptionNode, models.Warnings) { platformOption := models.NewOption(expoPlatformInputTitle, expoPlatformInputSummary, expoPlatformInputEnvKey, models.TypeSelector) configOption := models.NewConfigOption(expoConfigName, nil) @@ -35,28 +30,17 @@ func (scanner *Scanner) expoOptions() (models.OptionNode, models.Warnings, error platformOption.AddConfig(platform, configOption) } - return *platformOption, nil, nil + return *platformOption, nil } // expoConfigs implements ScannerInterface.Configs function for Expo based React Native projects. -func (scanner *Scanner) expoConfigs(isPrivateRepo bool) (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 == "." { - // package.json placed in the search dir, no need to change-dir in the workflows - relPackageJSONDir = "" - } - log.TPrintf("Working directory: %v", relPackageJSONDir) - + testSteps := getTestSteps(project.projectRelDir, project.hasYarnLockFile, project.hasTest) // primary workflow primaryDescription := expoPrimaryWorkflowDescription - if !scanner.hasTest { + if !project.hasTest { primaryDescription = expoPrimaryWorkflowNoTestsDescription } @@ -66,13 +50,13 @@ func (scanner *Scanner) expoConfigs(isPrivateRepo bool) (models.BitriseConfigMap ShouldIncludeCache: false, ShouldIncludeActivateSSH: isPrivateRepo, })...) - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, scanner.getTestSteps(relPackageJSONDir)...) + configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, testSteps...) configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultDeployStepListV2(false)...) // deploy workflow deployDescription := expoDeployWorkflowDescription - if !scanner.hasTest { + if !project.hasTest { deployDescription = expoDeployWorkflowNoTestsDescription } @@ -81,8 +65,8 @@ func (scanner *Scanner) expoConfigs(isPrivateRepo bool) (models.BitriseConfigMap ShouldIncludeCache: false, ShouldIncludeActivateSSH: isPrivateRepo, })...) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, scanner.getTestSteps(relPackageJSONDir)...) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.RunEASBuildStepListItem(relPackageJSONDir, "$"+expoPlatformInputEnvKey)) + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, testSteps...) + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.RunEASBuildStepListItem(project.projectRelDir, "$"+expoPlatformInputEnvKey)) configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultDeployStepList(false)...) // generate bitrise.yml diff --git a/scanners/reactnative/plain.go b/scanners/reactnative/plain.go index 39d54b3f..89adb72a 100644 --- a/scanners/reactnative/plain.go +++ b/scanners/reactnative/plain.go @@ -2,13 +2,11 @@ package reactnative import ( "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" "gopkg.in/yaml.v2" @@ -21,6 +19,7 @@ const ( type configDescriptor struct { hasIOS, hasAndroid bool hasTest bool + hasYarnLockFile bool ios ios.ConfigDescriptor } @@ -44,11 +43,14 @@ func (d configDescriptor) configName() string { if d.hasTest { name += "-test" } + if d.hasYarnLockFile { + name += "-yarn" + } return name + "-config" } -func generateIOSOptions(result ios.DetectResult, hasAndroid, hasTests bool) (*models.OptionNode, models.Warnings, []configDescriptor) { +func generateIOSOptions(result ios.DetectResult, hasAndroid, hasTests, hasYarnLockFile bool) (*models.OptionNode, models.Warnings, []configDescriptor) { var ( warnings models.Warnings descriptors []configDescriptor @@ -68,10 +70,11 @@ func generateIOSOptions(result ios.DetectResult, hasAndroid, hasTests bool) (*mo 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, - ios: iosConfig, + hasIOS: true, + hasAndroid: hasAndroid, + hasTest: hasTests, + hasYarnLockFile: hasYarnLockFile, + ios: iosConfig, } descriptors = append(descriptors, descriptor) @@ -84,7 +87,7 @@ func generateIOSOptions(result ios.DetectResult, hasAndroid, hasTests bool) (*mo } // options implements ScannerInterface.Options function for plain React Native projects. -func (scanner *Scanner) options() (models.OptionNode, models.Warnings) { +func (scanner *Scanner) options(project project) (models.OptionNode, models.Warnings) { var ( rootOption models.OptionNode allDescriptors []configDescriptor @@ -92,23 +95,24 @@ func (scanner *Scanner) options() (models.OptionNode, models.Warnings) { ) // Android - if len(scanner.androidProjects) > 0 { + if len(project.androidProjects) > 0 { androidOptions := models.NewOption(android.ProjectLocationInputTitle, android.ProjectLocationInputSummary, android.ProjectLocationInputEnvKey, models.TypeSelector) rootOption = *androidOptions - for _, project := range scanner.androidProjects { - warnings = append(warnings, project.Warnings...) + 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(project.RelPath, moduleOption) + androidOptions.AddOption(androidProject.RelPath, moduleOption) moduleOption.AddOption("app", variantOption) - if len(scanner.iosProjects.Projects) == 0 { + if len(project.iosProjects.Projects) == 0 { descriptor := configDescriptor{ - hasAndroid: true, - hasTest: scanner.hasTest, + hasAndroid: true, + hasTest: project.hasTest, + hasYarnLockFile: project.hasYarnLockFile, } allDescriptors = append(allDescriptors, descriptor) @@ -117,20 +121,20 @@ func (scanner *Scanner) options() (models.OptionNode, models.Warnings) { continue } - iosOptions, iosWarnings, descriptors := generateIOSOptions(scanner.iosProjects, true, scanner.hasTest) + iosOptions, iosWarnings, descriptors := generateIOSOptions(project.iosProjects, true, project.hasTest, project.hasYarnLockFile) warnings = append(warnings, iosWarnings...) allDescriptors = append(allDescriptors, descriptors...) variantOption.AddOption("", iosOptions) } } else { - options, iosWarnings, descriptors := generateIOSOptions(scanner.iosProjects, false, scanner.hasTest) + options, iosWarnings, descriptors := generateIOSOptions(project.iosProjects, false, project.hasTest, project.hasYarnLockFile) rootOption = *options warnings = append(warnings, iosWarnings...) - allDescriptors = descriptors + allDescriptors = append(allDescriptors, descriptors...) } - scanner.configDescriptors = removeDuplicatedConfigDescriptors(allDescriptors) + scanner.configDescriptors = removeDuplicatedConfigDescriptors(append(scanner.configDescriptors, allDescriptors...)) return rootOption, warnings } @@ -156,19 +160,14 @@ func (scanner *Scanner) defaultOptions() models.OptionNode { 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 = "" + if len(scanner.configDescriptors) == 0 { + return models.BitriseConfigMap{}, fmt.Errorf("invalid state, no config descriptors found") } for _, descriptor := range scanner.configDescriptors { configBuilder := models.NewDefaultConfigBuilder() + testSteps := getTestSteps("$"+projectDirInputEnvKey, descriptor.hasYarnLockFile, descriptor.hasTest) // ci primaryDescription := primaryWorkflowNoTestsDescription if descriptor.hasTest { @@ -180,7 +179,7 @@ func (scanner *Scanner) configs(isPrivateRepo bool) (models.BitriseConfigMap, er ShouldIncludeCache: false, ShouldIncludeActivateSSH: isPrivateRepo, })...) - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, scanner.getTestSteps(relPackageJSONDir)...) + configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, testSteps...) configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultDeployStepListV2(false)...) @@ -190,7 +189,7 @@ func (scanner *Scanner) configs(isPrivateRepo bool) (models.BitriseConfigMap, er ShouldIncludeCache: false, ShouldIncludeActivateSSH: isPrivateRepo, })...) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, scanner.getTestSteps(relPackageJSONDir)...) + configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, testSteps...) // android cd if descriptor.hasAndroid { @@ -328,10 +327,6 @@ func getTestSteps(workDir string, hasYarnLockFile, hasTest bool) []bitriseModels return testSteps } -func (scanner *Scanner) getTestSteps(workDir string) []bitriseModels.StepListItemModel { - return getTestSteps(workDir, scanner.hasYarnLockFile, scanner.hasTest) -} - func removeDuplicatedConfigDescriptors(configDescriptors []configDescriptor) []configDescriptor { descritorNameMap := map[string]configDescriptor{} for _, descriptor := range configDescriptors { diff --git a/scanners/reactnative/reactnative.go b/scanners/reactnative/reactnative.go index 68fc0f58..fd869c8a 100644 --- a/scanners/reactnative/reactnative.go +++ b/scanners/reactnative/reactnative.go @@ -15,28 +15,31 @@ import ( const scannerName = "react-native" const ( - // workDirInputKey is a key of the working directory step input. - workDirInputKey = "workdir" -) + projectDirInputTitle = "React-native/Expo project directory" + projectDirInputSummary = "Path of the directory containing the project's `package.json` and/or app configuration file (`app.json`, `app.config.js`, `app.config.ts`)." + projectDirInputEnvKey = "WORKDIR" -const ( 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 - iosProjects ios.DetectResult - androidProjects []android.Project - - configDescriptors []configDescriptor +type project struct { + projectRelDir string hasTest bool hasYarnLockFile bool - packageJSONPth string + // 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. @@ -74,7 +77,7 @@ func isExpoBasedProject(packageJSONPth string) (bool, error) { return false, nil } -func hasNativeIOSProject(searchDir, projectDir string, iosScanner *ios.Scanner) (bool, ios.DetectResult, error) { +func hasNativeIOSProject(projectDir string, iosScanner *ios.Scanner) (bool, ios.DetectResult, error) { absProjectDir, err := pathutil.AbsPath(projectDir) if err != nil { return false, ios.DetectResult{}, err @@ -85,12 +88,12 @@ func hasNativeIOSProject(searchDir, projectDir string, iosScanner *ios.Scanner) return false, ios.DetectResult{}, err } - detected, err := iosScanner.DetectPlatform(searchDir) + detected, err := iosScanner.DetectPlatform(projectDir) return detected, iosScanner.DetectResult, err } -func hasNativeAndroidProject(searchDir, projectDir string, androidScanner *android.Scanner) (bool, []android.Project, error) { +func hasNativeAndroidProject(projectDir string, androidScanner *android.Scanner) (bool, []android.Project, error) { absProjectDir, err := pathutil.AbsPath(projectDir) if err != nil { return false, nil, err @@ -101,18 +104,57 @@ func hasNativeAndroidProject(searchDir, projectDir string, androidScanner *andro return false, nil, err } - if detected, err := androidScanner.DetectPlatform(searchDir); err != nil || !detected { + if detected, err := androidScanner.DetectPlatform(projectDir); err != nil || !detected { return false, nil, err } return true, androidScanner.Projects, nil } +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 { + log.TWarnf("failed to check native iOS projects: %s", err) + } + log.TPrintf("Found native ios project: %v", isIOSProject) + + 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) + + // 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 + + log.TPrintf("iosProjects %+v", iosProjects) + + 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 { @@ -120,87 +162,97 @@ func (scanner *Scanner) DetectPlatform(searchDir string) (bool, error) { } log.TPrintf("%d package.json file detected", len(packageJSONPths)) - log.TPrintf("Filter relevant package.json files") - - isExpoBased := false - 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) - expoBased, err := isExpoBasedProject(packageJSONPth) + isExpoBased, err := isExpoBasedProject(packageJSONPth) if err != nil { log.TWarnf("failed to determine if project is Expo based: %s", err) - } else if expoBased { - log.TPrintf("Project uses expo: %v", expoBased) - isExpoBased = true - packageFile = packageJSONPth - // TODO: This break drops other package.json files - break } - log.TPrintf("Project uses expo: %v", expoBased) + log.TPrintf("Project uses expo: %v", isExpoBased) + + // 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 relPackageJSONDir == "." { + // package.json placed in the search dir, no need to change-dir in the workflows + relPackageJSONDir = "" + } var ( - iosScanner = ios.NewScanner() - androidScanner = android.NewScanner() + iosProjects ios.DetectResult + androidProjects []android.Project ) - iosScanner.ExcludeAppIcon = true - iosScanner.SuppressPodFileParseError = true + if !isExpoBased { + iosProjects, androidProjects = getNativeProjects(packageJSONPth, relPackageJSONDir) + if len(iosProjects.Projects) == 0 && len(androidProjects) == 0 { + continue + } + } - projectDir := filepath.Dir(packageJSONPth) - isIOSProject, iosProjects, err := hasNativeIOSProject(searchDir, projectDir, iosScanner) + // determine Js dependency manager + hasYarnLockFile, err := containsYarnLock(filepath.Dir(packageJSONPth)) if err != nil { - log.TWarnf("failed to check native iOS projects: %s", err) + return false, err } - log.TPrintf("Found native ios project: %v", isIOSProject) - scanner.iosProjects = iosProjects + log.TPrintf("Js dependency manager for %s is yarn: %t", packageJSONPth, hasYarnLockFile) - isAndroidProject, androidProjects, err := hasNativeAndroidProject(searchDir, projectDir, androidScanner) + packages, err := utility.ParsePackagesJSON(packageJSONPth) if err != nil { - log.TWarnf("failed to check native Android projects: %s", err) + return false, err } - log.TPrintf("Found native android project: %v", isAndroidProject) - scanner.androidProjects = androidProjects - if isIOSProject || isAndroidProject { - 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.isExpoBased = isExpoBased - 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) { +func (scanner *Scanner) Options() (options models.OptionNode, allWarnings models.Warnings, icons models.Icons, err error) { if scanner.isExpoBased { - options, warnings, err = scanner.expoOptions() + options, allWarnings = scanner.expoOptions() } else { - options, warnings = 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 @@ -209,7 +261,7 @@ func (scanner *Scanner) Options() (options models.OptionNode, warnings models.Wa // Configs implements ScannerInterface.Configs function. func (scanner *Scanner) Configs(isPrivateRepo bool) (models.BitriseConfigMap, error) { if scanner.isExpoBased { - return scanner.expoConfigs(isPrivateRepo) + return scanner.expoConfigs(scanner.projects[0], isPrivateRepo) } return scanner.configs(isPrivateRepo) diff --git a/scanners/reactnative/utility.go b/scanners/reactnative/utility.go index a12716c3..2846525e 100644 --- a/scanners/reactnative/utility.go +++ b/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 } From 84a00e7e010da7c767e61a317dbc10f626cf03f6 Mon Sep 17 00:00:00 2001 From: Laszlo Pusok Date: Mon, 14 Feb 2022 12:31:57 +0100 Subject: [PATCH 6/9] Empty workdir fixed for RN, tests updated --- _tests/integration/reactnative_test.go | 774 ++++++++++++++----------- scanners/reactnative/expo.go | 5 + scanners/reactnative/plain.go | 7 +- scanners/reactnative/reactnative.go | 6 +- 4 files changed, 431 insertions(+), 361 deletions(-) diff --git a/_tests/integration/reactnative_test.go b/_tests/integration/reactnative_test.go index 8859132e..5aeb2aaf 100644 --- a/_tests/integration/reactnative_test.go +++ b/_tests/integration/reactnative_test.go @@ -162,81 +162,90 @@ var sampleAppsReactNativeSubdirVersions = []interface{}{ var sampleAppsReactNativeSubdirResultYML = fmt.Sprintf(`options: react-native: - title: The root directory of an Android project - summary: The root directory of your Android project, stored as an Environment - Variable. In your Workflows, you can specify paths relative to this path. You - can change this at any time. - env_key: PROJECT_LOCATION + title: React-native/Expo project directory + summary: Path of the directory containing the project's `+"`package.json`"+` file. + env_key: WORKDIR type: selector value_map: - project/android: - title: Module - summary: Modules provide a container for your Android project's source code, - resource files, and app level settings, such as the module-level build file - and Android manifest file. Each module can be independently built, tested, - and debugged. You can add new modules to your Bitrise builds at any time. - env_key: MODULE - type: user_input + project: + title: The root directory of an Android project + summary: The root directory of your Android project, stored as an Environment + Variable. In your Workflows, you can specify paths relative to this path. + You can change this at any time. + env_key: PROJECT_LOCATION + type: selector value_map: - app: - title: Variant - summary: Your Android build variant. You can add variants at any time, - as well as further configure your existing variants later. - env_key: VARIANT - type: user_input_optional + project/android: + title: Module + summary: Modules provide a container for your Android project's source + code, resource files, and app level settings, such as the module-level + build file and Android manifest file. Each module can be independently + built, tested, and debugged. You can add new modules to your Bitrise + builds at any time. + env_key: MODULE + type: user_input value_map: - "": - title: Project or Workspace path - summary: The location of your Xcode project or Xcode workspace files, - stored as an Environment Variable. In your Workflows, you can specify - paths relative to this path. - env_key: BITRISE_PROJECT_PATH - type: selector + app: + title: Variant + summary: Your Android build variant. You can add variants at any time, + as well as further configure your existing variants later. + env_key: VARIANT + type: user_input_optional value_map: - project/ios/SampleAppsReactNativeAndroid.xcodeproj: - title: Scheme name - summary: An Xcode scheme defines a collection of targets to build, - a configuration to use when building, and a collection of tests - to execute. Only shared schemes are detected automatically but - you can use any scheme as a target on Bitrise. You can change - the scheme at any time in your Env Vars. - env_key: BITRISE_SCHEME + Debug: + title: Project or Workspace path + summary: The location of your Xcode project or Xcode workspace + files, stored as an Environment Variable. In your Workflows, + you can specify paths relative to this path. + env_key: BITRISE_PROJECT_PATH type: selector value_map: - SampleAppsReactNativeAndroid: - title: Distribution method - summary: The export method used to create an .ipa file in - your builds, stored as an Environment Variable. You can - change this at any time, or even create several .ipa files - with different export methods in the same build. - env_key: BITRISE_DISTRIBUTION_METHOD + project/ios/SampleAppsReactNativeAndroid.xcodeproj: + title: Scheme name + summary: An Xcode scheme defines a collection of targets to + build, a configuration to use when building, and a collection + of tests to execute. Only shared schemes are detected automatically + but you can use any scheme as a target on Bitrise. You can + change the scheme at any time in your Env Vars. + env_key: BITRISE_SCHEME type: selector value_map: - ad-hoc: - config: react-native-android-ios-test-config - app-store: - config: react-native-android-ios-test-config - development: - config: react-native-android-ios-test-config - enterprise: - config: react-native-android-ios-test-config - SampleAppsReactNativeAndroid-tvOS: - title: Distribution method - summary: The export method used to create an .ipa file in - your builds, stored as an Environment Variable. You can - change this at any time, or even create several .ipa files - with different export methods in the same build. - env_key: BITRISE_DISTRIBUTION_METHOD - type: selector - value_map: - ad-hoc: - config: react-native-android-ios-test-config - app-store: - config: react-native-android-ios-test-config - development: - config: react-native-android-ios-test-config - enterprise: - config: react-native-android-ios-test-config + SampleAppsReactNativeAndroid: + title: Distribution method + summary: The export method used to create an .ipa file + in your builds, stored as an Environment Variable. You + can change this at any time, or even create several + .ipa files with different export methods in the same + build. + env_key: BITRISE_DISTRIBUTION_METHOD + type: selector + value_map: + ad-hoc: + config: react-native-android-ios-test-config + app-store: + config: react-native-android-ios-test-config + development: + config: react-native-android-ios-test-config + enterprise: + config: react-native-android-ios-test-config + SampleAppsReactNativeAndroid-tvOS: + title: Distribution method + summary: The export method used to create an .ipa file + in your builds, stored as an Environment Variable. You + can change this at any time, or even create several + .ipa files with different export methods in the same + build. + env_key: BITRISE_DISTRIBUTION_METHOD + type: selector + value_map: + ad-hoc: + config: react-native-android-ios-test-config + app-store: + config: react-native-android-ios-test-config + development: + config: react-native-android-ios-test-config + enterprise: + config: react-native-android-ios-test-config configs: react-native: react-native-android-ios-test-config: | @@ -261,11 +270,11 @@ configs: - git-clone@%s: {} - npm@%s: inputs: - - workdir: project + - workdir: $WORKDIR - command: install - npm@%s: inputs: - - workdir: project + - workdir: $WORKDIR - command: test - install-missing-android-tools@%s: inputs: @@ -273,6 +282,8 @@ configs: - android-build@%s: inputs: - project_location: $PROJECT_LOCATION + - module: $MODULE + - variant: $VARIANT - xcode-archive@%s: inputs: - project_path: $BITRISE_PROJECT_PATH @@ -292,11 +303,11 @@ configs: - git-clone@%s: {} - npm@%s: inputs: - - workdir: project + - workdir: $WORKDIR - command: install - npm@%s: inputs: - - workdir: project + - workdir: $WORKDIR - command: test - deploy-to-bitrise-io@%s: {} warnings: @@ -326,81 +337,90 @@ var sampleAppsReactNativeIosAndAndroidVersions = []interface{}{ var sampleAppsReactNativeIosAndAndroidResultYML = fmt.Sprintf(`options: react-native: - title: The root directory of an Android project - summary: The root directory of your Android project, stored as an Environment - Variable. In your Workflows, you can specify paths relative to this path. You - can change this at any time. - env_key: PROJECT_LOCATION + title: React-native/Expo project directory + summary: Path of the directory containing the project's `+"`package.json`"+` file. + env_key: WORKDIR type: selector value_map: - android: - title: Module - summary: Modules provide a container for your Android project's source code, - resource files, and app level settings, such as the module-level build file - and Android manifest file. Each module can be independently built, tested, - and debugged. You can add new modules to your Bitrise builds at any time. - env_key: MODULE - type: user_input + .: + title: The root directory of an Android project + summary: The root directory of your Android project, stored as an Environment + Variable. In your Workflows, you can specify paths relative to this path. + You can change this at any time. + env_key: PROJECT_LOCATION + type: selector value_map: - app: - title: Variant - summary: Your Android build variant. You can add variants at any time, - as well as further configure your existing variants later. - env_key: VARIANT - type: user_input_optional + android: + title: Module + summary: Modules provide a container for your Android project's source + code, resource files, and app level settings, such as the module-level + build file and Android manifest file. Each module can be independently + built, tested, and debugged. You can add new modules to your Bitrise + builds at any time. + env_key: MODULE + type: user_input value_map: - "": - title: Project or Workspace path - summary: The location of your Xcode project or Xcode workspace files, - stored as an Environment Variable. In your Workflows, you can specify - paths relative to this path. - env_key: BITRISE_PROJECT_PATH - type: selector + app: + title: Variant + summary: Your Android build variant. You can add variants at any time, + as well as further configure your existing variants later. + env_key: VARIANT + type: user_input_optional value_map: - ios/SampleAppsReactNativeAndroid.xcodeproj: - title: Scheme name - summary: An Xcode scheme defines a collection of targets to build, - a configuration to use when building, and a collection of tests - to execute. Only shared schemes are detected automatically but - you can use any scheme as a target on Bitrise. You can change - the scheme at any time in your Env Vars. - env_key: BITRISE_SCHEME + Debug: + title: Project or Workspace path + summary: The location of your Xcode project or Xcode workspace + files, stored as an Environment Variable. In your Workflows, + you can specify paths relative to this path. + env_key: BITRISE_PROJECT_PATH type: selector value_map: - SampleAppsReactNativeAndroid: - title: Distribution method - summary: The export method used to create an .ipa file in - your builds, stored as an Environment Variable. You can - change this at any time, or even create several .ipa files - with different export methods in the same build. - env_key: BITRISE_DISTRIBUTION_METHOD - type: selector - value_map: - ad-hoc: - config: react-native-android-ios-test-config - app-store: - config: react-native-android-ios-test-config - development: - config: react-native-android-ios-test-config - enterprise: - config: react-native-android-ios-test-config - SampleAppsReactNativeAndroid-tvOS: - title: Distribution method - summary: The export method used to create an .ipa file in - your builds, stored as an Environment Variable. You can - change this at any time, or even create several .ipa files - with different export methods in the same build. - env_key: BITRISE_DISTRIBUTION_METHOD + ios/SampleAppsReactNativeAndroid.xcodeproj: + title: Scheme name + summary: An Xcode scheme defines a collection of targets to + build, a configuration to use when building, and a collection + of tests to execute. Only shared schemes are detected automatically + but you can use any scheme as a target on Bitrise. You can + change the scheme at any time in your Env Vars. + env_key: BITRISE_SCHEME type: selector value_map: - ad-hoc: - config: react-native-android-ios-test-config - app-store: - config: react-native-android-ios-test-config - development: - config: react-native-android-ios-test-config - enterprise: - config: react-native-android-ios-test-config + SampleAppsReactNativeAndroid: + title: Distribution method + summary: The export method used to create an .ipa file + in your builds, stored as an Environment Variable. You + can change this at any time, or even create several + .ipa files with different export methods in the same + build. + env_key: BITRISE_DISTRIBUTION_METHOD + type: selector + value_map: + ad-hoc: + config: react-native-android-ios-test-config + app-store: + config: react-native-android-ios-test-config + development: + config: react-native-android-ios-test-config + enterprise: + config: react-native-android-ios-test-config + SampleAppsReactNativeAndroid-tvOS: + title: Distribution method + summary: The export method used to create an .ipa file + in your builds, stored as an Environment Variable. You + can change this at any time, or even create several + .ipa files with different export methods in the same + build. + env_key: BITRISE_DISTRIBUTION_METHOD + type: selector + value_map: + ad-hoc: + config: react-native-android-ios-test-config + app-store: + config: react-native-android-ios-test-config + development: + config: react-native-android-ios-test-config + enterprise: + config: react-native-android-ios-test-config configs: react-native: react-native-android-ios-test-config: | @@ -425,9 +445,11 @@ configs: - git-clone@%s: {} - npm@%s: inputs: + - workdir: $WORKDIR - command: install - npm@%s: inputs: + - workdir: $WORKDIR - command: test - install-missing-android-tools@%s: inputs: @@ -435,6 +457,8 @@ configs: - android-build@%s: inputs: - project_location: $PROJECT_LOCATION + - module: $MODULE + - variant: $VARIANT - xcode-archive@%s: inputs: - project_path: $BITRISE_PROJECT_PATH @@ -454,9 +478,11 @@ configs: - git-clone@%s: {} - npm@%s: inputs: + - workdir: $WORKDIR - command: install - npm@%s: inputs: + - workdir: $WORKDIR - command: test - deploy-to-bitrise-io@%s: {} warnings: @@ -484,81 +510,90 @@ var sampleAppsReactNativeIosAndAndroidNoTestVersions = []interface{}{ var sampleAppsReactNativeIosAndAndroidNoTestResultYML = fmt.Sprintf(`options: react-native: - title: The root directory of an Android project - summary: The root directory of your Android project, stored as an Environment - Variable. In your Workflows, you can specify paths relative to this path. You - can change this at any time. - env_key: PROJECT_LOCATION + title: React-native/Expo project directory + summary: Path of the directory containing the project's `+"`package.json`"+` file. + env_key: WORKDIR type: selector value_map: - android: - title: Module - summary: Modules provide a container for your Android project's source code, - resource files, and app level settings, such as the module-level build file - and Android manifest file. Each module can be independently built, tested, - and debugged. You can add new modules to your Bitrise builds at any time. - env_key: MODULE - type: user_input + .: + title: The root directory of an Android project + summary: The root directory of your Android project, stored as an Environment + Variable. In your Workflows, you can specify paths relative to this path. + You can change this at any time. + env_key: PROJECT_LOCATION + type: selector value_map: - app: - title: Variant - summary: Your Android build variant. You can add variants at any time, - as well as further configure your existing variants later. - env_key: VARIANT - type: user_input_optional + android: + title: Module + summary: Modules provide a container for your Android project's source + code, resource files, and app level settings, such as the module-level + build file and Android manifest file. Each module can be independently + built, tested, and debugged. You can add new modules to your Bitrise + builds at any time. + env_key: MODULE + type: user_input value_map: - "": - title: Project or Workspace path - summary: The location of your Xcode project or Xcode workspace files, - stored as an Environment Variable. In your Workflows, you can specify - paths relative to this path. - env_key: BITRISE_PROJECT_PATH - type: selector + app: + title: Variant + summary: Your Android build variant. You can add variants at any time, + as well as further configure your existing variants later. + env_key: VARIANT + type: user_input_optional value_map: - ios/SampleAppsReactNativeAndroid.xcodeproj: - title: Scheme name - summary: An Xcode scheme defines a collection of targets to build, - a configuration to use when building, and a collection of tests - to execute. Only shared schemes are detected automatically but - you can use any scheme as a target on Bitrise. You can change - the scheme at any time in your Env Vars. - env_key: BITRISE_SCHEME + Debug: + title: Project or Workspace path + summary: The location of your Xcode project or Xcode workspace + files, stored as an Environment Variable. In your Workflows, + you can specify paths relative to this path. + env_key: BITRISE_PROJECT_PATH type: selector value_map: - SampleAppsReactNativeAndroid: - title: Distribution method - summary: The export method used to create an .ipa file in - your builds, stored as an Environment Variable. You can - change this at any time, or even create several .ipa files - with different export methods in the same build. - env_key: BITRISE_DISTRIBUTION_METHOD + ios/SampleAppsReactNativeAndroid.xcodeproj: + title: Scheme name + summary: An Xcode scheme defines a collection of targets to + build, a configuration to use when building, and a collection + of tests to execute. Only shared schemes are detected automatically + but you can use any scheme as a target on Bitrise. You can + change the scheme at any time in your Env Vars. + env_key: BITRISE_SCHEME type: selector value_map: - ad-hoc: - config: react-native-android-ios-config - app-store: - config: react-native-android-ios-config - development: - config: react-native-android-ios-config - enterprise: - config: react-native-android-ios-config - SampleAppsReactNativeAndroid-tvOS: - title: Distribution method - summary: The export method used to create an .ipa file in - your builds, stored as an Environment Variable. You can - change this at any time, or even create several .ipa files - with different export methods in the same build. - env_key: BITRISE_DISTRIBUTION_METHOD - type: selector - value_map: - ad-hoc: - config: react-native-android-ios-config - app-store: - config: react-native-android-ios-config - development: - config: react-native-android-ios-config - enterprise: - config: react-native-android-ios-config + SampleAppsReactNativeAndroid: + title: Distribution method + summary: The export method used to create an .ipa file + in your builds, stored as an Environment Variable. You + can change this at any time, or even create several + .ipa files with different export methods in the same + build. + env_key: BITRISE_DISTRIBUTION_METHOD + type: selector + value_map: + ad-hoc: + config: react-native-android-ios-config + app-store: + config: react-native-android-ios-config + development: + config: react-native-android-ios-config + enterprise: + config: react-native-android-ios-config + SampleAppsReactNativeAndroid-tvOS: + title: Distribution method + summary: The export method used to create an .ipa file + in your builds, stored as an Environment Variable. You + can change this at any time, or even create several + .ipa files with different export methods in the same + build. + env_key: BITRISE_DISTRIBUTION_METHOD + type: selector + value_map: + ad-hoc: + config: react-native-android-ios-config + app-store: + config: react-native-android-ios-config + development: + config: react-native-android-ios-config + enterprise: + config: react-native-android-ios-config configs: react-native: react-native-android-ios-config: | @@ -583,6 +618,7 @@ configs: - git-clone@%s: {} - npm@%s: inputs: + - workdir: $WORKDIR - command: install - install-missing-android-tools@%s: inputs: @@ -590,6 +626,8 @@ configs: - android-build@%s: inputs: - project_location: $PROJECT_LOCATION + - module: $MODULE + - variant: $VARIANT - xcode-archive@%s: inputs: - project_path: $BITRISE_PROJECT_PATH @@ -610,6 +648,7 @@ configs: - git-clone@%s: {} - npm@%s: inputs: + - workdir: $WORKDIR - command: install - deploy-to-bitrise-io@%s: {} warnings: @@ -639,84 +678,93 @@ var sampleAppsReactNativeIosAndAndroidYarnVersions = []interface{}{ var sampleAppsReactNativeIosAndAndroidYarnResultYML = fmt.Sprintf(`options: react-native: - title: The root directory of an Android project - summary: The root directory of your Android project, stored as an Environment - Variable. In your Workflows, you can specify paths relative to this path. You - can change this at any time. - env_key: PROJECT_LOCATION + title: React-native/Expo project directory + summary: Path of the directory containing the project's `+"`package.json`"+` file. + env_key: WORKDIR type: selector value_map: - android: - title: Module - summary: Modules provide a container for your Android project's source code, - resource files, and app level settings, such as the module-level build file - and Android manifest file. Each module can be independently built, tested, - and debugged. You can add new modules to your Bitrise builds at any time. - env_key: MODULE - type: user_input + .: + title: The root directory of an Android project + summary: The root directory of your Android project, stored as an Environment + Variable. In your Workflows, you can specify paths relative to this path. + You can change this at any time. + env_key: PROJECT_LOCATION + type: selector value_map: - app: - title: Variant - summary: Your Android build variant. You can add variants at any time, - as well as further configure your existing variants later. - env_key: VARIANT - type: user_input_optional + android: + title: Module + summary: Modules provide a container for your Android project's source + code, resource files, and app level settings, such as the module-level + build file and Android manifest file. Each module can be independently + built, tested, and debugged. You can add new modules to your Bitrise + builds at any time. + env_key: MODULE + type: user_input value_map: - "": - title: Project or Workspace path - summary: The location of your Xcode project or Xcode workspace files, - stored as an Environment Variable. In your Workflows, you can specify - paths relative to this path. - env_key: BITRISE_PROJECT_PATH - type: selector + app: + title: Variant + summary: Your Android build variant. You can add variants at any time, + as well as further configure your existing variants later. + env_key: VARIANT + type: user_input_optional value_map: - ios/SampleAppsReactNativeAndroid.xcodeproj: - title: Scheme name - summary: An Xcode scheme defines a collection of targets to build, - a configuration to use when building, and a collection of tests - to execute. Only shared schemes are detected automatically but - you can use any scheme as a target on Bitrise. You can change - the scheme at any time in your Env Vars. - env_key: BITRISE_SCHEME + Debug: + title: Project or Workspace path + summary: The location of your Xcode project or Xcode workspace + files, stored as an Environment Variable. In your Workflows, + you can specify paths relative to this path. + env_key: BITRISE_PROJECT_PATH type: selector value_map: - SampleAppsReactNativeAndroid: - title: Distribution method - summary: The export method used to create an .ipa file in - your builds, stored as an Environment Variable. You can - change this at any time, or even create several .ipa files - with different export methods in the same build. - env_key: BITRISE_DISTRIBUTION_METHOD + ios/SampleAppsReactNativeAndroid.xcodeproj: + title: Scheme name + summary: An Xcode scheme defines a collection of targets to + build, a configuration to use when building, and a collection + of tests to execute. Only shared schemes are detected automatically + but you can use any scheme as a target on Bitrise. You can + change the scheme at any time in your Env Vars. + env_key: BITRISE_SCHEME type: selector value_map: - ad-hoc: - config: react-native-android-ios-test-config - app-store: - config: react-native-android-ios-test-config - development: - config: react-native-android-ios-test-config - enterprise: - config: react-native-android-ios-test-config - SampleAppsReactNativeAndroid-tvOS: - title: Distribution method - summary: The export method used to create an .ipa file in - your builds, stored as an Environment Variable. You can - change this at any time, or even create several .ipa files - with different export methods in the same build. - env_key: BITRISE_DISTRIBUTION_METHOD - type: selector - value_map: - ad-hoc: - config: react-native-android-ios-test-config - app-store: - config: react-native-android-ios-test-config - development: - config: react-native-android-ios-test-config - enterprise: - config: react-native-android-ios-test-config + SampleAppsReactNativeAndroid: + title: Distribution method + summary: The export method used to create an .ipa file + in your builds, stored as an Environment Variable. You + can change this at any time, or even create several + .ipa files with different export methods in the same + build. + env_key: BITRISE_DISTRIBUTION_METHOD + type: selector + value_map: + ad-hoc: + config: react-native-android-ios-test-yarn-config + app-store: + config: react-native-android-ios-test-yarn-config + development: + config: react-native-android-ios-test-yarn-config + enterprise: + config: react-native-android-ios-test-yarn-config + SampleAppsReactNativeAndroid-tvOS: + title: Distribution method + summary: The export method used to create an .ipa file + in your builds, stored as an Environment Variable. You + can change this at any time, or even create several + .ipa files with different export methods in the same + build. + env_key: BITRISE_DISTRIBUTION_METHOD + type: selector + value_map: + ad-hoc: + config: react-native-android-ios-test-yarn-config + app-store: + config: react-native-android-ios-test-yarn-config + development: + config: react-native-android-ios-test-yarn-config + enterprise: + config: react-native-android-ios-test-yarn-config configs: react-native: - react-native-android-ios-test-config: | + react-native-android-ios-test-yarn-config: | format_version: "%s" default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git project_type: react-native @@ -738,9 +786,11 @@ configs: - git-clone@%s: {} - yarn@%s: inputs: + - workdir: $WORKDIR - command: install - yarn@%s: inputs: + - workdir: $WORKDIR - command: test - install-missing-android-tools@%s: inputs: @@ -748,6 +798,8 @@ configs: - android-build@%s: inputs: - project_location: $PROJECT_LOCATION + - module: $MODULE + - variant: $VARIANT - xcode-archive@%s: inputs: - project_path: $BITRISE_PROJECT_PATH @@ -767,9 +819,11 @@ configs: - git-clone@%s: {} - yarn@%s: inputs: + - workdir: $WORKDIR - command: install - yarn@%s: inputs: + - workdir: $WORKDIR - command: test - deploy-to-bitrise-io@%s: {} warnings: @@ -798,98 +852,108 @@ var sampleAppsReactNativeJoplinVersions = []interface{}{ var sampleAppsReactNativeJoplinResultYML = fmt.Sprintf(`options: react-native: - title: The root directory of an Android project - summary: The root directory of your Android project, stored as an Environment - Variable. In your Workflows, you can specify paths relative to this path. You - can change this at any time. - env_key: PROJECT_LOCATION + title: React-native/Expo project directory + summary: Path of the directory containing the project's `+"`package.json`"+` file. + env_key: WORKDIR type: selector value_map: - packages/app-mobile/android: - title: Module - summary: Modules provide a container for your Android project's source code, - resource files, and app level settings, such as the module-level build file - and Android manifest file. Each module can be independently built, tested, - and debugged. You can add new modules to your Bitrise builds at any time. - env_key: MODULE - type: user_input + packages/app-mobile: + title: The root directory of an Android project + summary: The root directory of your Android project, stored as an Environment + Variable. In your Workflows, you can specify paths relative to this path. + You can change this at any time. + env_key: PROJECT_LOCATION + type: selector value_map: - app: - title: Variant - summary: Your Android build variant. You can add variants at any time, - as well as further configure your existing variants later. - env_key: VARIANT - type: user_input_optional + packages/app-mobile/android: + title: Module + summary: Modules provide a container for your Android project's source + code, resource files, and app level settings, such as the module-level + build file and Android manifest file. Each module can be independently + built, tested, and debugged. You can add new modules to your Bitrise + builds at any time. + env_key: MODULE + type: user_input value_map: - "": - title: Project or Workspace path - summary: The location of your Xcode project or Xcode workspace files, - stored as an Environment Variable. In your Workflows, you can specify - paths relative to this path. - env_key: BITRISE_PROJECT_PATH - type: selector + app: + title: Variant + summary: Your Android build variant. You can add variants at any time, + as well as further configure your existing variants later. + env_key: VARIANT + type: user_input_optional value_map: - packages/app-mobile/ios/Joplin.xcworkspace: - title: Scheme name - summary: An Xcode scheme defines a collection of targets to build, - a configuration to use when building, and a collection of tests - to execute. Only shared schemes are detected automatically but - you can use any scheme as a target on Bitrise. You can change - the scheme at any time in your Env Vars. - env_key: BITRISE_SCHEME + Debug: + title: Project or Workspace path + summary: The location of your Xcode project or Xcode workspace + files, stored as an Environment Variable. In your Workflows, + you can specify paths relative to this path. + env_key: BITRISE_PROJECT_PATH type: selector value_map: - Joplin: - title: Distribution method - summary: The export method used to create an .ipa file in - your builds, stored as an Environment Variable. You can - change this at any time, or even create several .ipa files - with different export methods in the same build. - env_key: BITRISE_DISTRIBUTION_METHOD - type: selector - value_map: - ad-hoc: - config: react-native-android-ios-pod-config - app-store: - config: react-native-android-ios-pod-config - development: - config: react-native-android-ios-pod-config - enterprise: - config: react-native-android-ios-pod-config - Joplin-tvOS: - title: Distribution method - summary: The export method used to create an .ipa file in - your builds, stored as an Environment Variable. You can - change this at any time, or even create several .ipa files - with different export methods in the same build. - env_key: BITRISE_DISTRIBUTION_METHOD - type: selector - value_map: - ad-hoc: - config: react-native-android-ios-pod-config - app-store: - config: react-native-android-ios-pod-config - development: - config: react-native-android-ios-pod-config - enterprise: - config: react-native-android-ios-pod-config - ShareExtension: - title: Distribution method - summary: The export method used to create an .ipa file in - your builds, stored as an Environment Variable. You can - change this at any time, or even create several .ipa files - with different export methods in the same build. - env_key: BITRISE_DISTRIBUTION_METHOD + packages/app-mobile/ios/Joplin.xcworkspace: + title: Scheme name + summary: An Xcode scheme defines a collection of targets to + build, a configuration to use when building, and a collection + of tests to execute. Only shared schemes are detected automatically + but you can use any scheme as a target on Bitrise. You can + change the scheme at any time in your Env Vars. + env_key: BITRISE_SCHEME type: selector value_map: - ad-hoc: - config: react-native-android-ios-pod-config - app-store: - config: react-native-android-ios-pod-config - development: - config: react-native-android-ios-pod-config - enterprise: - config: react-native-android-ios-pod-config + Joplin: + title: Distribution method + summary: The export method used to create an .ipa file + in your builds, stored as an Environment Variable. You + can change this at any time, or even create several + .ipa files with different export methods in the same + build. + env_key: BITRISE_DISTRIBUTION_METHOD + type: selector + value_map: + ad-hoc: + config: react-native-android-ios-pod-config + app-store: + config: react-native-android-ios-pod-config + development: + config: react-native-android-ios-pod-config + enterprise: + config: react-native-android-ios-pod-config + Joplin-tvOS: + title: Distribution method + summary: The export method used to create an .ipa file + in your builds, stored as an Environment Variable. You + can change this at any time, or even create several + .ipa files with different export methods in the same + build. + env_key: BITRISE_DISTRIBUTION_METHOD + type: selector + value_map: + ad-hoc: + config: react-native-android-ios-pod-config + app-store: + config: react-native-android-ios-pod-config + development: + config: react-native-android-ios-pod-config + enterprise: + config: react-native-android-ios-pod-config + ShareExtension: + title: Distribution method + summary: The export method used to create an .ipa file + in your builds, stored as an Environment Variable. You + can change this at any time, or even create several + .ipa files with different export methods in the same + build. + env_key: BITRISE_DISTRIBUTION_METHOD + type: selector + value_map: + ad-hoc: + config: react-native-android-ios-pod-config + app-store: + config: react-native-android-ios-pod-config + development: + config: react-native-android-ios-pod-config + enterprise: + config: react-native-android-ios-pod-config configs: react-native: react-native-android-ios-pod-config: | @@ -914,7 +978,7 @@ configs: - git-clone@%s: {} - npm@%s: inputs: - - workdir: packages/app-mobile + - workdir: $WORKDIR - command: install - install-missing-android-tools@%s: inputs: @@ -922,6 +986,8 @@ configs: - android-build@%s: inputs: - project_location: $PROJECT_LOCATION + - module: $MODULE + - variant: $VARIANT - cocoapods-install@%s: {} - xcode-archive@%s: inputs: @@ -943,7 +1009,7 @@ configs: - git-clone@%s: {} - npm@%s: inputs: - - workdir: packages/app-mobile + - workdir: $WORKDIR - command: install - deploy-to-bitrise-io@%s: {} warnings: diff --git a/scanners/reactnative/expo.go b/scanners/reactnative/expo.go index 8ad08c01..279a85f5 100644 --- a/scanners/reactnative/expo.go +++ b/scanners/reactnative/expo.go @@ -37,7 +37,12 @@ func (scanner *Scanner) expoOptions() (models.OptionNode, models.Warnings) { func (scanner *Scanner) expoConfigs(project project, isPrivateRepo bool) (models.BitriseConfigMap, error) { configMap := models.BitriseConfigMap{} + if project.projectRelDir == "." { + // package.json placed in the search dir, no need to change-dir in the workflows + project.projectRelDir = "" + } testSteps := getTestSteps(project.projectRelDir, project.hasYarnLockFile, project.hasTest) + // primary workflow primaryDescription := expoPrimaryWorkflowDescription if !project.hasTest { diff --git a/scanners/reactnative/plain.go b/scanners/reactnative/plain.go index 89adb72a..18caeb05 100644 --- a/scanners/reactnative/plain.go +++ b/scanners/reactnative/plain.go @@ -88,6 +88,7 @@ func generateIOSOptions(result ios.DetectResult, hasAndroid, hasTests, hasYarnLo // options implements ScannerInterface.Options function for plain React Native projects. func (scanner *Scanner) options(project project) (models.OptionNode, models.Warnings) { + const defaultVariant = "Debug" var ( rootOption models.OptionNode allDescriptors []configDescriptor @@ -116,7 +117,7 @@ func (scanner *Scanner) options(project project) (models.OptionNode, models.Warn } allDescriptors = append(allDescriptors, descriptor) - variantOption.AddConfig("", models.NewConfigOption(descriptor.configName(), nil)) + variantOption.AddConfig(defaultVariant, models.NewConfigOption(descriptor.configName(), nil)) continue } @@ -125,7 +126,7 @@ func (scanner *Scanner) options(project project) (models.OptionNode, models.Warn warnings = append(warnings, iosWarnings...) allDescriptors = append(allDescriptors, descriptors...) - variantOption.AddOption("", iosOptions) + variantOption.AddOption(defaultVariant, iosOptions) } } else { options, iosWarnings, descriptors := generateIOSOptions(project.iosProjects, false, project.hasTest, project.hasYarnLockFile) @@ -200,6 +201,8 @@ func (scanner *Scanner) configs(isPrivateRepo bool) (models.BitriseConfigMap, er )) configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.AndroidBuildStepListItem( envmanModels.EnvironmentItemModel{android.ProjectLocationInputKey: projectLocationEnv}, + envmanModels.EnvironmentItemModel{android.ModuleInputKey: "$" + android.ModuleInputEnvKey}, + envmanModels.EnvironmentItemModel{android.VariantInputKey: "$" + android.VariantInputEnvKey}, )) } diff --git a/scanners/reactnative/reactnative.go b/scanners/reactnative/reactnative.go index fd869c8a..2396b3f7 100644 --- a/scanners/reactnative/reactnative.go +++ b/scanners/reactnative/reactnative.go @@ -16,7 +16,7 @@ const scannerName = "react-native" const ( projectDirInputTitle = "React-native/Expo project directory" - projectDirInputSummary = "Path of the directory containing the project's `package.json` and/or app configuration file (`app.json`, `app.config.js`, `app.config.ts`)." + projectDirInputSummary = "Path of the directory containing the project's `package.json` file." projectDirInputEnvKey = "WORKDIR" isExpoBasedProjectInputTitle = "Is this an [Expo](https://expo.dev)-based React Native project?" @@ -183,10 +183,6 @@ func (scanner *Scanner) DetectPlatform(searchDir string) (bool, error) { if err != nil { return false, fmt.Errorf("failed to get relative package.json dir path: %s", err) } - if relPackageJSONDir == "." { - // package.json placed in the search dir, no need to change-dir in the workflows - relPackageJSONDir = "" - } var ( iosProjects ios.DetectResult From f9192fb8e9353e801b44b7099a82ce267b656998 Mon Sep 17 00:00:00 2001 From: Laszlo Pusok Date: Mon, 14 Feb 2022 12:33:47 +0100 Subject: [PATCH 7/9] Removed log --- scanners/reactnative/reactnative.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/scanners/reactnative/reactnative.go b/scanners/reactnative/reactnative.go index 2396b3f7..d0b6960e 100644 --- a/scanners/reactnative/reactnative.go +++ b/scanners/reactnative/reactnative.go @@ -147,8 +147,6 @@ func getNativeProjects(packageJSONPth, relPackageJSONDir string) (ios.DetectResu } androidProjects = newAndroidProjects - log.TPrintf("iosProjects %+v", iosProjects) - return iosProjects, androidProjects } From c57bfec2a08d717782a89825377060099b7b15e9 Mon Sep 17 00:00:00 2001 From: Laszlo Pusok Date: Mon, 14 Feb 2022 14:49:37 +0100 Subject: [PATCH 8/9] Updated RN default workflows default values. fixup: review comments. --- _tests/integration/manual_config_test.go | 10 ++++--- _tests/integration/reactnative_test.go | 10 +++---- scanners/reactnative/expo.go | 4 +-- scanners/reactnative/plain.go | 38 ++++++++++++++++-------- scanners/reactnative/reactnative.go | 4 +-- 5 files changed, 40 insertions(+), 26 deletions(-) diff --git a/_tests/integration/manual_config_test.go b/_tests/integration/manual_config_test.go index 29f9cf88..8281f745 100644 --- a/_tests/integration/manual_config_test.go +++ b/_tests/integration/manual_config_test.go @@ -502,7 +502,7 @@ var customConfigResultYML = fmt.Sprintf(`options: env_key: PROJECT_LOCATION type: user_input value_map: - "": + android: title: Module summary: Modules provide a container for your Android project's source code, resource files, and app level settings, such as the module-level @@ -512,14 +512,14 @@ var customConfigResultYML = fmt.Sprintf(`options: env_key: MODULE type: user_input value_map: - "": + app: title: Variant summary: Your Android build variant. You can add variants at any time, as well as further configure your existing variants later. env_key: VARIANT type: user_input_optional value_map: - "": + Debug: title: Project or Workspace path summary: The location of your Xcode project or Xcode workspace files, stored as an Environment Variable. In your Workflows, @@ -527,7 +527,7 @@ var customConfigResultYML = fmt.Sprintf(`options: env_key: BITRISE_PROJECT_PATH type: user_input value_map: - "": + ios: title: Scheme name summary: An Xcode scheme defines a collection of targets to build, a configuration to use when building, and a collection @@ -1239,6 +1239,8 @@ configs: - android-build@%s: inputs: - project_location: $PROJECT_LOCATION + - module: $MODULE + - variant: $VARIANT - xcode-archive@%s: inputs: - project_path: $BITRISE_PROJECT_PATH diff --git a/_tests/integration/reactnative_test.go b/_tests/integration/reactnative_test.go index 5aeb2aaf..acae842a 100644 --- a/_tests/integration/reactnative_test.go +++ b/_tests/integration/reactnative_test.go @@ -162,7 +162,7 @@ var sampleAppsReactNativeSubdirVersions = []interface{}{ var sampleAppsReactNativeSubdirResultYML = fmt.Sprintf(`options: react-native: - title: React-native/Expo project directory + title: React Native project directory summary: Path of the directory containing the project's `+"`package.json`"+` file. env_key: WORKDIR type: selector @@ -337,7 +337,7 @@ var sampleAppsReactNativeIosAndAndroidVersions = []interface{}{ var sampleAppsReactNativeIosAndAndroidResultYML = fmt.Sprintf(`options: react-native: - title: React-native/Expo project directory + title: React Native project directory summary: Path of the directory containing the project's `+"`package.json`"+` file. env_key: WORKDIR type: selector @@ -510,7 +510,7 @@ var sampleAppsReactNativeIosAndAndroidNoTestVersions = []interface{}{ var sampleAppsReactNativeIosAndAndroidNoTestResultYML = fmt.Sprintf(`options: react-native: - title: React-native/Expo project directory + title: React Native project directory summary: Path of the directory containing the project's `+"`package.json`"+` file. env_key: WORKDIR type: selector @@ -678,7 +678,7 @@ var sampleAppsReactNativeIosAndAndroidYarnVersions = []interface{}{ var sampleAppsReactNativeIosAndAndroidYarnResultYML = fmt.Sprintf(`options: react-native: - title: React-native/Expo project directory + title: React Native project directory summary: Path of the directory containing the project's `+"`package.json`"+` file. env_key: WORKDIR type: selector @@ -852,7 +852,7 @@ var sampleAppsReactNativeJoplinVersions = []interface{}{ var sampleAppsReactNativeJoplinResultYML = fmt.Sprintf(`options: react-native: - title: React-native/Expo project directory + title: React Native project directory summary: Path of the directory containing the project's `+"`package.json`"+` file. env_key: WORKDIR type: selector diff --git a/scanners/reactnative/expo.go b/scanners/reactnative/expo.go index 279a85f5..d8e23c40 100644 --- a/scanners/reactnative/expo.go +++ b/scanners/reactnative/expo.go @@ -22,7 +22,7 @@ const ( ) // expoOptions implements ScannerInterface.Options function for Expo based React Native projects. -func (scanner *Scanner) expoOptions() (models.OptionNode, models.Warnings) { +func (scanner *Scanner) expoOptions() models.OptionNode { platformOption := models.NewOption(expoPlatformInputTitle, expoPlatformInputSummary, expoPlatformInputEnvKey, models.TypeSelector) configOption := models.NewConfigOption(expoConfigName, nil) @@ -30,7 +30,7 @@ func (scanner *Scanner) expoOptions() (models.OptionNode, models.Warnings) { platformOption.AddConfig(platform, configOption) } - return *platformOption, nil + return *platformOption } // expoConfigs implements ScannerInterface.Configs function for Expo based React Native projects. diff --git a/scanners/reactnative/plain.go b/scanners/reactnative/plain.go index 18caeb05..4a550627 100644 --- a/scanners/reactnative/plain.go +++ b/scanners/reactnative/plain.go @@ -14,6 +14,9 @@ import ( const ( defaultConfigName = "default-react-native-config" + + defaultModule = "app" + defaultVariant = "Debug" ) type configDescriptor struct { @@ -88,11 +91,10 @@ func generateIOSOptions(result ios.DetectResult, hasAndroid, hasTests, hasYarnLo // options implements ScannerInterface.Options function for plain React Native projects. func (scanner *Scanner) options(project project) (models.OptionNode, models.Warnings) { - const defaultVariant = "Debug" var ( rootOption models.OptionNode allDescriptors []configDescriptor - warnings = models.Warnings{} + warnings models.Warnings ) // Android @@ -107,7 +109,7 @@ func (scanner *Scanner) options(project project) (models.OptionNode, models.Warn variantOption := models.NewOption(android.VariantInputTitle, android.VariantInputSummary, android.VariantInputEnvKey, models.TypeOptionalUserInput) androidOptions.AddOption(androidProject.RelPath, moduleOption) - moduleOption.AddOption("app", variantOption) + moduleOption.AddOption(defaultModule, variantOption) if len(project.iosProjects.Projects) == 0 { descriptor := configDescriptor{ @@ -142,19 +144,27 @@ func (scanner *Scanner) options(project project) (models.OptionNode, models.Warn // defaultOptions implements ScannerInterface.DefaultOptions function for plain React Native projects. func (scanner *Scanner) defaultOptions() models.OptionNode { - androidOptions := (&android.Scanner{}).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("ios", schemeOption) + + 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 + return *androidOptions } // configs implements ScannerInterface.Configs function for plain React Native projects. @@ -281,6 +291,8 @@ 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 diff --git a/scanners/reactnative/reactnative.go b/scanners/reactnative/reactnative.go index d0b6960e..c7d70e26 100644 --- a/scanners/reactnative/reactnative.go +++ b/scanners/reactnative/reactnative.go @@ -15,7 +15,7 @@ import ( const scannerName = "react-native" const ( - projectDirInputTitle = "React-native/Expo project directory" + projectDirInputTitle = "React Native project directory" projectDirInputSummary = "Path of the directory containing the project's `package.json` file." projectDirInputEnvKey = "WORKDIR" @@ -236,7 +236,7 @@ func (scanner *Scanner) DetectPlatform(searchDir string) (bool, error) { // Options implements ScannerInterface.Options function. func (scanner *Scanner) Options() (options models.OptionNode, allWarnings models.Warnings, icons models.Icons, err error) { if scanner.isExpoBased { - options, allWarnings = scanner.expoOptions() + options = scanner.expoOptions() } else { projectRootOption := models.NewOption(projectDirInputTitle, projectDirInputSummary, projectDirInputEnvKey, models.TypeSelector) options = *projectRootOption From 9fdd9091128ffd76d2e9274685ce1604cdf2a6c2 Mon Sep 17 00:00:00 2001 From: Laszlo Pusok Date: Mon, 14 Feb 2022 14:58:38 +0100 Subject: [PATCH 9/9] Restore default ios path --- _tests/integration/manual_config_test.go | 2 +- scanners/reactnative/plain.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/_tests/integration/manual_config_test.go b/_tests/integration/manual_config_test.go index 8281f745..87022f40 100644 --- a/_tests/integration/manual_config_test.go +++ b/_tests/integration/manual_config_test.go @@ -527,7 +527,7 @@ var customConfigResultYML = fmt.Sprintf(`options: env_key: BITRISE_PROJECT_PATH type: user_input value_map: - ios: + "": title: Scheme name summary: An Xcode scheme defines a collection of targets to build, a configuration to use when building, and a collection diff --git a/scanners/reactnative/plain.go b/scanners/reactnative/plain.go index 4a550627..8cbf4c8e 100644 --- a/scanners/reactnative/plain.go +++ b/scanners/reactnative/plain.go @@ -155,7 +155,7 @@ func (scanner *Scanner) defaultOptions() models.OptionNode { schemeOption := models.NewOption(ios.SchemeInputTitle, ios.SchemeInputSummary, ios.SchemeInputEnvKey, models.TypeUserInput) variantOption.AddOption(defaultVariant, projectPathOption) - projectPathOption.AddOption("ios", schemeOption) + projectPathOption.AddOption("", schemeOption) exportMethodOption := models.NewOption(ios.DistributionMethodInputTitle, ios.DistributionMethodInputSummary, ios.DistributionMethodEnvKey, models.TypeSelector) for _, exportMethod := range ios.IosExportMethods {