Skip to content

Commit

Permalink
Merge pull request #147 from The-Standard-Organization/users/mabroukm…
Browse files Browse the repository at this point in the history
…ahdhi/exposers-fluent-pipeline-builder

EXPOSERS: Fluent GitHub Pipeline Builder
  • Loading branch information
cjdutoit authored Jan 27, 2025
2 parents 55d51f8 + 3e04bab commit 5b39330
Show file tree
Hide file tree
Showing 7 changed files with 540 additions and 1 deletion.
4 changes: 4 additions & 0 deletions ADotNet/ADotNet.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,8 @@
</None>
</ItemGroup>

<ItemGroup>
<InternalsVisibleTo Include="ADotNet.Tests.Unit" />
</ItemGroup>

</Project>
2 changes: 1 addition & 1 deletion ADotNet/Clients/ADotNetClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

namespace ADotNet.Clients
{
public class ADotNetClient
public class ADotNetClient : IADotNetClient
{
private readonly IBuildService buildService;

Expand Down
108 changes: 108 additions & 0 deletions ADotNet/Clients/Builders/GitHubPipelineBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// ---------------------------------------------------------------------------
// Copyright (c) Hassan Habib & Shri Humrudha Jagathisun All rights reserved.
// Licensed under the MIT License.
// See License.txt in the project root for license information.
// ---------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using ADotNet.Models.Pipelines.GithubPipelines.DotNets;

namespace ADotNet.Clients.Builders
{
/// <summary>
/// Builder for creating a GitHub pipeline.
/// </summary>
public class GitHubPipelineBuilder
{
private readonly GithubPipeline githubPipeline;
private readonly IADotNetClient aDotNetClient;

internal GitHubPipelineBuilder(IADotNetClient aDotNetClient)
{
this.githubPipeline = new GithubPipeline
{
OnEvents = new Events(),
Jobs = new Dictionary<string, Job>()
};

this.aDotNetClient = aDotNetClient;
}

/// <summary>
/// Creates a new instance of the <see cref="GitHubPipelineBuilder"/> class
/// with a default <see cref="ADotNetClient"/>.
/// </summary>
/// <returns>A new instance of <see cref="GitHubPipelineBuilder"/>.</returns>
public static GitHubPipelineBuilder CreateNewPipeline()
{
var aDotNetClient = new ADotNetClient();

return new GitHubPipelineBuilder(aDotNetClient);
}

/// <summary>
/// Sets the name of the GitHub pipeline.
/// </summary>
/// <param name="name">The name of the pipeline.</param>
/// <returns>The current instance of <see cref="GitHubPipelineBuilder"/>.</returns>
public GitHubPipelineBuilder SetName(string name)
{
this.githubPipeline.Name = name;

return this;
}

/// <summary>
/// Configures the pipeline to trigger on push events for specified branches.
/// </summary>
/// <param name="branches">The branches to trigger on push events.</param>
/// <returns>The current instance of <see cref="GitHubPipelineBuilder"/>.</returns>
public GitHubPipelineBuilder OnPush(params string[] branches)
{
this.githubPipeline.OnEvents.Push = new PushEvent
{
Branches = branches
};

return this;
}

/// <summary>
/// Configures the pipeline to trigger on pull request events for specified branches.
/// </summary>
/// <param name="branches">The branches to trigger on pull request events.</param>
/// <returns>The current instance of <see cref="GitHubPipelineBuilder"/>.</returns>
public GitHubPipelineBuilder OnPullRequest(params string[] branches)
{
this.githubPipeline.OnEvents.PullRequest = new PullRequestEvent
{
Branches = branches
};

return this;
}

/// <summary>
/// Adds a job to the GitHub pipeline.
/// </summary>
/// <param name="jobIdentifier">The unique identifier for the job.</param>
/// <param name="configureJob">The action to configure the job.</param>
/// <returns>The current instance of <see cref="GitHubPipelineBuilder"/>.</returns>
public GitHubPipelineBuilder AddJob(string jobIdentifier, Action<JobBuilder> configureJob)
{
var jobBuilder = new JobBuilder();
configureJob(jobBuilder);
this.githubPipeline.Jobs[jobIdentifier] = jobBuilder.Build();

return this;
}

/// <summary>
/// Saves the configured pipeline (yml) to the specified file path.
/// </summary>
/// <param name="path">The file path where the pipeline will be saved.</param>
public void SaveToFile(string path) =>
this.aDotNetClient.SerializeAndWriteToFile(this.githubPipeline, path);
}
}
188 changes: 188 additions & 0 deletions ADotNet/Clients/Builders/JobBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
// ---------------------------------------------------------------------------
// Copyright (c) Hassan Habib & Shri Humrudha Jagathisun All rights reserved.
// Licensed under the MIT License.
// See License.txt in the project root for license information.
// ---------------------------------------------------------------------------

using System.Collections.Generic;
using ADotNet.Models.Pipelines.GithubPipelines.DotNets;
using ADotNet.Models.Pipelines.GithubPipelines.DotNets.Tasks;
using ADotNet.Models.Pipelines.GithubPipelines.DotNets.Tasks.SetupDotNetTaskV1s;

namespace ADotNet.Clients.Builders
{
/// <summary>
/// A builder to create a job for a GitHub Actions workflow.
/// </summary>
public class JobBuilder
{
private readonly Job job;

internal JobBuilder()
{
this.job = new Job
{
Steps = new List<GithubTask>(),
EnvironmentVariables = null
};
}

/// <summary>
/// Sets the name of the job.
/// </summary>
/// <param name="name">The name of the job.</param>
/// <returns>The current instance of <see cref="JobBuilder"/>.</returns>
public JobBuilder WithName(string name)
{
this.job.Name = name;

return this;
}

/// <summary>
/// Specifies the machine on which the job will run.
/// </summary>
/// <param name="machine">The machine or environment to run the job on.</param>
/// <returns>The current instance of <see cref="JobBuilder"/>.</returns>
public JobBuilder RunsOn(string machine)
{
this.job.RunsOn = machine;

return this;
}

/// <summary>
/// Adds an environment variable to the job.
/// </summary>
/// <param name="key">The key of the environment variable.</param>
/// <param name="value">The value of the environment variable.</param>
/// <returns>The current instance of <see cref="JobBuilder"/>.</returns>
public JobBuilder AddEnvironmentVariable(string key, string value)
{
this.job.EnvironmentVariables ??= new Dictionary<string, string>();

this.job.EnvironmentVariables[key] = value;

return this;
}

/// <summary>
/// Adds multiple environment variables to the job.
/// </summary>
/// <param name="variables">A dictionary of environment variables to add.</param>
/// <returns>The current instance of <see cref="JobBuilder"/>.</returns>
public JobBuilder AddEnvironmentVariables(Dictionary<string, string> variables)
{
this.job.EnvironmentVariables ??= new Dictionary<string, string>();

foreach (var variable in variables)
{
this.job.EnvironmentVariables[variable.Key] = variable.Value;
}

return this;
}

/// <summary>
/// Adds a checkout step to the job.
/// </summary>
/// <param name="name">The name of the checkout step (default: "Check out").</param>
/// <returns>The current instance of <see cref="JobBuilder"/>.</returns>
public JobBuilder AddCheckoutStep(string name = "Check out")
{
this.job.Steps.Add(new CheckoutTaskV2 { Name = name });

return this;
}

/// <summary>
/// Adds a setup step for a specific .NET version to the job.
/// </summary>
/// <param name="version">The version of .NET to set up.</param>
/// <param name="stepName">The name of the setup step (default: "Setup Dot Net Version").</param>
/// <param name="includePrerelease">Specifies whether to include prerelease versions.</param>
/// <returns>The current instance of <see cref="JobBuilder"/>.</returns>
public JobBuilder AddSetupDotNetStep(
string version,
string stepName = "Setup Dot Net Version",
bool includePrerelease = false)
{
this.job.Steps.Add(new SetupDotNetTaskV1
{
Name = stepName,
TargetDotNetVersion = new TargetDotNetVersion
{
DotNetVersion = version,
IncludePrerelease = includePrerelease
}
});

return this;
}

/// <summary>
/// Adds a restore step to the job.
/// </summary>
/// <param name="name">The name of the restore step (default: "Restore").</param>
/// <returns>The current instance of <see cref="JobBuilder"/>.</returns>
public JobBuilder AddRestoreStep(string name = "Restore")
{
this.job.Steps.Add(new RestoreTask { Name = name });

return this;
}

/// <summary>
/// Adds a build step to the job.
/// </summary>
/// <param name="name">The name of the build step (default: "Build").</param>
/// <returns>The current instance of <see cref="JobBuilder"/>.</returns>
public JobBuilder AddBuildStep(string name = "Build")
{
this.job.Steps.Add(new DotNetBuildTask { Name = name });

return this;
}

/// <summary>
/// Adds a test step to the job.
/// </summary>
/// <param name="name">The name of the test step (default: "Test").</param>
/// <param name="command">The command to execute the test
/// (default: "dotnet test --no-build --verbosity normal").</param>
/// <returns>The current instance of <see cref="JobBuilder"/>.</returns>
public JobBuilder AddTestStep(string name = "Test", string command = null)
{
this.job.Steps.Add(new TestTask
{
Name = name,
Run = command ?? "dotnet test --no-build --verbosity normal"
});

return this;
}

/// <summary>
/// Adds a generic step to the job with a custom command.
/// </summary>
/// <param name="name">The name of the step.</param>
/// <param name="runCommand">The command to execute for this step.</param>
/// <returns>The current instance of <see cref="JobBuilder"/>.</returns>
public JobBuilder AddGenericStep(string name, string runCommand)
{
this.job.Steps.Add(new GithubTask
{
Name = name,
Run = runCommand
});

return this;
}

/// <summary>
/// Builds and returns the configured job.
/// </summary>
/// <returns>The configured <see cref="Job"/> instance.</returns>
public Job Build() => this.job;
}
}
37 changes: 37 additions & 0 deletions AdoNet.Tests.Console/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

using System.Collections.Generic;
using ADotNet.Clients;
using ADotNet.Clients.Builders;
using ADotNet.Models.Pipelines.AdoPipelines.AspNets;
using ADotNet.Models.Pipelines.AdoPipelines.AspNets.Tasks.DotNetExecutionTasks;
using ADotNet.Models.Pipelines.AdoPipelines.AspNets.Tasks.PublishBuildArtifactTasks;
Expand Down Expand Up @@ -185,6 +186,42 @@ static void Main(string[] args)
};

adoClient.SerializeAndWriteToFile(githubPipeline, "github-pipelines.yaml");

string projectName = "OtripleS.Api.Infrastructure.Provision";

Check warning on line 190 in AdoNet.Tests.Console/Program.cs

View workflow job for this annotation

GitHub Actions / Build

The variable 'projectName' is assigned but its value is never used

Check warning on line 190 in AdoNet.Tests.Console/Program.cs

View workflow job for this annotation

GitHub Actions / Build

The variable 'projectName' is assigned but its value is never used

GitHubPipelineBuilder.CreateNewPipeline()
.SetName("Github")
.OnPush("master")
.OnPullRequest("master")

.AddJob("build", job => job
.WithName("Build")
.RunsOn(BuildMachines.WindowsLatest)
.AddEnvironmentVariable("AzureClientId", "${{ secrets.AZURECLIENTID }}")

.AddEnvironmentVariables(new Dictionary<string, string>
{
{ "AzureTenantId", "${{ secrets.AZURETENANTID }}" },
{ "AzureClientSecret", "${{ secrets.AZURECLIENTSECRET }}" },
{ "AzureAdminName", "${{ secrets.AZUREADMINNAME }}" },
{ "AzureAdminAccess", "${{ secrets.AZUREADMINACCESS }}" }
})

.AddCheckoutStep("Check Out")

.AddSetupDotNetStep(
version: "6.0.101",
includePrerelease: true)

.AddRestoreStep()
.AddBuildStep()

.AddGenericStep(
name: "Provision",
runCommand:
"dotnet run --project .\\{projectName}\\{projectName}.csproj"))

.SaveToFile("github-pipelines-fluent.yaml");
}
}
}
Loading

0 comments on commit 5b39330

Please sign in to comment.