public BuildScriptSnippet GenerateBashBuildScriptSnippet()

in src/BuildScriptGenerator/Node/NodePlatform.cs [146:397]


        public BuildScriptSnippet GenerateBashBuildScriptSnippet(
            BuildScriptGeneratorContext ctx,
            PlatformDetectorResult detectorResult)
        {
            var nodePlatformDetectorResult = detectorResult as NodePlatformDetectorResult;
            if (nodePlatformDetectorResult == null)
            {
                throw new ArgumentException(
                    $"Expected '{nameof(detectorResult)}' argument to be of type " +
                    $"'{typeof(NodePlatformDetectorResult)}' but got '{detectorResult.GetType()}'.");
            }

            var manifestFileProperties = new Dictionary<string, string>();
            var nodeCommandManifestFileProperties = new Dictionary<string, string>();
            var nodeBuildCommandsFile = string.IsNullOrEmpty(_commonOptions.BuildCommandsFileName) ?
                    FilePaths.BuildCommandsFileName : _commonOptions.BuildCommandsFileName;
            nodeBuildCommandsFile = string.IsNullOrEmpty(_commonOptions.ManifestDir) ?
                Path.Combine(ctx.SourceRepo.RootPath, nodeBuildCommandsFile) :
                Path.Combine(_commonOptions.ManifestDir, nodeBuildCommandsFile);

            // Write the platform name and version to the manifest file
            manifestFileProperties[ManifestFilePropertyKeys.NodeVersion] = nodePlatformDetectorResult.PlatformVersion;
            manifestFileProperties[nameof(nodeBuildCommandsFile)] = nodeBuildCommandsFile;
            nodeCommandManifestFileProperties["PlatformWithVersion"] = "Node.js " + nodePlatformDetectorResult.PlatformVersion;
            var packageJson = GetPackageJsonObject(ctx.SourceRepo, _logger);
            string runBuildCommand = null;
            string runBuildAzureCommand = null;
            string runBuildLernaCommand = null;
            string runBuildLageCommand = null;
            string installLernaCommand = null;
            bool configureYarnCache = false;
            string packageManagerCmd = null;
            string packageInstallCommand = null;
            string packageInstallerVersionCommand = null;

            if (_nodeScriptGeneratorOptions.EnableNodeMonorepoBuild &&
                nodePlatformDetectorResult.HasLernaJsonFile &&
                nodePlatformDetectorResult.HasLageConfigJSFile)
            {
                _logger.LogError(
                "Could not build monorepo with multiple package management tools. Both 'lerna.json' and 'lage.config.js' files are found.");
                throw new InvalidUsageException("Multiple monorepo package management tools are found, please choose to use either Lerna or Lage.");
            }

            if (ctx.SourceRepo.FileExists(NodeConstants.YarnLockFileName) || packageJson?.engines?.yarn != null)
            {
                packageManagerCmd = NodeConstants.YarnCommand;
                configureYarnCache = false;
                packageInstallerVersionCommand = NodeConstants.YarnVersionCommand;

                // In Yarn 2+ and .yarnrc.yml file replaces .yarnrc in Yarn 2+.
                // Applying yarn 2 cache folder name and package install command.
                if (nodePlatformDetectorResult.HasYarnrcYmlFile)
                {
                    packageInstallCommand = NodeConstants.Yarn2PackageInstallCommand;
                }
                else
                {
                    packageInstallCommand = NodeConstants.YarnPackageInstallCommand;
                }
            }
            else
            {
                packageManagerCmd = NodeConstants.NpmCommand;
                packageInstallCommand = NodeConstants.NpmPackageInstallCommand;
                packageInstallerVersionCommand = NodeConstants.NpmVersionCommand;
            }

            if (_nodeScriptGeneratorOptions.EnableNodeMonorepoBuild)
            {
                // If a 'lerna.json' file exists, override the npm client that lerna chosen to build monorepo.
                if (nodePlatformDetectorResult.HasLernaJsonFile)
                {
                    packageManagerCmd = nodePlatformDetectorResult.LernaNpmClient;
                    runBuildLernaCommand = string.Format(
                            NodeConstants.PkgMgrRunBuildCommandTemplate,
                            NodeConstants.LernaCommand);
                    if (!string.IsNullOrEmpty(nodePlatformDetectorResult.LernaNpmClient)
                        && nodePlatformDetectorResult.LernaNpmClient.Equals(
                        NodeConstants.YarnCommand, StringComparison.OrdinalIgnoreCase))
                    {
                        packageInstallCommand = NodeConstants.YarnPackageInstallCommand;
                        configureYarnCache = false;
                        packageInstallerVersionCommand = NodeConstants.YarnVersionCommand;
                        installLernaCommand = NodeConstants.InstallLernaCommandYarn;
                    }
                    else
                    {
                        packageInstallCommand = NodeConstants.NpmPackageInstallCommand;
                        packageInstallerVersionCommand = NodeConstants.NpmVersionCommand;
                        installLernaCommand = NodeConstants.InstallLernaCommandNpm;
                    }
                }

                // If a 'lage.config.js' file exits, run build using lage specifc commands.
                if (nodePlatformDetectorResult.HasLageConfigJSFile)
                {
                    runBuildLageCommand = ctx.SourceRepo.FileExists(NodeConstants.YarnLockFileName) ?
                            NodeConstants.YarnRunLageBuildCommand : NodeConstants.NpmRunLageBuildCommand;
                }
            }

            _logger.LogInformation("Using {packageManager}", packageManagerCmd);

            var hasProdDependencies = false;
            if (packageJson?.dependencies != null)
            {
                hasProdDependencies = true;
            }

            var hasDevDependencies = false;
            if (packageJson?.devDependencies != null)
            {
                // If development time dependencies are present we want to avoid copying them to improve performance
                hasDevDependencies = true;
            }

            var productionOnlyPackageInstallCommand = string.Format(
                NodeConstants.ProductionOnlyPackageInstallCommandTemplate, packageInstallCommand);

            if (string.IsNullOrEmpty(_nodeScriptGeneratorOptions.CustomBuildCommand)
                && string.IsNullOrEmpty(_nodeScriptGeneratorOptions.CustomRunBuildCommand)
                && string.IsNullOrEmpty(runBuildLernaCommand)
                && string.IsNullOrEmpty(runBuildLageCommand))
            {
                var scriptsNode = packageJson?.scripts;
                if (scriptsNode != null)
                {
                    if (scriptsNode.build != null)
                    {
                        runBuildCommand = string.Format(NodeConstants.PkgMgrRunBuildCommandTemplate, packageManagerCmd);
                    }

                    if (scriptsNode["build:azure"] != null && !_commonOptions.ShouldPackage)
                    {
                        runBuildAzureCommand = string.Format(
                            NodeConstants.PkgMgrRunBuildAzureCommandTemplate,
                            packageManagerCmd);
                    }
                }
            }

            if (IsBuildRequired(ctx)
                && string.IsNullOrEmpty(_nodeScriptGeneratorOptions.CustomBuildCommand)
                && string.IsNullOrEmpty(_nodeScriptGeneratorOptions.CustomRunBuildCommand)
                && string.IsNullOrEmpty(runBuildCommand)
                && string.IsNullOrEmpty(runBuildAzureCommand)
                && string.IsNullOrEmpty(runBuildLernaCommand)
                && string.IsNullOrEmpty(runBuildLageCommand))
            {
                throw new NoBuildStepException(
                    "Could not find either 'build' or 'build:azure' node under 'scripts' in package.json. " +
                    "Could not find value for custom run build command using the environment variable " +
                    "key 'RUN_BUILD_COMMAND'." +
                    "Could not find tools for building monorepos, no 'lerna.json' or 'lage.config.js' files found.");
            }

            if (packageJson?.dependencies != null)
            {
                var depSpecs = ((JObject)packageJson.dependencies).ToObject<IDictionary<string, string>>();
                _logger.LogDependencies(
                    _commonOptions.PlatformName,
                    nodePlatformDetectorResult.PlatformVersion,
                    depSpecs.Select(d => d.Key + d.Value));
            }

            if (packageJson?.devDependencies != null)
            {
                var depSpecs = ((JObject)packageJson.devDependencies).ToObject<IDictionary<string, string>>();
                _logger.LogDependencies(
                    _commonOptions.PlatformName,
                    nodePlatformDetectorResult.PlatformVersion,
                    depSpecs.Select(d => d.Key + d.Value), true);
            }

            string compressNodeModulesCommand = null;
            string compressedNodeModulesFileName = null;
            GetNodeModulesPackOptions(ctx, out compressNodeModulesCommand, out compressedNodeModulesFileName);

            if (!string.IsNullOrWhiteSpace(compressedNodeModulesFileName))
            {
                manifestFileProperties[NodeConstants.NodeModulesFileBuildProperty] = compressedNodeModulesFileName;
            }

            bool pruneDevDependencies = ShouldPruneDevDependencies(ctx);
            string appInsightsInjectCommand = string.Empty;

            GetAppOutputDirPath(packageJson, manifestFileProperties);

            string customRegistryUrl = null;
            if (ctx.Properties != null)
            {
                ctx.Properties.TryGetValue(RegistryUrlPropertyKey, out customRegistryUrl);
                if (!string.IsNullOrWhiteSpace(customRegistryUrl))
                {
                    // Write the custom registry to the build manifest
                    manifestFileProperties[$"{NodeConstants.PlatformName}_{RegistryUrlPropertyKey}"] = customRegistryUrl;
                }
            }

            string packageDir = null;
            if (ctx.Properties != null)
            {
                ctx.Properties.TryGetValue(PackageDirectoryPropertyKey, out packageDir);
                if (!string.IsNullOrWhiteSpace(packageDir))
                {
                    // Write the package directory to the build manifest
                    manifestFileProperties[$"{PackageDirectoryPropertyKey}"] = packageDir;
                }
            }

            var scriptProps = new NodeBashBuildSnippetProperties
            {
                PackageRegistryUrl = customRegistryUrl,
                PackageDirectory = packageDir,
                PackageInstallCommand = packageInstallCommand,
                NpmRunBuildCommand = runBuildCommand,
                NpmRunBuildAzureCommand = runBuildAzureCommand,
                HasProdDependencies = hasProdDependencies,
                HasDevDependencies = hasDevDependencies,
                ProductionOnlyPackageInstallCommand = productionOnlyPackageInstallCommand,
                CompressNodeModulesCommand = compressNodeModulesCommand,
                CompressedNodeModulesFileName = compressedNodeModulesFileName,
                ConfigureYarnCache = configureYarnCache,
                PruneDevDependencies = pruneDevDependencies,
                AppInsightsInjectCommand = appInsightsInjectCommand,
                AppInsightsPackageName = NodeConstants.NodeAppInsightsPackageName,
                AppInsightsLoaderFileName = NodeAppInsightsLoader.NodeAppInsightsLoaderFileName,
                PackageInstallerVersionCommand = packageInstallerVersionCommand,
                RunNpmPack = _commonOptions.ShouldPackage,
                CustomBuildCommand = _nodeScriptGeneratorOptions.CustomBuildCommand,
                CustomRunBuildCommand = _nodeScriptGeneratorOptions.CustomRunBuildCommand,
                LernaRunBuildCommand = runBuildLernaCommand,
                InstallLernaCommand = installLernaCommand,
                LernaInitCommand = NodeConstants.LernaInitCommand,
                LernaBootstrapCommand = NodeConstants.LernaBootstrapCommand,
                InstallLageCommand = NodeConstants.InstallLageCommand,
                LageRunBuildCommand = runBuildLageCommand,
                NodeBuildProperties = nodeCommandManifestFileProperties,
                NodeBuildCommandsFile = nodeBuildCommandsFile,
            };
            string script = TemplateHelper.Render(
                TemplateHelper.TemplateResource.NodeBuildSnippet,
                scriptProps,
                _logger);

            return new BuildScriptSnippet
            {
                BashBuildScriptSnippet = script,
                BuildProperties = manifestFileProperties,
            };
        }