Merge branch 'master' into conditional-style

This commit is contained in:
Filip Bachul 2023-05-09 18:26:36 +02:00
commit bc9c7316c9
11 changed files with 178 additions and 38 deletions

View File

@ -529,6 +529,7 @@
}, },
"gcloud": { "gcloud": {
"default": { "default": {
"detect_env_vars": [],
"disabled": false, "disabled": false,
"format": "on [$symbol$account(@$domain)(\\($region\\))]($style) ", "format": "on [$symbol$account(@$domain)(\\($region\\))]($style) ",
"project_aliases": {}, "project_aliases": {},
@ -3179,6 +3180,13 @@
"additionalProperties": { "additionalProperties": {
"type": "string" "type": "string"
} }
},
"detect_env_vars": {
"default": [],
"type": "array",
"items": {
"type": "string"
}
} }
}, },
"additionalProperties": false "additionalProperties": false

View File

@ -10,7 +10,7 @@ If you have any questions that aren't addressed in this document, please don't h
- **Module**: A component in the prompt giving information based on contextual information from your OS. For example, the `rust` module shows the version of Rust that is currently installed on your computer, if your current directory is a Rust project. - **Module**: A component in the prompt giving information based on contextual information from your OS. For example, the `rust` module shows the version of Rust that is currently installed on your computer, if your current directory is a Rust project.
- **Segment**: Smaller sub-components that compose a module. For example, the `symbol` segment in the `rust` module contains the character that is shown before the version number (`🦀` by default). - **Segment**: Smaller subcomponents that compose a module. For example, the `symbol` segment in the `rust` module contains the character that is shown before the version number (`🦀` by default).
## Philosophy ## Philosophy
@ -50,7 +50,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
## External commands ## External commands
To run a external command (e.g. to get the version of a tool) and to allow for mocking use the `context.exec_cmd` function. Here's a quick example: To run an external command (e.g. to get the version of a tool) and to allow for mocking use the `context.exec_cmd` function. Here's a quick example:
```rust ```rust
use super::{Context, Module, ModuleConfig}; use super::{Context, Module, ModuleConfig};
@ -127,7 +127,7 @@ STARSHIP_LOG=trace cargo run
## Linting ## Linting
Starship source files are linted with [clippy](https://crates.io/crates/clippy). Clippy will be ran as part of CI. Linting errors will fail a build, so it is suggested that you run Clippy locally: Starship source files are linted with [clippy](https://crates.io/crates/clippy). Clippy will be run as part of CI. Linting errors will fail a build, so it is suggested that you run Clippy locally:
```sh ```sh
rustup component add clippy rustup component add clippy
@ -218,7 +218,7 @@ mod tests {
} }
``` ```
If a module depends on output of another program, then that output should be added to the match statement in [`utils.rs`](src/utils.rs). The match has to be exactly the same as the call to `utils::exec_cmd()`, including positional arguments and flags. The array of arguments are joined by a `" "`, so `utils::exec_cmd("program", &["arg", "more_args"])` would match with the `program arg more_args` match statement. If a module depends on output of another program, then that output should be added to the match statement in [`utils.rs`](src/utils.rs). The match has to be exactly the same as the call to `utils::exec_cmd()`, including positional arguments and flags. The array of arguments is joined by a `" "`, so `utils::exec_cmd("program", &["arg", "more_args"])` would match with the `program arg more_args` match statement.
If the program cannot be mocked (e.g. It performs some filesystem operations, either writing or reading files) then it has to added to the project's GitHub Actions workflow file([`.github/workflows/workflow.yml`](.github/workflows/workflow.yml)) and the test has to be marked with an `#[ignored]`. This ensures that anyone can run the test suite locally without needing to pre-configure their environment. The `#[ignored]` attribute is bypassed during CI runs in GitHub Actions. If the program cannot be mocked (e.g. It performs some filesystem operations, either writing or reading files) then it has to added to the project's GitHub Actions workflow file([`.github/workflows/workflow.yml`](.github/workflows/workflow.yml)) and the test has to be marked with an `#[ignored]`. This ensures that anyone can run the test suite locally without needing to pre-configure their environment. The `#[ignored]` attribute is bypassed during CI runs in GitHub Actions.

88
Cargo.lock generated
View File

@ -8,17 +8,6 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "ahash"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
dependencies = [
"getrandom",
"once_cell",
"version_check",
]
[[package]] [[package]]
name = "ahash" name = "ahash"
version = "0.8.3" version = "0.8.3"
@ -448,6 +437,28 @@ dependencies = [
"crossbeam-utils", "crossbeam-utils",
] ]
[[package]]
name = "const-random"
version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "368a7a772ead6ce7e1de82bfb04c485f3db8ec744f72925af5735e29a22cc18e"
dependencies = [
"const-random-macro",
"proc-macro-hack",
]
[[package]]
name = "const-random-macro"
version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d7d6ab3c3a2282db210df5f02c4dab6e0a7057af0fb7ebd4070f30fe05c0ddb"
dependencies = [
"getrandom",
"once_cell",
"proc-macro-hack",
"tiny-keccak",
]
[[package]] [[package]]
name = "const_format" name = "const_format"
version = "0.2.30" version = "0.2.30"
@ -569,6 +580,12 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "crunchy"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]] [[package]]
name = "crypto-common" name = "crypto-common"
version = "0.1.6" version = "0.1.6"
@ -716,9 +733,12 @@ dependencies = [
[[package]] [[package]]
name = "dlv-list" name = "dlv-list"
version = "0.3.0" version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257" checksum = "d529fd73d344663edfd598ccb3f344e46034db51ebd103518eae34338248ad73"
dependencies = [
"const-random",
]
[[package]] [[package]]
name = "downcast" name = "downcast"
@ -1528,9 +1548,6 @@ name = "hashbrown"
version = "0.12.3" version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
dependencies = [
"ahash 0.7.6",
]
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
@ -1623,7 +1640,7 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e98c1d0ad70fc91b8b9654b1f33db55e59579d3b3de2bffdced0fdb810570cb8" checksum = "e98c1d0ad70fc91b8b9654b1f33db55e59579d3b3de2bffdced0fdb810570cb8"
dependencies = [ dependencies = [
"ahash 0.8.3", "ahash",
"hashbrown 0.12.3", "hashbrown 0.12.3",
] ]
@ -2112,12 +2129,12 @@ dependencies = [
[[package]] [[package]]
name = "ordered-multimap" name = "ordered-multimap"
version = "0.4.3" version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a" checksum = "4ed8acf08e98e744e5384c8bc63ceb0364e68a6854187221c18df61c4797690e"
dependencies = [ dependencies = [
"dlv-list", "dlv-list",
"hashbrown 0.12.3", "hashbrown 0.13.2",
] ]
[[package]] [[package]]
@ -2360,6 +2377,12 @@ dependencies = [
"toml_edit", "toml_edit",
] ]
[[package]]
name = "proc-macro-hack"
version = "0.5.20+deprecated"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.56" version = "1.0.56"
@ -2520,9 +2543,9 @@ checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c"
[[package]] [[package]]
name = "rust-ini" name = "rust-ini"
version = "0.18.0" version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6d5f2436026b4f6e79dc829837d467cc7e9a55ee40e750d716713540715a2df" checksum = "7e2a3bcec1f113553ef1c88aae6c020a369d03d55b58de9869a0908930385091"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"ordered-multimap", "ordered-multimap",
@ -2620,18 +2643,18 @@ dependencies = [
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.160" version = "1.0.162"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" checksum = "71b2f6e1ab5c2b98c05f0f35b236b22e8df7ead6ffbf51d7808da7f8817e7ab6"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.160" version = "1.0.162"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" checksum = "a2a0814352fd64b58489904a44ea8d90cb1a91dcb6b4f5ebabc32c8318e93cb6"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -3113,6 +3136,15 @@ dependencies = [
"time-core", "time-core",
] ]
[[package]]
name = "tiny-keccak"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
dependencies = [
"crunchy",
]
[[package]] [[package]]
name = "tinyvec" name = "tinyvec"
version = "1.6.0" version = "1.6.0"
@ -3336,9 +3368,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]] [[package]]
name = "versions" name = "versions"
version = "4.1.0" version = "5.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee97e1d97bd593fb513912a07691b742361b3dd64ad56f2c694ea2dbfe0665d3" checksum = "32feb3eb91e495efe5b6b2e3ca9d78db603043434a3a398a84b47de28abb2d02"
dependencies = [ dependencies = [
"itertools", "itertools",
"nom 7.1.3", "nom 7.1.3",

View File

@ -68,9 +68,9 @@ quick-xml = "0.28.2"
rand = "0.8.5" rand = "0.8.5"
rayon = "1.7.0" rayon = "1.7.0"
regex = "1.8.1" regex = "1.8.1"
rust-ini = "0.18.0" rust-ini = "0.19.0"
semver = "1.0.17" semver = "1.0.17"
serde = { version = "1.0.160", features = ["derive"] } serde = { version = "1.0.162", features = ["derive"] }
serde_json = "1.0.96" serde_json = "1.0.96"
sha1 = "0.10.5" sha1 = "0.10.5"
shadow-rs = { version = "0.21.0", default-features = false } shadow-rs = { version = "0.21.0", default-features = false }
@ -85,7 +85,7 @@ toml_edit = "0.19.8"
unicode-segmentation = "1.10.1" unicode-segmentation = "1.10.1"
unicode-width = "0.1.10" unicode-width = "0.1.10"
urlencoding = "2.1.2" urlencoding = "2.1.2"
versions = "4.1.0" versions = "5.0.0"
which = "4.4.0" which = "4.4.0"
yaml-rust = "0.4.5" yaml-rust = "0.4.5"

View File

@ -271,7 +271,7 @@ Install Starship using any of the following package managers:
</details> </details>
### Step 2. Setup your shell to use Starship ### Step 2. Set up your shell to use Starship
Configure your shell to initialize starship. Select yours from the list below: Configure your shell to initialize starship. Select yours from the list below:

View File

@ -21,6 +21,7 @@ allow = [
"Apache-2.0", "Apache-2.0",
"BSD-2-Clause", "BSD-2-Clause",
"BSD-3-Clause", "BSD-3-Clause",
"CC0-1.0",
"ISC", "ISC",
"MIT-0", "MIT-0",
"MIT", "MIT",

View File

@ -356,7 +356,7 @@ format = '$all$directory$character'
The `aws` module shows the current AWS region and profile and an expiration timer when using temporary credentials. The `aws` module shows the current AWS region and profile and an expiration timer when using temporary credentials.
The output of the module uses the `AWS_REGION`, `AWS_DEFAULT_REGION`, and `AWS_PROFILE` env vars and the `~/.aws/config` and `~/.aws/credentials` files as required. The output of the module uses the `AWS_REGION`, `AWS_DEFAULT_REGION`, and `AWS_PROFILE` env vars and the `~/.aws/config` and `~/.aws/credentials` files as required.
The module will display a profile only if its credentials are present in `~/.aws/credentials` or if a `credential_process` or `sso_start_url` are defined in `~/.aws/config`. Alternatively, having any of the `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, or `AWS_SESSION_TOKEN` env vars defined will also suffice. The module will display a profile only if its credentials are present in `~/.aws/credentials` or if a `credential_process`, `sso_start_url`, or `sso_session` are defined in `~/.aws/config`. Alternatively, having any of the `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, or `AWS_SESSION_TOKEN` env vars defined will also suffice.
If the option `force_display` is set to `true`, all available information will be displayed even if no credentials per the conditions above are detected. If the option `force_display` is set to `true`, all available information will be displayed even if no credentials per the conditions above are detected.
When using [aws-vault](https://github.com/99designs/aws-vault) the profile When using [aws-vault](https://github.com/99designs/aws-vault) the profile
@ -1609,6 +1609,10 @@ truncation_symbol = ''
The `gcloud` module shows the current configuration for [`gcloud`](https://cloud.google.com/sdk/gcloud) CLI. The `gcloud` module shows the current configuration for [`gcloud`](https://cloud.google.com/sdk/gcloud) CLI.
This is based on the `~/.config/gcloud/active_config` file and the `~/.config/gcloud/configurations/config_{CONFIG NAME}` file and the `CLOUDSDK_CONFIG` env var. This is based on the `~/.config/gcloud/active_config` file and the `~/.config/gcloud/configurations/config_{CONFIG NAME}` file and the `CLOUDSDK_CONFIG` env var.
When the module is enabled it will always be active, unless `detect_env_vars` has
been set in which case the module will only be active be active when one of the
environment variables has been set.
### Options ### Options
| Option | Default | Description | | Option | Default | Description |
@ -1617,6 +1621,7 @@ This is based on the `~/.config/gcloud/active_config` file and the `~/.config/gc
| `symbol` | `'☁️ '` | The symbol used before displaying the current GCP profile. | | `symbol` | `'☁️ '` | The symbol used before displaying the current GCP profile. |
| `region_aliases` | `{}` | Table of region aliases to display in addition to the GCP name. | | `region_aliases` | `{}` | Table of region aliases to display in addition to the GCP name. |
| `project_aliases` | `{}` | Table of project aliases to display in addition to the GCP name. | | `project_aliases` | `{}` | Table of project aliases to display in addition to the GCP name. |
| `detect_env_vars` | `[]` | Which environmental variables should trigger this module |
| `style` | `'bold blue'` | The style for the module. | | `style` | `'bold blue'` | The style for the module. |
| `disabled` | `false` | Disables the `gcloud` module. | | `disabled` | `false` | Disables the `gcloud` module. |

View File

@ -15,6 +15,7 @@ pub struct GcloudConfig<'a> {
pub disabled: bool, pub disabled: bool,
pub region_aliases: HashMap<String, &'a str>, pub region_aliases: HashMap<String, &'a str>,
pub project_aliases: HashMap<String, &'a str>, pub project_aliases: HashMap<String, &'a str>,
pub detect_env_vars: Vec<&'a str>,
} }
impl<'a> Default for GcloudConfig<'a> { impl<'a> Default for GcloudConfig<'a> {
@ -26,6 +27,7 @@ impl<'a> Default for GcloudConfig<'a> {
disabled: false, disabled: false,
region_aliases: HashMap::new(), region_aliases: HashMap::new(),
project_aliases: HashMap::new(), project_aliases: HashMap::new(),
detect_env_vars: vec![],
} }
} }
} }

View File

@ -235,6 +235,10 @@ impl<'a> Context<'a> {
disabled == Some(true) disabled == Some(true)
} }
pub fn detect_env_vars(&'a self, env_vars: &'a [&'a str]) -> bool {
env_vars.is_empty() || (env_vars.iter().any(|e| self.get_env(e).is_some()))
}
// returns a new ScanDir struct with reference to current dir_files of context // returns a new ScanDir struct with reference to current dir_files of context
// see ScanDir for methods // see ScanDir for methods
pub fn try_begin_scan(&'a self) -> Option<ScanDir<'a>> { pub fn try_begin_scan(&'a self) -> Option<ScanDir<'a>> {

View File

@ -174,6 +174,7 @@ fn has_credential_process_or_sso(
Some( Some(
config_section.contains_key("credential_process") config_section.contains_key("credential_process")
|| config_section.contains_key("sso_session")
|| config_section.contains_key("sso_start_url") || config_section.contains_key("sso_start_url")
|| credential_section?.contains_key("credential_process") || credential_section?.contains_key("credential_process")
|| credential_section?.contains_key("sso_start_url"), || credential_section?.contains_key("sso_start_url"),
@ -996,7 +997,7 @@ credential_process = /opt/bin/awscreds-for-tests
} }
#[test] #[test]
fn sso_set() -> io::Result<()> { fn sso_legacy_set() -> io::Result<()> {
let dir = tempfile::tempdir()?; let dir = tempfile::tempdir()?;
let config_path = dir.path().join("config"); let config_path = dir.path().join("config");
let mut file = File::create(&config_path)?; let mut file = File::create(&config_path)?;
@ -1026,6 +1027,40 @@ sso_role_name = <AWS-ROLE-NAME>
dir.close() dir.close()
} }
#[test]
fn sso_set() -> io::Result<()> {
let dir = tempfile::tempdir()?;
let config_path = dir.path().join("config");
let mut config = File::create(&config_path)?;
config.write_all(
"[profile astronauts]
sso_session = my-sso
sso_account_id = 123456789011
sso_role_name = readOnly
region = us-west-2
output = json
[sso-session my-sso]
sso_region = us-east-1
sso_start_url = https://starship.rs/sso
sso_registration_scopes = sso:account:access
"
.as_bytes(),
)?;
let actual = ModuleRenderer::new("aws")
.env("AWS_CONFIG_FILE", config_path.to_string_lossy().as_ref())
.env("AWS_PROFILE", "astronauts")
.collect();
let expected = Some(format!(
"on {}",
Color::Yellow.bold().paint("☁️ astronauts (us-west-2) ")
));
assert_eq!(expected, actual);
dir.close()
}
#[test] #[test]
fn access_key_env_var_set() { fn access_key_env_var_set() {
let actual = ModuleRenderer::new("aws") let actual = ModuleRenderer::new("aws")

View File

@ -84,6 +84,10 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
let mut module = context.new_module("gcloud"); let mut module = context.new_module("gcloud");
let config: GcloudConfig = GcloudConfig::try_load(module.config); let config: GcloudConfig = GcloudConfig::try_load(module.config);
if !(context.detect_env_vars(&config.detect_env_vars)) {
return None;
}
let (config_name, config_path) = get_current_config(context)?; let (config_name, config_path) = get_current_config(context)?;
let gcloud_context = GcloudContext::new(&config_name, &config_path); let gcloud_context = GcloudContext::new(&config_name, &config_path);
let account: Lazy<Option<Account<'_>>, _> = Lazy::new(|| gcloud_context.get_account()); let account: Lazy<Option<Account<'_>>, _> = Lazy::new(|| gcloud_context.get_account());
@ -150,6 +154,55 @@ mod tests {
use crate::test::ModuleRenderer; use crate::test::ModuleRenderer;
#[test]
fn account_set_but_not_shown_because_of_detect_env_vars() -> io::Result<()> {
let dir = tempfile::tempdir()?;
let active_config_path = dir.path().join("active_config");
let mut active_config_file = File::create(active_config_path)?;
active_config_file.write_all(b"default")?;
// check if this config would lead to the module being rendered
assert_eq!(
ModuleRenderer::new("gcloud")
.env("CLOUDSDK_CONFIG", dir.path().to_string_lossy())
.config(toml::toml! {
[gcloud]
format = "$active"
})
.collect(),
Some("default".into())
);
// when we set `detect_env_vars` now, the module is empty
assert_eq!(
ModuleRenderer::new("gcloud")
.env("CLOUDSDK_CONFIG", dir.path().to_string_lossy())
.config(toml::toml! {
[gcloud]
format = "$active"
detect_env_vars = ["SOME_TEST_VAR"]
})
.collect(),
None
);
// and when the environment variable has a value, the module is shown
assert_eq!(
ModuleRenderer::new("gcloud")
.env("CLOUDSDK_CONFIG", dir.path().to_string_lossy())
.env("SOME_TEST_VAR", "1")
.config(toml::toml! {
[gcloud]
format = "$active"
detect_env_vars = ["SOME_TEST_VAR"]
})
.collect(),
Some("default".into())
);
dir.close()
}
#[test] #[test]
fn account_set() -> io::Result<()> { fn account_set() -> io::Result<()> {
let dir = tempfile::tempdir()?; let dir = tempfile::tempdir()?;