Upload checksums for installation artifacts (#4191)
The checksums are SHA-512 hashes, which users can use to verify file integrity and authenticity.
This commit is contained in:
parent
3e1eb008e2
commit
3ae14ab618
11 changed files with 402 additions and 200 deletions
|
@ -0,0 +1,86 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.DotNet.Cli.Build
|
||||
{
|
||||
public class CheckIfAllBuildsHavePublished : Task
|
||||
{
|
||||
private AzurePublisher _azurePublisher;
|
||||
|
||||
[Required]
|
||||
public string AccountName { get; set; }
|
||||
|
||||
[Required]
|
||||
public string AccountKey { get; set; }
|
||||
|
||||
[Required]
|
||||
public string ContainerName { get; set; }
|
||||
|
||||
[Required]
|
||||
public string NugetVersion { get; set; }
|
||||
|
||||
[Output]
|
||||
public string HaveAllBuildsPublished { get; set; }
|
||||
|
||||
private AzurePublisher AzurePublisherTool
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_azurePublisher == null)
|
||||
{
|
||||
_azurePublisher = new AzurePublisher(AccountName, AccountKey, ContainerName);
|
||||
}
|
||||
|
||||
return _azurePublisher;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Execute()
|
||||
{
|
||||
var badges = new Dictionary<string, bool>()
|
||||
{
|
||||
{ "Windows_x86", false },
|
||||
{ "Windows_x64", false },
|
||||
{ "Ubuntu_x64", false },
|
||||
{ "Ubuntu_16_04_x64", false },
|
||||
{ "RHEL_x64", false },
|
||||
{ "OSX_x64", false },
|
||||
{ "Debian_x64", false },
|
||||
{ "CentOS_x64", false },
|
||||
{ "Fedora_23_x64", false },
|
||||
{ "openSUSE_13_2_x64", false }
|
||||
};
|
||||
|
||||
var versionBadgeName = $"{Monikers.GetBadgeMoniker()}";
|
||||
if (!badges.ContainsKey(versionBadgeName))
|
||||
{
|
||||
throw new ArgumentException($"A new OS build '{versionBadgeName}' was added without adding the moniker to the {nameof(badges)} lookup");
|
||||
}
|
||||
|
||||
IEnumerable<string> blobs = AzurePublisherTool.ListBlobs(AzurePublisher.Product.Sdk, NugetVersion);
|
||||
foreach (string file in blobs)
|
||||
{
|
||||
string name = Path.GetFileName(file);
|
||||
foreach (string img in badges.Keys)
|
||||
{
|
||||
if ((name.StartsWith($"{img}")) && (name.EndsWith(".svg")))
|
||||
{
|
||||
badges[img] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HaveAllBuildsPublished = badges.Values.All(v => v).ToString();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
108
build_projects/dotnet-cli-build/CopyBlobsToLatest.cs
Normal file
108
build_projects/dotnet-cli-build/CopyBlobsToLatest.cs
Normal file
|
@ -0,0 +1,108 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Microsoft.DotNet.Cli.Build
|
||||
{
|
||||
public class CopyBlobsToLatest : Task
|
||||
{
|
||||
private AzurePublisher _azurePublisher;
|
||||
|
||||
[Required]
|
||||
public string AccountName { get; set; }
|
||||
|
||||
[Required]
|
||||
public string AccountKey { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Channel { get; set; }
|
||||
|
||||
[Required]
|
||||
public string CommitHash { get; set; }
|
||||
|
||||
[Required]
|
||||
public string ContainerName { get; set; }
|
||||
|
||||
[Required]
|
||||
public string NugetVersion { get; set; }
|
||||
|
||||
private AzurePublisher AzurePublisherTool
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_azurePublisher == null)
|
||||
{
|
||||
_azurePublisher = new AzurePublisher(AccountName, AccountKey, ContainerName);
|
||||
}
|
||||
|
||||
return _azurePublisher;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Execute()
|
||||
{
|
||||
string targetFolder = $"{AzurePublisher.Product.Sdk}/{Channel}";
|
||||
|
||||
string targetVersionFile = $"{targetFolder}/{CommitHash}";
|
||||
string semaphoreBlob = $"{targetFolder}/publishSemaphore";
|
||||
AzurePublisherTool.CreateBlobIfNotExists(semaphoreBlob);
|
||||
string leaseId = AzurePublisherTool.AcquireLeaseOnBlob(semaphoreBlob);
|
||||
|
||||
// Prevent race conditions by dropping a version hint of what version this is. If we see this file
|
||||
// and it is the same as our version then we know that a race happened where two+ builds finished
|
||||
// at the same time and someone already took care of publishing and we have no work to do.
|
||||
if (AzurePublisherTool.IsLatestSpecifiedVersion(targetVersionFile))
|
||||
{
|
||||
AzurePublisherTool.ReleaseLeaseOnBlob(semaphoreBlob, leaseId);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Regex versionFileRegex = new Regex(@"(?<CommitHash>[\w\d]{40})");
|
||||
|
||||
// Delete old version files
|
||||
AzurePublisherTool.ListBlobs(targetFolder)
|
||||
.Where(s => versionFileRegex.IsMatch(s))
|
||||
.ToList()
|
||||
.ForEach(f => AzurePublisherTool.TryDeleteBlob(f));
|
||||
|
||||
// Drop the version file signaling such for any race-condition builds (see above comment).
|
||||
AzurePublisherTool.DropLatestSpecifiedVersion(targetVersionFile);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
CopyBlobs(targetFolder);
|
||||
|
||||
string cliVersion = Utils.GetVersionFileContent(CommitHash, NugetVersion);
|
||||
AzurePublisherTool.PublishStringToBlob($"{targetFolder}/latest.version", cliVersion);
|
||||
}
|
||||
finally
|
||||
{
|
||||
AzurePublisherTool.ReleaseLeaseOnBlob(semaphoreBlob, leaseId);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void CopyBlobs(string destinationFolder)
|
||||
{
|
||||
Log.LogMessage("Copying blobs to {0}/{1}", ContainerName, destinationFolder);
|
||||
|
||||
foreach (string blob in AzurePublisherTool.ListBlobs(AzurePublisher.Product.Sdk, NugetVersion))
|
||||
{
|
||||
string targetName = Path.GetFileName(blob)
|
||||
.Replace(NugetVersion, "latest");
|
||||
|
||||
string target = $"{destinationFolder}/{targetName}";
|
||||
|
||||
AzurePublisherTool.CopyBlob(blob, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,163 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
|
||||
namespace Microsoft.DotNet.Cli.Build
|
||||
{
|
||||
public class FinalizeBuild : Task
|
||||
{
|
||||
private AzurePublisher _azurePublisher;
|
||||
|
||||
[Required]
|
||||
public string AccountName { get; set; }
|
||||
|
||||
[Required]
|
||||
public string AccountKey { get; set; }
|
||||
|
||||
[Required]
|
||||
public string NugetVersion { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Channel { get; set; }
|
||||
|
||||
[Required]
|
||||
public string CommitHash { get; set; }
|
||||
|
||||
[Required]
|
||||
public string BranchName { get; set; }
|
||||
|
||||
private AzurePublisher AzurePublisherTool
|
||||
{
|
||||
get
|
||||
{
|
||||
if(_azurePublisher == null)
|
||||
{
|
||||
_azurePublisher = new AzurePublisher(AccountName, AccountKey);
|
||||
}
|
||||
|
||||
return _azurePublisher;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Execute()
|
||||
{
|
||||
DoFinalizeBuild();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void DoFinalizeBuild()
|
||||
{
|
||||
if (CheckIfAllBuildsHavePublished())
|
||||
{
|
||||
string targetContainer = $"{AzurePublisher.Product.Sdk}/{Channel}";
|
||||
string targetVersionFile = $"{targetContainer}/{CommitHash}";
|
||||
string semaphoreBlob = $"{targetContainer}/publishSemaphore";
|
||||
AzurePublisherTool.CreateBlobIfNotExists(semaphoreBlob);
|
||||
string leaseId = AzurePublisherTool.AcquireLeaseOnBlob(semaphoreBlob);
|
||||
|
||||
// Prevent race conditions by dropping a version hint of what version this is. If we see this file
|
||||
// and it is the same as our version then we know that a race happened where two+ builds finished
|
||||
// at the same time and someone already took care of publishing and we have no work to do.
|
||||
if (AzurePublisherTool.IsLatestSpecifiedVersion(targetVersionFile))
|
||||
{
|
||||
AzurePublisherTool.ReleaseLeaseOnBlob(semaphoreBlob, leaseId);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Regex versionFileRegex = new Regex(@"(?<CommitHash>[\w\d]{40})");
|
||||
|
||||
// Delete old version files
|
||||
AzurePublisherTool.ListBlobs(targetContainer)
|
||||
.Where(s => versionFileRegex.IsMatch(s))
|
||||
.ToList()
|
||||
.ForEach(f => AzurePublisherTool.TryDeleteBlob(f));
|
||||
|
||||
// Drop the version file signaling such for any race-condition builds (see above comment).
|
||||
AzurePublisherTool.DropLatestSpecifiedVersion(targetVersionFile);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
CopyBlobsToLatest(targetContainer);
|
||||
|
||||
string cliVersion = Utils.GetVersionFileContent(CommitHash, NugetVersion);
|
||||
AzurePublisherTool.PublishStringToBlob($"{targetContainer}/latest.version", cliVersion);
|
||||
|
||||
UpdateVersionsRepo();
|
||||
}
|
||||
finally
|
||||
{
|
||||
AzurePublisherTool.ReleaseLeaseOnBlob(semaphoreBlob, leaseId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool CheckIfAllBuildsHavePublished()
|
||||
{
|
||||
var badges = new Dictionary<string, bool>()
|
||||
{
|
||||
{ "Windows_x86", false },
|
||||
{ "Windows_x64", false },
|
||||
{ "Ubuntu_x64", false },
|
||||
{ "Ubuntu_16_04_x64", false },
|
||||
{ "RHEL_x64", false },
|
||||
{ "OSX_x64", false },
|
||||
{ "Debian_x64", false },
|
||||
{ "CentOS_x64", false },
|
||||
{ "Fedora_23_x64", false },
|
||||
{ "openSUSE_13_2_x64", false }
|
||||
};
|
||||
|
||||
var versionBadgeName = $"{Monikers.GetBadgeMoniker()}";
|
||||
if (!badges.ContainsKey(versionBadgeName))
|
||||
{
|
||||
throw new ArgumentException($"A new OS build '{versionBadgeName}' was added without adding the moniker to the {nameof(badges)} lookup");
|
||||
}
|
||||
|
||||
IEnumerable<string> blobs = AzurePublisherTool.ListBlobs(AzurePublisher.Product.Sdk, NugetVersion);
|
||||
foreach (string file in blobs)
|
||||
{
|
||||
string name = Path.GetFileName(file);
|
||||
foreach (string img in badges.Keys)
|
||||
{
|
||||
if ((name.StartsWith($"{img}")) && (name.EndsWith(".svg")))
|
||||
{
|
||||
badges[img] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return badges.Values.All(v => v);
|
||||
}
|
||||
|
||||
private void CopyBlobsToLatest(string destinationFolder)
|
||||
{
|
||||
foreach (string blob in AzurePublisherTool.ListBlobs(AzurePublisher.Product.Sdk, NugetVersion))
|
||||
{
|
||||
string targetName = Path.GetFileName(blob)
|
||||
.Replace(NugetVersion, "latest");
|
||||
|
||||
string target = $"{destinationFolder}/{targetName}";
|
||||
AzurePublisherTool.CopyBlob(blob, target);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateVersionsRepo()
|
||||
{
|
||||
string githubAuthToken = EnvVars.EnsureVariable("GITHUB_PASSWORD");
|
||||
string nupkgFilePath = Dirs.Packages;
|
||||
string branchName = BranchName;
|
||||
string versionsRepoPath = $"build-info/dotnet/cli/{branchName}/Latest";
|
||||
|
||||
VersionRepoUpdater repoUpdater = new VersionRepoUpdater(githubAuthToken);
|
||||
repoUpdater.UpdatePublishedVersions(nupkgFilePath, versionsRepoPath).Wait();
|
||||
}
|
||||
}
|
||||
}
|
66
build_projects/dotnet-cli-build/GenerateChecksums.cs
Normal file
66
build_projects/dotnet-cli-build/GenerateChecksums.cs
Normal file
|
@ -0,0 +1,66 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace Microsoft.DotNet.Build.Tasks
|
||||
{
|
||||
public class GenerateChecksums : Task
|
||||
{
|
||||
/// <summary>
|
||||
/// An item collection of files for which to generate checksums. Each item must have metadata
|
||||
/// 'DestinationPath' that specifies the path of the checksum file to create.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem[] Items { get; set; }
|
||||
|
||||
public override bool Execute()
|
||||
{
|
||||
foreach (ITaskItem item in Items)
|
||||
{
|
||||
try
|
||||
{
|
||||
string destinationPath = item.GetMetadata("DestinationPath");
|
||||
if (string.IsNullOrEmpty(destinationPath))
|
||||
{
|
||||
throw new Exception($"Metadata 'DestinationPath' is missing for item '{item.ItemSpec}'.");
|
||||
}
|
||||
|
||||
if (!File.Exists(item.ItemSpec))
|
||||
{
|
||||
throw new Exception($"The file '{item.ItemSpec}' does not exist.");
|
||||
}
|
||||
|
||||
Log.LogMessage(
|
||||
MessageImportance.High,
|
||||
"Generating checksum for '{0}' into '{1}'...",
|
||||
item.ItemSpec,
|
||||
destinationPath);
|
||||
|
||||
using (FileStream stream = File.OpenRead(item.ItemSpec))
|
||||
{
|
||||
HashAlgorithm hashAlgorithm = SHA512.Create();
|
||||
byte[] hash = hashAlgorithm.ComputeHash(stream);
|
||||
string checksum = BitConverter.ToString(hash).Replace("-", string.Empty);
|
||||
File.WriteAllText(destinationPath, checksum);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// We have 2 log calls because we want a nice error message but we also want to capture the
|
||||
// callstack in the log.
|
||||
Log.LogError("An exception occurred while trying to generate a checksum for '{0}'.", item.ItemSpec);
|
||||
Log.LogMessage(MessageImportance.Low, e.ToString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
27
build_projects/dotnet-cli-build/UpdateVersionsRepo.cs
Normal file
27
build_projects/dotnet-cli-build/UpdateVersionsRepo.cs
Normal file
|
@ -0,0 +1,27 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
|
||||
namespace Microsoft.DotNet.Cli.Build
|
||||
{
|
||||
public class UpdateVersionsRepo : Task
|
||||
{
|
||||
[Required]
|
||||
public string BranchName { get; set; }
|
||||
|
||||
public override bool Execute()
|
||||
{
|
||||
string githubAuthToken = EnvVars.EnsureVariable("GITHUB_PASSWORD");
|
||||
string nupkgFilePath = Dirs.Packages;
|
||||
string branchName = BranchName;
|
||||
string versionsRepoPath = $"build-info/dotnet/cli/{branchName}/Latest";
|
||||
|
||||
VersionRepoUpdater repoUpdater = new VersionRepoUpdater(githubAuthToken);
|
||||
repoUpdater.UpdatePublishedVersions(nupkgFilePath, versionsRepoPath).Wait();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue