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

Add Azure.Sdk.Tools.NotificationConfiguration.Tests + improve NotificationConfiguration.Program.Main #5247

Merged
merged 4 commits into from
Jan 27, 2023
Merged
Show file tree
Hide file tree
Changes from 3 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
24 changes: 24 additions & 0 deletions tools/notification-configuration/notification-configuration.sln
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,18 @@ VisualStudioVersion = 17.5.33103.201
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Sdk.Tools.NotificationConfiguration", "notification-creator\Azure.Sdk.Tools.NotificationConfiguration.csproj", "{5759063D-A7B3-4D36-ACF4-5595C2789D27}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Sdk.Tools.NotificationConfiguration.Tests", "notification-creator.Tests\Azure.Sdk.Tools.NotificationConfiguration.Tests.csproj", "{3097CBB4-ED3C-4273-AC67-F5D189CB94BA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Sdk.Tools.CodeOwnersParser", "..\code-owners-parser\CodeOwnersParser\Azure.Sdk.Tools.CodeOwnersParser.csproj", "{A9826C8B-85DF-48DB-8A05-40FB04833C42}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Sdk.Tools.CodeOwnersParser.Tests", "..\code-owners-parser\Azure.Sdk.Tools.CodeOwnersParser.Tests\Azure.Sdk.Tools.CodeOwnersParser.Tests.csproj", "{2146E1FF-04D1-4B19-9767-C011A73CB40D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "identity-resolution", "..\identity-resolution\identity-resolution.csproj", "{9805B503-5469-412C-9A0C-F09F504F0ED8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Sdk.Tools.RetrieveCodeOwners", "..\code-owners-parser\Azure.Sdk.Tools.RetrieveCodeOwners\Azure.Sdk.Tools.RetrieveCodeOwners.csproj", "{3E5237F2-6536-4329-A9CF-92E42B040612}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Sdk.Tools.RetrieveCodeOwners.Tests", "..\code-owners-parser\Azure.Sdk.Tools.RetrieveCodeOwners.Tests\Azure.Sdk.Tools.RetrieveCodeOwners.Tests.csproj", "{8DAEC12F-8390-4122-9959-9CF3391F18CC}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{EBC153AF-0244-4DFB-8084-E6C0ACAA5CF3}"
ProjectSection(SolutionItems) = preProject
ci.yml = ci.yml
Expand All @@ -33,6 +41,22 @@ Global
{9805B503-5469-412C-9A0C-F09F504F0ED8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9805B503-5469-412C-9A0C-F09F504F0ED8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9805B503-5469-412C-9A0C-F09F504F0ED8}.Release|Any CPU.Build.0 = Release|Any CPU
{8DAEC12F-8390-4122-9959-9CF3391F18CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8DAEC12F-8390-4122-9959-9CF3391F18CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8DAEC12F-8390-4122-9959-9CF3391F18CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8DAEC12F-8390-4122-9959-9CF3391F18CC}.Release|Any CPU.Build.0 = Release|Any CPU
{2146E1FF-04D1-4B19-9767-C011A73CB40D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2146E1FF-04D1-4B19-9767-C011A73CB40D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2146E1FF-04D1-4B19-9767-C011A73CB40D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2146E1FF-04D1-4B19-9767-C011A73CB40D}.Release|Any CPU.Build.0 = Release|Any CPU
{3E5237F2-6536-4329-A9CF-92E42B040612}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3E5237F2-6536-4329-A9CF-92E42B040612}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3E5237F2-6536-4329-A9CF-92E42B040612}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3E5237F2-6536-4329-A9CF-92E42B040612}.Release|Any CPU.Build.0 = Release|Any CPU
{3097CBB4-ED3C-4273-AC67-F5D189CB94BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3097CBB4-ED3C-4273-AC67-F5D189CB94BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3097CBB4-ED3C-4273-AC67-F5D189CB94BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3097CBB4-ED3C-4273-AC67-F5D189CB94BA}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageReference Include="NUnit.Analyzers" Version="3.3.0" />
<PackageReference Include="coverlet.collector" Version="3.1.2" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\notification-creator\Azure.Sdk.Tools.NotificationConfiguration.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System;
using NUnit.Framework;

namespace Azure.Sdk.Tools.NotificationConfiguration.Tests;

[TestFixture]
public class ProgramTests
{
[Test]
public void ThrowsVssUnauthorizedException()
{
Environment.SetEnvironmentVariable("aadAppIdVar", "aadAppIdVarValue");
Environment.SetEnvironmentVariable("aadAppSecretVar", "aadAppSecretVarValue");
Environment.SetEnvironmentVariable("aadTenantVar", "aadTenantVarValue");
Assert.ThrowsAsync<Microsoft.VisualStudio.Services.Common.VssUnauthorizedException>(
async () =>
// Act
await Program.Main(
organization: "fooOrg",
project: "barProj",
pathPrefix: "qux",
tokenVariableName: "token",
aadAppIdVar: "aadAppIdVar",
aadAppSecretVar: "aadAppSecretVar",
aadTenantVar: "aadTenantVar",
selectionStrategy: PipelineSelectionStrategy.Scheduled,
dryRun: true)
);
}
}
155 changes: 102 additions & 53 deletions tools/notification-configuration/notification-creator/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,64 +7,113 @@
using Azure.Sdk.Tools.NotificationConfiguration.Helpers;
using Azure.Identity;

namespace Azure.Sdk.Tools.NotificationConfiguration
namespace Azure.Sdk.Tools.NotificationConfiguration;

/// <summary>
/// A tool for creating and configuring Azure DevOps groups for sending email notifications
/// on build failures to owners of relevant build definitions. The recipients are determined
/// based on the build definition .yml file paths as given by the CODEOWNERS of given build definition
/// source repository.
/// </summary>
public static class Program
{
class Program
/// <summary>
/// Create notification groups for failures in scheduled builds
/// </summary>
/// <param name="organization">Azure DevOps Organization</param>
/// <param name="project">Name of the DevOps project</param>
/// <param name="pathPrefix">Path prefix to include pipelines (e.g. "\net")</param>
/// <param name="tokenVariableName">Environment variable token name (e.g. "SYSTEM_ACCESSTOKEN")</param>
/// <param name="aadAppIdVar">AAD App ID environment variable name (OpensourceAPI access)</param>
/// <param name="aadAppSecretVar">AAD App Secret environment variable name (OpensourceAPI access)</param>
/// <param name="aadTenantVar">AAD Tenant environment variable name (OpensourceAPI access)</param>
/// <param name="selectionStrategy">Pipeline selection strategy</param>
/// <param name="dryRun">Prints changes but does not alter any objects</param>
/// <returns></returns>
public static async Task Main(
string organization,
string project,
string pathPrefix,
string tokenVariableName,
string aadAppIdVar,
string aadAppSecretVar,
string aadTenantVar,
PipelineSelectionStrategy selectionStrategy = PipelineSelectionStrategy.Scheduled,
bool dryRun = false)
{
/// <summary>
/// Create notification groups for failures in scheduled builds
/// </summary>
/// <param name="organization">Azure DevOps Organization</param>
/// <param name="project">Name of the DevOps project</param>
/// <param name="pathPrefix">Path prefix to include pipelines (e.g. "\net")</param>
/// <param name="tokenVariableName">Environment variable token name (e.g. "SYSTEM_ACCESSTOKEN")</param>
/// <param name="aadAppIdVar">AAD App ID environment variable name (OpensourceAPI access)</param>
/// <param name="aadAppSecretVar">AAD App Secret environment variable name (OpensourceAPI access)</param>
/// <param name="aadTenantVar">AAD Tenant environment variable name (OpensourceAPI access)</param>
/// <param name="selectionStrategy">Pipeline selection strategy</param>
/// <param name="dryRun">Prints changes but does not alter any objects</param>
/// <returns></returns>
static async Task Main(
string organization,
string project,
string pathPrefix,
string tokenVariableName,
string aadAppIdVar,
string aadAppSecretVar,
string aadTenantVar,
PipelineSelectionStrategy selectionStrategy = PipelineSelectionStrategy.Scheduled,
bool dryRun = false)
var loggerFactory = LoggerFactory.Create(builder =>
{
var devOpsToken = Environment.GetEnvironmentVariable(tokenVariableName);
var devOpsCreds = new VssBasicCredential("nobody", devOpsToken);
var devOpsConnection = new VssConnection(new Uri($"https://dev.azure.com/{organization}/"), devOpsCreds);
builder.AddSimpleConsole(config => { config.IncludeScopes = true; });
});
var logger = loggerFactory.CreateLogger(nameof(Program));
logger.LogInformation(
"Executing Main with following arguments: "
konrad-jamrozik marked this conversation as resolved.
Show resolved Hide resolved
+ "organization: '{organization}' "
+ "project: '{project}' "
+ "pathPrefix: '{pathPrefix}' "
+ "tokenVariableName: '{tokenVariableName}' "
+ "aadAppIdVar: '{aadAppIdVar}' "
+ "aadAppSecretVar: '{aadAppSecretVar}' "
+ "aadTenantVar: '{aadTenantVar}' "
+ "selectionStrategy: '{selectionStrategy}' "
+ "dryRun: '{dryRun}' "
, organization
, project
, pathPrefix
, tokenVariableName
, aadAppIdVar
, aadAppSecretVar
, aadTenantVar
, selectionStrategy
, dryRun);

var notificationConfigurator = new NotificationConfigurator(
AzureDevOpsService(organization, tokenVariableName, loggerFactory),
GitHubService(loggerFactory),
loggerFactory.CreateLogger<NotificationConfigurator>());

await notificationConfigurator.ConfigureNotifications(
project,
pathPrefix,
GitHubToAADConverter(aadTenantVar, aadAppIdVar, aadAppSecretVar, loggerFactory),
persistChanges: !dryRun,
strategy: selectionStrategy);
}

var loggerFactory = LoggerFactory.Create(builder =>
{
builder.AddSimpleConsole(config => { config.IncludeScopes = true; });
});
var devOpsServiceLogger = loggerFactory.CreateLogger<AzureDevOpsService>();
var notificationConfiguratorLogger = loggerFactory.CreateLogger<NotificationConfigurator>();
private static AzureDevOpsService AzureDevOpsService(
string organization,
string tokenVariableName,
ILoggerFactory loggerFactory)
{
var devOpsToken = Environment.GetEnvironmentVariable(tokenVariableName);
var devOpsCreds = new VssBasicCredential("nobody", devOpsToken);
var devOpsConnection = new VssConnection(
new Uri($"https://dev.azure.com/{organization}/"),
devOpsCreds);
var devOpsService = new AzureDevOpsService(
devOpsConnection,
loggerFactory.CreateLogger<AzureDevOpsService>());
return devOpsService;
}

var devOpsService = new AzureDevOpsService(devOpsConnection, devOpsServiceLogger);
var gitHubService = new GitHubService(loggerFactory.CreateLogger<GitHubService>());
var credential = new ClientSecretCredential(
Environment.GetEnvironmentVariable(aadTenantVar),
Environment.GetEnvironmentVariable(aadAppIdVar),
Environment.GetEnvironmentVariable(aadAppSecretVar));
var githubToAadResolver = new GitHubToAADConverter(
credential,
loggerFactory.CreateLogger<GitHubToAADConverter>()
);
var configurator = new NotificationConfigurator(devOpsService,
gitHubService, notificationConfiguratorLogger);
await configurator.ConfigureNotifications(
project,
pathPrefix,
githubToAadResolver,
persistChanges: !dryRun,
strategy: selectionStrategy);
private static GitHubService GitHubService(ILoggerFactory loggerFactory)
=> new GitHubService(loggerFactory.CreateLogger<GitHubService>());

private static GitHubToAADConverter GitHubToAADConverter(
string aadTenantVar,
string aadAppIdVar,
string aadAppSecretVar,
ILoggerFactory loggerFactory)
{
var credential = new ClientSecretCredential(
Environment.GetEnvironmentVariable(aadTenantVar),
Environment.GetEnvironmentVariable(aadAppIdVar),
Environment.GetEnvironmentVariable(aadAppSecretVar));

}
var githubToAadResolver = new GitHubToAADConverter(
credential,
loggerFactory.CreateLogger<GitHubToAADConverter>()
);
return githubToAadResolver;
}
}