Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 38 additions & 1 deletion src/commands/variables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,27 @@ pub struct Args {
#[clap(long)]
set: Vec<Variable>,

/// Read environment variable pairs from stdin.
///
/// Each line should contain exactly one "{KEY}={VALUE}"" pair. Leading and trailing whitespace is trimmed.
/// Empty lines are ignored. If combined with --set, values from both sources are applied.
///
/// Examples:
///
/// # Read a single variable from stdin
///
/// echo "FOO=bar" | railway variables --set-from-stdin
///
/// # Read multiple variables, one per line
///
/// printf "FOO=bar\nBAZ=qux\n" | railway variables --set-from-stdin
///
/// # Load variables from a .env file
///
/// cat .env | railway variables --set-from-stdin
#[clap(long, verbatim_doc_comment)]
set_from_stdin: bool,

/// Output in JSON format
#[clap(long)]
json: bool,
Expand All @@ -43,7 +64,7 @@ pub struct Args {
skip_deploys: bool,
}

pub async fn command(args: Args) -> Result<()> {
pub async fn command(mut args: Args) -> Result<()> {
let configs = Configs::new()?;
let client = GQLClient::new_authorized(&configs)?;
let linked_project = configs.get_linked_project().await?;
Expand Down Expand Up @@ -74,6 +95,22 @@ pub async fn command(args: Args) -> Result<()> {
_ => bail!(RailwayError::NoServiceLinked),
};

if args.set_from_stdin {
let stdin = stdin();

if stdin.is_terminal() {
bail!("--set-from-stdin requires input from stdin (e.g., via pipe or redirect)");
}

for line in stdin.lock().lines() {
let line = line?;

if !line.trim().is_empty() {
args.set.push(line.trim().to_string());
}
}
}

if !args.set.is_empty() {
set_variables(
args.set,
Expand Down
Loading