Example #1
0
 public PublishCommand(
     IBuildConfigurationBuilder buildConfigurationBuilder,
     IConfigurationFileMerger configurationFileMerger,
     IConfigurationFileValidator configurationFileValidator,
     IConfigurationFileUploader configurationFileUploader,
     IStaticAssetProcessor staticAssetProcessor,
     IAccessor <S3AssetHostConfiguration> assetHostConfigurationAccessor)
 {
     _buildConfigurationBuilder      = buildConfigurationBuilder.ThrowIfNull(nameof(buildConfigurationBuilder));
     _configurationFileUploader      = configurationFileUploader.ThrowIfNull(nameof(configurationFileUploader));
     _configurationFileMerger        = configurationFileMerger.ThrowIfNull(nameof(configurationFileMerger));
     _configurationFileValidator     = configurationFileValidator.ThrowIfNull(nameof(configurationFileValidator));
     _staticAssetProcessor           = staticAssetProcessor.ThrowIfNull(nameof(staticAssetProcessor));
     _assetHostConfigurationAccessor = assetHostConfigurationAccessor.ThrowIfNull(nameof(assetHostConfigurationAccessor));
 }
Example #2
0
        public static async Task <int> Build(MarvelMicroserviceConfig config, string publishedRuntimeImageName, BuildConfig buildConfig, IStaticAssetProcessor staticAssetProcessor)
        {
            var buildImageUri = await EcrResources.DotnetMicroserviceBuildImageUrl.EnsureImageIsPulled();

            if (!buildImageUri.WasSuccessful)
            {
                return(1);
            }

            var taskTimer = Stopwatch.StartNew();

            // Clear the old temp dir to ensure a fresh publish if running locally
            var outputPath = config.DotnetPublishOutputPath;

            if (Directory.Exists(outputPath))
            {
                Directory.Delete(outputPath, true);
            }
            Directory.CreateDirectory(outputPath);

            var dockerRunOptions = new List <string>
            {
                $"--rm",
                $"-e \"{LaunchCommand.ProjectNameEnvVariable}={config.ProjectName}\"",
                $"-e \"{LaunchCommand.SolutionNameEnvVariable}={config.SolutionName}\"",
                $"-e \"{WebappDirEnvVariable}={ContainerPaths.GetWebappDirectory(config)}\"",
                $"-e \"{BrowserAppDirEnvVariable}={ContainerPaths.GetBrowserAppDirectory(config)}\"",
                $"-v {config.BaseDirectory}:{ContainerPaths.MountedSourceDirectory}",
                $"-v {outputPath}:{ContainerPaths.BuildOutputDirectory}",
            };

            var runtimeImageLabelsTask = new LabelBuilder(config).GetLabels(buildConfig);

            var exitCode = 0;

            var dotnetBuildTimer = Stopwatch.StartNew();

            Output.Info($"Building dotnet webapp.");

            // Run container to build app and copy published resources to mounted output directory
            exitCode = CommandUtilities.ExecuteCommand("docker", $"run {string.Join(" ", dockerRunOptions)} {buildImageUri.Value} /bin/bash {ContainerPaths.DockerTaskScriptPath} buildWithoutCompose");
            if (exitCode != 0)
            {
                return(exitCode);
            }
            Output.Info($"dotnet webapp build completed {dotnetBuildTimer.Elapsed}");

            // Run static asset build from output directory
            await staticAssetProcessor.ProcessStaticAssets(Path.Combine(config.DotnetPublishOutputPath, "wwwroot"));

            // Build the image from the source output
            var dockerBuildTimer = Stopwatch.StartNew();

            Output.Info($"Building docker image {publishedRuntimeImageName}.");

            var labelArgs = LabelUtilities.FormatLabelsAsArguments(await runtimeImageLabelsTask);

            var buildArgs = labelArgs.Concat(new List <string> {
                $"-t {publishedRuntimeImageName}",
                $"--build-arg webappAssemblyPath={config.PublishedWebappAssemblyPath}",
                config.DotnetPublishOutputPath,
            });

            exitCode = CommandUtilities.ExecuteCommand("docker", $"build {string.Join(" ", buildArgs)}");
            if (exitCode != 0)
            {
                return(exitCode);
            }
            Output.Info($"Docker build completed {dockerBuildTimer.Elapsed}");

            Output.Info($"Build time elapsed {taskTimer.Elapsed}");

            return(exitCode);
        }
Example #3
0
 public BuildCommand(IStaticAssetProcessor staticAssetProcessor, IAccessor <S3AssetHostConfiguration> assetHostConfigurationAccessor)
 {
     _staticAssetProcessor           = staticAssetProcessor.ThrowIfNull(nameof(staticAssetProcessor));
     _assetHostConfigurationAccessor = assetHostConfigurationAccessor.ThrowIfNull(nameof(assetHostConfigurationAccessor));
 }
Example #4
0
        internal static async Task <int> Publish(MarvelMicroserviceConfig config, IBuildConfigurationBuilder configBuilder, IConfigurationFileMerger configMerger, IConfigurationFileUploader configUploader, IConfigurationFileValidator configValidator, IStaticAssetProcessor staticAssetProcessor, string nugetApiKey, string awsAccessKey, string awsAccessSecret, string branch, string gitSha, string buildNumber, bool mergeAndUploadServiceConfig, bool mergeServiceConfig)
        {
            Security.UseAwsCredentials(awsAccessKey, awsAccessSecret);

            var publishImage = ImageNameBuilder.CreateImageNameAndTag(
                config.ServiceName,
                branch,
                gitSha,
                DateTime.UtcNow,
                buildNumber);

            string[] serviceConfigFiles = null;
            if (mergeAndUploadServiceConfig || mergeServiceConfig)
            {
                GenerateBuildFile(configBuilder, config.BuildConfigFilePath, gitSha, branch, publishImage.FullPath, buildNumber);
                serviceConfigFiles = await MergeAllServiceConfigFiles(configMerger, config.SourceDirectory, config.ServiceConfigFileName, config.BuildConfigFilePath);

                var configIsValid = await ValidateAllServiceConfigFiles(configValidator, config.SourceDirectory, serviceConfigFiles);

                if (!configIsValid)
                {
                    Output.Error("Invalid service configuration.");
                    return(1);
                }
            }

            var exitCode = await BuildCommand.Build(config, publishImage.FullPath, new BuildConfig
            {
                BranchName  = branch,
                BuildNumber = buildNumber,
            }, staticAssetProcessor);

            if (exitCode != 0)
            {
                return(exitCode);
            }

            try
            {
                exitCode = PublishClientPackage(config, nugetApiKey, awsAccessKey, awsAccessSecret, branch, gitSha, buildNumber);
                if (exitCode != 0)
                {
                    return(exitCode);
                }

                // Publish to ECR
                Output.Info($"Publishing {publishImage.FullPath}");
                await Security.EnsureAuthenticatedWithEcr();

                exitCode = CommandUtilities.ExecuteCommand("docker", $"push {publishImage.FullPath}");
                if (exitCode != 0)
                {
                    return(exitCode);
                }
            }
            finally
            {
                // TODO always remove image, even on publish failure
                await CommandUtilities.RunCommandAsync("docker", $"rmi {publishImage.FullPath}", errorMessage : $"Failed to remove image {publishImage.FullPath}.");

                Output.Info($"Removed local image {publishImage.FullPath}");
            }

            try
            {
                if (mergeAndUploadServiceConfig && serviceConfigFiles != null)
                {
                    await UploadAllServiceConfigFiles(configUploader, config.SourceDirectory, serviceConfigFiles, publishImage.Tag);
                }
            }
            catch (Exception ex)
            {
                Output.Error($"Unable to upload service configuration files. Error: {ex.Message}");
                return(1);
            }

            File.WriteAllText(Path.Combine(config.WebappDirectory, "PublishedImageUrl.txt"), publishImage.FullPath);
            Output.Info("Publish successful");
            return(0);
        }