Publish #39
This file contains hidden or 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
| 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 |