summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/config/README.md17
-rw-r--r--src/configs/pulumi.rs2
-rw-r--r--src/modules/mod.rs2
-rw-r--r--src/modules/pulumi.rs122
4 files changed, 130 insertions, 13 deletions
diff --git a/docs/config/README.md b/docs/config/README.md
index e65a28df0..168c76c07 100644
--- a/docs/config/README.md
+++ b/docs/config/README.md
@@ -2424,7 +2424,7 @@ format = "via [🔹 $version](147 bold) "
## Pulumi
-The `pulumi` module shows the currently selected [Pulumi Stack](https://www.pulumi.com/docs/intro/concepts/stack/) and version.
+The `pulumi` module shows the current username, selected [Pulumi Stack](https://www.pulumi.com/docs/intro/concepts/stack/), and version.
::: tip
@@ -2440,13 +2440,13 @@ By default the module will be shown if any of the following conditions are met:
### Options
-| Option | Default | Description |
-| ---------------- | -------------------------------- | ------------------------------------------------------------------------- |
-| `format` | `"via [$symbol$stack]($style) "` | The format string for the module. |
-| `version_format` | `"v${raw}"` | The version format. Available vars are `raw`, `major`, `minor`, & `patch` |
-| `symbol` | `" "` | A format string shown before the Pulumi stack. |
-| `style` | `"bold 5"` | The style for the module. |
-| `disabled` | `false` | Disables the `pulumi` module. |
+| Option | Default | Description |
+| ---------------- | -------------------------------------------- | ------------------------------------------------------------------------- |
+| `format` | `"via [$symbol($username@)$stack]($style) "` | The format string for the module. |
+| `version_format` | `"v${raw}"` | The version format. Available vars are `raw`, `major`, `minor`, & `patch` |
+| `symbol` | `" "` | A format string shown before the Pulumi stack. |
+| `style` | `"bold 5"` | The style for the module. |
+| `disabled` | `false` | Disables the `pulumi` module. |
### Variables
@@ -2454,6 +2454,7 @@ By default the module will be shown if any of the following conditions are met:
| -------- | ---------- | ------------------------------------ |
| version | `v0.12.24` | The version of `pulumi` |
| stack | `dev` | The current Pulumi stack |
+| username | `alice` | The current Pulumi username |
| symbol | | Mirrors the value of option `symbol` |
| style\* | | Mirrors the value of option `style` |
diff --git a/src/configs/pulumi.rs b/src/configs/pulumi.rs
index 5a796dd79..2941bc1c4 100644
--- a/src/configs/pulumi.rs
+++ b/src/configs/pulumi.rs
@@ -15,7 +15,7 @@ pub struct PulumiConfig<'a> {
impl<'a> Default for PulumiConfig<'a> {
fn default() -> Self {
PulumiConfig {
- format: "via [$symbol$stack]($style) ",
+ format: "via [$symbol($username@)$stack]($style) ",
version_format: "v${raw}",
symbol: " ",
style: "bold 5",
diff --git a/src/modules/mod.rs b/src/modules/mod.rs
index fa79f4497..91333ccb4 100644
--- a/src/modules/mod.rs
+++ b/src/modules/mod.rs
@@ -222,7 +222,7 @@ pub fn description(module: &str) -> &'static str {
"package" => "The package version of the current directory's project",
"perl" => "The currently installed version of Perl",
"php" => "The currently installed version of PHP",
- "pulumi" => "The current stack and installed version of Pulumi",
+ "pulumi" => "The current username, stack, and installed version of Pulumi",
"purescript" => "The currently installed version of PureScript",
"python" => "The currently installed version of Python",
"red" => "The currently installed version of Red",
diff --git a/src/modules/pulumi.rs b/src/modules/pulumi.rs
index 7d07e87b6..fdd6dd5fc 100644
--- a/src/modules/pulumi.rs
+++ b/src/modules/pulumi.rs
@@ -1,8 +1,10 @@
#![warn(missing_docs)]
+use serde::Deserialize;
use sha1::{Digest, Sha1};
+use std::collections::HashMap;
use std::ffi::OsStr;
use std::fs::File;
-use std::io::Read;
+use std::io::{BufReader, Read};
use std::path::{Path, PathBuf};
use std::str::FromStr;
use yaml_rust::{Yaml, YamlLoader};
@@ -13,6 +15,17 @@ use crate::formatter::{StringFormatter, VersionFormatter};
static PULUMI_HOME: &str = "PULUMI_HOME";
+#[derive(Deserialize)]
+struct Credentials {
+ current: Option<String>,
+ accounts: Option<HashMap<String, Account>>,
+}
+
+#[derive(Deserialize)]
+struct Account {
+ username: Option<String>,
+}
+
/// Creates a module with the current Pulumi version and stack name.
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
let mut module = context.new_module("pulumi");
@@ -40,6 +53,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
)
}
.map(Ok),
+ "username" => get_pulumi_username(context).map(Ok),
"stack" => stack_name(&project_file, context).map(Ok),
_ => None,
})
@@ -163,6 +177,21 @@ fn pulumi_home_dir(context: &Context) -> Option<PathBuf> {
}
}
+fn get_pulumi_username(context: &Context) -> Option<String> {
+ let home_dir = pulumi_home_dir(context)?;
+ let creds_path = home_dir.join("credentials.json");
+
+ let file = File::open(creds_path).ok()?;
+ let reader = BufReader::new(file);
+
+ // Read the JSON contents of the file as an instance of `User`.
+ let creds: Credentials = serde_json::from_reader(reader).ok()?;
+
+ let current_api_provider = creds.current?;
+
+ creds.accounts?.remove(&current_api_provider)?.username
+}
+
#[cfg(test)]
mod tests {
use std::io;
@@ -259,16 +288,103 @@ mod tests {
),
)?;
workspace.sync_all()?;
+
+ let credential_path = root.join(".pulumi");
+ let _ = std::fs::create_dir_all(&credential_path)?;
+ let credential_path = &credential_path.join("credentials.json");
+ let mut credential = File::create(&credential_path)?;
+ serde_json::to_writer_pretty(
+ &mut credential,
+ &serde_json::json!(
+ {
+ "current": "https://api.example.com",
+ "accessTokens": {
+ "https://api.example.com": "redacted",
+ "https://api.pulumi.com": "redacted"
+ },
+ "accounts": {
+ "https://api.example.com": {
+ "accessToken": "redacted",
+ "username": "test-user",
+ "lastValidatedAt": "2022-01-12T00:00:00.000000000-08:00"
+ }
+ }
+ }
+ ),
+ )?;
+ credential.sync_all()?;
let rendered = ModuleRenderer::new("pulumi")
.path(root.clone())
.logical_path(root.clone())
.config(toml::toml! {
[pulumi]
- format = "in [$symbol($stack)]($style) "
+ format = "via [$symbol($username@)$stack]($style) "
+ })
+ .env("HOME", root.to_str().unwrap())
+ .collect();
+ let expected = format!(
+ "via {} ",
+ Color::Fixed(5).bold().paint(" test-user@launch")
+ );
+ assert_eq!(expected, rendered.expect("a result"));
+ dir.close()?;
+ Ok(())
+ }
+
+ #[test]
+ /// This test confirms a render when the account information incomplete, i.e.: no username for
+ /// the current API.
+ fn partial_login() -> io::Result<()> {
+ use io::Write;
+ let dir = tempfile::tempdir()?;
+ let root = std::fs::canonicalize(dir.path())?;
+ let mut yaml = File::create(root.join("Pulumi.yml"))?;
+ yaml.write_all("name: starship\nruntime: nodejs\ndescription: A thing\n".as_bytes())?;
+ yaml.sync_all()?;
+
+ let workspace_path = root.join(".pulumi").join("workspaces");
+ let _ = std::fs::create_dir_all(&workspace_path)?;
+ let workspace_path = &workspace_path.join("starship-test-workspace.json");
+ let mut workspace = File::create(&workspace_path)?;
+ serde_json::to_writer_pretty(
+ &mut workspace,
+ &serde_json::json!(
+ {
+ "stack": "launch"
+ }
+ ),
+ )?;
+ workspace.sync_all()?;
+
+ let credential_path = root.join(".pulumi");
+ let _ = std::fs::create_dir_all(&credential_path)?;
+ let credential_path = &credential_path.join("starship-test-credential.json");
+ let mut credential = File::create(&credential_path)?;
+ serde_json::to_writer_pretty(
+ &mut credential,
+ &serde_json::json!(
+ {
+ "current": "https://api.example.com",
+ "accessTokens": {
+ "https://api.example.com": "redacted",
+ "https://api.pulumi.com": "redacted"
+ },
+ "accounts": {
+ }
+ }
+ ),
+ )?;
+ credential.sync_all()?;
+ let rendered = ModuleRenderer::new("pulumi")
+ .path(root.clone())
+ .logical_path(root.clone())
+ .config(toml::toml! {
+ [pulumi]
+ format = "via [$symbol($username@)$stack]($style) "
})
.env("HOME", root.to_str().unwrap())
.collect();
- let expected = format!("in {} ", Color::Fixed(5).bold().paint(" launch"));
+ let expected = format!("via {} ", Color::Fixed(5).bold().paint(" launch"));
assert_eq!(expected, rendered.expect("a result"));
dir.close()?;
Ok(())