forked from rhysd/actionlint
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrule_workflow_call.go
80 lines (66 loc) · 2.05 KB
/
rule_workflow_call.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
package actionlint
import (
"strings"
)
// RuleWorkflowCall is a rule checker to check workflow call at jobs.<job_id>.
type RuleWorkflowCall struct {
RuleBase
workflowCallEventPos *Pos
}
// NewRuleWorkflowCall creates a new RuleWorkflowCall instance.
func NewRuleWorkflowCall() *RuleWorkflowCall {
return &RuleWorkflowCall{
RuleBase: RuleBase{name: "workflow-call"},
workflowCallEventPos: nil,
}
}
// VisitWorkflowPre is callback when visiting Workflow node before visiting its children.
func (rule *RuleWorkflowCall) VisitWorkflowPre(n *Workflow) error {
for _, e := range n.On {
if e, ok := e.(*WorkflowCallEvent); ok {
rule.workflowCallEventPos = e.Pos
break
}
}
return nil
}
// VisitJobPre is callback when visiting Job node before visiting its children.
func (rule *RuleWorkflowCall) VisitJobPre(n *Job) error {
if n.WorkflowCall == nil {
return nil
}
u := n.WorkflowCall.Uses
if u == nil || u.Value == "" {
return nil
}
if rule.workflowCallEventPos != nil {
rule.errorf(u.Pos, "reusable workflow cannot be nested. but this workflow hooks \"workflow_call\" event at %s", rule.workflowCallEventPos)
}
if !strings.Contains(u.Value, "${{") && !checkWorkflowCallUsesFormat(u.Value) {
rule.errorf(u.Pos, "reusable workflow call %q at \"uses\" is not following the format \"owner/repo/path/to/workflow.yml@ref\". see https://docs.github.com/en/actions/learn-github-actions/reusing-workflows for more details", u.Value)
}
return nil
}
// Parse {owner}/{repo}/{path to workflow.yml}@{ref}
// https://docs.github.com/en/actions/learn-github-actions/reusing-workflows#calling-a-reusable-workflow
func checkWorkflowCallUsesFormat(u string) bool {
if strings.HasPrefix(u, ".") {
return false // Local path is not supported.
}
idx := strings.IndexRune(u, '/')
if idx <= 0 {
return false
}
u = u[idx+1:] // Eat owner
idx = strings.IndexRune(u, '/')
if idx <= 0 {
return false
}
u = u[idx+1:] // Eat repo
idx = strings.IndexRune(u, '@')
if idx <= 0 {
return false
}
u = u[idx+1:] // Eat workflow path
return len(u) > 0
}