private async Task <IEnumerable <ImageResultInfo> > WaitForImageIngestionAsync(IMcrStatusClient statusClient)
        {
            ImageArtifactDetails imageArtifactDetails = ImageInfoHelper.LoadFromFile(Options.ImageInfoPath, Manifest);

            List <Task <ImageResultInfo> > tasks = GetImageDigestInfos(imageArtifactDetails)
                                                   .Select(digestInfo => ReportImageStatusWithContinuationAsync(statusClient, digestInfo))
                                                   .ToList();

            return(await TaskHelper.WhenAll(tasks, Options.WaitTimeout));
        }
        private void RemoveOutOfDateContent(ImageArtifactDetails imageArtifactDetails)
        {
            for (int repoIndex = imageArtifactDetails.Repos.Count - 1; repoIndex >= 0; repoIndex--)
            {
                RepoData repoData = imageArtifactDetails.Repos[repoIndex];

                // Since the registry name is not represented in the image info, make sure to compare the repo name with the
                // manifest's repo model name which isn't registry-qualified.
                RepoInfo?manifestRepo = Manifest.AllRepos.FirstOrDefault(manifestRepo => manifestRepo.Name == repoData.Repo);

                // If there doesn't exist a matching repo in the manifest, remove it from the image info
                if (manifestRepo is null)
                {
                    imageArtifactDetails.Repos.Remove(repoData);
                    continue;
                }

                for (int imageIndex = repoData.Images.Count - 1; imageIndex >= 0; imageIndex--)
                {
                    ImageData imageData     = repoData.Images[imageIndex];
                    ImageInfo manifestImage = imageData.ManifestImage;

                    // If there doesn't exist a matching image in the manifest, remove it from the image info
                    if (manifestImage is null)
                    {
                        repoData.Images.Remove(imageData);
                        continue;
                    }

                    for (int platformIndex = imageData.Platforms.Count - 1; platformIndex >= 0; platformIndex--)
                    {
                        PlatformData platformData     = imageData.Platforms[platformIndex];
                        PlatformInfo?manifestPlatform = manifestImage.AllPlatforms
                                                        .FirstOrDefault(manifestPlatform => platformData.PlatformInfo == manifestPlatform);

                        // If there doesn't exist a matching platform in the manifest, remove it from the image info
                        if (manifestPlatform is null)
                        {
                            imageData.Platforms.Remove(platformData);
                        }
                    }
                }
            }

            if (imageArtifactDetails.Repos.Count == 0)
            {
                // Failsafe to prevent wiping out the image info due to a bug in the logic
                throw new InvalidOperationException(
                          "Removal of out-of-date content resulted in there being no content remaining in the target image info file. Something is probably wrong with the logic.");
            }
        }
Exemple #3
0
        /// <summary>
        /// Loads image info string content as a parsed model.
        /// </summary>
        /// <param name="imageInfoContent">The image info content to load.</param>
        /// <param name="manifest">Representation of the manifest model.</param>
        /// <param name="skipManifestValidation">
        /// Whether to skip validation if no associated manifest model item was found for a given image info model item.
        /// </param>
        /// <param name="useFilteredManifest">Whether to use the filtered content of the manifest for lookups.</param>
        public static ImageArtifactDetails LoadFromContent(string imageInfoContent, ManifestInfo manifest,
                                                           bool skipManifestValidation = false, bool useFilteredManifest = false)
        {
            ImageArtifactDetails imageArtifactDetails = JsonConvert.DeserializeObject <ImageArtifactDetails>(imageInfoContent);

            foreach (RepoData repoData in imageArtifactDetails.Repos)
            {
                RepoInfo manifestRepo = (useFilteredManifest ? manifest.FilteredRepos : manifest.AllRepos)
                                        .FirstOrDefault(repo => repo.Name == repoData.Repo);
                if (manifestRepo == null)
                {
                    Console.WriteLine($"Image info repo not loaded: {repoData.Repo}");
                    continue;
                }

                foreach (ImageData imageData in repoData.Images)
                {
                    imageData.ManifestRepo = manifestRepo;

                    foreach (PlatformData platformData in imageData.Platforms)
                    {
                        foreach (ImageInfo manifestImage in (useFilteredManifest ? manifestRepo.FilteredImages : manifestRepo.AllImages))
                        {
                            PlatformInfo matchingManifestPlatform = (useFilteredManifest ? manifestImage.FilteredPlatforms : manifestImage.AllPlatforms)
                                                                    .FirstOrDefault(platform => ArePlatformsEqual(platformData, imageData, platform, manifestImage));
                            if (matchingManifestPlatform != null)
                            {
                                if (imageData.ManifestImage is null)
                                {
                                    imageData.ManifestImage = manifestImage;
                                }

                                platformData.PlatformInfo = matchingManifestPlatform;
                                platformData.ImageInfo    = manifestImage;
                                break;
                            }
                        }
                    }

                    PlatformData representativePlatform = imageData.Platforms.FirstOrDefault();
                    if (!skipManifestValidation && imageData.ManifestImage == null && representativePlatform != null)
                    {
                        throw new InvalidOperationException(
                                  $"Unable to find matching platform in manifest for platform '{representativePlatform.GetIdentifier()}'.");
                    }
                }
            }

            return(imageArtifactDetails);
        }
Exemple #4
0
        public async Task BuildCommand_ImageInfoOutput_CustomDockerfile()
        {
            using (TempFolderContext tempFolderContext = TestHelper.UseTempFolder())
            {
                Mock <IDockerService> dockerServiceMock = new Mock <IDockerService>();
                dockerServiceMock
                .SetupGet(o => o.Architecture)
                .Returns(Architecture.AMD64);
                const string digest = "runtime@sha256:c74364a9f125ca612f9a67e4a0551937b7a37c82fabb46172c4867b73edd638c";
                dockerServiceMock
                .Setup(o => o.GetImageDigest("runtime:runtime", false))
                .Returns(digest);

                const string runtimeRelativeDir = "1.0/runtime/os";
                Directory.CreateDirectory(Path.Combine(tempFolderContext.Path, runtimeRelativeDir));
                string dockerfileRelativePath = Path.Combine(runtimeRelativeDir, "Dockerfile.custom");
                File.WriteAllText(Path.Combine(tempFolderContext.Path, dockerfileRelativePath), "FROM repo:tag");

                const string       dockerfileCommitSha = "mycommit";
                Mock <IGitService> gitServiceMock      = new Mock <IGitService>();
                gitServiceMock
                .Setup(o => o.GetCommitSha(dockerfileRelativePath, It.IsAny <bool>()))
                .Returns(dockerfileCommitSha);

                BuildCommand command = new BuildCommand(dockerServiceMock.Object, Mock.Of <ILoggerService>(), Mock.Of <IEnvironmentService>(),
                                                        gitServiceMock.Object);
                command.Options.Manifest            = Path.Combine(tempFolderContext.Path, "manifest.json");
                command.Options.ImageInfoOutputPath = Path.Combine(tempFolderContext.Path, "image-info.json");
                command.Options.SourceRepoUrl       = "https://source";

                Manifest manifest = CreateManifest(
                    CreateRepo("runtime",
                               CreateImage(
                                   CreatePlatform(dockerfileRelativePath, new string[] { "runtime" })))
                    );

                File.WriteAllText(Path.Combine(tempFolderContext.Path, command.Options.Manifest), JsonConvert.SerializeObject(manifest));

                command.LoadManifest();
                await command.ExecuteAsync();

                ImageArtifactDetails imageArtifactDetails = JsonConvert.DeserializeObject <ImageArtifactDetails>(
                    File.ReadAllText(command.Options.ImageInfoOutputPath));
                Assert.Equal(
                    PathHelper.NormalizePath(dockerfileRelativePath),
                    imageArtifactDetails.Repos[0].Images.First().Platforms.First().Dockerfile);
            }
        }
Exemple #5
0
        public override async Task ExecuteAsync()
        {
            _loggerService.WriteHeading("TRIMMING UNCHANGED PLATFORMS");

            string imageInfoContents = await File.ReadAllTextAsync(Options.ImageInfoPath);

            ImageArtifactDetails imageArtifactDetails = JsonConvert.DeserializeObject <ImageArtifactDetails>(imageInfoContents);

            RemoveUnchangedPlatforms(imageArtifactDetails);
            imageInfoContents = JsonHelper.SerializeObject(imageArtifactDetails);

            if (!Options.IsDryRun)
            {
                await File.WriteAllTextAsync(Options.ImageInfoPath, imageInfoContents);
            }
        }
        public override Task ExecuteAsync()
        {
            IEnumerable <(string Tag, string Platform)> platformTags;

            if (string.IsNullOrEmpty(Options.ImageInfoPath))
            {
                platformTags = Manifest.GetFilteredPlatforms()
                               .Where(platform => platform.Tags.Any())
                               .Select(platform => (platform.Tags.First().FullyQualifiedName, platform.PlatformLabel));
            }
            else
            {
                // We want to apply manifest filtering to the loading of the image info file. This allows, for example,
                // only images of a specific architecture to be pulled.
                ImageArtifactDetails imageArtifactDetails = ImageInfoHelper.LoadFromFile(
                    Options.ImageInfoPath, Manifest, skipManifestValidation: true, useFilteredManifest: true);
                platformTags = imageArtifactDetails.Repos
                               .SelectMany(repo => repo.Images)
                               .SelectMany(image => image.Platforms)
                               // If the platform doesn't have an associated manifest instance, it means the manifest filter
                               // options had filtered out the platform. In that case, it doesn't apply and shouldn't be pulled.
                               .Where(platform => platform.PlatformInfo is not null && platform.SimpleTags.Any())
                               .Select(platform => (
                                           TagInfo.GetFullyQualifiedName(platform.PlatformInfo !.FullRepoModelName, platform.SimpleTags.First()),
                                           platform.PlatformInfo !.PlatformLabel));
            }

            platformTags = platformTags
                           .Distinct()
                           .ToList();

            _loggerService.WriteHeading("PULLING IMAGES");
            foreach ((string tag, string platform) in platformTags)
            {
                _dockerService.PullImage(tag, platform, Options.IsDryRun);
            }

            if (Options.OutputVariableName is not null)
            {
                _loggerService.WriteMessage(
                    PipelineHelper.FormatOutputVariable(
                        Options.OutputVariableName,
                        string.Join(',', platformTags.Select(platformTag => platformTag.Tag))));
            }

            return(Task.CompletedTask);
        }
Exemple #7
0
        private async Task <IEnumerable <string> > GetPathsToRebuildAsync(Subscription subscription)
        {
            // If the command is filtered with an OS type that does not match the OsType filter of the subscription,
            // then there are no images that need to be inspected.
            string osTypeRegexPattern = ManifestFilter.GetFilterRegexPattern(Options.FilterOptions.OsType);

            if (!string.IsNullOrEmpty(subscription.OsType) &&
                !Regex.IsMatch(subscription.OsType, osTypeRegexPattern, RegexOptions.IgnoreCase))
            {
                return(Enumerable.Empty <string>());
            }

            _loggerService.WriteMessage($"Processing subscription:  {subscription.Id}");

            string repoPath = await GetGitRepoPath(subscription);

            TempManifestOptions manifestOptions = new TempManifestOptions(Options.FilterOptions)
            {
                Manifest = Path.Combine(repoPath, subscription.Manifest.Path)
            };

            ManifestInfo manifest = ManifestInfo.Load(manifestOptions);

            ImageArtifactDetails imageArtifactDetails = await GetImageInfoForSubscriptionAsync(subscription, manifest);

            List <string> pathsToRebuild = new List <string>();

            IEnumerable <PlatformInfo> allPlatforms = manifest.GetAllPlatforms().ToList();

            foreach (RepoInfo repo in manifest.FilteredRepos)
            {
                IEnumerable <PlatformInfo> platforms = repo.FilteredImages
                                                       .SelectMany(image => image.FilteredPlatforms)
                                                       .Where(platform => !platform.IsInternalFromImage(platform.FinalStageFromImage));

                RepoData repoData = imageArtifactDetails.Repos
                                    .FirstOrDefault(s => s.Repo == repo.Name);

                foreach (PlatformInfo platform in platforms)
                {
                    pathsToRebuild.AddRange(GetPathsToRebuild(allPlatforms, platform, repoData));
                }
            }

            return(pathsToRebuild.Distinct().ToList());
        }
        private async Task RunTestAsync(ImageArtifactDetails input, ImageArtifactDetails expectedOutput)
        {
            using TempFolderContext tempFolderContext = new TempFolderContext();

            TrimUnchangedPlatformsCommand command = new TrimUnchangedPlatformsCommand(Mock.Of <ILoggerService>());

            command.Options.ImageInfoPath = Path.Combine(tempFolderContext.Path, "imageinfo.json");

            File.WriteAllText(command.Options.ImageInfoPath, JsonHelper.SerializeObject(input));

            await command.ExecuteAsync();

            string expectedContents = JsonHelper.SerializeObject(expectedOutput);
            string actualContents   = File.ReadAllText(command.Options.ImageInfoPath);

            Assert.Equal(expectedContents, actualContents);
        }
        private async Task ValidateExecuteAsync(
            TempFolderContext tempFolderContext,
            string manifestPath,
            ImageArtifactDetails srcImageArtifactDetails,
            string expectedImageData,
            string expectedLayerData)
        {
            string imageInfoPath = Path.Combine(tempFolderContext.Path, "image-info.json");

            File.WriteAllText(imageInfoPath, JsonHelper.SerializeObject(srcImageArtifactDetails));

            Dictionary <string, string> ingestedData = new();

            Mock <IKustoClient> kustoClientMock = new();

            kustoClientMock
            .Setup(o => o.IngestFromCsvAsync(
                       It.IsAny <string>(), It.IsAny <ServicePrincipalOptions>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <bool>()))
            .Callback <string, ServicePrincipalOptions, string, string, string, bool>(
                (csv, servicePrincipal, cluster, database, table, isDryRun) =>
            {
                ingestedData.Add(table, csv);
            });
            IngestKustoImageInfoCommand command = new(Mock.Of <ILoggerService>(), kustoClientMock.Object);

            command.Options.ImageInfoPath = imageInfoPath;
            command.Options.Manifest      = manifestPath;
            command.Options.ImageTable    = "ImageInfo";
            command.Options.LayerTable    = "LayerInfo";

            command.LoadManifest();
            await command.ExecuteAsync();

            _outputHelper.WriteLine($"Expected Image Data: {Environment.NewLine}{expectedImageData}");
            _outputHelper.WriteLine($"Actual Image Data: {Environment.NewLine}{ingestedData[command.Options.ImageTable]}");

            _outputHelper.WriteLine($"Expected Layer Data: {Environment.NewLine}{expectedLayerData}");
            _outputHelper.WriteLine($"Actual Layer Data: {Environment.NewLine}{ingestedData[command.Options.LayerTable]}");

            kustoClientMock.Verify(o => o.IngestFromCsvAsync(
                                       It.IsAny <string>(), It.IsAny <ServicePrincipalOptions>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <bool>()));
            Assert.Equal(expectedImageData, ingestedData[command.Options.ImageTable]);
            Assert.Equal(expectedLayerData, ingestedData[command.Options.LayerTable]);
        }
        private string?GetUpdatedImageInfo(string repoPath)
        {
            ImageArtifactDetails srcImageArtifactDetails = ImageInfoHelper.LoadFromFile(Options.ImageInfoPath, Manifest);

            string repoImageInfoPath = Path.Combine(repoPath, Options.GitOptions.Path);
            string originalTargetImageInfoContents = File.ReadAllText(repoImageInfoPath);

            ImageArtifactDetails newImageArtifactDetails;

            if (originalTargetImageInfoContents != null)
            {
                ImageArtifactDetails targetImageArtifactDetails = ImageInfoHelper.LoadFromContent(
                    originalTargetImageInfoContents, Manifest, skipManifestValidation: true);

                RemoveOutOfDateContent(targetImageArtifactDetails);

                ImageInfoMergeOptions options = new ImageInfoMergeOptions
                {
                    IsPublish = true
                };

                ImageInfoHelper.MergeImageArtifactDetails(srcImageArtifactDetails, targetImageArtifactDetails, options);

                newImageArtifactDetails = targetImageArtifactDetails;
            }
            else
            {
                // If there is no existing file to update, there's nothing to merge with so the source data
                // becomes the target data.
                newImageArtifactDetails = srcImageArtifactDetails;
            }

            string newTargetImageInfoContents =
                JsonHelper.SerializeObject(newImageArtifactDetails) + Environment.NewLine;

            if (originalTargetImageInfoContents != newTargetImageInfoContents)
            {
                return(newTargetImageInfoContents);
            }
            else
            {
                return(null);
            }
        }
        private async Task SaveTagInfoToImageInfoFileAsync(DateTime createdDate, ImageArtifactDetails imageArtifactDetails)
        {
            _loggerService.WriteSubheading("SETTING TAG INFO");

            IEnumerable <ImageData> images = imageArtifactDetails.Repos
                                             .SelectMany(repo => repo.Images)
                                             .Where(image => image.Manifest != null);

            await Parallel.ForEachAsync(images, async (image, cancellationToken) =>
            {
                image.Manifest.Created = createdDate;

                TagInfo sharedTag = image.ManifestImage.SharedTags.First();

                image.Manifest.Digest = DockerHelper.GetDigestString(
                    image.ManifestRepo.FullModelName,
                    await _manifestToolService.GetManifestDigestShaAsync(
                        sharedTag.FullyQualifiedName, Options.CredentialsOptions, Options.IsDryRun));

                IEnumerable <(string Repo, string Tag)> syndicatedRepresentativeSharedTags = image.ManifestImage.SharedTags
                                                                                             .Where(tag => tag.SyndicatedRepo is not null)
                                                                                             .GroupBy(tag => tag.SyndicatedRepo)
                                                                                             .Select(group => (group.Key, group.First().SyndicatedDestinationTags.First()))
                                                                                             .Cast <(string Repo, string Tag)>()
                                                                                             .OrderBy(obj => obj.Repo)
                                                                                             .ThenBy(obj => obj.Tag);

                foreach ((string Repo, string Tag)syndicatedSharedTag in syndicatedRepresentativeSharedTags)
                {
                    string digest = DockerHelper.GetDigestString(
                        DockerHelper.GetImageName(Manifest.Model.Registry, syndicatedSharedTag.Repo),
                        await _manifestToolService.GetManifestDigestShaAsync(
                            DockerHelper.GetImageName(Manifest.Registry, Options.RepoPrefix + syndicatedSharedTag.Repo, syndicatedSharedTag.Tag),
                            Options.CredentialsOptions,
                            Options.IsDryRun));
                    image.Manifest.SyndicatedDigests.Add(digest);
                }
            });

            string imageInfoString = JsonHelper.SerializeObject(imageArtifactDetails);

            File.WriteAllText(Options.ImageInfoPath, imageInfoString);
        }
        private void WriteImagesMarkdown(StringBuilder notificationMarkdown)
        {
            if (!File.Exists(Options.ImageInfoPath))
            {
                return;
            }

            ImageArtifactDetails    imageArtifactDetails = ImageInfoHelper.LoadFromFile(Options.ImageInfoPath, Manifest);
            IEnumerable <ImageData> images = imageArtifactDetails.Repos.SelectMany(repo => repo.Images);
            List <(string digestSha, IEnumerable <string> tags)> publishedImages = new();

            foreach (ImageData image in images)
            {
                if (image.Manifest is not null)
                {
                    string digestSha          = DockerHelper.GetDigestSha(image.Manifest.Digest);
                    IEnumerable <string> tags = GetTags(image.ManifestImage.SharedTags);
                    publishedImages.Add((digestSha, tags));
                }

                publishedImages.AddRange(
                    image.Platforms
                    .Where(platform => platform.PlatformInfo.Tags.Any())
                    .Select(platform =>
                {
                    string digestSha          = DockerHelper.GetDigestSha(platform.Digest);
                    IEnumerable <string> tags = GetTags(platform.PlatformInfo.Tags);
                    return(digestSha, tags);
                }));
            }

            notificationMarkdown.AppendLine("## Images");
            notificationMarkdown.AppendLine();

            foreach ((string digestSha, IEnumerable <string> tags) in publishedImages.OrderBy(digestTags => digestTags.digestSha))
            {
                notificationMarkdown.AppendLine($"* {digestSha}");
                foreach (string tag in tags.OrderBy(tag => tag))
                {
                    notificationMarkdown.AppendLine($"  * {tag}");
                }
            }
        }
Exemple #13
0
        public override Task ExecuteAsync()
        {
            _loggerService.WriteHeading("GENERATING MANIFESTS");

            ImageArtifactDetails imageArtifactDetails = ImageInfoHelper.LoadFromFile(Options.ImageInfoPath, Manifest);

            ExecuteWithUser(() =>
            {
                IEnumerable <string> manifests = Manifest.FilteredRepos
                                                 .SelectMany(repo =>
                                                             repo.FilteredImages
                                                             .Where(image => image.SharedTags.Any())
                                                             .Select(image => (repo, image)))
                                                 .SelectMany(repoImage => GenerateManifests(repoImage.repo, repoImage.image))
                                                 .ToList();

                DateTime createdDate = DateTime.Now.ToUniversalTime();
                Parallel.ForEach(manifests, manifest =>
                {
                    string manifestFilename = $"manifest.{Guid.NewGuid()}.yml";
                    _loggerService.WriteSubheading($"PUBLISHING MANIFEST:  '{manifestFilename}'{Environment.NewLine}{manifest}");
                    File.WriteAllText(manifestFilename, manifest);

                    try
                    {
                        _manifestToolService.PushFromSpec(manifestFilename, Options.IsDryRun);
                    }
                    finally
                    {
                        File.Delete(manifestFilename);
                    }
                });

                WriteManifestSummary();

                SaveTagInfoToImageInfoFile(createdDate, imageArtifactDetails);
            });

            return(Task.CompletedTask);
        }
Exemple #14
0
        public static ImageArtifactDetails LoadFromContent(string imageInfoContent, ManifestInfo manifest, bool skipManifestValidation = false)
        {
            ImageArtifactDetails imageArtifactDetails = JsonConvert.DeserializeObject <ImageArtifactDetails>(imageInfoContent);

            foreach (RepoData repoData in imageArtifactDetails.Repos)
            {
                RepoInfo manifestRepo = manifest.AllRepos.FirstOrDefault(repo => repo.Name == repoData.Repo);
                if (manifestRepo == null)
                {
                    Console.WriteLine($"Image info repo not loaded:  {repoData.Repo}");
                    continue;
                }
                foreach (ImageData imageData in repoData.Images)
                {
                    PlatformData platformData = imageData.Platforms.FirstOrDefault();
                    if (platformData != null)
                    {
                        foreach (ImageInfo manifestImage in manifestRepo.AllImages)
                        {
                            PlatformInfo matchingManifestPlatform = manifestImage.AllPlatforms
                                                                    .FirstOrDefault(platform => platformData.Equals(platform));
                            if (matchingManifestPlatform != null)
                            {
                                imageData.ManifestImage = manifestImage;
                                break;
                            }
                        }

                        if (!skipManifestValidation && imageData.ManifestImage == null)
                        {
                            throw new InvalidOperationException(
                                      $"Unable to find matching platform in manifest for platform '{platformData.GetIdentifier()}'.");
                        }
                    }
                }
            }

            return(imageArtifactDetails);
        }
Exemple #15
0
        private void SaveTagInfoToImageInfoFile(DateTime createdDate, ImageArtifactDetails imageArtifactDetails)
        {
            _loggerService.WriteSubheading("SETTING TAG INFO");

            IEnumerable <ImageData> images = imageArtifactDetails.Repos
                                             .SelectMany(repo => repo.Images)
                                             .Where(image => image.Manifest != null);

            Parallel.ForEach(images, image =>
            {
                image.Manifest.Created = createdDate;

                TagInfo sharedTag     = image.ManifestImage.SharedTags.First();
                image.Manifest.Digest = DockerHelper.GetDigestString(
                    image.ManifestRepo.FullModelName,
                    _manifestToolService.GetManifestDigestSha(
                        ManifestMediaType.ManifestList, sharedTag.FullyQualifiedName, Options.IsDryRun));
            });

            string imageInfoString = JsonHelper.SerializeObject(imageArtifactDetails);

            File.WriteAllText(Options.ImageInfoPath, imageInfoString);
        }
Exemple #16
0
        public void ImageInfoHelper_MergeRepos_EmptyTarget()
        {
            ImageArtifactDetails imageArtifactDetails = new ImageArtifactDetails
            {
                Repos =
                {
                    new RepoData
                    {
                        Repo = "repo1",
                    },
                    new RepoData
                    {
                        Repo   = "repo2",
                        Images =
                        {
                            new ImageData
                            {
                                Platforms =
                                {
                                    new PlatformData
                                    {
                                        Dockerfile = "image1"
                                    }
                                }
                            }
                        }
                    }
                }
            };

            ImageArtifactDetails targetImageArtifactDetails = new ImageArtifactDetails();

            ImageInfoHelper.MergeImageArtifactDetails(imageArtifactDetails, targetImageArtifactDetails);

            CompareImageArtifactDetails(imageArtifactDetails, targetImageArtifactDetails);
        }
        public async Task MergeImageInfoFilesCommand_SourceFolderEmpty()
        {
            using (TempFolderContext context = TestHelper.UseTempFolder())
            {
                ImageArtifactDetails imageArtifactDetails = new ImageArtifactDetails
                {
                    Repos =
                    {
                        new RepoData {
                            Repo = "repo"
                        }
                    }
                };

                // Store the content in a .txt file which the command should NOT be looking for.
                File.WriteAllText("image-info.txt", JsonHelper.SerializeObject(imageArtifactDetails));

                MergeImageInfoCommand command = new MergeImageInfoCommand();
                command.Options.SourceImageInfoFolderPath = context.Path;
                command.Options.DestinationImageInfoPath  = "output.json";

                await Assert.ThrowsAsync <InvalidOperationException>(() => command.ExecuteAsync());
            }
        }
Exemple #18
0
        public async Task PublishImageInfoCommand_ReplaceTags()
        {
            using (TempFolderContext tempFolderContext = TestHelper.UseTempFolder())
            {
                string   repo1Image1DockerfilePath = DockerfileHelper.CreateDockerfile("1.0/runtime/os", tempFolderContext);
                string   repo2Image2DockerfilePath = DockerfileHelper.CreateDockerfile("2.0/runtime/os", tempFolderContext);
                Manifest manifest = CreateManifest(
                    CreateRepo("repo1",
                               CreateImage(
                                   CreatePlatform(repo1Image1DockerfilePath, new string[0]))),
                    CreateRepo("repo2",
                               CreateImage(
                                   CreatePlatform(repo2Image2DockerfilePath, new string[0])))
                    );

                RepoData repo2;

                ImageArtifactDetails srcImageArtifactDetails = new ImageArtifactDetails
                {
                    Repos =
                    {
                        new RepoData
                        {
                            Repo   = "repo1",
                            Images =
                            {
                                new ImageData
                                {
                                    Platforms =
                                    {
                                        Helpers.ImageInfoHelper.CreatePlatform(repo1Image1DockerfilePath,
                                                                               simpleTags: new List <string>
                                        {
                                            "newtag"
                                        })
                                    }
                                }
                            }
                        },
                        {
                            repo2 = new RepoData
                            {
                                Repo   = "repo2",
                                Images =
                                {
                                    new ImageData
                                    {
                                        Platforms =
                                        {
                                            Helpers.ImageInfoHelper.CreatePlatform(repo2Image2DockerfilePath,
                                                                                   simpleTags: new List <string>
                                            {
                                                "tag1"
                                            })
                                        }
                                    }
                                }
                            }
                        }
                    }
                };

                string file = Path.Combine(tempFolderContext.Path, "image-info.json");
                File.WriteAllText(file, JsonHelper.SerializeObject(srcImageArtifactDetails));

                ImageArtifactDetails targetImageArtifactDetails = new ImageArtifactDetails
                {
                    Repos =
                    {
                        new RepoData
                        {
                            Repo   = "repo1",
                            Images =
                            {
                                new ImageData
                                {
                                    Platforms =
                                    {
                                        Helpers.ImageInfoHelper.CreatePlatform(repo1Image1DockerfilePath,
                                                                               simpleTags: new List <string>
                                        {
                                            "oldtag"
                                        })
                                    }
                                }
                            }
                        }
                    }
                };

                Mock <IGitHubClient> gitHubClientMock = GetGitHubClientMock();

                Mock <IGitHubClientFactory> gitHubClientFactoryMock = new Mock <IGitHubClientFactory>();
                gitHubClientFactoryMock
                .Setup(o => o.GetClient(It.IsAny <GitHubAuth>(), false))
                .Returns(gitHubClientMock.Object);

                GitOptions gitOptions = new GitOptions
                {
                    AuthToken = "token",
                    Repo      = "testRepo",
                    Branch    = "testBranch",
                    Path      = "imageinfo.json"
                };

                PublishImageInfoCommand command = new PublishImageInfoCommand(
                    gitHubClientFactoryMock.Object, Mock.Of <ILoggerService>(),
                    CreateHttpClientFactory(gitOptions, targetImageArtifactDetails));
                command.Options.ImageInfoPath = file;
                command.Options.GitOptions    = gitOptions;
                command.Options.Manifest      = Path.Combine(tempFolderContext.Path, "manifest.json");

                File.WriteAllText(Path.Combine(tempFolderContext.Path, command.Options.Manifest), JsonConvert.SerializeObject(manifest));

                command.LoadManifest();
                await command.ExecuteAsync();

                ImageArtifactDetails expectedImageArtifactDetails = new ImageArtifactDetails
                {
                    Repos =
                    {
                        new RepoData
                        {
                            Repo   = "repo1",
                            Images =
                            {
                                new ImageData
                                {
                                    Platforms =
                                    {
                                        Helpers.ImageInfoHelper.CreatePlatform(repo1Image1DockerfilePath,
                                                                               simpleTags: new List <string>
                                        {
                                            "newtag"
                                        })
                                    }
                                }
                            }
                        },
                        repo2
                    }
                };

                Func <GitObject[], bool> verifyGitObjects = (gitObjects) =>
                {
                    if (gitObjects.Length != 1)
                    {
                        return(false);
                    }

                    return(gitObjects[0].Content.Trim() == JsonHelper.SerializeObject(expectedImageArtifactDetails).Trim());
                };

                gitHubClientMock.Verify(
                    o => o.PostTreeAsync(It.IsAny <GitHubProject>(), It.IsAny <string>(), It.Is <GitObject[]>(gitObjects => verifyGitObjects(gitObjects))));
            }
        }
Exemple #19
0
        public void ImageInfoHelper_MergeRepos_ExistingTarget()
        {
            PlatformData repo2Image1;
            PlatformData repo2Image2;
            PlatformData repo2Image3;
            PlatformData repo3Image1;

            DateTime oldCreatedDate = DateTime.Now.Subtract(TimeSpan.FromDays(1));
            DateTime newCreatedDate = DateTime.Now;

            ImageInfo imageInfo1 = CreateImageInfo();
            ImageInfo imageInfo2 = CreateImageInfo();

            ImageArtifactDetails imageArtifactDetails = new ImageArtifactDetails
            {
                Repos =
                {
                    new RepoData
                    {
                        Repo   = "repo2",
                        Images =
                        {
                            new ImageData
                            {
                                ManifestImage = imageInfo1,
                                Platforms     =
                                {
                                    {
                                        repo2Image1 = new PlatformData
                                        {
                                            Dockerfile      = "image1",
                                            BaseImageDigest = "base1digest-NEW",
                                            Created         = newCreatedDate
                                        }
                                    },
                                    {
                                        repo2Image3 = new PlatformData
                                        {
                                            Dockerfile = "image3"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    new RepoData
                    {
                        Repo   = "repo3",
                        Images =
                        {
                            new ImageData
                            {
                                ManifestImage = imageInfo2,
                                Platforms     =
                                {
                                    {
                                        repo3Image1 = new PlatformData
                                        {
                                            Dockerfile = "image1"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    new RepoData
                    {
                        Repo = "repo4",
                    }
                }
            };

            ImageArtifactDetails targetImageArtifactDetails = new ImageArtifactDetails
            {
                Repos =
                {
                    new RepoData
                    {
                        Repo = "repo1"
                    },
                    new RepoData
                    {
                        Repo   = "repo2",
                        Images =
                        {
                            new ImageData
                            {
                                ManifestImage = imageInfo1,
                                Platforms     =
                                {
                                    new PlatformData
                                    {
                                        Dockerfile      = "image1",
                                        BaseImageDigest = "base1digest",
                                        Created         = oldCreatedDate
                                    },
                                    {
                                        repo2Image2 = new PlatformData
                                        {
                                            Dockerfile      = "image2",
                                            BaseImageDigest = "base2digest"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    new RepoData
                    {
                        Repo = "repo3"
                    }
                }
            };

            ImageInfoHelper.MergeImageArtifactDetails(imageArtifactDetails, targetImageArtifactDetails);

            ImageArtifactDetails expected = new ImageArtifactDetails
            {
                Repos =
                {
                    new RepoData
                    {
                        Repo = "repo1"
                    },
                    new RepoData
                    {
                        Repo   = "repo2",
                        Images =
                        {
                            new ImageData
                            {
                                Platforms =
                                {
                                    repo2Image1,
                                    repo2Image2,
                                    repo2Image3
                                }
                            }
                        }
                    },
                    new RepoData
                    {
                        Repo   = "repo3",
                        Images =
                        {
                            new ImageData
                            {
                                Platforms =
                                {
                                    repo3Image1
                                }
                            }
                        }
                    },
                    new RepoData
                    {
                        Repo = "repo4",
                    }
                }
            };

            CompareImageArtifactDetails(expected, targetImageArtifactDetails);
        }
        public async Task MergeImageInfoFilesCommand_DuplicateDockerfilePaths()
        {
            const string OsType = "Linux";
            const string Os1    = "bionic";
            const string Os2    = "focal";

            using (TempFolderContext context = TestHelper.UseTempFolder())
            {
                string dockerfile1 = CreateDockerfile("1.0/repo1/os1", context);
                string dockerfile2 = CreateDockerfile("1.0/repo1/os2", context);

                List <ImageArtifactDetails> imageArtifactDetailsList = new List <ImageArtifactDetails>
                {
                    new ImageArtifactDetails
                    {
                        Repos =
                        {
                            new RepoData
                            {
                                Repo   = "repo1",
                                Images =
                                {
                                    new ImageData
                                    {
                                        Platforms =
                                        {
                                            new PlatformData
                                            {
                                                Architecture = "arm32",
                                                OsVersion    = Os1,
                                                OsType       = OsType,
                                                Digest       = "digest1",
                                                Dockerfile   = dockerfile1,
                                                SimpleTags   =
                                                {
                                                    "tag1",
                                                    "tag2"
                                                }
                                            },
                                            new PlatformData
                                            {
                                                Architecture = "arm64",
                                                OsVersion    = Os1,
                                                OsType       = OsType,
                                                Digest       = "digest2",
                                                Dockerfile   = dockerfile1,
                                                SimpleTags   =
                                                {
                                                    "tag2"
                                                }
                                            }
                                        },
                                        ProductVersion = "1.0"
                                    },
                                    new ImageData
                                    {
                                        Platforms =
                                        {
                                            new PlatformData
                                            {
                                                Architecture = "arm32",
                                                OsVersion    = Os2,
                                                OsType       = OsType,
                                                Digest       = "digest4",
                                                Dockerfile   = dockerfile1,
                                                SimpleTags   =
                                                {
                                                    "tagA"
                                                }
                                            }
                                        },
                                        ProductVersion = "1.0"
                                    }
                                }
                            }
                        }
                    },
                    new ImageArtifactDetails
                    {
                        Repos =
                        {
                            new RepoData
                            {
                                Repo   = "repo1",
                                Images =
                                {
                                    new ImageData
                                    {
                                        Platforms =
                                        {
                                            new PlatformData
                                            {
                                                Architecture = "arm64",
                                                OsVersion    = Os1,
                                                OsType       = OsType,
                                                Digest       = "digest2-new",
                                                Dockerfile   = dockerfile1,
                                                SimpleTags   =
                                                {
                                                    "tag3",
                                                    "tag2"
                                                }
                                            }
                                        },
                                        ProductVersion = "1.0"
                                    }
                                }
                            }
                        }
                    },
                    new ImageArtifactDetails
                    {
                        Repos =
                        {
                            new RepoData
                            {
                                Repo   = "repo1",
                                Images =
                                {
                                    new ImageData
                                    {
                                        Platforms =
                                        {
                                            new PlatformData
                                            {
                                                Architecture = "amd64",
                                                Digest       = "digest3",
                                                OsVersion    = Os1,
                                                OsType       = OsType,
                                                Dockerfile   = dockerfile2,
                                                SimpleTags   =
                                                {
                                                    "tag1"
                                                }
                                            }
                                        },
                                        ProductVersion = "1.0"
                                    },
                                    new ImageData
                                    {
                                        Platforms =
                                        {
                                            new PlatformData
                                            {
                                                Architecture = "arm32",
                                                OsVersion    = Os2,
                                                OsType       = OsType,
                                                Digest       = "digest4-new",
                                                Dockerfile   = dockerfile1,
                                                SimpleTags   =
                                                {
                                                    "tagB"
                                                }
                                            }
                                        },
                                        ProductVersion = "1.0"
                                    }
                                }
                            }
                        }
                    }
                };

                MergeImageInfoCommand command = new MergeImageInfoCommand();
                command.Options.SourceImageInfoFolderPath = Path.Combine(context.Path, "image-infos");
                command.Options.DestinationImageInfoPath  = Path.Combine(context.Path, "output.json");
                command.Options.Manifest = Path.Combine(context.Path, "manifest.json");

                Directory.CreateDirectory(command.Options.SourceImageInfoFolderPath);
                for (int i = 0; i < imageArtifactDetailsList.Count; i++)
                {
                    string file = Path.Combine(command.Options.SourceImageInfoFolderPath, $"{i}.json");
                    File.WriteAllText(file, JsonHelper.SerializeObject(imageArtifactDetailsList[i]));
                }

                Manifest manifest = CreateManifest(
                    CreateRepo("repo1",
                               CreateImage(
                                   new Platform[]
                {
                    CreatePlatform(dockerfile1, new string[] { "tag1" }, osVersion: Os1, architecture: Architecture.ARM),
                    CreatePlatform(dockerfile1, new string[] { "tag2" }, osVersion: Os1, architecture: Architecture.ARM64)
                },
                                   productVersion: "1.0"),
                               CreateImage(
                                   new Platform[]
                {
                    CreatePlatform(dockerfile1, new string[] { "tag3" }, osVersion: Os2, architecture: Architecture.ARM)
                },
                                   productVersion: "1.0"),
                               CreateImage(
                                   new Platform[]
                {
                    CreatePlatform(dockerfile2, new string[] { "tag4" }, osVersion: Os1)
                },
                                   productVersion: "1.0"))
                    );
                File.WriteAllText(Path.Combine(context.Path, command.Options.Manifest), JsonConvert.SerializeObject(manifest));

                command.LoadManifest();
                await command.ExecuteAsync();

                string resultsContent       = File.ReadAllText(command.Options.DestinationImageInfoPath);
                ImageArtifactDetails actual = JsonConvert.DeserializeObject <ImageArtifactDetails>(resultsContent);

                ImageArtifactDetails expected = new ImageArtifactDetails
                {
                    Repos =
                    {
                        new RepoData
                        {
                            Repo   = "repo1",
                            Images =
                            {
                                new ImageData
                                {
                                    Platforms =
                                    {
                                        new PlatformData
                                        {
                                            Architecture = "arm32",
                                            OsVersion    = Os1,
                                            OsType       = OsType,
                                            Digest       = "digest1",
                                            Dockerfile   = dockerfile1,
                                            SimpleTags   =
                                            {
                                                "tag1",
                                                "tag2"
                                            }
                                        },
                                        new PlatformData
                                        {
                                            Architecture = "arm64",
                                            OsVersion    = Os1,
                                            OsType       = OsType,
                                            Digest       = "digest2-new",
                                            Dockerfile   = dockerfile1,
                                            SimpleTags   =
                                            {
                                                "tag2",
                                                "tag3"
                                            }
                                        }
                                    },
                                    ProductVersion = "1.0"
                                },
                                new ImageData
                                {
                                    Platforms =
                                    {
                                        new PlatformData
                                        {
                                            Architecture = "arm32",
                                            OsVersion    = Os2,
                                            OsType       = OsType,
                                            Digest       = "digest4-new",
                                            Dockerfile   = dockerfile1,
                                            SimpleTags   =
                                            {
                                                "tagA",
                                                "tagB"
                                            }
                                        }
                                    },
                                    ProductVersion = "1.0"
                                },
                                new ImageData
                                {
                                    Platforms =
                                    {
                                        new PlatformData
                                        {
                                            Architecture = "amd64",
                                            Digest       = "digest3",
                                            OsVersion    = Os1,
                                            OsType       = OsType,
                                            Dockerfile   = dockerfile2,
                                            SimpleTags   =
                                            {
                                                "tag1"
                                            }
                                        }
                                    },
                                    ProductVersion = "1.0"
                                }
                            }
                        }
                    }
                };

                ImageInfoHelperTests.CompareImageArtifactDetails(expected, actual);
            }
        }
        public async Task MergeImageInfoFilesCommand_HappyPath()
        {
            using (TempFolderContext context = TestHelper.UseTempFolder())
            {
                string repo2Image1Dockerfile = CreateDockerfile("1.0/repo2/os1", context);
                string repo2Image2Dockerfile = CreateDockerfile("1.0/repo2/os2", context);
                string repo4Image2Dockerfile = CreateDockerfile("1.0/repo4/os2", context);
                string repo4Image3Dockerfile = CreateDockerfile("1.0/repo4/os3", context);

                List <ImageArtifactDetails> imageArtifactDetailsList = new List <ImageArtifactDetails>
                {
                    new ImageArtifactDetails
                    {
                        Repos =
                        {
                            new RepoData
                            {
                                Repo = "repo1"
                            },
                            new RepoData
                            {
                                Repo   = "repo2",
                                Images =
                                {
                                    new ImageData
                                    {
                                        Platforms =
                                        {
                                            CreatePlatform(
                                                repo2Image1Dockerfile,
                                                simpleTags: new List <string>
                                            {
                                                "tag3"
                                            })
                                        },
                                        ProductVersion = "1.0"
                                    },
                                    new ImageData
                                    {
                                        Platforms =
                                        {
                                            CreatePlatform(repo2Image2Dockerfile)
                                        },
                                        ProductVersion = "1.0"
                                    }
                                }
                            },
                            new RepoData
                            {
                                Repo   = "repo4",
                                Images =
                                {
                                    new ImageData
                                    {
                                        Platforms =
                                        {
                                            CreatePlatform(
                                                repo4Image2Dockerfile,
                                                simpleTags: new List <string>
                                            {
                                                "tag1"
                                            })
                                        },
                                        ProductVersion = "1.0"
                                    }
                                }
                            }
                        }
                    },
                    new ImageArtifactDetails
                    {
                        Repos =
                        {
                            new RepoData
                            {
                                Repo   = "repo2",
                                Images =
                                {
                                    new ImageData
                                    {
                                        Platforms =
                                        {
                                            CreatePlatform(
                                                repo2Image1Dockerfile,
                                                simpleTags: new List <string>
                                            {
                                                "tag1"
                                            },
                                                baseImageDigest: "base1hash")
                                        },
                                        ProductVersion = "1.0"
                                    },
                                    new ImageData
                                    {
                                        Platforms =
                                        {
                                            CreatePlatform(
                                                repo2Image2Dockerfile,
                                                simpleTags: new List <string>
                                            {
                                                "tag2"
                                            })
                                        },
                                        ProductVersion = "1.0"
                                    }
                                }
                            },
                            new RepoData
                            {
                                Repo = "repo3",
                            },
                            new RepoData
                            {
                                Repo   = "repo4",
                                Images =
                                {
                                    new ImageData
                                    {
                                        Platforms =
                                        {
                                            CreatePlatform(
                                                repo4Image2Dockerfile,
                                                simpleTags: new List <string>
                                            {
                                                "tag2"
                                            })
                                        },
                                        ProductVersion = "1.0"
                                    },
                                    new ImageData
                                    {
                                        Platforms =
                                        {
                                            CreatePlatform(
                                                repo4Image3Dockerfile,
                                                simpleTags: new List <string>
                                            {
                                                "tag1"
                                            })
                                        },
                                        ProductVersion = "1.0"
                                    }
                                }
                            }
                        }
                    }
                };

                MergeImageInfoCommand command = new MergeImageInfoCommand();
                command.Options.SourceImageInfoFolderPath = Path.Combine(context.Path, "image-infos");
                command.Options.DestinationImageInfoPath  = Path.Combine(context.Path, "output.json");
                command.Options.Manifest = Path.Combine(context.Path, "manifest.json");

                Directory.CreateDirectory(command.Options.SourceImageInfoFolderPath);
                for (int i = 0; i < imageArtifactDetailsList.Count; i++)
                {
                    string file = Path.Combine(command.Options.SourceImageInfoFolderPath, $"{i}.json");
                    File.WriteAllText(file, JsonHelper.SerializeObject(imageArtifactDetailsList[i]));
                }

                Manifest manifest = CreateManifest(
                    CreateRepo("repo1"),
                    CreateRepo("repo2",
                               CreateImage(
                                   new Platform[]
                {
                    CreatePlatform(repo2Image1Dockerfile, new string[] { "tag1" })
                },
                                   productVersion: "1.0"),
                               CreateImage(
                                   new Platform[]
                {
                    CreatePlatform(repo2Image2Dockerfile, new string[] { "tag2" })
                },
                                   productVersion: "1.0")),
                    CreateRepo("repo3"),
                    CreateRepo("repo4",
                               CreateImage(
                                   new Platform[]
                {
                    CreatePlatform(repo4Image2Dockerfile, new string[] { "tag1" })
                },
                                   productVersion: "1.0"),
                               CreateImage(
                                   new Platform[]
                {
                    CreatePlatform(repo4Image3Dockerfile, new string[] { "tag2" })
                },
                                   productVersion: "1.0"))
                    );
                File.WriteAllText(Path.Combine(context.Path, command.Options.Manifest), JsonConvert.SerializeObject(manifest));

                command.LoadManifest();
                await command.ExecuteAsync();

                string resultsContent       = File.ReadAllText(command.Options.DestinationImageInfoPath);
                ImageArtifactDetails actual = JsonConvert.DeserializeObject <ImageArtifactDetails>(resultsContent);

                ImageArtifactDetails expected = new ImageArtifactDetails
                {
                    Repos =
                    {
                        new RepoData
                        {
                            Repo = "repo1"
                        },
                        new RepoData
                        {
                            Repo   = "repo2",
                            Images =
                            {
                                new ImageData
                                {
                                    Platforms =
                                    {
                                        CreatePlatform(
                                            repo2Image1Dockerfile,
                                            simpleTags: new List <string>
                                        {
                                            "tag1",
                                            "tag3"
                                        },
                                            baseImageDigest: "base1hash")
                                    },
                                    ProductVersion = "1.0"
                                },
                                new ImageData
                                {
                                    Platforms =
                                    {
                                        CreatePlatform(
                                            repo2Image2Dockerfile,
                                            simpleTags: new List <string>
                                        {
                                            "tag2"
                                        })
                                    },
                                    ProductVersion = "1.0"
                                }
                            }
                        },
                        new RepoData
                        {
                            Repo = "repo3",
                        },
                        new RepoData
                        {
                            Repo   = "repo4",
                            Images =
                            {
                                new ImageData
                                {
                                    Platforms =
                                    {
                                        CreatePlatform(
                                            repo4Image2Dockerfile,
                                            simpleTags: new List <string>
                                        {
                                            "tag1",
                                            "tag2"
                                        })
                                    },
                                    ProductVersion = "1.0"
                                },
                                new ImageData
                                {
                                    Platforms =
                                    {
                                        CreatePlatform(
                                            repo4Image3Dockerfile,
                                            simpleTags: new List <string>
                                        {
                                            "tag1"
                                        })
                                    },
                                    ProductVersion = "1.0"
                                }
                            }
                        }
                    }
                };

                ImageInfoHelperTests.CompareImageArtifactDetails(expected, actual);
            }
        }
Exemple #22
0
        public async Task BuildCommand_ImageInfoOutput_Basic()
        {
            const string repoName        = "runtime";
            const string sha             = "sha256:c74364a9f125ca612f9a67e4a0551937b7a37c82fabb46172c4867b73edd638c";
            string       digest          = $"{repoName}@{sha}";
            const string tag             = "tag";
            const string baseImageRepo   = "baserepo";
            string       baseImageTag    = $"{baseImageRepo}:basetag";
            string       baseImageDigest = $"{baseImageRepo}@sha256:d21234a9f125ca612f9a67e4a0551937b7a37c82fabb46172c4867b73edd1349";

            using (TempFolderContext tempFolderContext = TestHelper.UseTempFolder())
            {
                Mock <IDockerService> dockerServiceMock = new Mock <IDockerService>();
                dockerServiceMock
                .SetupGet(o => o.Architecture)
                .Returns(Architecture.AMD64);

                dockerServiceMock
                .Setup(o => o.GetImageDigest($"{repoName}:{tag}", false))
                .Returns(digest);

                dockerServiceMock
                .Setup(o => o.GetImageDigest(baseImageTag, false))
                .Returns(baseImageDigest);

                DateTime createdDate = DateTime.Now;

                dockerServiceMock
                .Setup(o => o.GetCreatedDate($"{repoName}:{tag}", false))
                .Returns(createdDate);

                const string runtimeRelativeDir = "1.0/runtime/os";
                Directory.CreateDirectory(Path.Combine(tempFolderContext.Path, runtimeRelativeDir));
                string dockerfileRelativePath = PathHelper.NormalizePath(Path.Combine(runtimeRelativeDir, "Dockerfile"));
                string fullDockerfilePath     = PathHelper.NormalizePath(Path.Combine(tempFolderContext.Path, dockerfileRelativePath));
                File.WriteAllText(fullDockerfilePath, $"FROM {baseImageTag}");

                const string       dockerfileCommitSha = "mycommit";
                Mock <IGitService> gitServiceMock      = new Mock <IGitService>();
                gitServiceMock
                .Setup(o => o.GetCommitSha(fullDockerfilePath, It.IsAny <bool>()))
                .Returns(dockerfileCommitSha);

                BuildCommand command = new BuildCommand(dockerServiceMock.Object, Mock.Of <ILoggerService>(), Mock.Of <IEnvironmentService>(),
                                                        gitServiceMock.Object);
                command.Options.Manifest            = Path.Combine(tempFolderContext.Path, "manifest.json");
                command.Options.ImageInfoOutputPath = Path.Combine(tempFolderContext.Path, "image-info.json");
                command.Options.IsPushEnabled       = true;
                command.Options.SourceRepoUrl       = "https://github.com/dotnet/test";

                const string ProductVersion = "1.0.1";

                Manifest manifest = CreateManifest(
                    CreateRepo(repoName,
                               CreateImage(
                                   new Platform[]
                {
                    CreatePlatform(dockerfileRelativePath, new string[] { tag })
                },
                                   new Dictionary <string, Tag>
                {
                    { "shared", new Tag() }
                },
                                   ProductVersion))
                    );

                File.WriteAllText(Path.Combine(tempFolderContext.Path, command.Options.Manifest), JsonConvert.SerializeObject(manifest));

                command.LoadManifest();
                await command.ExecuteAsync();

                ImageArtifactDetails imageArtifactDetails = new ImageArtifactDetails
                {
                    Repos =
                    {
                        new RepoData
                        {
                            Repo   = repoName,
                            Images =
                            {
                                new ImageData
                                {
                                    ProductVersion = ProductVersion,
                                    Platforms      =
                                    {
                                        new PlatformData
                                        {
                                            Dockerfile      = $"{runtimeRelativeDir}/Dockerfile",
                                            Architecture    = "amd64",
                                            OsType          = "Linux",
                                            OsVersion       = "Ubuntu 19.04",
                                            Digest          = sha,
                                            BaseImageDigest = baseImageDigest,
                                            Created         = createdDate.ToUniversalTime(),
                                            SimpleTags      =
                                            {
                                                tag
                                            },
                                            CommitUrl = $"{command.Options.SourceRepoUrl}/blob/{dockerfileCommitSha}/{dockerfileRelativePath}"
                                        }
                                    },
                                    Manifest = new ManifestData
                                    {
                                        SharedTags =
                                        {
                                            "shared"
                                        }
                                    }
                                }
                            }
                        }
                    }
                };

                string expectedOutput = JsonHelper.SerializeObject(imageArtifactDetails);
                string actualOutput   = File.ReadAllText(command.Options.ImageInfoOutputPath);

                Assert.Equal(expectedOutput, actualOutput);
            }
        }
Exemple #23
0
        public void ImageInfoHelper_MergeRepos_MergeTags()
        {
            PlatformData srcImage1;
            PlatformData targetImage2;

            ImageInfo imageInfo1 = CreateImageInfo();

            ImageArtifactDetails imageArtifactDetails = new ImageArtifactDetails
            {
                Repos =
                {
                    new RepoData
                    {
                        Repo   = "repo1",
                        Images =
                        {
                            new ImageData
                            {
                                ManifestImage = imageInfo1,
                                Platforms     =
                                {
                                    {
                                        srcImage1 = new PlatformData
                                        {
                                            Dockerfile = "image1",
                                            SimpleTags =
                                            {
                                                "tag1",
                                                "tag3"
                                            }
                                        }
                                    }
                                },
                                Manifest = new ManifestData
                                {
                                    SharedTags =
                                    {
                                        "shared1",
                                        "shared2"
                                    }
                                }
                            }
                        }
                    }
                }
            };

            ImageArtifactDetails targetImageArtifactDetails = new ImageArtifactDetails
            {
                Repos =
                {
                    new RepoData
                    {
                        Repo   = "repo1",
                        Images =
                        {
                            new ImageData
                            {
                                ManifestImage = imageInfo1,
                                Platforms     =
                                {
                                    new PlatformData
                                    {
                                        Dockerfile = "image1",
                                        SimpleTags =
                                        {
                                            "tag1",
                                            "tag2",
                                            "tag4"
                                        }
                                    },
                                    {
                                        targetImage2 = new PlatformData
                                        {
                                            Dockerfile = "image2",
                                            SimpleTags =
                                            {
                                                "a"
                                            }
                                        }
                                    }
                                },
                                Manifest = new ManifestData
                                {
                                    SharedTags =
                                    {
                                        "shared2",
                                        "shared3"
                                    }
                                }
                            }
                        }
                    }
                }
            };

            ImageInfoHelper.MergeImageArtifactDetails(imageArtifactDetails, targetImageArtifactDetails);

            ImageArtifactDetails expected = new ImageArtifactDetails
            {
                Repos =
                {
                    new RepoData
                    {
                        Repo   = "repo1",
                        Images =
                        {
                            new ImageData
                            {
                                Platforms =
                                {
                                    new PlatformData
                                    {
                                        Dockerfile = "image1",
                                        SimpleTags =
                                        {
                                            "tag1",
                                            "tag2",
                                            "tag3",
                                            "tag4"
                                        }
                                    },
                                    targetImage2
                                },
                                Manifest = new ManifestData
                                {
                                    SharedTags =
                                    {
                                        "shared1",
                                        "shared2",
                                        "shared3"
                                    }
                                }
                            }
                        }
                    }
                }
            };

            CompareImageArtifactDetails(expected, targetImageArtifactDetails);
        }
 private IEnumerable <DigestInfo> GetImageDigestInfos(ImageArtifactDetails imageArtifactDetails) =>
 imageArtifactDetails.Repos
 .SelectMany(repo => repo.Images.SelectMany(image => GetImageDigestInfos(image, repo)));
Exemple #25
0
        public void ImageInfoHelper_MergeRepos_RemoveTag()
        {
            PlatformData srcPlatform1;
            PlatformData targetPlatform2;

            ImageInfo imageInfo1 = CreateImageInfo();

            ImageArtifactDetails imageArtifactDetails = new ImageArtifactDetails
            {
                Repos =
                {
                    new RepoData
                    {
                        Repo   = "repo1",
                        Images =
                        {
                            new ImageData
                            {
                                ManifestImage = imageInfo1,
                                Platforms     =
                                {
                                    {
                                        srcPlatform1 = new PlatformData
                                        {
                                            Dockerfile = "image1",
                                            SimpleTags =
                                            {
                                                "tag1",
                                                "tag3"
                                            }
                                        }
                                    }
                                },
                                Manifest = new ManifestData
                                {
                                    SharedTags =
                                    {
                                        "sharedtag1",
                                    }
                                }
                            }
                        }
                    }
                }
            };

            ImageArtifactDetails targetImageArtifactDetails = new ImageArtifactDetails
            {
                Repos =
                {
                    new RepoData
                    {
                        Repo   = "repo1",
                        Images =
                        {
                            new ImageData
                            {
                                ManifestImage = imageInfo1,
                                Platforms     =
                                {
                                    {
                                        new PlatformData
                                        {
                                            Dockerfile = "image1",
                                            SimpleTags =
                                            {
                                                "tag1",
                                                "tag2",
                                                "tag4"
                                            }
                                        }
                                    },
                                    {
                                        targetPlatform2 = new PlatformData
                                        {
                                            Dockerfile = "image2",
                                            SimpleTags =
                                            {
                                                "a"
                                            }
                                        }
                                    }
                                },
                                Manifest = new ManifestData
                                {
                                    SharedTags =
                                    {
                                        "sharedtag2",
                                    }
                                }
                            }
                        }
                    }
                }
            };

            ImageInfoMergeOptions options = new ImageInfoMergeOptions
            {
                ReplaceTags = true
            };

            ImageInfoHelper.MergeImageArtifactDetails(imageArtifactDetails, targetImageArtifactDetails, options);

            ImageArtifactDetails expected = new ImageArtifactDetails
            {
                Repos =
                {
                    new RepoData
                    {
                        Repo   = "repo1",
                        Images =
                        {
                            new ImageData
                            {
                                Platforms =
                                {
                                    srcPlatform1,
                                    targetPlatform2
                                },
                                Manifest = new ManifestData
                                {
                                    SharedTags =
                                    {
                                        "sharedtag1",
                                    }
                                }
                            }
                        }
                    }
                }
            };

            CompareImageArtifactDetails(expected, targetImageArtifactDetails);
        }
Exemple #26
0
        public async Task IngestKustoImageInfoCommand_MultipleRepos()
        {
            using TempFolderContext tempFolderContext = TestHelper.UseTempFolder();

            string   repo1Image1DockerfilePath = DockerfileHelper.CreateDockerfile("1.0/sdk/os", tempFolderContext);
            string   repo1Image2DockerfilePath = DockerfileHelper.CreateDockerfile("1.0/sdk/os2", tempFolderContext);
            string   repo2Image2DockerfilePath = DockerfileHelper.CreateDockerfile("2.0/sdk/os", tempFolderContext);
            Manifest manifest = CreateManifest(
                CreateRepo("r1",
                           CreateImage(
                               new Platform[]
            {
                CreatePlatform(repo1Image1DockerfilePath, new string[] { "t1" }),
                CreatePlatform(repo1Image2DockerfilePath, new string[] { "t2" })
            },
                               productVersion: "1.0.2",
                               sharedTags: new Dictionary <string, Tag>
            {
                { "st1", new Tag() }
            })),
                CreateRepo("r2",
                           CreateImage(
                               new Platform[]
            {
                CreatePlatform(repo2Image2DockerfilePath, new string[] { "t3" })
            },
                               productVersion: "2.0.5"))
                );
            string manifestPath = Path.Combine(tempFolderContext.Path, "manifest.json");

            File.WriteAllText(manifestPath, JsonConvert.SerializeObject(manifest));

            ImageArtifactDetails srcImageArtifactDetails = new ImageArtifactDetails
            {
                Repos =
                {
                    new RepoData
                    {
                        Repo   = "r1",
                        Images =
                        {
                            new ImageData
                            {
                                Manifest = new ManifestData
                                {
                                    Created    = new DateTime(2020, 4, 20, 21, 57, 00, DateTimeKind.Utc),
                                    Digest     = "abc",
                                    SharedTags = new List <string>
                                    {
                                        "st1"
                                    }
                                },
                                Platforms =
                                {
                                    {
                                        Helpers.ImageInfoHelper.CreatePlatform(
                                            repo1Image1DockerfilePath,
                                            created: new DateTime(2020, 4, 20, 21, 56, 50, DateTimeKind.Utc),
                                            digest: "def",
                                            simpleTags: new List <string>
                                        {
                                            "t1"
                                        })
                                    },
                                    {
                                        Helpers.ImageInfoHelper.CreatePlatform(
                                            repo1Image2DockerfilePath,
                                            created: new DateTime(2020, 4, 20, 21, 56, 56, DateTimeKind.Utc),
                                            digest: "ghi",
                                            simpleTags: new List <string>
                                        {
                                            "t2"
                                        })
                                    }
                                },
                                ProductVersion = "1.0.2",
                            }
                        }
                    },
                    new RepoData
                    {
                        Repo   = "r2",
                        Images =
                        {
                            new ImageData
                            {
                                Platforms =
                                {
                                    Helpers.ImageInfoHelper.CreatePlatform(
                                        repo2Image2DockerfilePath,
                                        created: new DateTime(2020, 4, 20, 21, 56, 58, DateTimeKind.Utc),
                                        digest: "jkl",
                                        simpleTags: new List <string>
                                    {
                                        "t3"
                                    })
                                },
                                ProductVersion = "2.0.5"
                            }
                        }
                    }
                }
            };

            string expectedData =
                @"""def"",""amd64"",""Linux"",""Ubuntu 20.04"",""1.0.2"",""1.0/sdk/os/Dockerfile"",""r1"",""2020-04-20 21:56:50""
""t1"",""amd64"",""Linux"",""Ubuntu 20.04"",""1.0.2"",""1.0/sdk/os/Dockerfile"",""r1"",""2020-04-20 21:56:50""
""ghi"",""amd64"",""Linux"",""Ubuntu 20.04"",""1.0.2"",""1.0/sdk/os2/Dockerfile"",""r1"",""2020-04-20 21:56:56""
""t2"",""amd64"",""Linux"",""Ubuntu 20.04"",""1.0.2"",""1.0/sdk/os2/Dockerfile"",""r1"",""2020-04-20 21:56:56""
""jkl"",""amd64"",""Linux"",""Ubuntu 20.04"",""2.0.5"",""2.0/sdk/os/Dockerfile"",""r2"",""2020-04-20 21:56:58""
""t3"",""amd64"",""Linux"",""Ubuntu 20.04"",""2.0.5"",""2.0/sdk/os/Dockerfile"",""r2"",""2020-04-20 21:56:58""";

            expectedData = expectedData.NormalizeLineEndings(Environment.NewLine).Trim();

            string imageInfoPath = Path.Combine(tempFolderContext.Path, "image-info.json");

            File.WriteAllText(imageInfoPath, JsonHelper.SerializeObject(srcImageArtifactDetails));

            string ingestedData = null;

            Mock <IKustoClient> kustoClientMock = new Mock <IKustoClient>();

            kustoClientMock
            .Setup(o => o.IngestFromCsvStreamAsync(It.IsAny <Stream>(), It.IsAny <IngestKustoImageInfoOptions>()))
            .Callback <Stream, IngestKustoImageInfoOptions>((s, o) =>
            {
                StreamReader reader = new StreamReader(s);
                ingestedData        = reader.ReadToEnd();
            });
            IngestKustoImageInfoCommand command = new IngestKustoImageInfoCommand(
                Mock.Of <ILoggerService>(), kustoClientMock.Object);

            command.Options.ImageInfoPath = imageInfoPath;
            command.Options.Manifest      = manifestPath;

            command.LoadManifest();
            await command.ExecuteAsync();

            _outputHelper.WriteLine($"Expected Data: {Environment.NewLine}{expectedData}");
            _outputHelper.WriteLine($"Actual Data: {Environment.NewLine}{ingestedData}");

            kustoClientMock.Verify(o => o.IngestFromCsvStreamAsync(It.IsAny <Stream>(), It.IsAny <IngestKustoImageInfoOptions>()));
            Assert.Equal(expectedData, ingestedData);
        }
Exemple #27
0
 public static void CompareImageArtifactDetails(ImageArtifactDetails expected, ImageArtifactDetails actual)
 {
     Assert.Equal(JsonHelper.SerializeObject(expected), JsonHelper.SerializeObject(actual));
 }
Exemple #28
0
        public void PlatformVersionedOs_Cached(bool isRuntimeCached, bool isAspnetCached, bool isSdkCached, string expectedPaths)
        {
            using TempFolderContext tempFolderContext = TestHelper.UseTempFolder();
            GenerateBuildMatrixCommand command = new GenerateBuildMatrixCommand();

            command.Options.Manifest                 = Path.Combine(tempFolderContext.Path, "manifest.json");
            command.Options.MatrixType               = MatrixType.PlatformVersionedOs;
            command.Options.ImageInfoPath            = Path.Combine(tempFolderContext.Path, "imageinfo.json");
            command.Options.ProductVersionComponents = 2;

            string   runtimeDockerfilePath;
            string   aspnetDockerfilePath;
            string   sdkDockerfilePath;
            Manifest manifest = CreateManifest(
                CreateRepo("runtime",
                           CreateImage(
                               new Platform[]
            {
                CreatePlatform(
                    runtimeDockerfilePath = DockerfileHelper.CreateDockerfile("1.0/runtime/os", tempFolderContext),
                    new string[] { "tag" })
            },
                               productVersion: "1.0")),
                CreateRepo("aspnet",
                           CreateImage(
                               new Platform[]
            {
                CreatePlatform(
                    aspnetDockerfilePath = DockerfileHelper.CreateDockerfile("1.0/aspnet/os", tempFolderContext, "runtime:tag"),
                    new string[] { "tag" })
            },
                               productVersion: "1.0")),
                CreateRepo("sdk",
                           CreateImage(
                               new Platform[]
            {
                CreatePlatform(
                    sdkDockerfilePath = DockerfileHelper.CreateDockerfile("1.0/sdk/os", tempFolderContext, "aspnet:tag"),
                    new string[] { "tag" })
            },
                               productVersion: "1.0"))
                );

            File.WriteAllText(Path.Combine(tempFolderContext.Path, command.Options.Manifest), JsonConvert.SerializeObject(manifest));

            ImageArtifactDetails imageArtifactDetails = new ImageArtifactDetails
            {
                Repos =
                {
                    new RepoData
                    {
                        Repo   = "runtime",
                        Images =
                        {
                            new ImageData
                            {
                                ProductVersion = "1.0",
                                Platforms      =
                                {
                                    CreateSimplePlatformData(runtimeDockerfilePath, isCached: isRuntimeCached)
                                }
                            }
                        }
                    },
                    new RepoData
                    {
                        Repo   = "aspnet",
                        Images =
                        {
                            new ImageData
                            {
                                ProductVersion = "1.0",
                                Platforms      =
                                {
                                    CreateSimplePlatformData(aspnetDockerfilePath, isCached: isAspnetCached)
                                }
                            }
                        }
                    },
                    new RepoData
                    {
                        Repo   = "sdk",
                        Images =
                        {
                            new ImageData
                            {
                                ProductVersion = "1.0",
                                Platforms      =
                                {
                                    CreateSimplePlatformData(sdkDockerfilePath, isCached: isSdkCached)
                                }
                            }
                        }
                    }
                }
            };

            File.WriteAllText(command.Options.ImageInfoPath, JsonHelper.SerializeObject(imageArtifactDetails));

            command.LoadManifest();
            IEnumerable <BuildMatrixInfo> matrixInfos = command.GenerateMatrixInfo();

            if (isRuntimeCached && isAspnetCached && isSdkCached)
            {
                Assert.Empty(matrixInfos);
            }
            else
            {
                Assert.Single(matrixInfos);
                Assert.Single(matrixInfos.First().Legs);

                BuildLegInfo buildLeg          = matrixInfos.First().Legs.First();
                string       imageBuilderPaths = buildLeg.Variables.First(variable => variable.Name == "imageBuilderPaths").Value;

                Assert.Equal(expectedPaths, imageBuilderPaths);
            }
        }
        public async Task MixOfCachedPlatforms()
        {
            ImageArtifactDetails imageArtifactDetails = new ImageArtifactDetails
            {
                Repos = new List <RepoData>
                {
                    new RepoData
                    {
                        Repo   = "repo1",
                        Images = new List <ImageData>
                        {
                            new ImageData
                            {
                                Platforms = new List <PlatformData>
                                {
                                    new PlatformData(),
                                    new PlatformData {
                                        IsUnchanged = true
                                    },
                                }
                            },
                            new ImageData
                            {
                                Platforms = new List <PlatformData>
                                {
                                    new PlatformData {
                                        IsUnchanged = true
                                    },
                                }
                            },
                            new ImageData
                            {
                                Platforms = new List <PlatformData>
                                {
                                    new PlatformData(),
                                    new PlatformData(),
                                }
                            }
                        }
                    },
                    new RepoData
                    {
                        Repo   = "repo2",
                        Images = new List <ImageData>
                        {
                            new ImageData
                            {
                                Platforms = new List <PlatformData>
                                {
                                    new PlatformData {
                                        IsUnchanged = true
                                    },
                                }
                            },
                            new ImageData
                            {
                                Platforms = new List <PlatformData>
                                {
                                    new PlatformData {
                                        IsUnchanged = true
                                    },
                                }
                            }
                        }
                    },
                    new RepoData
                    {
                        Repo   = "repo3",
                        Images = new List <ImageData>
                        {
                            new ImageData
                            {
                                Platforms = new List <PlatformData>
                                {
                                    new PlatformData()
                                }
                            }
                        }
                    }
                }
            };

            ImageArtifactDetails expectedImageArtifactDetails = new ImageArtifactDetails
            {
                Repos = new List <RepoData>
                {
                    new RepoData
                    {
                        Repo   = "repo1",
                        Images = new List <ImageData>
                        {
                            new ImageData
                            {
                                Platforms = new List <PlatformData>
                                {
                                    new PlatformData(),
                                }
                            },
                            new ImageData
                            {
                                Platforms = new List <PlatformData>
                                {
                                    new PlatformData(),
                                    new PlatformData(),
                                }
                            }
                        }
                    },
                    new RepoData
                    {
                        Repo   = "repo3",
                        Images = new List <ImageData>
                        {
                            new ImageData
                            {
                                Platforms = new List <PlatformData>
                                {
                                    new PlatformData()
                                }
                            }
                        }
                    }
                }
            };

            await RunTestAsync(imageArtifactDetails, expectedImageArtifactDetails);
        }
Exemple #30
0
        private IHttpClientFactory CreateHttpClientFactory(IGitFileRef imageOptionsFileRef, ImageArtifactDetails imageArtifactDetails)
        {
            string tempDir = Directory.CreateDirectory(
                Path.Combine(Path.GetTempPath(), Path.GetRandomFileName())).FullName;

            this.foldersToDelete.Add(tempDir);

            string repoPath = Directory.CreateDirectory(
                Path.Combine(tempDir, $"{imageOptionsFileRef.Repo}-{imageOptionsFileRef.Branch}")).FullName;

            string imageInfoPath = Path.Combine(repoPath, imageOptionsFileRef.Path);

            File.WriteAllText(imageInfoPath, JsonConvert.SerializeObject(imageArtifactDetails));

            string repoZipPath = Path.Combine(tempDir, "repo.zip");

            ZipFile.CreateFromDirectory(repoPath, repoZipPath, CompressionLevel.Fastest, true);

            Dictionary <string, HttpResponseMessage> responses = new Dictionary <string, HttpResponseMessage>
            {
                {
                    GitHelper.GetArchiveUrl(imageOptionsFileRef).ToString(),
                    new HttpResponseMessage
                    {
                        StatusCode = HttpStatusCode.OK,
                        Content    = new ByteArrayContent(File.ReadAllBytes(repoZipPath))
                    }
                }
            };

            HttpClient client = new HttpClient(new TestHttpMessageHandler(responses));

            Mock <IHttpClientFactory> httpClientFactoryMock = new Mock <IHttpClientFactory>();

            httpClientFactoryMock
            .Setup(o => o.GetClient())
            .Returns(client);

            return(httpClientFactoryMock.Object);
        }