Skip to content

release

release #12

Workflow file for this run

name: release
on:
push:
tags:
- "v*"
workflow_dispatch:
inputs:
tag:
description: "Tag to build and upload (e.g. v1.2.3)"
required: true
type: string
permissions:
contents: write
jobs:
meta:
runs-on: ubuntu-latest
outputs:
tag: ${{ steps.meta.outputs.tag }}
steps:
- id: meta
shell: bash
run: |
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
echo "tag=${{ github.event.inputs.tag }}" >> "$GITHUB_OUTPUT"
else
echo "tag=${{ github.ref_name }}" >> "$GITHUB_OUTPUT"
fi
verify:
runs-on: ubuntu-latest
timeout-minutes: 30
needs: meta
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ needs.meta.outputs.tag }}
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.8"
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Run CI checks
run: make test-all
create_release:
runs-on: ubuntu-latest
needs: [meta, verify]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ needs.meta.outputs.tag }}
- name: Create GitHub Release (if missing)
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG='${{ needs.meta.outputs.tag }}'
if gh release view "$TAG" >/dev/null 2>&1; then
echo "Release already exists: $TAG"
exit 0
fi
gh release create "$TAG" --generate-notes
build_upload:
needs: [meta, create_release]
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
bun_target: bun-linux-x64
platform: linux-x64
exe: roboppi
opentui_pkg: ""
- os: ubuntu-latest
bun_target: bun-linux-arm64
platform: linux-arm64
exe: roboppi
opentui_pkg: "@opentui/core-linux-arm64"
- os: macos-latest
bun_target: bun-darwin-arm64
platform: macos-arm64
exe: roboppi
opentui_pkg: ""
- os: macos-latest
bun_target: bun-darwin-x64
platform: macos-x64
exe: roboppi
opentui_pkg: "@opentui/core-darwin-x64"
- os: windows-latest
bun_target: bun-windows-x64
platform: windows-x64
exe: roboppi.exe
opentui_pkg: ""
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ needs.meta.outputs.tag }}
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.8"
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Install OpenTUI platform package (for cross builds)
if: ${{ matrix.opentui_pkg != '' }}
shell: bash
env:
PKG: ${{ matrix.opentui_pkg }}
run: |
set -euo pipefail
VER=$(node -e "const p=require('./package.json'); process.stdout.write(String((p.dependencies||{})['@opentui/core']||''));")
if [[ -z "$VER" ]]; then
echo "@opentui/core version not found in package.json" >&2
exit 1
fi
TARBALL=$(VER="$VER" python - <<'PY'
import json
import os
import urllib.request
import urllib.parse
pkg = os.environ['PKG']
ver = os.environ['VER']
meta_url = 'https://registry.npmjs.org/' + urllib.parse.quote(pkg, safe='')
with urllib.request.urlopen(meta_url) as r:
meta = json.load(r)
try:
tarball = meta['versions'][ver]['dist']['tarball']
except Exception as e:
raise SystemExit(f'could not resolve tarball for {pkg}@{ver}: {e}')
print(tarball)
PY
)
echo "Installing $PKG@$VER from $TARBALL" >&2
rm -f /tmp/opentui-pkg.tgz
curl -fsSL "$TARBALL" -o /tmp/opentui-pkg.tgz
SCOPE=$(node -e "const s=process.env.PKG; process.stdout.write(s.startsWith('@')?s.split('/')[0].slice(1):'');")
NAME=$(node -e "const s=process.env.PKG; process.stdout.write(s.startsWith('@')?s.split('/')[1]:s);")
if [[ -z "$SCOPE" || -z "$NAME" ]]; then
echo "Could not parse scoped package name: $PKG" >&2
exit 1
fi
DEST="node_modules/@${SCOPE}/${NAME}"
mkdir -p "$DEST"
tar -xzf /tmp/opentui-pkg.tgz -C "$DEST" --strip-components=1 package
- name: Build standalone binary
shell: bash
run: |
rm -rf dist release stage
mkdir -p dist
bun build --compile --target=${{ matrix.bun_target }} --outfile "dist/${{ matrix.exe }}" src/cli.ts
- name: Package (tar.gz)
shell: bash
run: |
TAG='${{ needs.meta.outputs.tag }}'
ASSET="roboppi-${TAG}-${{ matrix.platform }}"
mkdir -p stage release
cp "dist/${{ matrix.exe }}" stage/
cp README.md stage/
if [[ -f README.ja.md ]]; then cp README.ja.md stage/; fi
tar -czf "release/${ASSET}.tar.gz" -C stage .
ASSET="$ASSET" python - <<'PY'
import os
import hashlib
from pathlib import Path
asset = os.environ["ASSET"]
p = Path("release") / f"{asset}.tar.gz"
h = hashlib.sha256(p.read_bytes()).hexdigest()
(p.parent / (p.name + ".sha256")).write_text(f"{h} {p.name}\n", encoding="utf-8")
PY
- name: Upload assets to GitHub Release
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG='${{ needs.meta.outputs.tag }}'
ASSET="roboppi-${TAG}-${{ matrix.platform }}"
gh release upload "$TAG" \
"release/${ASSET}.tar.gz" \
"release/${ASSET}.tar.gz.sha256" \
--clobber