Skip to content
Closed
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
56 changes: 56 additions & 0 deletions .github/workflows/CreateRelease.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: CreateRelease

on:
workflow_dispatch:

permissions: { }

jobs:

SetupBuildInfo:
runs-on: ubuntu-latest
outputs:
build-name: ${{ steps.SetupBuildInfo.outputs.build-name }}
build-id: ${{ steps.SetupBuildInfo.outputs.build-id }}
build-version: ${{ steps.SetupBuildInfo.outputs.build-version }}
build-timestamp: ${{ steps.SetupBuildInfo.outputs.build-timestamp }}
steps:

- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Setup .NET 10.0.x
uses: actions/setup-dotnet@v5
with:
dotnet-version: 10.0.x

- name: SetupBuildInfo
id: SetupBuildInfo
run: dotnet run --project _atom/_atom.csproj -- SetupBuildInfo --skip --headless

CreateGithubRelease:
permissions:
contents: write
needs: [ SetupBuildInfo ]
runs-on: ubuntu-latest
steps:

- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Setup .NET 10.0.x
uses: actions/setup-dotnet@v5
with:
dotnet-version: 10.0.x

- name: CreateGithubRelease
id: CreateGithubRelease
run: dotnet run --project _atom/_atom.csproj -- CreateGithubRelease --skip --headless
env:
build-version: ${{ needs.SetupBuildInfo.outputs.build-version }}
github-token: ${{ secrets.GITHUB_TOKEN }}

1 change: 1 addition & 0 deletions Invex.Atom.sln.DotSettings
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EUnitTestFramework_002EMigrations_002EEnableDisabledProvidersMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Commitish/@EntryIndexedValue">True</s:Boolean>
</wpf:ResourceDictionary>
20 changes: 20 additions & 0 deletions _atom/IBuild.cs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,26 @@ internal interface IBuild : IWorkflowBuildDefinition,
],
Types = [WorkflowTypes.Github.Action],
},
new("CreateRelease")
{
Triggers = [WorkflowTriggers.Manual],
Targets =
[
new(nameof(SetupBuildInfo)),
new(nameof(CreateGithubRelease))
{
Options =
[
BuildOptions.Inject.Secret(nameof(GithubToken)),
new GithubTokenPermissionsOption(new Permissions.Exact(new()
{
Contents = PermissionsLevel.Write,
})),
],
},
],
Types = [WorkflowTypes.Github.Action],
},

// Test devops
new("Test_Devops_Build")
Expand Down
10 changes: 10 additions & 0 deletions _atom/Targets/IDeployTargets.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,14 @@ await PushPackageToNuget(
foreach (var artifact in IBuildTargets.ProjectsToPack.Concat(ITestTargets.ProjectsToTest))
await UploadArtifactToRelease(artifact, $"v{BuildVersion}");
});

Target CreateGithubRelease =>
d => d
.DescribedAs("Creates a release on GitHub.")
.RequiresParam(nameof(GithubToken))
.ConsumesVariable(nameof(SetupBuildInfo), nameof(BuildVersion))
.Executes(async () => await CreateRelease(
$"v{BuildVersion.Major}.{BuildVersion.Minor}.{BuildVersion.Patch}",
"main",
$"v{BuildVersion.Major}.{BuildVersion.Minor}.{BuildVersion.Patch}"));
Comment thread
DecSmith42 marked this conversation as resolved.
}
17 changes: 17 additions & 0 deletions docs/modules/github-workflows.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,28 @@ if (Github.IsGithubActions)
}
```

### Release Helper

Implement `IGithubReleaseHelper` to create GitHub Releases and upload artifacts from your targets. `CreateRelease`
tags a commit (or the latest commit on a branch via `targetCommitish`) and creates the release for that tag:

```csharp
// Tag the latest commit on the 'main' branch and create a release for it.
await CreateRelease($"v{BuildVersion}", "main", name: $"v{BuildVersion}");

// Tag a specific commit SHA instead.
await CreateRelease("v1.2.3", "0a1b2c3d", body: "Release notes...", prerelease: true);
```

Use `UploadArtifactToRelease` / `UploadAssetToRelease` to attach assets to an existing release. When not running in
GitHub Actions these operations are simulated (logged only) by default.

### Variable Provider

`GithubVariableProvider` writes variables to `$GITHUB_OUTPUT` and reads them from job outputs, enabling cross-job data
sharing.


### Report Writer

`GithubSummaryOutcomeReportWriter` writes build report data to the GitHub Actions job summary (`$GITHUB_STEP_SUMMARY`).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,79 @@
[PublicAPI]
public interface IGithubReleaseHelper : IGithubHelper
{
/// <summary>
/// Creates a GitHub Release for a new tag, tagging a specific commit or the latest commit on a branch.
/// </summary>
/// <param name="tagName">
/// The name of the tag to create for the release (e.g. "v1.0.0"). The tag is created if it does not
/// already exist.
/// </param>
/// <param name="targetCommitish">
/// Specifies the commitish value that determines where the Git tag is created from. This can be a branch name
/// (in which case the tag is created from the latest commit on that branch) or a commit SHA (in which case the
/// tag is created from that specific commit). If <c>null</c> or empty, the repository's default branch is used.
/// </param>
/// <param name="name">
/// The display name of the release. If <c>null</c>, the <paramref name="tagName" /> is used as the
/// release name.
/// </param>
/// <param name="body">The description/body text of the release. May be <c>null</c> for an empty body.</param>
/// <param name="draft">If <c>true</c>, the release is created as an unpublished draft. Defaults to <c>false</c>.</param>
/// <param name="prerelease">If <c>true</c>, the release is flagged as a pre-release. Defaults to <c>false</c>.</param>
/// <param name="dryRunWhenNotRunningInGithubActions">
/// If <c>true</c> (default), the create operation will be simulated (logged but not executed)
/// when the build is not running in a GitHub Actions environment.
/// </param>
/// <returns>
/// A <see cref="Task" /> that resolves to the created <see cref="Release" />, or <c>null</c> when the operation
/// was simulated because the build is not running in GitHub Actions.
/// </returns>
/// <exception cref="InvalidOperationException">Thrown if the GitHub repository ID cannot be parsed.</exception>
/// <remarks>
/// GitHub automatically creates the Git tag <paramref name="tagName" /> from <paramref name="targetCommitish" />
/// as part of creating the release.
/// </remarks>
[PublicAPI]
async Task<Release?> CreateRelease(
string tagName,
string? targetCommitish = null,
string? name = null,
string? body = null,
bool draft = false,
bool prerelease = false,
bool dryRunWhenNotRunningInGithubActions = true)
{
if (!Github.IsGithubActions && dryRunWhenNotRunningInGithubActions)
{
Logger.LogWarning(
"Not running in GitHub Actions, simulating creation of release {TagName} targeting {TargetCommitish}.",
tagName,
string.IsNullOrEmpty(targetCommitish)
? "<default branch>"
: targetCommitish);

return null;
}

var client = new GitHubClient(new("Invex.Atom"), new InMemoryCredentialStore(new(GithubToken)));

var newRelease = new NewRelease(tagName)
{
Name = name ?? tagName,
Body = body,
Draft = draft,
Prerelease = prerelease,
};

if (!string.IsNullOrEmpty(targetCommitish))
newRelease.TargetCommitish = targetCommitish;

if (!long.TryParse(Github.Variables.RepositoryId, out var repositoryId))
throw new InvalidOperationException(
$"Unable to parse GitHub repository id from '{Github.VariableNames.RepositoryId}' (value: '{Github.Variables.RepositoryId}').");

return await client.Repository.Release.Create(repositoryId, newRelease);

/// <summary>
/// Uploads a build artifact to a specified GitHub Release.
/// </summary>
Expand Down Expand Up @@ -120,4 +193,4 @@
var asset = new ReleaseAssetUpload(assetPath.FileName, "application/zip", stream, TimeSpan.FromMinutes(5));
await client.Repository.Release.UploadAsset(release, asset);
}
}

Check failure on line 196 in src/Invex.Atom.Module.GithubWorkflows/Helpers/IGithubReleaseHelper.cs

View workflow job for this annotation

GitHub Actions / PackTool (macos-latest)

} expected

Check failure on line 196 in src/Invex.Atom.Module.GithubWorkflows/Helpers/IGithubReleaseHelper.cs

View workflow job for this annotation

GitHub Actions / TestProjects (macos-latest, net9.0)

} expected

Check failure on line 196 in src/Invex.Atom.Module.GithubWorkflows/Helpers/IGithubReleaseHelper.cs

View workflow job for this annotation

GitHub Actions / TestProjects (ubuntu-latest, net10.0)

} expected

Check failure on line 196 in src/Invex.Atom.Module.GithubWorkflows/Helpers/IGithubReleaseHelper.cs

View workflow job for this annotation

GitHub Actions / BuildDocs

} expected

Check failure on line 196 in src/Invex.Atom.Module.GithubWorkflows/Helpers/IGithubReleaseHelper.cs

View workflow job for this annotation

GitHub Actions / WaitForCopilotReview

} expected

Check failure on line 196 in src/Invex.Atom.Module.GithubWorkflows/Helpers/IGithubReleaseHelper.cs

View workflow job for this annotation

GitHub Actions / PackTool (ubuntu-latest)

} expected

Check failure on line 196 in src/Invex.Atom.Module.GithubWorkflows/Helpers/IGithubReleaseHelper.cs

View workflow job for this annotation

GitHub Actions / TestProjects (ubuntu-latest, net9.0)

} expected

Check failure on line 196 in src/Invex.Atom.Module.GithubWorkflows/Helpers/IGithubReleaseHelper.cs

View workflow job for this annotation

GitHub Actions / TestProjects (ubuntu-24.04-arm, net9.0)

} expected

Check failure on line 196 in src/Invex.Atom.Module.GithubWorkflows/Helpers/IGithubReleaseHelper.cs

View workflow job for this annotation

GitHub Actions / PackTool (ubuntu-24.04-arm)

} expected

Check failure on line 196 in src/Invex.Atom.Module.GithubWorkflows/Helpers/IGithubReleaseHelper.cs

View workflow job for this annotation

GitHub Actions / TestProjects (macos-latest, net10.0)

} expected

Check failure on line 196 in src/Invex.Atom.Module.GithubWorkflows/Helpers/IGithubReleaseHelper.cs

View workflow job for this annotation

GitHub Actions / TestProjects (ubuntu-24.04-arm, net8.0)

} expected

Check failure on line 196 in src/Invex.Atom.Module.GithubWorkflows/Helpers/IGithubReleaseHelper.cs

View workflow job for this annotation

GitHub Actions / TestProjects (macos-latest, net8.0)

} expected

Check failure on line 196 in src/Invex.Atom.Module.GithubWorkflows/Helpers/IGithubReleaseHelper.cs

View workflow job for this annotation

GitHub Actions / TestProjects (ubuntu-24.04-arm, net10.0)

} expected

Check failure on line 196 in src/Invex.Atom.Module.GithubWorkflows/Helpers/IGithubReleaseHelper.cs

View workflow job for this annotation

GitHub Actions / SetupBuildInfo

} expected

Check failure on line 196 in src/Invex.Atom.Module.GithubWorkflows/Helpers/IGithubReleaseHelper.cs

View workflow job for this annotation

GitHub Actions / PackProjects

} expected
Loading