private static async Task DeployApplicationManifestAsync(OutputContext output, ApplicationBuilder application, string applicationName, string environment) { using var step = output.BeginStep("Deploying Application Manifests..."); using var tempFile = TempFile.Create(); output.WriteInfoLine($"Writing output to '{tempFile.FilePath}'."); { using var stream = File.OpenWrite(tempFile.FilePath); using var writer = new StreamWriter(stream, Encoding.UTF8, leaveOpen: true); await ApplicationYamlWriter.WriteAsync(output, writer, application); } output.WriteDebugLine("Running 'kubectl apply'."); output.WriteCommandLine("kubectl", $"apply -f \"{tempFile.FilePath}\""); var capture = output.Capture(); var exitCode = await Process.ExecuteAsync( $"kubectl", $"apply -f \"{tempFile.FilePath}\"", System.Environment.CurrentDirectory, stdOut : capture.StdOut, stdErr : capture.StdErr); output.WriteDebugLine($"Done running 'kubectl apply' exit code: {exitCode}"); if (exitCode != 0) { throw new CommandException("'kubectl apply' failed."); } output.WriteInfoLine($"Deployed application '{applicationName}'."); step.MarkComplete(); }
public override async Task ExecuteAsync(OutputContext output, ApplicationBuilder application, ServiceBuilder service) { if (SkipWithoutDotnetProject(output, service, out var project)) { return; } if (SkipWithoutContainerInfo(output, service, out var container)) { return; } if (container.UseMultiphaseDockerfile != false) { return; } // NOTE: we're intentionally not cleaning up here. It's the responsibility of whomever consumes // the publish output to do cleanup. var outputDirectory = TempDirectory.Create(); output.WriteDebugLine("Running 'dotnet publish'."); var dotnetPublishArguments = project.BuildProperties.TryGetValue("TargetFramework", out var framework) ? $"publish \"{project.ProjectFile.FullName}\" -c Release -f {framework} -o \"{outputDirectory.DirectoryPath}\" /nologo" : $"publish \"{project.ProjectFile.FullName}\" -c Release -o \"{outputDirectory.DirectoryPath}\" /nologo"; output.WriteCommandLine("dotnet", dotnetPublishArguments); var publishResult = await ProcessUtil.RunAsync( $"dotnet", dotnetPublishArguments, project.ProjectFile.DirectoryName, throwOnError : false); output.WriteDebugLine($"Done running 'dotnet publish' exit code: {publishResult.ExitCode}"); if (publishResult.ExitCode != 0) { outputDirectory.Dispose(); output.WriteInfoLine($"'dotnet publish' failed. Error:"); foreach (var line in publishResult.StandardOutput.Split(Environment.NewLine)) { output.WriteInfoLine(line); } foreach (var line in publishResult.StandardError.Split(Environment.NewLine)) { output.WriteInfoLine(line); } throw new CommandException("'dotnet publish' failed."); } output.WriteDebugLine($"Created Publish Output: '{outputDirectory.DirectoryPath}'"); service.Outputs.Add(new ProjectPublishOutput(outputDirectory.DirectoryInfo)); }
public override async Task ExecuteAsync(OutputContext output, ApplicationBuilder application) { using var step = output.BeginStep(""); if (!await KubectlDetector.IsKubectlInstalledAsync(output)) { throw new CommandException($"Cannot apply manifests because kubectl is not installed."); } if (!await KubectlDetector.IsKubectlConnectedToClusterAsync(output)) { throw new CommandException($"Cannot apply manifests because kubectl is not connected to a cluster."); } using var tempFile = TempFile.Create(); output.WriteInfoLine($"Writing output to '{tempFile.FilePath}'."); { await using var stream = File.OpenWrite(tempFile.FilePath); await using var writer = new StreamWriter(stream, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false), leaveOpen: true); await ApplicationYamlWriter.WriteAsync(output, writer, application); } var ns = $"namespace ${application.Namespace}"; if (string.IsNullOrEmpty(application.Namespace)) { ns = "current namespace"; } output.WriteDebugLine($"Running 'kubectl apply' in ${ns}"); output.WriteCommandLine("kubectl", $"apply -f \"{tempFile.FilePath}\""); var capture = output.Capture(); var exitCode = await Process.ExecuteAsync( $"kubectl", $"apply -f \"{tempFile.FilePath}\"", System.Environment.CurrentDirectory, stdOut : capture.StdOut, stdErr : capture.StdErr); output.WriteDebugLine($"Done running 'kubectl apply' exit code: {exitCode}"); if (exitCode != 0) { throw new CommandException("'kubectl apply' failed."); } output.WriteInfoLine($"Deployed application '{application.Name}'."); }
public static Command CreateUndeployCommand() { var command = new Command("undeploy", "delete deployed application") { CommonArguments.Path_Required, StandardOptions.Namespace, StandardOptions.Interactive, StandardOptions.Verbosity, StandardOptions.Tags, new Option(new[] { "--what-if", }, "print what would be deleted without making changes") { Argument = new Argument <bool>(), }, }; command.Handler = CommandHandler.Create <UndeployCommandArguments>(args => { // Workaround for https://github.com/dotnet/command-line-api/issues/723#issuecomment-593062654 if (args.Path is null) { throw new CommandException("No project or solution file was found."); } var output = new OutputContext(args.Console, args.Verbosity); output.WriteInfoLine("Loading Application Details..."); var filter = ApplicationFactoryFilter.GetApplicationFactoryFilter(args.Tags); return(UndeployHost.UndeployAsync(output, args.Path, args.Namespace, args.Interactive, args.WhatIf, filter)); }); return(command); }
public static async Task ReadProjectDetailsAsync(OutputContext output, FileInfo projectFile, Project project) { if (output is null) { throw new ArgumentNullException(nameof(output)); } if (projectFile is null) { throw new ArgumentNullException(nameof(projectFile)); } if (project is null) { throw new ArgumentNullException(nameof(project)); } using (var step = output.BeginStep("Reading Project Details...")) { await EvaluateMSBuildAsync(output, projectFile, project); if (!SemVersion.TryParse(project.Version, out var version)) { output.WriteInfoLine($"No version or invalid version 'application.Version' found, using default."); version = new SemVersion(0, 1, 0); project.Version = version.ToString(); } step.MarkComplete(); } }
public override async Task ExecuteAsync(OutputContext output, ApplicationBuilder application, ServiceBuilder service) { if (SkipWithoutProject(output, service, out var project)) { return; } if (SkipWithoutContainerInfo(output, service, out var container)) { return; } if (container.UseMultiphaseDockerfile == false) { throw new CommandException("Generated Dockerfile workflow does not support single-phase Dockerfiles."); } container.UseMultiphaseDockerfile ??= true; var dockerFilePath = Path.Combine(project.ProjectFile.DirectoryName, "Dockerfile"); if (File.Exists(dockerFilePath) && !Force) { throw new CommandException("'Dockerfile' already exists for project. use '--force' to overwrite."); } File.Delete(dockerFilePath); await DockerfileGenerator.WriteDockerfileAsync(output, application, project, container, dockerFilePath); output.WriteInfoLine($"Generated Dockerfile at '{dockerFilePath}'."); }
public override async Task ExecuteAsync(OutputContext output, ApplicationBuilder application, ServiceBuilder service) { if (SkipWithoutProject(output, service, out var project)) { return; } if (SkipWithoutContainerInfo(output, service, out var container)) { return; } var chartDirectory = Path.Combine(project.ProjectFile.DirectoryName, "charts"); if (Directory.Exists(chartDirectory) && !Force) { throw new CommandException("'charts' directory already exists for project. use '--force' to overwrite."); } else if (Directory.Exists(chartDirectory)) { Directory.Delete(chartDirectory, recursive: true); } var chart = new HelmChartStep(); await HelmChartGenerator.GenerateAsync( output, application, project, container, chart, new DirectoryInfo(chartDirectory)); output.WriteInfoLine($"Generated Helm Chart at '{Path.Combine(chartDirectory, chart.ChartName)}'."); }
public static Command CreateGenerateCommand() { var command = new Command("generate", "generate kubernetes manifests") { CommonArguments.Path_Required, StandardOptions.Interactive, StandardOptions.Verbosity, StandardOptions.Namespace, StandardOptions.Tags, StandardOptions.Framework, }; // This is a super-secret VIP-only command! It's useful for testing, but we're // not documenting it right now. command.IsHidden = true; command.Handler = CommandHandler.Create <GenerateCommandArguments>(args => { // Workaround for https://github.com/dotnet/command-line-api/issues/723#issuecomment-593062654 if (args.Path is null) { throw new CommandException("No project or solution file was found."); } var output = new OutputContext(args.Console, args.Verbosity); output.WriteInfoLine("Loading Application Details..."); var filter = ApplicationFactoryFilter.GetApplicationFactoryFilter(args.Tags); return(GenerateHost.GenerateAsync(output, args.Path, args.Interactive, args.Namespace, args.Framework, filter)); }); return(command); }
public static Command CreateBuildCommand() { var command = new Command("build", "build containers for the application") { CommonArguments.Path_Required, StandardOptions.Interactive, StandardOptions.Tags, StandardOptions.Verbosity, StandardOptions.Framework, }; command.Handler = CommandHandler.Create <BuildCommandArguments>(args => { // Workaround for https://github.com/dotnet/command-line-api/issues/723#issuecomment-593062654 if (args.Path is null) { throw new CommandException("No project or solution file was found."); } var output = new OutputContext(args.Console, args.Verbosity); output.WriteInfoLine("Loading Application Details..."); var filter = ApplicationFactoryFilter.GetApplicationFactoryFilter(args.Tags); return(BuildHost.BuildAsync(output, args.Path, args.Interactive, args.Framework, filter)); }); return(command); }
public static Task ReadProjectDetailsAsync(OutputContext output, ProjectServiceBuilder project) { if (output is null) { throw new ArgumentNullException(nameof(output)); } if (project is null) { throw new ArgumentNullException(nameof(project)); } EnsureMSBuildRegistered(output, project.ProjectFile); EvaluateProject(output, project); if (!SemVersion.TryParse(project.Version, out var version)) { output.WriteInfoLine($"No version or invalid version '{project.Version}' found, using default."); version = new SemVersion(0, 1, 0); project.Version = version.ToString(); } return(Task.CompletedTask); }
public static void ReadProjectDetails(OutputContext output, DotnetProjectServiceBuilder project, string metadataFile) { if (output is null) { throw new ArgumentNullException(nameof(output)); } if (project is null) { throw new ArgumentNullException(nameof(project)); } if (project is null) { throw new ArgumentNullException(nameof(metadataFile)); } EvaluateProject(output, project, metadataFile); if (!SemVersion.TryParse(project.Version, out var version)) { output.WriteInfoLine($"No version or invalid version '{project.Version}' found, using default."); version = new SemVersion(0, 1, 0); project.Version = version.ToString(); } }
public override Task ExecuteAsync(OutputContext output, Application application, ServiceEntry service) { var yaml = service.Outputs.OfType <IYamlManifestOutput>().ToArray(); if (yaml.Length == 0) { output.WriteDebugLine($"No yaml manifests found for service '{service.FriendlyName}'. Skipping."); return(Task.CompletedTask); } var outputFilePath = Path.Combine(OutputDirectory.FullName, $"{service.Service.Name}.yaml"); output.WriteInfoLine($"Writing output to '{outputFilePath}'."); if (File.Exists(outputFilePath) && !Force) { throw new CommandException($"'{service.Service.Name}.yaml' already exists for project. use '--force' to overwrite."); } File.Delete(outputFilePath); using var stream = File.OpenWrite(outputFilePath); using var writer = new StreamWriter(stream, Encoding.UTF8, bufferSize: -1, leaveOpen: true); var yamlStream = new YamlStream(yaml.Select(y => y.Yaml)); yamlStream.Save(writer, assignAnchors: false); return(Task.CompletedTask); }
public static Task <bool> IsKubectlConnectedToClusterAsync(OutputContext output) { if (!_kubectlConnectedToCluster.IsValueCreated) { output.WriteInfoLine("Verifying kubectl connection to cluster..."); } return(_kubectlConnectedToCluster.Value); }
public static Task <Version?> GetKubernetesServerVersion(OutputContext output) { if (!_kubectlInstalled.IsValueCreated) { output.WriteInfoLine("Verifying kubectl installation..."); } return(_kubectlInstalled.Value); }
public static Task <bool> IsKubectlInstalledAsync(OutputContext output) { if (!_kubectlInstalled.IsValueCreated) { output.WriteInfoLine("Verifying kubectl installation..."); } return(_kubectlInstalled.Value); }
public static async Task UndeployAsync(IConsole console, FileInfo path, Verbosity verbosity, bool interactive, bool whatIf) { var output = new OutputContext(console, verbosity); output.WriteInfoLine("Loading Application Details..."); // We don't need to know anything about the services, just the application name. var application = ConfigFactory.FromFile(path); await ExecuteUndeployAsync(output, application, interactive, whatIf); }
public override async Task ExecuteAsync(OutputContext output, Application application, ServiceEntry service) { var yaml = service.Outputs.OfType <IYamlManifestOutput>().ToArray(); if (yaml.Length == 0) { output.WriteDebugLine($"No yaml manifests found for service '{service.FriendlyName}'. Skipping."); return; } if (!await KubectlDetector.Instance.IsKubectlInstalled.Value) { throw new CommandException($"Cannot apply manifests for '{service.Service.Name}' because kubectl is not installed."); } if (!await KubectlDetector.Instance.IsKubectlConnectedToCluster.Value) { throw new CommandException($"Cannot apply manifests for '{service.Service.Name}' because kubectl is not connected to a cluster."); } using var tempFile = TempFile.Create(); output.WriteDebugLine($"Writing output to '{tempFile.FilePath}'."); { using var stream = File.OpenWrite(tempFile.FilePath); using var writer = new StreamWriter(stream, Encoding.UTF8, bufferSize: -1, leaveOpen: true); var yamlStream = new YamlStream(yaml.Select(y => y.Yaml)); yamlStream.Save(writer, assignAnchors: false); } // kubectl apply logic is implemented in the client in older versions of k8s. The capability // to get the same behavior in the server isn't present in every version that's relevant. // // https://kubernetes.io/docs/reference/using-api/api-concepts/#server-side-apply // output.WriteDebugLine("Running 'kubectl apply'."); output.WriteCommandLine("kubectl", $"apply -f \"{tempFile.FilePath}\""); var capture = output.Capture(); var exitCode = await Process.ExecuteAsync( $"kubectl", $"apply -f \"{tempFile.FilePath}\"", System.Environment.CurrentDirectory, stdOut : capture.StdOut, stdErr : capture.StdErr); output.WriteDebugLine($"Done running 'kubectl apply' exit code: {exitCode}"); if (exitCode != 0) { throw new CommandException("'kubectl apply' failed."); } output.WriteInfoLine($"Deployed service '{service.FriendlyName}'."); }
private static Command CreateInitCommand() { var command = new Command("init", "create a yaml manifest") { CommonArguments.Path_Optional, StandardOptions.CreateForce("Overrides the tye.yaml file if already present for project.") }; command.Handler = CommandHandler.Create <InitCommandArguments>(args => { var watch = System.Diagnostics.Stopwatch.StartNew(); var output = new OutputContext(args.Console, args.Verbosity); var outputFilePath = InitHost.CreateTyeFile(args.Path, args.Force); output.WriteInfoLine($"Created '{outputFilePath}'."); watch.Stop(); var elapsedTime = watch.Elapsed; output.WriteInfoLine($"Time Elapsed: {elapsedTime.Hours:00}:{elapsedTime.Minutes:00}:{elapsedTime.Seconds:00}:{elapsedTime.Milliseconds / 10:00}"); }); return(command); }
public override async Task ExecuteAsync(OutputContext output, ApplicationBuilder application) { var outputFilePath = Path.GetFullPath(Path.Combine(application.Source.DirectoryName, $"{application.Name}-generate-{Environment}.yaml")); output.WriteInfoLine($"Writing output to '{outputFilePath}'."); { File.Delete(outputFilePath); await using var stream = File.OpenWrite(outputFilePath); await using var writer = new StreamWriter(stream, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false), leaveOpen: true); await ApplicationYamlWriter.WriteAsync(output, writer, application); } }
public static async Task GenerateAsync(IConsole console, FileInfo path, Verbosity verbosity, bool interactive) { var output = new OutputContext(console, verbosity); output.WriteInfoLine("Loading Application Details..."); var application = await ApplicationFactory.CreateAsync(output, path); if (application.Services.Count == 0) { throw new CommandException($"No services found in \"{application.Source.Name}\""); } await ExecuteGenerateAsync(output, application, environment : "production", interactive); }
public static async Task BuildContainerImageFromDockerFileAsync(OutputContext output, ApplicationBuilder application, DockerFileServiceBuilder containerService, ContainerInfo container) { if (output is null) { throw new ArgumentNullException(nameof(output)); } if (application is null) { throw new ArgumentNullException(nameof(application)); } if (containerService is null) { throw new ArgumentNullException(nameof(containerService)); } if (containerService.DockerFile is null) { throw new ArgumentNullException(nameof(containerService.DockerFile)); } var dockerFileInfo = new FileInfo(containerService.DockerFile); var contextDirectory = containerService.DockerFileContext ?? dockerFileInfo.DirectoryName; var dockerFilePath = Path.Combine(dockerFileInfo.DirectoryName, "Dockerfile"); output.WriteDebugLine($"Using existing Dockerfile '{dockerFilePath}'."); output.WriteDebugLine("Running 'docker build'."); output.WriteCommandLine("docker", $"build \"{contextDirectory}\" -t {container.ImageName}:{container.ImageTag} -f \"{dockerFilePath}\""); var capture = output.Capture(); var exitCode = await Process.ExecuteAsync( $"docker", $"build \"{contextDirectory}\" -t {container.ImageName}:{container.ImageTag} -f \"{dockerFilePath}\"", new FileInfo(containerService.DockerFile).DirectoryName, stdOut : capture.StdOut, stdErr : capture.StdErr); output.WriteDebugLine($"Done running 'docker build' exit code: {exitCode}"); if (exitCode != 0) { throw new CommandException("'docker build' failed."); } output.WriteInfoLine($"Created Docker Image: '{container.ImageName}:{container.ImageTag}'"); containerService.Outputs.Add(new DockerImageOutput(container.ImageName !, container.ImageTag !)); }
public static Command CreateDeployCommand() { var command = new Command("deploy", "deploy the application") { CommonArguments.Path_Required, StandardOptions.Interactive, StandardOptions.Verbosity, StandardOptions.Namespace, StandardOptions.Tags, }; command.AddOption(new Option(new[] { "-f", "--force" }) { Description = "Override validation and force deployment.", Required = false }); command.Handler = CommandHandler.Create <IConsole, FileInfo, Verbosity, bool, bool, string, string[]>(async(console, path, verbosity, interactive, force, @namespace, tags) => { // Workaround for https://github.com/dotnet/command-line-api/issues/723#issuecomment-593062654 if (path is null) { throw new CommandException("No project or solution file was found."); } var output = new OutputContext(console, verbosity); output.WriteInfoLine("Loading Application Details..."); var filter = ApplicationFactoryFilter.GetApplicationFactoryFilter(tags); var application = await ApplicationFactory.CreateAsync(output, path, filter); if (application.Services.Count == 0) { throw new CommandException($"No services found in \"{application.Source.Name}\""); } if (!string.IsNullOrEmpty(@namespace)) { application.Namespace = @namespace; } await ExecuteDeployAsync(new OutputContext(console, verbosity), application, environment: "production", interactive, force); }); return(command); }
private static async Task GenerateApplicationManifestAsync(OutputContext output, ApplicationBuilder application, string environment) { using var step = output.BeginStep("Generating Application Manifests..."); var outputFilePath = Path.GetFullPath(Path.Combine(application.Source.DirectoryName, $"{application.Name}-generate-{environment}.yaml")); output.WriteInfoLine($"Writing output to '{outputFilePath}'."); { File.Delete(outputFilePath); await using var stream = File.OpenWrite(outputFilePath); await using var writer = new StreamWriter(stream, Encoding.UTF8, leaveOpen: true); await ApplicationYamlWriter.WriteAsync(output, writer, application); } step.MarkComplete(); }
public static async Task GenerateAsync(IConsole console, FileInfo path, Verbosity verbosity, bool interactive, string ns, string[] tags) { var output = new OutputContext(console, verbosity); output.WriteInfoLine("Loading Application Details..."); var filter = ApplicationFactoryFilter.GetApplicationFactoryFilter(tags); var application = await ApplicationFactory.CreateAsync(output, path, filter); if (application.Services.Count == 0) { throw new CommandException($"No services found in \"{application.Source.Name}\""); } if (!String.IsNullOrEmpty(ns)) { application.Namespace = ns; } await ExecuteGenerateAsync(output, application, environment : "production", interactive); }
public static Command CreateDeployCommand() { var command = new Command("deploy", "deploy the application") { CommonArguments.Path_Required, StandardOptions.Interactive, StandardOptions.Verbosity, StandardOptions.Namespace, StandardOptions.Framework, StandardOptions.Tags, StandardOptions.CreateForce("Override validation and force deployment.") }; command.Handler = CommandHandler.Create <DeployCommandArguments>(async args => { // Workaround for https://github.com/dotnet/command-line-api/issues/723#issuecomment-593062654 if (args.Path is null) { throw new CommandException("No project or solution file was found."); } var output = new OutputContext(args.Console, args.Verbosity); output.WriteInfoLine("Loading Application Details..."); var filter = ApplicationFactoryFilter.GetApplicationFactoryFilter(args.Tags); var application = await ApplicationFactory.CreateAsync(output, args.Path, args.Framework, filter); if (application.Services.Count == 0) { throw new CommandException($"No services found in \"{application.Source.Name}\""); } if (!string.IsNullOrEmpty(args.Namespace)) { application.Namespace = args.Namespace; } var executeOutput = new OutputContext(args.Console, args.Verbosity); await ExecuteDeployAsync(executeOutput, application, environment: "production", args.Interactive, args.Force); }); return(command); }
public override async Task ExecuteAsync(OutputContext output, ApplicationBuilder application, ServiceBuilder service) { if (SkipWithoutProject(output, service, out var _)) { return; } if (SkipWithoutContainerInfo(output, service, out var _)) { return; } foreach (var image in service.Outputs.OfType <DockerImageOutput>()) { await DockerPush.ExecuteAsync(output, image.ImageName, image.ImageTag); output.WriteInfoLine($"Pushed docker image: '{image.ImageName}:{image.ImageTag}'"); } }
protected bool SkipWithoutProject(OutputContext output, ServiceBuilder service, [MaybeNullWhen(returnValue: true)] out ProjectServiceBuilder project) { if (output is null) { throw new ArgumentNullException(nameof(output)); } if (service is null) { throw new ArgumentNullException(nameof(service)); } if (service is ProjectServiceBuilder p) { project = p; return(false); } output.WriteInfoLine($"Service '{service.Name}' does not have a project associated. Skipping."); project = default !;
public override async Task ExecuteAsync(OutputContext output, Application application, ServiceEntry service) { if (SkipWithoutProject(output, service, out var project)) { return; } if (SkipWithoutContainerInfo(output, service, out var container)) { return; } if (container.UseMultiphaseDockerfile != false) { return; } var projectFilePath = Path.Combine(application.RootDirectory, project.RelativeFilePath); var outputDirectory = Path.Combine(Path.GetDirectoryName(projectFilePath) !, "bin", "Release", project.TargetFramework, "publish"); output.WriteDebugLine("Running 'dotnet publish'."); output.WriteCommandLine("dotnet", $"publish \"{projectFilePath}\" -c Release -o \"{outputDirectory}\""); var capture = output.Capture(); var exitCode = await Process.ExecuteAsync( $"dotnet", $"publish \"{projectFilePath}\" -c Release -o \"{outputDirectory}\"", application.GetProjectDirectory(project), stdOut : capture.StdOut, stdErr : capture.StdErr); output.WriteDebugLine($"Done running 'dotnet publish' exit code: {exitCode}"); if (exitCode != 0) { throw new CommandException("'dotnet publish' failed."); } output.WriteInfoLine($"Created Publish Output: '{outputDirectory}'"); service.Outputs.Add(new ProjectPublishOutput(new DirectoryInfo(outputDirectory))); }
public static Command CreatePushCommand() { var command = new Command("push", "build and push application containers to registry") { CommonArguments.Path_Required, StandardOptions.Interactive, StandardOptions.Verbosity, }; command.AddOption(new Option(new[] { "-f", "--force" }) { Description = "Override validation and force push.", Required = false }); command.Handler = CommandHandler.Create <IConsole, FileInfo, Verbosity, bool, bool>(async(console, path, verbosity, interactive, force) => { // Workaround for https://github.com/dotnet/command-line-api/issues/723#issuecomment-593062654 if (path is null) { throw new CommandException("No project or solution file was found."); } var output = new OutputContext(console, verbosity); output.WriteInfoLine("Loading Application Details..."); var application = await ApplicationFactory.CreateAsync(output, path); if (application.Services.Count == 0) { throw new CommandException($"No services found in \"{application.Source.Name}\""); } await ExecutePushAsync(new OutputContext(console, verbosity), application, environment: "production", interactive, force); }); return(command); }