コード例 #1
0
        public void DuplicatedPlatforms(MatrixType matrixType)
        {
            TempFolderContext          tempFolderContext = TestHelper.UseTempFolder();
            GenerateBuildMatrixCommand command           = new GenerateBuildMatrixCommand();

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

            Manifest manifest = CreateManifest(
                CreateRepo("runtime",
                           CreateImage(
                               new Platform[]
            {
                CreatePlatform(
                    DockerfileHelper.CreateDockerfile("3.1/runtime/os", tempFolderContext),
                    new string[] { "tag" })
            },
                               productVersion: "3.1"),
                           CreateImage(
                               new Platform[]
            {
                CreatePlatform(
                    DockerfileHelper.CreateDockerfile("3.1/runtime/os", tempFolderContext),
                    Array.Empty <string>())
            },
                               productVersion: "3.1")));

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

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

            Assert.Single(matrixInfos);

            BuildMatrixInfo matrixInfo = matrixInfos.First();

            Assert.Single(matrixInfo.Legs);

            string expectedLegName;

            if (matrixType == MatrixType.PlatformDependencyGraph)
            {
                expectedLegName = "3.1-runtime-os-Dockerfile-graph";
            }
            else
            {
                expectedLegName = "3.1-focal-runtime";
            }

            Assert.Equal(expectedLegName, matrixInfo.Legs[0].Name);

            string imageBuilderPaths = matrixInfo.Legs[0].Variables.First(variable => variable.Name == "imageBuilderPaths").Value;

            Assert.Equal($"--path 3.1/runtime/os/Dockerfile", imageBuilderPaths);
        }
コード例 #2
0
        public void Load_Include_Repos()
        {
            const string includeManifestPath1 = "manifest.custom1.json";
            const string includeManifestPath2 = "manifest.custom2.json";
            string       manifest             =
                $@"
{{
  ""includes"": [
    ""{includeManifestPath1}"",
    ""{includeManifestPath2}""
  ]
}}";

            string includeManifest1 =
                $@"
{{
  ""repos"": [
    {CreateRepo("testRepo1", s_dockerfilePath, "testTag1")},
    {CreateRepo("testRepo2", s_dockerfilePath)}
  ]
}}";

            string includeManifest2 =
                $@"
{{
  ""repos"": [
    {CreateRepo("testRepo1", s_dockerfilePath, "testTag2")},
    {CreateRepo("testRepo3", s_dockerfilePath)}
  ]
}}";

            using TempFolderContext tempFolderContext = TestHelper.UseTempFolder();

            string manifestPath = Path.Combine(tempFolderContext.Path, "manifest.json");

            File.WriteAllText(manifestPath, manifest);

            File.WriteAllText(Path.Combine(tempFolderContext.Path, includeManifestPath1), includeManifest1);
            File.WriteAllText(Path.Combine(tempFolderContext.Path, includeManifestPath2), includeManifest2);

            DockerfileHelper.CreateDockerfile(s_dockerfilePath, tempFolderContext);

            IManifestOptionsInfo manifestOptions = ManifestHelper.GetManifestOptions(manifestPath);
            ManifestInfo         manifestInfo    = ManifestInfo.Load(manifestOptions);

            Assert.Equal(3, manifestInfo.Model.Repos.Length);
            Assert.Equal("testRepo1", manifestInfo.Model.Repos[0].Name);
            Assert.Equal("testRepo2", manifestInfo.Model.Repos[1].Name);
            Assert.Equal("testRepo3", manifestInfo.Model.Repos[2].Name);

            Assert.Equal(2, manifestInfo.Model.Repos[0].Images.Length);
            Assert.Equal(1, manifestInfo.Model.Repos[1].Images.Length);
            Assert.Equal(1, manifestInfo.Model.Repos[2].Images.Length);
        }
コード例 #3
0
        private GenerateReadmesCommand InitializeCommand(
            TempFolderContext tempFolderContext,
            string readmeTemplate       = ReadmeTemplate,
            string productFamilyReadme  = DefaultReadme,
            string repoReadme           = DefaultReadme,
            bool allowOptionalTemplates = true,
            bool validate = false)
        {
            DockerfileHelper.CreateFile(ProductFamilyReadmePath, tempFolderContext, productFamilyReadme);
            DockerfileHelper.CreateFile(RepoReadmePath, tempFolderContext, repoReadme);

            DockerfileHelper.CreateFile(AboutRepoTemplatePath, tempFolderContext, AboutRepoTemplate);

            string templatePath = null;

            if (readmeTemplate != null)
            {
                DockerfileHelper.CreateFile(ReadmeTemplatePath, tempFolderContext, readmeTemplate);
                templatePath = ReadmeTemplatePath;
            }

            Repo repo = CreateRepo("dotnet/repo");

            repo.Readmes = new[]
            {
                new Readme(RepoReadmePath, templatePath)
            };
            Manifest manifest = CreateManifest(repo);

            manifest.Registry = "mcr.microsoft.com";
            manifest.Readme   = new(ProductFamilyReadmePath, templatePath);

            string manifestPath = Path.Combine(tempFolderContext.Path, "manifest.json");

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

            Mock <IGitService> gitServiceMock = new Mock <IGitService>();

            _environmentServiceMock = new Mock <IEnvironmentService>();
            _environmentServiceMock
            .Setup(o => o.Exit(1))
            .Throws(_exitException);

            GenerateReadmesCommand command = new GenerateReadmesCommand(_environmentServiceMock.Object, gitServiceMock.Object);

            command.Options.Manifest = manifestPath;
            command.Options.AllowOptionalTemplates = allowOptionalTemplates;
            command.Options.Validate = validate;
            command.LoadManifest();

            return(command);
        }
コード例 #4
0
        private GenerateDockerfilesCommand InitializeCommand(
            TempFolderContext tempFolderContext,
            string dockerfileTemplate = DefaultDockerfileTemplate,
            string dockerfile         = DefaultDockerfile,
            bool validate             = false)
        {
            DockerfileHelper.CreateFile(DockerfileTemplatePath, tempFolderContext, dockerfileTemplate);
            DockerfileHelper.CreateFile(DockerfilePath, tempFolderContext, dockerfile);

            Manifest manifest = CreateManifest(
                CreateRepo("repo1",
                           CreateImage(
                               CreatePlatform(
                                   DockerfilePath,
                                   new string[] { "tag1" },
                                   OS.Linux,
                                   "buster-slim",
                                   Architecture.ARM,
                                   "v7",
                                   dockerfileTemplatePath: DockerfileTemplatePath),
                               CreatePlatform(
                                   DockerfilePath,
                                   new string[] { "tag2" },
                                   OS.Windows,
                                   "nanoserver-1903"),
                               CreatePlatform(
                                   DockerfilePath,
                                   new string[] { "tag3" },
                                   OS.Linux,
                                   "alpine3.12")))
                );

            AddVariable(manifest, "Variable1", "Value1");

            string manifestPath = Path.Combine(tempFolderContext.Path, "manifest.json");

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

            _environmentServiceMock = new Mock <IEnvironmentService>();
            _environmentServiceMock
            .Setup(o => o.Exit(1))
            .Throws(_exitException);

            GenerateDockerfilesCommand command = new GenerateDockerfilesCommand(_environmentServiceMock.Object);

            command.Options.Manifest = manifestPath;
            command.Options.Validate = validate;
            command.LoadManifest();

            return(command);
        }
コード例 #5
0
        public async Task GenerateDockerfilesCommand_MismatchedTemplates()
        {
            using TempFolderContext tempFolderContext = TestHelper.UseTempFolder();
            DockerfileHelper.CreateFile(DockerfilePath, tempFolderContext, DefaultDockerfile);

            string templatePath1 = "Dockerfile.Template1";

            DockerfileHelper.CreateFile(templatePath1, tempFolderContext, DefaultDockerfileTemplate);

            string templatePath2 = "Dockerfile.Template2";

            DockerfileHelper.CreateFile(templatePath2, tempFolderContext, DefaultDockerfileTemplate);

            Manifest manifest = CreateManifest(
                CreateRepo("repo1",
                           CreateImage(
                               new Platform[]
            {
                CreatePlatform(
                    DockerfilePath,
                    new string[] { "tag1" },
                    OS.Windows,
                    "nanoserver-1903",
                    dockerfileTemplatePath: templatePath1),
                CreatePlatform(
                    DockerfilePath,
                    new string[] { "tag2" },
                    OS.Windows,
                    "windowsservercore-1903",
                    dockerfileTemplatePath: templatePath2)
            },
                               productVersion: "1.2.3"
                               )
                           )
                );

            string manifestPath = Path.Combine(tempFolderContext.Path, "manifest.json");

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

            GenerateDockerfilesCommand command = new(Mock.Of <IEnvironmentService>());

            command.Options.Manifest = manifestPath;
            command.LoadManifest();

            InvalidOperationException exception = await Assert.ThrowsAsync <InvalidOperationException>(() => command.ExecuteAsync());

            Assert.StartsWith("Multiple unique template files are associated with the generated artifact path", exception.Message);
        }
コード例 #6
0
        private static ManifestInfo LoadManifestInfo(string manifest, string includeManifestPath = null, string includeManifest = null)
        {
            using TempFolderContext tempFolderContext = TestHelper.UseTempFolder();

            string manifestPath = Path.Combine(tempFolderContext.Path, "manifest.json");

            File.WriteAllText(manifestPath, manifest);

            if (includeManifestPath != null)
            {
                string fullIncludeManifestPath = Path.Combine(tempFolderContext.Path, includeManifestPath);
                File.WriteAllText(fullIncludeManifestPath, includeManifest);
            }

            DockerfileHelper.CreateDockerfile(s_dockerfilePath, tempFolderContext);

            IManifestOptionsInfo manifestOptions = ManifestHelper.GetManifestOptions(manifestPath);

            return(ManifestInfo.Load(manifestOptions));
        }
コード例 #7
0
        public async Task GenerateReadmesCommand_TemplateArgs()
        {
            const string readmeTemplate =
                @"Hello World
{{InsertTemplate(""template-with-args.md"", [ ""my-arg"": 123 ])}}";

            const string templateWithArgs =
                @"ABC-{{ARGS[""my-arg""]}}";

            using TempFolderContext tempFolderContext = TestHelper.UseTempFolder();
            DockerfileHelper.CreateFile("template-with-args.md", tempFolderContext, templateWithArgs);
            GenerateReadmesCommand command = InitializeCommand(tempFolderContext, readmeTemplate);

            await command.ExecuteAsync();

            string generatedReadme = File.ReadAllText(Path.Combine(tempFolderContext.Path, ProductFamilyReadmePath));
            string expectedReadme  =
                @"Hello World
ABC-123";

            Assert.Equal(expectedReadme, generatedReadme);
        }
コード例 #8
0
        public void HandlesUndocumentedPlatform()
        {
            using TempFolderContext tempFolderContext = TestHelper.UseTempFolder();

            const string SourceRepoUrl = "https://www.github.com/dotnet/dotnet-docker";
            const string RepoName      = "repo";
            const string SourceBranch  = "branch";

            // Create MCR tags metadata template file
            StringBuilder tagsMetadataTemplateBuilder = new StringBuilder();

            tagsMetadataTemplateBuilder.AppendLine($"$(McrTagsYmlRepo:{RepoName})");
            tagsMetadataTemplateBuilder.AppendLine($"$(McrTagsYmlTagGroup:tag1a)");
            string tagsMetadataTemplatePath = Path.Combine(tempFolderContext.Path, "tags.yaml");

            File.WriteAllText(tagsMetadataTemplatePath, tagsMetadataTemplateBuilder.ToString());

            Platform platform = ManifestHelper.CreatePlatform(
                DockerfileHelper.CreateDockerfile($"1.0/{RepoName}/os", tempFolderContext),
                Array.Empty <string>());

            platform.Tags = new Dictionary <string, Tag>
            {
                {
                    "tag2",
                    new Tag
                    {
                        IsUndocumented = true
                    }
                }
            };

            // Create manifest
            Manifest manifest = ManifestHelper.CreateManifest(
                ManifestHelper.CreateRepo(RepoName,
                                          new Image[]
            {
                ManifestHelper.CreateImage(
                    platform,
                    ManifestHelper.CreatePlatform(
                        DockerfileHelper.CreateDockerfile($"1.0/{RepoName}/os2", tempFolderContext),
                        new string[] { "tag1a", "tag1b" }))
            },
                                          mcrTagsMetadataTemplatePath: Path.GetFileName(tagsMetadataTemplatePath))
                );
            string manifestPath = Path.Combine(tempFolderContext.Path, "manifest.json");

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

            // Load manifest
            IManifestOptionsInfo manifestOptions = GetManifestOptions(manifestPath);
            ManifestInfo         manifestInfo    = ManifestInfo.Load(manifestOptions);
            RepoInfo             repo            = manifestInfo.AllRepos.First();

            Mock <IGitService> gitServiceMock = new Mock <IGitService>();

            // Execute generator
            string result = McrTagsMetadataGenerator.Execute(
                gitServiceMock.Object, manifestInfo, repo, SourceRepoUrl, SourceBranch);

            Models.Mcr.McrTagsMetadata tagsMetadata = new DeserializerBuilder()
                                                      .WithNamingConvention(CamelCaseNamingConvention.Instance)
                                                      .Build()
                                                      .Deserialize <Models.Mcr.McrTagsMetadata>(result);

            // Verify the output only contains the platform with the documented tag
            Assert.Single(tagsMetadata.Repos[0].TagGroups);
            Assert.Equal(
                $"{SourceRepoUrl}/blob/{SourceBranch}/1.0/{RepoName}/os2/Dockerfile",
                tagsMetadata.Repos[0].TagGroups[0].Dockerfile);
            Assert.Equal(new string[] { "tag1a", "tag1b" }, tagsMetadata.Repos[0].TagGroups[0].Tags);
        }
コード例 #9
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);
        }
コード例 #10
0
        public void DuplicatedPlatform()
        {
            using TempFolderContext tempFolderContext = TestHelper.UseTempFolder();

            const string SourceRepoUrl = "https://www.github.com/dotnet/dotnet-docker";
            const string RepoName      = "repo";
            const string SourceBranch  = "branch";

            // Create MCR tags metadata template file
            StringBuilder tagsMetadataTemplateBuilder = new StringBuilder();

            tagsMetadataTemplateBuilder.AppendLine($"$(McrTagsYmlRepo:{RepoName})");
            tagsMetadataTemplateBuilder.AppendLine($"$(McrTagsYmlTagGroup:concreteTagA)");
            string tagsMetadataTemplatePath = Path.Combine(tempFolderContext.Path, "tags.yaml");

            File.WriteAllText(tagsMetadataTemplatePath, tagsMetadataTemplateBuilder.ToString());

            string emptyFileName = "emptyFile.md";
            string emptyFilePath = Path.Combine(tempFolderContext.Path, emptyFileName);

            File.WriteAllText(emptyFilePath, string.Empty);

            // Create manifest
            Manifest manifest = ManifestHelper.CreateManifest(
                ManifestHelper.CreateRepo(RepoName,
                                          new Image[]
            {
                ManifestHelper.CreateImage(
                    new Platform[]
                {
                    ManifestHelper.CreatePlatform(
                        DockerfileHelper.CreateDockerfile($"1.0/{RepoName}/os", tempFolderContext),
                        new string[] { "concreteTagZ", "concreteTagA" })
                },
                    sharedTags: new Dictionary <string, Tag>
                {
                    { "shared1", new Tag() },
                    { "latest", new Tag() },
                }),
                ManifestHelper.CreateImage(
                    new Platform[]
                {
                    ManifestHelper.CreatePlatform(
                        DockerfileHelper.CreateDockerfile($"1.0/{RepoName}/os", tempFolderContext),
                        Array.Empty <string>())
                },
                    sharedTags: new Dictionary <string, Tag>
                {
                    { "shared2", new Tag() }
                })
            },
                                          readme: emptyFileName,
                                          readmeTemplate: emptyFileName,
                                          mcrTagsMetadataTemplate: Path.GetFileName(tagsMetadataTemplatePath))
                );

            string manifestPath = Path.Combine(tempFolderContext.Path, "manifest.json");

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

            // Load manifest
            IManifestOptionsInfo manifestOptions = ManifestHelper.GetManifestOptions(manifestPath);
            ManifestInfo         manifestInfo    = ManifestInfo.Load(manifestOptions);
            RepoInfo             repo            = manifestInfo.AllRepos.First();

            Mock <IGitService> gitServiceMock = new Mock <IGitService>();

            // Execute generator
            string result = McrTagsMetadataGenerator.Execute(
                gitServiceMock.Object, manifestInfo, repo, SourceRepoUrl, SourceBranch);

            TagsMetadata tagsMetadata = new DeserializerBuilder()
                                        .WithNamingConvention(CamelCaseNamingConvention.Instance)
                                        .Build()
                                        .Deserialize <TagsMetadata>(result);

            // Verify the output only contains the platform with the documented tag
            Assert.Single(tagsMetadata.Repos[0].TagGroups);
            Assert.Equal(
                $"{SourceRepoUrl}/blob/{SourceBranch}/1.0/{RepoName}/os/Dockerfile",
                tagsMetadata.Repos[0].TagGroups[0].Dockerfile);

            List <string> expectedTags = new List <string>
            {
                "concreteTagZ",
                "concreteTagA",
                "shared2",
                "shared1",
                "latest"
            };

            Assert.Equal(expectedTags, tagsMetadata.Repos[0].TagGroups[0].Tags);
        }
コード例 #11
0
        public void CrossReferencedDockerfileFromMultipleRepos_ImageGraph(MatrixType matrixType)
        {
            TempFolderContext          tempFolderContext = TestHelper.UseTempFolder();
            GenerateBuildMatrixCommand command           = new GenerateBuildMatrixCommand();

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

            Manifest manifest = CreateManifest(
                CreateRepo("core/runtime-deps",
                           CreateImage(
                               new Platform[]
            {
                CreatePlatform(
                    DockerfileHelper.CreateDockerfile("3.1/runtime-deps/os", tempFolderContext),
                    new string[] { "tag" })
            },
                               productVersion: "3.1")),
                CreateRepo("core/runtime",
                           CreateImage(
                               new Platform[]
            {
                CreatePlatform(
                    DockerfileHelper.CreateDockerfile("3.1/runtime/os", tempFolderContext, "core/runtime-deps:tag"),
                    new string[] { "tag" })
            },
                               productVersion: "3.1")),
                CreateRepo("runtime-deps",
                           CreateImage(
                               new Platform[]
            {
                CreatePlatform(
                    "3.1/runtime-deps/os/Dockerfile",
                    new string[] { "tag" })
            },
                               productVersion: "5.0")),
                CreateRepo("runtime",
                           CreateImage(
                               new Platform[]
            {
                CreatePlatform(
                    DockerfileHelper.CreateDockerfile("5.0/runtime/os", tempFolderContext, "runtime-deps:tag"),
                    new string[] { "tag" })
            },
                               productVersion: "5.0"))
                );

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

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

            Assert.Single(matrixInfos);
            BuildMatrixInfo matrixInfo = matrixInfos.First();

            if (matrixType == MatrixType.PlatformDependencyGraph)
            {
                Assert.Single(matrixInfo.Legs);

                Assert.Equal("3.1-runtime-deps-os-Dockerfile-graph", matrixInfo.Legs[0].Name);
                string imageBuilderPaths = matrixInfo.Legs[0].Variables.First(variable => variable.Name == "imageBuilderPaths").Value;
                Assert.Equal($"--path 3.1/runtime-deps/os/Dockerfile --path 3.1/runtime/os/Dockerfile --path 5.0/runtime/os/Dockerfile", imageBuilderPaths);
            }
            else
            {
                Assert.Equal(2, matrixInfo.Legs.Count);

                Assert.Equal("3.1-focal-core-runtime-deps", matrixInfo.Legs[0].Name);
                string imageBuilderPaths = matrixInfo.Legs[0].Variables.First(variable => variable.Name == "imageBuilderPaths").Value;
                Assert.Equal($"--path 3.1/runtime-deps/os/Dockerfile --path 3.1/runtime/os/Dockerfile", imageBuilderPaths);

                Assert.Equal("5.0-focal-runtime-deps", matrixInfo.Legs[1].Name);
                imageBuilderPaths = matrixInfo.Legs[1].Variables.First(variable => variable.Name == "imageBuilderPaths").Value;
                Assert.Equal($"--path 3.1/runtime-deps/os/Dockerfile --path 5.0/runtime/os/Dockerfile", imageBuilderPaths);
            }
        }
コード例 #12
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);
            }
        }
コード例 #13
0
        public void GenerateBuildMatrixCommand_MultiBuildLegGroups()
        {
            using TempFolderContext tempFolderContext = TestHelper.UseTempFolder();
            const string customBuildLegGroup1  = "custom1";
            const string customBuildLegGroup2  = "custom2";
            GenerateBuildMatrixCommand command = new GenerateBuildMatrixCommand();

            command.Options.Manifest   = Path.Combine(tempFolderContext.Path, "manifest.json");
            command.Options.MatrixType = MatrixType.PlatformVersionedOs;
            command.Options.ProductVersionComponents = 2;
            command.Options.CustomBuildLegGroups     = new string[] { customBuildLegGroup1, customBuildLegGroup2 };

            Manifest manifest = CreateManifest(
                CreateRepo("repo1",
                           CreateImage(
                               new Platform[]
            {
                CreatePlatform(
                    DockerfileHelper.CreateDockerfile("1.0/repo1/os", tempFolderContext),
                    new string[] { "tag" },
                    osVersion: "bionic")
            },
                               productVersion: "1.0")),
                CreateRepo("repo2",
                           CreateImage(
                               new Platform[]
            {
                CreatePlatform(
                    DockerfileHelper.CreateDockerfile("1.0/repo2/os", tempFolderContext),
                    new string[] { "tag" },
                    osVersion: "focal",
                    customBuildLegGroups: new CustomBuildLegGroup[]
                {
                    new CustomBuildLegGroup
                    {
                        Name         = customBuildLegGroup1,
                        Type         = CustomBuildLegDependencyType.Supplemental,
                        Dependencies = new string[]
                        {
                            "repo1:tag"
                        }
                    }
                })
            },
                               productVersion: "1.0")),
                CreateRepo("repo3",
                           CreateImage(
                               new Platform[]
            {
                CreatePlatform(
                    DockerfileHelper.CreateDockerfile("1.0/repo3/os", tempFolderContext),
                    new string[] { "tag" },
                    osVersion: "buster")
            },
                               productVersion: "1.0")),
                CreateRepo("repo4",
                           CreateImage(
                               new Platform[]
            {
                CreatePlatform(
                    DockerfileHelper.CreateDockerfile("1.0/repo4/os", tempFolderContext),
                    new string[] { "tag" },
                    osVersion: "bullseye",
                    customBuildLegGroups: new CustomBuildLegGroup[]
                {
                    new CustomBuildLegGroup
                    {
                        Name         = customBuildLegGroup1,
                        Type         = CustomBuildLegDependencyType.Integral,
                        Dependencies = new string[]
                        {
                            "repo3:tag"
                        }
                    }
                })
            },
                               productVersion: "1.0"))
                );

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

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

            Assert.Single(matrixInfos);

            BuildMatrixInfo matrixInfo = matrixInfos.First();

            Assert.Equal(3, matrixInfo.Legs.Count());
            BuildLegInfo leg = matrixInfo.Legs.First();
            string       imageBuilderPaths = leg.Variables.First(variable => variable.Name == "imageBuilderPaths").Value;

            Assert.Equal(
                "--path 1.0/repo1/os/Dockerfile",
                imageBuilderPaths);

            leg = matrixInfo.Legs.ElementAt(1);
            imageBuilderPaths = leg.Variables.First(variable => variable.Name == "imageBuilderPaths").Value;
            Assert.Equal(
                "--path 1.0/repo2/os/Dockerfile --path 1.0/repo1/os/Dockerfile",
                imageBuilderPaths);

            leg = matrixInfo.Legs.ElementAt(2);
            imageBuilderPaths = leg.Variables.First(variable => variable.Name == "imageBuilderPaths").Value;
            Assert.Equal(
                "--path 1.0/repo3/os/Dockerfile --path 1.0/repo4/os/Dockerfile",
                imageBuilderPaths);
        }
コード例 #14
0
        public async Task PublishImageInfoCommand_RemoveOutOfDateContent()
        {
            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(
                                   new Platform[]
                {
                    CreatePlatform(repo1Image1DockerfilePath, new string[0])
                },
                                   productVersion: "1.0")),
                    CreateRepo("repo2",
                               CreateImage(
                                   new Platform[]
                {
                    CreatePlatform(repo2Image2DockerfilePath, new string[0])
                },
                                   productVersion: "2.0"))
                    );
                manifest.Registry = "mcr.microsoft.com";

                RepoData repo2;

                ImageArtifactDetails srcImageArtifactDetails = new ImageArtifactDetails
                {
                    Repos =
                    {
                        new RepoData
                        {
                            Repo   = "repo1",
                            Images =
                            {
                                new ImageData
                                {
                                    Platforms =
                                    {
                                        Helpers.ImageInfoHelper.CreatePlatform(repo1Image1DockerfilePath)
                                    },
                                    ProductVersion = "1.0"
                                }
                            }
                        },
                        {
                            repo2 = new RepoData
                            {
                                Repo   = "repo2",
                                Images =
                                {
                                    new ImageData
                                    {
                                        Platforms =
                                        {
                                            Helpers.ImageInfoHelper.CreatePlatform(repo2Image2DockerfilePath)
                                        },
                                        ProductVersion = "2.0"
                                    }
                                }
                            }
                        }
                    }
                };

                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)
                                    },
                                    ProductVersion = "1.0"
                                },
                                new ImageData
                                {
                                    Platforms =
                                    {
                                        Helpers.ImageInfoHelper.CreatePlatform(
                                            DockerfileHelper.CreateDockerfile("1.0/runtime2/os", tempFolderContext))
                                    },
                                    ProductVersion = "1.0"
                                }
                            }
                        },
                        new RepoData
                        {
                            Repo = "repo4"
                        }
                    }
                };

                GitOptions gitOptions = new GitOptions
                {
                    AuthToken = "token",
                    Repo      = "repo",
                    Owner     = "owner",
                    Path      = "imageinfo.json",
                    Branch    = "branch",
                    Email     = "*****@*****.**",
                    Username  = "******"
                };

                AzdoOptions azdoOptions = new AzdoOptions
                {
                    AccessToken  = "azdo-token",
                    Branch       = "testBranch",
                    Repo         = "testRepo",
                    Organization = "azdo-org",
                    Project      = "azdo-project",
                    Path         = "imageinfo.json"
                };

                Mock <IRepository> repositoryMock = GetRepositoryMock();
                Mock <IGitService> gitServiceMock = GetGitServiceMock(repositoryMock.Object, gitOptions.Path, targetImageArtifactDetails);


                PublishImageInfoCommand command = new PublishImageInfoCommand(gitServiceMock.Object, Mock.Of <ILoggerService>());
                command.Options.ImageInfoPath = file;
                command.Options.GitOptions    = gitOptions;
                command.Options.AzdoOptions   = azdoOptions;
                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)
                                    },
                                    ProductVersion = "1.0"
                                }
                            }
                        },
                        repo2
                    }
                };

                VerifyMocks(repositoryMock);
            }
        }
コード例 #15
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))));
            }
        }
コード例 #16
0
        public async Task ExcludeProductFamilyReadme()
        {
            Mock <IGitHubClient> gitHubClientMock = new();

            gitHubClientMock
            .Setup(o => o.GetReferenceAsync(It.IsAny <GitHubProject>(), It.IsAny <string>()))
            .ReturnsAsync(new GitReference
            {
                Object = new GitReferenceObject()
            });

            gitHubClientMock
            .Setup(o => o.PostTreeAsync(It.IsAny <GitHubProject>(), It.IsAny <string>(), It.IsAny <GitObject[]>()))
            .ReturnsAsync(new GitTree());

            gitHubClientMock
            .Setup(o => o.PostCommitAsync(It.IsAny <GitHubProject>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string[]>()))
            .ReturnsAsync(new GitCommit());

            Mock <IGitHubClientFactory> gitHubClientFactoryMock = new();

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

            PublishMcrDocsCommand command = new(Mock.Of <IGitService>(), gitHubClientFactoryMock.Object, Mock.Of <ILoggerService>());

            using TempFolderContext tempFolderContext = TestHelper.UseTempFolder();

            DockerfileHelper.CreateFile(ProductFamilyReadmePath, tempFolderContext, DefaultReadme);
            DockerfileHelper.CreateFile(RepoReadmePath, tempFolderContext, DefaultReadme);
            DockerfileHelper.CreateFile(AboutRepoTemplatePath, tempFolderContext, AboutRepoTemplate);
            DockerfileHelper.CreateFile(ReadmeTemplatePath, tempFolderContext, ReadmeTemplate);

            // Create MCR tags metadata template file
            StringBuilder tagsMetadataTemplateBuilder = new();

            tagsMetadataTemplateBuilder.AppendLine($"$(McrTagsYmlRepo:repo)");
            tagsMetadataTemplateBuilder.Append($"$(McrTagsYmlTagGroup:tag)");
            string tagsMetadataTemplatePath = Path.Combine(tempFolderContext.Path, TagsYamlPath);

            File.WriteAllText(tagsMetadataTemplatePath, tagsMetadataTemplateBuilder.ToString());

            Repo     repo;
            Manifest manifest = CreateManifest(
                repo = CreateRepo("dotnet/repo", new Image[]
            {
                CreateImage(
                    CreatePlatform(CreateDockerfile("1.0/runtime/linux", tempFolderContext), new string[] { "tag" }))
            }, RepoReadmePath, ReadmeTemplatePath, Path.GetFileName(tagsMetadataTemplatePath)));

            manifest.Registry = "mcr.microsoft.com";
            manifest.Readme   = new(ProductFamilyReadmePath, ReadmeTemplatePath);
            repo.Id           = "repo";

            string manifestPath = Path.Combine(tempFolderContext.Path, "manifest.json");

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

            command.Options.Manifest = manifestPath;
            command.Options.ExcludeProductFamilyReadme = true;
            command.LoadManifest();

            await command.ExecuteAsync();

            // Verify published file list does not contain ProductFamilyReadmePath
            gitHubClientMock
            .Verify(o =>
                    o.PostTreeAsync(It.IsAny <GitHubProject>(), It.IsAny <string>(),
                                    It.Is <GitObject[]>(objs =>
                                                        objs.Length == 2 &&
                                                        Path.GetFileName(objs[0].Path) == RepoReadmePath &&
                                                        Path.GetFileName(objs[1].Path) == TagsYamlPath)));
        }
コード例 #17
0
        public async Task PublishImageInfoCommand_ReplaceContent()
        {
            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(
                                   new Platform[]
                {
                    CreatePlatform(repo1Image1DockerfilePath, new string[] { "tag1" })
                },
                                   productVersion: "1.0")),
                    CreateRepo("repo2",
                               CreateImage(
                                   new Platform[]
                {
                    CreatePlatform(repo2Image2DockerfilePath, new string[] { "tag1" })
                },
                                   productVersion: "2.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"
                                        })
                                    },
                                    ProductVersion = "1.0",
                                    Manifest       = new ManifestData
                                    {
                                        SyndicatedDigests = new List <string>
                                        {
                                            "newdigest1",
                                            "newdigest2"
                                        }
                                    }
                                }
                            }
                        },
                        {
                            repo2 = new RepoData
                            {
                                Repo   = "repo2",
                                Images =
                                {
                                    new ImageData
                                    {
                                        Platforms =
                                        {
                                            Helpers.ImageInfoHelper.CreatePlatform(repo2Image2DockerfilePath,
                                                                                   simpleTags: new List <string>
                                            {
                                                "tag1"
                                            })
                                        },
                                        ProductVersion = "2.0"
                                    }
                                }
                            }
                        }
                    }
                };

                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"
                                        })
                                    },
                                    ProductVersion = "1.0",
                                    Manifest       = new ManifestData
                                    {
                                        SyndicatedDigests = new List <string>
                                        {
                                            "olddigest1",
                                            "olddigest2"
                                        }
                                    }
                                }
                            }
                        }
                    }
                };

                GitOptions gitOptions = new GitOptions
                {
                    AuthToken = "token",
                    Repo      = "PublishImageInfoCommand_ReplaceContent",
                    Branch    = "testBranch",
                    Path      = "imageinfo.json",
                    Email     = "*****@*****.**",
                    Username  = "******"
                };

                AzdoOptions azdoOptions = new AzdoOptions
                {
                    AccessToken  = "azdo-token",
                    AzdoBranch   = "testBranch",
                    AzdoRepo     = "testRepo",
                    Organization = "azdo-org",
                    Project      = "azdo-project",
                    AzdoPath     = "imageinfo.json"
                };

                Mock <IRepository> repositoryMock = GetRepositoryMock();
                Mock <IGitService> gitServiceMock = GetGitServiceMock(repositoryMock.Object, gitOptions.Path, targetImageArtifactDetails);

                string actualImageArtifactDetailsContents = null;
                gitServiceMock
                .Setup(o => o.Stage(It.IsAny <IRepository>(), It.IsAny <string>()))
                .Callback((IRepository repo, string path) =>
                {
                    actualImageArtifactDetailsContents = File.ReadAllText(path);
                });

                PublishImageInfoCommand command = new PublishImageInfoCommand(gitServiceMock.Object, Mock.Of <ILoggerService>());
                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"
                                        })
                                    },
                                    ProductVersion = "1.0",
                                    Manifest       = new ManifestData
                                    {
                                        SyndicatedDigests = new List <string>
                                        {
                                            "newdigest1",
                                            "newdigest2"
                                        }
                                    }
                                }
                            }
                        },
                        repo2
                    }
                };

                Assert.Equal(JsonHelper.SerializeObject(expectedImageArtifactDetails), actualImageArtifactDetailsContents.Trim());

                VerifyMocks(repositoryMock);
            }
        }
コード例 #18
0
        public async Task SyndicatedTag()
        {
            using TempFolderContext tempFolderContext = TestHelper.UseTempFolder();

            string   repo1Image1DockerfilePath = DockerfileHelper.CreateDockerfile("1.0/sdk/os", tempFolderContext);
            Manifest manifest = CreateManifest(
                CreateRepo("repo1",
                           CreateImage(
                               new Platform[]
            {
                CreatePlatform(repo1Image1DockerfilePath, new string[] { "t1", "t2", "t3" })
            },
                               productVersion: "1.0.5"))
                );

            const string syndicatedRepository = "repo2";
            Platform     platform             = manifest.Repos.First().Images.First().Platforms.First();

            platform.Tags["t1"].Syndication = new TagSyndication
            {
                Repo = syndicatedRepository
            };
            platform.Tags["t2"].Syndication = new TagSyndication
            {
                Repo            = syndicatedRepository,
                DestinationTags = new string[]
                {
                    "t2a",
                    "t2b"
                }
            };

            string manifestPath = Path.Combine(tempFolderContext.Path, "manifest.json");

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

            ImageArtifactDetails srcImageArtifactDetails = new()
            {
                Repos =
                {
                    new RepoData
                    {
                        Repo   = "repo1",
                        Images =
                        {
                            new ImageData
                            {
                                Platforms =
                                {
                                    Helpers.ImageInfoHelper.CreatePlatform(
                                        repo1Image1DockerfilePath,
                                        created: new DateTime(2020, 4, 20, 21, 56, 58, DateTimeKind.Utc),
                                        digest: "jkl",
                                        simpleTags: new List <string>
                                    {
                                        "t1",
                                        "t2",
                                        "t3"
                                    },
                                        layers: new List <string>
                                    {
                                        "zxc"
                                    })
                                },
                                ProductVersion = "1.0.5"
                            }
                        }
                    }
                }
            };

            string expectedImageData =
                @"""jkl"",""amd64"",""Linux"",""Ubuntu 20.04"",""1.0.5"",""1.0/sdk/os/Dockerfile"",""repo1"",""2020-04-20 21:56:58""
""jkl"",""amd64"",""Linux"",""Ubuntu 20.04"",""1.0.5"",""1.0/sdk/os/Dockerfile"",""repo2"",""2020-04-20 21:56:58""
""t1"",""amd64"",""Linux"",""Ubuntu 20.04"",""1.0.5"",""1.0/sdk/os/Dockerfile"",""repo1"",""2020-04-20 21:56:58""
""t1"",""amd64"",""Linux"",""Ubuntu 20.04"",""1.0.5"",""1.0/sdk/os/Dockerfile"",""repo2"",""2020-04-20 21:56:58""
""t2"",""amd64"",""Linux"",""Ubuntu 20.04"",""1.0.5"",""1.0/sdk/os/Dockerfile"",""repo1"",""2020-04-20 21:56:58""
""t2a"",""amd64"",""Linux"",""Ubuntu 20.04"",""1.0.5"",""1.0/sdk/os/Dockerfile"",""repo2"",""2020-04-20 21:56:58""
""t2b"",""amd64"",""Linux"",""Ubuntu 20.04"",""1.0.5"",""1.0/sdk/os/Dockerfile"",""repo2"",""2020-04-20 21:56:58""
""t3"",""amd64"",""Linux"",""Ubuntu 20.04"",""1.0.5"",""1.0/sdk/os/Dockerfile"",""repo1"",""2020-04-20 21:56:58""";

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

            string expectedLayerData =
                @"""zxc"",""0"",""1"",""jkl"",""amd64"",""Linux"",""Ubuntu 20.04"",""1.0.5"",""1.0/sdk/os/Dockerfile"",""repo1"",""2020-04-20 21:56:58""";

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

            await ValidateExecuteAsync(tempFolderContext, manifestPath, srcImageArtifactDetails, expectedImageData, expectedLayerData);
        }
コード例 #19
0
        public async Task CopyAcrImagesCommand_RuntimeDepsSharing()
        {
            const string subscriptionId = "my subscription";

            using TempFolderContext tempFolderContext = TestHelper.UseTempFolder();
            Mock <IRegistriesOperations> registriesOperationsMock = AzureHelper.CreateRegistriesOperationsMock();
            IAzure azure = AzureHelper.CreateAzureMock(registriesOperationsMock);
            Mock <IAzureManagementFactory> azureManagementFactoryMock =
                AzureHelper.CreateAzureManagementFactoryMock(subscriptionId, azure);

            Mock <IEnvironmentService> environmentServiceMock = new Mock <IEnvironmentService>();

            CopyAcrImagesCommand command = new CopyAcrImagesCommand(azureManagementFactoryMock.Object, Mock.Of <ILoggerService>());

            command.Options.Manifest         = Path.Combine(tempFolderContext.Path, "manifest.json");
            command.Options.Subscription     = subscriptionId;
            command.Options.ResourceGroup    = "my resource group";
            command.Options.SourceRepoPrefix = command.Options.RepoPrefix = "test/";
            command.Options.ImageInfoPath    = "image-info.json";

            string dockerfileRelativePath = DockerfileHelper.CreateDockerfile("3.1/runtime-deps/os", tempFolderContext);

            Manifest manifest = CreateManifest(
                CreateRepo("runtime-deps",
                           CreateImage(
                               new Platform[]
            {
                CreatePlatform(dockerfileRelativePath, new string[] { "3.1" }, osVersion: "focal")
            },
                               productVersion: "3.1"),
                           CreateImage(
                               new Platform[]
            {
                CreatePlatform(dockerfileRelativePath, new string[] { "5.0" }, osVersion: "focal")
            },
                               productVersion: "5.0"))
                );

            manifest.Registry = "mcr.microsoft.com";

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

            RepoData runtimeRepo;

            ImageArtifactDetails imageArtifactDetails = new ImageArtifactDetails
            {
                Repos =
                {
                    {
                        runtimeRepo = new RepoData
                        {
                            Repo   = "runtime-deps",
                            Images =
                            {
                                new ImageData
                                {
                                    Platforms =
                                    {
                                        CreatePlatform(
                                            PathHelper.NormalizePath(dockerfileRelativePath),
                                            simpleTags: new List <string>
                                        {
                                            "3.1"
                                        },
                                            osVersion: "focal")
                                    },
                                    ProductVersion = "3.1"
                                },
                                new ImageData
                                {
                                    Platforms =
                                    {
                                        CreatePlatform(
                                            PathHelper.NormalizePath(dockerfileRelativePath),
                                            simpleTags: new List <string>
                                        {
                                            "5.0"
                                        },
                                            osVersion: "focal")
                                    },
                                    ProductVersion = "5.0"
                                }
                            }
                        }
                    }
                }
            };

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

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

            List <string> expectedTags = new List <string>
            {
                $"{command.Options.RepoPrefix}{runtimeRepo.Repo}:3.1",
                $"{command.Options.RepoPrefix}{runtimeRepo.Repo}:5.0"
            };

            foreach (string expectedTag in expectedTags)
            {
                registriesOperationsMock
                .Verify(o => o.ImportImageWithHttpMessagesAsync(
                            command.Options.ResourceGroup,
                            manifest.Registry,
                            It.Is <ImportImageParametersInner>(parameters =>
                                                               VerifyImportImageParameters(parameters, new List <string> {
                    expectedTag
                })),
                            It.IsAny <Dictionary <string, List <string> > >(),
                            It.IsAny <CancellationToken>()));
            }
        }
コード例 #20
0
        public void GenerateBuildMatrixCommand_CustomBuildLegGroupingParentGraph()
        {
            using (TempFolderContext tempFolderContext = TestHelper.UseTempFolder())
            {
                const string customBuildLegGrouping = "custom";
                GenerateBuildMatrixCommand command  = new GenerateBuildMatrixCommand();
                command.Options.Manifest   = Path.Combine(tempFolderContext.Path, "manifest.json");
                command.Options.MatrixType = MatrixType.PlatformVersionedOs;
                command.Options.ProductVersionComponents = 2;
                command.Options.CustomBuildLegGrouping   = customBuildLegGrouping;

                string dockerfileRuntimeDepsFullPath = DockerfileHelper.CreateDockerfile("1.0/runtime-deps/os", tempFolderContext);
                string dockerfileRuntimePath         = DockerfileHelper.CreateDockerfile("1.0/runtime/os", tempFolderContext, "runtime-deps:tag");

                string dockerfileRuntime2FullPath = DockerfileHelper.CreateDockerfile("2.0/runtime/os2", tempFolderContext);
                string dockerfileSdk2FullPath     = DockerfileHelper.CreateDockerfile("2.0/sdk/os2", tempFolderContext, "runtime2:tag");

                Manifest manifest = CreateManifest(
                    CreateRepo("runtime-deps",
                               CreateImage(
                                   new Platform[]
                {
                    CreatePlatform(dockerfileRuntimeDepsFullPath, new string[] { "tag" })
                },
                                   productVersion: "1.0")),
                    CreateRepo("runtime",
                               CreateImage(
                                   new Platform[]
                {
                    CreatePlatform(dockerfileRuntimePath, new string[] { "runtime" },
                                   customBuildLegGroupings: new CustomBuildLegGrouping[]
                    {
                        new CustomBuildLegGrouping
                        {
                            Name         = customBuildLegGrouping,
                            Dependencies = new string[]
                            {
                                "sdk2:tag"
                            }
                        }
                    })
                },
                                   productVersion: "1.0")),
                    CreateRepo("runtime2",
                               CreateImage(
                                   new Platform[]
                {
                    CreatePlatform(dockerfileRuntime2FullPath, new string[] { "tag" }, osVersion: "buster-slim")
                },
                                   productVersion: "2.0")),
                    CreateRepo("sdk2",
                               CreateImage(
                                   new Platform[]
                {
                    CreatePlatform(dockerfileSdk2FullPath, new string[] { "tag" }, osVersion: "buster")
                },
                                   productVersion: "2.0"))
                    );

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

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

                BuildMatrixInfo matrixInfo        = matrixInfos.First();
                BuildLegInfo    leg_1_0           = matrixInfo.Legs.First();
                string          imageBuilderPaths = leg_1_0.Variables.First(variable => variable.Name == "imageBuilderPaths").Value;
                Assert.Equal("--path 1.0/runtime-deps/os/Dockerfile --path 1.0/runtime/os/Dockerfile --path 2.0/sdk/os2/Dockerfile --path 2.0/runtime/os2/Dockerfile", imageBuilderPaths);
                string osVersions = leg_1_0.Variables.First(variable => variable.Name == "osVersions").Value;
                Assert.Equal("--os-version disco --os-version buster --os-version buster-slim", osVersions);

                BuildLegInfo leg_2_0 = matrixInfo.Legs.ElementAt(1);
                imageBuilderPaths = leg_2_0.Variables.First(variable => variable.Name == "imageBuilderPaths").Value;
                Assert.Equal("--path 2.0/runtime/os2/Dockerfile --path 2.0/sdk/os2/Dockerfile", imageBuilderPaths);
                osVersions = leg_2_0.Variables.First(variable => variable.Name == "osVersions").Value;
                Assert.Equal("--os-version buster-slim --os-version buster", osVersions);
            }
        }
コード例 #21
0
        public void GenerateBuildMatrixCommand_ParentGraphOutsidePlatformGroup()
        {
            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.ProductVersionComponents = 2;

            string dockerfileRuntimeFullPath  = DockerfileHelper.CreateDockerfile("1.0/runtime/os", tempFolderContext);
            string dockerfileRuntime2FullPath = DockerfileHelper.CreateDockerfile("1.0/runtime2/os", tempFolderContext, "sdk3:tag");

            string dockerfileRuntime3FullPath = DockerfileHelper.CreateDockerfile("1.0/runtime3/os2", tempFolderContext);
            string dockerfileSdk3FullPath     = DockerfileHelper.CreateDockerfile("1.0/sdk3/os2", tempFolderContext, "runtime3:tag");

            Manifest manifest = CreateManifest(
                // Define a Dockerfile that has the same OS version and product version as runtime2 but no actual dependency to
                // ensure it gets its own matrix leg.
                CreateRepo("runtime",
                           CreateImage(
                               new Platform[]
            {
                CreatePlatform(dockerfileRuntimeFullPath, new string[] { "tag" }, osVersion: "buster")
            },
                               productVersion: "1.0")),
                CreateRepo("runtime2",
                           CreateImage(
                               new Platform[]
            {
                CreatePlatform(dockerfileRuntime2FullPath, new string[] { "runtime" }, osVersion: "bullseye")
            },
                               productVersion: "1.0")),
                CreateRepo("runtime3",
                           CreateImage(
                               new Platform[]
            {
                CreatePlatform(dockerfileRuntime3FullPath, new string[] { "tag" }, osVersion: "alpine3.12")
            },
                               productVersion: "1.0")),
                CreateRepo("sdk3",
                           CreateImage(
                               new Platform[]
            {
                CreatePlatform(dockerfileSdk3FullPath, new string[] { "tag" }, osVersion: "alpine3.12")
            },
                               productVersion: "1.0"))
                );

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

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

            Assert.Single(matrixInfos);

            BuildMatrixInfo matrixInfo = matrixInfos.First();

            Assert.Equal(2, matrixInfo.Legs.Count);
            BuildLegInfo leg_1_0           = matrixInfo.Legs.First();
            string       imageBuilderPaths = leg_1_0.Variables.First(variable => variable.Name == "imageBuilderPaths").Value;

            Assert.Equal("--path 1.0/runtime/os/Dockerfile", imageBuilderPaths);

            BuildLegInfo leg_2_0 = matrixInfo.Legs.ElementAt(1);

            imageBuilderPaths = leg_2_0.Variables.First(variable => variable.Name == "imageBuilderPaths").Value;
            Assert.Equal("--path 1.0/runtime2/os/Dockerfile --path 1.0/sdk3/os2/Dockerfile --path 1.0/runtime3/os2/Dockerfile", imageBuilderPaths);
        }
コード例 #22
0
        public void GenerateBuildMatrixCommand_ServerCoreAndNanoServerDependency()
        {
            using TempFolderContext tempFolderContext = TestHelper.UseTempFolder();
            const string customBuildLegGrouping = "custom";
            GenerateBuildMatrixCommand command  = new GenerateBuildMatrixCommand();

            command.Options.Manifest   = Path.Combine(tempFolderContext.Path, "manifest.json");
            command.Options.MatrixType = MatrixType.PlatformDependencyGraph;
            command.Options.ProductVersionComponents = 2;
            command.Options.CustomBuildLegGrouping   = customBuildLegGrouping;

            Manifest manifest = CreateManifest(
                CreateRepo("runtime",
                           CreateImage(
                               new Platform[]
            {
                CreatePlatform(
                    DockerfileHelper.CreateDockerfile("1.0/runtime/nanoserver-1909", tempFolderContext),
                    new string[] { "nanoserver-1909" },
                    os: OS.Windows,
                    osVersion: "nanoserver-1909")
            },
                               productVersion: "1.0"),
                           CreateImage(
                               new Platform[]
            {
                CreatePlatform(
                    DockerfileHelper.CreateDockerfile("1.0/runtime/windowsservercore-1909", tempFolderContext),
                    new string[] { "windowsservercore-1909" },
                    os: OS.Windows,
                    osVersion: "windowsservercore-1909")
            },
                               productVersion: "1.0")),
                CreateRepo("aspnet",
                           CreateImage(
                               new Platform[]
            {
                CreatePlatform(
                    DockerfileHelper.CreateDockerfile("1.0/aspnet/nanoserver-1909", tempFolderContext, "runtime:nanoserver-1909"),
                    new string[] { "nanoserver-1909" },
                    os: OS.Windows,
                    osVersion: "nanoserver-1909")
            },
                               productVersion: "1.0"),
                           CreateImage(
                               new Platform[]
            {
                CreatePlatform(
                    DockerfileHelper.CreateDockerfile("1.0/aspnet/windowsservercore-1909", tempFolderContext, "runtime:windowsservercore-1909"),
                    new string[] { "windowsservercore-1909" },
                    os: OS.Windows,
                    osVersion: "windowsservercore-1909",
                    customBuildLegGroupings: new CustomBuildLegGrouping[]
                {
                    new CustomBuildLegGrouping
                    {
                        Name         = customBuildLegGrouping,
                        Dependencies = new string[]
                        {
                            "aspnet:nanoserver-1909"
                        }
                    }
                })
            },
                               productVersion: "1.0"))
                );

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

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

            Assert.Single(matrixInfos);

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

            Assert.Equal(
                "--path 1.0/runtime/nanoserver-1909/Dockerfile --path 1.0/aspnet/nanoserver-1909/Dockerfile --path 1.0/runtime/windowsservercore-1909/Dockerfile --path 1.0/aspnet/windowsservercore-1909/Dockerfile",
                imageBuilderPaths);
            string osVersions = leg.Variables.First(variable => variable.Name == "osVersions").Value;

            Assert.Equal(
                "--os-version nanoserver-1909 --os-version windowsservercore-1909",
                osVersions);
        }
コード例 #23
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()
            {
                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"
                                        },
                                            layers: new List <string>
                                        {
                                            "qwe",
                                            "asd"
                                        })
                                    },
                                    {
                                        Helpers.ImageInfoHelper.CreatePlatform(
                                            repo1Image2DockerfilePath,
                                            created: new DateTime(2020, 4, 20, 21, 56, 56, DateTimeKind.Utc),
                                            digest: "ghi",
                                            simpleTags: new List <string>
                                        {
                                            "t2"
                                        },
                                            layers: new List <string>
                                        {
                                            "qwe"
                                        })
                                    }
                                },
                                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"
                                    },
                                        layers: new List <string>
                                    {
                                        "zxc"
                                    })
                                },
                                ProductVersion = "2.0.5"
                            }
                        }
                    }
                }
            };

            string expectedImageData =
                @"""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""";

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

            string expectedLayerData =
                @"""qwe"",""0"",""2"",""def"",""amd64"",""Linux"",""Ubuntu 20.04"",""1.0.2"",""1.0/sdk/os/Dockerfile"",""r1"",""2020-04-20 21:56:50""
""asd"",""0"",""1"",""def"",""amd64"",""Linux"",""Ubuntu 20.04"",""1.0.2"",""1.0/sdk/os/Dockerfile"",""r1"",""2020-04-20 21:56:50""
""qwe"",""0"",""1"",""ghi"",""amd64"",""Linux"",""Ubuntu 20.04"",""1.0.2"",""1.0/sdk/os2/Dockerfile"",""r1"",""2020-04-20 21:56:56""
""zxc"",""0"",""1"",""jkl"",""amd64"",""Linux"",""Ubuntu 20.04"",""2.0.5"",""2.0/sdk/os/Dockerfile"",""r2"",""2020-04-20 21:56:58""";

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

            await ValidateExecuteAsync(tempFolderContext, manifestPath, srcImageArtifactDetails, expectedImageData, expectedLayerData);
        }