Skip to content

v0.17.0-rc.4

v0.17.0-rc.4 #10

---
name: Release Publish
# Publishes packages to PyPI and crates.io when a release is published.
#
# For stable releases: publishes to PyPI, crates.io, and updates Homebrew tap.
# For pre-releases: publishes to PyPI and crates.io only (no Homebrew tap).
# For dev releases: ALL jobs are skipped. (Dev releases do trigger this workflow
# when release-build.yaml publishes them, but every job gates on is_dev.)
#
# PUBLISH ORDER:
# 1. coglet -> PyPI (must be first, SDK depends on it)
# 2. coglet -> crates.io (parallel with coglet PyPI)
# 3. SDK -> PyPI (after coglet is on PyPI)
# 4. Homebrew cask (stable only, after all publishing completes)
#
# REQUIRED GITHUB CONFIGURATION:
# 1. Create environments in Settings -> Environments:
# - "pypi": For PyPI publishing (Trusted Publisher)
# - "crates-io": For crates.io publishing
# - "homebrew": For Homebrew tap updates
#
# 2. Configure environment protection rules:
# - Deployment branches: "Selected branches and tags"
# - Add pattern: v* (to restrict to version tags only)
#
# 3. crates-io uses Trusted Publishing (OIDC via rust-lang/crates-io-auth-action)
#
# 4. Homebrew tap uses the cog-homebrew-tapbot GitHub App (ID: 1232932405)
# - Secret: COG_HOMEBREW_TAP_PRIVATE_KEY (app's private key)
on:
release:
types: [published]
permissions:
contents: read
id-token: write
env:
CARGO_TERM_COLOR: always
jobs:
verify-release:
name: Verify release tag
runs-on: ubuntu-latest
timeout-minutes: 5
outputs:
is_dev: ${{ steps.check.outputs.is_dev }}
is_prerelease: ${{ steps.check.outputs.is_prerelease }}
version: ${{ steps.check.outputs.version }}
steps:
- name: Verify valid release tag
id: check
run: |
TAG="${{ github.event.release.tag_name }}"
# Release must be from a valid version tag
if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+ ]]; then
echo "::error::Invalid tag format: $TAG"
echo "::error::Tags must match pattern v*.*.* (e.g., v1.0.0)"
exit 1
fi
echo "✓ Valid release tag: $TAG"
VERSION="${TAG#v}"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
# Classify release type
IS_DEV="false"
IS_PRERELEASE="false"
if [[ "$VERSION" == *-dev* ]]; then
IS_DEV="true"
echo "Dev release detected - skipping all publishing"
elif [[ "$VERSION" == *-* ]]; then
IS_PRERELEASE="true"
echo "Pre-release detected - publishing to PyPI/crates.io (no Homebrew tap)"
else
echo "Stable release detected - full publishing including Homebrew tap"
fi
echo "is_dev=$IS_DEV" >> "$GITHUB_OUTPUT"
echo "is_prerelease=$IS_PRERELEASE" >> "$GITHUB_OUTPUT"
publish-pypi-coglet:
name: Publish coglet to PyPI
needs: verify-release
if: needs.verify-release.outputs.is_dev != 'true'
runs-on: ubuntu-latest
environment: pypi
timeout-minutes: 10
steps:
- name: Download coglet wheels from release
run: |
mkdir -p dist
gh release download "$TAG" -p "coglet-*.whl" -D dist -R "${{ github.repository }}"
env:
TAG: ${{ github.event.release.tag_name }}
GH_TOKEN: ${{ github.token }}
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
publish-crates-io:
name: Publish coglet to crates.io
needs: verify-release
if: needs.verify-release.outputs.is_dev != 'true'
runs-on: ubuntu-latest
environment: crates-io
timeout-minutes: 15
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v6
with:
ref: ${{ github.event.release.tag_name }}
- uses: dtolnay/rust-toolchain@stable
- uses: rust-lang/crates-io-auth-action@v1
id: auth
- name: Publish to crates.io
run: cargo publish -p coglet --manifest-path crates/Cargo.toml
env:
CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
publish-pypi-sdk:
name: Publish SDK to PyPI
needs: [verify-release, publish-pypi-coglet]
if: needs.verify-release.outputs.is_dev != 'true'
runs-on: ubuntu-latest
environment: pypi
timeout-minutes: 10
steps:
- name: Download SDK artifacts from release
run: |
mkdir -p dist
gh release download "$TAG" -p "cog-*.whl" -D dist -R "${{ github.repository }}"
gh release download "$TAG" -p "cog-*.tar.gz" -D dist -R "${{ github.repository }}"
env:
TAG: ${{ github.event.release.tag_name }}
GH_TOKEN: ${{ github.token }}
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
update-homebrew-tap:
name: Update Homebrew cask
needs: [verify-release, publish-pypi-sdk, publish-crates-io]
# Stable releases only — no dev, no pre-release
if: >-
needs.verify-release.outputs.is_dev != 'true' &&
needs.verify-release.outputs.is_prerelease != 'true'
runs-on: ubuntu-latest
environment: homebrew
timeout-minutes: 10
steps:
- name: Generate GitHub App token
id: app-token
uses: actions/create-github-app-token@v3
with:
app-id: 1232932405
private-key: ${{ secrets.COG_HOMEBREW_TAP_PRIVATE_KEY }}
owner: replicate
repositories: homebrew-tap
- name: Download checksums from release
run: gh release download "$TAG" -p checksums.txt -R "${{ github.repository }}"
env:
TAG: ${{ github.event.release.tag_name }}
GH_TOKEN: ${{ github.token }}
- name: Generate and push cask
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
TAG: ${{ github.event.release.tag_name }}
VERSION: ${{ needs.verify-release.outputs.version }}
run: |
# Extract SHA256s for Darwin binaries from checksums.txt
SHA_X86=$(grep 'cog_Darwin_x86_64' checksums.txt | awk '{print $1}')
SHA_ARM=$(grep 'cog_Darwin_arm64' checksums.txt | awk '{print $1}')
if [ -z "$SHA_X86" ] || [ -z "$SHA_ARM" ]; then
echo "::error::Missing Darwin binary checksums in checksums.txt"
echo "Darwin x86_64: ${SHA_X86:-MISSING}"
echo "Darwin arm64: ${SHA_ARM:-MISSING}"
cat checksums.txt
exit 1
fi
echo "Checksums:"
echo " Darwin x86_64: $SHA_X86"
echo " Darwin arm64: $SHA_ARM"
BASE_URL="https://github.com/replicate/cog/releases/download/${TAG}"
# Generate cask file (no indentation to avoid stripping issues)
cat > cog.rb <<CASK
cask "cog" do
version "${VERSION}"
on_intel do
url "${BASE_URL}/cog_Darwin_x86_64"
sha256 "${SHA_X86}"
end
on_arm do
url "${BASE_URL}/cog_Darwin_arm64"
sha256 "${SHA_ARM}"
end
name "Cog"
desc "Containers for machine learning"
homepage "https://cog.run"
binary "cog_Darwin_#{Hardware::CPU.intel? ? "x86_64" : "arm64"}", target: "cog"
postflight do
system_command "/usr/bin/xattr",
args: ["-dr", "com.apple.quarantine", "#{staged_path}/cog"]
end
end
CASK
# Strip heredoc indentation
sed -i 's/^ //' cog.rb
echo "Generated cask:"
cat cog.rb
# Clone tap repo and push update
git clone "https://x-access-token:${GH_TOKEN}@github.com/replicate/homebrew-tap.git" tap
mkdir -p tap/Casks
cp cog.rb tap/Casks/cog.rb
cd tap
git config user.name "cog-homebrew-tapbot[bot]"
git config user.email "1232932405+cog-homebrew-tapbot[bot]@users.noreply.github.com"
git add Casks/cog.rb
git diff --cached --quiet && echo "No changes to cask" && exit 0
git commit -m "Update cog to ${VERSION}"
git push origin main
echo "✓ Homebrew cask updated to ${VERSION}"