Skip to content

Commit

Permalink
Merge branch 'feature/release-automation' into feature-work/nuget-val…
Browse files Browse the repository at this point in the history
…idator
  • Loading branch information
tippmar-nr authored Aug 2, 2023
2 parents 69124ca + bbdad76 commit db1e04a
Show file tree
Hide file tree
Showing 9 changed files with 321 additions and 0 deletions.
38 changes: 38 additions & 0 deletions .github/workflows/deploy_agent.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ on:
description: 'If "true", will run the index-download-site job. If "false", will not.'
required: true
default: 'true'
update-apm-version:
description: 'If "true", will run the update-apm job. If "false", will not.'
required: true
default: 'true'

permissions:
contents: read
Expand Down Expand Up @@ -334,3 +338,37 @@ jobs:
run: |
curl -i -X POST -H 'Fastly-Key:${{ secrets.FASTLY_TOKEN }}' ${{ secrets.FASTLY_URL }}
shell: bash

update-apm:
name: Update System Configuration Page
runs-on: ubuntu-latest
if: ${{ github.event.inputs.update-apm-version == true }}
steps:
- name: Update system configuration page
run: |
PAYLOAD="{
\"system_configuration\": {
\"key\": \"dotnet_agent_version\",
\"value\": \"${{ github.event.inputs.agent_version }}\"
}
}"
CONTENT_TYPE='Content-Type: application/json'
# STAGING
curl -X POST 'https://staging-api.newrelic.com/v2/system_configuration.json' \
-H "X-Api-Key:${{ secrets.NEW_RELIC_API_KEY_STAGING }}" -i \
-H "$CONTENT_TYPE" \
-d "$PAYLOAD"
# PRODUCTION
curl -X POST 'https://api.newrelic.com/v2/system_configuration.json' \
-H "X-Api-Key:${{ secrets.NEW_RELIC_API_KEY_PRODUCTION }}" -i \
-H "$CONTENT_TYPE" \
-d "$PAYLOAD"
# EU PRODUCTION
curl -X POST 'https://api.eu.newrelic.com/v2/system_configuration.json' \
-H "X-Api-Key:${{ secrets.NEW_RELIC_API_KEY_PRODUCTION }}" -i \
-H "$CONTENT_TYPE" \
-d "$PAYLOAD"
5 changes: 5 additions & 0 deletions build/BuildTools.sln
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NewRelic.NuGetHelper", "NewRelic.NuGetHelper\NewRelic.NuGetHelper.csproj", "{94BF8D27-2122-4573-AA79-90B977B40EF3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NugetValidator", "NugetValidator\NugetValidator.csproj", "{C3F69996-5A5F-4836-A485-C270C318C6E9}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "S3Validator", "S3Validator\S3Validator.csproj", "{648D08B2-E677-4009-A593-D03E0579E859}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand All @@ -27,6 +28,10 @@ Global
{C3F69996-5A5F-4836-A485-C270C318C6E9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C3F69996-5A5F-4836-A485-C270C318C6E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C3F69996-5A5F-4836-A485-C270C318C6E9}.Release|Any CPU.Build.0 = Release|Any CPU
{648D08B2-E677-4009-A593-D03E0579E859}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{648D08B2-E677-4009-A593-D03E0579E859}.Debug|Any CPU.Build.0 = Debug|Any CPU
{648D08B2-E677-4009-A593-D03E0579E859}.Release|Any CPU.ActiveCfg = Release|Any CPU
{648D08B2-E677-4009-A593-D03E0579E859}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
17 changes: 17 additions & 0 deletions build/S3Validator/Configuration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright 2020 New Relic, Inc. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

namespace S3Validator
{
public class Configuration
{
[YamlDotNet.Serialization.YamlMember(Alias = "base-url")]
public string? BaseUrl { get; set; }

[YamlDotNet.Serialization.YamlMember(Alias = "directory-list")]
public List<string>? DirectoryList { get; set; }

[YamlDotNet.Serialization.YamlMember(Alias = "file-list")]
public List<FileDetails>? FileList { get; set; }
}
}
13 changes: 13 additions & 0 deletions build/S3Validator/ExitCode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2020 New Relic, Inc. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

namespace S3Validator
{
enum ExitCode : int
{
Success = 0,
Error = 1,
FileNotFound = 2,
BadArguments = 160
}
}
14 changes: 14 additions & 0 deletions build/S3Validator/FileDetails.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright 2020 New Relic, Inc. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

namespace S3Validator
{
public struct FileDetails
{
[YamlDotNet.Serialization.YamlMember(Alias = "name")]
public string Name { get; set; }

[YamlDotNet.Serialization.YamlMember(Alias = "size")]
public long Size { get; set; }
}
}
16 changes: 16 additions & 0 deletions build/S3Validator/Options.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2020 New Relic, Inc. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

using CommandLine;

namespace S3Validator
{
public class Options
{
[Option('v', "version", Required = true, HelpText = "Version to validate.")]
public required string Version { get; set; }

[Option('c', "config", Default = "config.yml", Required = false, HelpText = "Path to the configuration file.")]
public required string ConfigurationPath { get; set; }
}
}
126 changes: 126 additions & 0 deletions build/S3Validator/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// Copyright 2020 New Relic, Inc. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

using CommandLine;

namespace S3Validator
{
internal class Program
{
private const string VersionToken = @"{version}";

private static readonly HttpClient _client = new();

static void Main(string[] args)
{
var result = Parser.Default.ParseArguments<Options>(args)
.WithParsed(ValidateOptions)
.WithNotParsed(HandleParseError);

var version = result.Value.Version;
var configuration = LoadConfiguration(result.Value.ConfigurationPath);
Validate(version, configuration);
Console.WriteLine("Valid.");
}

private static void Validate(string version, Configuration configuration)
{
var tasks = new List<Task<HttpResponseMessage>>();
foreach (var dir in configuration.DirectoryList!)
{
foreach (var fileDetail in configuration.FileList!)
{
var url = $"{configuration.BaseUrl}/{dir.Replace(VersionToken, version)}/{fileDetail.Name.Replace(VersionToken, version)}";
var request = new HttpRequestMessage(HttpMethod.Head, url);
request.Options.TryAdd("expectedSize", fileDetail.Size);
tasks.Add(_client.SendAsync(request));
}
}

if (!tasks.Any())
{
ExitWithError(ExitCode.Error, "There was nothing to validate.");
}

var taskCompleted = Task.WaitAll(tasks.ToArray(), 10000);
if (!taskCompleted)
{
ExitWithError(ExitCode.Error, "Validation timed out waiting for HttpClient requests to complete.");
}

var isValid = true;
var results = new List<string>();
foreach (var task in tasks)
{
var status = "Valid";

if (!task.Result.IsSuccessStatusCode)
{
isValid = false;
status = task.Result.StatusCode.ToString();
}
else if (task.Result.Content.Headers.ContentLength < task.Result.RequestMessage?.Options.GetValue<long>("expectedSize"))
{
isValid = false;
status = "FileSize";
}

results.Add($"{status,-12}{task.Result.RequestMessage?.RequestUri}");
}

if (!isValid)
{
ExitWithError(ExitCode.Error, "Validation failed. Results:" + Environment.NewLine + string.Join(Environment.NewLine, results));
}
}

private static void ValidateOptions(Options opts)
{
if (string.IsNullOrWhiteSpace(opts.Version)
|| string.IsNullOrWhiteSpace(opts.ConfigurationPath))
{
ExitWithError(ExitCode.BadArguments, "Arguments were empty or whitespace.");
}

if (!Version.TryParse(opts.Version, out _))
{
ExitWithError(ExitCode.Error, $"Version provided, '{opts.Version}', was not a valid version.");
}

if (!File.Exists(opts.ConfigurationPath))
{
ExitWithError(ExitCode.FileNotFound, $"Configuration file did not exist at {opts.ConfigurationPath}.");
}
}

private static Configuration LoadConfiguration(string path)
{
var input = File.ReadAllText(path);
var deserializer = new YamlDotNet.Serialization.Deserializer();
return deserializer.Deserialize<Configuration>(input);
}

private static void HandleParseError(IEnumerable<Error> errs)
{
ExitWithError(ExitCode.BadArguments, "Error occurred while parsing command line arguments.");
}

public static void ExitWithError(ExitCode exitCode, string message)
{
Console.WriteLine(message);
Environment.Exit((int)exitCode);
}
}

public static class Helpers
{

// Simplfy the TryGetValue into something more usable.
public static T? GetValue<T>(this HttpRequestOptions options, string key)
{
options.TryGetValue(new HttpRequestOptionsKey<T>(key), out var value);
return value;
}
}

}
26 changes: 26 additions & 0 deletions build/S3Validator/S3Validator.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<LangVersion>11.0</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<None Remove="config.yml" />
</ItemGroup>

<ItemGroup>
<Content Include="config.yml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>

<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.9.1" />
<PackageReference Include="YamlDotNet" Version="13.1.1" />
</ItemGroup>

</Project>
66 changes: 66 additions & 0 deletions build/S3Validator/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Copyright 2020 New Relic, Inc. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

# BaseUrl
# Should include the full path the to root of the agent folder - no trailing slash. Example: https://download.newrelic.com/dot_net_agent
base-url: https://download.newrelic.com/dot_net_agent

# DirectoryList
# A list of sub directories to check - no leading or trailing slash. The FileList will be checked in each directory.
# Use '{version}' in places where the version would be found. This will be replaced with the version supplied to the tool on execution.
# Example: 'previous_releases/10.13.0' becomes 'previous_releases/{version}'
directory-list:
- latest_release
- previous_releases/{version}

# FileList
# Use the relative path, starting at each directory in DirectoryList, to each file and a minimum acceptable size.
# Do not use the exact size - this file should not need to be update just to change sizes under normal circumstances.
# Use '{version}' in places where the version would be found. This will be replaced with the version supplied to the tool on execution.
# Example: 'NewRelicDotNetAgent_10.13.0_x64.msi' becomes 'NewRelicDotNetAgent_{version}_x64.msi'
file-list:
- name: NewRelicDotNetAgent_{version}_x64.msi
size: 13000000
- name: NewRelicDotNetAgent_{version}_x64.zip
size: 11500000
- name: NewRelicDotNetAgent_{version}_x86.msi
size: 12500000
- name: NewRelicDotNetAgent_{version}_x86.zip
size: 11500000
- name: NewRelicDotNetAgent_x64.msi
size: 13000000
- name: NewRelicDotNetAgent_x86.msi
size: 12500000
- name: Readme.txt
size: 1500
- name: newrelic-dotnet-agent-{version}-1.x86_64.rpm
size: 3000000
- name: newrelic-dotnet-agent_{version}_amd64.deb
size: 2500000
- name: newrelic-dotnet-agent_{version}_amd64.tar.gz
size: 3900000
- name: newrelic-dotnet-agent_{version}_arm64.deb
size: 2100000
- name: newrelic-dotnet-agent_{version}_arm64.tar.gz
size: 3700000
- name: SHA256/NewRelicDotNetAgent_{version}_x64.msi.sha256
size: 58
- name: SHA256/NewRelicDotNetAgent_{version}_x64.zip.sha256
size: 58
- name: SHA256/NewRelicDotNetAgent_{version}_x86.msi.sha256
size: 58
- name: SHA256/NewRelicDotNetAgent_{version}_x86.zip.sha256
size: 58
- name: SHA256/checksums.md
size: 800
- name: SHA256/newrelic-dotnet-agent-{version}-1.x86_64.rpm.sha256
size: 95
- name: SHA256/newrelic-dotnet-agent_{version}_amd64.deb.sha256
size: 95
- name: SHA256/newrelic-dotnet-agent_{version}_amd64.tar.gz.sha256
size: 95
- name: SHA256/newrelic-dotnet-agent_{version}_arm64.deb.sha256
size: 95
- name: SHA256/newrelic-dotnet-agent_{version}_arm64.tar.gz.sha256
size: 95

0 comments on commit db1e04a

Please sign in to comment.