Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modernize tools #6

Merged
merged 3 commits into from
Feb 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,16 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<PropertyGroup>
<NoWarn>$(NoWarn),SA0001,CA1014</NoWarn>
<NoWarn>$(NoWarn),SA0001,SA1200,SA1516,CA1014,CA1812</NoWarn>
blairconrad marked this conversation as resolved.
Show resolved Hide resolved
<SimpleExecVersion>6.1.0</SimpleExecVersion>
<NuGetVersion>4.1.0</NuGetVersion>
<OctokitVersion>0.31.0</OctokitVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Remove="Microsoft.CodeAnalysis.FxCopAnalyzers" />
</ItemGroup>
blairconrad marked this conversation as resolved.
Show resolved Hide resolved

</Project>
253 changes: 120 additions & 133 deletions FakeItEasy.Deploy/Program.cs
Original file line number Diff line number Diff line change
@@ -1,147 +1,134 @@
namespace FakeItEasy.Deploy
using FakeItEasy.Deploy;
using FakeItEasy.Tools;
using Octokit;
using static FakeItEasy.Tools.ReleaseHelpers;
using static SimpleExec.Command;

if (args.Length != 1)
{
Console.WriteLine("Illegal arguments. Usage:");
Console.WriteLine("<program> <artifactsFolder>");
}

string artifactsFolder = args[0];

var releaseName = GetAppVeyorTagName();
if (string.IsNullOrEmpty(releaseName))
{
Console.WriteLine("No Appveyor tag name supplied. Not deploying.");
return;
}

var nugetServerUrl = GetNuGetServerUrl();
var nugetApiKey = GetNuGetApiKey();
var (repoOwner, repoName) = GetRepositoryName();
var gitHubClient = GetAuthenticatedGitHubClient();

Console.WriteLine($"Deploying {releaseName}");
Console.WriteLine($"Looking for GitHub release {releaseName}");

var releases = await gitHubClient.Repository.Release.GetAll(repoOwner, repoName);
var release = releases.FirstOrDefault(r => r.Name == releaseName)
?? throw new Exception($"Can't find release {releaseName}");

const string artifactsPattern = "*.nupkg";

var artifacts = Directory.GetFiles(artifactsFolder, artifactsPattern);
if (!artifacts.Any())
{
throw new Exception("Can't find any artifacts to publish");
}

Console.WriteLine($"Uploading artifacts to GitHub release {releaseName}");
foreach (var file in artifacts)
{
await UploadArtifactToGitHubReleaseAsync(gitHubClient, release, file);
}

Console.WriteLine($"Pushing nupkgs to {nugetServerUrl}");
foreach (var file in artifacts)
{
await UploadPackageToNuGetAsync(file, nugetServerUrl, nugetApiKey);
}

var issueNumbersInCurrentRelease = GetIssueNumbersReferencedFromReleases(new[] { release });
var preReleases = GetPreReleasesContributingToThisRelease(release, releases);
var issueNumbersInPreReleases = GetIssueNumbersReferencedFromReleases(preReleases);
var newIssueNumbers = issueNumbersInCurrentRelease.Except(issueNumbersInPreReleases);

Console.WriteLine($"Adding 'released as part of' notes to {newIssueNumbers.Count()} issues");
var commentText = $"This change has been released as part of [{repoName} {releaseName}](https://github.com/{repoOwner}/{repoName}/releases/tag/{releaseName}).";
await Task.WhenAll(newIssueNumbers.Select(n => gitHubClient.Issue.Comment.Create(repoOwner, repoName, n, commentText)));

Console.WriteLine("Finished deploying");

static IEnumerable<Release> GetPreReleasesContributingToThisRelease(Release release, IReadOnlyList<Release> releases)
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using FakeItEasy.Tools;
using Octokit;
using static FakeItEasy.Tools.ReleaseHelpers;
using static SimpleExec.Command;

internal static class Program
if (release.Prerelease)
{
public static async Task Main(string[] args)
{
if (args.Length != 1)
{
Console.WriteLine("Illegal arguments. Usage:");
Console.WriteLine("<program> <artifactsFolder>");
}

string artifactsFolder = args[0];

var releaseName = GetAppVeyorTagName();
if (string.IsNullOrEmpty(releaseName))
{
Console.WriteLine("No Appveyor tag name supplied. Not deploying.");
return;
}

var nugetServerUrl = GetNuGetServerUrl();
var nugetApiKey = GetNuGetApiKey();
var (repoOwner, repoName) = GetRepositoryName();
var gitHubClient = GetAuthenticatedGitHubClient();

Console.WriteLine($"Deploying {releaseName}");
Console.WriteLine($"Looking for GitHub release {releaseName}");

var releases = await gitHubClient.Repository.Release.GetAll(repoOwner, repoName);
var release = releases.FirstOrDefault(r => r.Name == releaseName)
?? throw new Exception($"Can't find release {releaseName}");

const string artifactsPattern = "*.nupkg";

var artifacts = Directory.GetFiles(artifactsFolder, artifactsPattern);
if (!artifacts.Any())
{
throw new Exception("Can't find any artifacts to publish");
}

Console.WriteLine($"Uploading artifacts to GitHub release {releaseName}");
foreach (var file in artifacts)
{
await UploadArtifactToGitHubReleaseAsync(gitHubClient, release, file);
}

Console.WriteLine($"Pushing nupkgs to {nugetServerUrl}");
foreach (var file in artifacts)
{
await UploadPackageToNuGetAsync(file, nugetServerUrl, nugetApiKey);
}

var issueNumbersInCurrentRelease = GetIssueNumbersReferencedFromReleases(new[] { release });
var preReleases = GetPreReleasesContributingToThisRelease(release, releases);
var issueNumbersInPreReleases = GetIssueNumbersReferencedFromReleases(preReleases);
var newIssueNumbers = issueNumbersInCurrentRelease.Except(issueNumbersInPreReleases);

Console.WriteLine($"Adding 'released as part of' notes to {newIssueNumbers.Count()} issues");
var commentText = $"This change has been released as part of [{repoName} {releaseName}](https://github.com/{repoOwner}/{repoName}/releases/tag/{releaseName}).";
await Task.WhenAll(newIssueNumbers.Select(n => gitHubClient.Issue.Comment.Create(repoOwner, repoName, n, commentText)));

Console.WriteLine("Finished deploying");
}

private static IEnumerable<Release> GetPreReleasesContributingToThisRelease(Release release, IReadOnlyList<Release> releases)
{
if (release.Prerelease)
{
return Enumerable.Empty<Release>();
}
return Enumerable.Empty<Release>();
}

string baseName = BaseName(release);
return releases.Where(r => r.Prerelease && BaseName(r) == baseName);
string baseName = BaseName(release);
return releases.Where(r => r.Prerelease && BaseName(r) == baseName);

string BaseName(Release release) => release.Name.Split('-')[0];
}
string BaseName(Release release) => release.Name.Split('-')[0];
}

private static async Task UploadArtifactToGitHubReleaseAsync(GitHubClient client, Release release, string path)
{
var name = Path.GetFileName(path);
Console.WriteLine($"Uploading {name}");
using (var stream = File.OpenRead(path))
{
var upload = new ReleaseAssetUpload
{
FileName = name,
ContentType = "application/octet-stream",
RawData = stream,
Timeout = TimeSpan.FromSeconds(100)
};

var asset = await client.Repository.Release.UploadAsset(release, upload);
Console.WriteLine($"Uploaded {asset.Name}");
}
}

private static async Task UploadPackageToNuGetAsync(string path, string nugetServerUrl, string nugetApiKey)
static async Task UploadArtifactToGitHubReleaseAsync(GitHubClient client, Release release, string path)
{
var name = Path.GetFileName(path);
Console.WriteLine($"Uploading {name}");
using (var stream = File.OpenRead(path))
{
var upload = new ReleaseAssetUpload
{
string name = Path.GetFileName(path);
Console.WriteLine($"Pushing {name}");
await RunAsync(ToolPaths.NuGet, $"push \"{path}\" -ApiKey {nugetApiKey} -Source {nugetServerUrl} -NonInteractive -ForceEnglishOutput", noEcho: true);
Console.WriteLine($"Pushed {name}");
}
FileName = name,
ContentType = "application/octet-stream",
RawData = stream,
Timeout = TimeSpan.FromSeconds(100)
};

var asset = await client.Repository.Release.UploadAsset(release, upload);
Console.WriteLine($"Uploaded {asset.Name}");
}
}

private static (string repoOwner, string repoName) GetRepositoryName()
{
var repoNameWithOwner = GetRequiredEnvironmentVariable("APPVEYOR_REPO_NAME");
var parts = repoNameWithOwner.Split('/');
return (parts[0], parts[1]);
}
static async Task UploadPackageToNuGetAsync(string path, string nugetServerUrl, string nugetApiKey)
{
string name = Path.GetFileName(path);
Console.WriteLine($"Pushing {name}");
await RunAsync(ToolPaths.NuGet, $"push \"{path}\" -ApiKey {nugetApiKey} -Source {nugetServerUrl} -NonInteractive -ForceEnglishOutput", noEcho: true);
Console.WriteLine($"Pushed {name}");
}

private static GitHubClient GetAuthenticatedGitHubClient()
{
var token = GitHubTokenSource.GetAccessToken();
var credentials = new Credentials(token);
return new GitHubClient(new ProductHeaderValue("FakeItEasy-build-scripts")) { Credentials = credentials };
}
static (string repoOwner, string repoName) GetRepositoryName()
{
var repoNameWithOwner = GetRequiredEnvironmentVariable("APPVEYOR_REPO_NAME");
var parts = repoNameWithOwner.Split('/');
return (parts[0], parts[1]);
}

private static string? GetAppVeyorTagName() => Environment.GetEnvironmentVariable("APPVEYOR_REPO_TAG_NAME");
static GitHubClient GetAuthenticatedGitHubClient()
{
var token = GitHubTokenSource.GetAccessToken();
var credentials = new Credentials(token);
return new GitHubClient(new ProductHeaderValue("FakeItEasy-build-scripts")) { Credentials = credentials };
}

private static string GetNuGetServerUrl() => GetRequiredEnvironmentVariable("NUGET_SERVER_URL");
static string? GetAppVeyorTagName() => Environment.GetEnvironmentVariable("APPVEYOR_REPO_TAG_NAME");

private static string GetNuGetApiKey() => GetRequiredEnvironmentVariable("NUGET_API_KEY");
static string GetNuGetServerUrl() => GetRequiredEnvironmentVariable("NUGET_SERVER_URL");

private static string GetRequiredEnvironmentVariable(string key)
{
var environmentValue = Environment.GetEnvironmentVariable(key);
if (string.IsNullOrEmpty(environmentValue))
{
throw new Exception($"Required environment variable {key} is not set. Unable to continue.");
}

return environmentValue;
}
static string GetNuGetApiKey() => GetRequiredEnvironmentVariable("NUGET_API_KEY");

static string GetRequiredEnvironmentVariable(string key)
{
var environmentValue = Environment.GetEnvironmentVariable(key);
if (string.IsNullOrEmpty(environmentValue))
{
throw new Exception($"Required environment variable {key} is not set. Unable to continue.");
}

return environmentValue;
}
Loading