private async Task <bool> UpdateDeploymentManifests( Repository gitRepository, DeploymentUpdate deploymentUpdate, Dictionary <Image, string> imageToFilenameMap, string currentImageTag, string applicationSourcePath, YamlUtilities yamlUtilities, string relativePath) { if (!imageToFilenameMap.TryGetValue(deploymentUpdate.Image, out string file)) { // TODO: warn that we have an image tag update but no corresponding file _log.LogWarning("Update to {Repository} cannot be applied since there isn't matching file."); return(false); } _log.LogInformation("Upgrading {Repository} to {NewTag} from {Tag}", deploymentUpdate.Image.Repository, deploymentUpdate.TargetTag, currentImageTag ); var yaml = new YamlStream(); var filePath = Path.Combine(applicationSourcePath, file); yamlUtilities.ReadYamlStream(yaml, filePath); var image = deploymentUpdate.Image; var doCommit = false; foreach (var doc in yaml.Documents) { var tagInManifest = yamlUtilities.ExtractValueFromDoc(image.TagProperty.Path, doc); if (tagInManifest == null) { continue; } if (tagInManifest == deploymentUpdate.TargetTag) { _log.LogInformation("Tag for {Repository} matches new tag {NewTag}", image.Repository, deploymentUpdate.TargetTag); continue; } _log.LogInformation("Setting current-tag for {Repository} to {Tag}", image.Repository, deploymentUpdate.TargetTag); yamlUtilities.SetValueInDoc(image.TagProperty.Path, doc, deploymentUpdate.TargetTag); doCommit = true; } if (!doCommit) { return(true); } yamlUtilities.WriteYamlStream(yaml, filePath); _log.LogInformation("Adding {Path} to repository staging", filePath); var gitFilePath = Path.Combine(relativePath, file); Commands.Stage(gitRepository, gitFilePath); gitRepository.Commit( $"[{deploymentUpdate.Application}] Updated deployment for {image.RepositoryName}; {deploymentUpdate.CurrentTag} to {deploymentUpdate.TargetTag}", new Signature("deploy-bot", "*****@*****.**", DateTimeOffset.Now), new Signature("deploy-bot", "*****@*****.**", DateTimeOffset.Now) ); // add delay instruction due to the deployment update notification delivered too fast await Task.Delay(500); return(true); }
private async Task <bool> SynchronizeHelmApplicationSource(Repository gitRepository, ApplicationSourceTrackingContext context, HelmApplicationSource helmApplicationSource) { var relativePath = helmApplicationSource.Path; var applicationSourcePath = Path.Combine(context.GitRepositoryPath, relativePath); var application = context.Application; var yamlUtilities = new YamlUtilities(); // build map of images -> yaml file that defines them and image -> current tag _log.LogInformation("Beginning to parse value files defined in application source ..."); var imageToFilenameMap = new Dictionary <Image, string>(); var imageToTagInManifest = new Dictionary <Image, string>(); foreach (var file in helmApplicationSource.ValuesFiles) { var yaml = new YamlStream(); var filePath = Path.Combine(applicationSourcePath, file); yamlUtilities.ReadYamlStream(yaml, filePath); foreach (var doc in yaml.Documents) { foreach (var image in context.Application.Images) { var tagInManifest = yamlUtilities.ExtractValueFromDoc(image.TagProperty.Path, doc); if (tagInManifest == null) { continue; } if (imageToFilenameMap.ContainsKey(image)) { // TODO: handle situation where multiple files define the same image tag (ERROR and warn user) } imageToFilenameMap[image] = file; imageToTagInManifest[image] = tagInManifest; } } } _log.LogInformation("Completing parsing value files defined in application source ..."); // start updating files var manifestsChanged = false; DeploymentUpdate deploymentUpdate = null; while ((deploymentUpdate = await _deploymentService.GetNextPendingDeploymentUpdate(application)) != null) { _log.LogInformation("Executing pending deployment update ..."); await _deploymentService.ChangeDeploymentUpdateStatus( deploymentUpdate, DeploymentUpdateStatus.UpdatingManifests ); manifestsChanged = await UpdateDeploymentManifests(gitRepository, deploymentUpdate, imageToFilenameMap, imageToTagInManifest.TryGetAndReturn(deploymentUpdate.Image) ?? "n/a", applicationSourcePath, yamlUtilities, relativePath); if (manifestsChanged) { imageToTagInManifest[deploymentUpdate.Image] = deploymentUpdate.TargetTag; } await _deploymentService.FinishDeploymentUpdate( deploymentUpdate, manifestsChanged?DeploymentUpdateStatus.Complete : DeploymentUpdateStatus.Failed ); } if (!manifestsChanged) { // we don't have a deployment, ensure application manifest is up to date with latest image tags foreach (var keyValuePair in imageToTagInManifest) { _applicationService.SetCurrentImageTag(application, keyValuePair.Key, keyValuePair.Value); } } return(manifestsChanged); }