-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Automate bumping version numbers for release automation
- Loading branch information
1 parent
20ab7e8
commit 31aa11f
Showing
5 changed files
with
276 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
# GitHub Actions Utility Functions | ||
# https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions | ||
import os | ||
import sys | ||
|
||
errors_were_printed = False | ||
|
||
def fail_if_errors(): | ||
if errors_were_printed: | ||
print("Exiting due to previous errors.") | ||
sys.exit(1) | ||
|
||
def print_error(message): | ||
global errors_were_printed | ||
errors_were_printed = True | ||
print(f"::error::{message}") | ||
|
||
def print_warning(message): | ||
print(f"::warning::{message}") | ||
|
||
def print_notice(message): | ||
print(f"::notice::{message}") | ||
|
||
def print_debug(message): | ||
print(f"::debug::{message}") | ||
|
||
def github_file_command(command, message): | ||
command = f"GITHUB_{command}" | ||
command_file = os.getenv(command) | ||
|
||
if command_file is None: | ||
print_error(f"Missing required GitHub environment variable '{command}'") | ||
sys.exit(1) | ||
|
||
if not os.path.exists(command_file): | ||
print_error(f"'{command}' points to non-existent file '{command_file}')") | ||
sys.exit(1) | ||
|
||
with open(command_file, 'a') as command_file_handle: | ||
command_file_handle.write(message) | ||
command_file_handle.write('\n') | ||
|
||
def set_output(name, value): | ||
if isinstance(value, bool): | ||
value = "true" if value else "false" | ||
github_file_command("OUTPUT", f"{name}<<GHA_PY_EOF\n{value}\nGHA_PY_EOF") | ||
|
||
def set_environment_variable(name, value): | ||
github_file_command("ENV", f"{name}={value}") | ||
|
||
def add_path(path): | ||
github_file_command("PATH", path) | ||
|
||
if __name__ == "__main__": | ||
args = sys.argv | ||
|
||
def pop_arg(): | ||
global args | ||
if len(args) == 0: | ||
print_error("Bad command line, not enough arguments specified.") | ||
sys.exit(1) | ||
result = args[0] | ||
args = args[1:] | ||
return result | ||
|
||
def done_parsing(): | ||
if len(args) > 0: | ||
print_error("Bad command line, too many arguments specified.") | ||
sys.exit(1) | ||
|
||
pop_arg() # Skip script name | ||
command = pop_arg() | ||
if command == "print_error": | ||
message = pop_arg() | ||
done_parsing() | ||
print_error(message) | ||
elif command == "print_warning": | ||
message = pop_arg() | ||
done_parsing() | ||
print_warning(message) | ||
elif command == "print_notice": | ||
message = pop_arg() | ||
done_parsing() | ||
print_notice(message) | ||
elif command == "set_output": | ||
name = pop_arg() | ||
value = pop_arg() | ||
done_parsing() | ||
set_output(name, value) | ||
elif command == "set_environment_variable": | ||
name = pop_arg() | ||
value = pop_arg() | ||
done_parsing() | ||
set_environment_variable(name, value) | ||
elif command == "add_path": | ||
path = pop_arg() | ||
done_parsing() | ||
add_path(path) | ||
else: | ||
print_error(f"Unknown command '{command}'") | ||
sys.exit(1) | ||
|
||
fail_if_errors() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
#!/usr/bin/env python3 | ||
import os | ||
import re | ||
|
||
import gha | ||
|
||
TEMPLATE_PATH = ".github/workflows/version-info-template.md" | ||
INSTALLATION_ARTICLE_PATH = "articles/installation.md" | ||
|
||
project_url_base = "https://github.com/bonsai-rx/bonsai/" | ||
|
||
#================================================================================================== | ||
# Get inputs | ||
#================================================================================================== | ||
def get_environment_variable(name) -> str: | ||
ret = os.getenv(name) | ||
|
||
if ret is None or ret == '': | ||
gha.print_error(f"Missing required parameter '{name}'") | ||
return '' | ||
|
||
return ret | ||
|
||
workflow_dispatch_version = get_environment_variable('workflow_dispatch_version') | ||
|
||
# Handle forks for testing purposes | ||
if os.getenv('is_canonical_docs_repo') != 'true': | ||
project_fork_url = get_environment_variable('project_fork_url') | ||
project_url_base = project_fork_url.removesuffix('.git') | ||
if project_url_base[-1] != '/': | ||
project_url_base += '/' | ||
|
||
gha.fail_if_errors() | ||
|
||
#================================================================================================== | ||
# Populate template | ||
#================================================================================================== | ||
|
||
version_info = "" | ||
with open(TEMPLATE_PATH, 'r', encoding='utf-8') as f: | ||
version_info = f.read() | ||
|
||
version_info = version_info.replace("$VERSION$", workflow_dispatch_version) | ||
version_info = version_info.replace("$PROJECT_URL_BASE$", project_url_base) | ||
|
||
#================================================================================================== | ||
# Update article | ||
#================================================================================================== | ||
|
||
article = "" | ||
with open(INSTALLATION_ARTICLE_PATH, 'r', encoding='utf-8') as f: | ||
article = f.read() | ||
|
||
def replace_function(match): | ||
return f"{match.group(1)}{version_info}{match.group(3)}" | ||
|
||
(article, replacement_count) = re.subn( | ||
r'(<!-- \[RELEASE_INFO\].+?-->\r?\n)(.+)(<!-- \[/RELEASE_INFO\] -->)', | ||
replace_function, | ||
article, | ||
1, | ||
re.DOTALL | ||
) | ||
|
||
if replacement_count != 1: | ||
gha.print_error(f"Failed to find the RELEASE_INFO block within '{INSTALLATION_ARTICLE_PATH}'.") | ||
gha.fail_if_errors() | ||
|
||
with open(INSTALLATION_ARTICLE_PATH, 'w',encoding='utf-8') as f: | ||
f.write(article) | ||
|
||
print(f"Bonsai release info in '{INSTALLATION_ARTICLE_PATH}' updated to {workflow_dispatch_version}.") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
# This workflow bumps the submodule version used for a particular project | ||
# In the case of Bonsai being updated, this also updates the installation page with the latest version info | ||
name: Update documented project version | ||
run-name: Update `${{github.event.inputs.project}}` to `${{github.event.inputs.version}}` | ||
on: | ||
workflow_dispatch: | ||
inputs: | ||
project: | ||
description: "The name of the project to be updated (IE: a folder name within the src directory)" | ||
required: true | ||
version: | ||
description: "The target version to update to (IE: a Git tag in the project)" | ||
required: true | ||
project-fork-url: | ||
description: "Git URL of the project for testing in forks" | ||
default: "" | ||
concurrency: | ||
group: version-bump | ||
permissions: | ||
# Required to trigger GitHub Pages deployment | ||
actions: write | ||
# Required to push changes | ||
contents: write | ||
jobs: | ||
update: | ||
name: Update ${{github.event.inputs.project}} to ${{github.event.inputs.version}} | ||
runs-on: ubuntu-latest | ||
env: | ||
PROJECT: ${{github.event.inputs.project}} | ||
VERSION: ${{github.event.inputs.version}} | ||
steps: | ||
# ----------------------------------------------------------------------- Checkout | ||
- name: Checkout | ||
uses: actions/checkout@v4 | ||
|
||
# ----------------------------------------------------------------------- Override the submodule URL | ||
# This is to support testing release automation in forks, it is disabled for the canonical docs repo | ||
- name: Override ${{github.event.inputs.project}}'s submodule URL | ||
if: vars.IS_CANONICAL_DOCS_REPO != 'true' && github.event.inputs.project-fork-url != '' | ||
run: git config --local --add "submodule.src/$PROJECT.url" "$FORK_URL" | ||
env: | ||
FORK_URL: ${{github.event.inputs.project-fork-url}} | ||
|
||
# ----------------------------------------------------------------------- Update the submodule | ||
- name: Clone ${{github.event.inputs.project}} submodule | ||
run: git submodule update --init "src/$PROJECT/" | ||
- name: Update ${{github.event.inputs.project}} submodule | ||
working-directory: src/${{github.event.inputs.project}}/ | ||
run: git checkout "refs/tags/$VERSION" | ||
- name: Stage ${{github.event.inputs.project}} submodule | ||
run: git add "src/$PROJECT/" | ||
|
||
# ----------------------------------------------------------------------- Update the installation page | ||
- name: Setup Python 3.10 | ||
if: github.event.inputs.project == 'bonsai' | ||
uses: actions/setup-python@v5 | ||
with: | ||
python-version: '3.10' | ||
- name: Update Bonsai version info | ||
if: github.event.inputs.project == 'bonsai' | ||
run: | | ||
python .github/workflows/update-bonsai-version-info.py | ||
git add articles/installation.md | ||
env: | ||
workflow_dispatch_version: ${{github.event.inputs.version}} | ||
is_canonical_docs_repo: ${{vars.IS_CANONICAL_DOCS_REPO}} | ||
project_fork_url: ${{github.event.inputs.project-fork-url}} | ||
|
||
# ----------------------------------------------------------------------- Commit changes | ||
# Skip the rest of the job if there aren't any changes to commit | ||
# (IE: the submodule was already the relevant version) | ||
- name: Check if update was necessary | ||
id: pre-commit-check | ||
run: | | ||
(git diff-index --cached --exit-code HEAD \ | ||
&& python .github/workflows/gha.py print_notice "Version bump was no-op, no changes to commit.") \ | ||
|| python .github/workflows/gha.py set_output continue true | ||
- name: Commit changes | ||
if: steps.pre-commit-check.outputs.continue == 'true' | ||
run: | | ||
git config user.name "github-actions[bot]" | ||
git config user.email "github-actions[bot]@users.noreply.github.com" | ||
git commit -m "Update \`$PROJECT\` to \`$VERSION\`" | ||
- name: Push changes | ||
if: steps.pre-commit-check.outputs.continue == 'true' | ||
run: git push | ||
# The above push will not actually trigger a deployment as actions performed using temporary GitHub Actions tokens | ||
# do not trigger events in order to avoid unintentional recursion. As such we manually trigger deployment. | ||
- name: Trigger GitHub Pages deployment | ||
if: steps.pre-commit-check.outputs.continue == 'true' | ||
run: gh workflow run build.yml | ||
env: | ||
GH_TOKEN: ${{github.token}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
The latest stable release is: **$VERSION$** | ||
|
||
[<i class="fa fa-download"></i> Download Installer (.exe)]($PROJECT_URL_BASE$releases/download/$VERSION$/Bonsai-$VERSION$.exe){class="btn btn-success"} | ||
[<i class="fa fa-download"></i> Download Portable (.zip)]($PROJECT_URL_BASE$releases/download/$VERSION$/Bonsai.zip){class="btn btn-warning"} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters