Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 17 additions & 24 deletions crates/wright-cli/src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use std::path::PathBuf;

use crate::serve::{LintPolicyArgs, ServeArgs};
mod lint;
pub(crate) use lint::*;

use crate::serve::ServeArgs;
use crate::ui::UiArgs;
use crate::update::UpdateArgs;
use clap::{Args, Parser, Subcommand, ValueEnum};
Expand All @@ -23,6 +26,13 @@ pub(crate) struct Cli {
pub(crate) version: bool,
}

/// A command whose clean verdict is its own name — the read-only query
/// commands, not a judging word (ADR-0030 decision 4).
pub(crate) fn is_query_command(command: &str) -> bool {
const QUERIES: &str = "inspect rules symbols refs cfg callgraph cost lookup package-search package-list package-outdated";
QUERIES.split(' ').any(|query| query == command)
}

pub(crate) const LONG_ABOUT: &str = "Wright compiler and Workshop tooling CLI.

Commands check correctness, summarize semantic hotspots, lint, compile,
Expand Down Expand Up @@ -91,7 +101,12 @@ pub(crate) enum Command {
/// Summarize Workshop cost, complexity hotspots, risk indicators, and
/// cross-cutting state.
Analyze(AnalyzeArgs),
/// Parse, lower, and report lint findings.
/// Parse, lower, and report lint findings. The `package` subcommand
/// manages GitHub lint rule packages (#844).
#[command(
args_conflicts_with_subcommands = true,
subcommand_precedence_over_arg = true
)]
Lint(LintArgs),
/// Parse, lower, and inspect semantic facts: the bare command prints the
/// summary, and its query subcommands expose each detail area (#429).
Expand Down Expand Up @@ -533,28 +548,6 @@ pub(crate) struct CallgraphArgs {
pub(crate) max: Option<usize>,
}

#[derive(Debug, Args)]
pub(crate) struct LintArgs {
#[command(flatten)]
pub(crate) common: CommonArgs,
#[command(flatten)]
pub(crate) select: SelectArgs,
/// Return every finding.
#[arg(long)]
pub(crate) all: bool,
/// Show the automated fixes lint offers for fixable findings as a
/// validated diff, without writing (#556).
#[arg(long, conflicts_with = "all")]
pub(crate) fix: bool,
/// Apply the fixes `--fix` previews: each fix is re-validated against
/// the current source before writing; a stale source refuses and
/// writes nothing (#556).
#[arg(long, requires = "fix")]
pub(crate) write: bool,
#[command(flatten)]
pub(crate) policy: LintPolicyArgs,
}

#[derive(Debug, Args)]
pub(crate) struct CompletionArgs {
#[command(subcommand)]
Expand Down
140 changes: 140 additions & 0 deletions crates/wright-cli/src/cli/lint.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
//! The `lint` command tree: the finding-report arguments plus the
//! `lint package` subcommand tree (#844) — discovery and lifecycle
//! management for GitHub lint rule packages over the wright-driver store
//! (#842). Installing a package never activates it; project configuration
//! pins packages by commit SHA (#843).

use clap::{Args, Subcommand};

use super::{ColorArg, CommonArgs, OutputFormatArg, RendererArg, SelectArgs};
use crate::serve::LintPolicyArgs;

/// Arguments of `wright lint`: the shared workflow options, the
/// finding-selection and policy flags, `--fix`/`--write`, and the
/// `package` subcommand.
#[derive(Debug, Args)]
pub(crate) struct LintArgs {
#[command(flatten)]
pub(crate) common: CommonArgs,
#[command(flatten)]
pub(crate) select: SelectArgs,
/// Return every finding.
#[arg(long)]
pub(crate) all: bool,
/// Show the automated fixes lint offers for fixable findings as a
/// validated diff, without writing (#556).
#[arg(long, conflicts_with = "all")]
pub(crate) fix: bool,
/// Apply the fixes `--fix` previews: each fix is re-validated against
/// the current source before writing; a stale source refuses and
/// writes nothing (#556).
#[arg(long, requires = "fix")]
pub(crate) write: bool,
#[command(flatten)]
pub(crate) policy: LintPolicyArgs,
#[command(subcommand)]
pub(crate) command: Option<LintSubcommand>,
}

/// The `lint` subcommands; only `package` exists today.
#[derive(Debug, Subcommand)]
pub(crate) enum LintSubcommand {
/// Manage GitHub lint rule packages: search, install, list, outdated,
/// update, remove (#844).
Package(PackageArgs),
}

/// Arguments of `lint package`: the package lifecycle subcommand.
#[derive(Debug, Args)]
pub(crate) struct PackageArgs {
#[command(subcommand)]
pub(crate) command: LintPackageCommand,
}

/// The `lint package` subcommands.
#[derive(Debug, Subcommand)]
pub(crate) enum LintPackageCommand {
/// Search GitHub repositories carrying the `wrightkit-lint` topic.
Search(PackageSearchArgs),
/// Download a GitHub lint rule package into the store, keyed by commit SHA.
Install(PackageInstallArgs),
/// List the package entries currently in the store.
List(PackageOutputArgs),
/// Check installed packages against the remote default-branch head
/// without changing the store.
Outdated(PackageOutputArgs),
/// Install the current default-branch head for installed packages.
Update(PackageUpdateArgs),
/// Remove a package's store entries; only Wright-managed content is
/// deleted.
Remove(PackageRemoveArgs),
}

/// The output flags every `lint package` subcommand shares.
#[derive(Debug, Args)]
pub(crate) struct PackageOutputArgs {
/// Output format.
#[arg(short = 'f', long, value_enum, default_value_t = OutputFormatArg::Text)]
pub(crate) format: OutputFormatArg,
/// Renderer environment; `auto` detects terminal, CI, and GitHub Actions.
#[arg(long, value_enum, default_value_t = RendererArg::Auto)]
pub(crate) renderer: RendererArg,
/// ANSI color policy.
#[arg(long, value_enum, default_value_t = ColorArg::Auto)]
pub(crate) color: ColorArg,
/// Return every row instead of the default bounded report.
#[arg(long)]
pub(crate) all: bool,
}

/// Arguments of `lint package search`: optional terms narrowing the
/// `topic:wrightkit-lint` repository query.
#[derive(Debug, Args)]
pub(crate) struct PackageSearchArgs {
/// Terms narrowing the repository search (for example `wait` or
/// `org:myteam`); the `wrightkit-lint` topic filter always applies.
#[arg(value_name = "QUERY")]
pub(crate) query: Option<String>,
#[command(flatten)]
pub(crate) output: PackageOutputArgs,
}

/// Arguments of `lint package install`: a GitHub `owner/repo` source —
/// URL spellings are accepted — plus an optional branch, tag, or commit.
#[derive(Debug, Args)]
pub(crate) struct PackageInstallArgs {
/// The package source: `owner/repo`, a github.com URL, or
/// `owner/repo@<ref>`; `@<ref>` and URL spellings select the revision.
#[arg(value_name = "SOURCE")]
pub(crate) source: String,
/// The branch, tag, or commit SHA to install; without it the remote
/// default-branch head is used. A full SHA installs offline.
#[arg(long = "ref", value_name = "REF")]
pub(crate) reference: Option<String>,
#[command(flatten)]
pub(crate) output: PackageOutputArgs,
}

/// Arguments of `lint package update`: an optional `owner/repo` or
/// `owner/repo@<ref>` restricting which store entries are updated.
#[derive(Debug, Args)]
pub(crate) struct PackageUpdateArgs {
/// Restrict the update to one repository, or to the one store entry a
/// `@<ref>` resolves to; without it every installed package is checked.
#[arg(value_name = "SOURCE")]
pub(crate) source: Option<String>,
#[command(flatten)]
pub(crate) output: PackageOutputArgs,
}

/// Arguments of `lint package remove`: the `owner/repo` or
/// `owner/repo@<ref>` store entry to remove.
#[derive(Debug, Args)]
pub(crate) struct PackageRemoveArgs {
/// The package to remove: `owner/repo` removes every installed entry,
/// `owner/repo@<ref>` removes only the entry the ref resolves to.
#[arg(value_name = "SOURCE")]
pub(crate) source: String,
#[command(flatten)]
pub(crate) output: PackageOutputArgs,
}
60 changes: 60 additions & 0 deletions crates/wright-cli/src/lint.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//! The `lint` command's dispatch: `lint package <subcommand>` manages
//! GitHub lint rule packages over the wright-driver store (#844) — no
//! project session is involved — while bare `lint` runs the finding
//! workflow through the shared configured runner like the other workflow
//! commands.

mod package;
mod report;

use std::process::ExitCode;

use wright_driver::result::exit;

use crate::present::{self, Presentation};
use crate::{cli, essential_envelope, fail_on, run_configured, selection_from_args};
use crate::{config_from_common, present::terminal};

/// Run `wright lint`: the `package` subcommand goes to the store commands,
/// otherwise the lint finding workflow (plain or `--fix`) runs.
pub(crate) fn run(args: cli::LintArgs) -> ExitCode {
if let Some(cli::LintSubcommand::Package(package)) = args.command {
return package::run(&package);
}
let mut config = config_from_common(&args.common);
config.selection = selection_from_args(&args.select);
if let Err(message) = args.policy.apply_to(&mut config) {
terminal::report_error(
Presentation::from_common(&args.common),
"USAGE",
"lint",
&message,
);
return ExitCode::from(exit::USAGE);
}
let presentation = present::Presentation::from_common(&args.common);
if args.fix {
return run_configured(
"lint",
config,
presentation,
fail_on(&args.common),
None,
move |session| session.lint_fix(args.write),
);
}
run_configured(
"lint",
config,
presentation.with_all(args.all),
fail_on(&args.common),
None,
|session| {
essential_envelope(
session.lint(),
|value| wright_driver::essential::lint(value, args.all),
|result| result.selection.clone(),
)
},
)
}
Loading
Loading