Release #5
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: Release | |
| on: | |
| push: | |
| tags: | |
| - 'v*' | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: 'Tag to build (e.g. v0.1.0)' | |
| required: true | |
| type: string | |
| # REPLACE these per-project: | |
| env: | |
| # Path to the CLI crate inside joulesperbit. | |
| # The Cargo package name is the last path segment; the build uses | |
| # `-p ${CLI_CRATE_PATH##*/}` -> `-p joulec`. The full-pipeline Rust compiler | |
| # lives at compiler/joulec (package `joulec`), not bootstrap (which is the | |
| # separate `joule-bootstrap-tools` package and does not produce this binary). | |
| CLI_CRATE_PATH: crates/joule-lang/compiler/joulec | |
| # Self-contained nested cargo workspace that owns joulec. The joulesperbit | |
| # monorepo root workspace is NOT buildable from a fresh checkout (some members | |
| # path-depend on external sibling repos), so we build from this inner | |
| # workspace, which is clean and has no external/registry dependencies. | |
| WORKSPACE_DIR: joulesperbit/crates/joule-lang | |
| # Name of the CLI binary that ends up in target/release/ | |
| BIN_NAME: joulec | |
| # Public name (what the tarball is named) | |
| RELEASE_NAME: joulec | |
| jobs: | |
| build: | |
| name: Build ${{ matrix.target }} | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - target: x86_64-apple-darwin | |
| os: macos-14 | |
| archive: tar.gz | |
| - target: aarch64-apple-darwin | |
| os: macos-14 | |
| archive: tar.gz | |
| - target: x86_64-unknown-linux-musl | |
| os: ubuntu-latest | |
| archive: tar.gz | |
| use-cross: true | |
| - target: aarch64-unknown-linux-musl | |
| os: ubuntu-latest | |
| archive: tar.gz | |
| use-cross: true | |
| - target: x86_64-pc-windows-msvc | |
| os: windows-latest | |
| archive: zip | |
| steps: | |
| - name: Resolve tag | |
| id: tag | |
| shell: bash | |
| run: | | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| echo "tag=${{ inputs.tag }}" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "tag=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Checkout public release surface | |
| uses: actions/checkout@v4 | |
| - name: Checkout private source | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: openIE-dev/joulesperbit | |
| token: ${{ secrets.JOULESPERBIT_READ_TOKEN }} | |
| path: joulesperbit | |
| ref: ${{ steps.tag.outputs.tag }} | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.target }} | |
| - name: Install cross (Linux only) | |
| if: matrix.use-cross | |
| run: cargo install cross --locked | |
| - name: Build | |
| shell: bash | |
| working-directory: ${{ env.WORKSPACE_DIR }} | |
| run: | | |
| if [ "${{ matrix.use-cross }}" = "true" ]; then | |
| cross build --release --target ${{ matrix.target }} -p "${CLI_CRATE_PATH##*/}" | |
| else | |
| cargo build --release --target ${{ matrix.target }} -p "${CLI_CRATE_PATH##*/}" | |
| fi | |
| - name: Package | |
| shell: bash | |
| run: | | |
| STAGE=$(mktemp -d) | |
| TAG="${{ steps.tag.outputs.tag }}" | |
| BASE="${RELEASE_NAME}-${TAG#v}-${{ matrix.target }}" | |
| mkdir -p "$STAGE/$BASE" | |
| if [ "${{ matrix.target }}" = "x86_64-pc-windows-msvc" ]; then | |
| cp "${WORKSPACE_DIR}/target/${{ matrix.target }}/release/${BIN_NAME}.exe" "$STAGE/$BASE/" | |
| else | |
| cp "${WORKSPACE_DIR}/target/${{ matrix.target }}/release/${BIN_NAME}" "$STAGE/$BASE/" | |
| fi | |
| cp LICENSE README.md "$STAGE/$BASE/" 2>/dev/null || true | |
| cd "$STAGE" | |
| if [ "${{ matrix.archive }}" = "zip" ]; then | |
| (cd "$BASE" && 7z a -tzip "../${BASE}.zip" .) | |
| mv "${BASE}.zip" "${{ github.workspace }}/" | |
| (cd "${{ github.workspace }}" && shasum -a 256 "${BASE}.zip" > "${BASE}.zip.sha256") | |
| else | |
| tar czf "${BASE}.tar.gz" "$BASE" | |
| mv "${BASE}.tar.gz" "${{ github.workspace }}/" | |
| (cd "${{ github.workspace }}" && shasum -a 256 "${BASE}.tar.gz" > "${BASE}.tar.gz.sha256") | |
| fi | |
| ls -la "${{ github.workspace }}"/*${BASE}* | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ env.RELEASE_NAME }}-${{ matrix.target }} | |
| path: | | |
| ${{ env.RELEASE_NAME }}-*-${{ matrix.target }}.tar.gz* | |
| ${{ env.RELEASE_NAME }}-*-${{ matrix.target }}.zip* | |
| release: | |
| name: Publish Release | |
| needs: build | |
| # Publish whatever built. With fail-fast:false the matrix legs are | |
| # independent; if an unverified target (e.g. musl/windows) fails, the | |
| # platforms that did build still ship. An empty dist still fails below | |
| # via fail_on_unmatched_files, so a total build failure is not masked. | |
| if: ${{ always() }} | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: artifacts | |
| - name: Collect | |
| run: | | |
| mkdir -p dist | |
| find artifacts -type f \( -name '*.tar.gz' -o -name '*.zip' -o -name '*.sha256' \) -exec mv {} dist/ \; | |
| ls -la dist/ | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| files: dist/* | |
| generate_release_notes: true | |
| fail_on_unmatched_files: true |