Skip to content

Commit

Permalink
[spr] initial version
Browse files Browse the repository at this point in the history
Created using spr 1.3.6-beta.1
  • Loading branch information
sunshowers committed Aug 17, 2024
1 parent c86ff79 commit 2c87d14
Show file tree
Hide file tree
Showing 12 changed files with 442 additions and 126 deletions.
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ members = [
"dev-tools/omicron-dev",
"dev-tools/omicron-dev-lib",
"dev-tools/openapi-manager",
"dev-tools/openapi-manager/types",
"dev-tools/oxlog",
"dev-tools/reconfigurator-cli",
"dev-tools/releng",
Expand Down Expand Up @@ -142,6 +143,7 @@ default-members = [
"dev-tools/omicron-dev",
"dev-tools/omicron-dev-lib",
"dev-tools/openapi-manager",
"dev-tools/openapi-manager/types",
"dev-tools/oxlog",
"dev-tools/reconfigurator-cli",
"dev-tools/releng",
Expand Down Expand Up @@ -447,6 +449,7 @@ oxlog = { path = "dev-tools/oxlog" }
oxnet = { git = "https://github.com/oxidecomputer/oxnet" }
once_cell = "1.19.0"
openapi-lint = { git = "https://github.com/oxidecomputer/openapi-lint", branch = "main" }
openapi-manager-types = { path = "dev-tools/openapi-manager/types" }
openapiv3 = "2.0.0"
# must match samael's crate!
openssl = "0.10"
Expand Down
1 change: 1 addition & 0 deletions dev-tools/openapi-manager/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ nexus-internal-api.workspace = true
omicron-workspace-hack.workspace = true
openapiv3.workspace = true
openapi-lint.workspace = true
openapi-manager-types.workspace = true
owo-colors.workspace = true
oximeter-api.workspace = true
serde_json.workspace = true
Expand Down
128 changes: 78 additions & 50 deletions dev-tools/openapi-manager/src/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,16 @@
use std::{io::Write, process::ExitCode};

use anyhow::Result;
use camino::Utf8Path;
use indent_write::io::IndentWriter;
use owo_colors::OwoColorize;
use similar::TextDiff;

use crate::{
output::{
display_api_spec, display_error, display_summary, headers::*, plural,
write_diff, OutputOpts, Styles,
display_api_spec, display_api_spec_file, display_error,
display_summary, headers::*, plural, write_diff, OutputOpts, Styles,
},
spec::{all_apis, CheckStatus},
spec::{all_apis, CheckError, Environment},
FAILURE_EXIT_CODE, NEEDS_UPDATE_EXIT_CODE,
};

Expand All @@ -37,7 +36,7 @@ impl CheckResult {
}

pub(crate) fn check_impl(
dir: &Utf8Path,
env: &Environment,
output: &OutputOpts,
) -> Result<CheckResult> {
let mut styles = Styles::default();
Expand All @@ -48,6 +47,7 @@ pub(crate) fn check_impl(
let all_apis = all_apis();
let total = all_apis.len();
let count_width = total.to_string().len();
let count_section_indent = count_section_indent(count_width);
let continued_indent = continued_indent(count_width);

eprintln!("{:>HEADER_WIDTH$}", SEPARATOR);
Expand All @@ -59,56 +59,85 @@ pub(crate) fn check_impl(
plural::documents(total),
);
let mut num_up_to_date = 0;
let mut num_stale = 0;
let mut num_missing = 0;
let mut num_out_of_date = 0;
let mut num_failed = 0;

for (ix, spec) in all_apis.iter().enumerate() {
let count = ix + 1;

match spec.check(&dir) {
Ok(status) => match status {
CheckStatus::Ok(summary) => {
eprintln!(
"{:>HEADER_WIDTH$} [{count:>count_width$}/{total}] {}: {}",
UP_TO_DATE.style(styles.success_header),
display_api_spec(spec, &styles),
display_summary(&summary, &styles),
);
match spec.check(env) {
Ok(status) => {
let total_errors = status.total_errors();
let total_errors_width = total_errors.to_string().len();

if total_errors == 0 {
// Success case.
let extra = if status.extra_files_len() > 0 {
format!(
", {} extra files",
status.extra_files_len().style(styles.bold)
)
} else {
"".to_string()
};

num_up_to_date += 1;
}
CheckStatus::Stale { full_path, actual, expected } => {
eprintln!(
"{:>HEADER_WIDTH$} [{count:>count_width$}/{total}] {}",
STALE.style(styles.warning_header),
"{:>HEADER_WIDTH$} [{count:>count_width$}/{total}] {}: {}{extra}",
UP_TO_DATE.style(styles.success_header),
display_api_spec(spec, &styles),
display_summary(&status.summary, &styles),
);

let diff = TextDiff::from_lines(&actual, &expected);
write_diff(
&diff,
&full_path,
&styles,
// Add an indent to align diff with the status message.
&mut IndentWriter::new(
&continued_indent,
std::io::stderr(),
),
)?;

num_stale += 1;
num_up_to_date += 1;
continue;
}
CheckStatus::Missing => {
eprintln!(
"{:>HEADER_WIDTH$} [{count:>count_width$}/{total}] {}",
MISSING.style(styles.warning_header),
display_api_spec(spec, &styles),
);

num_missing += 1;
// Out of date: print errors.
eprintln!(
"{:>HEADER_WIDTH$} [{count:>count_width$}/{total}] {}",
OUT_OF_DATE.style(styles.warning_header),
display_api_spec(spec, &styles),
);
num_out_of_date += 1;

for (error_ix, (spec_file, error)) in
status.iter_errors().enumerate()
{
let error_count = error_ix + 1;

match error {
CheckError::Stale { full_path, actual, expected } => {
eprintln!(
"{:>HEADER_WIDTH$}{count_section_indent}\
({error_count:>total_errors_width$}/{total_errors}) {}",
STALE.style(styles.warning_header),
display_api_spec_file(spec, spec_file, &styles),
);

let diff =
TextDiff::from_lines(&**actual, &**expected);
write_diff(
&diff,
&full_path,
&styles,
// Add an indent to align diff with the status message.
&mut IndentWriter::new(
&continued_indent,
std::io::stderr(),
),
)?;
}
CheckError::Missing => {
eprintln!(
"{:>HEADER_WIDTH$}{count_section_indent}\
({error_count:>total_errors_width$}/{total_errors}) {}",
MISSING.style(styles.warning_header),
display_api_spec_file(spec, spec_file, &styles),
);
}
}
}
},
}
Err(error) => {
eprint!(
"{:>HEADER_WIDTH$} [{count:>count_width$}/{total}] {}",
Expand All @@ -131,20 +160,19 @@ pub(crate) fn check_impl(

let status_header = if num_failed > 0 {
FAILURE.style(styles.failure_header)
} else if num_stale > 0 {
STALE.style(styles.warning_header)
} else if num_out_of_date > 0 {
OUT_OF_DATE.style(styles.warning_header)
} else {
SUCCESS.style(styles.success_header)
};

eprintln!(
"{:>HEADER_WIDTH$} {} {} checked: {} up-to-date, {} stale, {} missing, {} failed",
"{:>HEADER_WIDTH$} {} {} checked: {} up-to-date, {} out-of-date, {} failed",
status_header,
total.style(styles.bold),
plural::documents(total),
num_up_to_date.style(styles.bold),
num_stale.style(styles.bold),
num_missing.style(styles.bold),
num_out_of_date.style(styles.bold),
num_failed.style(styles.bold),
);
if num_failed > 0 {
Expand All @@ -154,7 +182,7 @@ pub(crate) fn check_impl(
"cargo xtask openapi generate".style(styles.bold)
);
Ok(CheckResult::Failures)
} else if num_stale > 0 {
} else if num_out_of_date > 0 {
eprintln!(
"{:>HEADER_WIDTH$} (run {} to update)",
"",
Expand All @@ -170,14 +198,14 @@ pub(crate) fn check_impl(
mod tests {
use std::process::ExitCode;

use crate::spec::find_openapi_dir;
use crate::spec::Environment;

use super::*;

#[test]
fn check_apis_up_to_date() -> Result<ExitCode> {
let output = OutputOpts { color: clap::ColorChoice::Auto };
let dir = find_openapi_dir()?;
let dir = Environment::new(None)?;

let result = check_impl(&dir, &output)?;
Ok(result.to_exit_code())
Expand Down
8 changes: 4 additions & 4 deletions dev-tools/openapi-manager/src/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use clap::{Args, Parser, Subcommand};

use crate::{
check::check_impl, generate::generate_impl, list::list_impl,
output::OutputOpts, spec::openapi_dir,
output::OutputOpts, spec::Environment,
};

/// Manage OpenAPI specifications.
Expand Down Expand Up @@ -73,7 +73,7 @@ pub struct GenerateArgs {

impl GenerateArgs {
fn exec(self, output: &OutputOpts) -> anyhow::Result<ExitCode> {
let dir = openapi_dir(self.dir)?;
let dir = Environment::new(self.dir)?;
Ok(generate_impl(&dir, output)?.to_exit_code())
}
}
Expand All @@ -87,8 +87,8 @@ pub struct CheckArgs {

impl CheckArgs {
fn exec(self, output: &OutputOpts) -> anyhow::Result<ExitCode> {
let dir = openapi_dir(self.dir)?;
Ok(check_impl(&dir, output)?.to_exit_code())
let env = Environment::new(self.dir)?;
Ok(check_impl(&env, output)?.to_exit_code())
}
}

Expand Down
26 changes: 14 additions & 12 deletions dev-tools/openapi-manager/src/generate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
use std::{io::Write, process::ExitCode};

use anyhow::Result;
use camino::Utf8Path;
use indent_write::io::IndentWriter;
use owo_colors::OwoColorize;

Expand All @@ -14,7 +13,7 @@ use crate::{
display_api_spec, display_error, display_summary, headers::*, plural,
OutputOpts, Styles,
},
spec::{all_apis, OverwriteStatus},
spec::{all_apis, Environment},
FAILURE_EXIT_CODE,
};

Expand All @@ -34,7 +33,7 @@ impl GenerateResult {
}

pub(crate) fn generate_impl(
dir: &Utf8Path,
env: &Environment,
output: &OutputOpts,
) -> Result<GenerateResult> {
let mut styles = Styles::default();
Expand Down Expand Up @@ -62,27 +61,30 @@ pub(crate) fn generate_impl(
for (ix, spec) in all_apis.iter().enumerate() {
let count = ix + 1;

match spec.overwrite(&dir) {
Ok((status, summary)) => match status {
OverwriteStatus::Updated => {
match spec.overwrite(env) {
Ok(status) => {
let updated_count = status.updated_count();

if updated_count > 0 {
eprintln!(
"{:>HEADER_WIDTH$} [{count:>count_width$}/{total}] {}: {}",
"{:>HEADER_WIDTH$} [{count:>count_width$}/{total}] {}: {} ({} {} updated)",
UPDATED.style(styles.success_header),
display_api_spec(spec, &styles),
display_summary(&summary, &styles),
display_summary(&status.summary, &styles),
updated_count.style(styles.bold),
plural::files(updated_count),
);
num_updated += 1;
}
OverwriteStatus::Unchanged => {
} else {
eprintln!(
"{:>HEADER_WIDTH$} [{count:>count_width$}/{total}] {}: {}",
UNCHANGED.style(styles.unchanged_header),
display_api_spec(spec, &styles),
display_summary(&summary, &styles),
display_summary(&status.summary, &styles),
);
num_unchanged += 1;
}
},
}
Err(err) => {
eprintln!(
"{:>HEADER_WIDTH$} [{count:>count_width$}/{total}] {}",
Expand Down
Loading

0 comments on commit 2c87d14

Please sign in to comment.