{"record":{"id":"b795d5b30996c9ce","repo":"dbt-labs/dbt-core","slug":"commit-author-and-commit-email-must-be-set-tog","errorCode":null,"errorMessage":"--commit-author and --commit-email must be set together","messagePattern":"--commit-author and --commit-email must be set together","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/dbt-ci/src/homebrew/publish.rs","lineNumber":97,"sourceCode":"    fs::copy(&args.formula, &dest)\n        .with_context(|| format!(\"copy {} -> {}\", args.formula.display(), dest.display()))?;\n\n    let status = run_git_capture(Some(work.path()), &[\"status\", \"--porcelain\"])?;\n    if status.trim().is_empty() {\n        eprintln!(\"✓ {} already up to date in tap\", filename);\n        return Ok(());\n    }\n\n    // Only override identity if BOTH flags are provided. Otherwise inherit\n    // whatever git config the cloned tap has — which on a dev machine comes\n    // from `~/.gitconfig`.\n    match (&args.commit_author, &args.commit_email) {\n        (Some(name), Some(email)) => {\n            run_git(Some(work.path()), &[\"config\", \"user.name\", name])?;\n            run_git(Some(work.path()), &[\"config\", \"user.email\", email])?;\n        }\n        (None, None) => {} // inherit\n        _ => bail!(\"--commit-author and --commit-email must be set together\"),\n    }\n\n    run_git(Some(work.path()), &[\"add\", &format!(\"Formula/{filename}\")])?;\n    let message = format!(\n        \"{stem} {version}\",\n        stem = filename.trim_end_matches(\".rb\"),\n        version = args.version,\n    );\n    run_git(Some(work.path()), &[\"commit\", \"-m\", &message])?;\n\n    if args.dry_run {\n        eprintln!(\"→ dry-run: skipping push. Patch follows:\\n\");\n        run_git(Some(work.path()), &[\"--no-pager\", \"show\", \"HEAD\"])?;\n        return Ok(());\n    }\n\n    // Push needs the same `-c http.extraHeader=…` knobs as clone.\n    let mut push_argv: Vec<OsString> = auth_args;","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/dbt-labs/dbt-core/blob/0267ce9170576975b76b64ce856b2e5848e96617/crates/dbt-ci/src/homebrew/publish.rs#L79-L115","documentation":"When committing the formula update to the tap repository, the commit author identity can optionally be overridden via `--commit-author` and `--commit-email`. `run` enforces that these two options are always supplied together: providing exactly one leaves git's user config half-specified, so the command bails with a descriptive message. Providing neither is allowed, in which case the inherited git identity is used.","triggerScenarios":"Running `dbt-ci homebrew publish` with `--commit-author <name>` but no `--commit-email`, or `--commit-email <email>` but no `--commit-author`.","commonSituations":"CI templating that fills one variable but not the other (e.g., a secrets/config map containing the bot name but not the email); a developer hand-typing the flags and forgetting the pair; scripts updated to add an author override without updating the email.","solutions":["Pass both flags together: `--commit-author \"Bot Name\" --commit-email bot@example.com`.","If you want the default git identity, remove both flags and let the tap repo's configured user.name/user.email apply.","Fix the CI template/workflow so both values are sourced together (e.g., from the same bot identity config)."],"exampleFix":"// before\ndbt-ci homebrew publish --formula Formula/dbt.rb --commit-author \"Release Bot\"\n// after\ndbt-ci homebrew publish --formula Formula/dbt.rb --commit-author \"Release Bot\" --commit-email bot@example.com","handlingStrategy":"validation","validationCode":"fn validate_commit_identity(author: &Option<String>, email: &Option<String>) -> Result<(), String> {\n    match (author, email) {\n        (Some(_), Some(_)) | (None, None) => Ok(()),\n        _ => Err(\"--commit-author and --commit-email must be set together\".to_string()),\n    }\n}","typeGuard":null,"tryCatchPattern":"match publish(args) {\n    Err(e) if e.to_string().contains(\"must be set together\") => {\n        eprintln!(\"Supply both --commit-author and --commit-email, or neither.\");\n        std::process::exit(2);\n    }\n    Err(e) => return Err(e),\n    Ok(v) => Ok(v),\n}","preventionTips":["Define the bot identity (name + email) as a single unit in CI config so both flags are always templated together.","Wrap the publish invocation in a wrapper script that enforces the pair before calling the CLI.","Default to omitting both flags and relying on the tap repo's configured git identity when unsure."],"tags":["cli","validation","git","arguments"],"backgroundTag":"mutually-exclusive-flags","analyzedSha":"0267ce9170576975b76b64ce856b2e5848e96617","analyzedAt":"2026-09-07T21:53:39.732Z","contentChangedAt":"2026-09-07T21:53:39.732Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}