name: build release
permissions:
"contents": "write"
on:
workflow_call:
inputs:
tag:
required: true
type: string
jobs:
plan:
runs-on: "ubuntu-22.04"
outputs:
val: ${{ steps.plan.outputs.manifest }}
tag: ${{ inputs.tag }}
tag-flag: ${{ format('--tag={0}', inputs.tag) }}
publishing: true
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v6
with:
ref: ${{ inputs.tag }}
persist-credentials: false
submodules: recursive
- name: Install dist
shell: bash
run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.31.0/cargo-dist-installer.sh | sh"
- name: Cache dist
uses: actions/upload-artifact@v6
with:
name: cargo-dist-cache
path: ~/.cargo/bin/dist
- id: plan
run: |
dist host --steps=create --tag=${{ inputs.tag }} --output-format=json > plan-dist-manifest.json
echo "dist ran successfully"
cat plan-dist-manifest.json
echo "manifest=$(jq -c "." plan-dist-manifest.json)" >> "$GITHUB_OUTPUT"
- name: "Upload dist-manifest.json"
uses: actions/upload-artifact@v6
with:
name: artifacts-plan-dist-manifest
path: plan-dist-manifest.json
build-local-artifacts:
name: build-local-artifacts (${{ join(matrix.targets, ', ') }})
needs:
- plan
if: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix.include != null && (needs.plan.outputs.publishing == 'true' || fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload') }}
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.plan.outputs.val || '{"ci":{"github":{"artifacts_matrix":{"include":[]}}}}').ci.github.artifacts_matrix }}
runs-on: ${{ matrix.runner }}
container: ${{ matrix.container && matrix.container.image || null }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CURSEFORGE_API_KEY: ${{ secrets.CURSEFORGE_API_KEY }}
BUILD_MANIFEST_NAME: target/distrib/${{ join(matrix.targets, '-') }}-dist-manifest.json
steps:
- name: enable windows longpaths
run: |
git config --global core.longpaths true
- uses: actions/checkout@v6
with:
ref: ${{ inputs.tag }}
persist-credentials: false
submodules: recursive
- name: Install Rust non-interactively if not already installed
if: ${{ matrix.container }}
run: |
if ! command -v cargo > /dev/null 2>&1; then
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
fi
- name: "install JDK"
uses: "actions/setup-java@v5"
with:
"distribution": "temurin"
"java-version": "21"
- name: Install dist
run: ${{ matrix.install_dist.run }}
- name: Fetch local artifacts
uses: actions/download-artifact@v7
with:
pattern: artifacts-*
path: target/distrib/
merge-multiple: true
- name: Install dependencies
run: |
${{ matrix.packages_install }}
- name: Build artifacts
run: |
# Actually do builds and make zips and whatnot
dist build ${{ needs.plan.outputs.tag-flag }} --print=linkage --output-format=json ${{ matrix.dist_args }} > dist-manifest.json
echo "dist ran successfully"
- id: cargo-dist
name: Post-build
shell: bash
run: |
# Parse out what we just built and upload it to scratch storage
echo "paths<<EOF" >> "$GITHUB_OUTPUT"
dist print-upload-files-from-manifest --manifest dist-manifest.json >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
cp dist-manifest.json "$BUILD_MANIFEST_NAME"
- name: "Upload artifacts"
uses: actions/upload-artifact@v6
with:
name: artifacts-build-local-${{ join(matrix.targets, '_') }}
path: |
${{ steps.cargo-dist.outputs.paths }}
${{ env.BUILD_MANIFEST_NAME }}
build-global-artifacts:
needs:
- plan
- build-local-artifacts
runs-on: "ubuntu-22.04"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BUILD_MANIFEST_NAME: target/distrib/global-dist-manifest.json
steps:
- uses: actions/checkout@v6
with:
ref: ${{ inputs.tag }}
persist-credentials: false
submodules: recursive
- name: Install cached dist
uses: actions/download-artifact@v7
with:
name: cargo-dist-cache
path: ~/.cargo/bin/
- run: chmod +x ~/.cargo/bin/dist
- name: Fetch local artifacts
uses: actions/download-artifact@v7
with:
pattern: artifacts-*
path: target/distrib/
merge-multiple: true
- id: cargo-dist
shell: bash
run: |
dist build ${{ needs.plan.outputs.tag-flag }} --output-format=json "--artifacts=global" > dist-manifest.json
echo "dist ran successfully"
# Parse out what we just built and upload it to scratch storage
echo "paths<<EOF" >> "$GITHUB_OUTPUT"
jq --raw-output ".upload_files[]" dist-manifest.json >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
cp dist-manifest.json "$BUILD_MANIFEST_NAME"
- name: "Upload artifacts"
uses: actions/upload-artifact@v6
with:
name: artifacts-build-global
path: |
${{ steps.cargo-dist.outputs.paths }}
${{ env.BUILD_MANIFEST_NAME }}
host:
needs:
- plan
- build-local-artifacts
- build-global-artifacts
if: ${{ always() && needs.plan.result == 'success' && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.build-local-artifacts.result == 'skipped' || needs.build-local-artifacts.result == 'success') }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
runs-on: "ubuntu-22.04"
outputs:
val: ${{ steps.host.outputs.manifest }}
steps:
- uses: actions/checkout@v6
with:
ref: ${{ inputs.tag }}
persist-credentials: false
submodules: recursive
fetch-depth: 0
fetch-tags: true
- name: Install cached dist
uses: actions/download-artifact@v7
with:
name: cargo-dist-cache
path: ~/.cargo/bin/
- run: chmod +x ~/.cargo/bin/dist
- name: Fetch artifacts
uses: actions/download-artifact@v7
with:
pattern: artifacts-*
path: target/distrib/
merge-multiple: true
- id: host
shell: bash
run: |
dist host ${{ needs.plan.outputs.tag-flag }} --steps=upload --steps=release --output-format=json > dist-manifest.json
echo "artifacts uploaded and released successfully"
cat dist-manifest.json
echo "manifest=$(jq -c "." dist-manifest.json)" >> "$GITHUB_OUTPUT"
- name: "Upload dist-manifest.json"
uses: actions/upload-artifact@v6
with:
name: artifacts-dist-manifest
path: dist-manifest.json
- name: "Download GitHub Artifacts"
uses: actions/download-artifact@v7
with:
pattern: artifacts-*
path: artifacts
merge-multiple: true
- name: Cleanup
run: |
# Remove internal cargo-dist manifests from the public GitHub Release.
rm -f artifacts/*-dist-manifest.json artifacts/dist-manifest.json
- name: Generate changelog
id: changelog
uses: orhun/git-cliff-action@v4
with:
args: --latest --strip header
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Create GitHub Release
env:
PRERELEASE_FLAG: "${{ fromJson(steps.host.outputs.manifest).announcement_is_prerelease && '--prerelease' || '' }}"
ANNOUNCEMENT_TITLE: "${{ fromJson(steps.host.outputs.manifest).announcement_title }}"
RELEASE_COMMIT: "${{ github.sha }}"
CHANGELOG: "${{ steps.changelog.outputs.content }}"
RELEASE_TAG: "${{ needs.plan.outputs.tag }}"
APP_VERSION: "${{ fromJson(steps.host.outputs.manifest).releases[0].app_version }}"
run: |
echo "$CHANGELOG" > $RUNNER_TEMP/notes.txt
cat >> $RUNNER_TEMP/notes.txt <<EOF
## downloads
| File | Platform | Checksum |
| --- | --- | --- |
| [rmcl-aarch64-apple-darwin.tar.xz](https://github.com/objz/rmcl/releases/download/${RELEASE_TAG}/rmcl-aarch64-apple-darwin.tar.xz) | Apple Silicon macOS | [checksum](https://github.com/objz/rmcl/releases/download/${RELEASE_TAG}/rmcl-aarch64-apple-darwin.tar.xz.sha256) |
| [rmcl-x86_64-apple-darwin.tar.xz](https://github.com/objz/rmcl/releases/download/${RELEASE_TAG}/rmcl-x86_64-apple-darwin.tar.xz) | Intel macOS | [checksum](https://github.com/objz/rmcl/releases/download/${RELEASE_TAG}/rmcl-x86_64-apple-darwin.tar.xz.sha256) |
| [rmcl-x86_64-pc-windows-msvc.zip](https://github.com/objz/rmcl/releases/download/${RELEASE_TAG}/rmcl-x86_64-pc-windows-msvc.zip) | x64 Windows | [checksum](https://github.com/objz/rmcl/releases/download/${RELEASE_TAG}/rmcl-x86_64-pc-windows-msvc.zip.sha256) |
| [rmcl-x86_64-pc-windows-msvc.msi](https://github.com/objz/rmcl/releases/download/${RELEASE_TAG}/rmcl-x86_64-pc-windows-msvc.msi) | x64 Windows | [checksum](https://github.com/objz/rmcl/releases/download/${RELEASE_TAG}/rmcl-x86_64-pc-windows-msvc.msi.sha256) |
| [rmcl-aarch64-unknown-linux-gnu.tar.xz](https://github.com/objz/rmcl/releases/download/${RELEASE_TAG}/rmcl-aarch64-unknown-linux-gnu.tar.xz) | ARM64 Linux | [checksum](https://github.com/objz/rmcl/releases/download/${RELEASE_TAG}/rmcl-aarch64-unknown-linux-gnu.tar.xz.sha256) |
| [rmcl-x86_64-unknown-linux-gnu.tar.xz](https://github.com/objz/rmcl/releases/download/${RELEASE_TAG}/rmcl-x86_64-unknown-linux-gnu.tar.xz) | x64 Linux | [checksum](https://github.com/objz/rmcl/releases/download/${RELEASE_TAG}/rmcl-x86_64-unknown-linux-gnu.tar.xz.sha256) |
## installation
release archives and installers are attached above. package-manager releases can take a little longer to become available.
### Cargo
\`\`\`
cargo install rmcl
\`\`\`
### Homebrew
\`\`\`
brew install objz/tap/rmcl
\`\`\`
### WinGet
\`\`\`
winget install Objz.Rmcl
\`\`\`
The generated WinGet manifest is attached as \`winget-manifest-${APP_VERSION}.zip\` for local validation.
### AUR
\`\`\`
paru -S rmcl-bin
\`\`\`
EOF
gh release create "${{ needs.plan.outputs.tag }}" --target "$RELEASE_COMMIT" $PRERELEASE_FLAG --title "$ANNOUNCEMENT_TITLE" --notes-file "$RUNNER_TEMP/notes.txt" artifacts/*
publish-homebrew-formula:
needs:
- plan
- host
runs-on: "ubuntu-22.04"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PLAN: ${{ needs.plan.outputs.val }}
HOMEBREW_TAP_REPOSITORY: "objz/homebrew-tap"
GITHUB_USER: "axo bot"
GITHUB_EMAIL: "admin+bot@axo.dev"
if: ${{ !fromJson(needs.plan.outputs.val).announcement_is_prerelease || fromJson(needs.plan.outputs.val).publish_prereleases }}
steps:
- uses: actions/checkout@v6
with:
persist-credentials: true
repository: ${{ env.HOMEBREW_TAP_REPOSITORY }}
token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
- name: Fetch homebrew formulae
uses: actions/download-artifact@v7
with:
pattern: artifacts-*
path: Formula/
merge-multiple: true
- name: Commit formula files
run: |
git config --global user.name "${GITHUB_USER}"
git config --global user.email "${GITHUB_EMAIL}"
starting_commit="$(git rev-parse HEAD)"
for release in $(echo "$PLAN" | jq --compact-output '.releases[] | select([.artifacts[] | endswith(".rb")] | any)'); do
filename=$(echo "$release" | jq '.artifacts[] | select(endswith(".rb"))' --raw-output)
name=$(echo "$filename" | sed "s/\.rb$//")
version=$(echo "$release" | jq .app_version --raw-output)
export PATH="/home/linuxbrew/.linuxbrew/bin:$PATH"
brew update
# We avoid reformatting user-provided data such as the app description and homepage.
brew style --except-cops FormulaAudit/Homepage,FormulaAudit/Desc,FormulaAuditStrict --fix "Formula/${filename}" || true
git add "Formula/${filename}"
if git diff --cached --quiet; then
echo "Formula/${filename} is unchanged"
else
git commit -m "${name} ${version}"
fi
done
if [ "$(git rev-parse HEAD)" = "$starting_commit" ]; then
echo "No Homebrew formula changes to push"
else
git push
fi
custom-publish-crates:
needs:
- plan
- host
if: ${{ !fromJson(needs.plan.outputs.val).announcement_is_prerelease || fromJson(needs.plan.outputs.val).publish_prereleases }}
uses: ./.github/workflows/publish-crates.yml
with:
plan: ${{ needs.plan.outputs.val }}
dry_run: false
secrets: inherit
permissions:
"contents": "read"
custom-publish-aur:
needs:
- plan
- host
if: ${{ !fromJson(needs.plan.outputs.val).announcement_is_prerelease || fromJson(needs.plan.outputs.val).publish_prereleases }}
uses: ./.github/workflows/publish-aur.yml
with:
plan: ${{ needs.plan.outputs.val }}
secrets: inherit
permissions:
"contents": "read"
custom-publish-winget:
needs:
- plan
- host
if: ${{ !fromJson(needs.plan.outputs.val).announcement_is_prerelease || fromJson(needs.plan.outputs.val).publish_prereleases }}
uses: ./.github/workflows/publish-winget.yml
with:
plan: ${{ needs.plan.outputs.val }}
secrets: inherit
permissions:
"contents": "write"
announce:
needs:
- plan
- host
- publish-homebrew-formula
- custom-publish-crates
- custom-publish-aur
- custom-publish-winget
if: ${{ always() && needs.host.result == 'success' && (needs.publish-homebrew-formula.result == 'skipped' || needs.publish-homebrew-formula.result == 'success') && (needs.custom-publish-crates.result == 'skipped' || needs.custom-publish-crates.result == 'success') && (needs.custom-publish-aur.result == 'skipped' || needs.custom-publish-aur.result == 'success') && (needs.custom-publish-winget.result == 'skipped' || needs.custom-publish-winget.result == 'success') }}
runs-on: "ubuntu-22.04"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
submodules: recursive