Detailed changes
@@ -10,7 +10,7 @@ on:
type: string
jobs:
run_bump_patch_version:
- if: github.repository_owner == 'zed-industries'
+ if: (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions')
runs-on: namespace-profile-16x32-ubuntu-2204
steps:
- id: generate-token
@@ -25,8 +25,8 @@ jobs:
clean: false
ref: ${{ inputs.branch }}
token: ${{ steps.generate-token.outputs.token }}
- - id: bump-version
- name: bump_patch_version::run_bump_patch_version::bump_version
+ - id: channel
+ name: bump_patch_version::run_bump_patch_version::read_channel
run: |
channel="$(cat crates/zed/RELEASE_CHANNEL)"
@@ -38,30 +38,53 @@ jobs:
tag_suffix="-pre"
;;
*)
- echo "this must be run on either of stable|preview release branches" >&2
+ echo "::error::must be run on a stable or preview release branch"
exit 1
;;
esac
- which cargo-set-version > /dev/null || cargo install cargo-edit -f --no-default-features --features "set-version"
+
+ version=$(script/get-crate-version zed)
+
+ {
+ echo "channel=$channel"
+ echo "version=$version"
+ echo "tag_suffix=$tag_suffix"
+ } >> "$GITHUB_OUTPUT"
+ - name: bump_patch_version::run_bump_patch_version::verify_prior_release_exists
+ run: |
+ status=$(curl -s -o /dev/null -w '%{http_code}' "https://cloud.zed.dev/releases/$CHANNEL/$VERSION/asset?asset=zed&os=macos&arch=aarch64")
+ if [[ "$status" != "200" ]]; then
+ echo "::error::version $VERSION has not been released on $CHANNEL yet (HTTP $status) — bump the patch version only after the current version is released"
+ exit 1
+ fi
+ env:
+ CHANNEL: ${{ steps.channel.outputs.channel }}
+ VERSION: ${{ steps.channel.outputs.version }}
+ - name: steps::install_cargo_edit
+ uses: taiki-e/install-action@02cc5f8ca9f2301050c0c099055816a41ee05507
+ with:
+ tool: cargo-edit
+ - id: bump-version
+ name: bump_patch_version::run_bump_patch_version::bump_version
+ run: |
version="$(cargo set-version -p zed --bump patch 2>&1 | sed 's/.* //')"
echo "version=$version" >> "$GITHUB_OUTPUT"
- echo "tag_suffix=$tag_suffix" >> "$GITHUB_OUTPUT"
- id: commit
- name: bump_patch_version::run_bump_patch_version::commit_changes
+ name: steps::bot_commit
uses: IAreKyleW00t/verified-bot-commit@126a6a11889ab05bcff72ec2403c326cd249b84c
with:
message: Bump to ${{ steps.bump-version.outputs.version }} for @${{ github.actor }}
ref: refs/heads/${{ inputs.branch }}
files: '**'
token: ${{ steps.generate-token.outputs.token }}
- - name: bump_patch_version::run_bump_patch_version::create_version_tag
+ - name: steps::create_tag
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b
with:
script: |
github.rest.git.createRef({
owner: context.repo.owner,
repo: context.repo.repo,
- ref: 'refs/tags/v${{ steps.bump-version.outputs.version }}${{ steps.bump-version.outputs.tag_suffix }}',
+ ref: 'refs/tags/v${{ steps.bump-version.outputs.version }}${{ steps.channel.outputs.tag_suffix }}',
sha: '${{ steps.commit.outputs.commit }}'
})
github-token: ${{ steps.generate-token.outputs.token }}
@@ -0,0 +1,226 @@
+# Generated from xtask::workflows::bump_zed_version
+# Rebuild with `cargo xtask workflows`.
+name: bump_zed_version
+on:
+ workflow_dispatch:
+ inputs:
+ target:
+ description: 'Which channels to bump: all, main, preview, or stable'
+ type: string
+ default: all
+jobs:
+ resolve_versions:
+ if: github.repository_owner == 'zed-industries'
+ runs-on: namespace-profile-16x32-ubuntu-2204
+ steps:
+ - id: generate-token
+ name: steps::authenticate_as_zippy
+ uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859
+ with:
+ app-id: ${{ secrets.ZED_ZIPPY_APP_ID }}
+ private-key: ${{ secrets.ZED_ZIPPY_APP_PRIVATE_KEY }}
+ - name: steps::checkout_repo
+ uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd
+ with:
+ clean: false
+ ref: main
+ token: ${{ steps.generate-token.outputs.token }}
+ - id: versions
+ name: bump_zed_version::resolve_versions::extract_versions
+ run: |
+ version=$(script/get-crate-version zed)
+ major=$(echo "$version" | cut -d. -f1)
+ minor=$(echo "$version" | cut -d. -f2)
+
+ channel=$(cat crates/zed/RELEASE_CHANNEL)
+ if [[ "$channel" != "dev" && "$channel" != "nightly" ]]; then
+ echo "::error::release channel on main should be dev or nightly, found: $channel"
+ exit 1
+ fi
+
+ # Next main version after bump
+ next_version="${major}.$((minor + 1)).0"
+ next_major=$(echo "$next_version" | cut -d. -f1)
+ next_minor=$(echo "$next_version" | cut -d. -f2)
+ pr_branch="bump-zed-to-v${next_major}.${next_minor}.0"
+
+ # New preview branch from current main
+ preview_branch="v${major}.${minor}.x"
+ preview_tag="v${version}-pre"
+
+ # Current preview to promote to stable — derive branch from released preview version
+ released_preview=$(script/get-released-version preview)
+ if [[ -z "$released_preview" ]]; then
+ echo "::error::could not determine released preview version"
+ exit 1
+ fi
+ stable_major=$(echo "$released_preview" | cut -d. -f1)
+ stable_minor=$(echo "$released_preview" | cut -d. -f2)
+ stable_branch="v${stable_major}.${stable_minor}.x"
+
+ # Final validation
+ for var in next_version pr_branch preview_branch preview_tag stable_branch; do
+ if [[ -z "${!var}" ]]; then
+ echo "::error::failed to compute $var"
+ exit 1
+ fi
+ done
+
+ {
+ echo "next_version=$next_version"
+ echo "pr_branch=$pr_branch"
+ echo "preview_branch=$preview_branch"
+ echo "preview_tag=$preview_tag"
+ echo "stable_branch=$stable_branch"
+ } >> "$GITHUB_OUTPUT"
+
+ echo "Resolved: next=$next_version preview=$preview_branch($preview_tag) stable=$stable_branch pr=$pr_branch"
+ outputs:
+ next_version: ${{ steps.versions.outputs.next_version }}
+ pr_branch: ${{ steps.versions.outputs.pr_branch }}
+ preview_branch: ${{ steps.versions.outputs.preview_branch }}
+ preview_tag: ${{ steps.versions.outputs.preview_tag }}
+ stable_branch: ${{ steps.versions.outputs.stable_branch }}
+ bump_main:
+ needs:
+ - resolve_versions
+ if: inputs.target == 'all' || inputs.target == 'main'
+ runs-on: namespace-profile-16x32-ubuntu-2204
+ steps:
+ - id: generate-token
+ name: steps::authenticate_as_zippy
+ uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859
+ with:
+ app-id: ${{ secrets.ZED_ZIPPY_APP_ID }}
+ private-key: ${{ secrets.ZED_ZIPPY_APP_PRIVATE_KEY }}
+ - name: steps::checkout_repo
+ uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd
+ with:
+ clean: false
+ ref: main
+ token: ${{ steps.generate-token.outputs.token }}
+ - name: steps::install_cargo_edit
+ uses: taiki-e/install-action@02cc5f8ca9f2301050c0c099055816a41ee05507
+ with:
+ tool: cargo-edit
+ - name: bump_zed_version::bump_main::bump_version
+ run: cargo set-version -p zed --bump minor
+ - name: steps::create_pull_request
+ uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725
+ with:
+ title: Bump Zed to v${{ needs.resolve_versions.outputs.next_version }}
+ body: |-
+ Release Notes:
+
+ - N/A
+ commit-message: Bump Zed to v${{ needs.resolve_versions.outputs.next_version }}
+ branch: ${{ needs.resolve_versions.outputs.pr_branch }}
+ committer: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
+ author: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
+ base: main
+ delete-branch: true
+ token: ${{ steps.generate-token.outputs.token }}
+ sign-commits: true
+ assignees: ${{ github.actor }}
+ create_preview_branch:
+ needs:
+ - resolve_versions
+ if: inputs.target == 'all' || inputs.target == 'preview'
+ runs-on: namespace-profile-16x32-ubuntu-2204
+ steps:
+ - id: generate-token
+ name: steps::authenticate_as_zippy
+ uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859
+ with:
+ app-id: ${{ secrets.ZED_ZIPPY_APP_ID }}
+ private-key: ${{ secrets.ZED_ZIPPY_APP_PRIVATE_KEY }}
+ - name: steps::checkout_repo
+ uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd
+ with:
+ clean: false
+ ref: main
+ token: ${{ steps.generate-token.outputs.token }}
+ - id: main-sha
+ name: bump_zed_version::create_preview_branch::get_main_sha
+ run: echo "main_sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
+ - name: bump_zed_version::create_preview_branch::promote_to_preview
+ run: echo -n preview > crates/zed/RELEASE_CHANNEL
+ - name: steps::create_branch
+ uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b
+ with:
+ script: |
+ github.rest.git.createRef({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ ref: 'refs/heads/${{ needs.resolve_versions.outputs.preview_branch }}',
+ sha: '${{ steps.main-sha.outputs.main_sha }}'
+ })
+ github-token: ${{ steps.generate-token.outputs.token }}
+ - id: commit
+ name: steps::bot_commit
+ uses: IAreKyleW00t/verified-bot-commit@126a6a11889ab05bcff72ec2403c326cd249b84c
+ with:
+ message: ${{ needs.resolve_versions.outputs.preview_branch }} preview
+ ref: refs/heads/${{ needs.resolve_versions.outputs.preview_branch }}
+ files: crates/zed/RELEASE_CHANNEL
+ token: ${{ steps.generate-token.outputs.token }}
+ - name: steps::create_tag
+ uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b
+ with:
+ script: |
+ github.rest.git.createRef({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ ref: 'refs/tags/${{ needs.resolve_versions.outputs.preview_tag }}',
+ sha: '${{ steps.commit.outputs.commit }}'
+ })
+ github-token: ${{ steps.generate-token.outputs.token }}
+ promote_to_stable:
+ needs:
+ - resolve_versions
+ if: inputs.target == 'all' || inputs.target == 'stable'
+ runs-on: namespace-profile-16x32-ubuntu-2204
+ steps:
+ - id: generate-token
+ name: steps::authenticate_as_zippy
+ uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859
+ with:
+ app-id: ${{ secrets.ZED_ZIPPY_APP_ID }}
+ private-key: ${{ secrets.ZED_ZIPPY_APP_PRIVATE_KEY }}
+ - name: steps::checkout_repo
+ uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd
+ with:
+ clean: false
+ ref: ${{ needs.resolve_versions.outputs.stable_branch }}
+ token: ${{ steps.generate-token.outputs.token }}
+ - id: stable-info
+ name: bump_zed_version::promote_to_stable
+ run: |
+ stable_version=$(script/get-crate-version zed)
+ {
+ echo "stable_tag=v${stable_version}"
+ } >> "$GITHUB_OUTPUT"
+ - name: bump_zed_version::promote_to_stable
+ run: echo -n stable > crates/zed/RELEASE_CHANNEL
+ - id: commit
+ name: steps::bot_commit
+ uses: IAreKyleW00t/verified-bot-commit@126a6a11889ab05bcff72ec2403c326cd249b84c
+ with:
+ message: ${{ needs.resolve_versions.outputs.stable_branch }} stable
+ ref: refs/heads/${{ needs.resolve_versions.outputs.stable_branch }}
+ files: crates/zed/RELEASE_CHANNEL
+ token: ${{ steps.generate-token.outputs.token }}
+ - name: steps::create_tag
+ uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b
+ with:
+ script: |
+ github.rest.git.createRef({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ ref: 'refs/tags/${{ steps.stable-info.outputs.stable_tag }}',
+ sha: '${{ steps.commit.outputs.commit }}'
+ })
+ github-token: ${{ steps.generate-token.outputs.token }}
+defaults:
+ run:
+ shell: bash -euxo pipefail {0}
@@ -137,7 +137,7 @@ jobs:
OLD_VERSION: ${{ needs.check_version_changed.outputs.current_version }}
BUMP_TYPE: ${{ inputs.bump-type }}
WORKING_DIR: ${{ inputs.working-directory }}
- - name: extension_bump::create_pull_request
+ - name: steps::create_pull_request
uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725
with:
title: ${{ steps.bump-version.outputs.title }}
@@ -145,6 +145,7 @@ jobs:
commit-message: ${{ steps.bump-version.outputs.title }}
branch: ${{ steps.bump-version.outputs.branch_name }}
committer: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
+ author: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
base: main
delete-branch: true
token: ${{ steps.generate-token.outputs.token }}
@@ -172,10 +172,9 @@ jobs:
run: |
echo "sha_short=$(echo "$GITHUB_SHA" | cut -c1-7)" >> "$GITHUB_OUTPUT"
- id: create-pr
- name: extension_workflow_rollout::rollout_workflows_to_extension::create_pull_request
+ name: steps::create_pull_request
uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725
with:
- path: extension
title: Update CI workflows to `${{ steps.short-sha.outputs.sha_short }}`
body: |
This PR updates the CI workflow files from the main Zed repository
@@ -190,6 +189,8 @@ jobs:
delete-branch: true
token: ${{ steps.generate-token.outputs.token }}
sign-commits: true
+ assignees: ${{ inputs.filter-repos != '' && github.actor || '' }}
+ path: extension
- name: extension_workflow_rollout::rollout_workflows_to_extension::enable_auto_merge
run: |
if [ -n "$PR_NUMBER" ]; then
@@ -62,7 +62,7 @@ jobs:
tooling/xtask/src/tasks/workflows/extension_tests.rs
- name: publish_extension_cli::update_sha_in_zed::regenerate_workflows
run: cargo xtask workflows
- - name: publish_extension_cli::create_pull_request_zed
+ - name: steps::create_pull_request
uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725
with:
title: 'extension_ci: Bump extension CLI version to `${{ steps.short-sha.outputs.sha_short }}`'
@@ -75,6 +75,7 @@ jobs:
commit-message: 'extension_ci: Bump extension CLI version to `${{ steps.short-sha.outputs.sha_short }}`'
branch: update-extension-cli-sha
committer: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
+ author: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
base: main
delete-branch: true
token: ${{ steps.generate-token.outputs.token }}
@@ -107,7 +108,7 @@ jobs:
run: |
sed -i "s/ZED_EXTENSION_CLI_SHA: [a-f0-9]*/ZED_EXTENSION_CLI_SHA: $GITHUB_SHA/" \
.github/workflows/ci.yml
- - name: publish_extension_cli::create_pull_request_extensions
+ - name: steps::create_pull_request
uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725
with:
title: Bump extension CLI version to `${{ steps.short-sha.outputs.sha_short }}`
@@ -116,12 +117,13 @@ jobs:
commit-message: Bump extension CLI version to `${{ steps.short-sha.outputs.sha_short }}`
branch: update-extension-cli-sha
committer: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
+ author: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
base: main
delete-branch: true
token: ${{ steps.generate-token.outputs.token }}
sign-commits: true
- labels: allow-no-extension
assignees: ${{ github.actor }}
+ labels: allow-no-extension
defaults:
run:
shell: bash -euxo pipefail {0}
@@ -0,0 +1,88 @@
+# Generated from xtask::workflows::retag_release
+# Rebuild with `cargo xtask workflows`.
+name: retag_release
+on:
+ workflow_dispatch:
+ inputs:
+ branch:
+ description: Release branch to re-tag (e.g. v0.180.x)
+ required: true
+ type: string
+jobs:
+ run_retag_release:
+ if: (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions')
+ runs-on: namespace-profile-16x32-ubuntu-2204
+ steps:
+ - id: generate-token
+ name: steps::authenticate_as_zippy
+ uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859
+ with:
+ app-id: ${{ secrets.ZED_ZIPPY_APP_ID }}
+ private-key: ${{ secrets.ZED_ZIPPY_APP_PRIVATE_KEY }}
+ - name: steps::checkout_repo
+ uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd
+ with:
+ clean: false
+ ref: ${{ inputs.branch }}
+ token: ${{ steps.generate-token.outputs.token }}
+ - id: info
+ name: retag_release::run_retag_release::resolve_tag
+ run: |
+ if [[ ! "$BRANCH" =~ ^v[0-9]+\.[0-9]{1,3}\.x$ ]]; then
+ echo "::error::branch '$BRANCH' does not match the release branch pattern v[N].[N].x"
+ exit 1
+ fi
+
+ channel="$(cat crates/zed/RELEASE_CHANNEL)"
+
+ tag_suffix=""
+ case $channel in
+ stable)
+ ;;
+ preview)
+ tag_suffix="-pre"
+ ;;
+ *)
+ echo "::error::must be run on a stable or preview release branch"
+ exit 1
+ ;;
+ esac
+
+ version=$(script/get-crate-version zed)
+
+ {
+ echo "channel=$channel"
+ echo "version=$version"
+ echo "tag_suffix=$tag_suffix"
+ echo "head_sha=$(git rev-parse HEAD)"
+ } >> "$GITHUB_OUTPUT"
+ env:
+ BRANCH: ${{ inputs.branch }}
+ - name: retag_release::run_retag_release::verify_no_existing_release
+ run: |
+ status=$(curl -s -o /dev/null -w '%{http_code}' "https://cloud.zed.dev/releases/$CHANNEL/$VERSION/asset?asset=zed&os=macos&arch=aarch64")
+ if [[ "$status" == "200" ]]; then
+ echo "::error::version $VERSION is already released on $CHANNEL — cannot re-tag a released version"
+ exit 1
+ fi
+ env:
+ CHANNEL: ${{ steps.info.outputs.channel }}
+ VERSION: ${{ steps.info.outputs.version }}
+ - name: steps::update_tag
+ uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b
+ with:
+ script: |
+ github.rest.git.updateRef({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ ref: 'tags/v${{ steps.info.outputs.version }}${{ steps.info.outputs.tag_suffix }}',
+ sha: '${{ steps.info.outputs.head_sha }}',
+ force: true
+ })
+ github-token: ${{ steps.generate-token.outputs.token }}
+concurrency:
+ group: ${{ github.workflow }}-${{ inputs.branch }}
+ cancel-in-progress: true
+defaults:
+ run:
+ shell: bash -euxo pipefail {0}
@@ -1,123 +0,0 @@
-#!/usr/bin/env bash
-
-set -eu
-
-# Ensure cargo-edit is installed
-which cargo-set-version > /dev/null || cargo install cargo-edit
-
-# Ensure we're in a clean state on an up-to-date `main` branch.
-if [[ -n $(git status --short --untracked-files=no) ]]; then
- echo "can't bump versions with uncommitted changes"
- exit 1
-fi
-if [[ $(git rev-parse --abbrev-ref HEAD) != "main" ]]; then
- echo "this command must be run on main"
- exit 1
-fi
-git pull -q --ff-only origin main
-
-# Parse the current version
-version=$(script/get-crate-version zed)
-major=$(echo $version | cut -d. -f1)
-minor=$(echo $version | cut -d. -f2)
-patch=$(echo $version | cut -d. -f3)
-prev_minor=$(expr $minor - 1)
-next_minor=$(expr $minor + 1)
-
-minor_branch_name="v${major}.${minor}.x"
-prev_minor_branch_name="v${major}.${prev_minor}.x"
-next_minor_branch_name="v${major}.${next_minor}.x"
-preview_tag_name="v${major}.${minor}.${patch}-pre"
-bump_main_branch_name="set-minor-version-to-${major}.${next_minor}"
-
-git fetch origin ${prev_minor_branch_name}:${prev_minor_branch_name}
-git fetch origin --tags
-cargo check -q
-
-function cleanup {
- git checkout -q main
-}
-trap cleanup EXIT
-
-echo "Checking invariants before taking any actions..."
-if [[ $(cat crates/zed/RELEASE_CHANNEL) != dev && $(cat crates/zed/RELEASE_CHANNEL) != nightly ]]; then
- echo "release channel on main should be dev or nightly"
- exit 1
-fi
-if git show-ref --quiet refs/tags/${preview_tag_name}; then
- echo "tag ${preview_tag_name} already exists"
- exit 1
-fi
-if git show-ref --quiet refs/heads/${minor_branch_name}; then
- echo "branch ${minor_branch_name} already exists"
- exit 1
-fi
-if ! git show-ref --quiet refs/heads/${prev_minor_branch_name}; then
- echo "previous branch ${minor_branch_name} doesn't exist"
- exit 1
-fi
-if [[ $(git show ${prev_minor_branch_name}:crates/zed/RELEASE_CHANNEL) != preview ]]; then
- echo "release channel on branch ${prev_minor_branch_name} should be preview"
- exit 1
-fi
-
-echo "Promoting existing branch ${prev_minor_branch_name} to stable..."
-git checkout -q ${prev_minor_branch_name}
-git clean -q -dff
-stable_tag_name="v$(script/get-crate-version zed)"
-if git show-ref --quiet refs/tags/${stable_tag_name}; then
- echo "tag ${stable_tag_name} already exists"
- exit 1
-fi
-old_prev_minor_sha=$(git rev-parse HEAD)
-echo -n stable > crates/zed/RELEASE_CHANNEL
-git commit -q --all --message "${prev_minor_branch_name} stable"
-git tag ${stable_tag_name}
-
-echo "Creating new preview branch ${minor_branch_name}..."
-git checkout -q main
-git checkout -q -b ${minor_branch_name}
-echo -n preview > crates/zed/RELEASE_CHANNEL
-git commit -q --all --message "${minor_branch_name} preview"
-git tag ${preview_tag_name}
-
-echo "Preparing main for version ${next_minor_branch_name}..."
-git checkout -q main
-git clean -q -dff
-git checkout -q -b ${bump_main_branch_name}
-cargo set-version --package zed --bump minor
-cargo check -q
-
-git commit -q --all --message "${next_minor_branch_name} dev"
-
-git checkout -q main
-
-cat <<MESSAGE
-Prepared new Zed versions locally. You will need to push the branches and open a PR for the change to main.
-
-# To push and open a PR to update main:
-
- git push -u origin \\
- ${preview_tag_name} \\
- ${stable_tag_name} \\
- ${minor_branch_name} \\
- ${prev_minor_branch_name} \\
- ${bump_main_branch_name}
-
- echo -e "Release Notes:\n\n- N/A" | gh pr create \\
- --title "Bump Zed to v${major}.${next_minor}" \\
- --body-file "-" \\
- --base main \\
- --head ${bump_main_branch_name} \\
- --web
-
-# To undo this push:
-
- git push -f . \\
- :${preview_tag_name} \\
- :${stable_tag_name} \\
- :${minor_branch_name} \\
- :${bump_main_branch_name} \\
- ${old_prev_minor_sha}:${prev_minor_branch_name}
-
-MESSAGE
@@ -1,18 +0,0 @@
-#!/usr/bin/env bash
-
-channel=$(cat crates/zed/RELEASE_CHANNEL)
-
-tag_suffix=""
-case $channel in
- stable)
- ;;
- preview)
- tag_suffix="-pre"
- ;;
- *)
- echo "this must be run on either of stable|preview release branches" >&2
- exit 1
- ;;
-esac
-
-exec script/lib/bump-version.sh zed v "$tag_suffix" patch
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+
+set -eu
+
+usage() {
+ echo "Usage: $0 [target]"
+ echo ""
+ echo "Triggers the bump_zed_version workflow to perform a minor release version bump "
+ echo "and update the stable and preview versions."
+ echo ""
+ echo "Arguments:"
+ echo " target Which channels to bump: all (default), main, preview, or stable"
+ exit 1
+}
+
+target="${1:-all}"
+
+if [[ "$target" != "all" && "$target" != "main" && "$target" != "preview" && "$target" != "stable" ]]; then
+ echo "error: invalid target '$target'" >&2
+ echo "Valid targets: all, main, preview, stable" >&2
+ exit 1
+fi
+
+day_of_week=$(date +%u)
+if [[ $day_of_week -ne 3 ]]; then
+ day_name=$(date +%A)
+ echo "Warning: Today is $day_name. Release version bumps are typically only done on Zednesdays."
+ read -r -p "Continue anyway? (y/N) " confirm
+ if [[ "$confirm" != "y" && "$confirm" != "Y" ]]; then
+ echo "Aborted."
+ exit 0
+ fi
+fi
+
+which gh > /dev/null 2>&1 || {
+ echo "error: GitHub CLI (gh) is required but not installed." >&2
+ echo "Install it with: brew install gh" >&2
+ exit 1
+}
+
+echo "Triggering bump_zed_version workflow:"
+echo " target: $target"
+echo ""
+
+gh workflow run bump_zed_version.yml \
+ -f target="$target"
+
+echo ""
+echo "Workflow triggered. Monitor progress at:"
+echo " https://github.com/zed-industries/zed/actions/workflows/bump_zed_version.yml"
@@ -0,0 +1,38 @@
+#!/usr/bin/env bash
+
+set -eu
+
+usage() {
+ echo "Usage: $0 <branch>"
+ echo ""
+ echo "Re-tags the HEAD of a release branch by force-updating the tag."
+ echo "This is useful when commits were added to a release branch after"
+ echo "tagging but before the release was published."
+ echo ""
+ echo "Arguments:"
+ echo " branch Release branch name (e.g. v0.180.x)"
+ exit 1
+}
+
+branch="${1:-}"
+
+if [[ -z "$branch" ]]; then
+ usage
+fi
+
+which gh > /dev/null 2>&1 || {
+ echo "error: GitHub CLI (gh) is required but not installed." >&2
+ echo "Install it with: brew install gh" >&2
+ exit 1
+}
+
+echo "Triggering retag_release workflow:"
+echo " branch: $branch"
+echo ""
+
+gh workflow run retag_release.yml \
+ -f branch="$branch"
+
+echo ""
+echo "Workflow triggered. Monitor progress at:"
+echo " https://github.com/zed-industries/zed/actions/workflows/retag_release.yml"
@@ -9,6 +9,7 @@ use crate::tasks::workflow_checks::{self};
mod after_release;
mod autofix_pr;
mod bump_patch_version;
+mod bump_zed_version;
mod cherry_pick;
mod compare_perf;
mod compliance_check;
@@ -22,6 +23,7 @@ mod extensions;
mod nix_build;
mod publish_extension_cli;
mod release_nightly;
+mod retag_release;
mod run_bundling;
mod release;
@@ -196,6 +198,7 @@ pub fn run_workflows(args: GenerateWorkflowArgs) -> Result<()> {
WorkflowFile::zed(after_release::after_release),
WorkflowFile::zed(autofix_pr::autofix_pr),
WorkflowFile::zed(bump_patch_version::bump_patch_version),
+ WorkflowFile::zed(bump_zed_version::bump_zed_version),
WorkflowFile::zed(cherry_pick::cherry_pick),
WorkflowFile::zed(compare_perf::compare_perf),
WorkflowFile::zed(compliance_check::compliance_check),
@@ -208,6 +211,7 @@ pub fn run_workflows(args: GenerateWorkflowArgs) -> Result<()> {
WorkflowFile::zed(publish_extension_cli::publish_extension_cli),
WorkflowFile::zed(release::release),
WorkflowFile::zed(release_nightly::release_nightly),
+ WorkflowFile::zed(retag_release::retag_release),
WorkflowFile::zed(run_agent_evals::run_cron_unit_evals),
WorkflowFile::zed(run_agent_evals::run_unit_evals),
WorkflowFile::zed(run_bundling::run_bundling),
@@ -61,12 +61,7 @@ fn run_autofix(pr_number: &WorkflowInput, run_clippy: &WorkflowInput) -> NamedJo
}
fn install_cargo_machete() -> Step<Use> {
- named::uses(
- "taiki-e",
- "install-action",
- "02cc5f8ca9f2301050c0c099055816a41ee05507",
- )
- .add_with(("tool", "cargo-machete@0.7.0"))
+ steps::taiki_install_action("cargo-machete@0.7.0")
}
fn run_cargo_fmt() -> Step<Run> {
@@ -2,7 +2,7 @@ use gh_workflow::*;
use crate::tasks::workflows::{
runners,
- steps::{self, CheckoutStep, named},
+ steps::{self, CheckoutStep, CommonJobConditions, named},
vars::{StepOutput, WorkflowInput},
};
@@ -28,7 +28,7 @@ fn run_bump_patch_version(branch: &WorkflowInput) -> steps::NamedJob {
.with_ref(branch.to_string())
}
- fn bump_version() -> Step<Run> {
+ fn read_channel() -> Step<Run> {
named::bash(indoc::indoc! {r#"
channel="$(cat crates/zed/RELEASE_CHANNEL)"
@@ -40,86 +40,68 @@ fn run_bump_patch_version(branch: &WorkflowInput) -> steps::NamedJob {
tag_suffix="-pre"
;;
*)
- echo "this must be run on either of stable|preview release branches" >&2
+ echo "::error::must be run on a stable or preview release branch"
exit 1
;;
esac
- which cargo-set-version > /dev/null || cargo install cargo-edit -f --no-default-features --features "set-version"
- version="$(cargo set-version -p zed --bump patch 2>&1 | sed 's/.* //')"
- echo "version=$version" >> "$GITHUB_OUTPUT"
- echo "tag_suffix=$tag_suffix" >> "$GITHUB_OUTPUT"
+
+ version=$(script/get-crate-version zed)
+
+ {
+ echo "channel=$channel"
+ echo "version=$version"
+ echo "tag_suffix=$tag_suffix"
+ } >> "$GITHUB_OUTPUT"
"#})
- .id("bump-version")
+ .id("channel")
}
- fn commit_changes(
- version: &StepOutput,
- token: &StepOutput,
- branch: &WorkflowInput,
- ) -> Step<Use> {
- named::uses(
- "IAreKyleW00t",
- "verified-bot-commit",
- "126a6a11889ab05bcff72ec2403c326cd249b84c", // v2.3.0
- )
- .id("commit")
- .add_with((
- "message",
- format!("Bump to {version} for @${{{{ github.actor }}}}"),
- ))
- .add_with(("ref", format!("refs/heads/{branch}")))
- .add_with(("files", "**"))
- .add_with(("token", token.to_string()))
+ fn verify_prior_release_exists() -> Step<Run> {
+ named::bash(indoc::indoc! {r#"
+ status=$(curl -s -o /dev/null -w '%{http_code}' "https://cloud.zed.dev/releases/$CHANNEL/$VERSION/asset?asset=zed&os=macos&arch=aarch64")
+ if [[ "$status" != "200" ]]; then
+ echo "::error::version $VERSION has not been released on $CHANNEL yet (HTTP $status) — bump the patch version only after the current version is released"
+ exit 1
+ fi
+ "#})
+ .add_env(("CHANNEL", "${{ steps.channel.outputs.channel }}"))
+ .add_env(("VERSION", "${{ steps.channel.outputs.version }}"))
}
- fn create_version_tag(
- version: &StepOutput,
- tag_suffix: &StepOutput,
- commit_sha: &StepOutput,
- token: &StepOutput,
- ) -> Step<Use> {
- named::uses(
- "actions",
- "github-script",
- "f28e40c7f34bde8b3046d885e986cb6290c5673b", // v7
- )
- .with(
- Input::default()
- .add(
- "script",
- indoc::formatdoc! {r#"
- github.rest.git.createRef({{
- owner: context.repo.owner,
- repo: context.repo.repo,
- ref: 'refs/tags/v{version}{tag_suffix}',
- sha: '{commit_sha}'
- }})
- "#},
- )
- .add("github-token", token.to_string()),
- )
+ fn bump_version() -> Step<Run> {
+ named::bash(indoc::indoc! {r#"
+ version="$(cargo set-version -p zed --bump patch 2>&1 | sed 's/.* //')"
+ echo "version=$version" >> "$GITHUB_OUTPUT"
+ "#})
+ .id("bump-version")
}
let (authenticate, token) = steps::authenticate_as_zippy().into();
+ let channel_step = read_channel();
+ let tag_suffix = StepOutput::new(&channel_step, "tag_suffix");
let bump_version_step = bump_version();
let version = StepOutput::new(&bump_version_step, "version");
- let tag_suffix = StepOutput::new(&bump_version_step, "tag_suffix");
- let commit_step = commit_changes(&version, &token, branch);
+ let commit_step: Step<Use> = steps::BotCommitStep::new(
+ format!("Bump to {version} for @${{{{ github.actor }}}}"),
+ branch,
+ &token,
+ )
+ .into();
let commit_sha = StepOutput::new_unchecked(&commit_step, "commit");
named::job(
Job::default()
- .cond(Expression::new(
- "github.repository_owner == 'zed-industries'",
- ))
- .runs_on(runners::LINUX_XL)
+ .with_repository_owner_guard()
+ .runs_on(runners::LINUX_DEFAULT)
.add_step(authenticate)
.add_step(checkout_branch(branch, &token))
+ .add_step(channel_step)
+ .add_step(verify_prior_release_exists())
+ .add_step(steps::install_cargo_edit())
.add_step(bump_version_step)
.add_step(commit_step)
- .add_step(create_version_tag(
- &version,
- &tag_suffix,
+ .add_step(steps::create_ref(
+ steps::GitRef::tag(format!("v{version}{tag_suffix}")),
&commit_sha,
&token,
)),
@@ -0,0 +1,264 @@
+use gh_workflow::*;
+
+use crate::tasks::workflows::{
+ runners,
+ steps::{self, named},
+ vars::{self, StepOutput, WorkflowInput},
+};
+
+pub fn bump_zed_version() -> Workflow {
+ let target = WorkflowInput::string("target", Some("all".to_string()))
+ .description("Which channels to bump: all, main, preview, or stable");
+
+ let (versions_job, outputs) = resolve_versions();
+
+ let bump_main_job = bump_main(&target, &versions_job, &outputs);
+ let preview_job = create_preview_branch(&target, &versions_job, &outputs);
+ let stable_job = promote_to_stable(&target, &versions_job, &outputs);
+
+ named::workflow()
+ .on(Event::default()
+ .workflow_dispatch(WorkflowDispatch::default().add_input(target.name, target.input())))
+ .add_job(versions_job.name, versions_job.job)
+ .add_job(bump_main_job.name, bump_main_job.job)
+ .add_job(preview_job.name, preview_job.job)
+ .add_job(stable_job.name, stable_job.job)
+}
+
+struct ResolvedOutputs {
+ next_version: vars::JobOutput,
+ pr_branch: vars::JobOutput,
+ preview_branch: vars::JobOutput,
+ preview_tag: vars::JobOutput,
+ stable_branch: vars::JobOutput,
+}
+
+fn resolve_versions() -> (steps::NamedJob, ResolvedOutputs) {
+ fn extract_versions() -> Step<Run> {
+ named::bash(indoc::indoc! {r#"
+ version=$(script/get-crate-version zed)
+ major=$(echo "$version" | cut -d. -f1)
+ minor=$(echo "$version" | cut -d. -f2)
+
+ channel=$(cat crates/zed/RELEASE_CHANNEL)
+ if [[ "$channel" != "dev" && "$channel" != "nightly" ]]; then
+ echo "::error::release channel on main should be dev or nightly, found: $channel"
+ exit 1
+ fi
+
+ # Next main version after bump
+ next_version="${major}.$((minor + 1)).0"
+ next_major=$(echo "$next_version" | cut -d. -f1)
+ next_minor=$(echo "$next_version" | cut -d. -f2)
+ pr_branch="bump-zed-to-v${next_major}.${next_minor}.0"
+
+ # New preview branch from current main
+ preview_branch="v${major}.${minor}.x"
+ preview_tag="v${version}-pre"
+
+ # Current preview to promote to stable — derive branch from released preview version
+ released_preview=$(script/get-released-version preview)
+ if [[ -z "$released_preview" ]]; then
+ echo "::error::could not determine released preview version"
+ exit 1
+ fi
+ stable_major=$(echo "$released_preview" | cut -d. -f1)
+ stable_minor=$(echo "$released_preview" | cut -d. -f2)
+ stable_branch="v${stable_major}.${stable_minor}.x"
+
+ # Final validation
+ for var in next_version pr_branch preview_branch preview_tag stable_branch; do
+ if [[ -z "${!var}" ]]; then
+ echo "::error::failed to compute $var"
+ exit 1
+ fi
+ done
+
+ {
+ echo "next_version=$next_version"
+ echo "pr_branch=$pr_branch"
+ echo "preview_branch=$preview_branch"
+ echo "preview_tag=$preview_tag"
+ echo "stable_branch=$stable_branch"
+ } >> "$GITHUB_OUTPUT"
+
+ echo "Resolved: next=$next_version preview=$preview_branch($preview_tag) stable=$stable_branch pr=$pr_branch"
+ "#})
+ .id("versions")
+ }
+
+ let (authenticate, token) = steps::authenticate_as_zippy().into();
+ let versions_step = extract_versions();
+ let next_version = StepOutput::new(&versions_step, "next_version");
+ let pr_branch = StepOutput::new(&versions_step, "pr_branch");
+ let preview_branch = StepOutput::new(&versions_step, "preview_branch");
+ let preview_tag = StepOutput::new(&versions_step, "preview_tag");
+ let stable_branch = StepOutput::new(&versions_step, "stable_branch");
+
+ let job = named::job(
+ Job::default()
+ .cond(Expression::new(
+ "github.repository_owner == 'zed-industries'",
+ ))
+ .runs_on(runners::LINUX_XL)
+ .add_step(authenticate)
+ .add_step(steps::checkout_repo().with_token(&token).with_ref("main"))
+ .add_step(versions_step)
+ .outputs([
+ (next_version.name.to_owned(), next_version.to_string()),
+ (pr_branch.name.to_owned(), pr_branch.to_string()),
+ (preview_branch.name.to_owned(), preview_branch.to_string()),
+ (preview_tag.name.to_owned(), preview_tag.to_string()),
+ (stable_branch.name.to_owned(), stable_branch.to_string()),
+ ]),
+ );
+
+ let outputs = ResolvedOutputs {
+ next_version: next_version.as_job_output(&job),
+ pr_branch: pr_branch.as_job_output(&job),
+ preview_branch: preview_branch.as_job_output(&job),
+ preview_tag: preview_tag.as_job_output(&job),
+ stable_branch: stable_branch.as_job_output(&job),
+ };
+
+ (job, outputs)
+}
+
+fn bump_main(
+ target: &WorkflowInput,
+ versions_job: &steps::NamedJob,
+ outputs: &ResolvedOutputs,
+) -> steps::NamedJob {
+ fn bump_version() -> Step<Run> {
+ named::bash("cargo set-version -p zed --bump minor")
+ }
+
+ let (authenticate, token) = steps::authenticate_as_zippy().into();
+
+ named::job(
+ Job::default()
+ .cond(Expression::new(format!(
+ "{} == 'all' || {} == 'main'",
+ target.expr(),
+ target.expr(),
+ )))
+ .needs(vec![versions_job.name.clone()])
+ .runs_on(runners::LINUX_DEFAULT)
+ .add_step(authenticate)
+ .add_step(steps::checkout_repo().with_token(&token).with_ref("main"))
+ .add_step(steps::install_cargo_edit())
+ .add_step(bump_version())
+ .add_step(steps::CreatePrStep::new(
+ format!("Bump Zed to v{}", outputs.next_version),
+ &outputs.pr_branch,
+ &token,
+ )),
+ )
+}
+
+fn create_preview_branch(
+ target: &WorkflowInput,
+ versions_job: &steps::NamedJob,
+ outputs: &ResolvedOutputs,
+) -> steps::NamedJob {
+ fn promote_to_preview() -> Step<Run> {
+ named::bash("echo -n preview > crates/zed/RELEASE_CHANNEL")
+ }
+
+ fn get_main_sha() -> Step<Run> {
+ named::bash("echo \"main_sha=$(git rev-parse HEAD)\" >> \"$GITHUB_OUTPUT\"").id("main-sha")
+ }
+
+ let (authenticate, token) = steps::authenticate_as_zippy().into();
+
+ let main_sha_step = get_main_sha();
+ let main_sha = StepOutput::new(&main_sha_step, "main_sha");
+
+ let commit_step: Step<Use> = steps::BotCommitStep::new(
+ format!("{} preview", outputs.preview_branch),
+ &outputs.preview_branch,
+ &token,
+ )
+ .with_files("crates/zed/RELEASE_CHANNEL")
+ .into();
+ let commit_sha = StepOutput::new_unchecked(&commit_step, "commit");
+
+ named::job(
+ Job::default()
+ .cond(Expression::new(format!(
+ "{} == 'all' || {} == 'preview'",
+ target.expr(),
+ target.expr(),
+ )))
+ .needs(vec![versions_job.name.clone()])
+ .runs_on(runners::LINUX_DEFAULT)
+ .add_step(authenticate)
+ .add_step(steps::checkout_repo().with_token(&token).with_ref("main"))
+ .add_step(main_sha_step)
+ .add_step(promote_to_preview())
+ .add_step(steps::create_ref(
+ steps::GitRef::branch(&outputs.preview_branch),
+ &main_sha,
+ &token,
+ ))
+ .add_step(commit_step)
+ .add_step(steps::create_ref(
+ steps::GitRef::tag(&outputs.preview_tag),
+ &commit_sha,
+ &token,
+ )),
+ )
+}
+
+fn promote_to_stable(
+ target: &WorkflowInput,
+ versions_job: &steps::NamedJob,
+ outputs: &ResolvedOutputs,
+) -> steps::NamedJob {
+ let (authenticate, token) = steps::authenticate_as_zippy().into();
+
+ let read_version_step = named::bash(indoc::indoc! {r#"
+ stable_version=$(script/get-crate-version zed)
+ {
+ echo "stable_tag=v${stable_version}"
+ } >> "$GITHUB_OUTPUT"
+ "#})
+ .id("stable-info");
+ let stable_tag = StepOutput::new(&read_version_step, "stable_tag");
+
+ let write_channel = named::bash("echo -n stable > crates/zed/RELEASE_CHANNEL");
+
+ let commit_step: Step<Use> = steps::BotCommitStep::new(
+ format!("{} stable", outputs.stable_branch),
+ &outputs.stable_branch,
+ &token,
+ )
+ .with_files("crates/zed/RELEASE_CHANNEL")
+ .into();
+ let commit_sha = StepOutput::new_unchecked(&commit_step, "commit");
+
+ named::job(
+ Job::default()
+ .cond(Expression::new(format!(
+ "{} == 'all' || {} == 'stable'",
+ target.expr(),
+ target.expr(),
+ )))
+ .needs(vec![versions_job.name.clone()])
+ .runs_on(runners::LINUX_DEFAULT)
+ .add_step(authenticate)
+ .add_step(
+ steps::checkout_repo()
+ .with_token(&token)
+ .with_ref(outputs.stable_branch.to_string()),
+ )
+ .add_step(read_version_step)
+ .add_step(write_channel)
+ .add_step(commit_step)
+ .add_step(steps::create_ref(
+ steps::GitRef::tag(&stable_tag),
+ &commit_sha,
+ &token,
+ )),
+ )
+}
@@ -1,4 +1,4 @@
-use gh_workflow::{ctx::Context, *};
+use gh_workflow::*;
use indoc::{formatdoc, indoc};
use crate::tasks::workflows::{
@@ -327,27 +327,9 @@ fn create_pull_request(
generated_token: StepOutput,
branch_name: StepOutput,
) -> Step<Use> {
- named::uses(
- "peter-evans",
- "create-pull-request",
- "98357b18bf14b5342f975ff684046ec3b2a07725",
- )
- .with(
- Input::default()
- .add("title", title.to_string())
- .add("body", body.to_string())
- .add("commit-message", title.to_string())
- .add("branch", branch_name.to_string())
- .add(
- "committer",
- "zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>",
- )
- .add("base", "main")
- .add("delete-branch", true)
- .add("token", generated_token.to_string())
- .add("sign-commits", true)
- .add("assignees", Context::github().actor().to_string()),
- )
+ steps::CreatePrStep::new(title.to_string(), branch_name, &generated_token)
+ .with_body(body)
+ .into()
}
fn trigger_release(
@@ -34,6 +34,7 @@ pub(crate) fn extension_workflow_rollout() -> Workflow {
removed_ci,
removed_shared,
&extra_context_input,
+ &filter_repos_input,
);
let create_tag = create_rollout_tag(&rollout_workflows, &filter_repos_input);
@@ -192,6 +193,7 @@ fn rollout_workflows_to_extension(
removed_ci: JobOutput,
removed_shared: JobOutput,
extra_context_input: &WorkflowInput,
+ filter_repos_input: &WorkflowInput,
) -> NamedJob {
fn checkout_extension_repo(token: &StepOutput) -> CheckoutStep {
steps::checkout_repo()
@@ -259,6 +261,7 @@ fn rollout_workflows_to_extension(
token: &StepOutput,
short_sha: &StepOutput,
context_input: &WorkflowInput,
+ filter_repos_input: &WorkflowInput,
) -> Step<Use> {
let title = format!("Update CI workflows to `{short_sha}`");
@@ -270,29 +273,16 @@ fn rollout_workflows_to_extension(
"#,
};
- named::uses(
- "peter-evans",
- "create-pull-request",
- "98357b18bf14b5342f975ff684046ec3b2a07725",
- )
- .add_with(("path", "extension"))
- .add_with(("title", title.clone()))
- .add_with(("body", body))
- .add_with(("commit-message", title))
- .add_with(("branch", "update-workflows"))
- .add_with((
- "committer",
- "zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>",
- ))
- .add_with((
- "author",
- "zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>",
- ))
- .add_with(("base", "main"))
- .add_with(("delete-branch", true))
- .add_with(("token", token.to_string()))
- .add_with(("sign-commits", true))
- .id("create-pr")
+ let pr_step: Step<Use> = steps::CreatePrStep::new(title, "update-workflows", token)
+ .with_body(body)
+ .with_path("extension")
+ // Save my inbox from exploding on rollout
+ .with_assignee(format!(
+ "${{{{ {repos_expr} != '' && github.actor || '' }}}}",
+ repos_expr = filter_repos_input.expr()
+ ))
+ .into();
+ pr_step.id("create-pr")
}
fn enable_auto_merge(token: &StepOutput) -> Step<gh_workflow::Run> {
@@ -345,7 +335,7 @@ fn rollout_workflows_to_extension(
.add_step(download_workflow_files())
.add_step(sync_workflow_files(removed_ci, removed_shared))
.add_step(calculate_short_sha)
- .add_step(create_pull_request(&token, &short_sha, extra_context_input))
+ .add_step(create_pull_request(&token, &short_sha, extra_context_input, filter_repos_input))
.add_step(enable_auto_merge(&token));
named::job(job)
@@ -1,4 +1,4 @@
-use gh_workflow::{ctx::Context, *};
+use gh_workflow::*;
use indoc::indoc;
use crate::tasks::workflows::{
@@ -88,31 +88,15 @@ fn create_pull_request_zed(generated_token: &StepOutput, short_sha: &StepOutput)
short_sha
);
- named::uses("peter-evans", "create-pull-request", "98357b18bf14b5342f975ff684046ec3b2a07725").with(
- Input::default()
- .add("title", title.clone())
- .add(
- "body",
- indoc! {r#"
- This PR bumps the extension CLI version used in the extension workflows to `${{ github.sha }}`.
-
- Release Notes:
-
- - N/A
- "#},
- )
- .add("commit-message", title)
- .add("branch", "update-extension-cli-sha")
- .add(
- "committer",
- "zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>",
- )
- .add("base", "main")
- .add("delete-branch", true)
- .add("token", generated_token.to_string())
- .add("sign-commits", true)
- .add("assignees", Context::github().actor().to_string()),
- )
+ steps::CreatePrStep::new(title, "update-extension-cli-sha", generated_token)
+ .with_body(indoc::indoc! {r#"
+ This PR bumps the extension CLI version used in the extension workflows to `${{ github.sha }}`.
+
+ Release Notes:
+
+ - N/A
+ "#})
+ .into()
}
fn update_sha_in_extensions(publish_job: &NamedJob) -> NamedJob {
@@ -160,28 +144,12 @@ fn create_pull_request_extensions(
) -> Step<Use> {
let title = format!("Bump extension CLI version to `{}`", short_sha);
- named::uses("peter-evans", "create-pull-request", "98357b18bf14b5342f975ff684046ec3b2a07725").with(
- Input::default()
- .add("title", title.clone())
- .add(
- "body",
- indoc! {r#"
- This PR bumps the extension CLI version to https://github.com/zed-industries/zed/commit/${{ github.sha }}.
- "#},
- )
- .add("commit-message", title)
- .add("branch", "update-extension-cli-sha")
- .add(
- "committer",
- "zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>",
- )
- .add("base", "main")
- .add("delete-branch", true)
- .add("token", generated_token.to_string())
- .add("sign-commits", true)
- .add("labels", "allow-no-extension")
- .add("assignees", Context::github().actor().to_string()),
- )
+ steps::CreatePrStep::new(title, "update-extension-cli-sha", generated_token)
+ .with_body(indoc::indoc! {r#"
+ This PR bumps the extension CLI version to https://github.com/zed-industries/zed/commit/${{ github.sha }}.
+ "#})
+ .with_labels("allow-no-extension")
+ .into()
}
fn get_short_sha() -> (Step<Run>, StepOutput) {
@@ -0,0 +1,100 @@
+use gh_workflow::*;
+
+use crate::tasks::workflows::{
+ runners,
+ steps::{self, CheckoutStep, CommonJobConditions, named},
+ vars::{StepOutput, WorkflowInput},
+};
+
+pub fn retag_release() -> Workflow {
+ let branch = WorkflowInput::string("branch", None)
+ .description("Release branch to re-tag (e.g. v0.180.x)");
+ let retag_job = run_retag_release(&branch);
+ named::workflow()
+ .on(Event::default()
+ .workflow_dispatch(WorkflowDispatch::default().add_input(branch.name, branch.input())))
+ .concurrency(
+ Concurrency::new(Expression::new(format!(
+ "${{{{ github.workflow }}}}-{branch}"
+ )))
+ .cancel_in_progress(true),
+ )
+ .add_job(retag_job.name, retag_job.job)
+}
+
+fn run_retag_release(branch: &WorkflowInput) -> steps::NamedJob {
+ fn checkout_branch(branch: &WorkflowInput, token: &StepOutput) -> CheckoutStep {
+ steps::checkout_repo()
+ .with_token(token)
+ .with_ref(branch.to_string())
+ }
+
+ fn resolve_tag(branch: &WorkflowInput) -> Step<Run> {
+ named::bash(indoc::indoc! {r#"
+ if [[ ! "$BRANCH" =~ ^v[0-9]+\.[0-9]{1,3}\.x$ ]]; then
+ echo "::error::branch '$BRANCH' does not match the release branch pattern v[N].[N].x"
+ exit 1
+ fi
+
+ channel="$(cat crates/zed/RELEASE_CHANNEL)"
+
+ tag_suffix=""
+ case $channel in
+ stable)
+ ;;
+ preview)
+ tag_suffix="-pre"
+ ;;
+ *)
+ echo "::error::must be run on a stable or preview release branch"
+ exit 1
+ ;;
+ esac
+
+ version=$(script/get-crate-version zed)
+
+ {
+ echo "channel=$channel"
+ echo "version=$version"
+ echo "tag_suffix=$tag_suffix"
+ echo "head_sha=$(git rev-parse HEAD)"
+ } >> "$GITHUB_OUTPUT"
+ "#})
+ .id("info")
+ .add_env(("BRANCH", branch.to_string()))
+ }
+
+ fn verify_no_existing_release() -> Step<Run> {
+ named::bash(indoc::indoc! {r#"
+ status=$(curl -s -o /dev/null -w '%{http_code}' "https://cloud.zed.dev/releases/$CHANNEL/$VERSION/asset?asset=zed&os=macos&arch=aarch64")
+ if [[ "$status" == "200" ]]; then
+ echo "::error::version $VERSION is already released on $CHANNEL — cannot re-tag a released version"
+ exit 1
+ fi
+ "#})
+ .add_env(("CHANNEL", "${{ steps.info.outputs.channel }}"))
+ .add_env(("VERSION", "${{ steps.info.outputs.version }}"))
+ }
+
+ let (authenticate, token) = steps::authenticate_as_zippy().into();
+ let resolve_step = resolve_tag(branch);
+ let version = StepOutput::new(&resolve_step, "version");
+ let tag_suffix = StepOutput::new(&resolve_step, "tag_suffix");
+ let head_sha = StepOutput::new(&resolve_step, "head_sha");
+
+ named::job(
+ Job::default()
+ .with_repository_owner_guard()
+ .runs_on(runners::LINUX_XL)
+ .add_step(authenticate)
+ .add_step(checkout_branch(branch, &token))
+ .add_step(resolve_step)
+ .add_step(verify_no_existing_release())
+ .add_step(steps::update_ref(
+ steps::GitRef::tag(format!("v{version}{tag_suffix}")),
+ &head_sha,
+ &token,
+ true,
+ )),
+ )
+}
@@ -430,12 +430,7 @@ fn check_style() -> NamedJob {
fn check_dependencies() -> NamedJob {
fn install_cargo_machete() -> Step<Use> {
- named::uses(
- "taiki-e",
- "install-action",
- "02cc5f8ca9f2301050c0c099055816a41ee05507",
- )
- .add_with(("tool", "cargo-machete@0.7.0"))
+ steps::taiki_install_action("cargo-machete@0.7.0")
}
fn run_cargo_machete() -> Step<Run> {
@@ -1,4 +1,4 @@
-use gh_workflow::*;
+use gh_workflow::{ctx::Context, *};
use serde_json::Value;
use crate::tasks::workflows::{
@@ -176,6 +176,20 @@ pub fn cargo_fmt() -> Step<Run> {
named::bash("cargo fmt --all -- --check")
}
+pub fn install_cargo_edit() -> Step<Use> {
+ taiki_install_action("cargo-edit")
+}
+
+pub fn taiki_install_action(tool: &str) -> Step<Use> {
+ Step::new(named::function_name(1))
+ .uses(
+ "taiki-e",
+ "install-action",
+ "02cc5f8ca9f2301050c0c099055816a41ee05507", // v2
+ )
+ .add_with(("tool", tool))
+}
+
pub fn cargo_install_nextest() -> Step<Use> {
named::uses(
"taiki-e",
@@ -648,3 +662,239 @@ fn generate_token_with_job_name<'a>(
permissions: None,
}
}
+
+pub(crate) struct BotCommitStep {
+ message: String,
+ branch: String,
+ files: String,
+ token: String,
+}
+
+impl BotCommitStep {
+ pub fn new(message: impl ToString, branch: impl ToString, token: &StepOutput) -> Self {
+ Self {
+ message: message.to_string(),
+ branch: branch.to_string(),
+ files: "**".to_string(),
+ token: token.to_string(),
+ }
+ }
+
+ pub fn with_files(self, files: impl ToString) -> Self {
+ Self {
+ files: files.to_string(),
+ ..self
+ }
+ }
+}
+
+impl From<BotCommitStep> for Step<Use> {
+ fn from(step: BotCommitStep) -> Self {
+ Step::new("steps::bot_commit")
+ .uses(
+ "IAreKyleW00t",
+ "verified-bot-commit",
+ "126a6a11889ab05bcff72ec2403c326cd249b84c", // v2.3.0
+ )
+ .id("commit")
+ .add_with(("message", step.message))
+ .add_with(("ref", format!("refs/heads/{}", step.branch)))
+ .add_with(("files", step.files))
+ .add_with(("token", step.token))
+ }
+}
+
+pub(crate) enum GitRef {
+ Tag(String),
+ Branch(String),
+}
+
+impl GitRef {
+ pub fn tag(name: impl ToString) -> Self {
+ Self::Tag(name.to_string())
+ }
+
+ pub fn branch(name: impl ToString) -> Self {
+ Self::Branch(name.to_string())
+ }
+
+ fn create_ref_path(&self) -> String {
+ match self {
+ Self::Tag(name) => format!("refs/tags/{name}"),
+ Self::Branch(name) => format!("refs/heads/{name}"),
+ }
+ }
+
+ fn update_ref_path(&self) -> String {
+ match self {
+ Self::Tag(name) => format!("tags/{name}"),
+ Self::Branch(name) => format!("heads/{name}"),
+ }
+ }
+
+ fn kind(&self) -> &'static str {
+ match self {
+ Self::Tag(_) => "tag",
+ Self::Branch(_) => "branch",
+ }
+ }
+}
+
+#[allow(unused)]
+enum RefOperation {
+ Create,
+ Update { force: bool },
+}
+
+struct RefOp {
+ git_ref: GitRef,
+ operation: RefOperation,
+ sha: String,
+ token: String,
+}
+
+impl From<RefOp> for Step<Use> {
+ fn from(op: RefOp) -> Self {
+ let (api_method, ref_path, force_line) = match &op.operation {
+ RefOperation::Create => ("createRef", op.git_ref.create_ref_path(), String::new()),
+ RefOperation::Update { force } => (
+ "updateRef",
+ op.git_ref.update_ref_path(),
+ format!(",\n force: {force}"),
+ ),
+ };
+ let step_name = match &op.operation {
+ RefOperation::Create => format!("steps::create_{}", op.git_ref.kind()),
+ RefOperation::Update { .. } => format!("steps::update_{}", op.git_ref.kind()),
+ };
+ let sha = &op.sha;
+ let script = indoc::formatdoc! {r#"
+ github.rest.git.{api_method}({{
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ ref: '{ref_path}',
+ sha: '{sha}'{force_line}
+ }})
+ "#};
+ Step::new(step_name)
+ .uses(
+ "actions",
+ "github-script",
+ "f28e40c7f34bde8b3046d885e986cb6290c5673b", // v7
+ )
+ .with(
+ Input::default()
+ .add("script", script)
+ .add("github-token", op.token),
+ )
+ }
+}
+
+pub(crate) fn create_ref(
+ git_ref: GitRef,
+ sha: impl ToString,
+ token: &StepOutput,
+) -> impl Into<Step<Use>> {
+ RefOp {
+ git_ref,
+ operation: RefOperation::Create,
+ sha: sha.to_string(),
+ token: token.to_string(),
+ }
+}
+
+#[allow(unused)]
+pub(crate) fn update_ref(
+ git_ref: GitRef,
+ sha: impl ToString,
+ token: &StepOutput,
+ force: bool,
+) -> impl Into<Step<Use>> {
+ RefOp {
+ git_ref,
+ operation: RefOperation::Update { force },
+ sha: sha.to_string(),
+ token: token.to_string(),
+ }
+}
+
+const ZED_ZIPPY_COMMITTER: &str =
+ "zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>";
+
+pub(crate) struct CreatePrStep {
+ title: String,
+ body: String,
+ branch: String,
+ base: String,
+ token: String,
+ assignees: Option<String>,
+ labels: Option<String>,
+ path: Option<String>,
+}
+
+impl CreatePrStep {
+ pub fn new(title: impl ToString, branch: impl ToString, token: &StepOutput) -> Self {
+ Self {
+ title: title.to_string(),
+ body: "Release Notes:\n\n- N/A".to_string(),
+ branch: branch.to_string(),
+ base: "main".to_string(),
+ token: token.to_string(),
+ assignees: Some(Context::github().actor().to_string()),
+ labels: None,
+ path: None,
+ }
+ }
+
+ pub fn with_body(self, body: impl ToString) -> Self {
+ Self {
+ body: body.to_string(),
+ ..self
+ }
+ }
+
+ pub fn with_assignee(self, assignee: impl ToString) -> Self {
+ Self {
+ assignees: Some(assignee.to_string()),
+ ..self
+ }
+ }
+
+ pub fn with_labels(self, labels: impl ToString) -> Self {
+ Self {
+ labels: Some(labels.to_string()),
+ ..self
+ }
+ }
+
+ pub fn with_path(self, path: impl ToString) -> Self {
+ Self {
+ path: Some(path.to_string()),
+ ..self
+ }
+ }
+}
+
+impl From<CreatePrStep> for Step<Use> {
+ fn from(step: CreatePrStep) -> Self {
+ Step::new("steps::create_pull_request")
+ .uses(
+ "peter-evans",
+ "create-pull-request",
+ "98357b18bf14b5342f975ff684046ec3b2a07725", // v7
+ )
+ .add_with(("title", step.title.clone()))
+ .add_with(("body", step.body))
+ .add_with(("commit-message", step.title))
+ .add_with(("branch", step.branch))
+ .add_with(("committer", ZED_ZIPPY_COMMITTER))
+ .add_with(("author", ZED_ZIPPY_COMMITTER))
+ .add_with(("base", step.base))
+ .add_with(("delete-branch", true))
+ .add_with(("token", step.token))
+ .add_with(("sign-commits", true))
+ .when_some(step.assignees, |s, v| s.add_with(("assignees", v)))
+ .when_some(step.labels, |s, v| s.add_with(("labels", v)))
+ .when_some(step.path, |s, v| s.add_with(("path", v)))
+ }
+}