Skip to content

Commit

Permalink
feat(turbo): g (#4896)
Browse files Browse the repository at this point in the history
Co-authored-by: Nicholas Yang <nicholas.yang@vercel.com>
  • Loading branch information
tknickman and NicholasLYang committed May 11, 2023
1 parent 5959a11 commit 3e1c136
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 1 deletion.
74 changes: 73 additions & 1 deletion crates/turborepo-lib/src/cli.rs
Expand Up @@ -14,7 +14,7 @@ use tracing::{debug, error};
use turbopath::AbsoluteSystemPathBuf;

use crate::{
commands::{bin, daemon, link, login, logout, unlink, CommandBase},
commands::{bin, daemon, generate, link, login, logout, unlink, CommandBase},
get_version,
shim::{RepoMode, RepoState},
tracing::TurboSubscriber,
Expand Down Expand Up @@ -264,6 +264,14 @@ pub enum Command {
#[clap(long, value_enum, default_value_t = LinkTarget::RemoteCache)]
target: LinkTarget,
},
/// Generate a new app / package
Generate {
#[clap(long, default_value_t = String::from("latest"), hide = true)]
tag: String,
#[clap(subcommand)]
#[serde(flatten)]
command: GenerateCommand,
},
/// Login to your Vercel account
Login {
#[clap(long = "sso-team")]
Expand Down Expand Up @@ -300,6 +308,66 @@ pub enum Command {
},
}

#[derive(Parser, Clone, Debug, Default, Serialize, PartialEq)]
pub struct GenerateCustomArgs {
/// The name of the generator to run
pub generator_name: Option<String>,
/// Generator configuration file
#[clap(short = 'c', long)]
pub config: Option<String>,
/// The root of your repository (default: directory with root turbo.json)
#[clap(short = 'r', long)]
pub root: Option<String>,
/// Answers passed directly to generator
#[clap(short = 'a', long, value_delimiter = ' ', num_args = 1..)]
pub args: Vec<String>,
}

#[derive(Parser, Clone, Debug, Default, Serialize, PartialEq)]
pub struct GenerateAddArgs {
/// Name for the new workspace
#[clap(short = 'n', long)]
pub name: Option<String>,
/// Generate an empty workspace
#[clap(short = 'b', long, conflicts_with = "copy", default_value_t = true)]
pub empty: bool,
/// Generate a workspace using an existing workspace as a template
#[clap(short = 'c', long, conflicts_with = "empty", default_value_t = false)]
pub copy: bool,
/// Where the new workspace should be created
#[clap(short = 'd', long)]
pub destination: Option<String>,
/// The type of workspace to create
#[clap(short = 'w', long)]
pub what: Option<String>,
/// The root of your repository (default: directory with root turbo.json)
#[clap(short = 'r', long)]
pub root: Option<String>,
/// An example package to add. You can use a GitHub URL with any branch
/// and/or subdirectory.
#[clap(short = 'e', long)]
pub example: Option<String>,
/// In a rare case, your GitHub URL might contain a branch name with a slash
/// (e.g. bug/fix-1) and the path to the example (e.g. foo/bar). In this
/// case, you must specify the path to the example separately:
/// --example-path foo/bar
#[clap(short = 'p', long)]
pub example_path: Option<String>,
/// Do not filter available dependencies by the workspace type
#[clap(long, default_value_t = false)]
pub show_all_dependencies: bool,
}

#[derive(Subcommand, Clone, Debug, Serialize, PartialEq)]
pub enum GenerateCommand {
/// Add a new package or app to your project
#[clap(name = "add", alias = "a")]
Add(GenerateAddArgs),
/// Run custom generators
#[clap(name = "run", alias = "r")]
Custom(GenerateCustomArgs),
}

#[derive(Parser, Clone, Debug, Default, Serialize, PartialEq)]
pub struct RunArgs {
/// Override the filesystem cache directory.
Expand Down Expand Up @@ -567,6 +635,10 @@ pub async fn run(

Ok(Payload::Rust(Ok(0)))
}
Command::Generate { command, tag } => {
generate::run(command, tag)?;
Ok(Payload::Rust(Ok(0)))
}
Command::Daemon { command, idle_time } => {
let base = CommandBase::new(cli_args.clone(), repo_root, version, ui)?;

Expand Down
54 changes: 54 additions & 0 deletions crates/turborepo-lib/src/commands/generate.rs
@@ -0,0 +1,54 @@
use std::process::{Command, Stdio};

use anyhow::Result;

use crate::{child::spawn_child, cli::GenerateCommand};

fn verify_requirements() -> Result<()> {
let output = Command::new("npx")
.arg("--version")
.stdout(Stdio::null())
.stderr(Stdio::null())
.status();

match output {
Ok(result) if result.success() => Ok(()),
_ => Err(anyhow::anyhow!(
"Unable to run generate - missing requirements (npx)"
)),
}
}

fn call_turbo_gen(command: &str, tag: &String, raw_args: &str) -> Result<i32> {
let mut npx = Command::new("npx");
npx.arg("--yes")
.arg(format!("@turbo/gen@{}", tag))
.arg("raw")
.arg(command)
.args(["--json", raw_args])
.stdout(Stdio::inherit())
.stderr(Stdio::inherit());

let child = spawn_child(npx)?;
let exit_code = child.wait()?.code().unwrap_or(2);
Ok(exit_code)
}

pub fn run(command: &GenerateCommand, tag: &String) -> Result<()> {
// ensure npx is available
verify_requirements()?;

match command {
GenerateCommand::Add(args) => {
// convert args to json
let raw_args = serde_json::to_string(args)?;
call_turbo_gen("add", tag, &raw_args)?;
}
GenerateCommand::Custom(args) => {
let raw_args = serde_json::to_string(args)?;
call_turbo_gen("generate", tag, &raw_args)?;
}
};

Ok(())
}
1 change: 1 addition & 0 deletions crates/turborepo-lib/src/commands/mod.rs
Expand Up @@ -17,6 +17,7 @@ use crate::{

pub(crate) mod bin;
pub(crate) mod daemon;
pub(crate) mod generate;
pub(crate) mod link;
pub(crate) mod login;
pub(crate) mod logout;
Expand Down
1 change: 1 addition & 0 deletions turborepo-tests/integration/tests/no_args.t
Expand Up @@ -12,6 +12,7 @@ Make sure exit code is 2 when no args are passed
completion Generate the autocompletion script for the specified shell
daemon Runs the Turborepo background daemon
link Link your local directory to a Vercel organization and enable remote caching
generate Generate a new app / package
login Login to your Vercel account
logout Logout to your Vercel account
prune Prepare a subset of your monorepo
Expand Down
2 changes: 2 additions & 0 deletions turborepo-tests/integration/tests/turbo_help.t
Expand Up @@ -12,6 +12,7 @@ Test help flag
completion Generate the autocompletion script for the specified shell
daemon Runs the Turborepo background daemon
link Link your local directory to a Vercel organization and enable remote caching
generate Generate a new app / package
login Login to your Vercel account
logout Logout to your Vercel account
prune Prepare a subset of your monorepo
Expand Down Expand Up @@ -78,6 +79,7 @@ Test help flag
completion Generate the autocompletion script for the specified shell
daemon Runs the Turborepo background daemon
link Link your local directory to a Vercel organization and enable remote caching
generate Generate a new app / package
login Login to your Vercel account
logout Logout to your Vercel account
prune Prepare a subset of your monorepo
Expand Down

1 comment on commit 3e1c136

@vercel
Copy link

@vercel vercel bot commented on 3e1c136 May 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.