Skip to content

Commit

Permalink
Remove deprecated --output format flags (#1804)
Browse files Browse the repository at this point in the history
❗ Breaking Change!

For about a year, Rover has printed a warning that future versions will
fail when running commands with `--output [json|plain]`, and that
`--format [json|plain]` should be used instead.

This warning has been removed alongside the code for backwards
compatibility.

Warning: You should update any usage of `rover [SUBCOMMAND] --output
[json|plain]` to `rover [SUBCOMMAND] --format [json|plain]` as of the
next release. Passing `--output json` will write plain text to `./json`.
  • Loading branch information
dylan-apollo authored May 9, 2024
1 parent 5c195d4 commit bc86204
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 127 deletions.
13 changes: 11 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ All notable changes to Rover will be documented in this file.

This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

<!-- # [x.x.x] (unreleased) - 2023-mm-dd
<!-- # [x.x.x] (unreleased) - 2024-mm-dd
> Important: x potentially breaking changes below, indicated by **❗ BREAKING ❗**
Expand All @@ -18,6 +18,16 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
## 📚 Documentation -->

# [0.24.0] (unreleased) - 2024-mm-dd

> Important: 1 potentially breaking change below, indicated by **❗ BREAKING ❗**
## ❗ BREAKING ❗

- **Removed the deprecated `plain` and `json` options for `--output` - @dylan-apollo PR #1804**

The `--output` option is now only for specifying a file to write to. The `--format` option should be used to specify the format of the output.

# [0.23.0] - 2024-03-26

## 🚀 Features
Expand Down Expand Up @@ -61,7 +71,6 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

- **Document how to use `subgraph fetch` with proposals - @Meschreiber PR #1823**


# [0.22.0] - 2023-12-13

## 🚀 Features
Expand Down
16 changes: 13 additions & 3 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use rover_client::shared::GitContext;
use sputnik::Session;
use timber::Level;

use std::fmt::Display;
use std::{io, process, thread};

#[derive(Debug, Serialize, Parser)]
Expand Down Expand Up @@ -116,7 +117,7 @@ impl Rover {
pub fn run(&self) -> RoverResult<()> {
timber::init(self.log_level);
tracing::trace!(command_structure = ?self);
self.output_opts.validate_options();
self.output_opts.set_no_color();

// attempt to create a new `Session` to capture anonymous usage data
let rover_output = match Session::new(self) {
Expand Down Expand Up @@ -412,14 +413,23 @@ pub enum Command {
License(command::License),
}

#[derive(Default, ValueEnum, Debug, Serialize, Clone, Eq, PartialEq)]
#[derive(Default, ValueEnum, Debug, Serialize, Clone, Copy, Eq, PartialEq)]
pub enum RoverOutputFormatKind {
#[default]
Plain,
Json,
}

#[derive(ValueEnum, Debug, Serialize, Clone, Eq, PartialEq)]
impl Display for RoverOutputFormatKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
RoverOutputFormatKind::Plain => write!(f, "plain"),
RoverOutputFormatKind::Json => write!(f, "json"),
}
}
}

#[derive(ValueEnum, Debug, Serialize, Clone, Copy, Eq, PartialEq)]
pub enum RoverOutputKind {
RoverOutput,
RoverError,
Expand Down
142 changes: 20 additions & 122 deletions src/options/output.rs
Original file line number Diff line number Diff line change
@@ -1,81 +1,44 @@
use std::{
fmt,
io::{self, IsTerminal},
str::FromStr,
};

use anyhow::Result;
use calm_io::{stderrln, stdoutln};
use camino::Utf8PathBuf;
use clap::{error::ErrorKind as ClapErrorKind, CommandFactory, Parser, ValueEnum};
use rover_std::{Emoji, Fs, Style};
use clap::Parser;
use serde::Serialize;
use serde_json::{json, Value};

use crate::{
cli::{Rover, RoverOutputFormatKind},
RoverError, RoverOutput, RoverResult,
};

#[derive(Debug, Parser)]
pub struct Output {
/// The file path to write the command output to.
#[clap(long)]
output: OutputOpt,
}

#[derive(Debug, Clone, Eq, PartialEq, Serialize)]
pub enum RoverOutputDestination {
File(Utf8PathBuf),
Stdout,
}

#[derive(Debug, Clone, Eq, PartialEq, Serialize)]
pub enum OutputOpt {
LegacyOutputType(RoverOutputFormatKind),
File(Utf8PathBuf),
}

impl FromStr for OutputOpt {
type Err = anyhow::Error;
use rover_std::{Emoji, Fs, Style};

fn from_str(s: &str) -> Result<Self, Self::Err> {
if let Ok(format_kind) = RoverOutputFormatKind::from_str(s, true) {
Ok(Self::LegacyOutputType(format_kind))
} else {
Ok(Self::File(Utf8PathBuf::from(s)))
}
}
}
use crate::{cli::RoverOutputFormatKind, RoverError, RoverOutput, RoverResult};

pub trait RoverPrinter {
fn write_or_print(self, output_opts: &OutputOpts) -> RoverResult<()>;
}

impl RoverPrinter for RoverOutput {
fn write_or_print(self, output_opts: &OutputOpts) -> RoverResult<()> {
let (format_kind, output_destination) = output_opts.get_format_and_strategy();

// Format the RoverOutput as either plain text or JSON.
let output = match format_kind {
let output = match output_opts.format_kind {
RoverOutputFormatKind::Plain => self.get_stdout(),
RoverOutputFormatKind::Json => Ok(Some(JsonOutput::from(self.clone()).to_string())),
};

// Print the RoverOutput to file or stdout.
if let Ok(Some(result)) = output {
match output_destination {
RoverOutputDestination::File(path) => {
match &output_opts.output_file {
Some(path) => {
let success_heading = Style::Heading.paint(format!(
"{}{} was printed to",
Emoji::Memo,
self.descriptor().unwrap_or("The output")
));
let path_text = Style::Path.paint(&path);
Fs::write_file(&path, result)?;
let path_text = Style::Path.paint(path);
Fs::write_file(path, result)?;
stderrln!("{} {}", success_heading, path_text)?;
}
RoverOutputDestination::Stdout => {
None => {
// Call the appropriate method based on the variant of RoverOutput.
if let RoverOutput::GraphPublishResponse { .. } = self {
self.print_one_line_descriptor()?;
Expand All @@ -94,19 +57,18 @@ impl RoverPrinter for RoverOutput {

impl RoverPrinter for RoverError {
fn write_or_print(self, output_opts: &OutputOpts) -> RoverResult<()> {
let (format_kind, output_destination) = output_opts.get_format_and_strategy();
match format_kind {
match output_opts.format_kind {
RoverOutputFormatKind::Plain => self.print(),
RoverOutputFormatKind::Json => {
let json = JsonOutput::from(self);
match output_destination {
RoverOutputDestination::File(file) => {
match &output_opts.output_file {
Some(file) => {
let success_heading = Style::Heading
.paint(format!("{}Error JSON was printed to", Emoji::Memo,));
Fs::write_file(&file, json.to_string())?;
Fs::write_file(file, json.to_string())?;
stderrln!("{} {}", success_heading, file)?;
}
RoverOutputDestination::Stdout => json.print()?,
None => json.print()?,
}
Ok(())
}
Expand All @@ -119,42 +81,18 @@ impl RoverPrinter for RoverError {
#[derive(Debug, Parser, Serialize)]
pub struct OutputOpts {
/// Specify Rover's format type
#[arg(long = "format", global = true)]
format_kind: Option<RoverOutputFormatKind>,
#[arg(long = "format", global = true, default_value_t)]
format_kind: RoverOutputFormatKind,

/// Specify a file to write Rover's output to
#[arg(long = "output", short = 'o', global = true)]
output_file: Option<OutputOpt>,
output_file: Option<Utf8PathBuf>,
}

impl OutputOpts {
/// Validates the argument group, exiting early if there are conflicts.
/// This should be called at the start of the application.
pub fn validate_options(&self) {
match (&self.format_kind, &self.output_file) {
(Some(_), Some(OutputOpt::LegacyOutputType(_))) => {
let mut cmd = Rover::command();
cmd.error(
ClapErrorKind::ArgumentConflict,
"The argument '--output' cannot be used with '--format' when '--output' is not a file",
)
.exit();
}
(None, Some(OutputOpt::LegacyOutputType(_))) => {
let warn_prefix = Style::WarningPrefix.paint("WARN:");
let output_argument = Style::Command.paint("'--output [json|plain]'");
let format_argument = Style::Command.paint("'--format [json|plain]'");
eprintln!("{} Support for {output_argument} will be removed in a future version of Rover. Use {format_argument} instead.", warn_prefix);
}
// there are default options, so if nothing is passed, print no errors or warnings
_ => (),
}

let (_, destination) = self.get_format_and_strategy();

if !std::io::stdout().is_terminal()
|| matches!(destination, RoverOutputDestination::File(_))
{
/// Sets the `NO_COLOR` env var if the output is not a terminal or if the output is a file.
pub fn set_no_color(&self) {
if !io::stdout().is_terminal() || self.output_file.is_some() {
std::env::set_var("NO_COLOR", "true");
}
}
Expand All @@ -166,46 +104,6 @@ impl OutputOpts {
{
rover_command_output.write_or_print(self)
}

/// Get the format (plain/json) and strategy (stdout/file)
pub fn get_format_and_strategy(&self) -> (RoverOutputFormatKind, RoverOutputDestination) {
let output_type = self.output_file.clone();

match (&self.format_kind, output_type) {
(None, None)
| (None, Some(OutputOpt::LegacyOutputType(RoverOutputFormatKind::Plain))) => {
(RoverOutputFormatKind::Plain, RoverOutputDestination::Stdout)
}
(None, Some(OutputOpt::LegacyOutputType(RoverOutputFormatKind::Json))) => {
(RoverOutputFormatKind::Json, RoverOutputDestination::Stdout)
}
(None, Some(OutputOpt::File(path))) => (
RoverOutputFormatKind::Plain,
RoverOutputDestination::File(path),
),
(Some(RoverOutputFormatKind::Plain), None)
| (
Some(RoverOutputFormatKind::Plain),
Some(OutputOpt::LegacyOutputType(RoverOutputFormatKind::Plain)),
) => (RoverOutputFormatKind::Plain, RoverOutputDestination::Stdout),
(
Some(RoverOutputFormatKind::Plain),
Some(OutputOpt::LegacyOutputType(RoverOutputFormatKind::Json)),
) => (RoverOutputFormatKind::Json, RoverOutputDestination::Stdout),
(Some(RoverOutputFormatKind::Plain), Some(OutputOpt::File(path))) => (
RoverOutputFormatKind::Plain,
RoverOutputDestination::File(path),
),
(Some(RoverOutputFormatKind::Json), None)
| (Some(RoverOutputFormatKind::Json), Some(OutputOpt::LegacyOutputType(_))) => {
(RoverOutputFormatKind::Json, RoverOutputDestination::Stdout)
}
(Some(RoverOutputFormatKind::Json), Some(OutputOpt::File(path))) => (
RoverOutputFormatKind::Json,
RoverOutputDestination::File(path),
),
}
}
}

#[derive(Debug, Clone, Serialize)]
Expand Down

0 comments on commit bc86204

Please sign in to comment.