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,
};
}