Skip to content

fix: Package-and-Upload workflow attaches binaries to UI-created releases - #459

Open
jacalata wants to merge 2 commits into
developmentfrom
jac/fix-package-workflow-upload
Open

fix: Package-and-Upload workflow attaches binaries to UI-created releases#459
jacalata wants to merge 2 commits into
developmentfrom
jac/fix-package-workflow-upload

Conversation

@jacalata

Copy link
Copy Markdown
Contributor

Motivation

Investigating why the v2.0.21 release page shipped with no executables attached, we found two bugs in the Package-and-Upload workflow. v2.0.19 had the same failure mode for the same reason.

Behavior change

Before: the "Upload binaries to release" step was gated on

if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')

Releases created via the GitHub UI create a tag but don't fire the push:tags: event that this workflow depends on. So the workflow only ran manually via workflow_dispatch afterward, built the binaries as workflow artifacts, and skipped the upload-to-release step because the if: guard requires push. The binaries were sitting in the artifact store for 90 days, never on the release.

Separately, both macOS build jobs used name: tabcmd-macos on actions/upload-artifact, so the two same-named artifacts collided in the artifact store and gh run download clobbered one with the other.

After:

  • New release_tag workflow_dispatch input. Set it when dispatching from a branch to attach binaries to a UI-created release. Falls back to github.ref_name when the workflow runs on a tag ref (push or dispatch).
  • Mac artifact collision fixed: matrix.UPLOAD_FILE_NAME (unique per platform) is now the artifact name instead of tabcmd-${{ matrix.TARGET }}.
  • Upload logic split into a new upload_to_release job that depends on buildexe, gated on environment: release. Anyone with dispatch access can trigger a build, but only an approved reviewer can attach binaries to a public release. Mirrors the existing pypi environment gate on this repo (PR security: add environment gate to production PyPI publish job #439).

Prerequisite before merging

The release environment already exists in this repo's Settings -> Environments with required-reviewer protection. Confirm it's still configured before merging; if it isn't, the upload_to_release job will run unguarded.

Test plan

  • Live-verified today via gh release upload v2.0.21 ... (with the artifacts downloaded from the last workflow_dispatch run) that the platform binaries were the right ones and could be attached to v2.0.21. The v2.0.21 release page now shows all four assets, retroactively fixed.
  • End-to-end verification after merge: for v2.0.22 or a test tag, either push a tag or create a UI release and dispatch the workflow with the release_tag input; confirm the approval gate fires and the four binaries end up on the release page.
  • Code review from code-reviewer agent — no blocking findings; added inline comments for the upload-artifact@v7 / download-artifact@v8 major mismatch (both are current best; upload@v8 doesn't exist yet) and the needs: buildexe all-matrix-legs-must-succeed semantics.

🤖 Generated with Claude Code

…ases

Two bugs found while investigating why v2.0.21 shipped without
executables attached:

1. The "Upload binaries to release" step was gated on
   `github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')`.
   Releases created via the GitHub UI create a tag but do not fire the
   push:tags: event that this workflow depends on, so v2.0.21 (and v2.0.19)
   ended up as releases with no assets. The only successful run for
   v2.0.21 was a workflow_dispatch afterward that built the binaries as
   artifacts but skipped the upload-to-release step.
2. Both macOS build jobs used `name: tabcmd-macos` on
   `actions/upload-artifact`, so the two same-named artifacts collided in
   the artifact store and downloads clobbered each other.

Fixes:

- New `release_tag` workflow_dispatch input. Set it when dispatching from
  a branch to attach binaries to a UI-created release. Falls back to
  `github.ref_name` when the workflow runs on a tag ref (push or dispatch).
- Fix mac artifact collision: use `matrix.UPLOAD_FILE_NAME` (unique per
  platform) as the artifact name instead of `tabcmd-${{ matrix.TARGET }}`.
- Split the upload into a separate `upload_to_release` job that depends on
  `buildexe`, gated on `environment: release`. The `release` environment
  needs to be created in the repo's Settings -> Environments with
  required-reviewer protection (mirroring the existing `pypi` environment).
  Anyone with dispatch access can trigger a build, but only an approved
  reviewer can attach binaries to a public release.
- Upload gate: `if: startsWith(github.ref, 'refs/tags/') || inputs.release_tag != ''`
  so both the push:tags path and the workflow_dispatch path work.

Live-verified by using `gh release upload` today to fix v2.0.21
retroactively with the artifacts from the last workflow_dispatch run.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 14, 2026

Copy link
Copy Markdown

Coverage

Coverage Report
FileStmtsMissCoverMissing
tabcmd
   __main__.py121212 0%
   _version.py111111 0%
   tabcmd.py151515 0%
   version.py955 44%
tabcmd/commands
   commands.py101010 0%
   constants.py771818 77%
   server.py1351818 87%
tabcmd/commands/auth
   session.py3945050 87%
tabcmd/commands/datasources_and_workbooks
   datasources_and_workbooks_command.py1571818 89%
   datasources_workbooks_views_url_parser.py14255 96%
   delete_command.py601616 73%
   export_command.py1202525 79%
   get_url_command.py1274747 63%
   publish_command.py1252929 77%
   runschedule_command.py2177 67%
tabcmd/commands/extracts
   create_extracts_command.py4288 81%
   decrypt_extracts_command.py2722 93%
   delete_extracts_command.py3766 84%
   encrypt_extracts_command.py2722 93%
   extracts.py2022 90%
   reencrypt_extracts_command.py2722 93%
   refresh_extracts_command.py481010 79%
tabcmd/commands/group
   create_group_command.py2955 83%
   delete_group_command.py2722 93%
tabcmd/commands/project
   create_project_command.py4688 83%
   delete_project_command.py3544 89%
   publish_samples_command.py3044 87%
tabcmd/commands/site
   create_site_command.py3455 85%
   delete_site_command.py2722 93%
   edit_site_command.py3822 95%
   list_command.py771212 84%
   list_sites_command.py2922 93%
tabcmd/commands/user
   add_users_command.py2955 83%
   create_site_users.py581111 81%
   create_users_command.py5999 85%
   delete_site_users_command.py4355 88%
   user_data.py2223131 86%
tabcmd/execution
   _version.py222 0%
   global_options.py12688 94%
   localize.py661111 83%
   logger_config.py6066 90%
   tabcmd_controller.py4277 83%
TOTAL287645984% 

- Switch to release: types: [published] as the trigger (matches
  publish-pypi.yml pattern). Removes the manual-dispatch-with-input
  footgun; release payload provides the tag directly.
- Add explicit permissions: contents: write on the upload job so it
  survives future org-default hardening.
- Add concurrency group keyed on the release tag; prevents overlapping
  runs from stomping each other's approved uploads.
- Pin download-artifact back to v7 to match upload-artifact@v7 until
  v7/v8 interop is verified.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 10, 2026 23:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Restore compatible dispatch behavior and resolve the release tag across all supported workflow paths.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Updates the packaging workflow to build platform binaries and upload them to releases through a reviewer-gated job.

Changes:

  • Adds unique artifact names to prevent macOS collisions.
  • Separates release uploads into a gated job.
  • Updates release-trigger and artifact-upload handling.

Review findings:

  • Moderate (3 votes): Removing workflow_dispatch breaks the existing release-on-merge caller and manual repair path.
  • Moderate (1 vote): Hard-coded github.event.release.tag_name is empty for dispatch and tag-ref workflows.
File summaries
File Description
.github/workflows/package.yml Updates workflow triggers, artifact naming, and release uploads.
Review details

Suppressed comments (1)

.github/workflows/package.yml:142

  • The upload job hard-codes github.event.release.tag_name, which is populated for the release event but not for the workflow-dispatch or tag-ref paths described in the PR. In those paths the upload action receives an empty target tag and cannot attach the artifacts to the release. Resolve a validated target tag from the dispatch input, release payload, or tag ref and reuse it for all uploads (and the concurrency group).
        tag: ${{ github.event.release.tag_name }}
  • Files reviewed: 1/1 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +12 to +13
release:
types: [published]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants