Detailed changes
@@ -13,6 +13,10 @@ on:
description: bump-type
type: string
default: patch
+ force-bump:
+ description: force-bump
+ required: true
+ type: boolean
secrets:
app-id:
description: The app ID used to create the PR
@@ -56,17 +60,24 @@ jobs:
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
clean: false
- fetch-depth: 10
+ fetch-depth: 0
- id: compare-versions-check
name: extension_bump::compare_versions
run: |
CURRENT_VERSION="$(sed -n 's/version = \"\(.*\)\"/\1/p' < extension.toml)"
+ PR_PARENT_SHA="${{ github.event.pull_request.head.sha }}"
- git checkout "$(git log -1 --format=%H)"~1
+ if [[ -n "$PR_PARENT_SHA" ]]; then
+ git checkout "$PR_PARENT_SHA"
+ elif BRANCH_PARENT_SHA="$(git merge-base origin/main origin/zed-zippy-autobump)"; then
+ git checkout "$BRANCH_PARENT_SHA"
+ else
+ git checkout "$(git log -1 --format=%H)"~1
+ fi
- PREV_COMMIT_VERSION="$(sed -n 's/version = \"\(.*\)\"/\1/p' < extension.toml)"
+ PARENT_COMMIT_VERSION="$(sed -n 's/version = \"\(.*\)\"/\1/p' < extension.toml)"
- [[ "$CURRENT_VERSION" == "$PREV_COMMIT_VERSION" ]] && \
+ [[ "$CURRENT_VERSION" == "$PARENT_COMMIT_VERSION" ]] && \
echo "needs_bump=true" >> "$GITHUB_OUTPUT" || \
echo "needs_bump=false" >> "$GITHUB_OUTPUT"
@@ -80,7 +91,9 @@ jobs:
needs:
- check_extension
- check_bump_needed
- if: (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions') && needs.check_bump_needed.outputs.needs_bump == 'true'
+ if: |-
+ (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions') &&
+ (inputs.force-bump == 'true' || needs.check_bump_needed.outputs.needs_bump == 'true')
runs-on: namespace-profile-8x16-ubuntu-2204
steps:
- id: generate-token
@@ -99,7 +112,7 @@ jobs:
- id: bump-version
name: extension_bump::bump_version
run: |
- OLD_VERSION="$(sed -n 's/version = \"\(.*\)\"/\1/p' < extension.toml)"
+ OLD_VERSION="${{ needs.check_bump_needed.outputs.current_version }}"
cat <<EOF > .bumpversion.cfg
[bumpversion]
@@ -117,7 +130,6 @@ jobs:
rm .bumpversion.cfg
- echo "old_version=${OLD_VERSION}" >> "$GITHUB_OUTPUT"
echo "new_version=${NEW_VERSION}" >> "$GITHUB_OUTPUT"
shell: bash -euxo pipefail {0}
- name: extension_bump::create_pull_request
@@ -126,7 +138,7 @@ jobs:
title: Bump version to ${{ steps.bump-version.outputs.new_version }}
body: This PR bumps the version of this extension to v${{ steps.bump-version.outputs.new_version }}
commit-message: Bump version to v${{ steps.bump-version.outputs.new_version }}
- branch: bump-from-${{ steps.bump-version.outputs.old_version }}
+ branch: zed-zippy-autobump
committer: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
base: main
delete-branch: true
@@ -137,7 +149,7 @@ jobs:
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'
+ if: (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions') && github.event_name == 'push' && github.ref == 'refs/heads/main' && needs.check_bump_needed.outputs.needs_bump == 'false'
runs-on: namespace-profile-8x16-ubuntu-2204
steps:
- id: generate-token
@@ -0,0 +1,41 @@
+# Generated from xtask::workflows::extension_release
+# Rebuild with `cargo xtask workflows`.
+name: extension_release
+on:
+ workflow_call:
+ secrets:
+ app-id:
+ description: The app ID used to create the PR
+ required: true
+ app-secret:
+ description: The app secret for the corresponding app ID
+ required: true
+jobs:
+ create_release:
+ if: (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions')
+ 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
+ - id: get-extension-id
+ name: extension_release::get_extension_id
+ run: |
+ EXTENSION_ID="$(sed -n 's/id = \"\(.*\)\"/\1/p' < extension.toml)"
+
+ echo "extension_id=${EXTENSION_ID}" >> "$GITHUB_OUTPUT"
+ shell: bash -euxo pipefail {0}
+ - name: extension_release::release_action
+ uses: huacnlee/zed-extension-action@v2
+ with:
+ extension-name: ${{ steps.get-extension-id.outputs.extension_id }}
+ push-to: zed-industries/extensions
+ env:
+ COMMITTER_TOKEN: ${{ steps.generate-token.outputs.token }}
@@ -13,7 +13,7 @@ jobs:
bundle_linux_aarch64:
if: |-
(github.event.action == 'labeled' && github.event.label.name == 'run-bundling') ||
- (github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'run-bundling'))
+ (github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'run-bundling'))
runs-on: namespace-profile-8x32-ubuntu-2004-arm-m4
env:
CARGO_INCREMENTAL: 0
@@ -56,7 +56,7 @@ jobs:
bundle_linux_x86_64:
if: |-
(github.event.action == 'labeled' && github.event.label.name == 'run-bundling') ||
- (github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'run-bundling'))
+ (github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'run-bundling'))
runs-on: namespace-profile-32x64-ubuntu-2004
env:
CARGO_INCREMENTAL: 0
@@ -99,7 +99,7 @@ jobs:
bundle_mac_aarch64:
if: |-
(github.event.action == 'labeled' && github.event.label.name == 'run-bundling') ||
- (github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'run-bundling'))
+ (github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'run-bundling'))
runs-on: self-mini-macos
env:
CARGO_INCREMENTAL: 0
@@ -145,7 +145,7 @@ jobs:
bundle_mac_x86_64:
if: |-
(github.event.action == 'labeled' && github.event.label.name == 'run-bundling') ||
- (github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'run-bundling'))
+ (github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'run-bundling'))
runs-on: self-mini-macos
env:
CARGO_INCREMENTAL: 0
@@ -191,7 +191,7 @@ jobs:
bundle_windows_aarch64:
if: |-
(github.event.action == 'labeled' && github.event.label.name == 'run-bundling') ||
- (github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'run-bundling'))
+ (github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'run-bundling'))
runs-on: self-32vcpu-windows-2022
env:
CARGO_INCREMENTAL: 0
@@ -229,7 +229,7 @@ jobs:
bundle_windows_x86_64:
if: |-
(github.event.action == 'labeled' && github.event.label.name == 'run-bundling') ||
- (github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'run-bundling'))
+ (github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'run-bundling'))
runs-on: self-32vcpu-windows-2022
env:
CARGO_INCREMENTAL: 0
@@ -6969,7 +6969,7 @@ dependencies = [
[[package]]
name = "gh-workflow"
version = "0.8.0"
-source = "git+https://github.com/zed-industries/gh-workflow?rev=3eaa84abca0778eb54272f45a312cb24f9a0b435#3eaa84abca0778eb54272f45a312cb24f9a0b435"
+source = "git+https://github.com/zed-industries/gh-workflow?rev=e5f883040530b4df36437f140084ee5cc7c1c9be#e5f883040530b4df36437f140084ee5cc7c1c9be"
dependencies = [
"async-trait",
"derive_more 2.0.1",
@@ -6986,7 +6986,7 @@ dependencies = [
[[package]]
name = "gh-workflow-macros"
version = "0.8.0"
-source = "git+https://github.com/zed-industries/gh-workflow?rev=3eaa84abca0778eb54272f45a312cb24f9a0b435#3eaa84abca0778eb54272f45a312cb24f9a0b435"
+source = "git+https://github.com/zed-industries/gh-workflow?rev=e5f883040530b4df36437f140084ee5cc7c1c9be#e5f883040530b4df36437f140084ee5cc7c1c9be"
dependencies = [
"heck 0.5.0",
"quote",
@@ -508,7 +508,7 @@ fork = "0.4.0"
futures = "0.3"
futures-batch = "0.6.1"
futures-lite = "1.13"
-gh-workflow = { git = "https://github.com/zed-industries/gh-workflow", rev = "3eaa84abca0778eb54272f45a312cb24f9a0b435" }
+gh-workflow = { git = "https://github.com/zed-industries/gh-workflow", rev = "e5f883040530b4df36437f140084ee5cc7c1c9be" }
git2 = { version = "0.20.1", default-features = false }
globset = "0.4"
handlebars = "4.3"
@@ -0,0 +1,48 @@
+# Generated from xtask::workflows:: within the Zed repository.extensions::bump_version
+# Rebuild with `cargo xtask workflows`.
+name: extensions::bump_version
+on:
+ pull_request:
+ types:
+ - labeled
+ push:
+ branches:
+ - main
+jobs:
+ determine_bump_type:
+ runs-on: namespace-profile-16x32-ubuntu-2204
+ steps:
+ - id: get-bump-type
+ name: extensions::bump_version::get_bump_type
+ run: |
+ if [ "$HAS_MAJOR_LABEL" = "true" ]; then
+ bump_type="major"
+ elif [ "$HAS_MINOR_LABEL" = "true" ]; then
+ bump_type="minor"
+ else
+ bump_type="patch"
+ fi
+ echo "bump_type=$bump_type" >> $GITHUB_OUTPUT
+ shell: bash -euxo pipefail {0}
+ env:
+ HAS_MAJOR_LABEL: |-
+ ${{ (github.event.action == 'labeled' && github.event.label.name == 'major') ||
+ (github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'major')) }}
+ HAS_MINOR_LABEL: |-
+ ${{ (github.event.action == 'labeled' && github.event.label.name == 'minor') ||
+ (github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'minor')) }}
+ outputs:
+ bump_type: ${{ steps.get-bump-type.outputs.bump_type }}
+ call_bump_version:
+ needs:
+ - determine_bump_type
+ if: |-
+ (github.event.action == 'labeled' && needs.determine_bump_type.outputs.bump_type != 'patch') ||
+ github.event_name == 'push'
+ uses: zed-industries/zed/.github/workflows/extension_bump.yml@main
+ secrets:
+ app-id: ${{ secrets.ZED_ZIPPY_APP_ID }}
+ app-secret: ${{ secrets.ZED_ZIPPY_APP_PRIVATE_KEY }}
+ with:
+ bump-type: ${{ needs.determine_bump_type.outputs.bump_type }}
+ force-bump: true
@@ -0,0 +1,13 @@
+# Generated from xtask::workflows:: within the Zed repository.extensions::release_version
+# Rebuild with `cargo xtask workflows`.
+name: extensions::release_version
+on:
+ push:
+ tags:
+ - v**
+jobs:
+ call_release_version:
+ uses: zed-industries/zed/.github/workflows/extension_release.yml@main
+ secrets:
+ app-id: ${{ secrets.ZED_ZIPPY_APP_ID }}
+ app-secret: ${{ secrets.ZED_ZIPPY_APP_PRIVATE_KEY }}
@@ -0,0 +1,13 @@
+# Generated from xtask::workflows:: within the Zed repository.extensions::run_tests
+# Rebuild with `cargo xtask workflows`.
+name: extensions::run_tests
+on:
+ pull_request:
+ branches:
+ - '**'
+jobs:
+ call_extension_tests:
+ uses: zed-industries/zed/.github/workflows/extension_tests.yml@main
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.ref_name == 'main' && github.sha || 'anysha' }}
+ cancel-in-progress: true
@@ -1,14 +1,17 @@
use anyhow::{Context, Result};
use clap::Parser;
+use gh_workflow::Workflow;
use std::fs;
-use std::path::Path;
+use std::path::{Path, PathBuf};
mod after_release;
mod cherry_pick;
mod compare_perf;
mod danger;
mod extension_bump;
+mod extension_release;
mod extension_tests;
+mod extensions;
mod nix_build;
mod release_nightly;
mod run_bundling;
@@ -23,44 +26,112 @@ mod vars;
#[derive(Parser)]
pub struct GenerateWorkflowArgs {}
+struct WorkflowFile {
+ source: fn() -> Workflow,
+ r#type: WorkflowType,
+}
+
+impl WorkflowFile {
+ fn zed(f: fn() -> Workflow) -> WorkflowFile {
+ WorkflowFile {
+ source: f,
+ r#type: WorkflowType::Zed,
+ }
+ }
+ fn extension(f: fn() -> Workflow) -> WorkflowFile {
+ WorkflowFile {
+ source: f,
+ r#type: WorkflowType::Extensions,
+ }
+ }
+
+ fn generate_file(&self) -> Result<()> {
+ let workflow = (self.source)();
+ let workflow_folder = self.r#type.folder_path();
+ let workflow_name = workflow
+ .name
+ .as_ref()
+ .expect("Workflow must have a name at this point");
+ let filename = format!(
+ "{}.yml",
+ workflow_name.rsplit("::").next().unwrap_or(workflow_name)
+ );
+
+ let workflow_path = workflow_folder.join(filename);
+
+ let content = workflow
+ .to_string()
+ .map_err(|e| anyhow::anyhow!("{:?}: {:?}", workflow_path, e))?;
+
+ let disclaimer = self.r#type.disclaimer(workflow_name);
+
+ let content = [disclaimer, content].join("\n");
+ fs::write(&workflow_path, content).map_err(Into::into)
+ }
+}
+
+enum WorkflowType {
+ Zed,
+ Extensions,
+}
+
+impl WorkflowType {
+ fn disclaimer(&self, workflow_name: &str) -> String {
+ format!(
+ concat!(
+ "# Generated from xtask::workflows::{}{}\n",
+ "# Rebuild with `cargo xtask workflows`.",
+ ),
+ matches!(self, WorkflowType::Extensions)
+ .then_some(" within the Zed repository.")
+ .unwrap_or_default(),
+ workflow_name
+ )
+ }
+
+ fn folder_path(&self) -> PathBuf {
+ match self {
+ WorkflowType::Zed => PathBuf::from(".github/workflows"),
+ WorkflowType::Extensions => PathBuf::from("extensions/workflows"),
+ }
+ }
+}
+
pub fn run_workflows(_: GenerateWorkflowArgs) -> Result<()> {
if !Path::new("crates/zed/").is_dir() {
anyhow::bail!("xtask workflows must be ran from the project root");
}
- let dir = Path::new(".github/workflows");
-
- let workflows = vec![
- ("danger.yml", danger::danger()),
- ("run_bundling.yml", run_bundling::run_bundling()),
- ("release_nightly.yml", release_nightly::release_nightly()),
- ("run_tests.yml", run_tests::run_tests()),
- ("release.yml", release::release()),
- ("cherry_pick.yml", cherry_pick::cherry_pick()),
- ("compare_perf.yml", compare_perf::compare_perf()),
- ("run_unit_evals.yml", run_agent_evals::run_unit_evals()),
- (
- "run_cron_unit_evals.yml",
- run_agent_evals::run_cron_unit_evals(),
- ),
- ("run_agent_evals.yml", run_agent_evals::run_agent_evals()),
- ("after_release.yml", after_release::after_release()),
- ("extension_tests.yml", extension_tests::extension_tests()),
- ("extension_bump.yml", extension_bump::extension_bump()),
+ let workflow_dir = Path::new(".github/workflows");
+ let extension_workflow_dir = Path::new("extensions/workflows");
+
+ let workflows = [
+ WorkflowFile::zed(danger::danger),
+ WorkflowFile::zed(run_bundling::run_bundling),
+ WorkflowFile::zed(release_nightly::release_nightly),
+ WorkflowFile::zed(run_tests::run_tests),
+ WorkflowFile::zed(release::release),
+ WorkflowFile::zed(cherry_pick::cherry_pick),
+ WorkflowFile::zed(compare_perf::compare_perf),
+ WorkflowFile::zed(run_agent_evals::run_unit_evals),
+ WorkflowFile::zed(run_agent_evals::run_cron_unit_evals),
+ WorkflowFile::zed(run_agent_evals::run_agent_evals),
+ WorkflowFile::zed(after_release::after_release),
+ WorkflowFile::zed(extension_tests::extension_tests),
+ WorkflowFile::zed(extension_bump::extension_bump),
+ WorkflowFile::zed(extension_release::extension_release),
+ /* workflows used for CI/CD in extension repositories */
+ WorkflowFile::extension(extensions::run_tests::run_tests),
+ WorkflowFile::extension(extensions::bump_version::bump_version),
+ WorkflowFile::extension(extensions::release_version::release_version),
];
- fs::create_dir_all(dir)
- .with_context(|| format!("Failed to create directory: {}", dir.display()))?;
- for (filename, workflow) in workflows {
- let content = workflow
- .to_string()
- .map_err(|e| anyhow::anyhow!("{}: {:?}", filename, e))?;
- let content = format!(
- "# Generated from xtask::workflows::{}\n# Rebuild with `cargo xtask workflows`.\n{}",
- workflow.name.unwrap(),
- content
- );
- let file_path = dir.join(filename);
- fs::write(&file_path, content)?;
+ for directory in [&workflow_dir, &extension_workflow_dir] {
+ fs::create_dir_all(directory)
+ .with_context(|| format!("Failed to create directory: {}", directory.display()))?;
+ }
+
+ for workflow_file in workflows {
+ workflow_file.generate_file()?;
}
Ok(())
@@ -2,6 +2,7 @@ use gh_workflow::*;
use indoc::indoc;
use crate::tasks::workflows::{
+ extension_release::extension_workflow_secrets,
extension_tests::{self},
runners,
steps::{self, CommonJobConditions, DEFAULT_REPOSITORY_OWNER_GUARD, NamedJob, named},
@@ -25,10 +26,11 @@ const VERSION_CHECK: &str = r#"sed -n 's/version = \"\(.*\)\"/\1/p' < extension.
// This is used by various extensions repos in the zed-extensions org to bump extension versions.
pub(crate) fn extension_bump() -> Workflow {
let bump_type = WorkflowInput::string("bump-type", Some("patch".to_owned()));
+ // TODO: Ideally, this would have a default of `false`, but this is currently not
+ // supported in gh-workflows
+ let force_bump = WorkflowInput::bool("force-bump", None);
- let app_id = WorkflowSecret::new("app-id", "The app ID used to create the PR");
- let app_secret =
- WorkflowSecret::new("app-secret", "The app secret for the corresponding app ID");
+ let (app_id, app_secret) = extension_workflow_secrets();
let test_extension = extension_tests::check_extension();
let (check_bump_needed, needs_bump, current_version) = check_bump_needed();
@@ -38,8 +40,15 @@ pub(crate) fn extension_bump() -> Workflow {
let dependencies = [&test_extension, &check_bump_needed];
- let bump_version =
- bump_extension_version(&dependencies, &bump_type, &needs_bump, &app_id, &app_secret);
+ let bump_version = bump_extension_version(
+ &dependencies,
+ ¤t_version,
+ &bump_type,
+ &needs_bump,
+ &force_bump,
+ &app_id,
+ &app_secret,
+ );
let create_label = create_version_label(
&dependencies,
&needs_bump,
@@ -53,6 +62,7 @@ pub(crate) fn extension_bump() -> Workflow {
Event::default().workflow_call(
WorkflowCall::default()
.add_input(bump_type.name, bump_type.call_input())
+ .add_input(force_bump.name, force_bump.call_input())
.secrets([
(app_id.name.to_owned(), app_id.secret_configuration()),
(
@@ -90,7 +100,7 @@ fn check_bump_needed() -> (NamedJob, StepOutput, StepOutput) {
])
.runs_on(runners::LINUX_SMALL)
.timeout_minutes(1u32)
- .add_step(steps::checkout_repo().add_with(("fetch-depth", 10)))
+ .add_step(steps::checkout_repo().add_with(("fetch-depth", 0)))
.add_step(compare_versions);
(named::job(job), version_changed, current_version)
@@ -106,7 +116,7 @@ fn create_version_label(
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'",
+ "{DEFAULT_REPOSITORY_OWNER_GUARD} && github.event_name == 'push' && github.ref == 'refs/heads/main' && {} == 'false'",
needs_bump.expr(),
)))
.runs_on(runners::LINUX_LARGE)
@@ -143,14 +153,21 @@ fn create_version_tag(current_version: &JobOutput, generated_token: StepOutput)
fn compare_versions() -> (Step<Run>, StepOutput, StepOutput) {
let check_needs_bump = named::bash(format!(
indoc! {
- r#"
+ r#"
CURRENT_VERSION="$({})"
+ PR_PARENT_SHA="${{{{ github.event.pull_request.head.sha }}}}"
- git checkout "$(git log -1 --format=%H)"~1
+ if [[ -n "$PR_PARENT_SHA" ]]; then
+ git checkout "$PR_PARENT_SHA"
+ elif BRANCH_PARENT_SHA="$(git merge-base origin/main origin/zed-zippy-autobump)"; then
+ git checkout "$BRANCH_PARENT_SHA"
+ else
+ git checkout "$(git log -1 --format=%H)"~1
+ fi
- PREV_COMMIT_VERSION="$({})"
+ PARENT_COMMIT_VERSION="$({})"
- [[ "$CURRENT_VERSION" == "$PREV_COMMIT_VERSION" ]] && \
+ [[ "$CURRENT_VERSION" == "$PARENT_COMMIT_VERSION" ]] && \
echo "needs_bump=true" >> "$GITHUB_OUTPUT" || \
echo "needs_bump=false" >> "$GITHUB_OUTPUT"
@@ -169,17 +186,20 @@ fn compare_versions() -> (Step<Run>, StepOutput, StepOutput) {
fn bump_extension_version(
dependencies: &[&NamedJob],
+ current_version: &JobOutput,
bump_type: &WorkflowInput,
needs_bump: &JobOutput,
+ force_bump: &WorkflowInput,
app_id: &WorkflowSecret,
app_secret: &WorkflowSecret,
) -> NamedJob {
let (generate_token, generated_token) = generate_token(app_id, app_secret);
- let (bump_version, old_version, new_version) = bump_version(bump_type);
+ let (bump_version, new_version) = bump_version(current_version, bump_type);
let job = steps::dependant_job(dependencies)
.cond(Expression::new(format!(
- "{DEFAULT_REPOSITORY_OWNER_GUARD} && {} == 'true'",
+ "{DEFAULT_REPOSITORY_OWNER_GUARD} &&\n({} == 'true' || {} == 'true')",
+ force_bump.expr(),
needs_bump.expr(),
)))
.runs_on(runners::LINUX_LARGE)
@@ -188,16 +208,15 @@ fn bump_extension_version(
.add_step(steps::checkout_repo())
.add_step(install_bump_2_version())
.add_step(bump_version)
- .add_step(create_pull_request(
- old_version,
- new_version,
- generated_token,
- ));
+ .add_step(create_pull_request(new_version, generated_token));
named::job(job)
}
-fn generate_token(app_id: &WorkflowSecret, app_secret: &WorkflowSecret) -> (Step<Use>, StepOutput) {
+pub(crate) fn generate_token(
+ app_id: &WorkflowSecret,
+ app_secret: &WorkflowSecret,
+) -> (Step<Use>, StepOutput) {
let step = named::uses("actions", "create-github-app-token", "v2")
.id("generate-token")
.add_with(
@@ -215,10 +234,10 @@ fn install_bump_2_version() -> Step<Run> {
named::run(runners::Platform::Linux, "pip install bump2version")
}
-fn bump_version(bump_type: &WorkflowInput) -> (Step<Run>, StepOutput, StepOutput) {
+fn bump_version(current_version: &JobOutput, bump_type: &WorkflowInput) -> (Step<Run>, StepOutput) {
let step = named::bash(format!(
indoc! {r#"
- OLD_VERSION="$({})"
+ OLD_VERSION="{}"
cat <<EOF > .bumpversion.cfg
{}
@@ -230,24 +249,18 @@ fn bump_version(bump_type: &WorkflowInput) -> (Step<Run>, StepOutput, StepOutput
rm .bumpversion.cfg
- echo "old_version=${{OLD_VERSION}}" >> "$GITHUB_OUTPUT"
echo "new_version=${{NEW_VERSION}}" >> "$GITHUB_OUTPUT"
"#
},
- VERSION_CHECK, BUMPVERSION_CONFIG, bump_type, VERSION_CHECK
+ current_version, BUMPVERSION_CONFIG, bump_type, VERSION_CHECK
))
.id("bump-version");
- let old_version = StepOutput::new(&step, "old_version");
let new_version = StepOutput::new(&step, "new_version");
- (step, old_version, new_version)
+ (step, new_version)
}
-fn create_pull_request(
- old_version: StepOutput,
- new_version: StepOutput,
- generated_token: StepOutput,
-) -> Step<Use> {
+fn create_pull_request(new_version: StepOutput, generated_token: StepOutput) -> Step<Use> {
let formatted_version = format!("v{}", new_version);
named::uses("peter-evans", "create-pull-request", "v7").with(
@@ -264,7 +277,7 @@ fn create_pull_request(
"commit-message",
format!("Bump version to {}", formatted_version),
)
- .add("branch", format!("bump-from-{}", old_version))
+ .add("branch", "zed-zippy-autobump")
.add(
"committer",
"zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>",
@@ -0,0 +1,70 @@
+use gh_workflow::{Event, Job, Run, Step, Use, Workflow, WorkflowCall};
+use indoc::indoc;
+
+use crate::tasks::workflows::{
+ extension_bump::generate_token,
+ runners,
+ steps::{CommonJobConditions, NamedJob, checkout_repo, named},
+ vars::{StepOutput, WorkflowSecret},
+};
+
+pub(crate) fn extension_release() -> Workflow {
+ let (app_id, app_secret) = extension_workflow_secrets();
+
+ let create_release = create_release(&app_id, &app_secret);
+ named::workflow()
+ .on(
+ Event::default().workflow_call(WorkflowCall::default().secrets([
+ (app_id.name.to_owned(), app_id.secret_configuration()),
+ (
+ app_secret.name.to_owned(),
+ app_secret.secret_configuration(),
+ ),
+ ])),
+ )
+ .add_job(create_release.name, create_release.job)
+}
+
+fn create_release(app_id: &WorkflowSecret, app_secret: &WorkflowSecret) -> NamedJob {
+ let (generate_token, generated_token) = generate_token(&app_id, &app_secret);
+ let (get_extension_id, extension_id) = get_extension_id();
+
+ let job = Job::default()
+ .with_repository_owner_guard()
+ .runs_on(runners::LINUX_LARGE)
+ .add_step(generate_token)
+ .add_step(checkout_repo())
+ .add_step(get_extension_id)
+ .add_step(release_action(extension_id, generated_token));
+
+ named::job(job)
+}
+
+fn get_extension_id() -> (Step<Run>, StepOutput) {
+ let step = named::bash(indoc! {
+ r#"
+ EXTENSION_ID="$(sed -n 's/id = \"\(.*\)\"/\1/p' < extension.toml)"
+
+ echo "extension_id=${EXTENSION_ID}" >> "$GITHUB_OUTPUT"
+ "#})
+ .id("get-extension-id");
+
+ let extension_id = StepOutput::new(&step, "extension_id");
+
+ (step, extension_id)
+}
+
+fn release_action(extension_id: StepOutput, generated_token: StepOutput) -> Step<Use> {
+ named::uses("huacnlee", "zed-extension-action", "v2")
+ .add_with(("extension-name", extension_id.to_string()))
+ .add_with(("push-to", "zed-industries/extensions"))
+ .add_env(("COMMITTER_TOKEN", generated_token.to_string()))
+}
+
+pub(crate) fn extension_workflow_secrets() -> (WorkflowSecret, WorkflowSecret) {
+ let app_id = WorkflowSecret::new("app-id", "The app ID used to create the PR");
+ let app_secret =
+ WorkflowSecret::new("app-secret", "The app secret for the corresponding app ID");
+
+ (app_id, app_secret)
+}
@@ -0,0 +1,99 @@
+use gh_workflow::{
+ Event, Expression, Input, Job, PullRequest, PullRequestType, Push, Run, Step, UsesJob, Workflow,
+};
+use indexmap::IndexMap;
+use indoc::indoc;
+
+use crate::tasks::workflows::{
+ runners,
+ steps::{NamedJob, named},
+ vars::{self, JobOutput, StepOutput},
+};
+
+pub(crate) fn bump_version() -> Workflow {
+ let (determine_bump_type, bump_type) = determine_bump_type();
+ let bump_type = bump_type.as_job_output(&determine_bump_type);
+
+ let call_bump_version = call_bump_version(&determine_bump_type, bump_type);
+
+ named::workflow()
+ .on(Event::default()
+ .push(Push::default().add_branch("main"))
+ .pull_request(PullRequest::default().add_type(PullRequestType::Labeled)))
+ .add_job(determine_bump_type.name, determine_bump_type.job)
+ .add_job(call_bump_version.name, call_bump_version.job)
+}
+
+pub(crate) fn call_bump_version(
+ depending_job: &NamedJob,
+ bump_type: JobOutput,
+) -> NamedJob<UsesJob> {
+ let job = Job::default()
+ .cond(Expression::new(format!(
+ indoc! {
+ "(github.event.action == 'labeled' && {} != 'patch') ||
+ github.event_name == 'push'"
+ },
+ bump_type.expr()
+ )))
+ .uses(
+ "zed-industries",
+ "zed",
+ ".github/workflows/extension_bump.yml",
+ "main",
+ )
+ .add_need(depending_job.name.clone())
+ .with(
+ Input::default()
+ .add("bump-type", bump_type.to_string())
+ .add("force-bump", true),
+ )
+ .secrets(IndexMap::from([
+ ("app-id".to_owned(), vars::ZED_ZIPPY_APP_ID.to_owned()),
+ (
+ "app-secret".to_owned(),
+ vars::ZED_ZIPPY_APP_PRIVATE_KEY.to_owned(),
+ ),
+ ]));
+
+ named::job(job)
+}
+
+fn determine_bump_type() -> (NamedJob, StepOutput) {
+ let (get_bump_type, output) = get_bump_type();
+ let job = Job::default()
+ .runs_on(runners::LINUX_DEFAULT)
+ .add_step(get_bump_type)
+ .outputs([(output.name.to_owned(), output.to_string())]);
+ (named::job(job), output)
+}
+
+fn get_bump_type() -> (Step<Run>, StepOutput) {
+ let step = named::bash(
+ indoc! {r#"
+ if [ "$HAS_MAJOR_LABEL" = "true" ]; then
+ bump_type="major"
+ elif [ "$HAS_MINOR_LABEL" = "true" ]; then
+ bump_type="minor"
+ else
+ bump_type="patch"
+ fi
+ echo "bump_type=$bump_type" >> $GITHUB_OUTPUT
+ "#},
+ )
+ .add_env(("HAS_MAJOR_LABEL",
+ indoc!{
+ "${{ (github.event.action == 'labeled' && github.event.label.name == 'major') ||
+ (github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'major')) }}"
+ }))
+ .add_env(("HAS_MINOR_LABEL",
+ indoc!{
+ "${{ (github.event.action == 'labeled' && github.event.label.name == 'minor') ||
+ (github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'minor')) }}"
+ }))
+ .id("get-bump-type");
+
+ let step_output = StepOutput::new(&step, "bump_type");
+
+ (step, step_output)
+}
@@ -0,0 +1,24 @@
+use gh_workflow::{Job, UsesJob};
+use indexmap::IndexMap;
+
+use crate::tasks::workflows::vars;
+
+pub(crate) mod bump_version;
+pub(crate) mod release_version;
+pub(crate) mod run_tests;
+
+pub(crate) trait WithAppSecrets: Sized {
+ fn with_app_secrets(self) -> Self;
+}
+
+impl WithAppSecrets for Job<UsesJob> {
+ fn with_app_secrets(self) -> Self {
+ self.secrets(IndexMap::from([
+ ("app-id".to_owned(), vars::ZED_ZIPPY_APP_ID.to_owned()),
+ (
+ "app-secret".to_owned(),
+ vars::ZED_ZIPPY_APP_PRIVATE_KEY.to_owned(),
+ ),
+ ]))
+ }
+}
@@ -0,0 +1,26 @@
+use gh_workflow::{Event, Job, Push, UsesJob, Workflow};
+
+use crate::tasks::workflows::{
+ extensions::WithAppSecrets,
+ steps::{NamedJob, named},
+};
+
+pub(crate) fn release_version() -> Workflow {
+ let create_release = call_release_version();
+ named::workflow()
+ .on(Event::default().push(Push::default().add_tag("v**")))
+ .add_job(create_release.name, create_release.job)
+}
+
+pub(crate) fn call_release_version() -> NamedJob<UsesJob> {
+ let job = Job::default()
+ .uses(
+ "zed-industries",
+ "zed",
+ ".github/workflows/extension_release.yml",
+ "main",
+ )
+ .with_app_secrets();
+
+ named::job(job)
+}
@@ -0,0 +1,25 @@
+use gh_workflow::{Event, Job, PullRequest, UsesJob, Workflow};
+
+use crate::tasks::workflows::{
+ steps::{NamedJob, named},
+ vars::one_workflow_per_non_main_branch,
+};
+
+pub(crate) fn run_tests() -> Workflow {
+ let call_extension_tests = call_extension_tests();
+ named::workflow()
+ .on(Event::default().pull_request(PullRequest::default().add_branch("**")))
+ .concurrency(one_workflow_per_non_main_branch())
+ .add_job(call_extension_tests.name, call_extension_tests.job)
+}
+
+pub(crate) fn call_extension_tests() -> NamedJob<UsesJob> {
+ let job = Job::default().uses(
+ "zed-industries",
+ "zed",
+ ".github/workflows/extension_tests.yml",
+ "main",
+ );
+
+ named::job(job)
+}
@@ -9,6 +9,7 @@ use crate::tasks::workflows::{
use super::{runners, steps};
use gh_workflow::*;
+use indoc::indoc;
pub fn run_bundling() -> Workflow {
let bundle = ReleaseBundleJobs {
@@ -42,10 +43,11 @@ pub fn run_bundling() -> Workflow {
fn bundle_job(deps: &[&NamedJob]) -> Job {
dependant_job(deps)
.when(deps.len() == 0, |job|
- job.cond(Expression::new(
- "(github.event.action == 'labeled' && github.event.label.name == 'run-bundling') ||
- (github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'run-bundling'))",
- )))
+ job.cond(Expression::new(
+ indoc! {
+ r#"(github.event.action == 'labeled' && github.event.label.name == 'run-bundling') ||
+ (github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'run-bundling'))"#,
+ })))
.timeout_minutes(60u32)
}
@@ -128,9 +128,9 @@ pub fn script(name: &str) -> Step<Run> {
}
}
-pub struct NamedJob {
+pub struct NamedJob<J: JobType = RunJob> {
pub name: String,
- pub job: Job,
+ pub job: Job<J>,
}
// impl NamedJob {
@@ -282,15 +282,19 @@ pub mod named {
Workflow::default().name(
named::function_name(1)
.split("::")
- .next()
- .unwrap()
- .to_owned(),
+ .collect::<Vec<_>>()
+ .into_iter()
+ .rev()
+ .skip(1)
+ .rev()
+ .collect::<Vec<_>>()
+ .join("::"),
)
}
/// Returns a Job with the same name as the enclosing function.
/// (note job names may not contain `::`)
- pub fn job(job: Job) -> NamedJob {
+ pub fn job<J: JobType>(job: Job<J>) -> NamedJob<J> {
NamedJob {
name: function_name(1).split("::").last().unwrap().to_owned(),
job,
@@ -219,6 +219,14 @@ impl WorkflowInput {
}
}
+ pub fn bool(name: &'static str, default: Option<bool>) -> Self {
+ Self {
+ input_type: "boolean",
+ name,
+ default: default.as_ref().map(ToString::to_string),
+ }
+ }
+
pub fn input(&self) -> WorkflowDispatchInput {
WorkflowDispatchInput {
description: self.name.to_owned(),
@@ -236,11 +244,15 @@ impl WorkflowInput {
default: self.default.clone(),
}
}
+
+ pub(crate) fn expr(&self) -> String {
+ format!("inputs.{}", self.name)
+ }
}
impl std::fmt::Display for WorkflowInput {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "${{{{ inputs.{} }}}}", self.name)
+ write!(f, "${{{{ {} }}}}", self.expr())
}
}