pin to v1.0.0 of github action parser
This commit is contained in:
6
vendor/github.com/actions/workflow-parser/model/configuration.go
generated
vendored
6
vendor/github.com/actions/workflow-parser/model/configuration.go
generated
vendored
@@ -1,5 +1,9 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Configuration is a parsed main.workflow file
|
||||
type Configuration struct {
|
||||
Actions []*Action
|
||||
@@ -52,7 +56,7 @@ func (c *Configuration) GetWorkflow(id string) *Workflow {
|
||||
func (c *Configuration) GetWorkflows(eventType string) []*Workflow {
|
||||
var ret []*Workflow
|
||||
for _, workflow := range c.Workflows {
|
||||
if IsMatchingEventType(workflow.On, eventType) {
|
||||
if strings.EqualFold(workflow.On, eventType) {
|
||||
ret = append(ret, workflow)
|
||||
}
|
||||
}
|
||||
|
70
vendor/github.com/actions/workflow-parser/parser/errors.go
generated
vendored
70
vendor/github.com/actions/workflow-parser/parser/errors.go
generated
vendored
@@ -10,29 +10,44 @@ import (
|
||||
"github.com/actions/workflow-parser/model"
|
||||
)
|
||||
|
||||
type ParserError struct {
|
||||
type Error struct {
|
||||
message string
|
||||
Errors ErrorList
|
||||
Errors []*ParseError
|
||||
Actions []*model.Action
|
||||
Workflows []*model.Workflow
|
||||
}
|
||||
|
||||
func (p *ParserError) Error() string {
|
||||
func (e *Error) Error() string {
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
buffer.WriteString(p.message)
|
||||
for _, e := range p.Errors {
|
||||
buffer.WriteString(e.message)
|
||||
for _, pe := range e.Errors {
|
||||
buffer.WriteString("\n ")
|
||||
buffer.WriteString(e.Error())
|
||||
buffer.WriteString(pe.Error())
|
||||
}
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
// Error represents an error identified by the parser, either syntactic
|
||||
// FirstError searches a Configuration for the first error at or above a
|
||||
// given severity level. Checking the return value against nil is a good
|
||||
// way to see if the file has any errors at or above the given severity.
|
||||
// A caller intending to execute the file might check for
|
||||
// `errors.FirstError(parser.WARNING)`, while a caller intending to
|
||||
// display the file might check for `errors.FirstError(parser.FATAL)`.
|
||||
func (e *Error) FirstError(severity Severity) error {
|
||||
for _, pe := range e.Errors {
|
||||
if pe.Severity >= severity {
|
||||
return pe
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParseError represents an error identified by the parser, either syntactic
|
||||
// (HCL) or semantic (.workflow) in nature. There are fields for location
|
||||
// (File, Line, Column), severity, and base error string. The `Error()`
|
||||
// function on this type concatenates whatever bits of the location are
|
||||
// available with the message. The severity is only used for filtering.
|
||||
type Error struct {
|
||||
type ParseError struct {
|
||||
message string
|
||||
Pos ErrorPos
|
||||
Severity Severity
|
||||
@@ -48,8 +63,8 @@ type ErrorPos struct {
|
||||
|
||||
// newFatal creates a new error at the FATAL level, indicating that the
|
||||
// file is so broken it should not be displayed.
|
||||
func newFatal(pos ErrorPos, format string, a ...interface{}) *Error {
|
||||
return &Error{
|
||||
func newFatal(pos ErrorPos, format string, a ...interface{}) *ParseError {
|
||||
return &ParseError{
|
||||
message: fmt.Sprintf(format, a...),
|
||||
Pos: pos,
|
||||
Severity: FATAL,
|
||||
@@ -58,8 +73,8 @@ func newFatal(pos ErrorPos, format string, a ...interface{}) *Error {
|
||||
|
||||
// newError creates a new error at the ERROR level, indicating that the
|
||||
// file can be displayed but cannot be run.
|
||||
func newError(pos ErrorPos, format string, a ...interface{}) *Error {
|
||||
return &Error{
|
||||
func newError(pos ErrorPos, format string, a ...interface{}) *ParseError {
|
||||
return &ParseError{
|
||||
message: fmt.Sprintf(format, a...),
|
||||
Pos: pos,
|
||||
Severity: ERROR,
|
||||
@@ -68,15 +83,15 @@ func newError(pos ErrorPos, format string, a ...interface{}) *Error {
|
||||
|
||||
// newWarning creates a new error at the WARNING level, indicating that
|
||||
// the file might be runnable but might not execute as intended.
|
||||
func newWarning(pos ErrorPos, format string, a ...interface{}) *Error {
|
||||
return &Error{
|
||||
func newWarning(pos ErrorPos, format string, a ...interface{}) *ParseError {
|
||||
return &ParseError{
|
||||
message: fmt.Sprintf(format, a...),
|
||||
Pos: pos,
|
||||
Severity: WARNING,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Error) Error() string {
|
||||
func (e *ParseError) Error() string {
|
||||
var sb strings.Builder
|
||||
if e.Pos.Line != 0 {
|
||||
sb.WriteString("Line ") // nolint: errcheck
|
||||
@@ -107,30 +122,15 @@ const (
|
||||
// workflow file. See the comments for WARNING, ERROR, and FATAL, above.
|
||||
type Severity int
|
||||
|
||||
// FirstError searches a Configuration for the first error at or above a
|
||||
// given severity level. Checking the return value against nil is a good
|
||||
// way to see if the file has any errors at or above the given severity.
|
||||
// A caller intending to execute the file might check for
|
||||
// `errors.FirstError(parser.WARNING)`, while a caller intending to
|
||||
// display the file might check for `errors.FirstError(parser.FATAL)`.
|
||||
func (errors ErrorList) FirstError(severity Severity) error {
|
||||
for _, e := range errors {
|
||||
if e.Severity >= severity {
|
||||
return e
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
type errorList []*ParseError
|
||||
|
||||
type ErrorList []*Error
|
||||
|
||||
func (a ErrorList) Len() int { return len(a) }
|
||||
func (a ErrorList) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a ErrorList) Less(i, j int) bool { return a[i].Pos.Line < a[j].Pos.Line }
|
||||
func (a errorList) Len() int { return len(a) }
|
||||
func (a errorList) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a errorList) Less(i, j int) bool { return a[i].Pos.Line < a[j].Pos.Line }
|
||||
|
||||
// sortErrors sorts the errors reported by the parser. Do this after
|
||||
// parsing is complete. The sort is stable, so order is preserved within
|
||||
// a single line: left to right, syntax errors before validation errors.
|
||||
func (errors ErrorList) sort() {
|
||||
func (errors errorList) sort() {
|
||||
sort.Stable(errors)
|
||||
}
|
||||
|
@@ -1,20 +1,15 @@
|
||||
package model
|
||||
package parser
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// IsAllowedEventType returns true if the event type is supported.
|
||||
func IsAllowedEventType(eventType string) bool {
|
||||
// isAllowedEventType returns true if the event type is supported.
|
||||
func isAllowedEventType(eventType string) bool {
|
||||
_, ok := eventTypeWhitelist[strings.ToLower(eventType)]
|
||||
return ok
|
||||
}
|
||||
|
||||
// IsMatchingEventType checks to see if the "flowOn" string from a flow's on attribute matches the incoming webhook of type eventType.
|
||||
func IsMatchingEventType(flowOn, eventType string) bool {
|
||||
return strings.EqualFold(flowOn, eventType)
|
||||
}
|
||||
|
||||
// https://developer.github.com/actions/creating-workflows/workflow-configuration-options/#events-supported-in-workflow-files
|
||||
var eventTypeWhitelist = map[string]struct{}{
|
||||
"check_run": {},
|
||||
@@ -45,11 +40,3 @@ var eventTypeWhitelist = map[string]struct{}{
|
||||
"status": {},
|
||||
"watch": {},
|
||||
}
|
||||
|
||||
func AddAllowedEventType(s string) {
|
||||
eventTypeWhitelist[s] = struct{}{}
|
||||
}
|
||||
|
||||
func RemoveAllowedEventType(s string) {
|
||||
delete(eventTypeWhitelist, s)
|
||||
}
|
6
vendor/github.com/actions/workflow-parser/parser/opts.go
generated
vendored
6
vendor/github.com/actions/workflow-parser/parser/opts.go
generated
vendored
@@ -1,15 +1,15 @@
|
||||
package parser
|
||||
|
||||
type OptionFunc func(*parseState)
|
||||
type OptionFunc func(*Parser)
|
||||
|
||||
func WithSuppressWarnings() OptionFunc {
|
||||
return func(ps *parseState) {
|
||||
return func(ps *Parser) {
|
||||
ps.suppressSeverity = WARNING
|
||||
}
|
||||
}
|
||||
|
||||
func WithSuppressErrors() OptionFunc {
|
||||
return func(ps *parseState) {
|
||||
return func(ps *Parser) {
|
||||
ps.suppressSeverity = ERROR
|
||||
}
|
||||
}
|
||||
|
350
vendor/github.com/actions/workflow-parser/parser/parser.go
generated
vendored
350
vendor/github.com/actions/workflow-parser/parser/parser.go
generated
vendored
@@ -19,11 +19,11 @@ const minVersion = 0
|
||||
const maxVersion = 0
|
||||
const maxSecrets = 100
|
||||
|
||||
type parseState struct {
|
||||
Version int
|
||||
Actions []*model.Action
|
||||
Workflows []*model.Workflow
|
||||
Errors ErrorList
|
||||
type Parser struct {
|
||||
version int
|
||||
actions []*model.Action
|
||||
workflows []*model.Workflow
|
||||
errors errorList
|
||||
|
||||
posMap map[interface{}]ast.Node
|
||||
suppressSeverity Severity
|
||||
@@ -41,8 +41,8 @@ func Parse(reader io.Reader, options ...OptionFunc) (*model.Configuration, error
|
||||
if err != nil {
|
||||
if pe, ok := err.(*hclparser.PosError); ok {
|
||||
pos := ErrorPos{File: pe.Pos.Filename, Line: pe.Pos.Line, Column: pe.Pos.Column}
|
||||
errors := ErrorList{newFatal(pos, pe.Err.Error())}
|
||||
return nil, &ParserError{
|
||||
errors := errorList{newFatal(pos, pe.Err.Error())}
|
||||
return nil, &Error{
|
||||
message: "unable to parse",
|
||||
Errors: errors,
|
||||
}
|
||||
@@ -50,49 +50,49 @@ func Parse(reader io.Reader, options ...OptionFunc) (*model.Configuration, error
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ps := parseAndValidate(root.Node, options...)
|
||||
if len(ps.Errors) > 0 {
|
||||
return nil, &ParserError{
|
||||
p := parseAndValidate(root.Node, options...)
|
||||
if len(p.errors) > 0 {
|
||||
return nil, &Error{
|
||||
message: "unable to parse and validate",
|
||||
Errors: ps.Errors,
|
||||
Actions: ps.Actions,
|
||||
Workflows: ps.Workflows,
|
||||
Errors: p.errors,
|
||||
Actions: p.actions,
|
||||
Workflows: p.workflows,
|
||||
}
|
||||
}
|
||||
|
||||
return &model.Configuration{
|
||||
Actions: ps.Actions,
|
||||
Workflows: ps.Workflows,
|
||||
Actions: p.actions,
|
||||
Workflows: p.workflows,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// parseAndValidate converts a HCL AST into a parseState and validates
|
||||
// parseAndValidate converts a HCL AST into a Parser and validates
|
||||
// high-level structure.
|
||||
// Parameters:
|
||||
// - root - the contents of a .workflow file, as AST
|
||||
// Returns:
|
||||
// - a parseState structure containing actions and workflow definitions
|
||||
func parseAndValidate(root ast.Node, options ...OptionFunc) *parseState {
|
||||
ps := &parseState{
|
||||
// - a Parser structure containing actions and workflow definitions
|
||||
func parseAndValidate(root ast.Node, options ...OptionFunc) *Parser {
|
||||
p := &Parser{
|
||||
posMap: make(map[interface{}]ast.Node),
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
option(ps)
|
||||
option(p)
|
||||
}
|
||||
|
||||
ps.parseRoot(root)
|
||||
ps.validate()
|
||||
ps.Errors.sort()
|
||||
p.parseRoot(root)
|
||||
p.validate()
|
||||
p.errors.sort()
|
||||
|
||||
return ps
|
||||
return p
|
||||
}
|
||||
|
||||
func (ps *parseState) validate() {
|
||||
ps.analyzeDependencies()
|
||||
ps.checkCircularDependencies()
|
||||
ps.checkActions()
|
||||
ps.checkFlows()
|
||||
func (p *Parser) validate() {
|
||||
p.analyzeDependencies()
|
||||
p.checkCircularDependencies()
|
||||
p.checkActions()
|
||||
p.checkFlows()
|
||||
}
|
||||
|
||||
func uniqStrings(items []string) []string {
|
||||
@@ -110,17 +110,17 @@ func uniqStrings(items []string) []string {
|
||||
// checkCircularDependencies finds loops in the action graph.
|
||||
// It emits a fatal error for each cycle it finds, in the order (top to
|
||||
// bottom, left to right) they appear in the .workflow file.
|
||||
func (ps *parseState) checkCircularDependencies() {
|
||||
// make a map from action name to node ID, which is the index in the ps.Actions array
|
||||
// That is, ps.Actions[actionmap[X]].Identifier == X
|
||||
func (p *Parser) checkCircularDependencies() {
|
||||
// make a map from action name to node ID, which is the index in the p.actions array
|
||||
// That is, p.actions[actionmap[X]].Identifier == X
|
||||
actionmap := make(map[string]graph.NI)
|
||||
for i, action := range ps.Actions {
|
||||
for i, action := range p.actions {
|
||||
actionmap[action.Identifier] = graph.NI(i)
|
||||
}
|
||||
|
||||
// make an adjacency list representation of the action dependency graph
|
||||
adjList := make(graph.AdjacencyList, len(ps.Actions))
|
||||
for i, action := range ps.Actions {
|
||||
adjList := make(graph.AdjacencyList, len(p.actions))
|
||||
for i, action := range p.actions {
|
||||
adjList[i] = make([]graph.NI, 0, len(action.Needs))
|
||||
for _, depName := range action.Needs {
|
||||
if depIdx, ok := actionmap[depName]; ok {
|
||||
@@ -132,20 +132,20 @@ func (ps *parseState) checkCircularDependencies() {
|
||||
// find cycles, and print a fatal error for each one
|
||||
g := graph.Directed{AdjacencyList: adjList}
|
||||
g.Cycles(func(cycle []graph.NI) bool {
|
||||
node := ps.posMap[&ps.Actions[cycle[len(cycle)-1]].Needs]
|
||||
ps.addFatal(node, "Circular dependency on `%s'", ps.Actions[cycle[0]].Identifier)
|
||||
node := p.posMap[&p.actions[cycle[len(cycle)-1]].Needs]
|
||||
p.addFatal(node, "Circular dependency on `%s'", p.actions[cycle[0]].Identifier)
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
// checkActions returns error if any actions are syntactically correct but
|
||||
// have structural errors
|
||||
func (ps *parseState) checkActions() {
|
||||
func (p *Parser) checkActions() {
|
||||
secrets := make(map[string]bool)
|
||||
for _, t := range ps.Actions {
|
||||
for _, t := range p.actions {
|
||||
// Ensure the Action has a `uses` attribute
|
||||
if t.Uses == nil {
|
||||
ps.addError(ps.posMap[t], "Action `%s' must have a `uses' attribute", t.Identifier)
|
||||
p.addError(p.posMap[t], "Action `%s' must have a `uses' attribute", t.Identifier)
|
||||
// continue, checking other actions
|
||||
}
|
||||
|
||||
@@ -154,7 +154,7 @@ func (ps *parseState) checkActions() {
|
||||
if !secrets[str] {
|
||||
secrets[str] = true
|
||||
if len(secrets) == maxSecrets+1 {
|
||||
ps.addError(ps.posMap[&t.Secrets], "All actions combined must not have more than %d unique secrets", maxSecrets)
|
||||
p.addError(p.posMap[&t.Secrets], "All actions combined must not have more than %d unique secrets", maxSecrets)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -166,16 +166,16 @@ func (ps *parseState) checkActions() {
|
||||
// Finally, ensure that the same key name isn't used more than once
|
||||
// between env and secrets, combined.
|
||||
for k := range t.Env {
|
||||
ps.checkEnvironmentVariable(k, ps.posMap[&t.Env])
|
||||
p.checkEnvironmentVariable(k, p.posMap[&t.Env])
|
||||
}
|
||||
secretVars := make(map[string]bool)
|
||||
for _, k := range t.Secrets {
|
||||
ps.checkEnvironmentVariable(k, ps.posMap[&t.Secrets])
|
||||
p.checkEnvironmentVariable(k, p.posMap[&t.Secrets])
|
||||
if _, found := t.Env[k]; found {
|
||||
ps.addError(ps.posMap[&t.Secrets], "Secret `%s' conflicts with an environment variable with the same name", k)
|
||||
p.addError(p.posMap[&t.Secrets], "Secret `%s' conflicts with an environment variable with the same name", k)
|
||||
}
|
||||
if secretVars[k] {
|
||||
ps.addWarning(ps.posMap[&t.Secrets], "Secret `%s' redefined", k)
|
||||
p.addWarning(p.posMap[&t.Secrets], "Secret `%s' redefined", k)
|
||||
}
|
||||
secretVars[k] = true
|
||||
}
|
||||
@@ -184,26 +184,26 @@ func (ps *parseState) checkActions() {
|
||||
|
||||
var envVarChecker = regexp.MustCompile(`\A[A-Za-z_][A-Za-z_0-9]*\z`)
|
||||
|
||||
func (ps *parseState) checkEnvironmentVariable(key string, node ast.Node) {
|
||||
func (p *Parser) checkEnvironmentVariable(key string, node ast.Node) {
|
||||
if key != "GITHUB_TOKEN" && strings.HasPrefix(key, "GITHUB_") {
|
||||
ps.addWarning(node, "Environment variables and secrets beginning with `GITHUB_' are reserved")
|
||||
p.addWarning(node, "Environment variables and secrets beginning with `GITHUB_' are reserved")
|
||||
}
|
||||
if !envVarChecker.MatchString(key) {
|
||||
ps.addWarning(node, "Environment variables and secrets must contain only A-Z, a-z, 0-9, and _ characters, got `%s'", key)
|
||||
p.addWarning(node, "Environment variables and secrets must contain only A-Z, a-z, 0-9, and _ characters, got `%s'", key)
|
||||
}
|
||||
}
|
||||
|
||||
// checkFlows appends an error if any workflows are syntactically correct but
|
||||
// have structural errors
|
||||
func (ps *parseState) checkFlows() {
|
||||
actionmap := makeActionMap(ps.Actions)
|
||||
for _, f := range ps.Workflows {
|
||||
func (p *Parser) checkFlows() {
|
||||
actionmap := makeActionMap(p.actions)
|
||||
for _, f := range p.workflows {
|
||||
// make sure there's an `on` attribute
|
||||
if f.On == "" {
|
||||
ps.addError(ps.posMap[f], "Workflow `%s' must have an `on' attribute", f.Identifier)
|
||||
p.addError(p.posMap[f], "Workflow `%s' must have an `on' attribute", f.Identifier)
|
||||
// continue, checking other workflows
|
||||
} else if !model.IsAllowedEventType(f.On) {
|
||||
ps.addError(ps.posMap[&f.On], "Workflow `%s' has unknown `on' value `%s'", f.Identifier, f.On)
|
||||
} else if !isAllowedEventType(f.On) {
|
||||
p.addError(p.posMap[&f.On], "Workflow `%s' has unknown `on' value `%s'", f.Identifier, f.On)
|
||||
// continue, checking other workflows
|
||||
}
|
||||
|
||||
@@ -211,7 +211,7 @@ func (ps *parseState) checkFlows() {
|
||||
for _, actionID := range f.Resolves {
|
||||
_, ok := actionmap[actionID]
|
||||
if !ok {
|
||||
ps.addError(ps.posMap[&f.Resolves], "Workflow `%s' resolves unknown action `%s'", f.Identifier, actionID)
|
||||
p.addError(p.posMap[&f.Resolves], "Workflow `%s' resolves unknown action `%s'", f.Identifier, actionID)
|
||||
// continue, checking other workflows
|
||||
}
|
||||
}
|
||||
@@ -229,28 +229,28 @@ func makeActionMap(actions []*model.Action) map[string]*model.Action {
|
||||
// Fill in Action dependencies for all actions based on explicit dependencies
|
||||
// declarations.
|
||||
//
|
||||
// ps.Actions is an array of Action objects, as parsed. The Action objects in
|
||||
// p.actions is an array of Action objects, as parsed. The Action objects in
|
||||
// this array are mutated, by setting Action.dependencies for each.
|
||||
func (ps *parseState) analyzeDependencies() {
|
||||
actionmap := makeActionMap(ps.Actions)
|
||||
for _, action := range ps.Actions {
|
||||
func (p *Parser) analyzeDependencies() {
|
||||
actionmap := makeActionMap(p.actions)
|
||||
for _, action := range p.actions {
|
||||
// analyze explicit dependencies for each "needs" keyword
|
||||
ps.analyzeNeeds(action, actionmap)
|
||||
p.analyzeNeeds(action, actionmap)
|
||||
}
|
||||
|
||||
// uniq all the dependencies lists
|
||||
for _, action := range ps.Actions {
|
||||
for _, action := range p.actions {
|
||||
if len(action.Needs) >= 2 {
|
||||
action.Needs = uniqStrings(action.Needs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (ps *parseState) analyzeNeeds(action *model.Action, actionmap map[string]*model.Action) {
|
||||
func (p *Parser) analyzeNeeds(action *model.Action, actionmap map[string]*model.Action) {
|
||||
for _, need := range action.Needs {
|
||||
_, ok := actionmap[need]
|
||||
if !ok {
|
||||
ps.addError(ps.posMap[&action.Needs], "Action `%s' needs nonexistent action `%s'", action.Identifier, need)
|
||||
p.addError(p.posMap[&action.Needs], "Action `%s' needs nonexistent action `%s'", action.Identifier, need)
|
||||
// continue, checking other actions
|
||||
}
|
||||
}
|
||||
@@ -263,27 +263,27 @@ func (ps *parseState) analyzeNeeds(action *model.Action, actionmap map[string]*m
|
||||
// if it's not an object, or it has non-assignment attributes, or if any
|
||||
// of its values are anything other than a string, the function appends an
|
||||
// appropriate error.
|
||||
func (ps *parseState) literalToStringMap(node ast.Node) map[string]string {
|
||||
func (p *Parser) literalToStringMap(node ast.Node) map[string]string {
|
||||
obj, ok := node.(*ast.ObjectType)
|
||||
|
||||
if !ok {
|
||||
ps.addError(node, "Expected object, got %s", typename(node))
|
||||
p.addError(node, "Expected object, got %s", typename(node))
|
||||
return nil
|
||||
}
|
||||
|
||||
ps.checkAssignmentsOnly(obj.List, "")
|
||||
p.checkAssignmentsOnly(obj.List, "")
|
||||
|
||||
ret := make(map[string]string)
|
||||
for _, item := range obj.List.Items {
|
||||
if !isAssignment(item) {
|
||||
continue
|
||||
}
|
||||
str, ok := ps.literalToString(item.Val)
|
||||
str, ok := p.literalToString(item.Val)
|
||||
if ok {
|
||||
key := ps.identString(item.Keys[0].Token)
|
||||
key := p.identString(item.Keys[0].Token)
|
||||
if key != "" {
|
||||
if _, found := ret[key]; found {
|
||||
ps.addWarning(node, "Environment variable `%s' redefined", key)
|
||||
p.addWarning(node, "Environment variable `%s' redefined", key)
|
||||
}
|
||||
ret[key] = str
|
||||
}
|
||||
@@ -293,14 +293,14 @@ func (ps *parseState) literalToStringMap(node ast.Node) map[string]string {
|
||||
return ret
|
||||
}
|
||||
|
||||
func (ps *parseState) identString(t token.Token) string {
|
||||
func (p *Parser) identString(t token.Token) string {
|
||||
switch t.Type {
|
||||
case token.STRING:
|
||||
return t.Value().(string)
|
||||
case token.IDENT:
|
||||
return t.Text
|
||||
default:
|
||||
ps.addErrorFromToken(t,
|
||||
p.addErrorFromToken(t,
|
||||
"Each identifier should be a string, got %s",
|
||||
strings.ToLower(t.Type.String()))
|
||||
return ""
|
||||
@@ -316,25 +316,25 @@ func (ps *parseState) identString(t token.Token) string {
|
||||
// If promoteScalars is true, then values that are scalar strings are
|
||||
// promoted to a single-entry string array. E.g., "foo" becomes the Go
|
||||
// expression []string{ "foo" }.
|
||||
func (ps *parseState) literalToStringArray(node ast.Node, promoteScalars bool) ([]string, bool) {
|
||||
func (p *Parser) literalToStringArray(node ast.Node, promoteScalars bool) ([]string, bool) {
|
||||
literal, ok := node.(*ast.LiteralType)
|
||||
if ok {
|
||||
if promoteScalars && literal.Token.Type == token.STRING {
|
||||
return []string{literal.Token.Value().(string)}, true
|
||||
}
|
||||
ps.addError(node, "Expected list, got %s", typename(node))
|
||||
p.addError(node, "Expected list, got %s", typename(node))
|
||||
return nil, false
|
||||
}
|
||||
|
||||
list, ok := node.(*ast.ListType)
|
||||
if !ok {
|
||||
ps.addError(node, "Expected list, got %s", typename(node))
|
||||
p.addError(node, "Expected list, got %s", typename(node))
|
||||
return nil, false
|
||||
}
|
||||
|
||||
ret := make([]string, 0, len(list.List))
|
||||
for _, literal := range list.List {
|
||||
str, ok := ps.literalToString(literal)
|
||||
str, ok := p.literalToString(literal)
|
||||
if ok {
|
||||
ret = append(ret, str)
|
||||
}
|
||||
@@ -346,8 +346,8 @@ func (ps *parseState) literalToStringArray(node ast.Node, promoteScalars bool) (
|
||||
// literalToString converts a literal value from the AST into a string.
|
||||
// If the value isn't a scalar or isn't a string, the function appends an
|
||||
// appropriate error and returns "", false.
|
||||
func (ps *parseState) literalToString(node ast.Node) (string, bool) {
|
||||
val := ps.literalCast(node, token.STRING)
|
||||
func (p *Parser) literalToString(node ast.Node) (string, bool) {
|
||||
val := p.literalCast(node, token.STRING)
|
||||
if val == nil {
|
||||
return "", false
|
||||
}
|
||||
@@ -359,117 +359,117 @@ func (ps *parseState) literalToString(node ast.Node) (string, bool) {
|
||||
// Exponents (1e6) and floats (123.456) generate errors.
|
||||
// If the value isn't a scalar or isn't a number, the function appends an
|
||||
// appropriate error and returns 0, false.
|
||||
func (ps *parseState) literalToInt(node ast.Node) (int64, bool) {
|
||||
val := ps.literalCast(node, token.NUMBER)
|
||||
func (p *Parser) literalToInt(node ast.Node) (int64, bool) {
|
||||
val := p.literalCast(node, token.NUMBER)
|
||||
if val == nil {
|
||||
return 0, false
|
||||
}
|
||||
return val.(int64), true
|
||||
}
|
||||
|
||||
func (ps *parseState) literalCast(node ast.Node, t token.Type) interface{} {
|
||||
func (p *Parser) literalCast(node ast.Node, t token.Type) interface{} {
|
||||
literal, ok := node.(*ast.LiteralType)
|
||||
if !ok {
|
||||
ps.addError(node, "Expected %s, got %s", strings.ToLower(t.String()), typename(node))
|
||||
p.addError(node, "Expected %s, got %s", strings.ToLower(t.String()), typename(node))
|
||||
return nil
|
||||
}
|
||||
|
||||
if literal.Token.Type != t {
|
||||
ps.addError(node, "Expected %s, got %s", strings.ToLower(t.String()), typename(node))
|
||||
p.addError(node, "Expected %s, got %s", strings.ToLower(t.String()), typename(node))
|
||||
return nil
|
||||
}
|
||||
|
||||
return literal.Token.Value()
|
||||
}
|
||||
|
||||
// parseRoot parses the root of the AST, filling in ps.Version, ps.Actions,
|
||||
// and ps.Workflows.
|
||||
func (ps *parseState) parseRoot(node ast.Node) {
|
||||
// parseRoot parses the root of the AST, filling in p.version, p.actions,
|
||||
// and p.workflows.
|
||||
func (p *Parser) parseRoot(node ast.Node) {
|
||||
objectList, ok := node.(*ast.ObjectList)
|
||||
if !ok {
|
||||
// It should be impossible for HCL to return anything other than an
|
||||
// ObjectList as the root node. This error should never happen.
|
||||
ps.addError(node, "Internal error: root node must be an ObjectList")
|
||||
p.addError(node, "Internal error: root node must be an ObjectList")
|
||||
return
|
||||
}
|
||||
|
||||
ps.Actions = make([]*model.Action, 0, len(objectList.Items))
|
||||
ps.Workflows = make([]*model.Workflow, 0, len(objectList.Items))
|
||||
p.actions = make([]*model.Action, 0, len(objectList.Items))
|
||||
p.workflows = make([]*model.Workflow, 0, len(objectList.Items))
|
||||
identifiers := make(map[string]bool)
|
||||
for idx, item := range objectList.Items {
|
||||
if item.Assign.IsValid() {
|
||||
ps.parseVersion(idx, item)
|
||||
p.parseVersion(idx, item)
|
||||
continue
|
||||
}
|
||||
ps.parseBlock(item, identifiers)
|
||||
p.parseBlock(item, identifiers)
|
||||
}
|
||||
}
|
||||
|
||||
// parseBlock parses a single, top-level "action" or "workflow" block,
|
||||
// appending it to ps.Actions or ps.Workflows as appropriate.
|
||||
func (ps *parseState) parseBlock(item *ast.ObjectItem, identifiers map[string]bool) {
|
||||
// appending it to p.actions or p.workflows as appropriate.
|
||||
func (p *Parser) parseBlock(item *ast.ObjectItem, identifiers map[string]bool) {
|
||||
if len(item.Keys) != 2 {
|
||||
ps.addError(item, "Invalid toplevel declaration")
|
||||
p.addError(item, "Invalid toplevel declaration")
|
||||
return
|
||||
}
|
||||
|
||||
cmd := ps.identString(item.Keys[0].Token)
|
||||
cmd := p.identString(item.Keys[0].Token)
|
||||
var id string
|
||||
|
||||
switch cmd {
|
||||
case "action":
|
||||
action := ps.actionifyItem(item)
|
||||
action := p.actionifyItem(item)
|
||||
if action != nil {
|
||||
id = action.Identifier
|
||||
ps.Actions = append(ps.Actions, action)
|
||||
p.actions = append(p.actions, action)
|
||||
}
|
||||
case "workflow":
|
||||
workflow := ps.workflowifyItem(item)
|
||||
workflow := p.workflowifyItem(item)
|
||||
if workflow != nil {
|
||||
id = workflow.Identifier
|
||||
ps.Workflows = append(ps.Workflows, workflow)
|
||||
p.workflows = append(p.workflows, workflow)
|
||||
}
|
||||
default:
|
||||
ps.addError(item, "Invalid toplevel keyword, `%s'", cmd)
|
||||
p.addError(item, "Invalid toplevel keyword, `%s'", cmd)
|
||||
return
|
||||
}
|
||||
|
||||
if identifiers[id] {
|
||||
ps.addError(item, "Identifier `%s' redefined", id)
|
||||
p.addError(item, "Identifier `%s' redefined", id)
|
||||
}
|
||||
|
||||
identifiers[id] = true
|
||||
}
|
||||
|
||||
// parseVersion parses a top-level `version=N` statement, filling in
|
||||
// ps.Version.
|
||||
func (ps *parseState) parseVersion(idx int, item *ast.ObjectItem) {
|
||||
if len(item.Keys) != 1 || ps.identString(item.Keys[0].Token) != "version" {
|
||||
// p.version.
|
||||
func (p *Parser) parseVersion(idx int, item *ast.ObjectItem) {
|
||||
if len(item.Keys) != 1 || p.identString(item.Keys[0].Token) != "version" {
|
||||
// not a valid `version` declaration
|
||||
ps.addError(item.Val, "Toplevel declarations cannot be assignments")
|
||||
p.addError(item.Val, "Toplevel declarations cannot be assignments")
|
||||
return
|
||||
}
|
||||
if idx != 0 {
|
||||
ps.addError(item.Val, "`version` must be the first declaration")
|
||||
p.addError(item.Val, "`version` must be the first declaration")
|
||||
return
|
||||
}
|
||||
version, ok := ps.literalToInt(item.Val)
|
||||
version, ok := p.literalToInt(item.Val)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if version < minVersion || version > maxVersion {
|
||||
ps.addError(item.Val, "`version = %d` is not supported", version)
|
||||
p.addError(item.Val, "`version = %d` is not supported", version)
|
||||
return
|
||||
}
|
||||
ps.Version = int(version)
|
||||
p.version = int(version)
|
||||
}
|
||||
|
||||
// parseIdentifier parses the double-quoted identifier (name) for a
|
||||
// "workflow" or "action" block.
|
||||
func (ps *parseState) parseIdentifier(key *ast.ObjectKey) string {
|
||||
func (p *Parser) parseIdentifier(key *ast.ObjectKey) string {
|
||||
id := key.Token.Text
|
||||
if len(id) < 3 || id[0] != '"' || id[len(id)-1] != '"' {
|
||||
ps.addError(key, "Invalid format for identifier `%s'", id)
|
||||
p.addError(key, "Invalid format for identifier `%s'", id)
|
||||
return ""
|
||||
}
|
||||
return id[1 : len(id)-1]
|
||||
@@ -477,20 +477,20 @@ func (ps *parseState) parseIdentifier(key *ast.ObjectKey) string {
|
||||
|
||||
// parseRequiredString parses a string value, setting its value into the
|
||||
// out-parameter `value` and returning true if successful.
|
||||
func (ps *parseState) parseRequiredString(value *string, val ast.Node, nodeType, name, id string) bool {
|
||||
func (p *Parser) parseRequiredString(value *string, val ast.Node, nodeType, name, id string) bool {
|
||||
if *value != "" {
|
||||
ps.addWarning(val, "`%s' redefined in %s `%s'", name, nodeType, id)
|
||||
p.addWarning(val, "`%s' redefined in %s `%s'", name, nodeType, id)
|
||||
// continue, allowing the redefinition
|
||||
}
|
||||
|
||||
newVal, ok := ps.literalToString(val)
|
||||
newVal, ok := p.literalToString(val)
|
||||
if !ok {
|
||||
ps.addError(val, "Invalid format for `%s' in %s `%s', expected string", name, nodeType, id)
|
||||
p.addError(val, "Invalid format for `%s' in %s `%s', expected string", name, nodeType, id)
|
||||
return false
|
||||
}
|
||||
|
||||
if newVal == "" {
|
||||
ps.addError(val, "`%s' value in %s `%s' cannot be blank", name, nodeType, id)
|
||||
p.addError(val, "`%s' value in %s `%s' cannot be blank", name, nodeType, id)
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -500,8 +500,8 @@ func (ps *parseState) parseRequiredString(value *string, val ast.Node, nodeType,
|
||||
|
||||
// parseBlockPreamble parses the beginning of a "workflow" or "action"
|
||||
// block.
|
||||
func (ps *parseState) parseBlockPreamble(item *ast.ObjectItem, nodeType string) (string, *ast.ObjectType) {
|
||||
id := ps.parseIdentifier(item.Keys[1])
|
||||
func (p *Parser) parseBlockPreamble(item *ast.ObjectItem, nodeType string) (string, *ast.ObjectType) {
|
||||
id := p.parseIdentifier(item.Keys[1])
|
||||
if id == "" {
|
||||
return "", nil
|
||||
}
|
||||
@@ -509,18 +509,18 @@ func (ps *parseState) parseBlockPreamble(item *ast.ObjectItem, nodeType string)
|
||||
node := item.Val
|
||||
obj, ok := node.(*ast.ObjectType)
|
||||
if !ok {
|
||||
ps.addError(node, "Each %s must have an { ... } block", nodeType)
|
||||
p.addError(node, "Each %s must have an { ... } block", nodeType)
|
||||
return "", nil
|
||||
}
|
||||
|
||||
ps.checkAssignmentsOnly(obj.List, id)
|
||||
p.checkAssignmentsOnly(obj.List, id)
|
||||
|
||||
return id, obj
|
||||
}
|
||||
|
||||
// actionifyItem converts an AST block to an Action object.
|
||||
func (ps *parseState) actionifyItem(item *ast.ObjectItem) *model.Action {
|
||||
id, obj := ps.parseBlockPreamble(item, "action")
|
||||
func (p *Parser) actionifyItem(item *ast.ObjectItem) *model.Action {
|
||||
id, obj := p.parseBlockPreamble(item, "action")
|
||||
if obj == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -528,10 +528,10 @@ func (ps *parseState) actionifyItem(item *ast.ObjectItem) *model.Action {
|
||||
action := &model.Action{
|
||||
Identifier: id,
|
||||
}
|
||||
ps.posMap[action] = item
|
||||
p.posMap[action] = item
|
||||
|
||||
for _, item := range obj.List.Items {
|
||||
ps.parseActionAttribute(ps.identString(item.Keys[0].Token), action, item.Val)
|
||||
p.parseActionAttribute(p.identString(item.Keys[0].Token), action, item.Val)
|
||||
}
|
||||
|
||||
return action
|
||||
@@ -543,53 +543,53 @@ func (ps *parseState) actionifyItem(item *ast.ObjectItem) *model.Action {
|
||||
// It also has higher-than-normal cyclomatic complexity, so we ask the
|
||||
// gocyclo linter to ignore it.
|
||||
// nolint: gocyclo
|
||||
func (ps *parseState) parseActionAttribute(name string, action *model.Action, val ast.Node) {
|
||||
func (p *Parser) parseActionAttribute(name string, action *model.Action, val ast.Node) {
|
||||
switch name {
|
||||
case "uses":
|
||||
ps.parseUses(action, val)
|
||||
p.parseUses(action, val)
|
||||
case "needs":
|
||||
if needs, ok := ps.literalToStringArray(val, true); ok {
|
||||
if needs, ok := p.literalToStringArray(val, true); ok {
|
||||
action.Needs = needs
|
||||
ps.posMap[&action.Needs] = val
|
||||
p.posMap[&action.Needs] = val
|
||||
}
|
||||
case "runs":
|
||||
if runs := ps.parseCommand(action, action.Runs, name, val, false); runs != nil {
|
||||
if runs := p.parseCommand(action, action.Runs, name, val, false); runs != nil {
|
||||
action.Runs = runs
|
||||
}
|
||||
case "args":
|
||||
if args := ps.parseCommand(action, action.Args, name, val, true); args != nil {
|
||||
if args := p.parseCommand(action, action.Args, name, val, true); args != nil {
|
||||
action.Args = args
|
||||
}
|
||||
case "env":
|
||||
if env := ps.literalToStringMap(val); env != nil {
|
||||
if env := p.literalToStringMap(val); env != nil {
|
||||
action.Env = env
|
||||
}
|
||||
ps.posMap[&action.Env] = val
|
||||
p.posMap[&action.Env] = val
|
||||
case "secrets":
|
||||
if secrets, ok := ps.literalToStringArray(val, false); ok {
|
||||
if secrets, ok := p.literalToStringArray(val, false); ok {
|
||||
action.Secrets = secrets
|
||||
ps.posMap[&action.Secrets] = val
|
||||
p.posMap[&action.Secrets] = val
|
||||
}
|
||||
default:
|
||||
ps.addWarning(val, "Unknown action attribute `%s'", name)
|
||||
p.addWarning(val, "Unknown action attribute `%s'", name)
|
||||
}
|
||||
}
|
||||
|
||||
// parseUses sets the action.Uses value based on the contents of the AST
|
||||
// node. This function enforces formatting requirements on the value.
|
||||
func (ps *parseState) parseUses(action *model.Action, node ast.Node) {
|
||||
func (p *Parser) parseUses(action *model.Action, node ast.Node) {
|
||||
if action.Uses != nil {
|
||||
ps.addWarning(node, "`uses' redefined in action `%s'", action.Identifier)
|
||||
p.addWarning(node, "`uses' redefined in action `%s'", action.Identifier)
|
||||
// continue, allowing the redefinition
|
||||
}
|
||||
strVal, ok := ps.literalToString(node)
|
||||
strVal, ok := p.literalToString(node)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if strVal == "" {
|
||||
action.Uses = &model.UsesInvalid{}
|
||||
ps.addError(node, "`uses' value in action `%s' cannot be blank", action.Identifier)
|
||||
p.addError(node, "`uses' value in action `%s' cannot be blank", action.Identifier)
|
||||
return
|
||||
}
|
||||
if strings.HasPrefix(strVal, "./") {
|
||||
@@ -605,14 +605,14 @@ func (ps *parseState) parseUses(action *model.Action, node ast.Node) {
|
||||
tok := strings.Split(strVal, "@")
|
||||
if len(tok) != 2 {
|
||||
action.Uses = &model.UsesInvalid{Raw: strVal}
|
||||
ps.addError(node, "The `uses' attribute must be a path, a Docker image, or owner/repo@ref")
|
||||
p.addError(node, "The `uses' attribute must be a path, a Docker image, or owner/repo@ref")
|
||||
return
|
||||
}
|
||||
ref := tok[1]
|
||||
tok = strings.SplitN(tok[0], "/", 3)
|
||||
if len(tok) < 2 {
|
||||
action.Uses = &model.UsesInvalid{Raw: strVal}
|
||||
ps.addError(node, "The `uses' attribute must be a path, a Docker image, or owner/repo@ref")
|
||||
p.addError(node, "The `uses' attribute must be a path, a Docker image, or owner/repo@ref")
|
||||
return
|
||||
}
|
||||
usesRepo := &model.UsesRepository{Repository: tok[0] + "/" + tok[1], Ref: ref}
|
||||
@@ -625,15 +625,15 @@ func (ps *parseState) parseUses(action *model.Action, node ast.Node) {
|
||||
// parseUses sets the action.Runs or action.Args value based on the
|
||||
// contents of the AST node. This function enforces formatting
|
||||
// requirements on the value.
|
||||
func (ps *parseState) parseCommand(action *model.Action, cmd model.Command, name string, node ast.Node, allowBlank bool) model.Command {
|
||||
func (p *Parser) parseCommand(action *model.Action, cmd model.Command, name string, node ast.Node, allowBlank bool) model.Command {
|
||||
if cmd != nil {
|
||||
ps.addWarning(node, "`%s' redefined in action `%s'", name, action.Identifier)
|
||||
p.addWarning(node, "`%s' redefined in action `%s'", name, action.Identifier)
|
||||
// continue, allowing the redefinition
|
||||
}
|
||||
|
||||
// Is it a list?
|
||||
if _, ok := node.(*ast.ListType); ok {
|
||||
if parsed, ok := ps.literalToStringArray(node, false); ok {
|
||||
if parsed, ok := p.literalToStringArray(node, false); ok {
|
||||
return &model.ListCommand{Values: parsed}
|
||||
}
|
||||
return nil
|
||||
@@ -642,12 +642,12 @@ func (ps *parseState) parseCommand(action *model.Action, cmd model.Command, name
|
||||
// If not, parse a whitespace-separated string into a list.
|
||||
var raw string
|
||||
var ok bool
|
||||
if raw, ok = ps.literalToString(node); !ok {
|
||||
ps.addError(node, "The `%s' attribute must be a string or a list", name)
|
||||
if raw, ok = p.literalToString(node); !ok {
|
||||
p.addError(node, "The `%s' attribute must be a string or a list", name)
|
||||
return nil
|
||||
}
|
||||
if raw == "" && !allowBlank {
|
||||
ps.addError(node, "`%s' value in action `%s' cannot be blank", name, action.Identifier)
|
||||
p.addError(node, "`%s' value in action `%s' cannot be blank", name, action.Identifier)
|
||||
return nil
|
||||
}
|
||||
return &model.StringCommand{Value: raw}
|
||||
@@ -667,8 +667,8 @@ func typename(val interface{}) string {
|
||||
}
|
||||
|
||||
// workflowifyItem converts an AST block to a Workflow object.
|
||||
func (ps *parseState) workflowifyItem(item *ast.ObjectItem) *model.Workflow {
|
||||
id, obj := ps.parseBlockPreamble(item, "workflow")
|
||||
func (p *Parser) workflowifyItem(item *ast.ObjectItem) *model.Workflow {
|
||||
id, obj := p.parseBlockPreamble(item, "workflow")
|
||||
if obj == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -676,32 +676,32 @@ func (ps *parseState) workflowifyItem(item *ast.ObjectItem) *model.Workflow {
|
||||
var ok bool
|
||||
workflow := &model.Workflow{Identifier: id}
|
||||
for _, item := range obj.List.Items {
|
||||
name := ps.identString(item.Keys[0].Token)
|
||||
name := p.identString(item.Keys[0].Token)
|
||||
|
||||
switch name {
|
||||
case "on":
|
||||
ok = ps.parseRequiredString(&workflow.On, item.Val, "workflow", name, id)
|
||||
ok = p.parseRequiredString(&workflow.On, item.Val, "workflow", name, id)
|
||||
if ok {
|
||||
ps.posMap[&workflow.On] = item
|
||||
p.posMap[&workflow.On] = item
|
||||
}
|
||||
case "resolves":
|
||||
if workflow.Resolves != nil {
|
||||
ps.addWarning(item.Val, "`resolves' redefined in workflow `%s'", id)
|
||||
p.addWarning(item.Val, "`resolves' redefined in workflow `%s'", id)
|
||||
// continue, allowing the redefinition
|
||||
}
|
||||
workflow.Resolves, ok = ps.literalToStringArray(item.Val, true)
|
||||
ps.posMap[&workflow.Resolves] = item
|
||||
workflow.Resolves, ok = p.literalToStringArray(item.Val, true)
|
||||
p.posMap[&workflow.Resolves] = item
|
||||
if !ok {
|
||||
ps.addError(item.Val, "Invalid format for `resolves' in workflow `%s', expected list of strings", id)
|
||||
p.addError(item.Val, "Invalid format for `resolves' in workflow `%s', expected list of strings", id)
|
||||
// continue, allowing workflow with no `resolves`
|
||||
}
|
||||
default:
|
||||
ps.addWarning(item.Val, "Unknown workflow attribute `%s'", name)
|
||||
p.addWarning(item.Val, "Unknown workflow attribute `%s'", name)
|
||||
// continue, treat as no-op
|
||||
}
|
||||
}
|
||||
|
||||
ps.posMap[workflow] = item
|
||||
p.posMap[workflow] = item
|
||||
return workflow
|
||||
}
|
||||
|
||||
@@ -711,7 +711,7 @@ func isAssignment(item *ast.ObjectItem) bool {
|
||||
|
||||
// checkAssignmentsOnly ensures that all elements in the object are "key =
|
||||
// value" pairs.
|
||||
func (ps *parseState) checkAssignmentsOnly(objectList *ast.ObjectList, actionID string) {
|
||||
func (p *Parser) checkAssignmentsOnly(objectList *ast.ObjectList, actionID string) {
|
||||
for _, item := range objectList.Items {
|
||||
if !isAssignment(item) {
|
||||
var desc string
|
||||
@@ -720,44 +720,44 @@ func (ps *parseState) checkAssignmentsOnly(objectList *ast.ObjectList, actionID
|
||||
} else {
|
||||
desc = fmt.Sprintf("action `%s'", actionID)
|
||||
}
|
||||
ps.addErrorFromObjectItem(item, "Each attribute of %s must be an assignment", desc)
|
||||
p.addErrorFromObjectItem(item, "Each attribute of %s must be an assignment", desc)
|
||||
continue
|
||||
}
|
||||
|
||||
child, ok := item.Val.(*ast.ObjectType)
|
||||
if ok {
|
||||
ps.checkAssignmentsOnly(child.List, actionID)
|
||||
p.checkAssignmentsOnly(child.List, actionID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (ps *parseState) addWarning(node ast.Node, format string, a ...interface{}) {
|
||||
if ps.suppressSeverity < WARNING {
|
||||
ps.Errors = append(ps.Errors, newWarning(posFromNode(node), format, a...))
|
||||
func (p *Parser) addWarning(node ast.Node, format string, a ...interface{}) {
|
||||
if p.suppressSeverity < WARNING {
|
||||
p.errors = append(p.errors, newWarning(posFromNode(node), format, a...))
|
||||
}
|
||||
}
|
||||
|
||||
func (ps *parseState) addError(node ast.Node, format string, a ...interface{}) {
|
||||
if ps.suppressSeverity < ERROR {
|
||||
ps.Errors = append(ps.Errors, newError(posFromNode(node), format, a...))
|
||||
func (p *Parser) addError(node ast.Node, format string, a ...interface{}) {
|
||||
if p.suppressSeverity < ERROR {
|
||||
p.errors = append(p.errors, newError(posFromNode(node), format, a...))
|
||||
}
|
||||
}
|
||||
|
||||
func (ps *parseState) addErrorFromToken(t token.Token, format string, a ...interface{}) {
|
||||
if ps.suppressSeverity < ERROR {
|
||||
ps.Errors = append(ps.Errors, newError(posFromToken(t), format, a...))
|
||||
func (p *Parser) addErrorFromToken(t token.Token, format string, a ...interface{}) {
|
||||
if p.suppressSeverity < ERROR {
|
||||
p.errors = append(p.errors, newError(posFromToken(t), format, a...))
|
||||
}
|
||||
}
|
||||
|
||||
func (ps *parseState) addErrorFromObjectItem(objectItem *ast.ObjectItem, format string, a ...interface{}) {
|
||||
if ps.suppressSeverity < ERROR {
|
||||
ps.Errors = append(ps.Errors, newError(posFromObjectItem(objectItem), format, a...))
|
||||
func (p *Parser) addErrorFromObjectItem(objectItem *ast.ObjectItem, format string, a ...interface{}) {
|
||||
if p.suppressSeverity < ERROR {
|
||||
p.errors = append(p.errors, newError(posFromObjectItem(objectItem), format, a...))
|
||||
}
|
||||
}
|
||||
|
||||
func (ps *parseState) addFatal(node ast.Node, format string, a ...interface{}) {
|
||||
if ps.suppressSeverity < FATAL {
|
||||
ps.Errors = append(ps.Errors, newFatal(posFromNode(node), format, a...))
|
||||
func (p *Parser) addFatal(node ast.Node, format string, a ...interface{}) {
|
||||
if p.suppressSeverity < FATAL {
|
||||
p.errors = append(p.errors, newFatal(posFromNode(node), format, a...))
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user