in tool/TeamCity.Docker/ReadmeFilesGenerator.cs [30:235]
public void Generate(IGraph<IArtifact, Dependency> graph)
{
if (graph == null) throw new ArgumentNullException(nameof(graph));
var groups = (
from node in graph.Nodes
let image = node.Value as Image
where image != null
group node by image.File.ImageId
into groupsByImageId
orderby groupsByImageId.Key
from groupByImageId in
from groupByImageId in groupsByImageId
let image = groupByImageId.Value as Image
where image != null
orderby image.File
group groupByImageId by image.File
group groupByImageId by groupsByImageId.Key)
.ToList();
foreach (var groupByImageId in groups)
{
var imageId = groupByImageId.Key;
var lines = new List<string>();
graph.TryAddNode(new FileArtifact(GetReadmeFile(imageId), lines), out var readmeNode);
var groupByImage = groupByImageId.ToList();
lines.Add($"## {imageId} tags");
lines.Add(string.Empty);
var otherImages = groups.Where(i => i.Key != imageId).ToList();
if (otherImages.Any())
{
lines.Add("Other tags");
lines.Add(string.Empty);
foreach (var image in otherImages)
{
lines.Add($"- [{image.Key}]({GetReadmeFilePath(image.Key)})");
}
}
lines.Add(string.Empty);
// ReSharper disable once IdentifierTypo
var mutliArch = (
from grp in (
from image in groupByImage
where image.Key.Repositories.Any()
from tag in image.Key.Tags.Skip(1)
where tag.Length > 0 && char.IsLetterOrDigit(tag[0])
orderby tag descending
group image by tag)
orderby $"{grp.Count()} {grp.Key}" descending
select grp)
.ToList();
if (mutliArch.Any())
{
lines.Add("#### multi-architecture");
lines.Add(string.Empty);
lines.Add("When running an image with multi-architecture support, docker will automatically select an image variant which matches your OS and architecture.");
lines.Add(string.Empty);
foreach (var dockerfileByMultiArchTag in mutliArch)
{
lines.Add($"- [{dockerfileByMultiArchTag.Key}](#{Normalize(dockerfileByMultiArchTag.Key)})");
}
lines.Add(string.Empty);
}
var dockerfileGroups =
from image in groupByImage
orderby image.Key.Platform
group image by image.Key.Platform
into grp1
from grp2 in (
from image in grp1
orderby image.Key.Description descending
group image by image.Key.Description)
group grp2 by grp1.Key;
foreach (var dockerfileByPlatform in dockerfileGroups)
{
lines.Add($"#### {dockerfileByPlatform.Key}");
lines.Add(string.Empty);
foreach (var dockerfileByDescription in dockerfileByPlatform)
{
lines.Add($"- {dockerfileByDescription.Key}");
foreach (var dockerfile in dockerfileByDescription)
{
lines.Add($" - [{GetReadmeTagName(dockerfile.Key)}](#{GetTagLink(dockerfile.Key)})");
}
}
lines.Add(string.Empty);
}
lines.Add(string.Empty);
foreach (var dockerfileByMultiArchTag in mutliArch)
{
lines.Add($"### {dockerfileByMultiArchTag.Key}");
lines.Add(string.Empty);
var platforms = string.Join(", ", dockerfileByMultiArchTag.Select(i => $"{i.Key.Platform} {i.Key.Description}").Distinct().OrderBy(i => i));
lines.Add($"Supported platforms: {platforms}");
lines.Add(string.Empty);
lines.Add("#### Content");
lines.Add(string.Empty);
foreach (var dockerfile in dockerfileByMultiArchTag)
{
lines.Add($"- [{GetReadmeTagName(dockerfile.Key)}](#{GetTagLink(dockerfile.Key)})");
}
lines.Add(string.Empty);
}
// Adding Dockerfile links
lines.Add(string.Empty);
lines.Add("# Dockerfile links\n");
lines.Add(GetLinkForOs(groupByImage, "Linux"));
lines.Add(GetLinkForOs(groupByImage, "Windows"));
lines.Add(string.Empty);
foreach (var groupByFile in groupByImage)
{
var dockerFile = groupByFile.Key;
lines.Add($"### {GetReadmeTagName(dockerFile)}");
lines.Add(string.Empty);
lines.Add($"[Dockerfile]({_pathService.Normalize(Path.Combine(dockerFile.Path, "Dockerfile"))})");
if (dockerFile.Comments.Any())
{
lines.Add(string.Empty);
foreach (var comment in dockerFile.Comments)
{
lines.Add(comment);
}
}
if (dockerFile.Repositories.Any(i => !string.IsNullOrWhiteSpace(i)))
{
lines.Add(string.Empty);
lines.Add("The docker image is available on:");
lines.Add(string.Empty);
foreach (var repo in dockerFile.Repositories.Where(i => !string.IsNullOrWhiteSpace(i)))
{
lines.Add($"- [{repo}{dockerFile.ImageId}]({repo}{dockerFile.ImageId})");
}
}
else
{
lines.Add("The docker image is not available and may be created manually.");
}
if (dockerFile.Components.Any())
{
lines.Add(string.Empty);
lines.Add("Installed components:");
lines.Add(string.Empty);
foreach (var component in dockerFile.Components)
{
lines.Add($"- {component}");
}
}
lines.Add(string.Empty);
lines.Add($"Container platform: {dockerFile.Platform}");
foreach (var node in groupByFile)
{
var weight = 0;
var script = _scriptGenerator.GenerateScript(graph, node, artifact =>
{
weight += artifact.Weight.Value;
return true;
}).ToList();
if (weight > 0)
{
lines.Add(string.Empty);
lines.Add("Docker build commands:");
lines.Add(string.Empty);
lines.Add("```");
lines.AddRange(script);
lines.Add("```");
if (weight > 0)
{
lines.Add(string.Empty);
lines.Add($"_The required free space to generate image(s) is about **{weight} GB**._");
}
lines.Add(string.Empty);
}
}
foreach (var node in groupByFile)
{
graph.TryAddLink(node, GenerateDependency, readmeNode, out _);
}
}
}
}