Skip to content

Commit

Permalink
Automate bumping version numbers for release automation
Browse files Browse the repository at this point in the history
  • Loading branch information
PathogenDavid committed Jul 3, 2024
1 parent 20ab7e8 commit 31aa11f
Show file tree
Hide file tree
Showing 5 changed files with 276 additions and 2 deletions.
103 changes: 103 additions & 0 deletions .github/workflows/gha.py
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()
72 changes: 72 additions & 0 deletions .github/workflows/update-bonsai-version-info.py
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}.")
93 changes: 93 additions & 0 deletions .github/workflows/version-bump.yml
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}}
4 changes: 4 additions & 0 deletions .github/workflows/version-info-template.md
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"}
6 changes: 4 additions & 2 deletions articles/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ title: "Installing Bonsai"

# Installing Bonsai

The Bonsai editor is currently designed to work with the .NET framework on Windows desktop operating systems, version 7 or later. The easiest way to get started with Bonsai is by downloading the latest installer.
The Bonsai editor is currently designed to work with the .NET Framework on Windows desktop operating systems, version 7 or later. The easiest way to get started with Bonsai is by downloading the latest installer.

The latest stable release is: **2.8.3 (2.8.3.4546)**
<!-- [RELEASE_INFO] The info below is generated automatically by .github/workflows/update-version.yml, don't modify it by hand! -->
The latest stable release is: **2.8.3**

[<i class="fa fa-download"></i> Download Installer (.exe)](https://github.com/bonsai-rx/bonsai/releases/download/2.8.3/Bonsai-2.8.3.exe){class="btn btn-success"}
[<i class="fa fa-download"></i> Download Portable (.zip)](https://github.com/bonsai-rx/bonsai/releases/download/2.8.3/Bonsai.zip){class="btn btn-warning"}
<!-- [/RELEASE_INFO] -->

The installer will make sure that .NET and any other required system dependencies for running Bonsai are correctly setup in your computer.

0 comments on commit 31aa11f

Please sign in to comment.