diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index c2564345..a63a5d04 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -7,7 +7,7 @@ on:
jobs:
# Actually release the binaries including signing them
release:
- runs-on: depot-ubuntu-22.04-8
+ runs-on: depot-ubuntu-22.04-32
if: ${{ github.event_name != 'pull_request' }}
permissions:
contents: write
diff --git a/cmd/changes_get_change.go b/cmd/changes_get_change.go
index d3205ea0..c2af8db7 100644
--- a/cmd/changes_get_change.go
+++ b/cmd/changes_get_change.go
@@ -38,7 +38,7 @@ var getChangeCmd = &cobra.Command{
// to reflect the latest version
//
// This allows us to update the assets without fear of breaking older comments
-const assetVersion = "17c7fd2c365d4f4cdd8e414ca5148f825fa4febd"
+const assetVersion = "476f6df5bc783c17b1d0513a43e0a0aa9c075588" // tag from v1.6.1
func GetChange(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
@@ -204,8 +204,10 @@ fetch:
SeverityText string
Title string
Description string
+ RiskUrl string
}
type TemplateData struct {
+ BlastRadiusUrl string
ChangeUrl string
ExpectedChanges []TemplateItem
UnmappedChanges []TemplateItem
@@ -214,6 +216,7 @@ fetch:
Risks []TemplateRisk
// Path to the assets folder on github
AssetPath string
+ TagsLine string
}
status := map[sdp.ItemDiffStatus]TemplateItem{
sdp.ItemDiffStatus_ITEM_DIFF_STATUS_UNSPECIFIED: {
@@ -267,6 +270,7 @@ fetch:
app, _ = strings.CutSuffix(app, "/")
data := TemplateData{
ChangeUrl: fmt.Sprintf("%v/changes/%v", app, changeUuid.String()),
+ BlastRadiusUrl: fmt.Sprintf("%v/changes/%v/blast-radius", app, changeUuid.String()),
ExpectedChanges: []TemplateItem{},
UnmappedChanges: []TemplateItem{},
BlastItems: int(changeRes.Msg.GetChange().GetMetadata().GetNumAffectedItems()),
@@ -326,14 +330,20 @@ fetch:
}
for _, risk := range riskRes.Msg.GetChangeRiskMetadata().GetRisks() {
+ // parse the risk UUID to a string
+ riskUuid, _ := uuid.FromBytes(risk.GetUUID())
data.Risks = append(data.Risks, TemplateRisk{
SeverityAlt: severity[risk.GetSeverity()].SeverityAlt,
SeverityIcon: severity[risk.GetSeverity()].SeverityIcon,
SeverityText: severity[risk.GetSeverity()].SeverityText,
Title: risk.GetTitle(),
Description: risk.GetDescription(),
+ RiskUrl: fmt.Sprintf("%v/changes/%v/blast-radius?selectedRisk=%v&activeTab=risks", app, changeUuid.String(), riskUuid.String()),
})
}
+ // get the tags in
+ data.TagsLine = getTagsLine(changeRes.Msg.GetChange().GetProperties().GetEnrichedTags().GetTagValue())
+ data.TagsLine = strings.TrimSpace(data.TagsLine)
tmpl, err := template.New("comment").Parse(commentTemplate)
if err != nil {
@@ -386,6 +396,32 @@ func renderRiskFilter(levels []sdp.Risk_Severity) string {
return strings.Join(result, ", ")
}
+func getTagsLine(tags map[string]*sdp.TagValue) string {
+ autoTags := ""
+ userTags := ""
+
+ for key, value := range tags {
+ if value.GetAutoTagValue() != nil {
+ suffix := ""
+ if value.GetAutoTagValue().GetValue() != "" {
+ suffix = fmt.Sprintf("|%s", value.GetAutoTagValue().GetValue())
+ }
+ autoTags += fmt.Sprintf("`✨%s%s` ", key, suffix)
+ } else if value.GetUserTagValue() != nil {
+ suffix := ""
+ if value.GetUserTagValue().GetValue() != "" {
+ suffix = fmt.Sprintf("|%s", value.GetUserTagValue().GetValue())
+ }
+ userTags += fmt.Sprintf("`%s%s` ", key, suffix)
+ } else {
+ // we should never get here, but just in case.
+ // its a tag jim, but not as we know it
+ userTags += fmt.Sprintf("`%s` ", key)
+ }
+ }
+ return autoTags + userTags
+}
+
func init() {
changesCmd.AddCommand(getChangeCmd)
addAPIFlags(getChangeCmd)
diff --git a/cmd/changes_get_change_test.go b/cmd/changes_get_change_test.go
new file mode 100644
index 00000000..827be3a2
--- /dev/null
+++ b/cmd/changes_get_change_test.go
@@ -0,0 +1,104 @@
+package cmd
+
+import (
+ "testing"
+
+ "github.com/overmindtech/cli/sdp-go"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestGetTagsLine(t *testing.T) {
+ tests := []struct {
+ name string
+ tags map[string]*sdp.TagValue
+ want string
+ }{
+ {
+ name: "empty tags",
+ tags: map[string]*sdp.TagValue{},
+ want: "",
+ },
+ {
+ name: "key only",
+ tags: map[string]*sdp.TagValue{
+ "key": {},
+ },
+ want: "`key` ",
+ },
+ {
+ name: "auto tag without value",
+ tags: map[string]*sdp.TagValue{
+ "autoTag": {
+ Value: &sdp.TagValue_AutoTagValue{
+ AutoTagValue: &sdp.AutoTagValue{},
+ },
+ },
+ },
+ want: "`✨autoTag` ",
+ },
+ {
+ name: "auto tag with value",
+ tags: map[string]*sdp.TagValue{
+ "autoTag": {
+ Value: &sdp.TagValue_AutoTagValue{
+ AutoTagValue: &sdp.AutoTagValue{
+ Value: "value",
+ },
+ },
+ },
+ },
+ want: "`✨autoTag|value` ",
+ },
+ {
+ name: "user tag without value",
+ tags: map[string]*sdp.TagValue{
+ "userTag": {
+ Value: &sdp.TagValue_UserTagValue{
+ UserTagValue: &sdp.UserTagValue{},
+ },
+ },
+ },
+ want: "`userTag` ",
+ },
+ {
+ name: "user tag with value",
+ tags: map[string]*sdp.TagValue{
+ "userTag": {
+ Value: &sdp.TagValue_UserTagValue{
+ UserTagValue: &sdp.UserTagValue{
+ Value: "value",
+ },
+ },
+ },
+ },
+ want: "`userTag|value` ",
+ },
+ {
+ name: "mixed tags",
+ tags: map[string]*sdp.TagValue{
+ "autoTag": {
+ Value: &sdp.TagValue_AutoTagValue{
+ AutoTagValue: &sdp.AutoTagValue{
+ Value: "value",
+ },
+ },
+ },
+ "userTag": {
+ Value: &sdp.TagValue_UserTagValue{
+ UserTagValue: &sdp.UserTagValue{
+ Value: "value",
+ },
+ },
+ },
+ },
+ want: "`✨autoTag|value` `userTag|value` ",
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got := getTagsLine(tt.tags)
+ assert.Equal(t, tt.want, got)
+ })
+ }
+}
diff --git a/cmd/changes_list_changes.go b/cmd/changes_list_changes.go
index 07d67653..4b52b61e 100644
--- a/cmd/changes_list_changes.go
+++ b/cmd/changes_list_changes.go
@@ -238,6 +238,18 @@ func printJson(_ context.Context, b []byte, prefix, id string, cmd *cobra.Comman
return flagError{fmt.Sprintf("need --dir value to write to files\n\n%v", cmd.UsageString())}
}
+ // attempt to create the directory
+ err := os.MkdirAll(dir, 0755)
+ if err != nil {
+ return loggedError{
+ err: err,
+ fields: log.Fields{
+ "output-dir": dir,
+ },
+ message: "failed to create output directory",
+ }
+ }
+
// write the change to a file
fileName := fmt.Sprintf("%v/%v-%v.json", dir, prefix, id)
file, err := os.Create(fileName)
diff --git a/cmd/comment.md b/cmd/comment.md
index 500fa950..ee765d34 100644
--- a/cmd/comment.md
+++ b/cmd/comment.md
@@ -1,9 +1,27 @@
{{ $top := . -}}
+# 
+{{ if .TagsLine -}}
+{{ .TagsLine }}
+{{ end -}}
+
+#
Risks
+{{ if not .Risks }}
+Overmind has not identified any risks associated with this change.
+
+This could be due to the change being low risk with no impact on other parts of the system, or involving resources that Overmind currently does not support.
+{{ else -}}
+{{ range .Risks }}
+##
{{ .Title }} [{{ .SeverityText }}]
+
+{{ .Description }} [Open Risk]({{ .RiskUrl }})
+{{ end }}
+{{ end -}}
+
#
Expected Changes
{{ range .ExpectedChanges -}}
-
{{ .Type }} › {{ .Title }}
+
{{ .Type }} › {{ .Title }}
{{ if .Diff -}}
```diff
@@ -20,7 +38,7 @@ No expected changes found.
{{ end }}
{{ if .UnmappedChanges -}}
-##
Unmapped Changes
+#
Unmapped Changes
> [!NOTE]
> These changes couldn't be mapped to a discoverable cloud resource and therefore won't be included in the blast radius calculation.
@@ -28,7 +46,7 @@ No expected changes found.
{{ range .UnmappedChanges -}}
-
{{ .Type }} › {{ .Title }}
+
{{ .Type }} › {{ .Title }}
{{ if .Diff -}}
@@ -44,23 +62,12 @@ No expected changes found.
{{ end }}
{{ end }}
-# Blast Radius
+#
Blast Radius
-|
Items |
Edges |
+|
Items |
Edges |
| ------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| {{ .BlastItems }} | {{ .BlastEdges }} |
-[Open in Overmind]({{ .ChangeUrl }})
-
-#
Risks
-{{ if not .Risks }}
-Overmind has not identified any risks associated with this change.
+[Open Blast Radius]({{ .BlastRadiusUrl }})
-This could be due to the change being low risk with no impact on other parts of the system, or involving resources that Overmind currently does not support.
-{{ else -}}
-{{ range .Risks }}
-##
{{ .Title }} [{{ .SeverityText }}]
-
-{{ .Description }}
-{{ end }}
-{{ end -}}
+[
]({{ .ChangeUrl }})
diff --git a/cmd/root.go b/cmd/root.go
index d332f767..086d217c 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -77,7 +77,7 @@ func PreRunSetup(cmd *cobra.Command, args []string) {
// set up tracing
if honeycombApiKey := viper.GetString("honeycomb-api-key"); honeycombApiKey != "" {
- if err := tracing.InitTracerWithUpstreams("cli", honeycombApiKey, ""); err != nil {
+ if err := tracing.InitTracerWithUpstreams("overmind-cli", honeycombApiKey, ""); err != nil {
log.Fatal(err)
}
@@ -578,7 +578,7 @@ func getAPIKeyToken(ctx context.Context, oi sdp.OvermindInstance, apiKey string,
if !ok {
return nil, fmt.Errorf("authenticated successfully against %s, but your API key is missing this permission: '%v'", app, missing)
}
- pterm.Info.Println(fmt.Sprintf("Using Overmind API key for %s", app))
+ log.WithField("app", app).Info("Using Overmind API key")
return token, nil
}
diff --git a/sdp-go/changes.go b/sdp-go/changes.go
index 430636d3..322a4ffd 100644
--- a/sdp-go/changes.go
+++ b/sdp-go/changes.go
@@ -354,7 +354,9 @@ func (cp *ChangeProperties) ToMap() map[string]any {
"rawPlan": cp.GetRawPlan(),
"codeChanges": cp.GetCodeChanges(),
"repo": cp.GetRepo(),
- "tags": cp.GetTags(),
+ "tags": cp.GetEnrichedTags(),
+ "autoTaggingRuleSource": cp.GetAutoTaggingRuleSource().ToMessage(),
+ "skippedAutoTags": cp.GetSkippedAutoTags(),
}
}
@@ -429,6 +431,19 @@ func (s EndChangeResponse_State) ToMessage() string {
}
}
+func (s ChangeProperties_AutoTaggingRuleSource) ToMessage() string {
+ switch s {
+ case ChangeProperties_AUTO_TAGGING_RULE_SOURCE_UNSPECIFIED:
+ return "unknown"
+ case ChangeProperties_AUTO_TAGGING_RULE_SOURCE_FILE:
+ return "file"
+ case ChangeProperties_AUTO_TAGGING_RULE_SOURCE_UI:
+ return "ui"
+ default:
+ return "unknown"
+ }
+}
+
// allow custom auto tag rules to be passed on the cli, via a yaml file
//
// rules: