diff --git a/.github/workflows/ecosystem.yml b/.github/workflows/ecosystem.yml index 4966f10f3..00c4ec3fb 100644 --- a/.github/workflows/ecosystem.yml +++ b/.github/workflows/ecosystem.yml @@ -6,17 +6,19 @@ on: types: [opened, synchronize] paths: - 'crates/oxc_parser/**' + - 'crates/oxc_diagnostics/**' - 'crates/oxc_cli/**' - 'crates/oxc_linter/**' - - '!.github/workflows/ecosystem.yml' + - '.github/workflows/ecosystem.yml' push: branches: - main paths: - 'crates/oxc_parser/**' + - 'crates/oxc_diagnostics/**' - 'crates/oxc_cli/**' - 'crates/oxc_linter/**' - - '!.github/workflows/ecosystem.yml' + - '.github/workflows/ecosystem.yml' concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} @@ -59,7 +61,7 @@ jobs: ref: master steps: - name: Clone ${{ matrix.repository }} - uses: taiki-e/checkout-action@v1 + uses: actions/checkout@v4 with: repository: ${{ matrix.repository }} ref: ${{ matrix.ref }} diff --git a/crates/oxc_cli/src/command/lint.rs b/crates/oxc_cli/src/command/lint.rs index 9ee8ec3e5..86eeca652 100644 --- a/crates/oxc_cli/src/command/lint.rs +++ b/crates/oxc_cli/src/command/lint.rs @@ -135,7 +135,7 @@ pub struct WarningOptions { /// Output #[derive(Debug, Clone, Bpaf)] pub struct OutputOptions { - /// Use a specific output format (default, json) + /// Use a specific output format (default, json, unix, checkstyle, github) #[bpaf(long, short, fallback(OutputFormat::Default), hide_usage)] pub format: OutputFormat, } @@ -143,6 +143,9 @@ pub struct OutputOptions { #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum OutputFormat { Default, + /// GitHub Check Annotation + /// + Github, Json, Unix, Checkstyle, @@ -156,6 +159,7 @@ impl FromStr for OutputFormat { "default" => Ok(Self::Default), "unix" => Ok(Self::Unix), "checkstyle" => Ok(Self::Checkstyle), + "github" => Ok(Self::Github), _ => Err(format!("'{s}' is not a known format")), } } diff --git a/crates/oxc_cli/src/lint/mod.rs b/crates/oxc_cli/src/lint/mod.rs index 30027238b..e8d8cd39c 100644 --- a/crates/oxc_cli/src/lint/mod.rs +++ b/crates/oxc_cli/src/lint/mod.rs @@ -165,6 +165,7 @@ impl LintRunner { OutputFormat::Json => diagnostic_service.set_json_reporter(), OutputFormat::Unix => diagnostic_service.set_unix_reporter(), OutputFormat::Checkstyle => diagnostic_service.set_checkstyle_reporter(), + OutputFormat::Github => diagnostic_service.set_github_reporter(), } diagnostic_service } diff --git a/crates/oxc_diagnostics/src/reporter/github.rs b/crates/oxc_diagnostics/src/reporter/github.rs new file mode 100644 index 000000000..70e1a2892 --- /dev/null +++ b/crates/oxc_diagnostics/src/reporter/github.rs @@ -0,0 +1,42 @@ +use std::{ + borrow::Cow, + io::{BufWriter, Stdout, Write}, +}; + +use crate::{miette::Error, Severity}; + +use super::{writer, DiagnosticReporter, Info}; + +pub struct GithubReporter { + writer: BufWriter, +} + +impl Default for GithubReporter { + fn default() -> Self { + Self { writer: writer() } + } +} + +impl DiagnosticReporter for GithubReporter { + fn finish(&mut self) { + self.writer.flush().unwrap(); + } + + fn render_diagnostics(&mut self, _s: &[u8]) {} + + fn render_error(&mut self, error: Error) -> Option { + let message = format_github(&error); + self.writer.write_all(message.as_bytes()).unwrap(); + None + } +} + +fn format_github(diagnostic: &Error) -> String { + let Info { line, column, filename, message, severity, rule_id } = Info::new(diagnostic); + let severity = match severity { + Severity::Error => "error", + Severity::Warning | miette::Severity::Advice => "warning", + }; + let title = rule_id.map_or(Cow::Borrowed("oxlint"), Cow::Owned); + format!("::{severity} file={filename},line={line},endLine={line},col={column},endColumn={column},title={title}::{message}\n") +} diff --git a/crates/oxc_diagnostics/src/reporter/mod.rs b/crates/oxc_diagnostics/src/reporter/mod.rs index 4536bdb8b..dd12eb16d 100644 --- a/crates/oxc_diagnostics/src/reporter/mod.rs +++ b/crates/oxc_diagnostics/src/reporter/mod.rs @@ -1,11 +1,12 @@ mod checkstyle; +mod github; mod graphical; mod json; mod unix; pub use self::{ - checkstyle::CheckstyleReporter, graphical::GraphicalReporter, json::JsonReporter, - unix::UnixReporter, + checkstyle::CheckstyleReporter, github::GithubReporter, graphical::GraphicalReporter, + json::JsonReporter, unix::UnixReporter, }; use std::io::{BufWriter, Stdout}; diff --git a/crates/oxc_diagnostics/src/service.rs b/crates/oxc_diagnostics/src/service.rs index 058fd09e5..6c83057fa 100644 --- a/crates/oxc_diagnostics/src/service.rs +++ b/crates/oxc_diagnostics/src/service.rs @@ -7,7 +7,8 @@ use std::{ use crate::{ miette::NamedSource, reporter::{ - CheckstyleReporter, DiagnosticReporter, GraphicalReporter, JsonReporter, UnixReporter, + CheckstyleReporter, DiagnosticReporter, GithubReporter, GraphicalReporter, JsonReporter, + UnixReporter, }, Error, MinifiedFileError, Severity, }; @@ -64,6 +65,10 @@ impl DiagnosticService { self.reporter = Box::::default(); } + pub fn set_github_reporter(&mut self) { + self.reporter = Box::::default(); + } + #[must_use] pub fn with_quiet(mut self, yes: bool) -> Self { self.quiet = yes;