I recently made some changes to BRW and added some Github workflows to make life easier maintaining UPM repositories.
They're all currently standalone. I haven't figured out how I can "invoke" other workflows from a main workflow. So except for one, all others are manually triggered. Of course, you can merge them all into a single workflow file. Or introduce some ways to ensure they run in the order you want.
You can find the workflows here. In case they change in the future, here they are.
npm-publish.yaml
I added this file because currently I publish locally from my desktop. This requires me to checkout the upm-latest branch, do a git clean -df so I only have the package contents, and then invoke npm publish.
# Github action that can be triggered to make an npm release
# You need a secret on Github called NPM_PUBLISH_TOKEN
# Configure RELEASE_BRANCH to match the name of the branch that has package.json as the root
name: Publish to NPM
on:
workflow_dispatch:
env:
RELEASE_BRANCH: upm-latest
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout upm-latest branch
uses: actions/checkout@v4
with:
ref: ${{ env.RELEASE_BRANCH }}
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
- name: Configure npm authentication
run: |
npm whoami
- name: Publish to npm
run: npm publish
update-version.yaml
Sometimes I just forget to update package.json
This is very annoying.
So this file allows me to trigger a version update.
# Github action that can be triggered to update the version in package.json
# Allows you to define values like major.minor.patch and if that should be set as the new version of incremented
# Set PACKAGE_JSON_PATH based on your repo
name: Update Package Version
on:
workflow_dispatch:
inputs:
major:
description: 'Major version number'
required: true
type: number
default: 0
minor:
description: 'Minor version number'
required: true
type: number
default: 0
patch:
description: 'Patch version number'
required: true
type: number
default: 0
update_method:
description: 'Update method'
required: true
type: choice
options:
- increment
- set
default: 'set'
env:
PACKAGE_JSON_PATH: Assets/Adrenak.BRW/package.json
jobs:
bump-version:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 0
- name: Configure Git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- name: Read current version
id: current-version
run: |
if [ ! -f "${{ env.PACKAGE_JSON_PATH }}" ]; then
echo "Error: package.json not found at ${{ env.PACKAGE_JSON_PATH }}"
exit 1
fi
CURRENT_VERSION=$(node -p "require('./${{ env.PACKAGE_JSON_PATH }}').version")
echo "current_version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
echo "Current version: $CURRENT_VERSION"
# Parse version components
IFS='.' read -r CURRENT_MAJOR CURRENT_MINOR CURRENT_PATCH <<< "$CURRENT_VERSION"
echo "current_major=$CURRENT_MAJOR" >> $GITHUB_OUTPUT
echo "current_minor=$CURRENT_MINOR" >> $GITHUB_OUTPUT
echo "current_patch=$CURRENT_PATCH" >> $GITHUB_OUTPUT
- name: Calculate new version
id: new-version
run: |
CURRENT_MAJOR=${{ steps.current-version.outputs.current_major }}
CURRENT_MINOR=${{ steps.current-version.outputs.current_minor }}
CURRENT_PATCH=${{ steps.current-version.outputs.current_patch }}
INPUT_MAJOR=${{ inputs.major }}
INPUT_MINOR=${{ inputs.minor }}
INPUT_PATCH=${{ inputs.patch }}
UPDATE_METHOD="${{ inputs.update_method }}"
if [ "$UPDATE_METHOD" = "increment" ]; then
# Increment mode: add values to current version
NEW_MAJOR=$((CURRENT_MAJOR + INPUT_MAJOR))
NEW_MINOR=$((CURRENT_MINOR + INPUT_MINOR))
NEW_PATCH=$((CURRENT_PATCH + INPUT_PATCH))
# Validate no negative values
if [ $NEW_MAJOR -lt 0 ] || [ $NEW_MINOR -lt 0 ] || [ $NEW_PATCH -lt 0 ]; then
echo "Error: Version cannot be negative. Result would be: $NEW_MAJOR.$NEW_MINOR.$NEW_PATCH"
exit 1
fi
else
# Set mode: use input values directly
NEW_MAJOR=$INPUT_MAJOR
NEW_MINOR=$INPUT_MINOR
NEW_PATCH=$INPUT_PATCH
# Validate no negative values
if [ $NEW_MAJOR -lt 0 ] || [ $NEW_MINOR -lt 0 ] || [ $NEW_PATCH -lt 0 ]; then
echo "Error: Version cannot be negative. Input: $NEW_MAJOR.$NEW_MINOR.$NEW_PATCH"
exit 1
fi
fi
NEW_VERSION="$NEW_MAJOR.$NEW_MINOR.$NEW_PATCH"
echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT
echo "New version: $NEW_VERSION"
- name: Update package.json
run: |
NEW_VERSION="${{ steps.new-version.outputs.new_version }}"
node -e "
const fs = require('fs');
const path = '${{ env.PACKAGE_JSON_PATH }}';
const pkg = JSON.parse(fs.readFileSync(path, 'utf8'));
pkg.version = '$NEW_VERSION';
fs.writeFileSync(path, JSON.stringify(pkg, null, '\t') + '\n');
"
echo "Updated ${{ env.PACKAGE_JSON_PATH }} to version $NEW_VERSION"
- name: Commit and push changes
run: |
git add "${{ env.PACKAGE_JSON_PATH }}"
if git diff --staged --quiet; then
echo "No changes to commit."
else
CURRENT_VERSION="${{ steps.current-version.outputs.current_version }}"
NEW_VERSION="${{ steps.new-version.outputs.new_version }}"
git commit -m "chore: bump version from $CURRENT_VERSION to $NEW_VERSION"
git push origin master
echo "Committed and pushed version bump: $CURRENT_VERSION -> $NEW_VERSION"
fi
sync-readme-and-update-upm-branch.yaml
I configure this to also run on push because this ensures my README files and upm-branch contents are always up to date.
# Used for Unity UPM repositories where the main/master branch has the Unity project root and the actual UPM package directory is somewhere inside Assets/
# This file updates Assets/../README.md based on the latest root README.md
# Then updates a dedicated UPM branch
# Configure env variables based on your needs
name: Sync README and Update UPM Branch
on:
push:
branches:
- master
workflow_dispatch:
env:
SUBDIRECTORY_PATH: Assets/Adrenak.BRW
UPM_BRANCH: upm-latest
jobs:
sync-readme:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 0
- name: Configure Git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- name: Check if README needs update
id: check-readme
run: |
ROOT_README="README.md"
SUB_README="${{ env.SUBDIRECTORY_PATH }}/README.md"
if [ ! -f "$ROOT_README" ]; then
echo "Root README.md not found. Exiting."
exit 1
fi
if [ ! -f "$SUB_README" ]; then
echo "needs_update=true" >> $GITHUB_OUTPUT
echo "Subdirectory README.md does not exist. Will create it."
elif ! cmp -s "$ROOT_README" "$SUB_README"; then
echo "needs_update=true" >> $GITHUB_OUTPUT
echo "README.md files differ. Will update subdirectory README."
else
echo "needs_update=false" >> $GITHUB_OUTPUT
echo "README.md files are identical. No update needed."
fi
- name: Copy README to subdirectory
if: steps.check-readme.outputs.needs_update == 'true'
run: |
mkdir -p "${{ env.SUBDIRECTORY_PATH }}"
cp README.md "${{ env.SUBDIRECTORY_PATH }}/README.md"
echo "Copied README.md to ${{ env.SUBDIRECTORY_PATH }}/"
- name: Commit and push changes
if: steps.check-readme.outputs.needs_update == 'true'
run: |
git add "${{ env.SUBDIRECTORY_PATH }}/README.md"
if git diff --staged --quiet; then
echo "No changes to commit."
else
git commit -m "chore: sync README.md to ${{ env.SUBDIRECTORY_PATH }}/"
git push origin master
echo "Committed and pushed README.md update."
fi
update-upm-branch:
needs: sync-readme
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout master branch
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 0
ref: master
- name: Configure Git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- name: Check if subdirectory exists
id: check-subdir
run: |
if [ ! -d "${{ env.SUBDIRECTORY_PATH }}" ]; then
echo "Subdirectory ${{ env.SUBDIRECTORY_PATH }} not found. Exiting."
exit 1
fi
echo "Subdirectory found: ${{ env.SUBDIRECTORY_PATH }}"
- name: Copy subdirectory to temporary location
run: |
# Copy subdirectory contents to a temp location before switching branches
mkdir -p /tmp/package-contents
cp -r "${{ env.SUBDIRECTORY_PATH }}"/* /tmp/package-contents/ 2>/dev/null || true
cp -r "${{ env.SUBDIRECTORY_PATH }}"/.[!.]* /tmp/package-contents/ 2>/dev/null || true
echo "Copied contents to temporary location"
- name: Create or checkout upm-latest branch
run: |
# Check if branch exists
if git ls-remote --heads origin ${{ env.UPM_BRANCH }} | grep -q "${{ env.UPM_BRANCH }}"; then
echo "Branch ${{ env.UPM_BRANCH }} exists. Checking out..."
git fetch origin ${{ env.UPM_BRANCH }}:${{ env.UPM_BRANCH }}
git checkout ${{ env.UPM_BRANCH }}
else
echo "Branch ${{ env.UPM_BRANCH }} does not exist. Creating..."
git checkout --orphan ${{ env.UPM_BRANCH }}
git rm -rf --cached . || true
fi
- name: Clear branch contents
run: |
# Remove all files except .git
find . -mindepth 1 -maxdepth 1 ! -name '.git' -exec rm -rf {} +
- name: Copy subdirectory contents to branch root
run: |
# Copy from temporary location to branch root
cp -r /tmp/package-contents/* .
echo "Copied contents from temporary location to branch root"
- name: Commit and push changes
run: |
git add -A
if git diff --staged --quiet && git diff --quiet; then
echo "No changes to commit."
else
git commit -m "chore: update upm-latest branch with latest package contents"
git push origin ${{ env.UPM_BRANCH }}
echo "Committed and pushed to ${{ env.UPM_BRANCH }} branch."
fi