Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 20 additions & 9 deletions cli-engine/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1864,11 +1864,15 @@ impl Cli {
apply_pagination_flags(&mut middleware, &command.spec, leaf);
let args = command_args_from_matches(leaf, &command.spec, false);
let user_args = command_args_from_matches(leaf, &command.spec, true);
let pagination_command = command
.spec
.pagination
.is_some()
.then(|| pagination_command_base(&command_path, &command.spec, &user_args, &flags));
let pagination_command = command.spec.pagination.is_some().then(|| {
pagination_command_base(
&self.config.name,
&command_path,
&command.spec,
&user_args,
&flags,
)
});
if let Err(err) = self.run_pre_run(&mut middleware, &command_path, &args) {
return self.finish_run(render_cli_error(&middleware, &err, &self.config.app_id));
}
Expand Down Expand Up @@ -2571,9 +2575,12 @@ fn apply_pagination_flags(middleware: &mut Middleware, spec: &CommandSpec, leaf:
}

/// Replays a paginating command's own explicit args, plus the global
/// `--filter`/`--expr`/`--fields` flags, as `--flag value` text — the base a
/// "view the next page" [`crate::NextAction`] is built from once the
/// response's [`crate::PaginationMeta`] is known.
/// `--filter`/`--expr`/`--fields` flags, as `--flag value` text, prefixed
/// with the CLI's binary name — the base a "view the next page"
/// [`crate::NextAction`] is built from once the response's
/// [`crate::PaginationMeta`] is known. Leading with the binary name keeps the
/// suggested command copy-pastable rather than a fragment starting at the
/// noun/verb path.
///
/// `--filter`/`--expr`/`--fields` sit in the same output pipeline as
/// pagination itself (filter -> paginate -> expr -> fields) and change what
Expand All @@ -2594,12 +2601,16 @@ fn apply_pagination_flags(middleware: &mut Middleware, spec: &CommandSpec, leaf:
/// those are added by the caller once it knows the
/// next page's offset.
fn pagination_command_base(
binary_name: &str,
command_path: &str,
spec: &CommandSpec,
user_args: &crate::middleware::ValueMap,
flags: &GlobalFlags,
) -> String {
let mut parts = vec![command_path.replace(':', " ")];
let mut parts = vec![
quote_pagination_value(binary_name),
command_path.replace(':', " "),
];
for arg in &spec.args {
Comment thread
jpage-godaddy marked this conversation as resolved.
let id = arg.get_id().as_str();
if let Some(value) = user_args.get(id) {
Expand Down
42 changes: 32 additions & 10 deletions cli-engine/tests/pagination.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ async fn default_limit_applies_when_neither_flag_is_passed() {
);
assert_eq!(
rendered["next_actions"][0]["command"],
"list --limit 2 --offset 2"
"my-cli list --limit 2 --offset 2"
);
assert!(rendered.get("metadata").is_none(), "{}", output.rendered);
}
Expand Down Expand Up @@ -131,7 +131,7 @@ async fn explicit_limit_and_offset_override_the_default_and_expose_pagination()
);
assert_eq!(
rendered["next_actions"][0]["command"],
"list --limit 2 --offset 3"
"my-cli list --limit 2 --offset 3"
);
assert_eq!(
rendered["next_actions"][0]["description"],
Expand Down Expand Up @@ -184,7 +184,7 @@ async fn next_page_action_replays_other_flags_the_user_passed() {
let rendered: serde_json::Value = serde_json::from_str(&output.rendered).expect("valid json");
assert_eq!(
rendered["next_actions"][0]["command"],
"list --status active --limit 2 --offset 2"
"my-cli list --status active --limit 2 --offset 2"
);
}

Expand Down Expand Up @@ -214,7 +214,29 @@ async fn next_page_action_quotes_values_with_whitespace() {
let rendered: serde_json::Value = serde_json::from_str(&output.rendered).expect("valid json");
assert_eq!(
rendered["next_actions"][0]["command"],
"list --status \"in review\" --limit 2 --offset 2"
"my-cli list --status \"in review\" --limit 2 --offset 2"
);
}

#[tokio::test]
async fn next_page_action_quotes_a_binary_name_with_whitespace() {
let mut cli = Cli::new(CliConfig::new("my cli", "Dev tooling", "my-cli"));
cli.add_command(RuntimeCommandSpec::new(
CommandSpec::new("list", "List things")
.no_auth(true)
.with_pagination(PaginationConfig {
default_limit: 2,
..PaginationConfig::default()
}),
async |_credential, _args| Ok(CommandResult::new(json!(items()))),
));

let output = cli.run(["my cli", "list", "--output", "json"]).await;
assert_eq!(output.exit_code, 0, "{}", output.rendered);
let rendered: serde_json::Value = serde_json::from_str(&output.rendered).expect("valid json");
assert_eq!(
rendered["next_actions"][0]["command"],
"\"my cli\" list --limit 2 --offset 2"
);
}

Expand Down Expand Up @@ -250,7 +272,7 @@ async fn next_page_action_uses_the_real_long_flag_not_the_value_map_key() {
let rendered: serde_json::Value = serde_json::from_str(&output.rendered).expect("valid json");
assert_eq!(
rendered["next_actions"][0]["command"],
"list --sort-order asc --limit 2 --offset 2"
"my-cli list --sort-order asc --limit 2 --offset 2"
);
}

Expand Down Expand Up @@ -365,7 +387,7 @@ async fn human_output_shows_pagination_summary_and_next_steps() {
output.rendered
);
assert!(
output.rendered.contains("list --limit 2 --offset 2"),
output.rendered.contains("my-cli list --limit 2 --offset 2"),
"{}",
output.rendered
);
Expand Down Expand Up @@ -433,7 +455,7 @@ async fn next_page_action_preserves_filter_expr_and_fields() {
let rendered: serde_json::Value = serde_json::from_str(&output.rendered).expect("valid json");
assert_eq!(
rendered["next_actions"][0]["command"],
"list --filter \"name != 'alpha'\" --expr \"sort_by(@, &name)\" --fields name --limit 2 --offset 2"
"my-cli list --filter \"name != 'alpha'\" --expr \"sort_by(@, &name)\" --fields name --limit 2 --offset 2"
);
}

Expand Down Expand Up @@ -463,7 +485,7 @@ async fn next_page_action_replays_a_set_false_flag_as_a_bare_switch() {
let rendered: serde_json::Value = serde_json::from_str(&output.rendered).expect("valid json");
assert_eq!(
rendered["next_actions"][0]["command"],
"list --no-cache --limit 2 --offset 2"
"my-cli list --no-cache --limit 2 --offset 2"
);
}

Expand Down Expand Up @@ -531,7 +553,7 @@ async fn next_page_action_replays_a_multi_value_arg_as_repeated_flags() {
let rendered: serde_json::Value = serde_json::from_str(&output.rendered).expect("valid json");
assert_eq!(
rendered["next_actions"][0]["command"],
"list --scope a --scope b --limit 2 --offset 2"
"my-cli list --scope a --scope b --limit 2 --offset 2"
);
}

Expand Down Expand Up @@ -607,7 +629,7 @@ async fn next_page_action_escapes_shell_metacharacters_and_expansions() {
let rendered: serde_json::Value = serde_json::from_str(&output.rendered).expect("valid json");
assert_eq!(
rendered["next_actions"][0]["command"],
r#"list --status "a;\$(whoami)\`x\`\"y\"\\z" --limit 2 --offset 2"#
r#"my-cli list --status "a;\$(whoami)\`x\`\"y\"\\z" --limit 2 --offset 2"#
);
}

Expand Down