Switch to interface{} instead of map[string]... (#700)

* fix: change `env` to be an interface

allows to use GitHub functions like `fromJson()`

* fix: change matrix to an interface instead of map

This allows to use GitHub functions like `fromJson()` to create dynamic
matrixes

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
This commit is contained in:
Ryan (hackercat) 2021-06-06 14:53:18 +00:00 committed by GitHub
parent fa93f4d5e7
commit 33ccfa6f3b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 76 additions and 20 deletions

View file

@ -58,7 +58,7 @@ type Job struct {
Name string `yaml:"name"` Name string `yaml:"name"`
RawNeeds yaml.Node `yaml:"needs"` RawNeeds yaml.Node `yaml:"needs"`
RawRunsOn yaml.Node `yaml:"runs-on"` RawRunsOn yaml.Node `yaml:"runs-on"`
Env map[string]string `yaml:"env"` Env interface{} `yaml:"env"`
If yaml.Node `yaml:"if"` If yaml.Node `yaml:"if"`
Steps []*Step `yaml:"steps"` Steps []*Step `yaml:"steps"`
TimeoutMinutes int64 `yaml:"timeout-minutes"` TimeoutMinutes int64 `yaml:"timeout-minutes"`
@ -72,7 +72,7 @@ type Job struct {
type Strategy struct { type Strategy struct {
FailFast bool `yaml:"fail-fast"` FailFast bool `yaml:"fail-fast"`
MaxParallel int `yaml:"max-parallel"` MaxParallel int `yaml:"max-parallel"`
Matrix map[string][]interface{} `yaml:"matrix"` Matrix interface{} `yaml:"matrix"`
} }
// Default settings that will apply to all steps in the job or workflow // Default settings that will apply to all steps in the job or workflow
@ -148,23 +148,75 @@ func (j *Job) RunsOn() []string {
return nil return nil
} }
func environment(e interface{}) map[string]string {
env := make(map[string]string)
switch t := e.(type) {
case map[string]interface{}:
for k, v := range t {
switch t := v.(type) {
case string:
env[k] = t
case interface{}:
env[k] = ""
}
}
case map[string]string:
for k, v := range e.(map[string]string) {
env[k] = v
}
}
return env
}
func (j *Job) Environment() map[string]string {
return environment(j.Env)
}
func (j *Job) Matrix() map[string][]interface{} {
a := reflect.ValueOf(j.Strategy.Matrix)
if a.Type().Kind() == reflect.Map {
output := make(map[string][]interface{})
for _, e := range a.MapKeys() {
v := a.MapIndex(e)
switch t := v.Interface().(type) {
case []interface{}:
output[e.String()] = t
case interface{}:
var in []interface{}
in = append(in, t)
output[e.String()] = in
}
}
return output
}
return nil
}
// GetMatrixes returns the matrix cross product // GetMatrixes returns the matrix cross product
func (j *Job) GetMatrixes() []map[string]interface{} { func (j *Job) GetMatrixes() []map[string]interface{} {
matrixes := make([]map[string]interface{}, 0) matrixes := make([]map[string]interface{}, 0)
if j.Strategy != nil { if j.Strategy != nil {
m := j.Matrix()
includes := make([]map[string]interface{}, 0) includes := make([]map[string]interface{}, 0)
for _, v := range j.Strategy.Matrix["include"] { for _, v := range m["include"] {
switch t := v.(type) {
case []interface{}:
for _, i := range t {
includes = append(includes, i.(map[string]interface{}))
}
case interface{}:
includes = append(includes, v.(map[string]interface{})) includes = append(includes, v.(map[string]interface{}))
} }
delete(j.Strategy.Matrix, "include") }
delete(m, "include")
excludes := make([]map[string]interface{}, 0) excludes := make([]map[string]interface{}, 0)
for _, v := range j.Strategy.Matrix["exclude"] { for _, v := range m["exclude"] {
excludes = append(excludes, v.(map[string]interface{})) excludes = append(excludes, v.(map[string]interface{}))
} }
delete(j.Strategy.Matrix, "exclude") delete(m, "exclude")
matrixProduct := common.CartesianProduct(j.Strategy.Matrix) matrixProduct := common.CartesianProduct(m)
MATRIX: MATRIX:
for _, matrix := range matrixProduct { for _, matrix := range matrixProduct {
@ -217,7 +269,7 @@ type Step struct {
Run string `yaml:"run"` Run string `yaml:"run"`
WorkingDirectory string `yaml:"working-directory"` WorkingDirectory string `yaml:"working-directory"`
Shell string `yaml:"shell"` Shell string `yaml:"shell"`
Env map[string]string `yaml:"env"` Env interface{} `yaml:"env"`
With map[string]string `yaml:"with"` With map[string]string `yaml:"with"`
ContinueOnError bool `yaml:"continue-on-error"` ContinueOnError bool `yaml:"continue-on-error"`
TimeoutMinutes int64 `yaml:"timeout-minutes"` TimeoutMinutes int64 `yaml:"timeout-minutes"`
@ -235,18 +287,20 @@ func (s *Step) String() string {
return s.ID return s.ID
} }
func (s *Step) Environment() map[string]string {
return environment(s.Env)
}
// GetEnv gets the env for a step // GetEnv gets the env for a step
func (s *Step) GetEnv() map[string]string { func (s *Step) GetEnv() map[string]string {
rtnEnv := make(map[string]string) env := s.Environment()
for k, v := range s.Env {
rtnEnv[k] = v
}
for k, v := range s.With { for k, v := range s.With {
envKey := regexp.MustCompile("[^A-Z0-9-]").ReplaceAllString(strings.ToUpper(k), "_") envKey := regexp.MustCompile("[^A-Z0-9-]").ReplaceAllString(strings.ToUpper(k), "_")
envKey = fmt.Sprintf("INPUT_%s", strings.ToUpper(envKey)) envKey = fmt.Sprintf("INPUT_%s", strings.ToUpper(envKey))
rtnEnv[envKey] = v env[envKey] = v
} }
return rtnEnv return env
} }
// ShellCommand returns the command for the shell // ShellCommand returns the command for the shell

View file

@ -55,7 +55,7 @@ type stepResult struct {
// GetEnv returns the env for the context // GetEnv returns the env for the context
func (rc *RunContext) GetEnv() map[string]string { func (rc *RunContext) GetEnv() map[string]string {
if rc.Env == nil { if rc.Env == nil {
rc.Env = mergeMaps(rc.Config.Env, rc.Run.Workflow.Env, rc.Run.Job().Env) rc.Env = mergeMaps(rc.Config.Env, rc.Run.Workflow.Env, rc.Run.Job().Environment())
} }
rc.Env["ACT"] = "true" rc.Env["ACT"] = "true"
return rc.Env return rc.Env

View file

@ -574,13 +574,15 @@ func (sc *StepContext) execAsComposite(ctx context.Context, step *model.Step, _
stepClone.Env = make(map[string]string) stepClone.Env = make(map[string]string)
} }
actionPath := filepath.Join(containerActionDir, actionName) actionPath := filepath.Join(containerActionDir, actionName)
stepClone.Env["GITHUB_ACTION_PATH"] = actionPath
env := stepClone.Environment()
env["GITHUB_ACTION_PATH"] = actionPath
stepClone.Run = strings.ReplaceAll(stepClone.Run, "${{ github.action_path }}", actionPath) stepClone.Run = strings.ReplaceAll(stepClone.Run, "${{ github.action_path }}", actionPath)
stepContext := StepContext{ stepContext := StepContext{
RunContext: rcClone, RunContext: rcClone,
Step: &stepClone, Step: &stepClone,
Env: mergeMaps(sc.Env, stepClone.Env), Env: mergeMaps(sc.Env, env),
} }
// Interpolate the outer inputs into the composite step with items // Interpolate the outer inputs into the composite step with items