Skip to content

Refinements, lexical-scope reflection, and definition-site line numbe… #175

Refinements, lexical-scope reflection, and definition-site line numbe…

Refinements, lexical-scope reflection, and definition-site line numbe… #175

# Builds prebuilt monoruby binaries and attaches them to a GitHub release,
# so the setup-monoruby action (root action.yml) can download them instead of
# compiling from source. Three triggers:
#
# * push to master — rolling nightly: the `nightly` tag is force-moved to
# the pushed commit and the assets on the `nightly`
# prerelease are replaced (serves `@master`/`@nightly`)
# * release published — assets for that release tag (serves `@v…`)
# * workflow_dispatch — build assets for an existing tag on demand
#
# Automatic triggers (push / release) build x86-64 Linux only, to keep the
# per-push runner cost at one job. Other architectures (Linux arm64, macOS
# arm64) are built on demand: dispatch the workflow with the wanted tag
# (`nightly` or a release tag) and target selection. Platforms without an
# asset simply fall back to the action's source-build path.
#
# Each asset is a tarball named monoruby-<tag>-<target>.tar.gz containing:
#
# bin/monoruby, bin/irm release binaries
# monoruby-home/v<version>/ the runtime tree build.rs installed
# (vendored stdlib + Ruby builtins + stubs)
#
# The binary bakes in the *build* machine's install-root path
# (~/.monoruby/v<version>); binaries built after the runtime
# MONORUBY_INSTALL_ROOT override landed are relocatable via that env var,
# and the action sets it after extraction. GitHub-hosted runners share the
# same $HOME per OS anyway, so even override-less binaries (backfills of
# older tags) work there.
name: release binaries
on:
push:
branches: [master]
release:
types: [published]
workflow_dispatch:
inputs:
tag:
description: "Tag to build assets for: a release tag (e.g. v3.0.1) or `nightly`"
required: true
targets:
description: "Which architectures to build"
type: choice
default: all
options:
- all
- x86_64-linux
- aarch64-linux
- aarch64-macos
permissions:
contents: write # move the nightly tag, create/edit the release, upload assets
# One run per target tag; a newer master push supersedes an in-flight
# nightly build.
concurrency:
group: release-binaries-${{ github.event_name == 'push' && 'nightly' || github.event.release.tag_name || inputs.tag }}
cancel-in-progress: true
jobs:
# Rolling nightly bookkeeping (push events only): move the `nightly` tag to
# the pushed commit and make sure the `nightly` prerelease exists, so the
# matrix jobs have a release to upload onto.
prepare-nightly:
if: github.event_name == 'push'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Move nightly tag and upsert the nightly prerelease
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
git tag -f nightly "$GITHUB_SHA"
git push -f origin nightly
notes="Rolling nightly build of master, replaced on every push. Currently ${GITHUB_SHA}. Consumed by the setup-monoruby action (see action.yml) for \`@master\` / \`@nightly\` refs."
if gh release view nightly --json id >/dev/null 2>&1; then
gh release edit nightly --prerelease --title "Nightly build (master)" --notes "$notes"
else
gh release create nightly --prerelease --title "Nightly build (master)" --notes "$notes"
fi
# Only the x86-64 Linux asset is rebuilt per push; drop other-arch
# assets (from earlier on-demand dispatches) so a stale binary is
# never served for the new commit — those platforms fall back to
# the action's source build until re-dispatched. The x86-64 asset
# stays up (one-build lag) until the build job clobbers it.
for a in $(gh release view nightly --json assets -q '.assets[].name'); do
case "$a" in
monoruby-nightly-x86_64-unknown-linux-gnu.tar.gz) ;;
*) gh release delete-asset nightly "$a" -y ;;
esac
done
build:
needs: prepare-nightly
# Run when prepare-nightly succeeded (push) or was skipped (release /
# dispatch), but never build the `nightly` tag from a release event — the
# nightly is owned by the push path.
if: >-
always() &&
(needs.prepare-nightly.result == 'success' || needs.prepare-nightly.result == 'skipped') &&
!(github.event_name == 'release' && github.event.release.tag_name == 'nightly')
strategy:
fail-fast: false
matrix:
# Automatic triggers (push / release) build x86-64 Linux only;
# workflow_dispatch picks runners from its `targets` input.
# ubuntu-22.04 keeps the glibc floor low enough for every
# currently-hosted Linux runner image; macos-latest is
# arm64-apple-darwin.
os: ${{ fromJSON(
github.event_name != 'workflow_dispatch' && '["ubuntu-22.04"]'
|| inputs.targets == 'x86_64-linux' && '["ubuntu-22.04"]'
|| inputs.targets == 'aarch64-linux' && '["ubuntu-22.04-arm"]'
|| inputs.targets == 'aarch64-macos' && '["macos-latest"]'
|| '["ubuntu-22.04", "ubuntu-22.04-arm", "macos-latest"]') }}
runs-on: ${{ matrix.os }}
timeout-minutes: 60
env:
TAG: ${{ github.event_name == 'push' && 'nightly' || github.event.release.tag_name || inputs.tag }}
steps:
- uses: actions/checkout@v4
with:
# Nightly builds pin the pushed commit (not the moving tag);
# release/dispatch builds check out the release tag.
ref: ${{ github.event_name == 'push' && github.sha || github.event.release.tag_name || inputs.tag }}
- name: Install pinned Rust toolchain
run: |
channel=$(sed -n 's/^channel[[:space:]]*=[[:space:]]*"\([^"]*\)".*/\1/p' rust-toolchain.toml)
rustup toolchain install "$channel" --profile minimal --no-self-update
- name: Install libffi + pkg-config (macOS)
# The aarch64-macOS dep block in monoruby/Cargo.toml builds libffi-sys
# against the system libffi; the Homebrew keg is keg-only, so
# pkg-config needs its prefix.
if: runner.os == 'macOS'
run: |
brew install libffi pkg-config
echo "PKG_CONFIG_PATH=$(brew --prefix libffi)/lib/pkgconfig" >> "$GITHUB_ENV"
- name: Build monoruby
run: cargo install --path monoruby --locked --force
- name: Package tarball
id: package
run: |
set -euo pipefail
target=$(rustc -vV | sed -n 's/^host: //p')
asset="monoruby-${TAG}-${target}.tar.gz"
pkg="$RUNNER_TEMP/pkg"
mkdir -p "$pkg/bin" "$pkg/monoruby-home"
cp "$HOME/.cargo/bin/monoruby" "$HOME/.cargo/bin/irm" "$pkg/bin/"
# The per-version runtime tree build.rs just installed; exclude the
# version-independent host-probe caches (library_path/gem_path),
# which consumers regenerate at runtime.
cp -R "$HOME"/.monoruby/v* "$pkg/monoruby-home/"
tar -C "$pkg" -czf "$RUNNER_TEMP/$asset" bin monoruby-home
echo "asset=$RUNNER_TEMP/$asset" >> "$GITHUB_OUTPUT"
# Sanity-check the packaged pair the way the action will consume it:
# extracted to a fresh location, wired up via MONORUBY_INSTALL_ROOT.
check="$RUNNER_TEMP/check"
mkdir -p "$check"
tar -C "$check" -xzf "$RUNNER_TEMP/$asset"
vdir=$(basename "$check"/monoruby-home/v*)
out=$(MONORUBY_INSTALL_ROOT="$check/monoruby-home/$vdir" \
"$check/bin/monoruby" -e 'require "json"; puts JSON.generate({"ok" => 1})')
test "$out" = '{"ok":1}'
- name: Upload to release
env:
GH_TOKEN: ${{ github.token }}
run: gh release upload "$TAG" "${{ steps.package.outputs.asset }}" --clobber