Skip to content

Commit 44ba7f3

Browse files
authored
Merge pull request #7 from kontrolplane/patch
chore: change environment variable parsing and logging
2 parents deb253c + 6a47912 commit 44ba7f3

7 files changed

Lines changed: 130 additions & 57 deletions

File tree

.github/workflows/continuous-integration.yaml

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,7 @@ jobs:
1717
- name: install go
1818
uses: actions/setup-go@v4
1919
with:
20-
go-version: 1.21.3
20+
go-version: 1.23.1
2121

22-
- name: run linters
23-
uses: golangci/golangci-lint-action@v3
24-
with:
25-
version: v1.53
26-
27-
- name: checkout code
28-
uses: actions/checkout@v4
29-
3022
- name: pull request title validator
3123
uses: ./ # kontrolplane/pull-request-title-validator@latest
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: update-contributors
2+
3+
on:
4+
workflow_dispatch:
5+
schedule:
6+
- cron: '0 0 * * 0'
7+
8+
jobs:
9+
update-contributors:
10+
name: validate-pull-request-title
11+
runs-on: ubuntu-latest
12+
steps:
13+
- name: checkout
14+
uses: actions/checkout@v4
15+
16+
- name: update-contributors
17+
uses: kontrolplane/generate-contributors-list@v1.0.0
18+
with:
19+
owner: kontrolplane
20+
repository: pull-request-title-validator
21+
22+
- name: open-pull-request
23+
env:
24+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
25+
run: |
26+
git config user.name github-actions
27+
git config user.email github-actions@github.com
28+
git add README.md
29+
git commit -m "chore: update contributors section"
30+
git push -u origin update-contributors
31+
gh pr create \
32+
--title "chore: update contributors" \
33+
--body "Automatically update contributors section." \
34+
--base main \
35+
--head update-contributors

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM golang:1.21.3 AS build
1+
FROM golang:1.23.1 AS build
22
WORKDIR /action
33
COPY . .
44
RUN CGO_ENABLED=0 go build -o pull-request-title-validator

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,12 @@ jobs:
9494
with:
9595
scopes: "api,lang,parser,package/.+"
9696
```
97+
98+
## Contributors
99+
100+
[//]: kontrolplane/generate-contributors-list
101+
102+
<a href="https://github.com/levivannoort"><img src="https://avatars.githubusercontent.com/u/73097785?v=4" title="levivannoort" width="50" height="50"></a>
103+
<a href="https://github.com/paopa"><img src="https://avatars.githubusercontent.com/u/52045032?v=4" title="paopa" width="50" height="50"></a>
104+
105+
[//]: kontrolplane/generate-contributors-list

go.mod

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
module github.com/kontrolplane/pull-request-title-validator
22

3-
go 1.21.1
3+
go 1.23.1
4+
5+
require github.com/caarlos0/env v3.5.0+incompatible
6+
7+
require github.com/stretchr/testify v1.10.0 // indirect

go.sum

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
github.com/caarlos0/env v3.5.0+incompatible h1:Yy0UN8o9Wtr/jGHZDpCBLpNrzcFLLM2yixi/rBrKyJs=
2+
github.com/caarlos0/env v3.5.0+incompatible/go.mod h1:tdCsowwCzMLdkqRYDlHpZCp2UooDD3MspDBjZ2AD02Y=
3+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
4+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
6+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
7+
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
8+
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
9+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
10+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

main.go

Lines changed: 69 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,22 @@ import (
66
"os"
77
"regexp"
88
"strings"
9+
10+
"log/slog"
11+
12+
"github.com/caarlos0/env"
913
)
1014

1115
var desiredFormat string = "<type>(optional: <scope>): <message>"
1216
var defaultConventionTypes []string = []string{"fix", "feat", "chore", "docs", "build", "ci", "refactor", "perf", "test"}
1317

18+
type config struct {
19+
GithubEventName string `env:"GITHUB_EVENT_NAME"`
20+
GithubEventPath string `env:"GITHUB_EVENT_PATH"`
21+
Types string `env:"INPUT_TYPES"`
22+
Scope string `env:"INPUT_SCOPE"`
23+
}
24+
1425
type PullRequest struct {
1526
Title string `json:"title"`
1627
}
@@ -22,132 +33,144 @@ type Event struct {
2233
// The pull-request-title-validator function mankes sure that for each pull request created the
2334
// title of the pull request adheres to a desired structure, in this case convention commit style.
2435
func main() {
25-
githubEventName := os.Getenv("GITHUB_EVENT_NAME")
26-
githubEventPath := os.Getenv("GITHUB_EVENT_PATH")
27-
conventionTypes := parseTypes(os.Getenv("INPUT_TYPES"), defaultConventionTypes)
28-
scopes := parseScopes(os.Getenv("INPUT_SCOPES"))
2936

30-
if githubEventName != "pull_request" && githubEventName != "pull_request_target" {
31-
fmt.Printf("Error: the 'pull_request' trigger type should be used, received '%s'\n", githubEventName)
37+
var cfg config
38+
if err := env.Parse(&cfg); err != nil {
39+
fmt.Printf("unable to parse the environment variables: %v", err)
40+
os.Exit(1)
41+
}
42+
43+
logHandler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
44+
AddSource: false,
45+
Level: slog.LevelInfo,
46+
})
47+
logger := slog.New(logHandler)
48+
49+
logger.Info("starting pull-request-title-validator", slog.String("event", cfg.GithubEventName))
50+
51+
if cfg.GithubEventName != "pull_request" && cfg.GithubEventName != "pull_request_target" {
52+
logger.Error("invalid event type", slog.String("event", cfg.GithubEventName))
3253
os.Exit(1)
3354
}
3455

35-
title := fetchTitle(githubEventPath)
36-
titleType, titleScope, titleMessage := splitTitle(title)
56+
title := fetchTitle(logger, cfg.GithubEventPath)
57+
titleType, titleScope, titleMessage := splitTitle(logger, title)
3758

38-
if err := checkAgainstConventionTypes(titleType, conventionTypes); err != nil {
39-
fmt.Printf("The type passed '%s' is not present in the types allowed by the convention: %s\n", titleType, conventionTypes)
59+
parsedTypes := parseTypes(logger, cfg.Types, defaultConventionTypes)
60+
parsedScope := parseScopes(logger, cfg.Scope)
61+
62+
if err := checkAgainstConventionTypes(logger, titleType, parsedTypes); err != nil {
63+
logger.Error("error while checking the type against the allowed types",
64+
slog.String("event name", cfg.GithubEventName),
65+
slog.String("event path", cfg.GithubEventPath),
66+
slog.Any("convention types", parsedTypes),
67+
)
4068
os.Exit(1)
4169
}
4270

43-
if err := checkAgainstScopes(titleScope, scopes); err != nil && len(scopes) >= 1 {
44-
fmt.Println(err)
71+
if err := checkAgainstScopes(logger, titleScope, parsedScope); err != nil && len(parsedScope) >= 1 {
72+
logger.Error("error while checking the scope against the allowed scopes", slog.Any("error", err))
4573
os.Exit(1)
4674
}
4775

48-
fmt.Printf("commit title type used: %s\n", titleType)
49-
fmt.Printf("commit title scope used: %s\n", titleScope)
50-
fmt.Printf("commit title message used: %s\n\n", titleMessage)
51-
fmt.Printf("the commit message adheres to the configured standard")
76+
logger.Info("commit title validated successfully",
77+
slog.String("type", titleType),
78+
slog.String("scope", titleScope),
79+
slog.String("message", titleMessage),
80+
)
81+
logger.Info("the commit message adheres to the configured standard")
5282
}
5383

54-
func fetchTitle(githubEventPath string) string {
55-
84+
func fetchTitle(logger *slog.Logger, githubEventPath string) string {
5685
var event Event
5786
var eventData []byte
5887
var err error
5988

6089
if eventData, err = os.ReadFile(githubEventPath); err != nil {
61-
fmt.Printf("Problem reading the event json file: %v\n", err)
62-
os.Exit(1)
90+
logger.Error("Problem reading the event JSON file", slog.String("path", githubEventPath), slog.Any("error", err))
91+
os.Exit(1) // You might want to return an empty string or handle this error upstream instead.
6392
}
6493

6594
if err = json.Unmarshal(eventData, &event); err != nil {
66-
fmt.Printf("Failed to unmarshal JSON: %v", err)
95+
logger.Error("Failed to unmarshal JSON", slog.Any("error", err))
6796
os.Exit(1)
6897
}
6998

7099
return event.PullRequest.Title
71100
}
72101

73-
func splitTitle(title string) (titleType string, titleScope string, titleMessage string) {
74-
75-
// this part of the function extracts the type
102+
func splitTitle(logger *slog.Logger, title string) (titleType string, titleScope string, titleMessage string) {
76103
if index := strings.Index(title, "("); strings.Contains(title, "(") {
77104
titleType = title[:index]
78105
} else if index := strings.Index(title, ":"); strings.Contains(title, ":") {
79106
titleType = title[:index]
80107
} else {
81-
fmt.Println("No type was included in the pull request title.")
82-
fmt.Println(desiredFormat)
108+
logger.Error("No type was included in the pull request title.", slog.String("desired format", desiredFormat))
83109
os.Exit(1)
84110
}
85111

86-
// this part of the function extracts the optional scope
87112
if strings.Contains(title, "(") && strings.Contains(title, ")") {
88113
scope := regexp.MustCompile(`\(([^)]+)\)`)
89-
titleScope = scope.FindStringSubmatch(title)[1]
114+
if matches := scope.FindStringSubmatch(title); len(matches) > 1 {
115+
titleScope = matches[1]
116+
}
90117
}
91118

92-
// this part of the function extracts the message
93119
if strings.Contains(title, ":") {
94120
titleMessage = strings.SplitAfter(title, ":")[1]
95121
titleMessage = strings.TrimSpace(titleMessage)
96122
} else {
97-
fmt.Println("no message was included in the pull request title.")
98-
fmt.Println(desiredFormat)
123+
logger.Error("No message was included in the pull request title.", slog.String("desired format", desiredFormat))
99124
os.Exit(1)
100125
}
101126

102127
return
103128
}
104129

105-
func checkAgainstConventionTypes(titleType string, conventionTypes []string) error {
130+
func checkAgainstConventionTypes(logger *slog.Logger, titleType string, conventionTypes []string) error {
106131
for _, conventionType := range conventionTypes {
107132
if titleType == conventionType {
108133
return nil
109134
}
110135
}
111-
112-
return fmt.Errorf("the type passed '%s' is not present in the types allowed by the convention: %s", titleType, conventionTypes)
136+
logger.Error("Type not allowed by the convention", slog.String("type", titleType), slog.Any("allowedTypes", conventionTypes))
137+
return fmt.Errorf("type '%s' is not allowed", titleType)
113138
}
114139

115-
func checkAgainstScopes(titleScope string, scopes []string) error {
140+
func checkAgainstScopes(logger *slog.Logger, titleScope string, scopes []string) error {
116141
for _, scope := range scopes {
117142
if regexp.MustCompile("(?i)" + scope + "$").MatchString(titleScope) {
118143
return nil
119144
}
120145
}
121146

122-
return fmt.Errorf("the scope '%s' is not allowed. Please choose from the following patterns of scopes: %s", titleScope, scopes)
147+
return fmt.Errorf("scope '%s' is not allowed", titleScope)
123148
}
124149

125-
func parseTypes(input string, fallback []string) []string {
150+
func parseTypes(logger *slog.Logger, input string, fallback []string) []string {
126151
if input == "" {
127-
fmt.Println("no custom list of commit types was passed using fallback.")
152+
logger.Warn("No custom list of commit types passed, using fallback.")
128153
return fallback
129154
}
155+
130156
types := strings.Split(input, ",")
131157
for i := range types {
132158
types[i] = strings.TrimSpace(types[i])
133159
}
134-
if len(types) == 0 {
135-
return fallback
136-
}
160+
137161
return types
138162
}
139163

140-
func parseScopes(input string) []string {
164+
func parseScopes(logger *slog.Logger, input string) []string {
141165
if input == "" {
142-
fmt.Println("no custom list of commit scopes was passed using fallback.")
166+
logger.Warn("No custom list of commit scopes passed, using fallback.")
143167
return []string{}
144168
}
169+
145170
scopes := strings.Split(input, ",")
146171
for i := range scopes {
147172
scopes[i] = strings.TrimSpace(scopes[i])
148173
}
149-
if len(scopes) == 0 {
150-
return []string{}
151-
}
174+
152175
return scopes
153176
}

0 commit comments

Comments
 (0)