homeMaker Vision Alignment: strip dev UI, home AI agent, product identity #3
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
| # SECURITY: This workflow is hardened against fork PR attacks. See docs/security/ci-hardening.md | |
| name: Auto Release | |
| # Fires when a staging→main PR is merged. Creates a git tag and GitHub Release | |
| # from the version already bumped on staging by prepare-release.yml. | |
| # | |
| # Flow: prepare-release.yml bumps version on staging → staging→main PR merges | |
| # → this workflow tags main and creates the GitHub Release. | |
| # | |
| # NOTE: To allow the v* tag push to trigger build-electron.yml, this workflow | |
| # must use a PAT (stored as GH_PAT secret) rather than the default GITHUB_TOKEN. | |
| # GitHub blocks cross-workflow event chains when using GITHUB_TOKEN to prevent | |
| # infinite loops. If GH_PAT is not set, the tag push will succeed but | |
| # build-electron.yml will not fire automatically. | |
| on: | |
| pull_request: | |
| types: [closed] | |
| branches: | |
| - main | |
| workflow_dispatch: | |
| permissions: read-all | |
| jobs: | |
| release: | |
| runs-on: self-hosted | |
| if: >- | |
| (github.event_name == 'workflow_dispatch') || | |
| (github.event.pull_request.merged == true && | |
| github.event.pull_request.head.ref == 'staging' && | |
| github.repository == 'protoLabsAI/protoMaker') | |
| timeout-minutes: 10 | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| env: | |
| DISCORD_DEV_WEBHOOK: ${{ secrets.DISCORD_DEV_WEBHOOK }} | |
| DISCORD_ALERTS_WEBHOOK: ${{ secrets.DISCORD_ALERTS_WEBHOOK }} | |
| steps: | |
| - name: Verify GH_PAT is set | |
| run: | | |
| if [ -z "${{ secrets.GH_PAT }}" ]; then | |
| echo "WARNING: GH_PAT secret is not set." | |
| echo "The v* tag push will fall back to GITHUB_TOKEN." | |
| echo "build-electron.yml will NOT fire automatically." | |
| echo "Set GH_PAT in repository secrets to enable the release → Electron build chain." | |
| else | |
| echo "GH_PAT is configured — release → Electron build chain is active." | |
| fi | |
| - name: Checkout | |
| uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ secrets.GH_PAT || secrets.GITHUB_TOKEN }} | |
| - name: Setup project | |
| uses: ./.github/actions/setup-project | |
| with: | |
| skip-native-rebuild: 'true' | |
| - name: Configure git | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| - name: Get version | |
| id: version | |
| # Version was already bumped on staging by prepare-release.yml. | |
| # Read it from the merged content on main. | |
| run: | | |
| VERSION=$(node -p "require('./libs/types/package.json').version") | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "Detected version: v${VERSION}" | |
| # Verify this version isn't already tagged | |
| if git tag -l "v${VERSION}" | grep -q "v${VERSION}"; then | |
| echo "already_tagged=true" >> $GITHUB_OUTPUT | |
| echo "WARNING: v${VERSION} is already tagged. Skipping." | |
| else | |
| echo "already_tagged=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Create tag | |
| if: steps.version.outputs.already_tagged != 'true' | |
| run: | | |
| VERSION="v${{ steps.version.outputs.version }}" | |
| git tag -a "$VERSION" -m "$VERSION" | |
| git push origin "$VERSION" | |
| - name: Create GitHub Release | |
| if: steps.version.outputs.already_tagged != 'true' | |
| run: | | |
| VERSION="v${{ steps.version.outputs.version }}" | |
| # Generate notes, then filter out chore PRs (unless they're the only entries) | |
| RAW_NOTES=$(gh api "repos/${{ github.repository }}/releases/generate-notes" \ | |
| -f tag_name="$VERSION" --jq '.body') | |
| # Extract "What's Changed" lines (PR entries start with "* ") | |
| ALL_LINES=$(echo "$RAW_NOTES" | grep '^\* ' || true) | |
| NON_CHORE=$(echo "$ALL_LINES" | grep -vi '^\* chore' || true) | |
| if [ -n "$NON_CHORE" ]; then | |
| # Has real changes — filter out chores | |
| FILTERED_NOTES=$(echo "$RAW_NOTES" | grep -vi '^\* chore') | |
| else | |
| # Only chores — keep them so the release isn't empty | |
| FILTERED_NOTES="$RAW_NOTES" | |
| fi | |
| gh release create "$VERSION" \ | |
| --title "$VERSION Alpha" \ | |
| --notes "$FILTERED_NOTES" | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Rewrite and post release notes to Discord | |
| if: steps.version.outputs.already_tagged != 'true' && env.DISCORD_DEV_WEBHOOK != '' | |
| continue-on-error: true | |
| run: | | |
| VERSION="v${{ steps.version.outputs.version }}" | |
| PREV_TAG=$(git tag --sort=-v:refname | grep -v "^${VERSION}$" | head -1) | |
| node scripts/rewrite-release-notes.mjs "$VERSION" "$PREV_TAG" --post-discord | |
| env: | |
| ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} | |
| - name: Sync main back to staging | |
| if: steps.version.outputs.already_tagged != 'true' | |
| run: | | |
| # After tagging, merge main back into staging so staging has | |
| # the merge commit. Without this, the next staging→main promotion | |
| # diverges on package.json versions and creates merge conflicts. | |
| echo "Syncing main back to staging..." | |
| git fetch origin staging | |
| git checkout staging | |
| git merge origin/main --no-edit -m "chore: sync main merge commit back to staging" | |
| git push origin staging | |
| echo "Staging synced with main" | |
| - name: Sync main back to dev | |
| if: steps.version.outputs.already_tagged != 'true' | |
| continue-on-error: true | |
| run: | | |
| # Also sync to dev to keep all three branches aligned | |
| echo "Syncing main back to dev..." | |
| git fetch origin dev | |
| git checkout dev | |
| git merge origin/main --no-edit -m "chore: sync main merge commit back to dev" | |
| git push origin dev | |
| echo "Dev synced with main" | |
| - name: Alert on skipped release | |
| if: steps.version.outputs.already_tagged == 'true' | |
| run: | | |
| VERSION="v${{ steps.version.outputs.version }}" | |
| RUN_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" | |
| MSG="Release SKIPPED: ${VERSION} is already tagged. Was prepare-release.yml run before promotion? ${RUN_URL}" | |
| echo "::error::${MSG}" | |
| if [ -n "${DISCORD_ALERTS_WEBHOOK:-}" ]; then | |
| curl -sf -H "Content-Type: application/json" \ | |
| -d "{\"content\": \"${MSG}\"}" \ | |
| "$DISCORD_ALERTS_WEBHOOK" || true | |
| fi | |
| exit 1 | |
| - name: Alert on release failure | |
| if: failure() && steps.version.outputs.already_tagged != 'true' | |
| run: | | |
| RUN_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" | |
| MSG="ALERT: Auto-release FAILED. Tag or GitHub Release may be incomplete. ${RUN_URL}" | |
| if [ -n "${DISCORD_ALERTS_WEBHOOK:-}" ]; then | |
| curl -sf -H "Content-Type: application/json" \ | |
| -d "{\"content\": \"${MSG}\"}" \ | |
| "$DISCORD_ALERTS_WEBHOOK" || true | |
| fi |