Skip to content

Commit

Permalink
Reformat Comment and support multiple environments (#7)
Browse files Browse the repository at this point in the history
* Reformat comment to be more readable using tables.
* Handle json variations
* Truncate variation info at 50 characters
* Loop over environments commenting with settings
  • Loading branch information
InTheCloudDan authored Apr 20, 2021
1 parent 9a7499e commit 566bf17
Show file tree
Hide file tree
Showing 9 changed files with 152 additions and 48 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Hello world action step
- name: Find LaunchDarkly Feature Flags
uses: ./ # Uses an action in the root directory
id: find_flags
with:
projKey: support-service
envKey: dano
envKey: dano,production
accessToken: ${{ secrets.LD_ACCESS_TOKEN }}
githubToken: ${{ secrets.GITHUB_TOKEN }}
baseUri: https://app.launchdarkly.com
67 changes: 48 additions & 19 deletions comments/comments.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,57 +5,86 @@ import (
"crypto/md5"
"encoding/hex"
"fmt"
"html"
"html/template"
"reflect"
"sort"
"strings"

"github.com/Masterminds/sprig/v3"

"github.com/google/go-github/github"
ldapi "github.com/launchdarkly/api-client-go"
"github.com/launchdarkly/cr-flags/config"
lcr "github.com/launchdarkly/cr-flags/config"
)

type Comment struct {
Flag ldapi.FeatureFlag
Aliases []string
ChangeType string
Environment ldapi.FeatureFlagConfig
LDInstance string
Flag ldapi.FeatureFlag
Aliases []string
ChangeType string
Primary ldapi.FeatureFlagConfig
Environments map[string]ldapi.FeatureFlagConfig
LDInstance string
}

func githubFlagComment(flag ldapi.FeatureFlag, aliases []string, environment string, instance string) (string, error) {
func isNil(a interface{}) bool {
defer func() { recover() }()
return a == nil || reflect.ValueOf(a).IsNil()
}

func githubFlagComment(flag ldapi.FeatureFlag, aliases []string, config *config.Config) (string, error) {
commentTemplate := Comment{
Flag: flag,
Aliases: aliases,
Environment: flag.Environments[environment],
LDInstance: instance,
Flag: flag,
Aliases: aliases,
Primary: flag.Environments[config.LdEnvironment[0]],
Environments: flag.Environments,
LDInstance: config.LdInstance,
}
var commentBody bytes.Buffer
tmplSetup := `
**[{{.Flag.Name}}]({{.LDInstance}}{{.Environment.Site.Href}})** ` + "`" + `{{.Flag.Key}}` + "`" + `
**[{{.Flag.Name}}]({{.LDInstance}}{{.Primary.Site.Href}})** ` + "`" + `{{.Flag.Key}}` + "`" + `
{{- if .Flag.Description}}
*{{trim .Flag.Description}}*
{{- end}}
{{- if .Flag.Tags}}
Tags: {{ range $i, $e := .Flag.Tags }}` + "{{if $i}}, {{end}}`" + `{{$e}}` + "`" + `{{end}}
{{- end}}
Default variation: ` + "`" + `{{(index .Flag.Variations .Environment.Fallthrough_.Variation).Value}}` + "`" + `
Off variation: ` + "`" + `{{(index .Flag.Variations .Environment.OffVariation).Value}}` + "`" + `
{{ end}}
Kind: **{{ .Flag.Kind }}**
Temporary: **{{ .Flag.Temporary }}**
{{- if .Aliases }}
{{- if ne (len .Aliases) 0}}
Aliases: {{range $i, $e := .Aliases }}` + "{{if $i}}, {{end}}`" + `{{$e}}` + "`" + `{{end}}
{{- end}}
{{- end}}
{{ "\n" }}
{{- range $key, $env := .Environments }}
Environment: **{{ $key }}**
| Type | Variation | Weight(if Rollout) |
| --- | --- | --- |
{{- if not (isNil .Fallthrough_.Rollout) }}
{{- if not (isNil .Fallthrough_.Rollout.Variations)}}
| Default | Rollout | |
{{- range .Fallthrough_.Rollout.Variations }}
| |` + "`" + `{{ trunc 50 (toRawJson (index $.Flag.Variations .Variation).Value) }}` + "` | `" + `{{ divf .Weight 1000 }}%` + "`|" + `
{{- end }}
{{- end }}
{{- else }}
| Default | ` + "`" + `{{ trunc 50 (toRawJson (index $.Flag.Variations .Fallthrough_.Variation).Value) }}` + "`| |" + `
{{- end }}
{{- if kindIs "int32" .OffVariation }}
| Off | ` + "`" + `{{ trunc 50 (toRawJson (index $.Flag.Variations .OffVariation).Value) }}` + "` | |" + `
{{- else }}
Off variation: No off variation set.
{{- end }}
{{ end }}
`
tmpl := template.Must(template.New("comment").Funcs(template.FuncMap{"trim": strings.TrimSpace}).Parse(tmplSetup))
tmpl := template.Must(template.New("comment").Funcs(template.FuncMap{"trim": strings.TrimSpace, "isNil": isNil}).Funcs(sprig.FuncMap()).Parse(tmplSetup))
err := tmpl.Execute(&commentBody, commentTemplate)
if err != nil {
return "", err
}
return commentBody.String(), nil
return html.UnescapeString(commentBody.String()), nil
}

func GithubNoFlagComment() *github.IssueComment {
Expand Down Expand Up @@ -125,7 +154,7 @@ func ProcessFlags(flagsRef FlagsRef, flags ldapi.FeatureFlags, config *lcr.Confi
}
}
idx, _ := find(flags.Items, flagKey)
createComment, err := githubFlagComment(flags.Items[idx], flagAliases, config.LdEnvironment, config.LdInstance)
createComment, err := githubFlagComment(flags.Items[idx], flagAliases, config)
buildComment.CommentsAdded = append(buildComment.CommentsAdded, createComment)
if err != nil {
fmt.Println(err)
Expand All @@ -145,7 +174,7 @@ func ProcessFlags(flagsRef FlagsRef, flags ldapi.FeatureFlags, config *lcr.Confi
}
}
idx, _ := find(flags.Items, flagKey)
removedComment, err := githubFlagComment(flags.Items[idx], flagAliases, config.LdEnvironment, config.LdInstance)
removedComment, err := githubFlagComment(flags.Items[idx], flagAliases, config)
buildComment.CommentsRemoved = append(buildComment.CommentsRemoved, removedComment)
if err != nil {
fmt.Println(err)
Expand Down
61 changes: 48 additions & 13 deletions comments/comments_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,20 @@ import (
func ptr(v interface{}) *interface{} { return &v }

type testFlagEnv struct {
Flag ldapi.FeatureFlag
Flag ldapi.FeatureFlag
Config config.Config
}

func newTestAccEnv() *testFlagEnv {

flag := createFlag("example-flag")

config := config.Config{
LdEnvironment: []string{"production"},
LdInstance: "https://example.com/",
}
return &testFlagEnv{
Flag: flag,
Flag: flag,
Config: config,
}
}

Expand Down Expand Up @@ -89,7 +94,7 @@ func newProcessFlagAccEnv() *testProcessor {
}

config := config.Config{
LdEnvironment: "production",
LdEnvironment: []string{"production"},
LdInstance: "https://example.com/",
}
return &testProcessor{
Expand All @@ -105,6 +110,7 @@ func TestGithubFlagComment(t *testing.T) {
t.Run("Flag with alias", acceptanceTestEnv.Alias)
t.Run("Flag with tag", acceptanceTestEnv.Tag)
t.Run("Flag with aliases and tags", acceptanceTestEnv.AliasesAndTags)
t.Run("Flag Rollout", acceptanceTestEnv.RolloutFlag)
}

func TestProcessFlags(t *testing.T) {
Expand All @@ -127,37 +133,66 @@ func TestBuildFlagComment(t *testing.T) {
}

func (e *testFlagEnv) noAliasesNoTags(t *testing.T) {
comment, err := githubFlagComment(e.Flag, []string{}, "production", "https://example.com/")

comment, err := githubFlagComment(e.Flag, []string{}, &e.Config)
if err != nil {
t.Fatalf("err:%v", err)
}
assert.Equal(t, "\n**[Sample Flag](https://example.com/test)** `example-flag`\n\nDefault variation: `true`\nOff variation: `true`\nKind: **boolean**\nTemporary: **false**\n", comment, "they should be equal")
assert.Equal(t, "\n**[Sample Flag](https://example.com/test)** `example-flag`\nKind: **boolean**\nTemporary: **false**\n\n\nEnvironment: **production**\n| Type | Variation | Weight(if Rollout) |\n| --- | --- | --- |\n| Default | `true`| |\n| Off | `true` | |\n\n", comment, "they should be equal")
}

func (e *testFlagEnv) Alias(t *testing.T) {
comment, err := githubFlagComment(e.Flag, []string{"exampleFlag"}, "production", "https://example.com/")
comment, err := githubFlagComment(e.Flag, []string{"exampleFlag"}, &e.Config)
if err != nil {
t.Fatalf("err:%v", err)
}
assert.Equal(t, "\n**[Sample Flag](https://example.com/test)** `example-flag`\n\nDefault variation: `true`\nOff variation: `true`\nKind: **boolean**\nTemporary: **false**\nAliases: `exampleFlag`\n", comment, "they should be equal")
assert.Equal(t, "\n**[Sample Flag](https://example.com/test)** `example-flag`\nKind: **boolean**\nTemporary: **false**\nAliases: `exampleFlag`\n\n\nEnvironment: **production**\n| Type | Variation | Weight(if Rollout) |\n| --- | --- | --- |\n| Default | `true`| |\n| Off | `true` | |\n\n", comment, "they should be equal")
}

func (e *testFlagEnv) Tag(t *testing.T) {
e.Flag.Tags = []string{"myTag"}
comment, err := githubFlagComment(e.Flag, []string{}, "production", "https://example.com/")
comment, err := githubFlagComment(e.Flag, []string{}, &e.Config)
if err != nil {
t.Fatalf("err:%v", err)
}
assert.Equal(t, "\n**[Sample Flag](https://example.com/test)** `example-flag`\nTags: `myTag`\n\nDefault variation: `true`\nOff variation: `true`\nKind: **boolean**\nTemporary: **false**\n", comment, "they should be equal")
assert.Equal(t, "\n**[Sample Flag](https://example.com/test)** `example-flag`\nTags: `myTag`\n\nKind: **boolean**\nTemporary: **false**\n\n\nEnvironment: **production**\n| Type | Variation | Weight(if Rollout) |\n| --- | --- | --- |\n| Default | `true`| |\n| Off | `true` | |\n\n", comment, "they should be equal")
}

func (e *testFlagEnv) AliasesAndTags(t *testing.T) {
e.Flag.Tags = []string{"myTag", "otherTag", "finalTag"}
comment, err := githubFlagComment(e.Flag, []string{"exampleFlag", "example_flag", "ExampleFlag"}, "production", "https://example.com/")
comment, err := githubFlagComment(e.Flag, []string{"exampleFlag", "example_flag", "ExampleFlag"}, &e.Config)
if err != nil {
t.Fatalf("err:%v", err)
}
assert.Equal(t, "\n**[Sample Flag](https://example.com/test)** `example-flag`\nTags: `myTag`, `otherTag`, `finalTag`\n\nKind: **boolean**\nTemporary: **false**\nAliases: `exampleFlag`, `example_flag`, `ExampleFlag`\n\n\nEnvironment: **production**\n| Type | Variation | Weight(if Rollout) |\n| --- | --- | --- |\n| Default | `true`| |\n| Off | `true` | |\n\n", comment, "they should be equal")
}

func (e *testFlagEnv) RolloutFlag(t *testing.T) {
trueRollout := ldapi.WeightedVariation{
Variation: 0,
Weight: 12345,
}
falseRollout := ldapi.WeightedVariation{
Variation: 1,
Weight: 87655,
}
rollout := ldapi.Rollout{
Variations: []ldapi.WeightedVariation{trueRollout, falseRollout},
}
environment := ldapi.FeatureFlagConfig{
Site: &ldapi.Site{
Href: "test",
},
Fallthrough_: &ldapi.ModelFallthrough{
Rollout: &rollout,
},
}
e.Flag.Environments["production"] = environment
comment, err := githubFlagComment(e.Flag, []string{"exampleFlag", "example_flag", "ExampleFlag"}, &e.Config)
if err != nil {
t.Fatalf("err:%v", err)
}
assert.Equal(t, "\n**[Sample Flag](https://example.com/test)** `example-flag`\nTags: `myTag`, `otherTag`, `finalTag`\n\nDefault variation: `true`\nOff variation: `true`\nKind: **boolean**\nTemporary: **false**\nAliases: `exampleFlag`, `example_flag`, `ExampleFlag`\n", comment, "they should be equal")
assert.Equal(t, "\n**[Sample Flag](https://example.com/test)** `example-flag`\nTags: `myTag`, `otherTag`, `finalTag`\n\nKind: **boolean**\nTemporary: **false**\nAliases: `exampleFlag`, `example_flag`, `ExampleFlag`\n\n\nEnvironment: **production**\n| Type | Variation | Weight(if Rollout) |\n| --- | --- | --- |\n| Default | Rollout | |\n| |`true` | `12.345%`|\n| |`false` | `87.655%`|\n| Off | `true` | |\n\n", comment, "they should be equal")
}

func (e *testCommentBuilder) AddedOnly(t *testing.T) {
Expand Down Expand Up @@ -187,7 +222,7 @@ func (e *testProcessor) Basic(t *testing.T) {
e.FlagsRef.FlagsAdded["example-flag"] = []string{""}
processor := ProcessFlags(e.FlagsRef, e.Flags, &e.Config)
expected := FlagComments{
CommentsAdded: []string{"\n**[Sample Flag](https://example.com/test)** `example-flag`\n\nDefault variation: `true`\nOff variation: `true`\nKind: **boolean**\nTemporary: **false**\n"},
CommentsAdded: []string{"\n**[Sample Flag](https://example.com/test)** `example-flag`\nKind: **boolean**\nTemporary: **false**\n\n\nEnvironment: **production**\n| Type | Variation | Weight(if Rollout) |\n| --- | --- | --- |\n| Default | `true`| |\n| Off | `true` | |\n\n"},
}
assert.Equal(t, expected, processor)
}
6 changes: 3 additions & 3 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (

type Config struct {
LdProject string
LdEnvironment string
LdEnvironment []string
LdInstance string
Owner string
Repo []string
Expand All @@ -28,8 +28,8 @@ func ValidateInputandParse(ctx context.Context) (*Config, error) {
return nil, errors.New("`project` is required.")

}
config.LdEnvironment = os.Getenv("INPUT_ENVKEY")
if config.LdEnvironment == "" {
config.LdEnvironment = strings.Split(os.Getenv("INPUT_ENVKEY"), ",")
if len(config.LdEnvironment) == 0 {
return nil, errors.New("`environment` is required.")
}
config.LdInstance = os.Getenv("INPUT_BASEURI")
Expand Down
2 changes: 1 addition & 1 deletion diff/diff_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func newProcessFlagAccEnv() *testProcessor {
}

config := config.Config{
LdEnvironment: "production",
LdEnvironment: []string{"production"},
LdInstance: "https://example.com/",
}
return &testProcessor{
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/launchdarkly/cr-flags
go 1.15

require (
github.com/antihax/optional v1.0.0
github.com/Masterminds/sprig/v3 v3.2.2
github.com/google/go-github v17.0.0+incompatible
github.com/google/go-querystring v1.0.0 // indirect
github.com/hashicorp/go-retryablehttp v0.6.8 // indirect
Expand Down
Loading

0 comments on commit 566bf17

Please sign in to comment.