Skip to content

Commit

Permalink
feat: move validate-tag to zx
Browse files Browse the repository at this point in the history
  • Loading branch information
guitarrapc committed Jan 8, 2025
1 parent 8f35a71 commit 826f8e2
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 43 deletions.
1 change: 0 additions & 1 deletion .github/workflows/update-packagejson.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ jobs:
id: update
run: |
file_path_csv=$(echo "${{ inputs.file-path }}" | tr '\n' ',' | sed 's/,$/\n/')
echo "file_path_csv: $file_path_csv"
dotnet run --project "./src/Actions/Actions.csproj" -- update-version --version "${{ needs.validate.outputs.normalized_tag }}" --paths "${file_path_csv}" ${{ inputs.dry-run && '--dry-run' || '' }}
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
Expand Down
43 changes: 7 additions & 36 deletions .github/workflows/validate-tag.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ on:
required: true
type: string
outputs:
normalized_tag:
normalized-tag:
description: normalized tag, tag without v prefix.
value: ${{ jobs.validate.outputs.normalized_tag }}
value: ${{ jobs.validate.outputs.normalized-tag }}
tag:
description: same as input tag
value: ${{ jobs.validate.outputs.tag }}
Expand Down Expand Up @@ -43,43 +43,14 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 5
outputs:
tag: ${{ steps.trim.outputs.tag }}
normalized_tag: ${{ steps.trim.outputs.normalized_tag }}
tag: ${{ steps.validate.outputs.tag }}
normalized-tag: ${{ steps.validate.outputs.normalized-tag }}
validated: ${{ steps.validate.outputs.validated }}
steps:
- name: Set version without "v" prefix
id: trim
run: |
input_tag="${{ inputs.tag }}"
if [[ "$input_tag" == v* ]]; then
normalized_tag="${input_tag:1}"
else
normalized_tag="$input_tag"
fi
echo "normalized_tag=$normalized_tag" | tee -a "$GITHUB_OUTPUT"
echo "tag=${{ inputs.tag }}" | tee -a "$GITHUB_OUTPUT"
# Only check released tag, allow override draft and pre-release. Old to new sort by version number.
- name: Validate tag is not reverting
shell: bash
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main
- name: Validate Tag
id: validate
run: |
release_latest=$(gh release list --exclude-drafts --exclude-pre-releases --json tagName,isLatest | jq -c -r ".[] | select(.isLatest == true) | .tagName")
sorted_latest=$(echo -e "${release_latest}\n${{ steps.trim.outputs.normalized_tag }}" | sort -V | tail -n 1)
if [[ "$release_latest" == "" ]]; then
echo "There is not release tag."
echo "validated=true" | tee -a "$GITHUB_OUTPUT"
elif [[ "$sorted_latest" == "$release_latest" ]]; then
echo "Tag is reverting to old version. Please bump the version. tag: ${{ inputs.tag }} (normalized_tag: ${{ steps.trim.outputs.normalized_tag }}), latest: $release_latest"
echo "validated=false" | tee -a "$GITHUB_OUTPUT"
if [[ "${{ inputs.require-validation }}" == "true" ]]; then
exit 1
fi
else
echo "Great, tag is latest. tag: ${{ inputs.tag }} (normalized_tag: ${{ steps.trim.outputs.normalized_tag }}), latest: $release_latest"
echo "validated=true" | tee -a "$GITHUB_OUTPUT"
fi
run: dotnet run --project "./src/Actions/Actions.csproj" -- validate-tag --tag "${{ inputs.tag }}" ${{ inputs.require-validation && '--require-validation' || '' }}
env:
GH_REPO: ${{ github.repository }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
34 changes: 34 additions & 0 deletions src/Actions.Tests/ValidateTagCommandTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Actions.Commands;
using FluentAssertions;

namespace Actions.Tests;

public class ValidateTagCommandTest
{
[Theory]
[InlineData("0.1.0", "0.1.0")]
[InlineData("v0.1.0", "0.1.0")]
[InlineData("v10.1.0", "10.1.0")]
public void NormalizeTest(string tag, string expected)
{
var command = new ValidateTagCommand();
var actual = command.Normalize(tag);

actual.Should().Be(expected);
}

[Theory]
[InlineData("0.1.0", false)]
[InlineData("1.0.0", false)]
[InlineData("1.1.0", false)]
[InlineData("1.2.0", true)] // Current Release Tag is 1.2.0
[InlineData("1.2.1", true)]
[InlineData("999.0.0", true)]
public async Task ValidateTest(string tag, bool expected)
{
var command = new ValidateTagCommand();
var (success, releaseTag) = await command.ValidateTagAsync(tag);

success.Should().Be(expected);
}
}
12 changes: 6 additions & 6 deletions src/Actions.Tests/VersioningCommandTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ public class VersioningCommandTest
[InlineData("0.1.0", VersionIncrement.Major, "1.1.0")]
[InlineData("0.1.0", VersionIncrement.Minor, "0.2.0")]
[InlineData("0.1.0", VersionIncrement.Patch, "0.1.1")]
public void VersionIncrementTest(string tag, VersionIncrement versionIncrement, string actual)
public void VersionIncrementTest(string tag, VersionIncrement versionIncrement, string expected)
{
var command = new VersioningCommand(tag, prefix: "", versionIncrement: versionIncrement, isPrelease: false, prerelease: "");
var versioning = command.Versioning();

versioning.Should().Be(actual);
versioning.Should().Be(expected);
}

[Theory]
Expand All @@ -24,23 +24,23 @@ public void VersionIncrementTest(string tag, VersionIncrement versionIncrement,
[InlineData("v0.1.0", "v", false, "v0.1.1")]
[InlineData("Ver0.1.0", "Ver", false, "Ver0.1.1")]
[InlineData("Ver.0.1.0", "Ver.", false, "Ver.0.1.1")]
public void VersionPrefixTest(string tag, string prefix, bool withoutPrefix, string actual)
public void VersionPrefixTest(string tag, string prefix, bool withoutPrefix, string expected)
{
var command = new VersioningCommand(tag, prefix: prefix, versionIncrement: VersionIncrement.Patch, isPrelease: false, prerelease: "");
var versioning = command.Versioning(withoutPrefix);

versioning.Should().Be(actual);
versioning.Should().Be(expected);
}

[Theory]
[InlineData("0.1.0", "", "0.1.1")]
[InlineData("0.1.0", "alpha", "0.1.1-alpha")]
[InlineData("0.1.0", "preview", "0.1.1-preview")]
public void VersionPrereleaseTest(string tag, string prerelease, string actual)
public void VersionPrereleaseTest(string tag, string prerelease, string expected)
{
var command = new VersioningCommand(tag, prefix: "", versionIncrement: VersionIncrement.Patch, isPrelease: true, prerelease: prerelease);
var versioning = command.Versioning();

versioning.Should().Be(actual);
versioning.Should().Be(expected);
}
}
52 changes: 52 additions & 0 deletions src/Actions/Commands/ValidateTagCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Actions.Commands;

public class ValidateTagCommand()
{
/// <summary>
/// Normalize input tag. If the tag starts with 'v', it will be removed.
/// </summary>
/// <param name="tag"></param>
/// <returns></returns>
public string Normalize(string tag) => tag.StartsWith("v") ? tag.Substring(1) : tag;

/// <summary>
/// Validate input tag. If the input tag is older than the latest release tag, it will return false. Otherwise, it will return true.
/// </summary>
/// <param name="tag"></param>
/// <returns></returns>
public async Task<(bool result, string releaseTag)> ValidateTagAsync(string tag)
{
// release_latest=$(gh release list --exclude-drafts --exclude-pre-releases --json tagName,isLatest | jq -c -r ".[] | select(.isLatest == true) | .tagName")
// sorted_latest=$(echo - e "${release_latest}\n${{ steps.trim.outputs.normalized_tag }}" | sort - V | tail - n 1)
var releaseLatests = await "gh release list --exclude-drafts --exclude-pre-releases --json tagName,isLatest";
var githubReleases = JsonSerializer.Deserialize<GitHubRelease[]>(releaseLatests);
var releaseTag = githubReleases?.SingleOrDefault(x => x.IsLatest)?.TagName;

if (releaseTag == null)
{
// no release tag
return (true, "");
}

var sortedLatest = new[] { releaseTag, tag }.OrderBy(x => x).Last();
if (sortedLatest == tag)
{
// input tag is same or newer than latest tag
return (true, releaseTag);
}

// input tag is older than latest tag, reverting!!
return (false, releaseTag);
}

private record GitHubRelease
{
[JsonPropertyName("tagName")]
public required string TagName { get; init; }
[JsonPropertyName("isLatest")]
public required bool IsLatest { get; init; }
}
}
54 changes: 54 additions & 0 deletions src/Actions/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,43 @@ public void Versioning(string tag, string prefix = "", VersionIncrement versionI
WriteLog(output);
}

/// <summary>
/// Validate Tag and remove v prefix if exists
/// </summary>
/// <param name="tag"></param>
/// <param name="requireValidation">Set true to exit 1 on fail. Set false to exit 0 even fail.</param>
/// <returns></returns>
[ConsoleAppFilter<GitHubCliFilter>]
[Command("validate-tag")]
public async Task<int> ValidateTag(string tag, bool requireValidation)
{
var command = new ValidateTagCommand();
var normalizedTag = command.Normalize(tag);
var (validated, releaseTag) = await command.ValidateTagAsync(normalizedTag);
if (!validated)
{
WriteLog($"Tag is reverting to old version. Please bump the version. tag: {tag}, normalizedTag: {normalizedTag}, releaseTag: {releaseTag}");

if (requireValidation)
{
return 1;
}
}

GitHubOutput("tag", tag);
GitHubOutput("normalized-tag", normalizedTag);
GitHubOutput("validated", validated.ToString().ToLower());

return 0;
}

/// <summary>
/// Update Version for specified path and commit
/// </summary>
/// <param name="version"></param>
/// <param name="paths"></param>
/// <param name="dryRun"></param>
[ConsoleAppFilter<GitHubContextFilter>]
[Command("update-version")]
public async Task<int> UpdateVersion(string version, string[] paths, bool dryRun)
{
Expand Down Expand Up @@ -245,6 +276,29 @@ private static void GitHubOutput(string key, string value, [CallerMemberName]str
}
}

internal class GitHubCliFilter(ConsoleAppFilter next) : ConsoleAppFilter(next)
{
public override async Task InvokeAsync(ConsoleAppContext context, CancellationToken cancellationToken)
{
// Ensure GH CLI can access on CI.
if (Environment.GetEnvironmentVariable("CI") is not null)
{
_ = Environment.GetEnvironmentVariable("GH_REPO") ?? throw new ActionCommandException("Environment Variable 'GH_REPO' is required");
_ = Environment.GetEnvironmentVariable("GH_TOKEN") ?? throw new ActionCommandException("Environment Variable 'GH_TOKEN' is required");
}
await Next.InvokeAsync(context, cancellationToken);
}
}

internal class GitHubContextFilter(ConsoleAppFilter next) : ConsoleAppFilter(next)
{
public override async Task InvokeAsync(ConsoleAppContext context, CancellationToken cancellationToken)
{
_ = Environment.GetEnvironmentVariable("GITHUB_CONTEXT") ?? throw new ArgumentNullException("Environment Variable 'GITHUB_CONTEXT' is required");
await Next.InvokeAsync(context, cancellationToken);
}
}

public class ActionCommandException(string message, Exception? innterException = null) : Exception(message, innterException);

internal static class ActionsBatchOptions
Expand Down
9 changes: 9 additions & 0 deletions src/Actions/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@
"commandName": "Project",
"commandLineArgs": "--help"
},
// validate-tag
"validate-tag (help)": {
"commandName": "Project",
"commandLineArgs": "validate-tag --help"
},
"validate-tag": {
"commandName": "Project",
"commandLineArgs": "validate-tag --tag \"1.3.0\" --require-validation"
},
// versioning
"versioning (help)": {
"commandName": "Project",
Expand Down

0 comments on commit 826f8e2

Please sign in to comment.