Improve `extension_bump` workflow (#43612)

Finn Evers created

This extends the extension CI workflow to create a tag once the version
is bumped on main.

Release Notes:

- N/A

Change summary

.github/workflows/extension_bump.yml                | 33 +++++
tooling/xtask/src/tasks/workflows/extension_bump.rs | 84 ++++++++++++--
2 files changed, 104 insertions(+), 13 deletions(-)

Detailed changes

.github/workflows/extension_bump.yml 🔗

@@ -59,7 +59,7 @@ jobs:
         fetch-depth: 10
     - id: compare-versions-check
       name: extension_bump::compare_versions
-      run: |+
+      run: |
         CURRENT_VERSION="$(sed -n 's/version = \"\(.*\)\"/\1/p' < extension.toml)"
 
         git checkout "$(git log -1 --format=%H)"~1
@@ -70,9 +70,11 @@ jobs:
           echo "needs_bump=true" >> "$GITHUB_OUTPUT" || \
           echo "needs_bump=false" >> "$GITHUB_OUTPUT"
 
+        echo "current_version=${CURRENT_VERSION}" >> "$GITHUB_OUTPUT"
       shell: bash -euxo pipefail {0}
     outputs:
       needs_bump: ${{ steps.compare-versions-check.outputs.needs_bump }}
+      current_version: ${{ steps.compare-versions-check.outputs.current_version }}
     timeout-minutes: 1
   bump_extension_version:
     needs:
@@ -131,6 +133,35 @@ jobs:
         token: ${{ steps.generate-token.outputs.token }}
         sign-commits: true
     timeout-minutes: 1
+  create_version_label:
+    needs:
+    - check_extension
+    - check_bump_needed
+    if: (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions') && needs.check_bump_needed.outputs.needs_bump == 'false'
+    runs-on: namespace-profile-8x16-ubuntu-2204
+    steps:
+    - id: generate-token
+      name: extension_bump::generate_token
+      uses: actions/create-github-app-token@v2
+      with:
+        app-id: ${{ secrets.app-id }}
+        private-key: ${{ secrets.app-secret }}
+    - name: steps::checkout_repo
+      uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+      with:
+        clean: false
+    - name: extension_bump::create_version_tag
+      uses: actions/github-script@v7
+      with:
+        script: |-
+          github.rest.git.createRef({
+              owner: context.repo.owner,
+              repo: context.repo.repo,
+              ref: 'refs/tags/v${{ needs.check_bump_needed.outputs.current_version }}',
+              sha: context.sha
+          })
+        github-token: ${{ steps.generate-token.outputs.token }}
+    timeout-minutes: 1
 concurrency:
   group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.ref_name == 'main' && github.sha || 'anysha' }}
   cancel-in-progress: true

tooling/xtask/src/tasks/workflows/extension_bump.rs 🔗

@@ -31,11 +31,19 @@ pub(crate) fn extension_bump() -> Workflow {
         WorkflowSecret::new("app-secret", "The app secret for the corresponding app ID");
 
     let test_extension = extension_tests::check_extension();
-    let (check_bump_needed, needs_bump) = check_bump_needed();
-    let bump_version = bump_extension_version(
-        &[&test_extension, &check_bump_needed],
-        &bump_type,
-        needs_bump.as_job_output(&check_bump_needed),
+    let (check_bump_needed, needs_bump, current_version) = check_bump_needed();
+
+    let needs_bump = needs_bump.as_job_output(&check_bump_needed);
+    let current_version = current_version.as_job_output(&check_bump_needed);
+
+    let dependencies = [&test_extension, &check_bump_needed];
+
+    let bump_version =
+        bump_extension_version(&dependencies, &bump_type, &needs_bump, &app_id, &app_secret);
+    let create_label = create_version_label(
+        &dependencies,
+        &needs_bump,
+        &current_version,
         &app_id,
         &app_secret,
     );
@@ -65,24 +73,74 @@ pub(crate) fn extension_bump() -> Workflow {
         .add_job(test_extension.name, test_extension.job)
         .add_job(check_bump_needed.name, check_bump_needed.job)
         .add_job(bump_version.name, bump_version.job)
+        .add_job(create_label.name, create_label.job)
 }
 
-fn check_bump_needed() -> (NamedJob, StepOutput) {
-    let (compare_versions, version_changed) = compare_versions();
+fn check_bump_needed() -> (NamedJob, StepOutput, StepOutput) {
+    let (compare_versions, version_changed, current_version) = compare_versions();
 
     let job = Job::default()
         .with_repository_owner_guard()
-        .outputs([(version_changed.name.to_owned(), version_changed.to_string())])
+        .outputs([
+            (version_changed.name.to_owned(), version_changed.to_string()),
+            (
+                current_version.name.to_string(),
+                current_version.to_string(),
+            ),
+        ])
         .runs_on(runners::LINUX_SMALL)
         .timeout_minutes(1u32)
         .add_step(steps::checkout_repo().add_with(("fetch-depth", 10)))
         .add_step(compare_versions);
 
-    (named::job(job), version_changed)
+    (named::job(job), version_changed, current_version)
+}
+
+fn create_version_label(
+    dependencies: &[&NamedJob],
+    needs_bump: &JobOutput,
+    current_version: &JobOutput,
+    app_id: &WorkflowSecret,
+    app_secret: &WorkflowSecret,
+) -> NamedJob {
+    let (generate_token, generated_token) = generate_token(app_id, app_secret);
+    let job = steps::dependant_job(dependencies)
+        .cond(Expression::new(format!(
+            "{DEFAULT_REPOSITORY_OWNER_GUARD} && {} == 'false'",
+            needs_bump.expr(),
+        )))
+        .runs_on(runners::LINUX_LARGE)
+        .timeout_minutes(1u32)
+        .add_step(generate_token)
+        .add_step(steps::checkout_repo())
+        .add_step(create_version_tag(current_version, generated_token));
+
+    named::job(job)
+}
+
+fn create_version_tag(current_version: &JobOutput, generated_token: StepOutput) -> Step<Use> {
+    named::uses("actions", "github-script", "v7").with(
+        Input::default()
+            .add(
+                "script",
+                format!(
+                    indoc! {r#"
+                        github.rest.git.createRef({{
+                            owner: context.repo.owner,
+                            repo: context.repo.repo,
+                            ref: 'refs/tags/v{}',
+                            sha: context.sha
+                        }})"#
+                    },
+                    current_version
+                ),
+            )
+            .add("github-token", generated_token.to_string()),
+    )
 }
 
 /// Compares the current and previous commit and checks whether versions changed inbetween.
-fn compare_versions() -> (Step<Run>, StepOutput) {
+fn compare_versions() -> (Step<Run>, StepOutput, StepOutput) {
     let check_needs_bump = named::bash(format!(
         indoc! {
             r#"
@@ -96,6 +154,7 @@ fn compare_versions() -> (Step<Run>, StepOutput) {
           echo "needs_bump=true" >> "$GITHUB_OUTPUT" || \
           echo "needs_bump=false" >> "$GITHUB_OUTPUT"
 
+        echo "current_version=${{CURRENT_VERSION}}" >> "$GITHUB_OUTPUT"
         "#
         },
         VERSION_CHECK, VERSION_CHECK
@@ -103,14 +162,15 @@ fn compare_versions() -> (Step<Run>, StepOutput) {
     .id("compare-versions-check");
 
     let needs_bump = StepOutput::new(&check_needs_bump, "needs_bump");
+    let current_version = StepOutput::new(&check_needs_bump, "current_version");
 
-    (check_needs_bump, needs_bump)
+    (check_needs_bump, needs_bump, current_version)
 }
 
 fn bump_extension_version(
     dependencies: &[&NamedJob],
     bump_type: &WorkflowInput,
-    needs_bump: JobOutput,
+    needs_bump: &JobOutput,
     app_id: &WorkflowSecret,
     app_secret: &WorkflowSecret,
 ) -> NamedJob {