Skip to content

Commit e99d7c3

Browse files
authored
Better linting and error handling (#81)
* fix: allow CI pipeline to fail if the Change Request changes scm-engine configuration file otherwise, continue to fail open * fix: MergeRequestIDUint() possible overflow * feat: more schema validation and linting * pre-rework * feat: first draf of 'gitlab lint' command working * feat: more linting and code gen for JSON schema * feat: lint the configuration file
1 parent dd581f2 commit e99d7c3

20 files changed

+532
-204
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@
2121
/schema/ignore
2222
/scm-engine
2323
/scm-engine.exe
24-
/scm-engine.schema.json
24+
scm-engine.schema.json

Taskfile.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ tasks:
4343
- go run . gitlab -h > docs/gitlab/_partials/cmd-gitlab.md
4444
- go run . gitlab evaluate -h > docs/gitlab/_partials/cmd-gitlab-evaluate.md
4545
- go run . gitlab server -h > docs/gitlab/_partials/cmd-gitlab-server.md
46-
- go run . jsonschema > docs/scm-engine.schema.json
46+
- cp pkg/generated/resources/scm-engine.schema.json docs/scm-engine.schema.json
4747

4848
docs:server:
4949
desc: Run Docs dev server with live preview

cmd/gitlab.go

+13
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,19 @@ var GitLab = &cli.Command{
3636
},
3737
},
3838
Subcommands: []*cli.Command{
39+
{
40+
Name: "lint",
41+
Usage: "lint a configuration file",
42+
Args: false,
43+
Action: Lint,
44+
Flags: []cli.Flag{
45+
&cli.StringFlag{
46+
Name: "schema",
47+
Usage: "Where to find the JSON Schema file. Can load the file from either the embedded version (default), http://, https://, or a file:// URI",
48+
Value: "embed://",
49+
},
50+
},
51+
},
3952
{
4053
Name: "evaluate",
4154
Usage: "Evaluate a Merge Request",

cmd/gitlab_lint.go

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
"os"
7+
"strings"
8+
"time"
9+
10+
"github.com/jippi/scm-engine/pkg/config"
11+
"github.com/jippi/scm-engine/pkg/generated/resources"
12+
"github.com/jippi/scm-engine/pkg/scm/gitlab"
13+
"github.com/jippi/scm-engine/pkg/state"
14+
"github.com/santhosh-tekuri/jsonschema/v6"
15+
"github.com/urfave/cli/v2"
16+
slogctx "github.com/veqryn/slog-context"
17+
"gopkg.in/yaml.v3"
18+
)
19+
20+
func Lint(cCtx *cli.Context) error {
21+
ctx := cCtx.Context
22+
ctx = state.WithConfigFilePath(ctx, cCtx.String(FlagConfigFile))
23+
24+
// Read raw YAML file
25+
raw, err := os.ReadFile(state.ConfigFilePath(ctx))
26+
if err != nil {
27+
return err
28+
}
29+
30+
// Parse the YAML file into lose Go shape
31+
var yamlOutput any
32+
if err := yaml.Unmarshal(raw, &yamlOutput); err != nil {
33+
return err
34+
}
35+
36+
// Setup file loaders for reading the JSON schema file
37+
loader := jsonschema.SchemeURLLoader{
38+
"file": jsonschema.FileLoader{},
39+
"http": newHTTPURLLoader(),
40+
"https": newHTTPURLLoader(),
41+
"embed": &EmbedLoader{},
42+
}
43+
44+
// Create json schema compiler
45+
compiler := jsonschema.NewCompiler()
46+
compiler.UseLoader(loader)
47+
48+
// Compile the schema into validator format
49+
sch, err := compiler.Compile(cCtx.String("schema"))
50+
if err != nil {
51+
return err
52+
}
53+
54+
// Validate the json output
55+
if err := sch.Validate(yamlOutput); err != nil {
56+
return err
57+
}
58+
59+
// Load the configuration file via our Go struct
60+
cfg, err := config.LoadFile(state.ConfigFilePath(ctx))
61+
if err != nil {
62+
return err
63+
}
64+
65+
if len(cfg.Includes) != 0 {
66+
slogctx.Warn(ctx, "Configuration file contains 'include' settings, those are currently unsupported by 'lint' command and will be ignored")
67+
}
68+
69+
// To scm-engine specific linting last
70+
return cfg.Lint(ctx, &gitlab.Context{})
71+
}
72+
73+
type EmbedLoader struct{}
74+
75+
func (l *EmbedLoader) Load(url string) (any, error) {
76+
return jsonschema.UnmarshalJSON(strings.NewReader(resources.JSONSchema))
77+
}
78+
79+
type HTTPURLLoader http.Client
80+
81+
func (l *HTTPURLLoader) Load(url string) (any, error) {
82+
client := (*http.Client)(l)
83+
84+
resp, err := client.Get(url) //nolint
85+
if err != nil {
86+
return nil, err
87+
}
88+
89+
if resp.StatusCode != http.StatusOK {
90+
resp.Body.Close()
91+
92+
return nil, fmt.Errorf("%s returned status code %d", url, resp.StatusCode)
93+
}
94+
95+
defer resp.Body.Close()
96+
97+
return jsonschema.UnmarshalJSON(resp.Body)
98+
}
99+
100+
func newHTTPURLLoader() *HTTPURLLoader {
101+
httpLoader := HTTPURLLoader(http.Client{
102+
Timeout: 15 * time.Second,
103+
})
104+
105+
return &httpLoader
106+
}

cmd/shared.go

+5
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,11 @@ func ProcessMR(ctx context.Context, client scm.Client, cfg *config.Config, event
131131
ctx = state.WithDryRun(ctx, *cfg.DryRun)
132132
}
133133

134+
// Lint the configuration file to catch any misconfigurations
135+
if err := cfg.Lint(ctx, evalContext); err != nil {
136+
return fmt.Errorf("Configuration failed validation: %w", err)
137+
}
138+
134139
// Write the config to context so we can pull it out later
135140
ctx = config.WithConfig(ctx, cfg)
136141

generate.go

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package main
2+
3+
//go:generate go run ./pkg/generated/main.go

go.mod

+7-1
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,22 @@ require (
1111
github.com/golang-cz/devslog v0.0.9
1212
github.com/google/go-github/v64 v64.0.0
1313
github.com/guregu/null/v5 v5.0.0
14+
github.com/hashicorp/go-multierror v1.1.1
1415
github.com/hasura/go-graphql-client v0.13.0
1516
github.com/iancoleman/strcase v0.3.0
1617
github.com/invopop/jsonschema v0.12.0
1718
github.com/lmittmann/tint v1.0.5
1819
github.com/muesli/termenv v0.15.2
1920
github.com/samber/slog-multi v1.2.1
21+
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1
2022
github.com/stretchr/testify v1.9.0
2123
github.com/teacat/noire v1.1.0
2224
github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569
2325
github.com/urfave/cli/v2 v2.27.4
2426
github.com/vektah/gqlparser/v2 v2.5.16
2527
github.com/veqryn/slog-context v0.7.0
2628
github.com/veqryn/slog-dedup v0.5.0
29+
github.com/wk8/go-ordered-map/v2 v2.1.8
2730
github.com/xanzy/go-gitlab v0.109.0
2831
github.com/xhit/go-str2duration/v2 v2.1.0
2932
golang.org/x/oauth2 v0.23.0
@@ -37,11 +40,14 @@ require (
3740
github.com/buger/jsonparser v1.1.1 // indirect
3841
github.com/charmbracelet/x/ansi v0.1.4 // indirect
3942
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
43+
github.com/fatih/color v1.17.0 // indirect
4044
github.com/go-logr/logr v1.4.1 // indirect
4145
github.com/google/go-querystring v1.1.0 // indirect
4246
github.com/google/uuid v1.6.0 // indirect
47+
github.com/hashicorp/errwrap v1.0.0 // indirect
4348
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
4449
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
50+
github.com/kr/pretty v0.1.0 // indirect
4551
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
4652
github.com/mailru/easyjson v0.7.7 // indirect
4753
github.com/mattn/go-isatty v0.0.20 // indirect
@@ -51,7 +57,6 @@ require (
5157
github.com/russross/blackfriday/v2 v2.1.0 // indirect
5258
github.com/samber/lo v1.38.1 // indirect
5359
github.com/sosodev/duration v1.3.1 // indirect
54-
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
5560
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
5661
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect
5762
golang.org/x/mod v0.20.0 // indirect
@@ -60,6 +65,7 @@ require (
6065
golang.org/x/text v0.17.0 // indirect
6166
golang.org/x/time v0.3.0 // indirect
6267
golang.org/x/tools v0.24.0 // indirect
68+
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
6369
modernc.org/b/v2 v2.1.0 // indirect
6470
nhooyr.io/websocket v1.8.11 // indirect
6571
)

go.sum

+17-3
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
2323
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2424
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g=
2525
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
26+
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
27+
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
2628
github.com/expr-lang/expr v1.16.9 h1:WUAzmR0JNI9JCiF0/ewwHB1gmcGw5wW7nWt8gc6PpCI=
2729
github.com/expr-lang/expr v1.16.9/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4=
28-
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
29-
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
30+
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
31+
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
3032
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
3133
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
3234
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
@@ -46,10 +48,14 @@ github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWm
4648
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
4749
github.com/guregu/null/v5 v5.0.0 h1:PRxjqyOekS11W+w/7Vfz6jgJE/BCwELWtgvOJzddimw=
4850
github.com/guregu/null/v5 v5.0.0/go.mod h1:SjupzNy+sCPtwQTKWhUCqjhVCO69hpsl2QsZrWHjlwU=
51+
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
52+
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
4953
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
5054
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
5155
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
5256
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
57+
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
58+
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
5359
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
5460
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
5561
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
@@ -61,6 +67,11 @@ github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47
6167
github.com/invopop/jsonschema v0.12.0 h1:6ovsNSuvn9wEQVOyc72aycBMVQFKz7cPdMJn10CvzRI=
6268
github.com/invopop/jsonschema v0.12.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
6369
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
70+
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
71+
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
72+
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
73+
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
74+
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
6475
github.com/lmittmann/tint v1.0.5 h1:NQclAutOfYsqs2F1Lenue6OoWCajs5wJcP3DfWVpePw=
6576
github.com/lmittmann/tint v1.0.5/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
6677
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
@@ -90,6 +101,8 @@ github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
90101
github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
91102
github.com/samber/slog-multi v1.2.1 h1:MRVc6JxvGiZ+ubyANneZkMREAFAykoW0CACJZagT7so=
92103
github.com/samber/slog-multi v1.2.1/go.mod h1:uLAvHpGqbYgX4FSL0p1ZwoLuveIAJvBECtE07XmYvFo=
104+
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 h1:PKK9DyHxif4LZo+uQSgXNqs0jj5+xZwwfKHgph2lxBw=
105+
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
93106
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
94107
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
95108
github.com/sosodev/duration v1.3.1 h1:qtHBDMQ6lvMQsL15g4aopM4HEfOaYuhWBw3NPTtlqq4=
@@ -136,8 +149,9 @@ golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
136149
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
137150
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
138151
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
139-
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
140152
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
153+
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
154+
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
141155
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
142156
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
143157
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

main.go

+3-22
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1+
//go:build !generate
2+
// +build !generate
3+
14
package main
25

36
import (
4-
"encoding/json"
57
"fmt"
68
"io"
79
"log"
810
"os"
911

1012
"github.com/davecgh/go-spew/spew"
11-
"github.com/invopop/jsonschema"
1213
"github.com/jippi/scm-engine/cmd"
13-
"github.com/jippi/scm-engine/pkg/config"
1414
"github.com/jippi/scm-engine/pkg/state"
1515
"github.com/jippi/scm-engine/pkg/tui"
1616
"github.com/urfave/cli/v2"
@@ -72,26 +72,7 @@ func main() {
7272
Commands: []*cli.Command{
7373
cmd.GitLab,
7474
cmd.GitHub,
75-
{
76-
Name: "jsonschema",
77-
Action: func(ctx *cli.Context) error {
78-
r := new(jsonschema.Reflector)
79-
if err := r.AddGoComments("github.com/jippi/scm-engine", "./"); err != nil {
80-
return err
81-
}
82-
83-
schema := r.Reflect(&config.Config{})
84-
85-
data, err := json.MarshalIndent(schema, "", " ")
86-
if err != nil {
87-
panic(err.Error())
88-
}
8975

90-
fmt.Println(string(data))
91-
92-
return os.WriteFile("scm-engine.schema.json", data, 0o600)
93-
},
94-
},
9576
// DEPRECATED COMMANDS
9677
{
9778
Name: "evaluate",

pkg/config/action.go

+28-5
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,32 @@ import (
1212
slogctx "github.com/veqryn/slog-context"
1313
)
1414

15-
type Actions []Action
15+
type (
16+
Actions []Action
17+
18+
Action struct {
19+
// The name of the action, this is purely for debugging and your convenience.
20+
//
21+
// See: https://jippi.github.io/scm-engine/configuration/#actions.name
22+
Name string `json:"name" yaml:"name"`
23+
24+
// (Optional) Only one action per group (in order) will be executed per evaluation cycle.
25+
// Use this to 'stop' other actions from running with the same group name
26+
Group string `json:"group,omitempty" yaml:"group"`
27+
28+
// A key controlling if the action should executed or not.
29+
//
30+
// This script is in Expr-lang: https://expr-lang.org/docs/language-definition
31+
//
32+
// See: https://jippi.github.io/scm-engine/configuration/#actions.if
33+
If string `json:"if" yaml:"if"`
34+
35+
// The list of operations to take if the action.if returned true.
36+
//
37+
// See: https://jippi.github.io/scm-engine/configuration/#actions.if.then
38+
Then []ActionStep `json:"then" yaml:"then"`
39+
}
40+
)
1641

1742
func (actions Actions) Evaluate(ctx context.Context, evalContext scm.EvalContext) ([]Action, error) {
1843
results := []Action{}
@@ -42,10 +67,8 @@ func (actions Actions) Evaluate(ctx context.Context, evalContext scm.EvalContext
4267
return results, nil
4368
}
4469

45-
type Action scm.EvaluationActionResult
46-
4770
func (p *Action) Evaluate(ctx context.Context, evalContext scm.EvalContext) (bool, error) {
48-
program, err := p.initialize(evalContext)
71+
program, err := p.Setup(evalContext)
4972
if err != nil {
5073
return false, err
5174
}
@@ -54,7 +77,7 @@ func (p *Action) Evaluate(ctx context.Context, evalContext scm.EvalContext) (boo
5477
return runAndCheckBool(ctx, program, evalContext)
5578
}
5679

57-
func (p *Action) initialize(evalContext scm.EvalContext) (*vm.Program, error) {
80+
func (p *Action) Setup(evalContext scm.EvalContext) (*vm.Program, error) {
5881
opts := []expr.Option{}
5982
opts = append(opts, expr.AsBool())
6083
opts = append(opts, expr.Env(evalContext))

0 commit comments

Comments
 (0)