summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAaron Friel <mayreply@aaronfriel.com>2022-01-25 08:40:44 -0800
committerGitHub <noreply@github.com>2022-01-25 10:40:44 -0600
commit568d0570322ccc06f62237ea6b36d53e6a5bbf88 (patch)
tree9338e25fbc40cdc40ea4c775078a30c78224ec4f /src
parentf4ddaa0d60f739e0b7b2358e80bb7fa23afe7fc2 (diff)
feat: add username to Pulumi module (#3428)
* feat: add username to Pulumi module * run dprint fmt
Diffstat (limited to 'src')
-rw-r--r--src/configs/pulumi.rs2
-rw-r--r--src/modules/mod.rs2
-rw-r--r--src/modules/pulumi.rs122
3 files changed, 121 insertions, 5 deletions
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(())