Skip to content

Commit

Permalink
Merge pull request #325 from Lombiq/issue/OSOE-735
Browse files Browse the repository at this point in the history
OSOE-735: Introduce versioning and releases
  • Loading branch information
BenedekFarkas authored Mar 21, 2024
2 parents fab0182 + a4eaf75 commit 0f3e011
Show file tree
Hide file tree
Showing 7 changed files with 303 additions and 3 deletions.
4 changes: 1 addition & 3 deletions .github/actions/publish-nuget/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -212,10 +212,8 @@ runs:
path: artifacts
retention-days: ${{ inputs.nuget-artifact-retention-days }}

# This is not in its own action because it's all very specific to this NuGet publishing.
- name: Create Release
# v1.11.2
uses: ncipollo/release-action@18eadf9c9b0f226f47f164f5373c6a44f0aae169
uses: Lombiq/GitHub-Actions/.github/actions/release-action@dev

Check notice on line 216 in .github/actions/publish-nuget/action.yml

View workflow job for this annotation

GitHub Actions / Tag Version Automation / Set GitHub Action/Workflow to Version Tag

GHA Ref pinned to 'v1.0'

GHA Ref changed to 'v1.0'
# This is to prevent creating releases when pushing tags for issue-specific pre-releases like
# v4.3.1-alpha.osoe-86.
if: "!contains(steps.setup.outputs.publish-version, '-')"
Expand Down
51 changes: 51 additions & 0 deletions .github/actions/release-action/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Create Release
description: >
Runs ncipollo/release-action. Exists only to centralize which version of the action we use. Intentionally not
documented in Actions.md since it's only meant for internal use.
# Copied from https://github.com/ncipollo/release-action/blob/v1.11.2/action.yml. Formatted to wrap long
# descriptions. Removed inputs not used by Lombiq GitHub-Actions.
inputs:
allowUpdates:
description: >
An optional flag which indicates if we should update a release if it already exists. Defaults to false.
required: false
default: ''
artifacts:
description: >
An optional set of paths representing artifacts to upload to the release. This may be a single path or a comma
delimited list of paths (or globs).
required: false
default: ''
generateReleaseNotes:
description: 'Indicates if release notes should be automatically generated.'
required: false
default: 'false'
tag:
description: 'An optional tag for the release. If this is omitted the git ref will be used (if it is a tag).'
required: false
default: ''

outputs:
id:
description: 'The identifier of the created release.'
value: ${{ steps.create-release.outputs.id }}
html_url:
description: 'The HTML URL of the release.'
value: ${{ steps.create-release.outputs.html_url }}
upload_url:
description: 'The URL for uploading assets to the release.'
value: ${{ steps.create-release.outputs.upload_url }}

runs:
using: 'composite'
steps:
- name: Create Release
id: create-release
# v1.11.2
uses: ncipollo/release-action@18eadf9c9b0f226f47f164f5373c6a44f0aae169
with:
allowUpdates: ${{ inputs.allowUpdates }}
artifacts: ${{ inputs.artifacts }}
generateReleaseNotes: ${{ inputs.generateReleaseNotes }}
tag: ${{ inputs.tag }}
46 changes: 46 additions & 0 deletions .github/actions/set-gha-refs/Set-Called-GHA-Refs.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
param(
[String[]] $CalledRepoBaseIncludeList,
[String[]] $AdditionalPatternIncludeList,
[String[]] $PathIncludeList,
[String[]] $FileIncludeList,
[String] $ExpectedRef
)

if ($CalledRepoBaseIncludeList.Count -eq 0)
{
Write-Output '::warning file=Check-Called-GHA-refs.ps1,line10::CalledRepoBaseIncludeList is empty which is unexpected. If this was intentional, you can ignore this warning.'
}
else
{
$CalledRepoBaseIncludeList = $CalledRepoBaseIncludeList.ForEach({ 'uses:\s*' + $PSItem + '.*@(?<ref>[\w\./-]*)' })

$matchedRefs = Get-ChildItem -Path $PathIncludeList -Include $FileIncludeList -Force -Recurse |
Select-String -Pattern $CalledRepoBaseIncludeList

$additionalRefs = Get-ChildItem -Path $PathIncludeList -Include $FileIncludeList -Force -Recurse |
Select-String -Pattern $AdditionalPatternIncludeList

$matchedRefs = $matchedRefs + $additionalRefs

if ($matchedRefs.Count -gt 0)
{
foreach ($matched in $matchedRefs)
{
$oldline = $matched.Line
$newline = $matched.Line -Replace $matched.Matches[0].Groups['ref'].Value, "$ExpectedRef"

if ($oldine -ne $newline)
{
Write-Output "$oldline => $newline"

$filename = $matched.RelativePath($pwd)
$linenumber = $matched.LineNumber
$title = "GHA Ref pinned to '$ExpectedRef'"

(Get-Content $filename).Replace($oldline, $newline) | Set-Content $filename

Write-Output "::notice file=$filename,line=$linenumber,title=$title::GHA Ref changed to '$ExpectedRef'"
}
}
}
}
55 changes: 55 additions & 0 deletions .github/actions/set-gha-refs/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Set GitHub Actions References
description: >
Explicitly sets all called GitHub Action and Workflow references to an expected version.
inputs:
path-include-list:
required: false
default: '@(".github")'
description: >
PowerShell string array of paths, relative to the repository root, to search for GHA files, e.g. '@(".github")' or
'@(".github/actions", ".github/workflows")'. The parameter must be a PowerShell string array.
file-include-list:
required: false
default: '@("*.yml","*.yaml")'
description: >
PowerShell string array of file name patterns to include when evaluating GHA files, e.g. '@("*.yml")' or
'@("*.yml", "*.yaml")'. The parameter must be a PowerShell string array.
called-repo-base-include-list:
required: false
default: '@("${{ github.repository }}")'
description: >
PowerShell string array of repository base URLs to include when evaluating called GHA Workflows and Actions, e.g
'@("Lombiq/GitHub-Actions")' or '@("Lombiq/GitHub-Actions", "Lombiq/Open-Source-Orchard-Core-Extensions")'. The
parameter must be a PowerShell string array.
additional-pattern-include-list:
required: false
default: '@()'
description: >
PowerShell string array of additional RegEx patterns to include when searching for branch references that need to
be updated, e.g. 'https://raw.githubusercontent.com/Lombiq/GitHub-Actions/(?<ref>[\w\./-]*)/.github/'.
The pattern MUST include a regex named capture group (?<ref>[\w\./-]*) so the captured ref can be
updated correctly. The parameter must be a PowerShell string array.
expected-ref:
required: true
description: The expected reference value to set for all called GHA Workflows and Actions.

runs:
using: 'composite'
steps:
- name: Setup
shell: pwsh
run: |
"${{ github.action_path }}" >> $Env:GITHUB_PATH
- name: Set References
shell: pwsh
run: |
$params = @{
PathIncludeList = ${{ inputs.path-include-list }}
FileIncludeList = ${{ inputs.file-include-list }}
CalledRepoBaseIncludeList = ${{ inputs.called-repo-base-include-list }}
AdditionalPatternIncludeList = ${{ inputs.additional-pattern-include-list }}
ExpectedRef = "${{ inputs.expected-ref }}"
}
Set-Called-GHA-Refs @params
16 changes: 16 additions & 0 deletions .github/workflows/tag-version-this-repo.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: Tag Version (this repo)

on:
push:
branches:
- release/**

jobs:
run:
name: Tag Version Automation
if: github.event.pusher.name != 'LombiqBot'
uses: Lombiq/GitHub-Actions/.github/workflows/tag-version.yml@dev
with:
additional-pattern-include-list: '@("https://raw.githubusercontent.com/Lombiq/GitHub-Actions/(?<ref>[\w\./-]*)/.github")'
secrets:
TAG_VERSION_TOKEN: ${{ secrets.LOMBIQBOT_GITHUB_PERSONAL_ACCESS_TOKEN }}
112 changes: 112 additions & 0 deletions .github/workflows/tag-version.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
name: Tag Version

on:
workflow_call:
secrets:
# We can't access org secrets here so they need to be passed in.
TAG_VERSION_TOKEN:
required: false
description: >
An authentication token, like a personal access token (PAT), that provides 'Workflow' permission with write
access to the workflow files of the repository and can be used to modify GitHub actions and workflows. This is
necessary because when a pull request is merged while being authenticated with the default GITHUB_TOKEN of a
workflow run, then the merge won't trigger other workflows (like a build workflow on the target branch). This
is an intentional limitation, see:
https://docs.github.com/en/actions/using-workflows/triggering-a-workflow#triggering-a-workflow-from-a-workflow.
Thus, we need to use an alternative authentication token. See
https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token
for info on how to create PATs; you'll need one with the "work" scope. We recommend creating such a token from
under a bot user account only used for such operations, so it's not tied to a natural person.
inputs:
path-include-list:
description: >
PowerShell string array of paths, relative to the repository root, to search for GHA files, e.g.
'@(".github")' or '@(".github/actions", ".github/workflows")'. The parameter must be a PowerShell string
array.
required: false
default: '@(".github")'
type: string
file-include-list:
required: false
default: '@("*.yml","*.yaml")'
description: >
PowerShell string array of file name patterns to include when evaluating GHA files, e.g. '@("*.yml")' or
'@("*.yml", "*.yaml")'. The parameter must be a PowerShell string array.
type: string
called-repo-base-include-list:
required: false
default: '@("${{ github.repository }}")'
description: >
PowerShell string array of repository base URLs to include when evaluating called GHA Workflows and Actions,
e.g '@("Lombiq/GitHub-Actions")' or '@("Lombiq/GitHub-Actions",
"Lombiq/Open-Source-Orchard-Core-Extensions")'. The parameter must be a PowerShell string array.
type: string
additional-pattern-include-list:
required: false
default: '@()'
description: >
PowerShell string array of additional RegEx patterns to include when searching for branch references that need
to be updated, e.g.
'https://raw.githubusercontent.com/Lombiq/GitHub-Actions/(?<ref>[\w\./-]*)/.github/'. The pattern
MUST include a regex named capture group (?<ref>[\w\./-]*) so the captured ref can be updated
correctly. The parameter must be a PowerShell string array.
type: string
expected-ref:
required: false
default: '${{ github.ref_name }}'
description: The expected reference value to set for all called GHA Workflows and Actions.
type: string

jobs:
run:
name: Set GitHub Action/Workflow to Version Tag
runs-on: ubuntu-latest
defaults:
run:
shell: pwsh
steps:

- name: Checkout Repository
uses: Lombiq/GitHub-Actions/.github/actions/checkout@dev
with:
token: ${{ secrets.TAG_VERSION_TOKEN }}

- name: Setup Scripts
run: |
(Resolve-Path "Scripts").Path >> $Env:GITHUB_PATH
- name: Determine Version Tag Name from Branch Name
id: determine-tag
run: |
$tagname = "${{ inputs.expected-ref }}" -replace 'release/', ''
Set-GitHubOutput -Key 'tagname' -Value $tagname
- name: Set Ref for GitHub Actions and Workflows
uses: Lombiq/GitHub-Actions/.github/actions/set-gha-refs@dev
with:
path-include-list: ${{ inputs.path-include-list }}
file-include-list: ${{ inputs.file-include-list }}
called-repo-base-include-list: ${{ inputs.called-repo-base-include-list }}
additional-pattern-include-list: ${{ inputs.additional-pattern-include-list }}
expected-ref: '${{ steps.determine-tag.outputs.tagname }}'

- name: Commit and Push Changes
uses: stefanzweifel/git-auto-commit-action@8756aa072ef5b4a080af5dc8fef36c5d586e521d # v5
with:
commit_message: 'Set GitHub Actions/Workflows to tag ${{ steps.determine-tag.outputs.tagname }}'
tagging_message: ${{ steps.determine-tag.outputs.tagname }}

- name: Force Push Tag
continue-on-error: true
run: git push --tags --force

- name: Create Release
uses: Lombiq/GitHub-Actions/.github/actions/release-action@dev
# This is to prevent creating releases when pushing tags for issue-specific pre-releases like
# v4.3.1-alpha.osoe-86.
if: "!contains(steps.determine-tag.outputs.tagname, '-')"
with:
allowUpdates: true
generateReleaseNotes: true
tag: ${{ steps.determine-tag.outputs.tagname }}

22 changes: 22 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,25 @@ Bug reports, feature requests, comments, questions, code contributions and love
This project is developed by [Lombiq Technologies](https://lombiq.com/). Commercial-grade support is available through Lombiq.

To ensure that when changing actions or workflows their references to other actions/workflows are up-to-date (i.e. instead of `@dev` they reference each other with `@current-branch`) the [Validate GitHub Actions Refs workflow](https://github.com/Lombiq/GitHub-Actions/blob/dev/.github/workflows/validate-this-gha-refs.yml) will fail if references are incorrect. This is the case also if after a pull request approve that references don't point to the target branch; before merging, that should be fixed, otherwise merging via the merge queue will fail.

## Versioning, Tags and Releases

To release versions of Lombiq GitHub Actions, and allow consumers to reference a specific version of a reusable workflow or composite action (e.g. `@v1.0`), we employ some automation to do this in a consistent and predictable way.
See [issue #284 "Introduce versioning and releases (OSOE-735)"](https://github.com/Lombiq/GitHub-Actions/issues/284) <!-- #spell-check-ignore-line -->
for additional details on why we do this.

New versions of Lombiq GitHub Actions are automatically tagged using the [Tag Version (this repo)](https://github.com/Lombiq/GitHub-Actions/blob/dev/.github/workflows/tag-version-this-repo.yml) workflow. This workflow is triggered for release branches with a name that matches the `release/**` pattern (e.g. `release/v1.0`, `release/v2.0-alpha`, etc.).

The create a new release, create a new branch following the above naming convention at the commit to be released and push it.

When you push your new release branch, the following things happen automatically:

1. The [Tag Version (this repo)](https://github.com/Lombiq/GitHub-Actions/blob/dev/.github/workflows/tag-version-this-repo.yml) workflow runs and calls the reusable workflow [Tag Version](https://github.com/Lombiq/GitHub-Actions/blob/dev/.github/workflows/tag-version.yml).
2. The [Tag Version](https://github.com/Lombiq/GitHub-Actions/blob/dev/.github/workflows/tag-version.yml) workflow calls the [Set GitHub Actions References](https://github.com/Lombiq/GitHub-Actions/blob/dev/.github/actions/set-gha-refs/action.yml) reusable action.
3. The [Set GitHub Actions References](https://github.com/Lombiq/GitHub-Actions/blob/dev/.github/actions/set-gha-refs/action.yml) action recursively searches all files in the `.github` folder to find each call to a GitHub Action or Workflow contained in this repository.
4. By default, references to called actions and workflows targeting the release branch (see above) are string replaced with the version name (e.g. `v1.0`).
- Additionally, the [Set GitHub Actions References](https://github.com/Lombiq/GitHub-Actions/blob/dev/.github/actions/set-gha-refs/action.yml) action has a parameter called [additional-pattern-include-list](https://github.com/Lombiq/GitHub-Actions/blob/dev/.github/actions/set-gha-refs/action.yml#L24) which allows for replacing `release/v1.0` under special circumstances such as for the [spelling action explicit file reference](https://github.com/Lombiq/GitHub-Actions/blob/dev/.github/actions/spelling/action.yml#L133) scenario.
5. The [stefanzweifel/git-auto-commit-action](https://github.com/stefanzweifel/git-auto-commit-action/commit/8756aa072ef5b4a080af5dc8fef36c5d586e521d) action is used to automatically: <!-- #spell-check-ignore-line -->
- Commit the updated files to the `release/v1.0` branch.
- Create a new git tag using the release name (e.g. `v1.0`).
6. Tags are force pushed to update the `v1.0` tag if it needs to be updated.

0 comments on commit 0f3e011

Please sign in to comment.