Skip to content

Curated build

Curated build #6

Workflow file for this run

# BonsaiPR — curated build
#
# Runs a *curated* BonsaiPR instance from a profile (RFC-001). Unlike the
# canonical instance, which builds every open non-draft PR, this builds only the
# PRs its profile selects — which is what makes it a distinct federation
# publisher rather than a second copy of the same answer.
#
# Manual-first on purpose: the schedule below is commented out. Run it by hand
# from the Actions tab until a full run has been seen to work end to end.
#
# Setup: see .github/workflows/README-curated-build.md
name: Curated build
on:
workflow_dispatch:
inputs:
profile:
description: "Profile name from profiles/ (without .json)"
required: true
default: openingdesign
stages:
description: "How much of the pipeline to run"
required: true
default: full
type: choice
options: [full, manifest-only]
# Enable once a manual run has succeeded. Every 6 hours:
# schedule:
# - cron: "0 */6 * * *"
concurrency:
# Two overlapping runs would fight over the same force-pushed build branch.
group: curated-build
cancel-in-progress: false
jobs:
build:
runs-on: ubuntu-latest
# A curated profile merges far fewer PRs than the canonical 847, but each
# merge fetches from a different contributor's fork, and that dominates.
timeout-minutes: 330
env:
BONSAIPR_PROFILE: ${{ inputs.profile }}
# Where releases and the extension index are published.
GITHUB_OWNER: ${{ vars.BONSAIPR_OWNER || 'OpeningDesign' }}
GITHUB_REPO: ${{ vars.BONSAIPR_REPO || 'bonsaiPR' }}
# Fork that receives the force-pushed build branch. MUST be a fork you own
# — the push is `--force` and will overwrite whatever is there.
FORK_OWNER: ${{ vars.BONSAIPR_FORK_OWNER || 'OpeningDesign' }}
FORK_REPO: ${{ vars.BONSAIPR_FORK_REPO || 'IfcOpenShell' }}
# Upstream being curated.
SOURCE_REPO_OWNER: IfcOpenShell
SOURCE_REPO_NAME: IfcOpenShell
SOURCE_BASE_BRANCH: v0.8.0
# Runner paths. BASE_CLONE_DIR is checked out, reset, branch-deleted and
# force-pushed from — it must never point at a repo anyone is working in.
BASE_CLONE_DIR: ${{ github.workspace }}/work/IfcOpenShell
BUILD_BASE_DIR: ${{ github.workspace }}/work/bonsaiPR-build
WORKING_DIR: ${{ github.workspace }}/work/MergingPR
REPORT_PATH: ${{ github.workspace }}/work/reports
# A curated profile is an explicit list; author filtering is not wanted.
USERNAMES: ""
EXCLUDED: ""
steps:
- name: Check out the automation
uses: actions/checkout@v4
with:
# commit_reports.py pushes report/state files back to this repo.
token: ${{ secrets.BONSAIPR_TOKEN }}
fetch-depth: 0
- name: Reclaim runner disk
# The IfcOpenShell clone plus per-platform build trees do not
# comfortably fit alongside the runner's preinstalled toolchains.
run: |
echo "before:"; df -h / | tail -1
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc \
/usr/local/share/boost "$AGENT_TOOLSDIRECTORY" || true
echo "after:"; df -h / | tail -1
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Set up Node
# Stage 1 runs `npm install` while packaging the add-on.
uses: actions/setup-node@v4
with:
node-version: "20"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r automation/requirements.txt
sudo apt-get update -qq
sudo apt-get install -y --no-install-recommends zip make
- name: Verify the profile resolves
# Fail before doing 40 minutes of merging if the curation is malformed.
working-directory: automation/scripts
run: |
python bonsaipr_profile.py show "$BONSAIPR_PROFILE"
- name: Configure git
run: |
git config --global user.name "bonsaiPR automation"
git config --global user.email "actions@users.noreply.github.com"
git config --global credential.helper store
echo "https://x-access-token:${{ secrets.BONSAIPR_TOKEN }}@github.com" \
> ~/.git-credentials
- name: Run the pipeline
env:
GITHUB_TOKEN: ${{ secrets.BONSAIPR_TOKEN }}
# Stage 0 writes state.<order>.json itself when stage 2 will not run.
# Never set for `full`, or stage 2 would diff the snapshot against
# itself and the release body would lose its delta section.
BONSAIPR_WRITE_STATE: ${{ inputs.stages == 'manifest-only' && '1' || '' }}
working-directory: automation/src
run: |
# NOT BASE_CLONE_DIR — stage 0 clones into it, and pre-creating it
# makes the script take its "update existing repo" path instead.
mkdir -p "$(dirname "$BASE_CLONE_DIR")" "$BUILD_BASE_DIR" "$WORKING_DIR" "$REPORT_PATH"
if [ "${{ inputs.stages }}" = "manifest-only" ]; then
# Stage 0 alone produces everything federation consumes: the report,
# state.<order>.json and rivals.<order>.json. Stages 1-2 only add
# installable zips and a release.
cd ../scripts && python 00_clone_merge_and_create_branch.py
else
python main.py
fi
- name: Aggregate own signals
# Cheap, and it means a failed federation step never costs a build.
continue-on-error: true
working-directory: automation/scripts
run: python federate.py aggregate
- name: Publish reports
env:
GITHUB_TOKEN: ${{ secrets.BONSAIPR_TOKEN }}
BONSAIPR_REPORTS_PUSH: "1"
working-directory: automation/scripts
run: python commit_reports.py || echo "no report changes to publish"
- name: Upload run artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: curated-build-${{ inputs.profile }}
retention-days: 14
path: |
automation/reports/
federation/
work/reports/
if-no-files-found: ignore