Skip to content

Publish

Publish #39

Workflow file for this run

name: Publish
on:
workflow_dispatch:
inputs:
package:
description: 'Package to release'
required: true
type: choice
options:
- hikkaku
- create-hikkaku
- vite-plugin-turbowarp-packager
- moonscratch
- testing
- gobox
release_type:
description: 'Version bump type'
required: true
type: choice
options:
- patch
- minor
- major
permissions:
id-token: write
contents: write
jobs:
publish:
runs-on: ubuntu-latest
concurrency:
group: publish-${{ inputs.package }}
cancel-in-progress: false
permissions:
contents: write
id-token: write
env:
GH_TOKEN: ${{ github.token }}
PACKAGE_NAME: ${{ inputs.package }}
INPUT_RELEASE_TYPE: ${{ inputs.release_type }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Bun
uses: oven-sh/setup-bun@v2
- name: Restore Bun/MoonBit/Turbo caches
uses: actions/cache@v4
with:
path: |
~/.bun/install
~/.moon
~/.turbo
**/.turbo
key: ${{ runner.os }}-bun-moonbit-turbo-${{ hashFiles('bun.lock', 'turbo.json', 'package.json') }}
restore-keys: |
${{ runner.os }}-bun-moonbit-turbo-
- name: Set up MoonBit
run: |
if [ ! -x "$HOME/.moon/bin/moon" ]; then
curl -fsSL https://cli.moonbitlang.com/install/unix.sh | bash
else
echo "MoonBit is already available from cache."
fi
echo "$HOME/.moon/bin" >> $GITHUB_PATH
- name: Update MoonBit dependencies
run: |
moon version --all
moon update
- uses: actions/setup-node@v4
with:
node-version: '24'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Resolve release metadata
id: metadata
shell: bash
run: |
package="$PACKAGE_NAME"
release_type="$INPUT_RELEASE_TYPE"
if ! [[ "$package" =~ ^(hikkaku|create-hikkaku|vite-plugin-turbowarp-packager|moonscratch|testing|gobox)$ ]]; then
echo "Unsupported package: $package"
exit 1
fi
if ! [[ "$release_type" =~ ^(major|minor|patch)$ ]]; then
echo "Invalid release_type: $release_type"
echo "Supported values: major, minor, patch"
exit 1
fi
# Derive current version from npm registry (fallback to package.json if unpublished)
package_json_path="packages/$package/package.json"
if [ ! -r "$package_json_path" ]; then
echo "package.json not found or not readable: $package_json_path"
exit 1
fi
package_name="$(node -e "const fs=require('fs');const pkg=JSON.parse(fs.readFileSync(process.argv[1],'utf8'));process.stdout.write(typeof pkg.name==='string'?pkg.name.trim():'')" "$package_json_path")"
if [ -z "$package_name" ]; then
echo "package.json does not contain a valid name field: $package_json_path"
exit 1
fi
has_repository="$(node -e "const fs=require('fs');const pkg=JSON.parse(fs.readFileSync(process.argv[1],'utf8'));const repo=pkg.repository;const ok=(typeof repo==='string'&&repo.trim()!=='')||(repo&&typeof repo==='object'&&typeof repo.url==='string'&&repo.url.trim()!=='');process.stdout.write(ok?'yes':'no')" "$package_json_path")"
if [ "$has_repository" != "yes" ]; then
echo "package.json must contain a non-empty repository field: $package_json_path"
exit 1
fi
if ! current_version="$(npm view "$package_name" version 2>/dev/null | tr -d '\r\n')"; then
current_version="$(node -e "const fs=require('fs');const pkg=JSON.parse(fs.readFileSync(process.argv[1],'utf8'));process.stdout.write(typeof pkg.version==='string'?pkg.version.trim():'')" "$package_json_path")"
if [ -z "$current_version" ]; then
echo "Could not fetch npm version and package.json does not contain a valid version field: $package_json_path"
exit 1
fi
echo "Could not fetch version from npm for $package_name, using package.json version: $current_version"
else
echo "Using npm registry version for $package_name: $current_version"
fi
if ! [[ "$current_version" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)([.-][0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$ ]]; then
echo "Invalid current package version: $current_version"
exit 1
fi
major="${BASH_REMATCH[1]}"
minor="${BASH_REMATCH[2]}"
patch="${BASH_REMATCH[3]}"
case "$release_type" in
major)
major=$((major + 1))
minor=0
patch=0
;;
minor)
minor=$((minor + 1))
patch=0
;;
patch)
patch=$((patch + 1))
;;
esac
version="$major.$minor.$patch"
tag="$package@$version"
if git rev-parse -q --verify "refs/tags/$tag" >/dev/null; then
echo "Tag already exists: $tag"
exit 1
fi
if gh release view "$tag" >/dev/null 2>&1; then
echo "Release already exists: $tag"
exit 1
fi
echo "package=$package" >> "$GITHUB_OUTPUT"
echo "version=$version" >> "$GITHUB_OUTPUT"
echo "tag=$tag" >> "$GITHUB_OUTPUT"
- name: Ensure workflow runs on branch
run: |
if [[ '${{ github.ref_type }}' != 'branch' ]]; then
echo "This workflow must run on a branch ref to push version updates."
echo "Current ref_type: ${{ github.ref_type }}"
exit 1
fi
- name: Update package version
run: |
node -e "const fs=require('fs');const path='packages/${{ steps.metadata.outputs.package }}/package.json';const version='${{ steps.metadata.outputs.version }}';const pkg=JSON.parse(fs.readFileSync(path,'utf8'));pkg.version=version;const hasPrivate=Object.prototype.hasOwnProperty.call(pkg,'private');if(hasPrivate&&(pkg.name==='create-hikkaku'||pkg.name==='vite-plugin-turbowarp-packager')){pkg.private=false;}fs.writeFileSync(path,JSON.stringify(pkg,null,2)+'\n');"
- name: Build hikkaku
if: steps.metadata.outputs.package == 'hikkaku'
run: bun run --filter hikkaku build
- name: Build create-hikkaku
if: steps.metadata.outputs.package == 'create-hikkaku'
run: bun run --filter create-hikkaku build
- name: Build vite-plugin-turbowarp-packager
if: steps.metadata.outputs.package == 'vite-plugin-turbowarp-packager'
run: bun run --filter vite-plugin-turbowarp-packager build
- name: Build moonscratch
if: steps.metadata.outputs.package == 'moonscratch'
run: bun run --filter moonscratch build
- name: Build testing
if: steps.metadata.outputs.package == 'testing'
run: bun run --cwd packages/testing build
- name: Build gobox
if: steps.metadata.outputs.package == 'gobox'
run: bun run --cwd packages/gobox build
- name: Build gpts zip
if: steps.metadata.outputs.package == 'hikkaku'
run: bun run --filter gpts-zip build
- name: Resolve publish directory
id: publish_dir
shell: bash
run: |
case '${{ steps.metadata.outputs.package }}' in
hikkaku)
dir='packages/hikkaku/dist'
;;
create-hikkaku)
dir='packages/create-hikkaku'
;;
vite-plugin-turbowarp-packager)
dir='packages/vite-plugin-turbowarp-packager'
;;
moonscratch)
dir='packages/moonscratch'
;;
testing)
dir='packages/testing'
;;
gobox)
dir='packages/gobox'
;;
*)
echo "Unsupported package: ${{ steps.metadata.outputs.package }}"
exit 1
;;
esac
echo "dir=$dir" >> "$GITHUB_OUTPUT"
- name: Pack package tarball
id: pack
shell: bash
run: |
publish_dir='${{ steps.publish_dir.outputs.dir }}'
tarball_output="$(cd "$publish_dir" && bun pm pack --quiet --destination "$RUNNER_TEMP")"
tarball_output="$(echo "$tarball_output" | tr -d '\n')"
if [[ "$tarball_output" = /* ]]; then
tarball_path="$tarball_output"
else
tarball_path="$RUNNER_TEMP/$tarball_output"
fi
if [[ ! -f "$tarball_path" ]]; then
echo "Tarball was not generated at expected path: $tarball_path"
exit 1
fi
echo "path=$tarball_path" >> "$GITHUB_OUTPUT"
- name: Publish package tarball to npm
run: npm publish '${{ steps.pack.outputs.path }}' --provenance --access public
- name: Commit and push version update
id: version_commit
shell: bash
run: |
file_path="packages/${{ steps.metadata.outputs.package }}/package.json"
git config user.name 'github-actions[bot]'
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
git add "$file_path"
if git diff --cached --quiet; then
echo "No version updates to commit."
echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
exit 0
fi
git commit -m 'chore(release): bump ${{ steps.metadata.outputs.package }} to v${{ steps.metadata.outputs.version }}'
git pull --rebase origin "${{ github.ref_name }}"
git push origin "HEAD:${{ github.ref_name }}"
echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
- name: Create release with generated notes
run: |
if [[ '${{ steps.metadata.outputs.package }}' == 'hikkaku' ]]; then
gh release create '${{ steps.metadata.outputs.tag }}' \
'packages/gpts-zip/dist.zip#gpts.zip' \
--generate-notes \
--target '${{ steps.version_commit.outputs.sha }}'
else
gh release create '${{ steps.metadata.outputs.tag }}' \
--generate-notes \
--target '${{ steps.version_commit.outputs.sha }}'
fi