Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(turbo): g #4896

Merged
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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
tknickman marked this conversation as resolved.
Show resolved Hide resolved
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