feat(az): use template for more flexibility

BREAKING CHANGE: this makes it so people have to remove the switches
in favor of the new template.
This commit is contained in:
Jan De Dobbeleer 2021-09-18 11:30:52 +02:00
parent c6a3dd4ee8
commit 2ed5d31f4f
No known key found for this signature in database
GPG key ID: F6CC273CE5BA9AEE
7 changed files with 265 additions and 291 deletions

View file

@ -33,7 +33,23 @@ To enable this, set `$env:AZ_ENABLED = $true` in your `$PROFILE`.
## Properties ## Properties
- display_account: `boolean` - display the subscription account name or not - defaults to `false` - template: `string` - A go [text/template][go-text-template] template extended with [sprig][sprig] utilizing the
- display_name: `boolean` - display the subscription name or not - defaults to `true` properties below. Defaults to `{{.Name}}`
- display_id: `boolean` - display the subscription ID or not - defaults to `false`
- info_separator: `string` - text/icon to put in between the values - defaults to ` | ` ## Template Properties
:::caution
When using the PowerShell module, only `.EnvironmentName`, `.ID`, `.Name` and `.User.Name` are available.
:::
- `.EnvironmentName`: `string` - the account environment name
- `.HomeTenantID`: `string` - the home tenant id
- `.ID`: `string` - the account/subscription id
- `.IsDefault`: `boolean` - is the default account or not
- `.Name`: `string` - the account name
- `.State`: `string` - the account state
- `.TenantID`: `string` - the tenant id
- `.User.Name`: `string` - the user name
[go-text-template]: https://golang.org/pkg/text/template/
[sprig]: https://masterminds.github.io/sprig/

View file

@ -50,16 +50,19 @@ function global:Initialize-ModuleSupport {
$env:POSH_GIT_STATUS = Write-GitStatus -Status $global:GitStatus $env:POSH_GIT_STATUS = Write-GitStatus -Status $global:GitStatus
} }
$env:AZ_SUBSCRIPTION_NAME = $null $env:AZ_ENVIRONMENT_NAME = $null
$env:AZ_USER_NAME = $null
$env:AZ_SUBSCRIPTION_ID = $null $env:AZ_SUBSCRIPTION_ID = $null
$env:AZ_ACCOUNT_NAME = $null
if ($env:AZ_ENABLED -eq $true) { if ($env:AZ_ENABLED -eq $true) {
try { try {
$subscription = Get-AzContext | Select-Object -ExpandProperty "Subscription" | Select-Object "Name", "Id", "Account" $context = Get-AzContext
if ($null -ne $subscription) { if ($null -ne $subscription) {
$env:AZ_SUBSCRIPTION_NAME = $subscription.Name $env:AZ_ENVIRONMENT_NAME = $context.Environment.Name
$env:AZ_SUBSCRIPTION_ID = $subscription.Id $env:AZ_USER_NAME = $context.Account.Id
$env:AZ_SUBSCRIPTION_ACCOUNT = $subscription.Account $env:AZ_SUBSCRIPTION_ID = $context.Subscription.Id
$env:AZ_ACCOUNT_NAME = $context.Subscription.Name
} }
} }
catch {} catch {}

View file

@ -1,57 +1,53 @@
package main package main
import ( import (
"encoding/json"
"strings" "strings"
) )
type az struct { type az struct {
props *properties props *properties
env environmentInfo env environmentInfo
name string AZ *AzureAccount
id string
account string
builder strings.Builder
separator string
} }
const ( const (
// SubscriptionInfoSeparator is put between the name and ID
SubscriptionInfoSeparator Property = "info_separator"
// DisplaySubscriptionID hides or show the subscription GUID
DisplaySubscriptionID Property = "display_id"
// DisplaySubscriptionName hides or shows the subscription display name
DisplaySubscriptionName Property = "display_name"
// DisplaySubscriptionAccount hides or shows the subscription account name
DisplaySubscriptionAccount Property = "display_account"
updateConsentNeeded = "Do you want to continue?" updateConsentNeeded = "Do you want to continue?"
updateMessage = "AZ CLI: Update needed!" updateMessage = "AZ CLI: Update needed!"
updateForeground = "#ffffff" updateForeground = "#ffffff"
updateBackground = "#ff5349" updateBackground = "#ff5349"
) )
func (a *az) string() string { type AzureUser struct {
a.separator = a.props.getString(SubscriptionInfoSeparator, " | ") Name string `json:"name"`
writeValue := func(value string) { }
if len(value) == 0 {
return
}
if a.builder.Len() > 0 {
a.builder.WriteString(a.separator)
}
a.builder.WriteString(value)
}
if a.props.getBool(DisplaySubscriptionAccount, false) {
writeValue(a.account)
}
if a.props.getBool(DisplaySubscriptionName, true) {
writeValue(a.name)
}
if a.props.getBool(DisplaySubscriptionID, false) {
writeValue(a.id)
}
return a.builder.String() type AzureAccount struct {
EnvironmentName string `json:"environmentName"`
HomeTenantID string `json:"homeTenantId"`
ID string `json:"id"`
IsDefault bool `json:"isDefault"`
Name string `json:"name"`
State string `json:"state"`
TenantID string `json:"tenantId"`
User *AzureUser `json:"user"`
}
func (a *az) string() string {
if a.AZ != nil && a.AZ.Name == updateMessage {
return updateMessage
}
segmentTemplate := a.props.getString(SegmentTemplate, "{{.Name}}")
template := &textTemplate{
Template: segmentTemplate,
Context: a.AZ,
Env: a.env,
}
text, err := template.render()
if err != nil {
return err.Error()
}
return text
} }
func (a *az) init(props *properties, env environmentInfo) { func (a *az) init(props *properties, env environmentInfo) {
@ -68,14 +64,24 @@ func (a *az) enabled() bool {
} }
func (a *az) getFromEnvVars() bool { func (a *az) getFromEnvVars() bool {
a.name = a.env.getenv("AZ_SUBSCRIPTION_NAME") environmentName := a.env.getenv("AZ_ENVIRONMENT_NAME")
a.id = a.env.getenv("AZ_SUBSCRIPTION_ID") userName := a.env.getenv("AZ_USER_NAME")
a.account = a.env.getenv("AZ_SUBSCRIPTION_ACCOUNT") id := a.env.getenv("AZ_SUBSCRIPTION_ID")
accountName := a.env.getenv("AZ_ACCOUNT_NAME")
if a.name == "" && a.id == "" { if userName == "" && environmentName == "" {
return false return false
} }
a.AZ = &AzureAccount{
EnvironmentName: environmentName,
Name: accountName,
ID: id,
User: &AzureUser{
Name: userName,
},
}
return true return true
} }
@ -85,7 +91,7 @@ func (a *az) getFromAzCli() bool {
return false return false
} }
output, _ := a.env.runCommand(cmd, "account", "show", "--query=[name,id,user.name]", "-o=tsv") output, _ := a.env.runCommand(cmd, "account", "show")
if len(output) == 0 { if len(output) == 0 {
return false return false
} }
@ -93,17 +99,13 @@ func (a *az) getFromAzCli() bool {
if strings.Contains(output, updateConsentNeeded) { if strings.Contains(output, updateConsentNeeded) {
a.props.foreground = updateForeground a.props.foreground = updateForeground
a.props.background = updateBackground a.props.background = updateBackground
a.name = updateMessage a.AZ = &AzureAccount{
Name: updateMessage,
}
return true return true
} }
splittedOutput := strings.Split(output, "\n") a.AZ = &AzureAccount{}
if len(splittedOutput) < 3 { err := json.Unmarshal([]byte(output), a.AZ)
return false return err == nil
}
a.name = strings.TrimSpace(splittedOutput[0])
a.id = strings.TrimSpace(splittedOutput[1])
a.account = strings.TrimSpace(splittedOutput[2])
return true
} }

View file

@ -9,162 +9,140 @@ import (
func TestAzSegment(t *testing.T) { func TestAzSegment(t *testing.T) {
cases := []struct { cases := []struct {
Case string Case string
ExpectedEnabled bool ExpectedEnabled bool
ExpectedString string ExpectedString string
EnvSubName string EnvEnvironmentName string
EnvSubID string EnvUserName string
EnvSubAccount string AccountName string
CliExists bool EnvSubscriptionID string
CliSubName string CLIExists bool
CliSubID string CLIEnvironmentname string
CliSubAccount string CLISubscriptionID string
InfoSeparator string CLIAccountName string
DisplayID bool CLIUserName string
DisplayName bool Template string
DisplayAccount bool
}{ }{
{ {
Case: "print only account", Case: "display account name",
ExpectedEnabled: true, ExpectedEnabled: true,
ExpectedString: "foobar", ExpectedString: "foobar",
CliExists: true, CLIExists: true,
CliSubName: "foo", CLIEnvironmentname: "foo",
CliSubID: "bar", CLISubscriptionID: "bar",
CliSubAccount: "foobar", CLIAccountName: "foobar",
InfoSeparator: "$", Template: "{{.Name}}",
DisplayID: false,
DisplayName: false,
DisplayAccount: true,
}, },
{ {
Case: "envvars present", Case: "envvars present",
ExpectedEnabled: true, ExpectedEnabled: true,
ExpectedString: "foo$bar", ExpectedString: "foo$bar",
EnvSubName: "foo", EnvEnvironmentName: "foo",
EnvSubID: "bar", EnvUserName: "bar",
CliExists: false, CLIExists: false,
InfoSeparator: "$", Template: "{{.EnvironmentName}}${{.User.Name}}",
DisplayID: true,
DisplayName: true,
}, },
{ {
Case: "envvar name present", Case: "envvar environment name present",
ExpectedEnabled: true, ExpectedEnabled: true,
ExpectedString: "foo", ExpectedString: "foo",
EnvSubName: "foo", EnvEnvironmentName: "foo",
CliExists: false, CLIExists: false,
InfoSeparator: "$", Template: "{{.EnvironmentName}}",
DisplayID: true,
DisplayName: true,
}, },
{ {
Case: "envvar id present", Case: "envvar user name present",
ExpectedEnabled: true, ExpectedEnabled: true,
ExpectedString: "bar", ExpectedString: "bar",
EnvSubID: "bar", EnvUserName: "bar",
CliExists: false, CLIExists: false,
InfoSeparator: "$", Template: "{{.User.Name}}",
DisplayID: true,
DisplayName: true,
}, },
{ {
Case: "envvar account present", Case: "envvar subscription id",
ExpectedEnabled: true, ExpectedEnabled: true,
ExpectedString: "foobar", ExpectedString: "foobar",
EnvSubAccount: "foobar", EnvSubscriptionID: "foobar",
EnvSubID: "bar", EnvUserName: "bar",
CliExists: false, CLIExists: false,
InfoSeparator: "$", Template: "{{.ID}}",
DisplayAccount: true,
}, },
{ {
Case: "cli not found", Case: "cli not found",
ExpectedEnabled: false, ExpectedEnabled: false,
ExpectedString: "", ExpectedString: "",
CliExists: false, CLIExists: false,
InfoSeparator: "$",
DisplayID: true,
DisplayName: true,
}, },
{ {
Case: "cli contains data", Case: "cli contains data",
ExpectedEnabled: true, ExpectedEnabled: true,
ExpectedString: "foo$bar", ExpectedString: "foo$bar",
CliExists: true, CLIExists: true,
CliSubName: "foo", CLIEnvironmentname: "foo",
CliSubID: "bar", CLISubscriptionID: "bar",
InfoSeparator: "$", Template: "{{.EnvironmentName}}${{.ID}}",
DisplayID: true,
DisplayName: true,
}, },
{ {
Case: "print only name", Case: "print only environment ame",
ExpectedEnabled: true, ExpectedEnabled: true,
ExpectedString: "foo", ExpectedString: "foo",
CliExists: true, CLIExists: true,
CliSubName: "foo", CLIEnvironmentname: "foo",
CliSubID: "bar", CLISubscriptionID: "bar",
InfoSeparator: "$", Template: "{{.EnvironmentName}}",
DisplayID: false,
DisplayName: true,
}, },
{ {
Case: "print only id", Case: "print only id",
ExpectedEnabled: true, ExpectedEnabled: true,
ExpectedString: "bar", ExpectedString: "bar",
CliExists: true, CLIExists: true,
CliSubName: "foo", CLIEnvironmentname: "foo",
CliSubID: "bar", CLISubscriptionID: "bar",
InfoSeparator: "$", Template: "{{.ID}}",
DisplayID: true,
DisplayName: false,
}, },
{ {
Case: "print none", Case: "print none",
ExpectedEnabled: true, ExpectedEnabled: true,
CliExists: true, CLIExists: true,
CliSubName: "foo", CLIEnvironmentname: "foo",
CliSubID: "bar", CLISubscriptionID: "bar",
InfoSeparator: "$",
}, },
{ {
Case: "update needed", Case: "update needed",
ExpectedEnabled: true, ExpectedEnabled: true,
ExpectedString: updateMessage, ExpectedString: updateMessage,
CliExists: true, CLIExists: true,
CliSubName: "Do you want to continue? (Y/n): Visual Studio Enterprise", CLIEnvironmentname: "Do you want to continue? (Y/n): Visual Studio Enterprise",
DisplayID: false,
DisplayName: true,
},
{
Case: "account info",
ExpectedEnabled: true,
ExpectedString: updateMessage,
CliExists: true,
CliSubName: "Do you want to continue? (Y/n): Visual Studio Enterprise",
DisplayID: false,
DisplayName: true,
DisplayAccount: true,
}, },
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(MockedEnvironment)
env.On("getenv", "AZ_SUBSCRIPTION_NAME").Return(tc.EnvSubName) env.On("getenv", "AZ_ENVIRONMENT_NAME").Return(tc.EnvEnvironmentName)
env.On("getenv", "AZ_SUBSCRIPTION_ID").Return(tc.EnvSubID) env.On("getenv", "AZ_USER_NAME").Return(tc.EnvUserName)
env.On("getenv", "AZ_SUBSCRIPTION_ACCOUNT").Return(tc.EnvSubAccount) env.On("getenv", "AZ_SUBSCRIPTION_ID").Return(tc.EnvSubscriptionID)
env.On("hasCommand", "az").Return(tc.CliExists) env.On("getenv", "AZ_ACCOUNT_NAME").Return(tc.AccountName)
env.On("runCommand", "az", []string{"account", "show", "--query=[name,id,user.name]", "-o=tsv"}).Return( env.On("hasCommand", "az").Return(tc.CLIExists)
fmt.Sprintf("%s\n%s\n%s\n", tc.CliSubName, tc.CliSubID, tc.CliSubAccount), env.On("runCommand", "az", []string{"account", "show"}).Return(
fmt.Sprintf(`{
"environmentName": "%s",
"homeTenantId": "8d934305-ac9f-46fe-b0e7-50fd32ad2acf",
"id": "%s",
"isDefault": true,
"managedByTenants": [],
"name": "%s",
"state": "Enabled",
"tenantId": "8d934305-ac9f-46fe-b0e7-50fd32ad2acf",
"user": {
"name": "%s",
"type": "user"
}
}`, tc.CLIEnvironmentname, tc.CLISubscriptionID, tc.CLIAccountName, tc.CLIUserName),
nil, nil,
) )
props := &properties{ props := &properties{
values: map[Property]interface{}{ values: map[Property]interface{}{
SubscriptionInfoSeparator: tc.InfoSeparator, SegmentTemplate: tc.Template,
DisplaySubscriptionID: tc.DisplayID,
DisplaySubscriptionName: tc.DisplayName,
DisplaySubscriptionAccount: tc.DisplayAccount,
}, },
} }

View file

@ -10,87 +10,84 @@
"alignment": "left", "alignment": "left",
"segments": [ "segments": [
{ {
"type": "text", "type": "text",
"style": "diamond", "style": "diamond",
"leading_diamond": "\ue0c2\ue0c2", "leading_diamond": "\ue0c2\ue0c2",
"foreground": "#000000", "foreground": "#000000",
"background": "#4707a8", "background": "#4707a8",
"properties": { "properties": {
"text": "", "text": "",
"postfix": "", "postfix": "",
"prefix": "" "prefix": ""
} }
}, },
{ {
"type": "session", "type": "session",
"style": "diamond", "style": "diamond",
"foreground": "#ffffff", "foreground": "#ffffff",
"background": "#4707a8", "background": "#4707a8",
"leading_diamond": "\uE0B6", "leading_diamond": "\uE0B6",
"trailing_diamond": "\uE0B0" "trailing_diamond": "\uE0B0"
}, },
{ {
"type": "az", "type": "az",
"style": "powerline", "style": "powerline",
"powerline_symbol": "\uE0B0", "powerline_symbol": "\uE0B0",
"foreground": "#ffffff", "foreground": "#ffffff",
"background": "#1a1af5", "background": "#1a1af5",
"properties": { "properties": {
"display_id": false, "prefix": " \uFD03 "
"display_name": true, }
"info_separator": " @ ",
"prefix": " \uFD03 "
}
}, },
{ {
"type": "exit", "type": "exit",
"style": "diamond", "style": "diamond",
"foreground": "#ffffff", "foreground": "#ffffff",
"background": "#4707a8", "background": "#4707a8",
"leading_diamond": "", "leading_diamond": "",
"trailing_diamond": "\uE0B4", "trailing_diamond": "\uE0B4",
"properties": { "properties": {
"display_exit_code": false, "display_exit_code": false,
"always_enabled": true, "always_enabled": true,
"error_color": "#f1184c", "error_color": "#f1184c",
"color_background": true, "color_background": true,
"prefix": "<transparent>\uE0B0</> \uE23A" "prefix": "<transparent>\uE0B0</> \uE23A"
} }
} }
] ]
}, },
{ {
"type": "prompt", "type": "prompt",
"alignment": "left", "alignment": "left",
"newline": true, "newline": true,
"segments": [ "segments": [
{ {
"type": "os", "type": "os",
"style": "diamond", "style": "diamond",
"leading_diamond": "\ue0c2\ue0c2", "leading_diamond": "\ue0c2\ue0c2",
"foreground": "#000000", "foreground": "#000000",
"background": "#ffffff", "background": "#ffffff",
"properties": { "properties": {
"alpine": "\uf300", "alpine": "\uf300",
"arch": "\uf303", "arch": "\uf303",
"centos": "\uf304", "centos": "\uf304",
"debian": "\uf306", "debian": "\uf306",
"elementary": "\uf309", "elementary": "\uf309",
"fedora": "\uf30a", "fedora": "\uf30a",
"gentoo": "\uf30d", "gentoo": "\uf30d",
"linux": "\ue712", "linux": "\ue712",
"macos": "\ue711", "macos": "\ue711",
"manjaro": "\uf312", "manjaro": "\uf312",
"mint": "\uf30f", "mint": "\uf30f",
"opensuse": "\uf314", "opensuse": "\uf314",
"raspbian": "\uf315", "raspbian": "\uf315",
"ubuntu": "\uf31c", "ubuntu": "\uf31c",
"wsl": "\ue712", "wsl": "\ue712",
"wsl_separator": " on ", "wsl_separator": " on ",
"windows": "\ue70f", "windows": "\ue70f",
"postfix": "<#000000> \ue0b1</>" "postfix": "<#000000> \ue0b1</>"
} }
}, },
{ {
@ -136,13 +133,13 @@
"prefix": "<#ffffff>\ue0b1 </>" "prefix": "<#ffffff>\ue0b1 </>"
} }
}, },
{ {
"type": "terraform", "type": "terraform",
"style": "powerline", "style": "powerline",
"powerline_symbol": "", "powerline_symbol": "",
"foreground": "#000000", "foreground": "#000000",
"background": "#ffffff" "background": "#ffffff"
}, },
{ {
"type": "text", "type": "text",
"style": "diamond", "style": "diamond",
@ -150,9 +147,9 @@
"foreground": "#000000", "foreground": "#000000",
"background": "#ffffff", "background": "#ffffff",
"properties": { "properties": {
"text": "", "text": "",
"postfix": "", "postfix": "",
"prefix": "" "prefix": ""
} }
} }
] ]
@ -166,7 +163,7 @@
"style": "plain", "style": "plain",
"foreground": "#1a1af5", "foreground": "#1a1af5",
"properties": { "properties": {
"text": "\u276F" "text": "\u276F"
} }
} }
] ]

View file

@ -39,9 +39,6 @@
"foreground": "#000000", "foreground": "#000000",
"background": "#008AD7", "background": "#008AD7",
"properties": { "properties": {
"display_id": false,
"display_name": true,
"info_separator": " @ ",
"prefix": " \uFD03 " "prefix": " \uFD03 "
} }
} }

View file

@ -290,23 +290,8 @@
"properties": { "properties": {
"properties": { "properties": {
"properties": { "properties": {
"display_id": { "template": {
"type": "boolean", "$ref": "#/definitions/template"
"title": "Display ID",
"description": "Display the subscription ID or not",
"default": false
},
"display_name": {
"type": "boolean",
"title": "Display Name",
"description": "Display the subscription name or not",
"default": true
},
"info_separator": {
"type": "string",
"title": "Display Name",
"description": "Text/icon to put in between the subscription name and ID",
"default": " | "
} }
} }
} }
@ -1597,11 +1582,7 @@
"title": "units", "title": "units",
"description": "Units of measurement. Available values are standard (kelvin), metric (celsius), and imperial (fahrenheit). Default is standard", "description": "Units of measurement. Available values are standard (kelvin), metric (celsius), and imperial (fahrenheit). Default is standard",
"default": "standard", "default": "standard",
"enum": [ "enum": ["standard", "metric", "imperial"]
"standard",
"metric",
"imperial"
]
}, },
"enable_hyperlink": { "enable_hyperlink": {
"$ref": "#/definitions/enable_hyperlink" "$ref": "#/definitions/enable_hyperlink"