public async Task <ExecutiveBuildDTO> GetExecutiveBuild(int projectId) { var project = await Context.Projects .Include(p => p.BuildSteps) .ThenInclude(s => s.PluginCommand) .ThenInclude(c => c.Plugin) .Include(p => p.Repository) .Include(p => p.BuildSteps) .ThenInclude(s => s.BuildPluginParameters) .Include(p => p.BuildSteps) .ThenInclude(s => s.CommandArguments) .FirstOrDefaultAsync(p => p.Id == projectId); if (project == null) { throw new NotFoundException("Project", projectId); } var executiveBuild = new ExecutiveBuildDTO { ProjectId = project.Id, RepositoryUrl = project.Repository.Url, BuildSteps = project.BuildSteps .Select(buildStep => Mapper.Map <BuildStepDTO>(buildStep)) .OrderBy(buildStep => buildStep.Index) }; return(executiveBuild); }
public async Task BuildProjectAsync(ExecutiveBuildDTO build) { var pathToClonedRepository = Path.Combine( _pathToProjects, $"{build.ProjectId}{DateTime.Now.Millisecond}{new Random().Next(1000000)}", "ClonedRepository" ); CloneRepository(build.RepositoryUrl, pathToClonedRepository); try { var dockerFileContent = GenerateDockerFileContent(build.BuildSteps, build.RepositoryUrl); await CreateDockerFileAsync(dockerFileContent, pathToClonedRepository); BuildDockerImage(pathToClonedRepository, build.ProjectId); } catch (Exception e) { Log.Error($"Error while building docker image. Reason: {e.Message}"); } finally { DeleteClonedRepository(pathToClonedRepository); // Remove all unused containers, networks, images (both dangling and unreferenced) Process process = new Process(); process.StartInfo.FileName = "docker"; process.StartInfo.Arguments = "system prune -f"; process.Start(); process.WaitForExit(); } }
public async Task BuildProjectAsync(ExecutiveBuildDTO build) { var pathToClonedRepository = Path.Combine( _pathToProjects, $"{build.ProjectId}{DateTime.Now.Millisecond}{new Random().Next(1000000)}", "ClonedRepository" ); CloneRepository(build.RepositoryUrl, pathToClonedRepository, build.BranchName); try { if (build.BuildSteps.Count() != 0 && build.BuildSteps.FirstOrDefault().BuildStepName == "Dockerfile") { var dockerfileDirectory = build.BuildSteps.FirstOrDefault().WorkDirectory; if (dockerfileDirectory != "") { pathToClonedRepository = Path.Combine(pathToClonedRepository, dockerfileDirectory); } } else { var dockerFileContent = GenerateDockerFileContent(build.BuildSteps, build.RepositoryUrl); await CreateDockerFileAsync(dockerFileContent, pathToClonedRepository); } BuildDockerImage(pathToClonedRepository, build); } catch (Exception e) { SendBuildStatus(BuildStatus.Error, build.BuildHistoryId, build.UserId); Log.Error($"Error while building docker image. Reason: {e.Message}"); } finally { DeleteClonedRepository(pathToClonedRepository); // Remove all unused containers, networks, images (both dangling and unreferenced) Process process = new Process(); process.StartInfo.FileName = "docker"; process.StartInfo.Arguments = "system prune -f"; process.Start(); process.WaitForExit(); } }
public void BuildDockerImage(string path, ExecutiveBuildDTO build) { Process process = new Process(); process.StartInfo.FileName = "docker"; process.StartInfo.Arguments = $"build {path}"; process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; //* Set your output and error (asynchronous) handlers process.OutputDataReceived += (object _sender, DataReceivedEventArgs _args) => OutputHandler(_sender, _args, build); process.ErrorDataReceived += (object _sender, DataReceivedEventArgs _args) => OutputHandler(_sender, _args, build); //* Start process and handlers process.Start(); process.BeginOutputReadLine(); process.BeginErrorReadLine(); process.WaitForExit(); }
public async void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine, ExecutiveBuildDTO build) { // If log starts with Step and containts FROM we stop logging because there will be useless Docker logs // (also applied to "Removing intermediate container" and "Sending build context"). Skip checking empty strings if (outLine.Data != null && ((outLine.Data.StartsWith("Step") && outLine.Data.Contains("FROM")) || outLine.Data.StartsWith("Removing intermediate container") || outLine.Data.StartsWith("Sending build context"))) { areDockerLogs = true; startLogging = 2; } // We begin logging again after logs that starts with Step and contains RUN. Usually RUN starts process, which we need logs to take from // TODO: We can add checking 'contains' from list, that will have all starter commands like RUN, CMD, etc. else if (outLine.Data != null && (outLine.Data.StartsWith("Step") && outLine.Data.Contains("RUN"))) { areDockerLogs = false; // Add one specific string to divide different build steps var log = new ProjectLog() { Timestamp = DateTime.Now, Message = $">>> Here starts a new step", BuildHistoryId = build.BuildHistoryId, ProjectId = build.ProjectId }; await _kafkaProducer.SendLog(log); } // This function is needed to get rid of first two lines before actual logs of our process if (!areDockerLogs) { startLogging--; } if (!areDockerLogs && startLogging < 0) { var log = new ProjectLog() { Timestamp = DateTime.Now, Message = outLine.Data, BuildHistoryId = build.BuildHistoryId, ProjectId = build.ProjectId }; await _elk.IndexDocumentAsync(log); await _kafkaProducer.SendLog(log); } }