Skip to content

Commit da81065

Browse files
Oded-Bhnnsgstfssn
andauthored
Sync PR 2 (#13)
* Document APPROVER_GITHUB_APP_ID and APPROVER_GITHUB_APP_PRIVATE_KEY_PATH env vars (#189) * Add a Target Description configuration keys to provide control over promotion PR titles (#191) * Add tests for the new **optional** configuration key * Provide example for PR title in doc * Allow skipping upstream TLS server certificate validation for the webhook proxy functionality (#190) --------- Co-authored-by: Hannes Gustafsson <hnnsgstfssn@gmail.com>
1 parent 324e6b0 commit da81065

File tree

8 files changed

+203
-8
lines changed

8 files changed

+203
-8
lines changed

docs/installation.md

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ Environment variables for the webhook process:
7575

7676
`APPROVER_GITHUB_OAUTH_TOKEN` GitHub OAuth token for automatically approving promotion PRs
7777

78+
`APPROVER_GITHUB_APP_ID` is an alternative to `APPROVER_GITHUB_OAUTH_TOKEN`. You can also use GitHub App style of authentication for the automated PR approval process. This variable supplies the Application ID.
79+
80+
`APPROVER_GITHUB_APP_PRIVATE_KEY_PATH` is an alternative to `APPROVER_GITHUB_OAUTH_TOKEN`. You can also use GitHub App style of authentication for the automated PR approval process. This variable supplies the path to the Github Application private key file (in `.pem` format).
81+
7882
`GITHUB_OAUTH_TOKEN` GitHub main OAuth token for all other GH operations
7983

8084
`GITHUB_HOST` Host name for github API, needed for Github Enterprise Server, should not include http scheme and path, e.g. :`my-gh-host.com`
@@ -114,9 +118,11 @@ Configuration keys:
114118
|`promotionPaths[0].conditions.autoMerge`| Boolean value. If set to true, PR will be automatically merged after it is created.|
115119
|`promotionPaths[0].promotionPrs`| Array of structures, each element represent a PR that will be opened when files are changed under `sourcePath`. Multiple elements means multiple PR will be opened|
116120
|`promotionPaths[0].promotionPrs[0].targetPaths`| Array of strings, each element represent a directory to by synced from the changed component under `sourcePath`. Multiple elements means multiple directories will be synced in a PR|
121+
|`promotionPaths[0].promotionPrs[0].targetDescription`| An optional string that describes the target paths, will be used in the promotion PR titles, for example "All Staging Clusters" or "Production Tier 2 Clusters". If this value is not provided Telefonistka will concatenate all `targetPaths` in the PR title which can make it very long and unreadable. Regardless of this configuration key, the PR titles will always start with the component name, e.g. `🚀 Promotion: nginx ➡️ Production Tier 2 Clusters` |
117122
|`dryRunMode`| if true, the bot will just comment the planned promotion on the merged PR|
118123
|`autoApprovePromotionPrs`| if true the bot will auto-approve all promotion PRs, with the assumption the original PR was peer reviewed and is promoted verbatim. Required additional GH token via APPROVER_GITHUB_OAUTH_TOKEN env variable|
119124
|`toggleCommitStatus`| Map of strings, allow (non-repo-admin) users to change the [Github commit status](https://docs.github.com/en/rest/commits/statuses) state(from failure to success and back). This can be used to continue promotion of a change that doesn't pass repo checks. the keys are strings commented in the PRs, values are [Github commit status context](https://docs.github.com/en/rest/commits/statuses?apiVersion=2022-11-28#create-a-commit-status) to be overridden|
125+
|`whProxtSkipTLSVerifyUpstream`| This disables upstream TLS server certificate validation for the webhook proxy functionality. Default is `false`. |
120126
|`commentArgocdDiffonPR`| Uses ArgoCD API to calculate expected changes to k8s state and comment the resulting "diff" as comment in the PR. Requires ARGOCD_* environment variables, see below. |
121127
|`autoMergeNoDiffPRs`| if true, Telefonistka will **merge** promotion PRs that are not expected to change the target clusters. Requires `commentArgocdDiffonPR` and possibly `autoApprovePromotionPrs`(depending on repo branch protection rules)|
122128
|`useSHALabelForArgoDicovery`| The default method for discovering relevant ArgoCD applications (for a PR) relies on fetching all applications in the repo and checking the `argocd.argoproj.io/manifest-generate-paths` **annotation**, this might cause a performance issue on a repo with a large number of ArgoCD applications. The alternative is to add SHA1 of the application path as a **label** and rely on ArgoCD server-side filtering, label name is `telefonistka.io/component-path-sha1`.|
@@ -130,7 +136,8 @@ promotionPaths:
130136
conditions:
131137
autoMerge: true
132138
promotionPrs:
133-
- targetPaths:
139+
- targetDescription: "All non-production clusters"
140+
targetPaths:
134141
- "clusters/dev/us-east4/c2"
135142
- "clusters/lab/europe-west4/c1"
136143
- "clusters/staging/us-central1/c1"
@@ -141,9 +148,11 @@ promotionPaths:
141148
prHasLabels:
142149
- "quick_promotion" # This flow will run only if PR has "quick_promotion" label, see targetPaths below
143150
promotionPrs:
144-
- targetPaths:
151+
- targetDescription: "Production clusters tier 1"
152+
targetPaths:
145153
- "clusters/prod/us-west1/c2" # First PR for only a single cluster
146-
- targetPaths:
154+
- targetDescription: "Production clusters tier 2"
155+
targetPaths:
147156
- "clusters/prod/europe-west3/c2" # 2nd PR will sync all 4 remaining clusters
148157
- "clusters/prod/europe-west4/c2"
149158
- "clusters/prod/us-central1/c2"

go.mod

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ toolchain go1.22.1
66

77
require (
88
github.com/alexliesenfeld/health v0.8.0
9+
10+
11+
require (
12+
=======
913
github.com/argoproj/argo-cd/v2 v2.11.2
1014
github.com/argoproj/gitops-engine v0.7.1-0.20240416142647-fbecbb86e412
1115
github.com/bradleyfalzon/ghinstallation/v2 v2.10.0
@@ -43,6 +47,7 @@ require (
4347
github.com/alecthomas/participle/v2 v2.1.1 // indirect
4448
github.com/argoproj/pkg v0.13.7-0.20230626144333-d56162821bd1 // indirect
4549
github.com/beorn7/perks v1.0.1 // indirect
50+
4651
github.com/blang/semver/v4 v4.0.0 // indirect
4752
github.com/bmatcuk/doublestar/v4 v4.6.1 // indirect
4853
github.com/bombsimon/logrusr/v2 v2.0.1 // indirect
@@ -80,6 +85,7 @@ require (
8085
github.com/goccy/go-yaml v1.11.3 // indirect
8186
github.com/gogo/protobuf v1.3.2 // indirect
8287
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
88+
8389
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
8490
github.com/golang/protobuf v1.5.4 // indirect
8591
github.com/google/btree v1.1.2 // indirect
@@ -103,6 +109,7 @@ require (
103109
github.com/itchyny/timefmt-go v0.1.5 // indirect
104110
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
105111
github.com/jinzhu/copier v0.4.0 // indirect
112+
106113
github.com/jonboulle/clockwork v0.4.0 // indirect
107114
github.com/josharian/intern v1.0.0 // indirect
108115
github.com/json-iterator/go v1.1.12 // indirect
@@ -114,6 +121,7 @@ require (
114121
github.com/mailru/easyjson v0.7.7 // indirect
115122
github.com/mattn/go-colorable v0.1.13 // indirect
116123
github.com/mattn/go-isatty v0.0.20 // indirect
124+
117125
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
118126
github.com/moby/spdystream v0.2.0 // indirect
119127
github.com/moby/term v0.5.0 // indirect
@@ -147,6 +155,7 @@ require (
147155
github.com/xanzy/ssh-agent v0.3.3 // indirect
148156
github.com/xlab/treeprint v1.2.0 // indirect
149157
github.com/yuin/gopher-lua v1.1.1 // indirect
158+
150159
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.50.0 // indirect
151160
go.opentelemetry.io/otel v1.25.0 // indirect
152161
go.opentelemetry.io/otel/metric v1.25.0 // indirect

go.sum

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
23
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
34
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
@@ -638,6 +639,7 @@ github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc
638639
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
639640
github.com/alexliesenfeld/health v0.8.0 h1:lCV0i+ZJPTbqP7LfKG7p3qZBl5VhelwUFCIVWl77fgk=
640641
github.com/alexliesenfeld/health v0.8.0/go.mod h1:TfNP0f+9WQVWMQRzvMUjlws4ceXKEL3WR+6Hp95HUFc=
642+
641643
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk=
642644
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
643645
github.com/alicebob/miniredis/v2 v2.30.4 h1:8S4/o1/KoUArAGbGwPxcwf0krlzceva2XVOSchFS7Eo=
@@ -835,6 +837,7 @@ github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD87
835837
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
836838
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
837839
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
840+
838841
github.com/go-redis/cache/v9 v9.0.0 h1:0thdtFo0xJi0/WXbRVu8B066z8OvVymXTJGaXrVWnN0=
839842
github.com/go-redis/cache/v9 v9.0.0/go.mod h1:cMwi1N8ASBOufbIvk7cdXe2PbPjK/WMRL95FFHWsSgI=
840843
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
@@ -850,6 +853,7 @@ github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
850853
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
851854
github.com/goccy/go-yaml v1.11.3 h1:B3W9IdWbvrUu2OYQGwvU1nZtvMQJPBKgBUuweJjLj6I=
852855
github.com/goccy/go-yaml v1.11.3/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU=
856+
853857
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
854858
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
855859
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
@@ -932,6 +936,7 @@ github.com/google/go-github/v62 v62.0.0 h1:/6mGCaRywZz9MuHyw9gD1CwsbmBX8GWsbFkwM
932936
github.com/google/go-github/v62 v62.0.0/go.mod h1:EMxeUqGJq2xRu9DYBMwel/mr7kZrzUOfQmmpYrZn2a4=
933937
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
934938
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
939+
935940
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
936941
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
937942
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
@@ -1086,6 +1091,7 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky
10861091
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
10871092
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
10881093
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
1094+
10891095
github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
10901096
github.com/migueleliasweb/go-github-mock v0.0.22 h1:iUvUKmYd7sFq/wrb9TrbEdvc30NaYxLZNtz7Uv2D+AQ=
10911097
github.com/migueleliasweb/go-github-mock v0.0.22/go.mod h1:UVvZ3S9IdTTRqThr1lgagVaua3Jl1bmY4E+C/Vybbn4=
@@ -1236,6 +1242,7 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS
12361242
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
12371243
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
12381244
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
1245+
12391246
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
12401247
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
12411248
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -2023,6 +2030,7 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
20232030
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
20242031
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
20252032
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
2033+
20262034
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
20272035
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
20282036
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

internal/pkg/configuration/config.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ type Condition struct {
2020
}
2121

2222
type PromotionPr struct {
23-
TargetPaths []string `yaml:"targetPaths"`
23+
TargetDescription string `yaml:"targetDescription"`
24+
TargetPaths []string `yaml:"targetPaths"`
2425
}
2526

2627
type PromotionPath struct {
@@ -35,14 +36,17 @@ type Config struct {
3536
PromotionPaths []PromotionPath `yaml:"promotionPaths"`
3637

3738
// Generic configuration
39+
3840
PromtionPrLables []string `yaml:"promtionPRlables"`
3941
DryRunMode bool `yaml:"dryRunMode"`
4042
AutoApprovePromotionPrs bool `yaml:"autoApprovePromotionPrs"`
4143
ToggleCommitStatus map[string]string `yaml:"toggleCommitStatus"`
4244
WebhookEndpointRegexs []WebhookEndpointRegex `yaml:"webhookEndpointRegexs"`
45+
WhProxtSkipTLSVerifyUpstream bool `yaml:"whProxtSkipTLSVerifyUpstream"`
4346
CommentArgocdDiffonPR bool `yaml:"commentArgocdDiffonPR"`
4447
AutoMergeNoDiffPRs bool `yaml:"autoMergeNoDiffPRs"`
4548
UseSHALabelForArgoDicovery bool `yaml:"useSHALabelForArgoDicovery"`
49+
4650
}
4751

4852
func ParseConfigFromYaml(y string) (*Config, error) {

internal/pkg/githubapi/github.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ func handleMergedPrEvent(ghPrClientDetails GhPrClientDetails, prApproverGithubCl
425425
}
426426

427427
components := strings.Join(promotion.Metadata.ComponentNames, ",")
428-
newPrTitle := fmt.Sprintf("🚀 Promotion: %s ➡️ %s", components, strings.Join(promotion.Metadata.TargetPaths, " "))
428+
newPrTitle := fmt.Sprintf("🚀 Promotion: %s ➡️ %s", components, promotion.Metadata.TargetDescription)
429429

430430
var originalPrAuthor string
431431
// If the triggering PR was opened manually and it doesn't include in-body metadata, use the PR author

internal/pkg/githubapi/promotion.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ type PromotionInstance struct {
2121
type PromotionInstanceMetaData struct {
2222
SourcePath string
2323
TargetPaths []string
24+
TargetDescription string
2425
PerComponentSkippedTargetPaths map[string][]string // ComponentName is the key,
2526
ComponentNames []string
2627
AutoMerge bool
@@ -109,6 +110,7 @@ func getComponentConfig(ghPrClientDetails GhPrClientDetails, componentPath strin
109110
return componentConfig, nil
110111
}
111112

113+
112114
// This function generates a list of "components" that where changed in the PR and are relevant for promotion)
113115
func generateListOfRelevantComponents(ghPrClientDetails GhPrClientDetails, config *cfg.Config) (relevantComponents map[relevantComponent]struct{}, err error) {
114116
relevantComponents = make(map[relevantComponent]struct{})
@@ -121,6 +123,7 @@ func generateListOfRelevantComponents(ghPrClientDetails GhPrClientDetails, confi
121123
prom.InstrumentGhCall(resp)
122124
if err != nil {
123125
ghPrClientDetails.PrLogger.Errorf("could not get file list from GH API: err=%s\nstatus code=%v", err, resp.Response.Status)
126+
124127
return nil, err
125128
}
126129
prFiles = append(prFiles, perPagePrFiles...)
@@ -208,9 +211,13 @@ func generatePlanBasedOnChangeddComponent(ghPrClientDetails GhPrClientDetails, c
208211
mapKey := configPromotionPath.SourcePath + ">" + strings.Join(ppr.TargetPaths, "|") // This key is used to aggregate the PR based on source and target combination
209212
if entry, ok := promotions[mapKey]; !ok {
210213
ghPrClientDetails.PrLogger.Debugf("Adding key %s", mapKey)
214+
if ppr.TargetDescription == "" {
215+
ppr.TargetDescription = strings.Join(ppr.TargetPaths, " ")
216+
}
211217
promotions[mapKey] = PromotionInstance{
212218
Metadata: PromotionInstanceMetaData{
213219
TargetPaths: ppr.TargetPaths,
220+
TargetDescription: ppr.TargetDescription,
214221
SourcePath: componentToPromote.SourcePath,
215222
ComponentNames: []string{componentToPromote.ComponentName},
216223
PerComponentSkippedTargetPaths: map[string][]string{},

0 commit comments

Comments
 (0)