Add an autofix workflow (#44922)

One of the major annoyances with writing code with claude is that its
poorly indented; instead of requiring manual intervention, let's just
fix that in CI.

Similar to https://autofix.ci, but as we already have a github app,
we can do it without relying on a 3rd party.

This PR doesn't trigger the workflow (we need a separate change in Zippy
to do
that) but will let me test it manually.

Release Notes:

- N/A
This commit is contained in:
Conrad Irwin
2025-12-15 15:22:29 -07:00
committed by GitHub
parent 5987dff7e4
commit 97f6cdac81
4 changed files with 143 additions and 1 deletions

View File

@@ -5,6 +5,7 @@ use std::fs;
use std::path::{Path, PathBuf};
mod after_release;
mod autofix_pr;
mod cherry_pick;
mod compare_perf;
mod danger;
@@ -111,6 +112,7 @@ pub fn run_workflows(_: GenerateWorkflowArgs) -> Result<()> {
WorkflowFile::zed(run_tests::run_tests),
WorkflowFile::zed(release::release),
WorkflowFile::zed(cherry_pick::cherry_pick),
WorkflowFile::zed(autofix_pr::autofix_pr),
WorkflowFile::zed(compare_perf::compare_perf),
WorkflowFile::zed(run_agent_evals::run_unit_evals),
WorkflowFile::zed(run_agent_evals::run_cron_unit_evals),

View File

@@ -0,0 +1,77 @@
use gh_workflow::*;
use crate::tasks::workflows::{
runners,
steps::{self, NamedJob, named},
vars::{self, StepOutput, WorkflowInput},
};
pub fn autofix_pr() -> Workflow {
let pr_number = WorkflowInput::string("pr_number", None);
let autofix = run_autofix(&pr_number);
named::workflow()
.run_name(format!("autofix PR #{pr_number}"))
.on(Event::default().workflow_dispatch(
WorkflowDispatch::default().add_input(pr_number.name, pr_number.input()),
))
.add_job(autofix.name, autofix.job)
}
fn run_autofix(pr_number: &WorkflowInput) -> NamedJob {
fn authenticate_as_zippy() -> (Step<Use>, StepOutput) {
let step = named::uses(
"actions",
"create-github-app-token",
"bef1eaf1c0ac2b148ee2a0a74c65fbe6db0631f1",
)
.add_with(("app-id", vars::ZED_ZIPPY_APP_ID))
.add_with(("private-key", vars::ZED_ZIPPY_APP_PRIVATE_KEY))
.id("get-app-token");
let output = StepOutput::new(&step, "token");
(step, output)
}
fn checkout_pr(pr_number: &WorkflowInput, token: &StepOutput) -> Step<Run> {
named::bash(&format!("gh pr checkout {pr_number}")).add_env(("GITHUB_TOKEN", token))
}
fn run_cargo_fmt() -> Step<Run> {
named::bash("cargo fmt --all")
}
fn run_clippy_fix() -> Step<Run> {
named::bash(
"cargo clippy --workspace --release --all-targets --all-features --fix --allow-dirty --allow-staged",
)
}
fn commit_and_push(token: &StepOutput) -> Step<Run> {
named::bash(indoc::indoc! {r#"
if git diff --quiet; then
echo "No changes to commit"
else
git add -A
git commit -m "Apply cargo fmt and clippy --fix"
git push
fi
"#})
.add_env(("GIT_COMMITTER_NAME", "Zed Zippy"))
.add_env(("GIT_COMMITTER_EMAIL", "hi@zed.dev"))
.add_env(("GIT_AUTHOR_NAME", "Zed Zippy"))
.add_env(("GIT_AUTHOR_EMAIL", "hi@zed.dev"))
.add_env(("GITHUB_TOKEN", token))
}
let (authenticate, token) = authenticate_as_zippy();
named::job(
Job::default()
.runs_on(runners::LINUX_SMALL)
.add_step(authenticate)
.add_step(steps::checkout_repo_with_token(&token))
.add_step(checkout_pr(pr_number, &token))
.add_step(run_cargo_fmt())
.add_step(run_clippy_fix())
.add_step(commit_and_push(&token)),
)
}

View File

@@ -1,6 +1,6 @@
use gh_workflow::*;
use crate::tasks::workflows::{runners::Platform, vars};
use crate::tasks::workflows::{runners::Platform, vars, vars::StepOutput};
pub const BASH_SHELL: &str = "bash -euxo pipefail {0}";
// https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#jobsjob_idstepsshell
@@ -17,6 +17,16 @@ pub fn checkout_repo() -> Step<Use> {
.add_with(("clean", false))
}
pub fn checkout_repo_with_token(token: &StepOutput) -> Step<Use> {
named::uses(
"actions",
"checkout",
"11bd71901bbe5b1630ceea73d27597364c9af683", // v4
)
.add_with(("clean", false))
.add_with(("token", token.to_string()))
}
pub fn setup_pnpm() -> Step<Use> {
named::uses(
"pnpm",