{"action":"created","comment":{"url":"https://api.github.com/repos/bitrise-core/bitrise-init/pulls/comments/190881805","pull_request_review_id":123356459,"id":190881805,"diff_hunk":"@@ -0,0 +1,674 @@\n+package expo\n+\n+import (\n+\t\"bufio\"\n+\t\"errors\"\n+\t\"fmt\"\n+\t\"io\"\n+\t\"os\"\n+\t\"os/exec\"\n+\t\"path/filepath\"\n+\t\"sync/atomic\"\n+\t\"time\"\n+\n+\t\"github.com/bitrise-core/bitrise-init/models\"\n+\t\"github.com/bitrise-core/bitrise-init/scanners/android\"\n+\t\"github.com/bitrise-core/bitrise-init/scanners/cordova\"\n+\t\"github.com/bitrise-core/bitrise-init/scanners/ios\"\n+\t\"github.com/bitrise-core/bitrise-init/scanners/reactnative\"\n+\t\"github.com/bitrise-core/bitrise-init/steps\"\n+\t\"github.com/bitrise-core/bitrise-init/utility\"\n+\tenvmanModels \"github.com/bitrise-io/envman/models\"\n+\t\"github.com/bitrise-io/go-utils/command\"\n+\t\"github.com/bitrise-io/go-utils/log\"\n+\t\"github.com/bitrise-io/go-utils/pathutil\"\n+\tyaml \"gopkg.in/yaml.v2\"\n+)\n+\n+// Name ...\n+const Name = \"react-native-expo\"\n+\n+const (\n+\tworkDirInputKey = \"workdir\"\n+\n+\tgradleFileInputKey    = \"gradle_file\"\n+\tgradleFileInputEnvKey = \"GRADLE_BUILD_FILE_PATH\"\n+\tgradleFileInputTitle  = \"Path to the gradle file to use\"\n+\n+\tgradleTaskInputKey = \"gradle_task\"\n+)\n+\n+// Scanner ...\n+type Scanner struct {\n+\tsearchDir          string\n+\tiosScanner         *ios.Scanner\n+\tandroidScanner     *android.Scanner\n+\treactnativeScanner *reactnative.Scanner\n+\thasNPMTest         bool\n+\tpackageJSONPth     string\n+}\n+\n+// LineModification ...\n+type LineModification struct {\n+\tlastTime    time.Time\n+\tanswerCount int\n+}\n+\n+// LastLineModification ...\n+var LastLineModification atomic.Value\n+\n+// NewScanner ...\n+func NewScanner() *Scanner {\n+\treturn &Scanner{}\n+}\n+\n+// Name ...\n+func (Scanner) Name() string {\n+\treturn Name\n+}\n+\n+// DetectPlatform ...\n+func (scanner *Scanner) DetectPlatform(searchDir string) (bool, error) {\n+\tscanner.searchDir = searchDir\n+\n+\tlog.TInfof(\"Collect package.json files\")\n+\n+\tpackageJSONPths, err := reactnative.CollectPackageJSONFiles(searchDir)\n+\tif err != nil {\n+\t\treturn false, err\n+\t}\n+\n+\tif len(packageJSONPths) == 0 {\n+\t\treturn false, nil\n+\t}\n+\n+\tlog.TPrintf(\"%d package.json file detected\", len(packageJSONPths))\n+\n+\tlog.TInfof(\"Filter relevant package.json files\")\n+\n+\trelevantPackageJSONPths := []string{}\n+\tiosScanner := ios.NewScanner()\n+\tandroidScanner := android.NewScanner()\n+\n+\tfor _, packageJSONPth := range packageJSONPths {\n+\t\tdependencyFound := false\n+\t\tdependencyExpo := \"expo\"\n+\t\tdependencyEject := \"eject\"\n+\n+\t\tvar err error\n+\t\tdependencyFound, err = FindDependency(packageJSONPth, dependencyExpo, \"dependencies\")\n+\t\tif err != nil {\n+\t\t\treturn false, err\n+\t\t}\n+\n+\t\t// expo dependency not found\n+\t\tif !dependencyFound {\n+\t\t\tcontinue\n+\t\t}\n+\n+\t\tdependencyFound, err = FindDependency(packageJSONPth, dependencyEject, \"scripts\")\n+\t\tif err != nil {\n+\t\t\treturn false, err\n+\t\t}\n+\n+\t\t// eject dependency not found\n+\t\tif !dependencyFound {\n+\t\t\tcontinue\n+\t\t}\n+\n+\t\tif err := ensureNodeModules(filepath.Dir(packageJSONPth)); err != nil {\n+\t\t\tlog.Errorf(\"ERROR DURING INSTALLING NPM: %s\", err)\n+\t\t\treturn false, nil\n+\t\t}\n+\n+\t\tif err := ejectProject(searchDir, filepath.Dir(packageJSONPth)); err != nil {\n+\t\t\tlog.Errorf(\"ERROR DURING EJECTING THE PROJECT: %s\", err)\n+\t\t\treturn false, nil\n+\t\t}\n+\t\tlog.TPrintf(\"checking: %s\", packageJSONPth)\n+\n+\t\tprojectDir := filepath.Dir(packageJSONPth)\n+\n+\t\tiosProjectDetected := false\n+\t\tiosDir := filepath.Join(projectDir, \"ios\")\n+\t\tif exist, err := pathutil.IsDirExists(iosDir); err != nil {\n+\t\t\treturn false, err\n+\t\t} else if exist {\n+\t\t\tif detected, err := iosScanner.DetectPlatform(scanner.searchDir); err != nil {\n+\t\t\t\treturn false, err\n+\t\t\t} else if detected {\n+\t\t\t\tiosProjectDetected = true\n+\t\t\t}\n+\t\t}\n+\n+\t\tandroidProjectDetected := false\n+\t\tandroidDir := filepath.Join(projectDir, \"android\")\n+\t\tif exist, err := pathutil.IsDirExists(androidDir); err != nil {\n+\t\t\treturn false, err\n+\t\t} else if exist {\n+\t\t\tif detected, err := androidScanner.DetectPlatform(scanner.searchDir); err != nil {\n+\t\t\t\treturn false, err\n+\t\t\t} else if detected {\n+\t\t\t\tandroidProjectDetected = true\n+\t\t\t}\n+\t\t}\n+\n+\t\tif iosProjectDetected || androidProjectDetected {\n+\t\t\trelevantPackageJSONPths = append(relevantPackageJSONPths, packageJSONPth)\n+\t\t} else {\n+\t\t\tlog.TWarnf(\"no ios nor android project found, skipping package.json file\")\n+\t\t}\n+\t}\n+\n+\tif len(relevantPackageJSONPths) == 0 {\n+\t\treturn false, nil\n+\t} else if len(relevantPackageJSONPths) > 1 {\n+\t\tlog.Warnf(\"More package.json file found\")\n+\t\tlog.Warnf(\"Using the %s package.json file\", relevantPackageJSONPths[0])\n+\t}\n+\n+\tscanner.packageJSONPth = relevantPackageJSONPths[0]\n+\n+\treturn true, nil\n+}\n+\n+// Options ...\n+func (scanner *Scanner) Options() (models.OptionModel, models.Warnings, error) {\n+\twarnings := models.Warnings{}\n+\n+\tvar rootOption models.OptionModel\n+\n+\t// react options\n+\tpackages, err := cordova.ParsePackagesJSON(scanner.packageJSONPth)\n+\tif err != nil {\n+\t\tfmt.Printf(\"JAJA erre gondolt - %s\\n\\n\", scanner.packageJSONPth)\n+\t\treturn models.OptionModel{}, warnings, err\n+\t}\n+\n+\thasNPMTest := false\n+\tif _, found := packages.Scripts[\"test\"]; found {\n+\t\thasNPMTest = true\n+\t\tscanner.hasNPMTest = true\n+\t}\n+\n+\tprojectDir := filepath.Dir(scanner.packageJSONPth)\n+\n+\t// android options\n+\tvar androidOptions *models.OptionModel\n+\tandroidDir := filepath.Join(projectDir, \"android\")\n+\tif exist, err := pathutil.IsDirExists(androidDir); err != nil {\n+\t\treturn models.OptionModel{}, warnings, err\n+\t} else if exist {\n+\t\tandroidScanner := android.NewScanner()\n+\n+\t\tif detected, err := androidScanner.DetectPlatform(scanner.searchDir); err != nil {\n+\t\t\treturn models.OptionModel{}, warnings, err\n+\t\t} else if detected {\n+\t\t\t// only the first match we need\n+\t\t\tandroidScanner.ExcludeTest = true\n+\t\t\tandroidScanner.ProjectRoots = []string{androidScanner.ProjectRoots[0]}\n+\n+\t\t\tnpmCmd := command.New(\"npm\", \"install\")\n+\t\t\tnpmCmd.SetDir(projectDir)\n+\t\t\tif out, err := npmCmd.RunAndReturnTrimmedCombinedOutput(); err != nil {\n+\t\t\t\treturn models.OptionModel{}, warnings, fmt.Errorf(\"failed to npm install react-native in: %s\\noutput: %s\\nerror: %s\", projectDir, out, err)\n+\t\t\t}\n+\n+\t\t\toptions, warns, err := androidScanner.Options()\n+\t\t\twarnings = append(warnings, warns...)\n+\t\t\tif err != nil {\n+\t\t\t\treturn models.OptionModel{}, warnings, err\n+\t\t\t}\n+\n+\t\t\tandroidOptions = &options\n+\t\t\tscanner.androidScanner = androidScanner\n+\t\t}\n+\t}\n+\n+\t// ios options\n+\tvar iosOptions *models.OptionModel\n+\tiosDir := filepath.Join(projectDir, \"ios\")\n+\tif exist, err := pathutil.IsDirExists(iosDir); err != nil {\n+\t\treturn models.OptionModel{}, warnings, err\n+\t} else if exist {\n+\t\tiosScanner := ios.NewScanner()\n+\n+\t\tif detected, err := iosScanner.DetectPlatform(scanner.searchDir); err != nil {\n+\t\t\treturn models.OptionModel{}, warnings, err\n+\t\t} else if detected {\n+\t\t\toptions, warns, err := iosScanner.Options()\n+\t\t\twarnings = append(warnings, warns...)\n+\t\t\tif err != nil {\n+\t\t\t\treturn models.OptionModel{}, warnings, err\n+\t\t\t}\n+\n+\t\t\tiosOptions = &options\n+\t\t\tscanner.iosScanner = iosScanner\n+\t\t}\n+\t}\n+\n+\tif androidOptions == nil && iosOptions == nil {\n+\t\treturn models.OptionModel{}, warnings, errors.New(\"no ios nor android project detected\")\n+\t}\n+\t// ---\n+\n+\tif androidOptions != nil {\n+\t\tif iosOptions == nil {\n+\t\t\t// we only found an android project\n+\t\t\t// we need to update the config names\n+\t\t\tlastChilds := androidOptions.LastChilds()\n+\t\t\tfor _, child := range lastChilds {\n+\t\t\t\tfor _, child := range child.ChildOptionMap {\n+\t\t\t\t\tif child.Config == \"\" {\n+\t\t\t\t\t\treturn models.OptionModel{}, warnings, fmt.Errorf(\"no config for option: %s\", child.String())\n+\t\t\t\t\t}\n+\n+\t\t\t\t\tconfigName := configName(true, false, hasNPMTest)\n+\t\t\t\t\tchild.Config = configName\n+\t\t\t\t}\n+\t\t\t}\n+\t\t} else {\n+\t\t\t// we have both ios and android projects\n+\t\t\t// we need to remove the android option's config names,\n+\t\t\t// since ios options will hold them\n+\t\t\tandroidOptions.RemoveConfigs()\n+\t\t}\n+\n+\t\trootOption = *androidOptions\n+\t}\n+\n+\tif iosOptions != nil {\n+\t\tlastChilds := iosOptions.LastChilds()\n+\t\tfor _, child := range lastChilds {\n+\t\t\tfor _, child := range child.ChildOptionMap {\n+\t\t\t\tif child.Config == \"\" {\n+\t\t\t\t\treturn models.OptionModel{}, warnings, fmt.Errorf(\"no config for option: %s\", child.String())\n+\t\t\t\t}\n+\n+\t\t\t\tconfigName := configName(scanner.androidScanner != nil, true, hasNPMTest)\n+\t\t\t\tchild.Config = configName\n+\t\t\t}\n+\t\t}\n+\n+\t\tif androidOptions == nil {\n+\t\t\t// we only found an ios project\n+\t\t\trootOption = *iosOptions\n+\t\t} else {\n+\t\t\t// we have both ios and android projects\n+\t\t\t// we attach ios options to the android options\n+\t\t\trootOption.AttachToLastChilds(iosOptions)\n+\t\t}\n+\n+\t}\n+\n+\treturn rootOption, warnings, nil\n+}\n+\n+// DefaultOptions ...\n+func (Scanner) DefaultOptions() models.OptionModel {\n+\tgradleFileOption := models.NewOption(gradleFileInputTitle, gradleFileInputEnvKey)\n+\n+\tgradlewPthOption := models.NewOption(android.GradlewPathInputTitle, android.GradlewPathInputEnvKey)\n+\tgradleFileOption.AddOption(\"_\", gradlewPthOption)\n+\n+\tprojectPathOption := models.NewOption(ios.ProjectPathInputTitle, ios.ProjectPathInputEnvKey)\n+\tgradlewPthOption.AddOption(\"_\", projectPathOption)\n+\n+\tschemeOption := models.NewOption(ios.SchemeInputTitle, ios.SchemeInputEnvKey)\n+\tprojectPathOption.AddOption(\"_\", schemeOption)\n+\n+\texportMethodOption := models.NewOption(ios.IosExportMethodInputTitle, ios.ExportMethodInputEnvKey)\n+\tschemeOption.AddOption(\"_\", exportMethodOption)\n+\n+\tfor _, exportMethod := range ios.IosExportMethods {\n+\t\tconfigOption := models.NewConfigOption(defaultConfigName())\n+\t\texportMethodOption.AddConfig(exportMethod, configOption)\n+\t}\n+\n+\treturn *gradleFileOption\n+}\n+\n+// Configs ...\n+func (scanner *Scanner) Configs() (models.BitriseConfigMap, error) {\n+\tconfigMap := models.BitriseConfigMap{}\n+\n+\tpackageJSONDir := filepath.Dir(scanner.packageJSONPth)\n+\trelPackageJSONDir, err := utility.RelPath(scanner.searchDir, packageJSONDir)\n+\tif err != nil {\n+\t\treturn models.BitriseConfigMap{}, fmt.Errorf(\"Failed to get relative config.xml dir path, error: %s\", err)\n+\t}\n+\tif relPackageJSONDir == \".\" {\n+\t\t// config.xml placed in the search dir, no need to change-dir in the workflows\n+\t\trelPackageJSONDir = \"\"\n+\t}\n+\n+\tworkdirEnvList := []envmanModels.EnvironmentItemModel{}\n+\tif relPackageJSONDir != \"\" {\n+\t\tworkdirEnvList = append(workdirEnvList, envmanModels.EnvironmentItemModel{workDirInputKey: relPackageJSONDir})\n+\t}\n+\n+\tif scanner.hasNPMTest {\n+\t\tconfigBuilder := models.NewDefaultConfigBuilder()\n+\n+\t\t// ci\n+\t\tconfigBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultPrepareStepList(false)...)\n+\t\tconfigBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.NpmStepListItem(append(workdirEnvList, envmanModels.EnvironmentItemModel{\"command\": \"install\"})...))\n+\t\tconfigBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.NpmStepListItem(append(workdirEnvList, envmanModels.EnvironmentItemModel{\"command\": \"test\"})...))\n+\t\tconfigBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultDeployStepList(false)...)\n+\n+\t\t// cd\n+\t\tconfigBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultPrepareStepList(false)...)\n+\t\tconfigBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.NpmStepListItem(append(workdirEnvList, envmanModels.EnvironmentItemModel{\"command\": \"install\"})...))\n+\n+\t\t// eject\n+\t\tconfigBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.NpmStepListItem(envmanModels.EnvironmentItemModel{\"command\": \"run eject\"}))\n+\n+\t\t// android cd\n+\t\tif scanner.androidScanner != nil {\n+\t\t\tprojectLocationEnv, moduleEnv, buildVariantEnv := \"$\"+android.ProjectLocationInputEnvKey, \"$\"+android.ModuleInputEnvKey, \"$\"+android.BuildVariantInputEnvKey\n+\n+\t\t\tconfigBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.InstallMissingAndroidToolsStepListItem())\n+\t\t\tconfigBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.AndroidBuildStepListItem(\n+\t\t\t\tenvmanModels.EnvironmentItemModel{android.ProjectLocationInputKey: projectLocationEnv},\n+\t\t\t\tenvmanModels.EnvironmentItemModel{android.ModuleInputKey: moduleEnv},\n+\t\t\t\tenvmanModels.EnvironmentItemModel{android.VariantInputKey: buildVariantEnv},\n+\t\t\t))\n+\t\t}\n+\n+\t\t// ios cd\n+\t\tif scanner.iosScanner != nil {\n+\t\t\tfor _, descriptor := range scanner.iosScanner.ConfigDescriptors {\n+\t\t\t\tconfigBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.CertificateAndProfileInstallerStepListItem())\n+\n+\t\t\t\tif descriptor.MissingSharedSchemes {\n+\t\t\t\t\tconfigBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.RecreateUserSchemesStepListItem(\n+\t\t\t\t\t\tenvmanModels.EnvironmentItemModel{ios.ProjectPathInputKey: \"$\" + ios.ProjectPathInputEnvKey},\n+\t\t\t\t\t))\n+\t\t\t\t}\n+\n+\t\t\t\tif descriptor.HasPodfile {\n+\t\t\t\t\tconfigBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.CocoapodsInstallStepListItem())\n+\t\t\t\t}\n+\n+\t\t\t\tif descriptor.CarthageCommand != \"\" {\n+\t\t\t\t\tconfigBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.CarthageStepListItem(\n+\t\t\t\t\t\tenvmanModels.EnvironmentItemModel{ios.CarthageCommandInputKey: descriptor.CarthageCommand},\n+\t\t\t\t\t))\n+\t\t\t\t}\n+\n+\t\t\t\tconfigBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.XcodeArchiveStepListItem(\n+\t\t\t\t\tenvmanModels.EnvironmentItemModel{ios.ProjectPathInputKey: \"$\" + ios.ProjectPathInputEnvKey},\n+\t\t\t\t\tenvmanModels.EnvironmentItemModel{ios.SchemeInputKey: \"$\" + ios.SchemeInputEnvKey},\n+\t\t\t\t\tenvmanModels.EnvironmentItemModel{ios.ExportMethodInputKey: \"$\" + ios.ExportMethodInputEnvKey},\n+\t\t\t\t\tenvmanModels.EnvironmentItemModel{ios.ConfigurationInputKey: \"Release\"},\n+\t\t\t\t))\n+\n+\t\t\t\tconfigBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultDeployStepList(false)...)\n+\n+\t\t\t\tbitriseDataModel, err := configBuilder.Generate(Name)\n+\t\t\t\tif err != nil {\n+\t\t\t\t\treturn models.BitriseConfigMap{}, err\n+\t\t\t\t}\n+\n+\t\t\t\tdata, err := yaml.Marshal(bitriseDataModel)\n+\t\t\t\tif err != nil {\n+\t\t\t\t\treturn models.BitriseConfigMap{}, err\n+\t\t\t\t}\n+\n+\t\t\t\tconfigName := configName(scanner.androidScanner != nil, true, true)\n+\t\t\t\tconfigMap[configName] = string(data)\n+\t\t\t}\n+\t\t} else {\n+\t\t\tconfigBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultDeployStepList(false)...)\n+\n+\t\t\tbitriseDataModel, err := configBuilder.Generate(Name)\n+\t\t\tif err != nil {\n+\t\t\t\treturn models.BitriseConfigMap{}, err\n+\t\t\t}\n+\n+\t\t\tdata, err := yaml.Marshal(bitriseDataModel)\n+\t\t\tif err != nil {\n+\t\t\t\treturn models.BitriseConfigMap{}, err\n+\t\t\t}\n+\n+\t\t\tconfigName := configName(scanner.androidScanner != nil, false, true)\n+\t\t\tconfigMap[configName] = string(data)\n+\t\t}\n+\t} else {\n+\t\tconfigBuilder := models.NewDefaultConfigBuilder()\n+\n+\t\tconfigBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultPrepareStepList(false)...)\n+\t\tconfigBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.NpmStepListItem(append(workdirEnvList, envmanModels.EnvironmentItemModel{\"command\": \"install\"})...))\n+\n+\t\t// eject\n+\t\tconfigBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.NpmStepListItem(envmanModels.EnvironmentItemModel{\"command\": \"run eject\"}))\n+\n+\t\tif scanner.androidScanner != nil {\n+\t\t\tprojectLocationEnv, moduleEnv, buildVariantEnv := \"$\"+android.ProjectLocationInputEnvKey, \"$\"+android.ModuleInputEnvKey, \"$\"+android.BuildVariantInputEnvKey\n+\n+\t\t\tconfigBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.InstallMissingAndroidToolsStepListItem())\n+\t\t\tconfigBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.AndroidBuildStepListItem(\n+\t\t\t\tenvmanModels.EnvironmentItemModel{android.ProjectLocationInputKey: projectLocationEnv},\n+\t\t\t\tenvmanModels.EnvironmentItemModel{android.ModuleInputKey: moduleEnv},\n+\t\t\t\tenvmanModels.EnvironmentItemModel{android.VariantInputKey: buildVariantEnv},\n+\t\t\t))\n+\t\t}\n+\n+\t\tif scanner.iosScanner != nil {\n+\t\t\tfor _, descriptor := range scanner.iosScanner.ConfigDescriptors {\n+\t\t\t\tconfigBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.CertificateAndProfileInstallerStepListItem())\n+\n+\t\t\t\tif descriptor.MissingSharedSchemes {\n+\t\t\t\t\tconfigBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.RecreateUserSchemesStepListItem(\n+\t\t\t\t\t\tenvmanModels.EnvironmentItemModel{ios.ProjectPathInputKey: \"$\" + ios.ProjectPathInputEnvKey},\n+\t\t\t\t\t))\n+\t\t\t\t}\n+\n+\t\t\t\tif descriptor.HasPodfile {\n+\t\t\t\t\tconfigBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.CocoapodsInstallStepListItem())\n+\t\t\t\t}\n+\n+\t\t\t\tif descriptor.CarthageCommand != \"\" {\n+\t\t\t\t\tconfigBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.CarthageStepListItem(\n+\t\t\t\t\t\tenvmanModels.EnvironmentItemModel{ios.CarthageCommandInputKey: descriptor.CarthageCommand},\n+\t\t\t\t\t))\n+\t\t\t\t}\n+\n+\t\t\t\tconfigBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.XcodeArchiveStepListItem(\n+\t\t\t\t\tenvmanModels.EnvironmentItemModel{ios.ProjectPathInputKey: \"$\" + ios.ProjectPathInputEnvKey},\n+\t\t\t\t\tenvmanModels.EnvironmentItemModel{ios.SchemeInputKey: \"$\" + ios.SchemeInputEnvKey},\n+\t\t\t\t\tenvmanModels.EnvironmentItemModel{ios.ExportMethodInputKey: \"$\" + ios.ExportMethodInputEnvKey},\n+\t\t\t\t\tenvmanModels.EnvironmentItemModel{ios.ConfigurationInputKey: \"Release\"},\n+\t\t\t\t))\n+\n+\t\t\t\tconfigBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultDeployStepList(false)...)\n+\n+\t\t\t\tbitriseDataModel, err := configBuilder.Generate(Name)\n+\t\t\t\tif err != nil {\n+\t\t\t\t\treturn models.BitriseConfigMap{}, err\n+\t\t\t\t}\n+\n+\t\t\t\tdata, err := yaml.Marshal(bitriseDataModel)\n+\t\t\t\tif err != nil {\n+\t\t\t\t\treturn models.BitriseConfigMap{}, err\n+\t\t\t\t}\n+\n+\t\t\t\tconfigName := configName(scanner.androidScanner != nil, true, false)\n+\t\t\t\tconfigMap[configName] = string(data)\n+\t\t\t}\n+\t\t} else {\n+\t\t\tconfigBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultDeployStepList(false)...)\n+\n+\t\t\tbitriseDataModel, err := configBuilder.Generate(Name)\n+\t\t\tif err != nil {\n+\t\t\t\treturn models.BitriseConfigMap{}, err\n+\t\t\t}\n+\n+\t\t\tdata, err := yaml.Marshal(bitriseDataModel)\n+\t\t\tif err != nil {\n+\t\t\t\treturn models.BitriseConfigMap{}, err\n+\t\t\t}\n+\n+\t\t\tconfigName := configName(scanner.androidScanner != nil, false, false)\n+\t\t\tconfigMap[configName] = string(data)\n+\t\t}\n+\t}\n+\n+\treturn configMap, nil\n+}\n+\n+// DefaultConfigs ...\n+func (Scanner) DefaultConfigs() (models.BitriseConfigMap, error) {\n+\tconfigBuilder := models.NewDefaultConfigBuilder()\n+\n+\t// ci\n+\tconfigBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultPrepareStepList(false)...)\n+\tconfigBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.NpmStepListItem(envmanModels.EnvironmentItemModel{\"command\": \"install\"}))\n+\tconfigBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.NpmStepListItem(envmanModels.EnvironmentItemModel{\"command\": \"test\"}))\n+\tconfigBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultDeployStepList(false)...)\n+\n+\t// cd\n+\tconfigBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultPrepareStepList(false)...)\n+\tconfigBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.NpmStepListItem(envmanModels.EnvironmentItemModel{\"command\": \"install\"}))\n+\n+\t// eject\n+\tconfigBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.NpmStepListItem(envmanModels.EnvironmentItemModel{\"command\": \"run eject\"}))\n+\n+\t// android\n+\tprojectLocationEnv, moduleEnv, buildVariantEnv := \"$\"+android.ProjectLocationInputEnvKey, \"$\"+android.ModuleInputEnvKey, \"$\"+android.BuildVariantInputEnvKey\n+\n+\tconfigBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.InstallMissingAndroidToolsStepListItem())\n+\tconfigBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.AndroidBuildStepListItem(\n+\t\tenvmanModels.EnvironmentItemModel{android.ProjectLocationInputKey: projectLocationEnv},\n+\t\tenvmanModels.EnvironmentItemModel{android.ModuleInputKey: moduleEnv},\n+\t\tenvmanModels.EnvironmentItemModel{android.VariantInputKey: buildVariantEnv},\n+\t))\n+\n+\t// ios\n+\tconfigBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.CertificateAndProfileInstallerStepListItem())\n+\tconfigBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.XcodeArchiveStepListItem(\n+\t\tenvmanModels.EnvironmentItemModel{ios.ProjectPathInputKey: \"$\" + ios.ProjectPathInputEnvKey},\n+\t\tenvmanModels.EnvironmentItemModel{ios.SchemeInputKey: \"$\" + ios.SchemeInputEnvKey},\n+\t\tenvmanModels.EnvironmentItemModel{ios.ExportMethodInputKey: \"$\" + ios.ExportMethodInputEnvKey},\n+\t\tenvmanModels.EnvironmentItemModel{ios.ConfigurationInputKey: \"Release\"},\n+\t))\n+\n+\tconfigBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultDeployStepList(false)...)\n+\n+\tbitriseDataModel, err := configBuilder.Generate(Name)\n+\tif err != nil {\n+\t\treturn models.BitriseConfigMap{}, err\n+\t}\n+\n+\tdata, err := yaml.Marshal(bitriseDataModel)\n+\tif err != nil {\n+\t\treturn models.BitriseConfigMap{}, err\n+\t}\n+\n+\tconfigName := defaultConfigName()\n+\tconfigMap := models.BitriseConfigMap{\n+\t\tconfigName: string(data),\n+\t}\n+\treturn configMap, nil\n+}\n+\n+// ExcludedScannerNames ...\n+func (Scanner) ExcludedScannerNames() []string {\n+\treturn []string{\n+\t\treactnative.Name,\n+\t\tstring(ios.XcodeProjectTypeIOS),\n+\t\tstring(ios.XcodeProjectTypeMacOS),\n+\t\tandroid.ScannerName,\n+\t}\n+}\n+\n+func ensureNodeModules(cmdDir string) error {\n+\tlog.Infof(\"Npm install\")\n+\n+\tcmd := command.New(\"npm\", \"install\")\n+\tcmd.SetStdout(os.Stdout)\n+\tcmd.SetStderr(os.Stderr)\n+\tcmd.SetDir(cmdDir)\n+\treturn cmd.Run()\n+}\n+\n+func ejectProject(pth string, cmdDir string) error {\n+\tlog.Infof(\"Eject project\")\n+\n+\tlineModification := LineModification{lastTime: time.Now(), answerCount: 0}\n+\tLastLineModification.Store(lineModification)\n+\n+\tcmd := exec.Command(\"npm\", \"run\", \"eject\")\n+\tcmd.Dir = cmdDir\n+\n+\tstdin, err := cmd.StdinPipe()\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\n+\tstdoutReader, err := cmd.StdoutPipe()\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\n+\tscanner := bufio.NewScanner(stdoutReader)\n+\tgo func() {\n+\t\tfor scanner.Scan() {\n+\t\t\tline := scanner.Text()\n+\t\t\tfmt.Println(line)\n+\n+\t\t\tlineModification, ok := LastLineModification.Load().(LineModification)\n+\t\t\tif !ok {\n+\t\t\t\tlog.Errorf(\"Error during casting LastLineModification to LineModification\")\n+\t\t\t\tbreak\n+\t\t\t}\n+\t\t\tlineModification.lastTime = time.Now()\n+\t\t\tLastLineModification.Store(lineModification)\n+\t\t}\n+\t}()\n+\n+\tch := make(chan bool)\n+\tstopWaiting := false\n+\tgo func(ch *chan bool) {\n+\t\tfor {\n+\t\t\tgo checkLastLineTime(ch)","path":"scanners/reactnative-expo/reactnative-expo.go","position":634,"original_position":634,"commit_id":"2681f257310f1b8d2d7e60a5801310acba708f18","original_commit_id":"2681f257310f1b8d2d7e60a5801310acba708f18","user":{"login":"godrei","id":12427060,"avatar_url":"https://avatars2.githubusercontent.com/u/12427060?v=4","gravatar_id":"","url":"https://api.github.com/users/godrei","html_url":"https://github.com/godrei","followers_url":"https://api.github.com/users/godrei/followers","following_url":"https://api.github.com/users/godrei/following{/other_user}","gists_url":"https://api.github.com/users/godrei/gists{/gist_id}","starred_url":"https://api.github.com/users/godrei/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/godrei/subscriptions","organizations_url":"https://api.github.com/users/godrei/orgs","repos_url":"https://api.github.com/users/godrei/repos","events_url":"https://api.github.com/users/godrei/events{/privacy}","received_events_url":"https://api.github.com/users/godrei/received_events","type":"User","site_admin":false},"body":"why do we do this in a new go routine?\r\n","created_at":"2018-05-25T12:43:31Z","updated_at":"2018-05-25T12:43:31Z","html_url":"https://github.com/bitrise-core/bitrise-init/pull/119#discussion_r190881805","pull_request_url":"https://api.github.com/repos/bitrise-core/bitrise-init/pulls/119","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/bitrise-core/bitrise-init/pulls/comments/190881805"},"html":{"href":"https://github.com/bitrise-core/bitrise-init/pull/119#discussion_r190881805"},"pull_request":{"href":"https://api.github.com/repos/bitrise-core/bitrise-init/pulls/119"}}},"pull_request":{"url":"https://api.github.com/repos/bitrise-core/bitrise-init/pulls/119","id":189707296,"html_url":"https://github.com/bitrise-core/bitrise-init/pull/119","diff_url":"https://github.com/bitrise-core/bitrise-init/pull/119.diff","patch_url":"https://github.com/bitrise-core/bitrise-init/pull/119.patch","issue_url":"https://api.github.com/repos/bitrise-core/bitrise-init/issues/119","number":119,"state":"open","locked":false,"title":"Reactnavite-expo scanner","user":{"login":"BirmacherAkos","id":37296013,"avatar_url":"https://avatars3.githubusercontent.com/u/37296013?v=4","gravatar_id":"","url":"https://api.github.com/users/BirmacherAkos","html_url":"https://github.com/BirmacherAkos","followers_url":"https://api.github.com/users/BirmacherAkos/followers","following_url":"https://api.github.com/users/BirmacherAkos/following{/other_user}","gists_url":"https://api.github.com/users/BirmacherAkos/gists{/gist_id}","starred_url":"https://api.github.com/users/BirmacherAkos/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/BirmacherAkos/subscriptions","organizations_url":"https://api.github.com/users/BirmacherAkos/orgs","repos_url":"https://api.github.com/users/BirmacherAkos/repos","events_url":"https://api.github.com/users/BirmacherAkos/events{/privacy}","received_events_url":"https://api.github.com/users/BirmacherAkos/received_events","type":"User","site_admin":false},"body":"","created_at":"2018-05-22T15:39:31Z","updated_at":"2018-05-25T12:43:31Z","closed_at":null,"merged_at":null,"merge_commit_sha":"1e61b72200eba8c895b6c22f23e3739a6a02a0a7","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/bitrise-core/bitrise-init/pulls/119/commits","review_comments_url":"https://api.github.com/repos/bitrise-core/bitrise-init/pulls/119/comments","review_comment_url":"https://api.github.com/repos/bitrise-core/bitrise-init/pulls/comments{/number}","comments_url":"https://api.github.com/repos/bitrise-core/bitrise-init/issues/119/comments","statuses_url":"https://api.github.com/repos/bitrise-core/bitrise-init/statuses/2681f257310f1b8d2d7e60a5801310acba708f18","head":{"label":"BirmacherAkos:fork-expo","ref":"fork-expo","sha":"2681f257310f1b8d2d7e60a5801310acba708f18","user":{"login":"BirmacherAkos","id":37296013,"avatar_url":"https://avatars3.githubusercontent.com/u/37296013?v=4","gravatar_id":"","url":"https://api.github.com/users/BirmacherAkos","html_url":"https://github.com/BirmacherAkos","followers_url":"https://api.github.com/users/BirmacherAkos/followers","following_url":"https://api.github.com/users/BirmacherAkos/following{/other_user}","gists_url":"https://api.github.com/users/BirmacherAkos/gists{/gist_id}","starred_url":"https://api.github.com/users/BirmacherAkos/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/BirmacherAkos/subscriptions","organizations_url":"https://api.github.com/users/BirmacherAkos/orgs","repos_url":"https://api.github.com/users/BirmacherAkos/repos","events_url":"https://api.github.com/users/BirmacherAkos/events{/privacy}","received_events_url":"https://api.github.com/users/BirmacherAkos/received_events","type":"User","site_admin":false},"repo":{"id":127910878,"name":"bitrise-init","full_name":"BirmacherAkos/bitrise-init","owner":{"login":"BirmacherAkos","id":37296013,"avatar_url":"https://avatars3.githubusercontent.com/u/37296013?v=4","gravatar_id":"","url":"https://api.github.com/users/BirmacherAkos","html_url":"https://github.com/BirmacherAkos","followers_url":"https://api.github.com/users/BirmacherAkos/followers","following_url":"https://api.github.com/users/BirmacherAkos/following{/other_user}","gists_url":"https://api.github.com/users/BirmacherAkos/gists{/gist_id}","starred_url":"https://api.github.com/users/BirmacherAkos/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/BirmacherAkos/subscriptions","organizations_url":"https://api.github.com/users/BirmacherAkos/orgs","repos_url":"https://api.github.com/users/BirmacherAkos/repos","events_url":"https://api.github.com/users/BirmacherAkos/events{/privacy}","received_events_url":"https://api.github.com/users/BirmacherAkos/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/BirmacherAkos/bitrise-init","description":null,"fork":true,"url":"https://api.github.com/repos/BirmacherAkos/bitrise-init","forks_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/forks","keys_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/keys{/key_id}","collaborators_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/teams","hooks_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/hooks","issue_events_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/issues/events{/number}","events_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/events","assignees_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/assignees{/user}","branches_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/branches{/branch}","tags_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/tags","blobs_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/git/refs{/sha}","trees_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/git/trees{/sha}","statuses_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/statuses/{sha}","languages_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/languages","stargazers_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/stargazers","contributors_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/contributors","subscribers_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/subscribers","subscription_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/subscription","commits_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/commits{/sha}","git_commits_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/git/commits{/sha}","comments_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/comments{/number}","issue_comment_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/issues/comments{/number}","contents_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/contents/{+path}","compare_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/compare/{base}...{head}","merges_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/merges","archive_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/downloads","issues_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/issues{/number}","pulls_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/pulls{/number}","milestones_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/milestones{/number}","notifications_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/labels{/name}","releases_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/releases{/id}","deployments_url":"https://api.github.com/repos/BirmacherAkos/bitrise-init/deployments","created_at":"2018-04-03T13:15:46Z","updated_at":"2018-04-03T13:15:48Z","pushed_at":"2018-05-23T13:44:30Z","git_url":"git://github.com/BirmacherAkos/bitrise-init.git","ssh_url":"git@github.com:BirmacherAkos/bitrise-init.git","clone_url":"https://github.com/BirmacherAkos/bitrise-init.git","svn_url":"https://github.com/BirmacherAkos/bitrise-init","homepage":null,"size":5678,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":null,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"bitrise-core:master","ref":"master","sha":"ec5a40fe768beac9379ac94b8cd9d1bbbfb3d746","user":{"login":"bitrise-core","id":16164690,"avatar_url":"https://avatars0.githubusercontent.com/u/16164690?v=4","gravatar_id":"","url":"https://api.github.com/users/bitrise-core","html_url":"https://github.com/bitrise-core","followers_url":"https://api.github.com/users/bitrise-core/followers","following_url":"https://api.github.com/users/bitrise-core/following{/other_user}","gists_url":"https://api.github.com/users/bitrise-core/gists{/gist_id}","starred_url":"https://api.github.com/users/bitrise-core/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bitrise-core/subscriptions","organizations_url":"https://api.github.com/users/bitrise-core/orgs","repos_url":"https://api.github.com/users/bitrise-core/repos","events_url":"https://api.github.com/users/bitrise-core/events{/privacy}","received_events_url":"https://api.github.com/users/bitrise-core/received_events","type":"Organization","site_admin":false},"repo":{"id":58053710,"name":"bitrise-init","full_name":"bitrise-core/bitrise-init","owner":{"login":"bitrise-core","id":16164690,"avatar_url":"https://avatars0.githubusercontent.com/u/16164690?v=4","gravatar_id":"","url":"https://api.github.com/users/bitrise-core","html_url":"https://github.com/bitrise-core","followers_url":"https://api.github.com/users/bitrise-core/followers","following_url":"https://api.github.com/users/bitrise-core/following{/other_user}","gists_url":"https://api.github.com/users/bitrise-core/gists{/gist_id}","starred_url":"https://api.github.com/users/bitrise-core/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bitrise-core/subscriptions","organizations_url":"https://api.github.com/users/bitrise-core/orgs","repos_url":"https://api.github.com/users/bitrise-core/repos","events_url":"https://api.github.com/users/bitrise-core/events{/privacy}","received_events_url":"https://api.github.com/users/bitrise-core/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/bitrise-core/bitrise-init","description":null,"fork":false,"url":"https://api.github.com/repos/bitrise-core/bitrise-init","forks_url":"https://api.github.com/repos/bitrise-core/bitrise-init/forks","keys_url":"https://api.github.com/repos/bitrise-core/bitrise-init/keys{/key_id}","collaborators_url":"https://api.github.com/repos/bitrise-core/bitrise-init/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/bitrise-core/bitrise-init/teams","hooks_url":"https://api.github.com/repos/bitrise-core/bitrise-init/hooks","issue_events_url":"https://api.github.com/repos/bitrise-core/bitrise-init/issues/events{/number}","events_url":"https://api.github.com/repos/bitrise-core/bitrise-init/events","assignees_url":"https://api.github.com/repos/bitrise-core/bitrise-init/assignees{/user}","branches_url":"https://api.github.com/repos/bitrise-core/bitrise-init/branches{/branch}","tags_url":"https://api.github.com/repos/bitrise-core/bitrise-init/tags","blobs_url":"https://api.github.com/repos/bitrise-core/bitrise-init/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/bitrise-core/bitrise-init/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/bitrise-core/bitrise-init/git/refs{/sha}","trees_url":"https://api.github.com/repos/bitrise-core/bitrise-init/git/trees{/sha}","statuses_url":"https://api.github.com/repos/bitrise-core/bitrise-init/statuses/{sha}","languages_url":"https://api.github.com/repos/bitrise-core/bitrise-init/languages","stargazers_url":"https://api.github.com/repos/bitrise-core/bitrise-init/stargazers","contributors_url":"https://api.github.com/repos/bitrise-core/bitrise-init/contributors","subscribers_url":"https://api.github.com/repos/bitrise-core/bitrise-init/subscribers","subscription_url":"https://api.github.com/repos/bitrise-core/bitrise-init/subscription","commits_url":"https://api.github.com/repos/bitrise-core/bitrise-init/commits{/sha}","git_commits_url":"https://api.github.com/repos/bitrise-core/bitrise-init/git/commits{/sha}","comments_url":"https://api.github.com/repos/bitrise-core/bitrise-init/comments{/number}","issue_comment_url":"https://api.github.com/repos/bitrise-core/bitrise-init/issues/comments{/number}","contents_url":"https://api.github.com/repos/bitrise-core/bitrise-init/contents/{+path}","compare_url":"https://api.github.com/repos/bitrise-core/bitrise-init/compare/{base}...{head}","merges_url":"https://api.github.com/repos/bitrise-core/bitrise-init/merges","archive_url":"https://api.github.com/repos/bitrise-core/bitrise-init/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/bitrise-core/bitrise-init/downloads","issues_url":"https://api.github.com/repos/bitrise-core/bitrise-init/issues{/number}","pulls_url":"https://api.github.com/repos/bitrise-core/bitrise-init/pulls{/number}","milestones_url":"https://api.github.com/repos/bitrise-core/bitrise-init/milestones{/number}","notifications_url":"https://api.github.com/repos/bitrise-core/bitrise-init/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/bitrise-core/bitrise-init/labels{/name}","releases_url":"https://api.github.com/repos/bitrise-core/bitrise-init/releases{/id}","deployments_url":"https://api.github.com/repos/bitrise-core/bitrise-init/deployments","created_at":"2016-05-04T13:20:41Z","updated_at":"2018-05-23T14:57:03Z","pushed_at":"2018-05-23T15:11:20Z","git_url":"git://github.com/bitrise-core/bitrise-init.git","ssh_url":"git@github.com:bitrise-core/bitrise-init.git","clone_url":"https://github.com/bitrise-core/bitrise-init.git","svn_url":"https://github.com/bitrise-core/bitrise-init","homepage":null,"size":5657,"stargazers_count":2,"watchers_count":2,"language":"Go","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":7,"mirror_url":null,"archived":false,"open_issues_count":4,"license":null,"forks":7,"open_issues":4,"watchers":2,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/bitrise-core/bitrise-init/pulls/119"},"html":{"href":"https://github.com/bitrise-core/bitrise-init/pull/119"},"issue":{"href":"https://api.github.com/repos/bitrise-core/bitrise-init/issues/119"},"comments":{"href":"https://api.github.com/repos/bitrise-core/bitrise-init/issues/119/comments"},"review_comments":{"href":"https://api.github.com/repos/bitrise-core/bitrise-init/pulls/119/comments"},"review_comment":{"href":"https://api.github.com/repos/bitrise-core/bitrise-init/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/bitrise-core/bitrise-init/pulls/119/commits"},"statuses":{"href":"https://api.github.com/repos/bitrise-core/bitrise-init/statuses/2681f257310f1b8d2d7e60a5801310acba708f18"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"godrei"}}