private Task <FileInfo?> InternalUpdateApplicationImageTag( RawDeploymentManifest manifest, DeploymentManifestInfo deploymentManifestInfo, ApplicationImage applicationImage, string instance, string targetTag ) { var yamlUtilities = new YamlUtilities(); var key = new DeploymentManifestInstanceKey(applicationImage, instance); string currentImageTag = deploymentManifestInfo.ManifestTags.GetValueOrDefault(key) ?? "n/a"; if (!deploymentManifestInfo.ApplicationImageToFileMapping.TryGetValue(key, out FileInfo? 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."); throw new InvalidOperationException("Update cannot be applied since there isn't matching file."); } _log.LogTrace("Upgrading {Repository} to {NewTag} from {Tag}", applicationImage.Repository, targetTag, currentImageTag ); return(yamlUtilities.UpdateValueInYamlFile(file, applicationImage.TagProperty.Path, targetTag) ? Task.FromResult((FileInfo?)file) : Task.FromResult((FileInfo?)null)); }
public async Task UpdateApplicationImageVersion( RawDeploymentManifest manifest, ApplicationImage applicationImage, string instance, string targetTag ) { var manifestInfo = await _parser.BuildDeploymentManifestInfo(manifest); var key = new DeploymentManifestInstanceKey(applicationImage, instance); string currentImageTag = manifestInfo.ManifestTags.GetValueOrDefault(key) ?? "n/a"; var result = await InternalUpdateApplicationImageTag(manifest, manifestInfo, applicationImage, instance, targetTag); if (result == null) { return; } // this is GIT requirement: we only work with relative paths in the git repository. _log.LogTrace("Adding {Path} to repository git staging", result); // var gitFilePath = Path.Combine(relativePath, file.Name); // var gitFilePath = Path.GetRelativePath(context.GitRepositoryRoot.FullName, file.FullName); // Commands.Stage(gitRepository, gitFilePath); var application = GetApplicationForApplicationImage(applicationImage); await _deploymentManifestRepositoryService.StageChanges(manifest.Repository, new[] { result }); await _deploymentManifestRepositoryService.Commit( manifest.Repository, $"[{application}] Updated deployment for {applicationImage.ShortRepository}; {currentImageTag} to {targetTag}" ); }
public async Task RemovePreviewRelease(RawDeploymentManifest manifest, ApplicationImage applicationImage, string instance) { var manifestInfo = await _parser.BuildDeploymentManifestInfo(manifest); var key = new DeploymentManifestInstanceKey(applicationImage, instance); if (!manifestInfo.Instances.ContainsKey(key)) { _log.LogError($"Cannot remove instance {key} because it doesn't exist"); return; } var instanceInfo = manifestInfo.Instances[key]; var files = instanceInfo.GetInstanceDeploymentFiles().ToList(); files.ForEach(f => f.Delete()); var application = GetApplicationForApplicationImage(applicationImage); await _deploymentManifestRepositoryService.StageChanges(manifest.Repository, files); await _deploymentManifestRepositoryService.Commit(manifest.Repository, $"[{application}] Remove preview release '{instance}'."); }
private async Task <bool> InternalExecute <TManifest>(TManifest manifest, Application application) where TManifest : DeploymentManifest { // prefetch and structure some metadata required throughout var imageMap = application.Images.ToDictionary( x => $"{x.Repository}-{x.TagProperty.Path}" ); // store var manifestsChanged = false; // 1. check for any orphan preview releases var appImagesWithPreviewReleases = imageMap.Values .Where(x => x.SourceCode.IsAvailable && x.DeploymentSettings.PreviewReleases.Enabled) .ToArray(); if (appImagesWithPreviewReleases.Any()) { _log.LogInformation("Checking for orphan preview releases ..."); foreach (var item in appImagesWithPreviewReleases) { if (!item.SourceCode.IsAvailable) { continue; } var openPullRequests = (await _githubPullRequestService.GetOpenPRs(item)) .ToArray(); _log.LogTrace("Found {prCount} open pull requests", openPullRequests.Length); var appImageInstances = (await _applicationImageInstanceService.GetInstancesFor(application, item)) .ToArray(); _log.LogTrace("Found {instanceCount} active instances", appImageInstances.Length); foreach (var applicationImageInstance in appImageInstances) { if (applicationImageInstance.Source.Type != ApplicationImageInstanceSourceType.PullRequest) { continue; } if (openPullRequests.Any(x => x.PrNumber.Equals(applicationImageInstance.Source.PullRequestId))) { continue; } _log.LogTrace("No pull request found for instance {instanceName}, removing ...", applicationImageInstance.Name); await _deploymentManifestSourceManagementFacade.RemovePreviewRelease(manifest, item, applicationImageInstance.Name); await _applicationImageInstanceService.RemoveInstance(application, item, applicationImageInstance); manifestsChanged = true; } } } _log.LogTrace("Checking for pending deployments to apply."); // start updating files var updatedImageTags = new Dictionary <ApplicationImageInstanceKey, string>(); Deployment?nextPendingDeployment = null; while ((nextPendingDeployment = await _deploymentQueueService.GetNextPendingDeploymentUpdate(application)) != null) { await _deploymentService.ChangeDeploymentUpdateStatus( nextPendingDeployment.Id, DeploymentStatus.Starting ); _log.LogTrace("Executing pending deployment update ..."); await _deploymentService.ChangeDeploymentUpdateStatus( nextPendingDeployment.Id, DeploymentStatus.UpdatingManifests ); var deploymentManifestInfo = await _deploymentManifestSourceManagementFacade.GetDeploymentManifestInfo(manifest); var image = imageMap[$"{nextPendingDeployment.ImageRepository}-{nextPendingDeployment.UpdatePath}"]; var dmiKey = new DeploymentManifestInstanceKey(image, nextPendingDeployment.InstanceId); switch (nextPendingDeployment.Type) { case DeploymentType.ImageUpdate: await _deploymentManifestSourceManagementFacade.UpdateApplicationImageVersion( manifest, image, nextPendingDeployment.InstanceId, nextPendingDeployment.TargetTag ); break; case DeploymentType.PreviewRelease: if (!deploymentManifestInfo.Instances.ContainsKey(dmiKey)) { await _deploymentManifestSourceManagementFacade.CreatePreviewRelease( manifest, image, nextPendingDeployment.InstanceId, nextPendingDeployment.TargetTag ); } else { await _deploymentManifestSourceManagementFacade.UpdateApplicationImageVersion( manifest, image, nextPendingDeployment.InstanceId, nextPendingDeployment.TargetTag ); } break; default: throw new ArgumentOutOfRangeException(); } var key = new ApplicationImageInstanceKey(application, image, nextPendingDeployment.InstanceId); updatedImageTags[key] = nextPendingDeployment.TargetTag; manifestsChanged = true; // TODO: rework this so that failures to push get indicated await _deploymentService.FinishDeploymentUpdate( nextPendingDeployment.Id, manifestsChanged?DeploymentStatus.Complete : DeploymentStatus.Failed ); } await SyncApplicationMetadataFromManifest(manifest, application, updatedImageTags); _log.LogTrace("Deployment manifest repository syncing complete ..."); return(manifestsChanged); }