logiguard fork v2: patched GPUI on verified 8c74db0 tree
Rebuilt from the exact zed-industries/zed @ 8c74db00c4053d6c0a9037863d7bd048658da4ca tree (previous orphan was based on a stale/wrong fetch). Same 3-file patch: - serial.rs: add SerialKind::KeyboardEnter - client.rs: store wl_keyboard.enter serial; add latest_serial_of() - window.rs: activate() uses keyboard-enter serial (Mutter focus gate) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,257 @@
|
||||
use anyhow::{Context, Result};
|
||||
use clap::Parser;
|
||||
use gh_workflow::Workflow;
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
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;
|
||||
mod danger;
|
||||
mod deploy_collab;
|
||||
mod deploy_docs;
|
||||
mod extension_auto_bump;
|
||||
mod extension_bump;
|
||||
mod extension_tests;
|
||||
mod extension_workflow_rollout;
|
||||
mod extensions;
|
||||
mod nix_build;
|
||||
mod publish_extension_cli;
|
||||
mod release_nightly;
|
||||
mod run_bundling;
|
||||
|
||||
mod release;
|
||||
mod run_agent_evals;
|
||||
mod run_tests;
|
||||
mod runners;
|
||||
mod steps;
|
||||
mod vars;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct GitSha(String);
|
||||
|
||||
impl AsRef<str> for GitSha {
|
||||
fn as_ref(&self) -> &str {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(
|
||||
clippy::disallowed_methods,
|
||||
reason = "This runs only in a CLI environment"
|
||||
)]
|
||||
fn parse_ref(value: &str) -> Result<GitSha, String> {
|
||||
const GIT_SHA_LENGTH: usize = 40;
|
||||
(value.len() == GIT_SHA_LENGTH)
|
||||
.then_some(value)
|
||||
.ok_or_else(|| {
|
||||
format!(
|
||||
"Git SHA has wrong length! \
|
||||
Only SHAs with a full length of {GIT_SHA_LENGTH} are supported, found {len} characters.",
|
||||
len = value.len()
|
||||
)
|
||||
})
|
||||
.and_then(|value| {
|
||||
let mut tmp = [0; 4];
|
||||
value
|
||||
.chars()
|
||||
.all(|char| u16::from_str_radix(char.encode_utf8(&mut tmp), 16).is_ok()).then_some(value)
|
||||
.ok_or_else(|| "Not a valid Git SHA".to_owned())
|
||||
})
|
||||
.and_then(|sha| {
|
||||
std::process::Command::new("git")
|
||||
.args([
|
||||
"rev-parse",
|
||||
"--quiet",
|
||||
"--verify",
|
||||
&format!("{sha}^{{commit}}")
|
||||
])
|
||||
.output()
|
||||
.map_err(|_| "Failed to spawn Git command to verify SHA".to_owned())
|
||||
.and_then(|output|
|
||||
output
|
||||
.status.success()
|
||||
.then_some(sha)
|
||||
.ok_or_else(|| format!("SHA {sha} is not a valid Git SHA within this repository!")))
|
||||
}).map(|sha| GitSha(sha.to_owned()))
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
pub(crate) struct GenerateWorkflowArgs {
|
||||
#[arg(value_parser = parse_ref)]
|
||||
/// The Git SHA to use when invoking this
|
||||
pub(crate) sha: Option<GitSha>,
|
||||
}
|
||||
|
||||
enum WorkflowSource {
|
||||
Contextless(fn() -> Workflow),
|
||||
WithContext(fn(&GenerateWorkflowArgs) -> Workflow),
|
||||
}
|
||||
|
||||
struct WorkflowFile {
|
||||
source: WorkflowSource,
|
||||
r#type: WorkflowType,
|
||||
}
|
||||
|
||||
impl WorkflowFile {
|
||||
fn zed(f: fn() -> Workflow) -> WorkflowFile {
|
||||
WorkflowFile {
|
||||
source: WorkflowSource::Contextless(f),
|
||||
r#type: WorkflowType::Zed,
|
||||
}
|
||||
}
|
||||
|
||||
fn extension(f: fn(&GenerateWorkflowArgs) -> Workflow) -> WorkflowFile {
|
||||
WorkflowFile {
|
||||
source: WorkflowSource::WithContext(f),
|
||||
r#type: WorkflowType::ExtensionCi,
|
||||
}
|
||||
}
|
||||
|
||||
fn extension_shared(f: fn(&GenerateWorkflowArgs) -> Workflow) -> WorkflowFile {
|
||||
WorkflowFile {
|
||||
source: WorkflowSource::WithContext(f),
|
||||
r#type: WorkflowType::ExtensionsShared,
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_file(&self, workflow_args: &GenerateWorkflowArgs) -> Result<()> {
|
||||
let workflow = match &self.source {
|
||||
WorkflowSource::Contextless(f) => f(),
|
||||
WorkflowSource::WithContext(f) => f(workflow_args),
|
||||
};
|
||||
let workflow_folder = self.r#type.folder_path();
|
||||
|
||||
fs::create_dir_all(&workflow_folder).with_context(|| {
|
||||
format!("Failed to create directory: {}", workflow_folder.display())
|
||||
})?;
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, strum::EnumIter)]
|
||||
pub enum WorkflowType {
|
||||
/// Workflows living in the Zed repository
|
||||
Zed,
|
||||
/// Workflows living in the `zed-extensions/workflows` repository that are
|
||||
/// required workflows for PRs to the extension organization
|
||||
ExtensionCi,
|
||||
/// Workflows living in each of the extensions to perform checks and version
|
||||
/// bumps until a better, more centralized system for that is in place.
|
||||
ExtensionsShared,
|
||||
}
|
||||
|
||||
impl WorkflowType {
|
||||
const PREAMBLE: &str = "# Generated from xtask::workflows::";
|
||||
|
||||
fn disclaimer(&self, workflow_name: &str) -> String {
|
||||
format!(
|
||||
concat!(
|
||||
"{preamble}{workflow_name}{external_disclaimer}\n",
|
||||
"# Rebuild with `cargo xtask workflows`.",
|
||||
),
|
||||
preamble = Self::PREAMBLE,
|
||||
workflow_name = workflow_name,
|
||||
external_disclaimer = (*self != WorkflowType::Zed)
|
||||
.then_some(" within the Zed repository.")
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn folder_path(&self) -> PathBuf {
|
||||
match self {
|
||||
WorkflowType::Zed => PathBuf::from(".github/workflows"),
|
||||
WorkflowType::ExtensionCi => PathBuf::from("extensions/workflows"),
|
||||
WorkflowType::ExtensionsShared => PathBuf::from("extensions/workflows/shared"),
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_generated_workflows() -> Result<()> {
|
||||
for workflow_type in Self::iter() {
|
||||
for path in fs::read_dir(workflow_type.folder_path())? {
|
||||
let entry = path?;
|
||||
if !entry.file_type().is_ok_and(|file_type| file_type.is_file()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let path = entry.path();
|
||||
if fs::read_to_string(&path)
|
||||
.is_ok_and(|content| content.starts_with(Self::PREAMBLE))
|
||||
{
|
||||
fs::remove_file(path)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_workflows(args: GenerateWorkflowArgs) -> Result<()> {
|
||||
if !Path::new("crates/zed/").is_dir() {
|
||||
anyhow::bail!("xtask workflows must be ran from the project root");
|
||||
}
|
||||
|
||||
// Remove all previously generated workflows to ensure these do not become stale.
|
||||
WorkflowType::remove_generated_workflows()?;
|
||||
|
||||
let workflows = [
|
||||
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),
|
||||
WorkflowFile::zed(danger::danger),
|
||||
WorkflowFile::zed(deploy_collab::deploy_collab),
|
||||
WorkflowFile::zed(deploy_docs::deploy_docs),
|
||||
WorkflowFile::zed(deploy_docs::deploy_nightly_docs),
|
||||
WorkflowFile::zed(extension_bump::extension_bump),
|
||||
WorkflowFile::zed(extension_auto_bump::extension_auto_bump),
|
||||
WorkflowFile::zed(extension_tests::extension_tests),
|
||||
WorkflowFile::zed(extension_workflow_rollout::extension_workflow_rollout),
|
||||
WorkflowFile::zed(publish_extension_cli::publish_extension_cli),
|
||||
WorkflowFile::zed(release::release),
|
||||
WorkflowFile::zed(release_nightly::release_nightly),
|
||||
WorkflowFile::zed(run_agent_evals::run_cron_unit_evals),
|
||||
WorkflowFile::zed(run_agent_evals::run_unit_evals),
|
||||
WorkflowFile::zed(run_bundling::run_bundling),
|
||||
WorkflowFile::zed(run_tests::run_tests),
|
||||
/* workflows used for CI/CD in extension repositories */
|
||||
WorkflowFile::extension(extensions::run_tests::run_tests),
|
||||
WorkflowFile::extension_shared(extensions::bump_version::bump_version),
|
||||
];
|
||||
|
||||
for workflow_file in workflows {
|
||||
workflow_file.generate_file(&args)?;
|
||||
}
|
||||
|
||||
workflow_checks::validate(Default::default())
|
||||
}
|
||||
Reference in New Issue
Block a user