Skip to content

Harden publish workflow recovery, notifications, and dispatch guard - #199

Merged
glenn-jocher merged 4 commits into
mainfrom
publish-recovery
Jul 4, 2026
Merged

Harden publish workflow recovery, notifications, and dispatch guard#199
glenn-jocher merged 4 commits into
mainfrom
publish-recovery

Conversation

@glenn-jocher

@glenn-jocher glenn-jocher commented Jul 4, 2026

Copy link
Copy Markdown
Member

🛠️ Summary

Ports three robustness fixes to publish.yml that came out of adversarial review rounds on ultralytics/template#91. The release pipeline previously had no recovery path after a partial failure, and Slack could report success before the pipeline actually finished.

1. Failed releases can now be recovered via workflow_dispatch

Previously, once the tag was pushed, any downstream failure (build, PyPI upload, SBOM) left the release unrecoverable: a re-run hit git tag -a on the existing tag and the check job died. Now:

  • workflow_dispatch always sets increment=True (manual recovery re-run)
  • Tagging is skipped when the tag already exists on origin (git ls-remote)
  • Release summarization is gated independently on release existence (gh release view), healing the tag-pushed-but-no-release state
  • PyPI upload uses skip-existing: true so re-runs tolerate already-uploaded dists
  • SBOM upload uses --clobber so re-runs can overwrite

A partially failed release can be re-run from any point and completes only what's missing.

2. Slack success can no longer fire prematurely

notify now includes sbom in needs and in the success/failure conditions, so the ✅ message reflects the entire pipeline rather than racing the SBOM job.

3. workflow_dispatch can no longer release a non-main commit

The check job now requires github.ref == 'refs/heads/main'; previously a dispatch from a feature branch could tag and release a commit that never landed on main.

🧪 Testing

🛠️ PR Summary

Made with ❤️ by Ultralytics Actions

🌟 Summary

Improves the PyPI release workflow to be safer, recoverable, and more reliable on reruns 🚀

📊 Key Changes

  • Restricts the release check job to run only on the main branch for the ultralytics/mkdocs repo and authorized actor 🔒
  • Adds support for manual PyPI dispatch recovery via a PYPI_DISPATCH input 🛠️
  • Prevents duplicate Git tags and GitHub releases by checking whether they already exist before creating them 🏷️
  • Improves release summary behavior by falling back to Git history when the previous tag is unavailable 📜
  • Enables PyPI publishing with skip-existing: true to tolerate reruns after partial failures 📦
  • Updates SBOM upload to use --clobber, allowing existing SBOM files to be replaced on reruns 📄
  • Makes Slack notifications depend on both publish and SBOM job results ✅

🎯 Purpose & Impact

  • Makes releases more robust by avoiding failures caused by existing tags, releases, PyPI files, or SBOM uploads 🔁
  • Improves recovery from interrupted or partially failed release workflows without requiring manual cleanup 🧯
  • Reduces risk of accidental publishing from non-main branches 🌿
  • Provides more accurate team notifications by reporting success only when both publishing and SBOM generation complete successfully 📣
  • Helps maintain smoother, safer documentation package releases for the Ultralytics MkDocs workflow ⚡

@UltralyticsAssistant UltralyticsAssistant added devops GitHub Devops or MLops fixed Bug has been resolved labels Jul 4, 2026
@UltralyticsAssistant

Copy link
Copy Markdown
Member

👋 Hello @glenn-jocher, thank you for submitting a ultralytics/mkdocs 🚀 PR! This automated message confirms your PR has been received, and an Ultralytics engineer will assist with review. To ensure a seamless integration of your workflow hardening changes, please review the following checklist:

  • Define a Purpose: Clearly explain the purpose of your fix or feature in your PR description, and link to any relevant issues. Ensure your commit messages are clear, concise, and adhere to the project's conventions.
  • Synchronize with Source: Confirm your PR is synchronized with the ultralytics/mkdocs main branch. If it's behind, update it by clicking the 'Update branch' button or by running git pull and git merge main locally.
  • Ensure CI Checks Pass: Verify all Ultralytics Continuous Integration (CI) checks are passing. If any checks fail, please address the issues.
  • Update Documentation: Update the relevant documentation for any new or modified features.
  • Add Tests: If applicable, include or update tests to cover your changes, and confirm that all tests are passing.
  • Sign the CLA: Please ensure you have signed our Contributor License Agreement if this is your first Ultralytics PR by writing "I have read the CLA Document and I sign the CLA" in a new message.
  • Minimize Changes: Limit your changes to the minimum necessary for your bug fix or feature addition. "It is not daily increase but daily decrease, hack away the unessential. The closer to the source, the less wastage there is." — Bruce Lee

For more guidance, please refer to our Contributing Guide. Don't hesitate to leave a comment if you have any questions. Thank you for contributing to Ultralytics! 🚀

@UltralyticsAssistant UltralyticsAssistant left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🔍 PR Review

Made with ❤️ by Ultralytics Actions

The workflow changes generally improve rerun tolerance and notification accuracy. One issue needs attention: the new manual recovery override ignores the existing pypi dispatch input, so any manual run on main triggers the publish path.

💬 Posted 1 inline comment

Comment thread .github/workflows/publish.yml Outdated
import os
from actions.utils import check_pypi_version
local_version, online_version, publish = check_pypi_version()
publish = publish or os.environ.get("GITHUB_EVENT_NAME") == "workflow_dispatch" # manual recovery re-run

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

💡 MEDIUM: This makes every manual dispatch on main set increment=True, even when the workflow_dispatch pypi input is left false/unchecked. Because that input is the only manual guard exposed by the workflow, an accidental dispatch would still proceed through tag/release creation, PyPI publish with skip-existing, SBOM upload, and failure notifications. Please include the dispatch input in this override so only an explicit recovery/publish request bypasses the PyPI version check.

@glenn-jocher
glenn-jocher merged commit a293c63 into main Jul 4, 2026
4 checks passed
@glenn-jocher
glenn-jocher deleted the publish-recovery branch July 4, 2026 19:02
@UltralyticsAssistant

Copy link
Copy Markdown
Member

Merged — thank you @glenn-jocher! 🚀

“Success is not final, failure is not fatal: it is the courage to continue that counts.” — Winston Churchill

This PR brings that spirit directly into the PyPI release workflow by making releases safer, rerunnable, and easier to recover from after partial failures. The added safeguards around main-only publishing, authorized dispatch, duplicate tag/release prevention, skip-existing PyPI uploads, SBOM clobbering, and more accurate Slack notifications will help keep Ultralytics MkDocs releases reliable and low-friction.

Great work strengthening the release pipeline for the team and community! 🙌

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

devops GitHub Devops or MLops fixed Bug has been resolved

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants