Skip to content

Commit bc259b9

Browse files
devin-ai-integration[bot]anthonyshewchris-olszewski
authored
feat: add noUpdateNotifier option to turbo.json (#10409)
# Allow disabling checking for a new version of Turborepo via turbo.json This PR adds a `noUpdateNotifier` option to `turbo.json` that allows disabling the update notification that appears when a new version of Turborepo is available. ## Changes - Added a `noUpdateNotifier` field to the `RawTurboJson` struct - Added a corresponding field to the `ConfigurationOptions` struct - Modified the update notifier code to check this configuration option - Added documentation for the new option Fixes #8564 Link to Devin run: https://app.devin.ai/sessions/0c3ac344fa1b4ba785417b7856eceb4f Requested by [email protected] --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: [email protected] <[email protected]> Co-authored-by: Chris Olszewski <[email protected]>
1 parent c77eafe commit bc259b9

File tree

10 files changed

+127
-5
lines changed

10 files changed

+127
-5
lines changed

crates/turborepo-lib/src/config/env.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ const TURBO_MAPPING: &[(&str, &str)] = [
4444
("turbo_cache", "cache"),
4545
("turbo_tui_scrollback_length", "tui_scrollback_length"),
4646
("turbo_concurrency", "concurrency"),
47+
("turbo_no_update_notifier", "no_update_notifier"),
4748
]
4849
.as_slice();
4950

@@ -166,6 +167,8 @@ impl ResolvedConfigurationOptions for EnvVars {
166167

167168
let allow_no_package_manager = self.truthy_value("allow_no_package_manager").flatten();
168169

170+
let no_update_notifier = self.truthy_value("no_update_notifier").flatten();
171+
169172
// Process daemon
170173
let daemon = self.truthy_value("daemon").flatten();
171174

@@ -231,6 +234,7 @@ impl ResolvedConfigurationOptions for EnvVars {
231234
remote_cache_read_only,
232235
run_summary,
233236
allow_no_turbo_json,
237+
no_update_notifier,
234238

235239
// Processed numbers
236240
timeout,

crates/turborepo-lib/src/config/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ pub struct ConfigurationOptions {
298298
pub(crate) allow_no_turbo_json: Option<bool>,
299299
pub(crate) tui_scrollback_length: Option<u64>,
300300
pub(crate) concurrency: Option<String>,
301+
pub(crate) no_update_notifier: Option<bool>,
301302
}
302303

303304
#[derive(Default)]
@@ -463,6 +464,10 @@ impl ConfigurationOptions {
463464
pub fn allow_no_turbo_json(&self) -> bool {
464465
self.allow_no_turbo_json.unwrap_or_default()
465466
}
467+
468+
pub fn no_update_notifier(&self) -> bool {
469+
self.no_update_notifier.unwrap_or_default()
470+
}
466471
}
467472

468473
// Maps Some("") to None to emulate how Go handles empty strings

crates/turborepo-lib/src/shim/mod.rs

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,16 @@ pub enum Error {
3939
#[label = "Requires a path to be passed after it"]
4040
flag_range: SourceSpan,
4141
},
42+
#[error("No value assigned to `--root-turbo-json` flag.")]
43+
#[diagnostic(code(turbo::shim::empty_root_turbo_json))]
44+
EmptyRootTurboJson {
45+
#[backtrace]
46+
backtrace: Backtrace,
47+
#[source_code]
48+
args_string: String,
49+
#[label = "Requires a path to be passed after it"]
50+
flag_range: SourceSpan,
51+
},
4252
#[error(transparent)]
4353
#[diagnostic(transparent)]
4454
Cli(#[from] cli::Error),
@@ -75,7 +85,12 @@ fn run_correct_turbo(
7585
ui: ColorConfig,
7686
) -> Result<i32, Error> {
7787
if let Some(turbo_state) = LocalTurboState::infer(&repo_state.root) {
78-
try_check_for_updates(&shim_args, turbo_state.version());
88+
let mut builder = crate::config::TurborepoConfigBuilder::new(&repo_state.root);
89+
if let Some(root_turbo_json) = &shim_args.root_turbo_json {
90+
builder = builder.with_root_turbo_json_path(Some(root_turbo_json.clone()));
91+
}
92+
let config = builder.build().unwrap_or_default();
93+
try_check_for_updates(&shim_args, turbo_state.version(), &config);
7994

8095
if turbo_state.local_is_self() {
8196
env::set_var(
@@ -95,7 +110,12 @@ fn run_correct_turbo(
95110
spawn_npx_turbo(&repo_state, local_config.turbo_version(), shim_args)
96111
} else {
97112
let version = get_version();
98-
try_check_for_updates(&shim_args, version);
113+
let mut builder = crate::config::TurborepoConfigBuilder::new(&repo_state.root);
114+
if let Some(root_turbo_json) = &shim_args.root_turbo_json {
115+
builder = builder.with_root_turbo_json_path(Some(root_turbo_json.clone()));
116+
}
117+
let config = builder.build().unwrap_or_default();
118+
try_check_for_updates(&shim_args, version, &config);
99119
// cli::run checks for this env var, rather than an arg, so that we can support
100120
// calling old versions without passing unknown flags.
101121
env::set_var(
@@ -251,8 +271,12 @@ fn is_turbo_binary_path_set() -> bool {
251271
env::var("TURBO_BINARY_PATH").is_ok()
252272
}
253273

254-
fn try_check_for_updates(args: &ShimArgs, current_version: &str) {
255-
if args.should_check_for_update() {
274+
fn try_check_for_updates(
275+
args: &ShimArgs,
276+
current_version: &str,
277+
config: &crate::config::ConfigurationOptions,
278+
) {
279+
if args.should_check_for_update() && !config.no_update_notifier() {
256280
// custom footer for update message
257281
let footer = format!(
258282
"Follow {username} for updates: {url}",

crates/turborepo-lib/src/shim/parser.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ pub struct ShimArgs {
5252
pub forwarded_args: Vec<String>,
5353
pub color: bool,
5454
pub no_color: bool,
55+
pub root_turbo_json: Option<AbsoluteSystemPathBuf>,
5556
}
5657

5758
impl ShimArgs {
@@ -75,6 +76,8 @@ impl ShimArgs {
7576
let mut is_forwarded_args = false;
7677
let mut color = false;
7778
let mut no_color = false;
79+
let mut root_turbo_json_flag_idx = None;
80+
let mut root_turbo_json = None;
7881

7982
let args = args.skip(1);
8083
for (idx, arg) in args.enumerate() {
@@ -127,6 +130,18 @@ impl ShimArgs {
127130
color = true;
128131
} else if arg == "--no-color" {
129132
no_color = true;
133+
} else if root_turbo_json_flag_idx.is_some() {
134+
// We've seen a `--root-turbo-json` and therefore add this as the path
135+
root_turbo_json = Some(AbsoluteSystemPathBuf::from_unknown(&invocation_dir, arg));
136+
root_turbo_json_flag_idx = None;
137+
} else if arg == "--root-turbo-json" {
138+
// If we see a `--root-turbo-json` we expect the next arg to be a path.
139+
root_turbo_json_flag_idx = Some(idx);
140+
} else if let Some(path) = arg.strip_prefix("--root-turbo-json=") {
141+
// In the case where `--root-turbo-json` is passed as
142+
// `--root-turbo-json=./path/to/turbo.json`, that entire chunk
143+
// is a single arg, so we need to split it up.
144+
root_turbo_json = Some(AbsoluteSystemPathBuf::from_unknown(&invocation_dir, path));
130145
} else {
131146
remaining_turbo_args.push(arg);
132147
}
@@ -143,6 +158,17 @@ impl ShimArgs {
143158
});
144159
}
145160

161+
if let Some(idx) = root_turbo_json_flag_idx {
162+
let (spans, args_string) =
163+
Self::get_spans_in_args_string(vec![idx], env::args().skip(1));
164+
165+
return Err(Error::EmptyRootTurboJson {
166+
backtrace: Backtrace::capture(),
167+
args_string,
168+
flag_range: spans[0],
169+
});
170+
}
171+
146172
if cwds.len() > 1 {
147173
let (indices, args_string) = Self::get_spans_in_args_string(
148174
cwds.iter().map(|(_, idx)| *idx).collect(),
@@ -175,6 +201,7 @@ impl ShimArgs {
175201
forwarded_args,
176202
color,
177203
no_color,
204+
root_turbo_json,
178205
})
179206
}
180207

@@ -301,6 +328,7 @@ mod test {
301328
pub color: bool,
302329
pub no_color: bool,
303330
pub relative_cwd: Option<&'static [&'static str]>,
331+
pub relative_root_turbo_json: Option<&'static str>,
304332
}
305333

306334
impl ExpectedArgs {
@@ -314,6 +342,7 @@ mod test {
314342
color,
315343
no_color,
316344
relative_cwd,
345+
relative_root_turbo_json,
317346
} = self;
318347
ShimArgs {
319348
cwd: relative_cwd.map_or_else(
@@ -331,6 +360,8 @@ mod test {
331360
force_update_check,
332361
color,
333362
no_color,
363+
root_turbo_json: relative_root_turbo_json
364+
.map(|path| AbsoluteSystemPathBuf::from_unknown(&invocation_dir, path)),
334365
}
335366
}
336367
}
@@ -461,6 +492,30 @@ mod test {
461492
}
462493
; "cwd equals"
463494
)]
495+
#[test_case(
496+
&["turbo", "--root-turbo-json", "path/to/turbo.json"],
497+
ExpectedArgs {
498+
relative_root_turbo_json: Some("path/to/turbo.json"),
499+
..Default::default()
500+
}
501+
; "root turbo json value"
502+
)]
503+
#[test_case(
504+
&["turbo", "--root-turbo-json=path/to/turbo.json"],
505+
ExpectedArgs {
506+
relative_root_turbo_json: Some("path/to/turbo.json"),
507+
..Default::default()
508+
}
509+
; "root turbo json equals"
510+
)]
511+
#[test_case(
512+
&["turbo", "--root-turbo-json", "/absolute/path/to/turbo.json"],
513+
ExpectedArgs {
514+
relative_root_turbo_json: Some("/absolute/path/to/turbo.json"),
515+
..Default::default()
516+
}
517+
; "root turbo json absolute path"
518+
)]
464519
fn test_shim_parsing(args: &[&str], expected: ExpectedArgs) {
465520
let cwd = AbsoluteSystemPathBuf::new(if cfg!(windows) {
466521
"Z:\\some\\dir"

crates/turborepo-lib/src/turbo_json/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,9 @@ pub struct RawTurboJson {
152152
#[serde(skip_serializing_if = "Option::is_none")]
153153
pub cache_dir: Option<Spanned<UnescapedString>>,
154154

155+
#[serde(skip_serializing_if = "Option::is_none")]
156+
pub no_update_notifier: Option<bool>,
157+
155158
#[serde(skip_serializing_if = "Option::is_none")]
156159
pub tags: Option<Spanned<Vec<Spanned<String>>>>,
157160

crates/turborepo-updater/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const DEFAULT_TIMEOUT: Duration = Duration::from_millis(800);
2121
// 1 day
2222
const DEFAULT_INTERVAL: Duration = Duration::from_secs(60 * 60 * 24);
2323

24-
const NOTIFIER_DISABLE_VARS: [&str; 2] = ["NO_UPDATE_NOTIFIER", "TURBO_NO_UPDATE_NOTIFIER"];
24+
const NOTIFIER_DISABLE_VARS: [&str; 1] = ["NO_UPDATE_NOTIFIER"];
2525
const ENVIRONMENTAL_DISABLE_VARS: [&str; 1] = ["CI"];
2626

2727
#[derive(ThisError, Debug)]

docs/site/content/docs/reference/configuration.mdx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,18 @@ Select a terminal UI for the repository.
9191
}
9292
```
9393

94+
### `noUpdateNotifier`
95+
96+
Default: `false`
97+
98+
When set to `true`, disables the update notification that appears when a new version of `turbo` is available.
99+
100+
```json title="./turbo.json"
101+
{
102+
"noUpdateNotifier": true
103+
}
104+
```
105+
94106
### `concurrency`
95107

96108
Default: `"10"`

packages/turbo-types/schemas/schema.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,11 @@
9797
"boundaries": {
9898
"$ref": "#/definitions/RootBoundariesConfig",
9999
"description": "Configuration for `turbo boundaries`. Allows users to restrict a package's dependencies and dependents"
100+
},
101+
"noUpdateNotifier": {
102+
"type": "boolean",
103+
"description": "When set to `true`, disables the update notification that appears when a new version of `turbo` is available.\n\nDocumentation: https://turborepo.com/docs/reference/configuration#noupdatenotifier",
104+
"default": false
100105
}
101106
},
102107
"additionalProperties": false,

packages/turbo-types/schemas/schema.v2.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,11 @@
9797
"boundaries": {
9898
"$ref": "#/definitions/RootBoundariesConfig",
9999
"description": "Configuration for `turbo boundaries`. Allows users to restrict a package's dependencies and dependents"
100+
},
101+
"noUpdateNotifier": {
102+
"type": "boolean",
103+
"description": "When set to `true`, disables the update notification that appears when a new version of `turbo` is available.\n\nDocumentation: https://turborepo.com/docs/reference/configuration#noupdatenotifier",
104+
"default": false
100105
}
101106
},
102107
"additionalProperties": false,

packages/turbo-types/src/types/config-v2.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,15 @@ export interface RootSchema extends BaseSchema {
181181
* Configuration for `turbo boundaries`. Allows users to restrict a package's dependencies and dependents
182182
*/
183183
boundaries?: RootBoundariesConfig;
184+
185+
/**
186+
* When set to `true`, disables the update notification that appears when a new version of `turbo` is available.
187+
*
188+
* Documentation: https://turborepo.com/docs/reference/configuration#noupdatenotifier
189+
*
190+
* @defaultValue `false`
191+
*/
192+
noUpdateNotifier?: boolean;
184193
}
185194

186195
export interface Pipeline {

0 commit comments

Comments
 (0)