actionlint

package module
v1.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 25, 2021 License: MIT Imports: 25 Imported by: 29

README

actionlint

CI Badge API Document

actionlint is a static checker for GitHub Actions workflow files.

Features:

  • Syntax check for workflow files to check unexpected or missing keys following workflow syntax
  • Strong type check for ${{ }} expressions to catch several semantic errors like access to not existing property, type mismatches, ...
  • shellcheck and pyflakes integrations for scripts in run:
  • Other several useful checks; dependencies check for needs:, runner label validation, cron syntax validation, ...

See 'Checks' section for full list of checks done by actionlint.

Example of broken workflow:

on:
  push:
    branch: main
jobs:
  test:
    strategy:
      matrix:
        os: [macos-latest, linux-latest]
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v2
      - uses: actions/cache@v2
        with:
          path: ~/.npm
          key: ${{ matrix.platform }}-node-${{ hashFiles('**/package-lock.json') }}
        if: ${{ github.repository.permissions.admin == true }}
      - run: npm install && npm test

Output from actionlint:

example.yaml:3:5: unexpected key "branch" for "push" section. expected one of "types", "branches", "branches-ignore", "tags", "tags-ignore", "paths", "paths-ignore", "workflows" [syntax-check]
3|     branch: main
 |     ^~~~~~~
example.yaml:9:28: label "linux-latest" is unknown. available labels are "windows-latest", "windows-2019", "windows-2016", "ubuntu-latest", ... [runner-label]
9|         os: [macos-latest, linux-latest]
 |                            ^~~~~~~~~~~~~
example.yaml:17:17: receiver of object dereference "permissions" must be type of object but got "string" [expression]
17|         if: ${{ github.repository.permissions.admin == true }}
  |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
example.yaml:16:20: property "platform" is not defined in object type {os: string} [expression]
16|           key: ${{ matrix.platform }}-node-${{ hashFiles('**/package-lock.json') }}
  |                    ^~~~~~~~~~~~~~~

actionlint tries to catch errors as much as possible and make false positives as minimal as possible.

Why?

  • Running workflow is very time consuming. You need to push the changes and wait until the workflow runs on GitHub even if it contains some trivial mistakes. act is useful to run the workflow locally. But it is not suitable for CI and still time consuming when your workflow gets larger.
  • Checks of workflow files by GitHub is very loose. It reports no error even if unexpected keys are in mappings (meant that some typos in keys). And also it reports no error when accessing to property which is actually not existing. For example matrix.foo when no foo is defined in matrix: section, it is evaluated to null and causes no error.
  • Some mistakes silently breaks workflow. Most common case I saw is specifying missing property to cache key. In the case cache silently does not work properly but workflow itself runs without error. So you might not notice the mistake forever.

Install

Homebrew on macOS

Tap this repository and install actionlint package.

brew tap "rhysd/actionlint" "https://github.com/rhysd/actionlint"
brew install actionlint

Prebuilt binaries

Download an archive file from releases page, unarchive it and put the executable file at a directory in $PATH.

Prebuilt binaries are built at each release by CI for the following OS and arch:

  • macOS (x86_64)
  • Linux (i386, x86_64, arm32, arm64)
  • Windows (i386, x86_64)
  • FreeBSD (i386, x86_64)

CI services

Please try the download script. It downloads the latest version of actionlint (actionlint.exe on Windows and actionlint on other OSes) to the current directory automatically. On GitHub Actions environment, it sets executable output to use the executable in the following steps easily.

Here is an example of simple workflow to run actionlint on GitHub Actions. Please ensure shell: bash since the default shell for Windows runners is pwsh.

name: Lint GitHub Actions workflows
on: [push, pull_request]

jobs:
  actionlint:
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v2
      - name: Download actionlint
        id: get_actionlint
        run: bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)
        shell: bash
      - name: Check workflow files
        run: ${{ steps.get_actionlint.outputs.executable }}
        shell: bash

or simply run

- name: Check workflow files
  run: |
    bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)
    ./actionlint
  shell: bash

Build from source

Go toolchain is necessary. It builds the latest main branch.

# Install the latest version
go install github.com/rhysd/actionlint/cmd/actionlint@latest

# Install the head of main branch
go install github.com/rhysd/actionlint/cmd/actionlint

Usage

With no argument, actionlint finds all workflow files in the current repository and checks them.

actionlint

When paths to YAML workflow files are given, actionlint checks them.

actionlint path/to/workflow1.yaml path/to/workflow2.yaml

See actionlint -h for all flags and options.

Checks

This section describes all checks done by actionlint with example input and output.

Note that actionlint focuses on catching mistakes in workflow files. If you want some code style checks, please consider to use a general YAML checker like yamllint.

Unexpected keys

Example input:

on: push
jobs:
  test:
    runs-on: ubuntu-latest
    step:

Output:

test.yaml:5:5: unexpected key "step" for "job" section. expected one of "name", "needs", "runs-on", "permissions", "environment", "concurrency", "outputs", "env", "defaults", "if", "steps", "timeout-minutes", "strategy", "continue-on-error", "container", "services" [syntax-check]
5|     step:
 |     ^~~~~

Workflow syntax defines what keys can be defined in which mapping object. When other keys are defined, they are simply ignored and don't affect workflow behavior. It means typo in keys is not detected by GitHub.

actionlint can detect unexpected keys while parsing workflow syntax and report them as error.

Missing required keys or key duplicates

Example input:

on: push
jobs:
  test:
    steps:
      - run: echo 'hello'
  TEST:
    runs-on: ubuntu-latest
    steps:
      - run: echo 'bye'

Output:

test.yaml:6:3: key "test" is duplicate in "jobs" section. previously defined at line:3,col:3. note that key names are case insensitive [syntax-check]
6|   TEST:
 |   ^~~~~
test.yaml:4:5: "runs-on" section is missing in job "test" [syntax-check]
4|     steps:
 |     ^~~~~~

Some mappings must include specific keys. For example, job mapping must include runs-on: and steps:.

And duplicate in keys is not allowed. In workflow syntax, comparing keys is case insensitive. For example, job ID test in lower case and job ID TEST in upper case are not able to exist in the same workflow.

actionlint checks these missing required keys and duplicate of keys while parsing, and reports an error.

Unexpected empty mappings

Example input:

on: push
jobs:

Output:

test.yaml:2:6: "jobs" section should not be empty. please remove this section if it's unnecessary [syntax-check]
2| jobs:
 |      ^

Some mappings and sequences should not be empty. For example, steps: must include at least one step.

actionlint checks such mappings and sequences are not empty while parsing, and reports the empty mappings and sequences as error.

Unexpected mapping values

Example input:

on: push
jobs:
  test:
    runs-on: ubuntu-latest
    permissions:
      issues: foo
    continue-on-error: foo
    steps:
      - run: echo 'hello'

Output:

test.yaml:6:15: permission must be one of "none", "read", "write" but got "foo" [syntax-check]
6|       issues: foo
 |               ^~~
test.yaml:7:24: expecting a string with ${{...}} expression or boolean literal "true" or "false", but found plain text node [syntax-check]
7|     continue-on-error: foo
 |                        ^~~

Some mapping's values are restricted to some constant strings. For example, values of permissions: mappings should be one of none, read, write. And several mapping values expect boolean value like true or false.

actionlint checks such constant strings are used properly while parsing, and reports an error when unexpected string value is specified.

Syntax check for expression ${{ }}

Example input:

on: push
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      # " is not available for string literal delimiter
      - run: echo '${{ "hello" }}'
      # + operator does not exist
      - run: echo '${{ 1 + 1 }}'
      # Missing ')' paren
      - run: echo "${{ toJson(hashFiles('**/lock', '**/cache/') }}"
      # unexpected end of input
      - run: echo '${{ github.event. }}'

Output:

test.yaml:7:25: got unexpected character '"' while lexing expression, expecting '_', '\'', '}', '(', ')', '[', ']', '.', '!', '<', '>', '=', '&', ... [expression]
7|       - run: echo '${{ "hello" }}'
 |                         ^~~~~~
test.yaml:9:27: got unexpected character '+' while lexing expression, expecting '_', '\'', '}', '(', ')', '[', ']', '.', '!', '<', '>', '=', '&', ... [expression]
9|       - run: echo '${{ 1 + 1 }}'
 |                           ^
test.yaml:11:65: unexpected end of input while parsing arguments of function call. expecting ",", ")" [expression]
11|       - run: echo "${{ toJson(hashFiles('**/lock', '**/cache/') }}"
  |                                                                 ^~~
test.yaml:13:38: unexpected end of input while parsing object property dereference like 'a.b' or array element dereference like 'a.*'. expecting "IDENT", "*" [expression]
13|       - run: echo '${{ github.event. }}'
  |                                      ^~~

actionlint lexes and parses expression in ${{ }} following the expression syntax document. It can detect many syntax errors like invalid characters, missing parens, unexpected end of input, ...

Type checks for expression syntax in ${{ }}

Example input:

on: push
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      # Basic type error like index access to object
      - run: echo '${{ env[0] }}'
      # Properties in objects are strongly typed. So missing property can be caught
      - run: echo '${{ job.container.os }}'
      # github.repository is string. So accessing .owner is invalid
      - run: echo '${{ github.repository.owner }}'

Output:

test.yaml:7:28: property access of object must be type of string but got "number" [expression]
7|       - run: echo '${{ env[0] }}'
 |                            ^~
test.yaml:9:24: property "os" is not defined in object type {id: string; network: string} [expression]
9|       - run: echo '${{ job.container.os }}'
 |                        ^~~~~~~~~~~~~~~~
test.yaml:11:24: receiver of object dereference "owner" must be type of object but got "string" [expression]
11|       - run: echo '${{ github.repository.owner }}'
  |                        ^~~~~~~~~~~~~~~~~~~~~~~

Type checks for expression syntax in ${{ }} are done by semantics checker. Note that actual type checks by GitHub Actions runtime is loose. For example any object value can be assigned into string value as string "Object". But such loose conversions are bugs in almost all cases. actionlint checks types more strictly.

There are two types of object types internally. One is an object which is strict for properties, which causes a type error when trying to access to unknown properties. And another is an object which is not strict for properties, which allows to access to unknown properties. In the case, accessing to unknown property is typed as any.

When the type check cannot be done statically, the type is deduced to any (e.g. return type from toJSON()).

And ${{ }} can be used for expanding values.

Example input:

on: push
jobs:
  test:
    strategy:
      matrix:
        env_string:
          - 'FOO=BAR'
          - 'FOO=PIYO'
        env_object:
          - FOO: BAR
          - FOO: PIYO
    runs-on: ubuntu-latest
    steps:
      # Expanding object at 'env:' section
      - run: echo "$FOO"
        env: ${{ matrix.env_object }}
      # String value cannot be expanded as object
      - run: echo "$FOO"
        env: ${{ matrix.env_string }}

Output:

test.yaml:19:14: type of expression at "env" must be object but found type string [expression]
19|         env: ${{ matrix.env_string }}
  |              ^~~

In above example, environment variables mapping is expanded at env: section. actionlint checks type of the expanded value.

Contexts and built-in functions

Example input:

on: push
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      # Access to undefined context
      - run: echo '${{ unknown_context }}'
      # Access to undefined property of context
      - run: echo '${{ github.events }}'
      # Calling undefined function (start's'With is correct)
      - run: echo "${{ startWith('hello, world', 'lo,') }}"
      # Wrong number of arguments
      - run: echo "${{ startsWith('hello, world') }}"
      # Wrong type of parameter
      - run: echo "${{ startsWith('hello, world', github.event) }}"
      # Function overloads can be handled properly. contains() has string version and array version
      - run: echo "${{ contains('hello, world', 'lo,') }}"
      - run: echo "${{ contains(github.event.labels.*.name, 'enhancement') }}"
      # format() has special check for formating string
      - run: echo "${{ format('{0}{1}', 1, 2, 3) }}"

Output:

test.yaml:7:24: undefined variable "unknown_context". available variables are "env", "github", "job", "matrix", "needs", "runner", "secrets", "steps", "strategy" [expression]
7|       - run: echo '${{ unknown_context }}'
 |                        ^~~~~~~~~~~~~~~
test.yaml:9:24: property "events" is not defined in object type {workspace: string; env: string; event_name: string; event_path: string; ...} [expression]
9|       - run: echo '${{ github.events }}'
 |                        ^~~~~~~~~~~~~
test.yaml:11:24: undefined function "startWith". available functions are "always", "cancelled", "contains", "endswith", "failure", "format", "fromjson", "hashfiles", "join", "startswith", "success", "tojson" [expression]
11|       - run: echo "${{ startWith('hello, world', 'lo,') }}"
  |                        ^~~~~~~~~~~~~~~~~
test.yaml:13:24: number of arguments is wrong. function "startsWith(string, string) -> bool" takes 2 parameters but 1 arguments are provided [expression]
13|       - run: echo "${{ startsWith('hello, world') }}"
  |                        ^~~~~~~~~~~~~~~~~~
test.yaml:15:51: 2nd argument of function call is not assignable. "object" cannot be assigned to "string". called function type is "startsWith(string, string) -> bool" [expression]
15|       - run: echo "${{ startsWith('hello, world', github.event) }}"
  |                                                   ^~~~~~~~~~~~~
test.yaml:20:24: format string "{0}{1}" contains 2 placeholders but 3 arguments are given to format [expression]
20|       - run: echo "${{ format('{0}{1}', 1, 2, 3) }}"
  |                        ^~~~~~~~~~~~~~~~

Contexts and built-in functions are strongly typed. Typos in property access of contexts and function names can be checked. And invalid function calls like wrong number of arguments or type mismatch at parameter also can be checked thanks to type checker.

The semantics checker can properly handle that

  • some functions are overloaded (e.g. contains(str, substr) and contains(array, item))
  • some parameters are optional (e.g. join(strings, sep) and join(strings))
  • some parameters are repeatable (e.g. hashFiles(file1, file2, ...))

In addition, format() function has special check for placeholders in the first parameter which represents formatting string.

Note that context names and function names are case insensitive. For example, toJSON and toJson are the same function.

Contextual typing for steps.<step_id> objects

Example input:

on: push
jobs:
  test:
    runs-on: ubuntu-latest
    outputs:
      # Step outputs can be used in job outputs since this section is evaluated after all steps were run
      foo: '${{ steps.get_value.outputs.name }}'
    steps:
      # Access to undefined step outputs
      - run: echo '${{ steps.get_value.outputs.name }}'
      # Outputs are set here
      - run: echo '::set-output name=foo::value'
        id: get_value
      # OK
      - run: echo '${{ steps.get_value.outputs.name }}'
      # OK
      - run: echo '${{ steps.get_value.conclusion }}'
  other:
    runs-on: ubuntu-latest
    steps:
      # Access to undefined step outputs. Step objects are job-local
      - run: echo '${{ steps.get_value.outputs.name }}'

Output:

test.yaml:10:24: property "get_value" is not defined in object type {} [expression]
10|       - run: echo '${{ steps.get_value.outputs.name }}'
  |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.yaml:22:24: property "get_value" is not defined in object type {} [expression]
22|       - run: echo '${{ steps.get_value.outputs.name }}'
  |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~

Outputs of step can be accessed via steps.<step_id> objects. The steps context is dynamic:

  • Accessing to the outputs before running the step are null
  • Outputs of steps only in the job can be accessed. It cannot access to steps across jobs

It is actually common mistake to access to the wrong step outputs since people often forget fixing placeholders on copying&pasting steps.

actionlint can catch the invalid accesses to step outputs and reports them as errors.

Contextual typing for matrix object

Example input:

on: push
jobs:
  test:
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest]
        node: [14, 15]
        package:
          - name: 'foo'
            optional: true
          - name: 'bar'
            optional: false
        include:
          - node: 15
            npm: 7.5.4
    runs-on: ${{ matrix.os }}
    steps:
      # Access to undefined matrix value
      - run: echo '${{ matrix.platform }}'
      # Matrix value is strongly typed. Below line causes an error since matrix.package is {name: string, optional: bool}
      - run: echo '${{ matrix.package.dev }}'
      # OK
      - run: |
          echo 'os: ${{ matrix.os }}'
          echo 'node version: ${{ matrix.node }}'
          echo 'package: ${{ matrix.package.name }} (optional=${{ matrix.package.optional }})'
      # Additional matrix values in 'include:' are supported
      - run: echo 'npm version is specified'
        if: ${{ contains(matrix.npm, '7.5') }}
  test2:
    runs-on: ubuntu-latest
    steps:
      # Matrix values in other job is not accessible
      - run: echo '${{ matrix.os }}'

Output:

test.yaml:19:24: property "platform" is not defined in object type {os: string; node: number; package: {name: string; optional: bool}; npm: string} [expression]
19|       - run: echo '${{ matrix.platform }}'
  |                        ^~~~~~~~~~~~~~~
test.yaml:21:24: property "dev" is not defined in object type {name: string; optional: bool} [expression]
21|       - run: echo '${{ matrix.package.dev }}'
  |                        ^~~~~~~~~~~~~~~~~~
test.yaml:34:24: property "os" is not defined in object type {} [expression]
34|       - run: echo '${{ matrix.os }}'
  |                        ^~~~~~~~~

Types of matrix context is contextually checked by the semantics checker. Type of matrix values in matrix: section is deduced from element values of its array. When the matrix value is an array of objects, objects' properties are checked strictly like package.name in above example.

When type of the array elements is not persistent, type of the matrix value falls back to any.

strategy:
  matrix:
    foo:
      - 'string value'
      - 42
      - {aaa: true, bbb: null}
    bar:
      - [42]
      - [true]
      - [{aaa: true, bbb: null}]
      - []
steps:
  # matrix.foo is any type value
  - run: echo ${{ matrix.foo }}
  # matrix.bar is array<any> type value
  - run: echo ${{ matrix.bar[0] }}

Contextual typing for needs object

Example input:

on: push
jobs:
  install:
    outputs:
      installed: '...'
    runs-on: ubuntu-latest
    steps:
      - run: echo 'install something'
  prepare:
    outputs:
      prepared: '...'
    runs-on: ubuntu-latest
    steps:
      - run: echo 'parepare something'
      # ERROR: Outputs in other job is not accessble
      - run: echo '${{ needs.prepare.outputs.prepared }}'
  build:
    needs: [install, prepare]
    outputs:
      built: '...'
    runs-on: ubuntu-latest
    steps:
      # OK: Accessing to job results
      - run: echo 'build something with ${{ needs.install.outputs.installed }} and ${{ needs.prepare.outputs.prepared }}'
      # ERROR: Accessing to undefined output cases an error
      - run: echo '${{ needs.install.outputs.foo }}'
      # ERROR: Accessing to undefined job ID
      - run: echo '${{ needs.some_job }}'
  other:
    runs-on: ubuntu-latest
    steps:
      # ERROR: Cannot access to outptus across jobs
      - run: echo '${{ needs.build.outputs.built }}'

Output:

test.yaml:16:24: property "prepare" is not defined in object type {} [expression]
16|       - run: echo '${{ needs.prepare.outputs.prepared }}'
  |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.yaml:26:24: property "foo" is not defined in object type {installed: string} [expression]
26|       - run: echo '${{ needs.install.outputs.foo }}'
  |                        ^~~~~~~~~~~~~~~~~~~~~~~~~
test.yaml:28:24: property "some_job" is not defined in object type {install: {outputs: {installed: string}; result: string}; prepare: {outputs: {prepared: string}; result: string}} [expression]
28|       - run: echo '${{ needs.some_job }}'
  |                        ^~~~~~~~~~~~~~
test.yaml:33:24: property "build" is not defined in object type {} [expression]
33|       - run: echo '${{ needs.build.outputs.built }}'
  |                        ^~~~~~~~~~~~~~~~~~~~~~~~~

Job dependencies can be defined at needs:. A job runs after all jobs defined in needs: are done. Outputs from the jobs can be accessed only from jobs following them via needs context.

actionlint defines type of needs variable contextually looking at each job's outputs: section and needs: section.

shellcheck integration for run:

Example input:

on: push
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - run: echo $FOO
  test-win:
    runs-on: windows-latest
    steps:
      # Shell on Windows is PowerShell by default.
      # shellcheck is not run in this case.
      - run: echo $FOO
      # This script is run with bash due to 'shell:' configuration
      - run: echo $FOO
        shell: bash

Output:

test.yaml:6:9: shellcheck reported issue in this script: SC2086:info:1:6: Double quote to prevent globbing and word splitting [shellcheck]
6|       - run: echo $FOO
 |         ^~~~
test.yaml:14:9: shellcheck reported issue in this script: SC2086:info:1:6: Double quote to prevent globbing and word splitting [shellcheck]
14|       - run: echo $FOO
  |         ^~~~

shellcheck is a famous linter for ShellScript. actionlint runs shellcheck for scripts at run: step in workflow. For installing shellcheck, see the official installation document.

actionlint detects which shell is used to run the scripts following the documentation. On Linux or macOS, the default shell is bash and on Windows it is pwsh. Shell can be configured by shell: configuration at workflow level or job level. Each step can configure shell to run scripts by shell:.

actionlint remembers the default shell and checks what OS the job runs on. Only when the shell is bash or sh, actionlint applies shellcheck to scripts.

By default, actionlint checks if shellcheck command exists in your system and uses it when it is found. The -shellcheck option on running actionlint command specifies the executable path of shellcheck. Setting empty string by shellcheck= disables shellcheck integration explicitly.

Since both ${{ }} expression syntax and ShellScript's variable access $FOO use $, remaining ${{ }} confuses shellcheck. To avoid it, actionlint replaces ${{ }} with underscores. For example echo '${{ matrix.os }}' is replaced with echo '________________'.

pyflakes integration for run:

Example input:

on: push
jobs:
  linux:
    runs-on: ubuntu-latest
    steps:
      # Yay! No error
      - run: print('${{ runner.os }}')
        shell: python
      # ERROR: Undefined variable
      - run: print(hello)
        shell: python
  linux2:
    runs-on: ubuntu-latest
    defaults:
      run:
        # Run script with Python by default
        shell: python
    steps:
      - run: |
          import sys
          for sys in ['system1', 'system2']:
            print(sys)
      - run: |
          from time import sleep
          print(100)

Output:

test.yaml:10:9: pyflakes reported issue in this script: 1:7 undefined name 'hello' [pyflakes]
10|       - run: print(hello)
  |         ^~~~
test.yaml:19:9: pyflakes reported issue in this script: 2:5 import 'sys' from line 1 shadowed by loop variable [pyflakes]
19|       - run: |
  |         ^~~~
test.yaml:23:9: pyflakes reported issue in this script: 1:1 'time.sleep' imported but unused [pyflakes]
23|       - run: |
  |         ^~~~

Python script can be written in run: when shell: python is configured.

pyflakes is a famous linter for Python. It is suitable for linting small code like scripts at run: since it focuses on finding mistakes (not a code style issue) and tries to make false positives as minimal as possible. Install pyflakes by pip install pyflakes.

actionlint runs pyflakes for scripts at run: steps in workflow and reports errors found by pyflakes. actionlint detects Python scripts in workflow by checking shell: python at steps and defaults: configurations at workflows and jobs.

By default, actionlint checks if pyflakes command exists in your system and uses it when found. The -pyflakes option of actionlint command allows to specify the executable path of pyflakes. Setting empty string by pyflakes= disables pyflakes integration explicitly.

Since both ${{ }} expression syntax is invalid as Python, remaining ${{ }} might confuse pyflakes. To avoid it, actionlint replaces ${{ }} with underscores. For example print('${{ matrix.os }}') is replaced with print('________________').

Job dependencies validation

Example input:

on: push
jobs:
  prepare:
    needs: [build]
    runs-on: ubuntu-latest
    steps:
      - run: echo 'prepare'
  install:
    needs: [prepare]
    runs-on: ubuntu-latest
    steps:
      - run: echo 'install'
  build:
    needs: [install]
    runs-on: ubuntu-latest
    steps:
      - run: echo 'build'

Output:

test.yaml:8:3: cyclic dependencies in "needs" configurations of jobs are detected. detected cycle is "install" -> "prepare", "prepare" -> "build", "build" -> "install" [job-needs]
8|   install:
 |   ^~~~~~~~

Job dependencies can be defined at needs:. If cyclic dependencies exist, jobs never start to run. actionlint detects cyclic dependencies in needs: sections of jobs and reports it as error.

actionlint also detects undefined jobs and duplicate jobs in needs: section.

Example input:

on: push
jobs:
  foo:
    needs: [bar, BAR]
    runs-on: ubuntu-latest
    steps:
      - run: echo 'hi'
  bar:
    needs: [unknown]
    runs-on: ubuntu-latest
    steps:
      - run: echo 'hi'

Output:

test.yaml:4:18: job ID "BAR" duplicates in "needs" section. note that job ID is case insensitive [job-needs]
4|     needs: [bar, BAR]
 |                  ^~~~
test.yaml:8:3: job "bar" needs job "unknown" which does not exist in this workflow [job-needs]
8|   bar:
 |   ^~~~

Matrix values

Example input:

on: push
jobs:
  test:
    strategy:
      matrix:
        node: [10, 12, 14, 14]
        os: [ubuntu-latest, macos-latest]
        exclude:
          - node: 13
            os: ubuntu-latest
          - node: 10
            platform: ubuntu-latest
    runs-on: ${{ matrix.os }}
    steps:
      - run: echo ...

Output:

test.yaml:6:28: duplicate value "14" is found in matrix "node". the same value is at line:6,col:24 [matrix]
6|         node: [10, 12, 14, 14]
 |                            ^~~
test.yaml:9:19: value "13" in "exclude" does not exist in matrix "node" combinations. possible values are "10", "12", "14", "14" [matrix]
9|           - node: 13
 |                   ^~
test.yaml:12:13: "platform" in "exclude" section does not exist in matrix. available matrix configurations are "node", "os" [matrix]
12|             platform: ubuntu-latest
  |             ^~~~~~~~~

matrix: defines combinations of multiple values. Nested include: and exclude: can add/remove specific combination of matrix values. actionlint checks

  • values in exclude: appear in matrix: or include:
  • duplicate in variations of matrix values

Webhook events validation

Example input:

on:
  push:
    # Unexpected filter. 'branches' is correct
    branch: foo
  issues:
    # Unexpected type. 'opened' is correct
    types: created
  pullreq:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - run: echo ...

Output:

test.yaml:4:5: unexpected key "branch" for "push" section. expected one of "types", "branches", "branches-ignore", "tags", "tags-ignore", ... [syntax-check]
4|     branch: foo
 |     ^~~~~~~
test.yaml:7:12: invalid activity type "created" for "issues" Webhook event. available types are "opened", "edited", "deleted", "transferred", ... [events]
7|     types: created
 |            ^~~~~~~
test.yaml:8:3: unknown Webhook event "pullreq". see https://docs.github.com/en/actions/reference/events-that-trigger-workflows#webhook-events for list of all Webhook event names [events]
8|   pullreq:
 |   ^~~~~~~~

At on:, Webhook events can be specified to trigger the workflow. Webhook event documentation defines which Webhook events are available and what types can be specified at types: for each event.

actionlint validates the Webhook configurations:

  • unknown Webhook event name
  • unknown type for Webhook event
  • invalid filter names

CRON syntax check at schedule:

Example input:

on:
  schedule:
    # Cron syntax is not correct
    - cron: '0 */3 * *'
    # Interval of scheduled job is too small (job runs too frequently)
    - cron: '* */3 * * *'

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - run: echo ...

Output:

test.yaml:4:13: invalid CRON format "0 */3 * *" in schedule event: Expected exactly 5 fields, found 4: 0 */3 * * [events]
4|     - cron: '0 */3 * *'
 |             ^~
test.yaml:6:13: scheduled job runs too frequently. it runs once per 60 seconds [events]
6|     - cron: '* */3 * * *'
 |             ^~

To trigger a workflow in specific interval, scheduled event can be defined in POSIX CRON syntax.

actionlint checks the CRON syntax and frequency of running the job. When a job is run more frequently than once per 1 minute, actionlint reports it as error.

Runner labels

Example input:

on: push
jobs:
  test:
    strategy:
      matrix:
        runner:
          # OK
          - macos-latest
          # ERROR: Unknown runner
          - linux-latest
          # OK: Preset labels for self-hosted runner
          - [self-hosted, linux, x64]
          # OK: Single preset label for self-hosted runner
          - arm64
          # ERROR: Unknown label "gpu". Custom label must be defined in actionlint.yaml config file
          - gpu
    runs-on: ${{ matrix.runner }}
    steps:
      - run: echo ...

  test2:
    # ERROR: Too old macOS worker
    runs-on: macos-10.13
    steps:
      - run: echo ...

Output:

test.yaml:10:13: label "linux-latest" is unknown. available labels are "windows-latest", "windows-2019", "windows-2016", "ubuntu-latest", ... [runner-label]
10|           - linux-latest
  |             ^~~~~~~~~~~~
test.yaml:16:13: label "gpu" is unknown. available labels are "windows-latest", "windows-2019", "windows-2016", "ubuntu-latest", ... [runner-label]
16|           - gpu
  |             ^~~
test.yaml:23:14: label "macos-10.13" is unknown. available labels are "windows-latest", "windows-2019", "windows-2016", "ubuntu-latest", ... [runner-label]
23|     runs-on: macos-10.13
  |              ^~~~~~~~~~~

GitHub Actions provides two kinds of job runners, GitHub-hosted runner and self-hosted runner. Each runner has one or more labels. GitHub Actions runtime finds a proper runner based on label(s) specified at runs-on: to run the job. So specifying proper labels at runs-on: is important.

actionlint checks proper label is used at runs-on: configuration. Even if an expression is used in the section like runs-on: ${{ matrix.foo }}, actionlint parses the expression and resolves the possible values, then validates the values.

When you define some custom labels for your self-hosted runner, actionlint does not know the labels. Please set the label names in actionlint.yaml configuration file to let actionlint know them.

Action format in uses:

Example input:

on: push
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      # ERROR: ref is missing
      - uses: actions/checkout
      # ERROR: owner name is missing
      - uses: checkout@v2
      # ERROR: tag is empty
      - uses: 'docker://image:'
      # ERROR: local action does not exist
      - uses: ./github/actions/my-action

Output:

test.yaml:7:15: specifying action "actions/checkout" in invalid format because ref is missng. available formats are "{owner}/{repo}@{ref}" or "{owner}/{repo}/{path}@{ref}" [action]
7|       - uses: actions/checkout
 |               ^~~~~~~~~~~~~~~~
test.yaml:9:15: specifying action "checkout@v2" in invalid format because owner is missing. available formats are "{owner}/{repo}@{ref}" or "{owner}/{repo}/{path}@{ref}" [action]
9|       - uses: checkout@v2
 |               ^~~~~~~~~~~
test.yaml:11:15: tag of Docker action should not be empty: "docker://image" [action]
11|       - uses: 'docker://image:'
  |               ^~~~~~~~~~~~~~~~~
test.yaml:13:15: Neither action.yaml nor action.yml is found in directory "github/actions/my-action" [action]
13|       - uses: ./github/actions/my-action
  |               ^~~~~~~~~~~~~~~~~~~~~~~~~~

Action needs to be specified in a format defined in the document. There are 3 types of actions:

  • action hosted on GitHub: owner/repo/path@ref
  • local action: ./path/to/my-action
  • Docker action: docker://image:tag

actionlint checks values at uses: sections follow one of these formats.

Local action inputs validation at with:

.github/actions/my-action/action.yaml:

name: 'My action'
author: 'rhysd <https://rhysd.github.io>'
description: 'my action'

inputs:
  name:
    description: your name
    default: anonymous
  message:
    description: message to this action
    required: true
  addition:
    description: additional information
    required: false

runs:
  using: 'node14'
  main: 'index.js'

Example input:

on: push
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      # missing required input "message"
      - uses: ./.github/actions/my-action
      # unexpected input "additions"
      - uses: ./.github/actions/my-action
        with:
          name: rhysd
          message: hello
          additions: foo, bar

Output:

test.yaml:7:15: missing input "message" which is required by action "My action" defined at "./.github/actions/my-action" [action]
7|       - uses: ./.github/actions/my-action
 |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~
test.yaml:13:11: input "additions" is not defined in action "./.github/actions/my-action" defined at "My action". available inputs are "addition", "message", "name" [action]
13|           additions: foo, bar
  |           ^~~~~~~~~~

When a local action is run in uses: of step:, actionlint reads action.yaml file in the local action directory and validates inputs at with: in the workflow are correct. Missing required inputs and unexpected inputs can be detected.

Shell name validation at shell:

Example input:

on: push
jobs:
  linux:
    runs-on: ubuntu-latest
    steps:
      - run: echo 'hello'
        # ERROR: Unavailable shell
        shell: dash
      - run: echo 'hello'
        # ERROR: 'powershell' is only available on Windows
        shell: powershell
      - run: echo 'hello'
        # OK: 'powershell' is only available on Windows
        shell: powershell
  mac:
    runs-on: macos-latest
    defaults:
      run:
        # ERROR: default config is also checked. fish is not supported
        shell: fish
    steps:
      - run: echo 'hello'
        # OK: Custom shell
        shell: 'perl {0}'
  windows:
    runs-on: windows-latest
    steps:
      - run: echo 'hello'
        # ERROR: 'sh' is only available on Windows
        shell: sh

Output:

test.yaml:8:16: shell name "dash" is invalid. available names are "bash", "pwsh", "python", "sh" [shell-name]
8|         shell: dash
 |                ^~~~
test.yaml:11:16: shell name "powershell" is invalid on macOS or Linux. available names are "bash", "pwsh", "python", "sh" [shell-name]
11|         shell: powershell
  |                ^~~~~~~~~~
test.yaml:14:16: shell name "powershell" is invalid on macOS or Linux. available names are "bash", "pwsh", "python", "sh" [shell-name]
14|         shell: powershell
  |                ^~~~~~~~~~
test.yaml:20:16: shell name "fish" is invalid. available names are "bash", "pwsh", "python", "sh" [shell-name]
20|         shell: fish
  |                ^~~~
test.yaml:30:16: shell name "sh" is invalid on Windows. available names are "bash", "pwsh", "python", "cmd", "powershell" [shell-name]
30|         shell: sh
  |                ^~

Available shells for runners are defined in the documentation. actionlint checks shell names at shell: configuration are properly using the available shells.

Job ID and step ID uniqueness

Example input:

on: push
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - run: echo 'hello'
        id: step_id
      - run: echo 'bye'
        # ERROR: Duplicate of step ID
        id: STEP_ID
  # ERROR: Duplicate of job ID
  TEST:
    runs-on: ubuntu-latest
    steps:
      - run: echo 'hello'
        # OK. Step ID uniqueness is job-local
        id: step_id

Output:

test.yaml:12:3: key "test" is duplicate in "jobs" section. previously defined at line:3,col:3. note that key names are case insensitive [syntax-check]
12|   TEST:
  |   ^~~~~
test.yaml:10:13: step ID "line:7,col:13" duplicates. previously defined at STEP_ID. step ID must be unique within a job. note that step ID is case insensitive [step-id]
10|         id: STEP_ID
  |             ^~~~~~~

Job IDs and step IDs in each job must be unique. IDs are compared in case insensitive. actionlint checks all job IDs and step IDs and reports errors when some IDs duplicate.

Hardcoded credentials

Example input:

on: push
jobs:
  test:
    runs-on: ubuntu-latest
    container:
      image: 'example.com/owner/image'
      credentials:
        username: user
        # ERROR: Hardcoded password
        password: pass
    services:
      redis:
        image: redis
        credentials:
          username: user
          # ERROR: Hardcoded password
          password: pass
    steps:
      - run: echo 'hello'

Output:

test.yaml:10:19: "password" section in "container" section should be specified via secrets. do not put password value directly [credentials]
10|         password: pass
  |                   ^~~~
test.yaml:17:21: "password" section in "redis" service should be specified via secrets. do not put password value directly [credentials]
17|           password: pass
  |                     ^~~~

Credentials for container can be put in container: configuration. Password should be put in secrets and the value should be expanded with ${{ }} syntax at password:. actionlint checks hardcoded credentials and reports them as error.

Environment variable names

Example input:

on: push
jobs:
  test:
    runs-on: ubuntu-latest
    env:
      FOO=BAR: foo
      FOO BAR: foo
    steps:
      - run: echo 'hello'

Output:

test.yaml:6:7: environment variable name "foo=bar" is invalid. '&', '=' and spaces should not be contained [env-var]
6|       FOO=BAR: foo
 |       ^~~~~~~~
test.yaml:7:7: environment variable name "foo bar" is invalid. '&', '=' and spaces should not be contained [env-var]
7|       FOO BAR: foo
 |       ^~~

= must not be included in environment variable names. And & and spaces should not be included in them. In almost all cases they are mistakes and they may cause some issues on using them in shell since they have special meaning in shell syntax.

actionlint checks environment variable names are correct in env: configuration.

Configuration file

Configuration file actionlint.yaml or actionlint.yml can be put in .github directory.

You don't need to write first configuration file by your hand. actionlint command can generate a default configuration.

actionlint -init-config
vim .github/actionlint.yaml

Since the author tries to keep configuration file as minimal as possible, currently only one item can be configured.

self-hosted-runner:
  # Labels of self-hosted runner in array of string
  labels:
    - linux.2xlarge
    - windows-latest-xl
    - linux-multi-gpu
  • self-hosted-runner: Configuration for your self-hosted runner environment
    • labels: Label names added to your self-hosted runners as list of string

Note that configuration file is optional. The author tries to keep configuration file as minimal as possible not to bother users to configure behavior of actionlint. Running actionlint without configuration file would work fine in most cases.

Use actionlint as library

actionlint can be used from Go programs. See the documentation to know the list of all APIs. It contains workflow file parser built on top of go-yaml/yaml, expression ${{ }} lexer/parser/checker, etc. Followings are unexhaustive list of interesting APIs.

  • Linter manages linter lifecycle and applies checks to given files. If you want to run actionlint checks in your program, please use this struct.
  • Project and Projects detect a project (Git repository) in a given directory path and find configuration in it.
  • Config represents structure of actionlint.yaml config file. It can be decoded by go-yaml/yaml library.
  • Workflow, Job, Step, ... are nodes of workflow syntax tree. Workflow is a root node.
  • Parse() parses given contents into a workflow syntax tree. It tries to find syntax errors as much as possible and returns found errors as slice.
  • Pass is a visitor to traverse a workflow syntax tree. Multiple passes can be applied at single pass using Visitor.
  • Rule is an interface for rule checkers and RuneBase is a base struct to implement a rule checker.
    • RuleExpression is a rule checker to check expression syntax in ${{ }}.
    • RuleShellcheck is a rule checker to apply shellcheck command to run: sections and collect errors from it.
    • RuleJobNeeds is a rule checker to check dependencies in needs: section. It can detect cyclic dependencies.
    • ...
  • ExprLexer lexes expression syntax in ${{ }} and returns slice of Token.
  • ExprParser parses given slice of Token and returns syntax tree for expression in ${{ }}. ExprNode is an interface for nodes in the expression syntax tree.
  • ExprType is an interface of types in expression syntax ${{ }}. ObjectType, ArrayType, StringType, NumberType, ... are structs to represent actual types of expression.
  • ExprSemanticsChecker checks semantics of expression syntax ${{ }}. It traverses given expression syntax tree and deduces its type, checking types and resolving variables (contexts).

Note that the version of this repository is for command line tool actionlint. So it does not represent version of the library, meant that patch version bump may introduce some breaking changes.

Testing

  • All examples in 'Checks' section are tested in example_test.go
  • I cloned GitHub top 1000 repositories and extracted 1400+ workflow files. And I tried actionlint with the collected workflow files. All bugs found while the trial were fixed and I confirmed no more false positives.

Bug reporting

When you 're seeing some bugs or false positives, it is helpful to file a new issue with a minimal example of input. Giving me some feedbacks like feature requests or idea of additional checks is also welcome.

License

actionlint is distributed under the MIT license.

Documentation

Index

Constants

View Source
const (
	// RawYAMLValueKindObject is kind for an object value of raw YAML value.
	RawYAMLValueKindObject = RawYAMLValueKind(yaml.MappingNode)
	// RawYAMLValueKindArray is kind for an array value of raw YAML value.
	RawYAMLValueKindArray = RawYAMLValueKind(yaml.SequenceNode)
	// RawYAMLValueKindString is kind for a string value of raw YAML value.
	RawYAMLValueKindString = RawYAMLValueKind(yaml.ScalarNode)
)
View Source
const (
	// LogLevelNone does not output any log output.
	LogLevelNone LogLevel = 0
	// LogLevelVerbose shows verbose log output. This is equivalent to specifying -verbose option
	// to actionlint command.
	LogLevelVerbose = 1
	// LogLevelDebug shows all log output including debug information.
	LogLevelDebug = 2
)

Variables

View Source
var BuiltinFuncSignatures = map[string][]*FuncSignature{
	"contains": {
		{
			Name: "contains",
			Ret:  BoolType{},
			Params: []ExprType{
				StringType{},
				StringType{},
			},
		},
		{
			Name: "contains",
			Ret:  BoolType{},
			Params: []ExprType{
				&ArrayType{Elem: AnyType{}},
				AnyType{},
			},
		},
	},
	"startswith": {
		{
			Name: "startsWith",
			Ret:  BoolType{},
			Params: []ExprType{
				StringType{},
				StringType{},
			},
		},
	},
	"endswith": {
		{
			Name: "endsWith",
			Ret:  BoolType{},
			Params: []ExprType{
				StringType{},
				StringType{},
			},
		},
	},
	"format": {
		{
			Name: "format",
			Ret:  StringType{},
			Params: []ExprType{
				StringType{},
				AnyType{},
			},
			VariableLengthParams: true,
		},
	},
	"join": {
		{
			Name: "join",
			Ret:  StringType{},
			Params: []ExprType{
				&ArrayType{Elem: StringType{}},
				StringType{},
			},
		},
		{
			Name: "join",
			Ret:  StringType{},
			Params: []ExprType{
				StringType{},
				StringType{},
			},
		},

		{
			Name: "join",
			Ret:  StringType{},
			Params: []ExprType{
				&ArrayType{Elem: StringType{}},
			},
		},
		{
			Name: "join",
			Ret:  StringType{},
			Params: []ExprType{
				StringType{},
			},
		},
	},
	"tojson": {{
		Name: "toJSON",
		Ret:  StringType{},
		Params: []ExprType{
			AnyType{},
		},
	}},
	"fromjson": {{
		Name: "fromJSON",
		Ret:  AnyType{},
		Params: []ExprType{
			StringType{},
		},
	}},
	"hashfiles": {{
		Name: "hashFiles",
		Ret:  StringType{},
		Params: []ExprType{
			StringType{},
		},
		VariableLengthParams: true,
	}},
	"success": {{
		Name:   "success",
		Ret:    BoolType{},
		Params: []ExprType{},
	}},
	"always": {{
		Name:   "always",
		Ret:    BoolType{},
		Params: []ExprType{},
	}},
	"cancelled": {{
		Name:   "cancelled",
		Ret:    BoolType{},
		Params: []ExprType{},
	}},
	"failure": {{
		Name:   "failure",
		Ret:    BoolType{},
		Params: []ExprType{},
	}},
}

BuiltinFuncSignatures is a set of all builtin function signatures. All function names are in lower case because function names are compared in case insensitive. https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#functions

View Source
var BuiltinGlobalVariableTypes = map[string]ExprType{

	"github": &ObjectType{
		Props: map[string]ExprType{
			"action":           StringType{},
			"action_path":      StringType{},
			"actor":            StringType{},
			"base_ref":         StringType{},
			"event":            NewObjectType(),
			"event_name":       StringType{},
			"event_path":       StringType{},
			"head_ref":         StringType{},
			"job":              StringType{},
			"ref":              StringType{},
			"repository":       StringType{},
			"repository_owner": StringType{},
			"run_id":           StringType{},
			"run_number":       StringType{},
			"sha":              StringType{},
			"token":            StringType{},
			"workflow":         StringType{},
			"workspace":        StringType{},

			"action_ref":        StringType{},
			"action_repository": StringType{},
			"api_url":           StringType{},
			"env":               StringType{},
			"graphql_url":       StringType{},
			"path":              StringType{},
			"repositoryurl":     StringType{},
			"retention_days":    NumberType{},
			"server_url":        StringType{},
		},
		StrictProps: true,
	},

	"env": NewObjectType(),

	"job": &ObjectType{
		Props: map[string]ExprType{
			"container": &ObjectType{
				Props: map[string]ExprType{
					"id":      StringType{},
					"network": StringType{},
				},
				StrictProps: true,
			},
			"services": NewObjectType(),
			"status":   StringType{},
		},
		StrictProps: true,
	},

	"steps": NewStrictObjectType(),

	"runner": &ObjectType{
		Props: map[string]ExprType{
			"os":         StringType{},
			"temp":       StringType{},
			"tool_cache": StringType{},

			"workspace": StringType{},
		},
		StrictProps: true,
	},

	"secrets": NewObjectType(),

	"strategy": &ObjectType{
		Props: map[string]ExprType{
			"fail-fast":    BoolType{},
			"job-index":    NumberType{},
			"job-total":    NumberType{},
			"max-parallel": NumberType{},
		},
	},

	"matrix": NewStrictObjectType(),

	"needs": NewStrictObjectType(),
}

BuiltinGlobalVariableTypes defines types of all global variables. All context variables are documented at https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#contexts

Functions

func Parse

func Parse(b []byte) (*Workflow, []*Error)

Parse parses given source as byte sequence into workflow syntax tree. It returns all errors detected while parsing the input. It means that detecting one error does not stop parsing. Even if one or more errors are detected, parser will try to continue parsing and finding more errors.

Types

type ActionSpec

type ActionSpec struct {
	// Name is "name" field of action.yaml
	Name string `yaml:"name"`
	// Inputs is "inputs" field of action.yaml
	Inputs map[string]struct {
		Required bool    `yaml:"required"`
		Default  *string `yaml:"default"`
	} `yaml:"inputs"`
	// Outputs is "outputs" field of action.yaml
	Outputs map[string]struct{} `yaml:"outputs"`
}

ActionSpec represents structure of action.yaml. https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions

type AnyType

type AnyType struct{}

AnyType represents type which can be any type. It also indicates that a value of the type cannot be type-checked since it's type cannot be known statically.

func (AnyType) Assignable

func (ty AnyType) Assignable(_ ExprType) bool

Assignable returns if other type can be assignable to the type.

func (AnyType) Equals

func (ty AnyType) Equals(other ExprType) bool

Equals returns if the type is equal to the other type.

func (AnyType) Fuse

func (ty AnyType) Fuse(other ExprType) ExprType

Fuse merges other type into this type. When other type conflicts with this type, fused result is any type as fallback.

func (AnyType) String

func (ty AnyType) String() string

type ArrayDerefNode

type ArrayDerefNode struct {
	// Receiver is an expression at receiver of array element dereference.
	Receiver ExprNode
}

ArrayDerefNode represents elements dereference of arrays like '*' in 'foo.bar.*.piyo'.

func (ArrayDerefNode) Token

func (n ArrayDerefNode) Token() *Token

Token returns the first token of the node. This method is useful to get position of this node.

type ArrayType

type ArrayType struct {
	// Elem is type of element of the array.
	Elem ExprType
	// Deref is true when this type was derived from array filter syntax (foo.*).
	Deref bool
}

ArrayType is type for arrays.

func (*ArrayType) Assignable

func (ty *ArrayType) Assignable(other ExprType) bool

Assignable returns if other type can be assignable to the type.

func (*ArrayType) Equals

func (ty *ArrayType) Equals(other ExprType) bool

Equals returns if the type is equal to the other type.

func (*ArrayType) Fuse

func (ty *ArrayType) Fuse(other ExprType) ExprType

Fuse merges two object types into one. When other object has unknown props, they are merged into current object. When both have same property, when they are assignable, it remains as-is. Otherwise, the property falls back to any type. Note that this method modifies itself destructively for efficiency.

func (*ArrayType) String

func (ty *ArrayType) String() string

type Bool

type Bool struct {
	// Value is a raw value of the bool string.
	Value bool
	// Expression is a string when expression syntax ${{ }} is used for this section.
	Expression *String
	// Pos is a position in source.
	Pos *Pos
}

Bool represents generic boolean value in YAML file with position.

type BoolNode

type BoolNode struct {
	// Value is value of the boolean literal.
	Value bool
	// contains filtered or unexported fields
}

BoolNode is node for boolean literal, true or false.

func (*BoolNode) Token

func (n *BoolNode) Token() *Token

Token returns the first token of the node. This method is useful to get position of this node.

type BoolType

type BoolType struct{}

BoolType is type for boolean values.

func (BoolType) Assignable

func (ty BoolType) Assignable(other ExprType) bool

Assignable returns if other type can be assignable to the type.

func (BoolType) Equals

func (ty BoolType) Equals(other ExprType) bool

Equals returns if the type is equal to the other type.

func (BoolType) Fuse

func (ty BoolType) Fuse(other ExprType) ExprType

Fuse merges other type into this type. When other type conflicts with this type, fused result is any type as fallback.

func (BoolType) String

func (ty BoolType) String() string

type ByErrorPosition added in v1.1.2

type ByErrorPosition []*Error

ByErrorPosition is type for sort.Interface. It sorts errors slice in line and column order.

func (ByErrorPosition) Len added in v1.1.2

func (by ByErrorPosition) Len() int

func (ByErrorPosition) Less added in v1.1.2

func (by ByErrorPosition) Less(i, j int) bool

func (ByErrorPosition) Swap added in v1.1.2

func (by ByErrorPosition) Swap(i, j int)

type CompareOpNode

type CompareOpNode struct {
	// Kind is a kind of this expression to show which operator is used.
	Kind CompareOpNodeKind
	// Left is an expression for left hand side of the binary operator.
	Left ExprNode
	// Right is an expression for right hand side of the binary operator.
	Right ExprNode
}

CompareOpNode is node for binary expression to compare values; ==, !=, <, <=, > or >=.

func (*CompareOpNode) Token

func (n *CompareOpNode) Token() *Token

Token returns the first token of the node. This method is useful to get position of this node.

type CompareOpNodeKind

type CompareOpNodeKind int

CompareOpNodeKind is a kind of compare operators; ==, !=, <, <=, >, >=.

const (
	// CompareOpNodeKindInvalid is invalid and initial value of CompareOpNodeKind values.
	CompareOpNodeKindInvalid CompareOpNodeKind = iota
	// CompareOpNodeKindLess is kind for < operator.
	CompareOpNodeKindLess
	// CompareOpNodeKindLessEq is kind for <= operator.
	CompareOpNodeKindLessEq
	// CompareOpNodeKindGreater is kind for > operator.
	CompareOpNodeKindGreater
	// CompareOpNodeKindGreaterEq is kind for >= operator.
	CompareOpNodeKindGreaterEq
	// CompareOpNodeKindEq is kind for == operator.
	CompareOpNodeKindEq
	// CompareOpNodeKindNotEq is kind for != operator.
	CompareOpNodeKindNotEq
)

type Concurrency

type Concurrency struct {
	// Group is name of the concurrency group.
	Group *String
	// CancelInProgress is a flag that shows if canceling this workflow cancels other jobs in progress.
	CancelInProgress *Bool
	// Pos is a position in source.
	Pos *Pos
}

Concurrency is a configuration of concurrency of the workflow. https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#concurrency

type Config

type Config struct {
	// SelfHostedRunner is configuration for self-hosted runner.
	SelfHostedRunner struct {
		// Labels is label names for self-hosted runner.
		Labels []string `yaml:"labels"`
	} `yaml:"self-hosted-runner"`
}

Config is configuration of actionlint. This struct instance is parsed from "actionlint.yaml" file usually put in ".github" directory.

type Container

type Container struct {
	// Image is specification of Docker image.
	// https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idcontainerimage
	Image *String
	// Credentials is credentials configuration of the Docker container.
	Credentials *Credentials
	// Env is environment variables setup in the container.
	// https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idcontainerenv
	Env *Env
	// Ports is list of port number mappings of the container.
	// https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idcontainerports
	Ports []*String
	// Volumes are list of volumes to be mounted to the container.
	// https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idcontainervolumes
	Volumes []*String
	// Options is options string to run the container.
	// https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idcontaineroptions
	Options *String
	// Pos is a position in source.
	Pos *Pos
}

Container is configuration of how to run the container. https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idcontainer

type Credentials

type Credentials struct {
	// Username is username for authentication.
	Username *String
	// Password is password for authentication.
	Password *String
	// Pos is a position in source.
	Pos *Pos
}

Credentials is credentials configuration. https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idcontainercredentials

type Defaults

type Defaults struct {
	// Run is configuration of how to run shell.
	Run *DefaultsRun
	// Pos is a position in source.
	Pos *Pos
}

Defaults is set of default configurations to run shell. https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#defaults

type DefaultsRun

type DefaultsRun struct {
	// Shell is shell name to be run.
	Shell *String
	// WorkingDirectory is a default working directory path.
	WorkingDirectory *String
	// Pos is a position in source.
	Pos *Pos
}

DefaultsRun is configuration that shell is how to be run. https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#defaultsrun

type DispatchInput

type DispatchInput struct {
	// Name is a name of input value specified on dispatching workflow manually.
	Name *String
	// Description is a description of input value specified on dispatching workflow manually.
	Description *String
	// Required is a flag to show if this input is mandatory or not on dispatching workflow manually.
	Required *Bool
	// Default is a default value of input value on dispatching workflow manually.
	Default *String
}

DispatchInput is input specified on dispatching workflow manually. https://docs.github.com/en/actions/reference/events-that-trigger-workflows#workflow_dispatch

type Env

type Env struct {
	// Vars is mapping from env var name to env var value.
	Vars map[string]*EnvVar
	// Expression is an expression string which contains ${{ ... }}. When this value is not empty,
	// Vars should be nil.
	Expression *String
}

Env represents set of environment variables.

type EnvVar

type EnvVar struct {
	// Name is name of the environment variable.
	Name *String
	// Value is string value of the environment variable.
	Value *String
}

EnvVar represents key-value of environment variable setup.

type Environment

type Environment struct {
	// Name is a name of environment which the workflow uses.
	Name *String
	// URL is the URL mapped to 'environment_url' in the deployments API. Empty value means no value was specified.
	URL *String
	// Pos is a position in source.
	Pos *Pos
}

Environment is a configuration of environment. https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idenvironment

type Error

type Error struct {
	// Message is an error message.
	Message string
	// Filepath is a file path where the error occurred.
	Filepath string
	// Line is a line number where the error occurred. This value is 1-based.
	Line int
	// Column is a column number where the error occurred. This value is 1-based.
	Column int
	// Kind is a string to represent kind of the error. Usually rule name which found the error.
	Kind string
}

Error represents an error detected by actionlint rules

func (*Error) Error

func (e *Error) Error() string

Error returns summary of the error as string.

func (*Error) PrettyPrint

func (e *Error) PrettyPrint(w io.Writer, source []byte)

PrettyPrint prints the error with user-friendly way. It prints file name, source position, error message with colorful output and source snippet with indicator. When nil is set to source, no source snippet is not printed. To disable colorful output, set true to fatih/color.NoColor.

type Event

type Event interface {
	// EventName returns name of the event to trigger this workflow.
	EventName() string
}

Event interface represents workflow events in 'on' section

type Exec

type Exec interface {
	// Kind returns kind of the step execution.
	Kind() ExecKind
	// SetWorkingDir sets working-directory section.
	SetWorkingDir(d *String)
}

Exec is an interface how the step is executed. Step in workflow runs either an action or a script

type ExecAction

type ExecAction struct {
	// https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstepsuses
	Uses *String
	// Inputs represents inputs to the action to execute in 'with' section
	Inputs map[string]*Input
	// Entrypoint represents optional 'entrypoint' field in 'with' section. Nil field means nothing specified
	// https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstepswithentrypoint
	Entrypoint *String
	// Args represents optional 'args' field in 'with' section. Nil field means nothing specified
	// https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstepswithargs
	Args *String
	// WorkingDirectory is a default working directory path to run action
	WorkingDirectory *String
}

ExecAction is configuration how to run action at the step. https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstepsuses

func (*ExecAction) Kind

func (r *ExecAction) Kind() ExecKind

Kind returns kind of the step execution.

func (*ExecAction) SetWorkingDir

func (e *ExecAction) SetWorkingDir(dir *String)

SetWorkingDir sets working-directory section.

type ExecKind

type ExecKind uint8

ExecKind is kind of how the step is executed. A step runs some action or runs some shell script.

const (
	// ExecKindAction is kind for step to run action
	ExecKindAction ExecKind = iota
	// ExecKindRun is kind for step to run shell script
	ExecKindRun
)

type ExecRun

type ExecRun struct {
	// Run is script to run.
	Run *String
	// Shell represents optional 'shell' field. Nil means nothing specified.
	Shell *String
	// WorkingDirectory represents optional 'working-directory' field. Nil means nothing specified.
	WorkingDirectory *String
	// RunPos is position of 'run' section
	RunPos *Pos
}

ExecRun is configuration how to run shell script at the step. https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstepsrun

func (*ExecRun) Kind

func (r *ExecRun) Kind() ExecKind

Kind returns kind of the step execution.

func (*ExecRun) SetWorkingDir

func (e *ExecRun) SetWorkingDir(dir *String)

SetWorkingDir sets working-directory section.

type ExprError

type ExprError struct {
	// Message is an error message
	Message string
	// Offset is byte offset position which caused the error
	Offset int
	// Offset is line number position which caused the error. Note that this value is 1-based.
	Line int
	// Column is column number position which caused the error. Note that this value is 1-based.
	Column int
}

ExprError is an error type caused by lexing/parsing expression syntax. For more details, see https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions

func (*ExprError) Error

func (e *ExprError) Error() string

type ExprLexer

type ExprLexer struct {
	// contains filtered or unexported fields
}

ExprLexer is a struct to lex expression syntax. To know the syntax, see https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions

func NewExprLexer

func NewExprLexer() *ExprLexer

NewExprLexer makes new ExprLexer instance.

func (*ExprLexer) Lex

func (lex *ExprLexer) Lex(src string) ([]*Token, int, *ExprError)

Lex lexes the given string as expression syntax. The parameter must contain '}}' which represents end of expression. Otherwise this function will report an error that it encountered unexpected EOF.

type ExprNode

type ExprNode interface {
	// Token returns the first token of the node. This method is useful to get position of this node.
	Token() *Token
}

ExprNode is a node of expression syntax tree. To know the syntax, see https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions

type ExprParser

type ExprParser struct {
	// contains filtered or unexported fields
}

ExprParser is a parser for expression syntax. To know the details, see https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions

func NewExprParser

func NewExprParser() *ExprParser

NewExprParser creates new ExprParser instance.

func (*ExprParser) Parse

func (p *ExprParser) Parse(t []*Token) (ExprNode, *ExprError)

Parse parses given token sequence into syntax tree. Token sequence t must end with TokenKindEnd token and it cannot be empty.

type ExprSemanticsChecker

type ExprSemanticsChecker struct {
	// contains filtered or unexported fields
}

ExprSemanticsChecker is a semantics checker for expression syntax. It checks types of values in given expression syntax tree. It additionally checks other semantics like arguments of format() built-in function. To know the details of the syntax, see https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#contexts

func NewExprSemanticsChecker

func NewExprSemanticsChecker() *ExprSemanticsChecker

NewExprSemanticsChecker creates new ExprSemanticsChecker instance.

func (*ExprSemanticsChecker) Check

func (sema *ExprSemanticsChecker) Check(expr ExprNode) (ExprType, []*ExprError)

Check checks sematics of given expression syntax tree. It returns the type of the expression as the first return value when the check was successfully done. And it returns all errors found while checking the expression as the second return value.

func (*ExprSemanticsChecker) UpdateMatrix

func (sema *ExprSemanticsChecker) UpdateMatrix(ty *ObjectType)

UpdateMatrix updates matrix object to given object type. Since matrix values change according to 'matrix' section of job configuration, the type needs to be updated.

func (*ExprSemanticsChecker) UpdateNeeds

func (sema *ExprSemanticsChecker) UpdateNeeds(ty *ObjectType)

UpdateNeeds updates 'needs' context object to given object type.

func (*ExprSemanticsChecker) UpdateSteps

func (sema *ExprSemanticsChecker) UpdateSteps(ty *ObjectType)

UpdateSteps updates 'steps' context object to given object type.

type ExprType

type ExprType interface {
	// String returns string representation of the type.
	String() string
	// Assignable returns if other type can be assignable to the type.
	Assignable(other ExprType) bool
	// Equals returns if the type is equal to the other type.
	Equals(other ExprType) bool
	// Fuse merges other type into this type. When other type conflicts with this type, fused
	// result is any type as fallback.
	Fuse(other ExprType) ExprType
}

ExprType is interface for types of values in expression.

func ElemTypeOf

func ElemTypeOf(ty ExprType) (ExprType, bool)

ElemTypeOf returns element type of given type when it is array type. When it is any type, it returns any type. Otherwise ti returns nil.

type Float

type Float struct {
	// Value is a raw value of the float string.
	Value float64
	// Expression is a string when expression syntax ${{ }} is used for this section.
	Expression *String
	// Pos is a position in source.
	Pos *Pos
}

Float represents generic float value in YAML file with position.

type FloatNode

type FloatNode struct {
	// Value is value of the float literal.
	Value float64
	// contains filtered or unexported fields
}

FloatNode is node for float literal.

func (*FloatNode) Token

func (n *FloatNode) Token() *Token

Token returns the first token of the node. This method is useful to get position of this node.

type FuncCallNode

type FuncCallNode struct {
	// Callee is a name of called function. This is string value because currently only built-in
	// functions can be called.
	Callee string
	// Args is arguments of the function call.
	Args []ExprNode
	// contains filtered or unexported fields
}

FuncCallNode represents function call in expression. Note that currently only calling builtin functions is supported.

func (*FuncCallNode) Token

func (n *FuncCallNode) Token() *Token

Token returns the first token of the node. This method is useful to get position of this node.

type FuncSignature

type FuncSignature struct {
	// Name is a name of the function.
	Name string
	// Ret is a return type of the function.
	Ret ExprType
	// Params is a list of parameter types of the function. The final element of this list might
	// be repeated as variable length arguments.
	Params []ExprType
	// VariableLengthParams is a flag to handle variable length parameters. When this flag is set to
	// true, it means that the last type of params might be specified multiple times (including zero
	// times). Setting true implies length of Params is more than 0.
	VariableLengthParams bool
}

FuncSignature is a signature of function, which holds return and arguments types.

func (*FuncSignature) String

func (sig *FuncSignature) String() string

type IndexAccessNode

type IndexAccessNode struct {
	// Operand is an expression at operand of index access, which should be array or object.
	Operand ExprNode
	// Index is an expression at index, which should be integer or string.
	Index ExprNode
}

IndexAccessNode is node for index access, which represents dynamic object property access or array index access.

func (*IndexAccessNode) Token

func (n *IndexAccessNode) Token() *Token

Token returns the first token of the node. This method is useful to get position of this node.

type Input

type Input struct {
	// Name is a name of the input.
	Name *String
	// Value is a value of the input.
	Value *String
}

Input is an input field for running an action. https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstepswith

type Int

type Int struct {
	// Value is a raw value of the integer string.
	Value int
	// Expression is a string when expression syntax ${{ }} is used for this section.
	Expression *String
	// Pos is a position in source.
	Pos *Pos
}

Int represents generic integer value in YAML file with position.

type IntNode

type IntNode struct {
	// Value is value of the integer literal.
	Value int
	// contains filtered or unexported fields
}

IntNode is node for integer literal.

func (*IntNode) Token

func (n *IntNode) Token() *Token

Token returns the first token of the node. This method is useful to get position of this node.

type Job

type Job struct {
	// ID is an ID of the job, which is key of job configuration objects.
	// https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_id
	ID *String
	// Name is a name of job that user can specify freely.
	// https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idname
	Name *String
	// Needs is list of job IDs which should be run before running this job.
	// https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idneeds
	Needs []*String
	// RunsOn is runner configuration which run the job.
	// https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on
	RunsOn *Runner
	// Permissions is permission configuration for running the job.
	Permissions *Permissions
	// Environment is environment specification where the job runs.
	Environment *Environment
	// Concurrency is concurrency configuration on running the job.
	Concurrency *Concurrency
	// Outputs is map from output name to output specifications.
	// https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idoutputs
	Outputs map[string]*Output
	// Env is environment variables setup while running the job.
	// https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idenv
	Env *Env
	// Defaults is default configurations of how to run scripts.
	Defaults *Defaults
	// If is a condition whether this job should be run.
	// https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idif
	If *String
	// Steps is list of steps to be run in the job.
	// https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idsteps
	Steps []*Step
	// TimeoutMinutes is timeout value of running the job in minutes.
	// https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idtimeout-minutes
	TimeoutMinutes *Float
	// Strategy is strategy configuration of running the job.
	// https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstrategy
	Strategy *Strategy
	// ContinueOnError is a flag to show if execution should continue on error.
	// https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idcontinue-on-error
	ContinueOnError *Bool
	// Container is container configuration to run the job.
	Container *Container
	// Services is map from service names to service configurations.
	// https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idservices
	Services map[string]*Service
	// Pos is a position in source.
	Pos *Pos
}

Job is configuration of how to run a job. https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobs

type Linter

type Linter struct {
	// contains filtered or unexported fields
}

Linter is struct to lint workflow files.

func NewLinter

func NewLinter(out io.Writer, opts *LinterOptions) (*Linter, error)

NewLinter creates a new Linter instance. The out parameter is used to output errors from Linter instance. Set io.Discard if you don't want the outputs. The opts parameter is LinterOptions instance which configures behavior of linting.

func (*Linter) GenerateDefaultConfig

func (l *Linter) GenerateDefaultConfig(dir string) error

GenerateDefaultConfig generates default config file at ".github/actionlint.yaml" in project which the given directory path belongs to.

func (*Linter) Lint

func (l *Linter) Lint(path string, content []byte, project *Project) ([]*Error, error)

Lint lints YAML workflow file content given as byte sequence. The path parameter is used as file path the content came from. Setting "<stdin>" to path parameter indicates the output came from STDIN. Note that only given Project instance is used for configuration. No config is automatically loaded based on path parameter.

func (*Linter) LintFile

func (l *Linter) LintFile(path string) ([]*Error, error)

LintFile lints one YAML workflow file and outputs the errors to given writer.

func (*Linter) LintFiles

func (l *Linter) LintFiles(filepaths []string) ([]*Error, error)

LintFiles lints YAML workflow files and outputs the errors to given writer. It applies lint rules to all given files.

func (*Linter) LintRepository

func (l *Linter) LintRepository(dir string) ([]*Error, error)

LintRepository lints YAML workflow files and outputs the errors to given writer. It finds the nearest `.github/workflow` directory based on `dir` and applies lint rules to all YAML worflow files under the directory.

type LinterOptions

type LinterOptions struct {
	// Verbose is flag if verbose log output is enabled.
	Verbose bool
	// Debug is flag if debug log output is enabled.
	Debug bool
	// LogWriter is io.Writer object to use to print log outputs. Note that error outputs detected
	// by the linter are not included in the log outputs.
	LogWriter io.Writer
	// NoColor is flag if colorful output is enabled.
	NoColor bool
	// Oneline is flag if one line output is enabled. When enabling it, one error is output per one
	// line. It is useful when reading outputs from programs.
	Oneline bool
	// Shellcheck is executable for running shellcheck external command. It can be command name like
	// "shellcheck" or file path like "/path/to/shellcheck", "path/to/shellcheck". When this value
	// is empty, shellcheck won't run to check scripts in workflow file.
	Shellcheck string
	// Pyflakes is executable for running pyflakes external command. It can be command name like "pyflakes"
	// or file path like "/path/to/pyflakes", "path/to/pyflakes". When this value is empty, pyflakes
	// won't run to check scripts in workflow file.
	Pyflakes string
	// IgnorePatterns is list of regular expression to filter errors. The pattern is applied to error
	// messages. When an error is matched, the error is ignored.
	IgnorePatterns []string
	// ConfigFile is a path to config file. Empty string means no config file path is given. In
	// the case, actionlint will try to read config from .github/actionlint.yaml.
	ConfigFile string
}

LinterOptions is set of options for Linter instance. This struct should be created by user and given to NewLinter factory function.

type LogLevel

type LogLevel int

LogLevel is log level of logger used in Linter instance.

type LogicalOpNode

type LogicalOpNode struct {
	// Kind is a kind to show which operator is used.
	Kind LogicalOpNodeKind
	// Left is an expression for left hand side of the binary operator.
	Left ExprNode
	// Right is an expression for right hand side of the binary operator.
	Right ExprNode
}

LogicalOpNode is node for logical binary operators; && or ||.

func (*LogicalOpNode) Token

func (n *LogicalOpNode) Token() *Token

Token returns the first token of the node. This method is useful to get position of this node.

type LogicalOpNodeKind

type LogicalOpNodeKind int

LogicalOpNodeKind is a kind of logical operators; && and ||.

const (
	// LogicalOpNodeKindInvalid is an invalid and initial value of LogicalOpNodeKind.
	LogicalOpNodeKindInvalid LogicalOpNodeKind = iota
	// LogicalOpNodeKindAnd is a kind for && operator.
	LogicalOpNodeKindAnd
	// LogicalOpNodeKindOr is a kind for || operator.
	LogicalOpNodeKindOr
)

func (LogicalOpNodeKind) String

func (k LogicalOpNodeKind) String() string

type Matrix

type Matrix struct {
	// Values stores mappings from name to values.
	Rows map[string]*MatrixRow
	// Include is list of combinations of matrix values and additional values on running matrix combinations.
	// https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#example-including-additional-values-into-combinations
	Include *MatrixCombinations
	// Exclude is list of combinations of matrix values which should not be run. Combinations in
	// this list will be removed from combinations of matrix to run.
	// https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#example-excluding-configurations-from-a-matrix
	Exclude *MatrixCombinations
	// Expression is a string when expression syntax ${{ }} is used for this section.
	Expression *String
	// Pos is a position in source.
	Pos *Pos
}

Matrix is matrix variations configuration of a job. https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix

type MatrixAssign

type MatrixAssign struct {
	// Key is a name of the matrix value.
	Key *String
	// Value is the value selected from values in row.
	Value RawYAMLValue
}

MatrixAssign represents which value should be taken in the row of the matrix. https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix

type MatrixCombination

type MatrixCombination struct {
	Assigns map[string]*MatrixAssign
	// Expression is a string when expression syntax ${{ }} is used for this section.
	Expression *String
}

MatrixCombination is combination of matrix value assignments to define one of matrix variations. https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix

type MatrixCombinations

type MatrixCombinations struct {
	Combinations []*MatrixCombination
	// Expression is a string when expression syntax ${{ }} is used for this section.
	Expression *String
}

MatrixCombinations is list of combinations of matrix assignments used for 'include' and 'exclude' sections. https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix

func (*MatrixCombinations) ContainsExpression

func (cs *MatrixCombinations) ContainsExpression() bool

ContainsExpression returns if the combinations section includes at least one expression node.

type MatrixRow

type MatrixRow struct {
	// Name is a name of matrix value.
	Name *String
	// Values is variations of values which the matrix value can take.
	Values []RawYAMLValue
	// Expression is a string when expression syntax ${{ }} is used for this section.
	Expression *String
}

MatrixRow is one row of matrix. One matrix row can take multiple values. Those variations are stored as row of values in this struct. https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix

type NotOpNode

type NotOpNode struct {
	// Operand is an expression at operand of ! operator.
	Operand ExprNode
	// contains filtered or unexported fields
}

NotOpNode is node for unary ! operator.

func (*NotOpNode) Token

func (n *NotOpNode) Token() *Token

Token returns the first token of the node. This method is useful to get position of this node.

type NullNode

type NullNode struct {
	// contains filtered or unexported fields
}

NullNode is node for null literal.

func (*NullNode) Token

func (n *NullNode) Token() *Token

Token returns the first token of the node. This method is useful to get position of this node.

type NullType

type NullType struct{}

NullType is type for null value.

func (NullType) Assignable

func (ty NullType) Assignable(other ExprType) bool

Assignable returns if other type can be assignable to the type.

func (NullType) Equals

func (ty NullType) Equals(other ExprType) bool

Equals returns if the type is equal to the other type.

func (NullType) Fuse

func (ty NullType) Fuse(other ExprType) ExprType

Fuse merges other type into this type. When other type conflicts with this type, fused result is any type as fallback.

func (NullType) String

func (ty NullType) String() string

type NumberType

type NumberType struct{}

NumberType is type for number values such as integer or float.

func (NumberType) Assignable

func (ty NumberType) Assignable(other ExprType) bool

Assignable returns if other type can be assignable to the type.

func (NumberType) Equals

func (ty NumberType) Equals(other ExprType) bool

Equals returns if the type is equal to the other type.

func (NumberType) Fuse

func (ty NumberType) Fuse(other ExprType) ExprType

Fuse merges other type into this type. When other type conflicts with this type, fused result is any type as fallback.

func (NumberType) String

func (ty NumberType) String() string

type ObjectDerefNode

type ObjectDerefNode struct {
	// Receiver is an expression at receiver of property dereference.
	Receiver ExprNode
	// Property is a name of property to access.
	Property string
}

ObjectDerefNode represents property dereference of object like 'foo.bar'.

func (ObjectDerefNode) Token

func (n ObjectDerefNode) Token() *Token

Token returns the first token of the node. This method is useful to get position of this node.

type ObjectType

type ObjectType struct {
	// Props is map from properties name to their type.
	Props map[string]ExprType
	// StrictProps is flag to check if the properties should be checked strictly. When this flag
	// is set to true, it means that other than properties defined in Props field are not permitted
	// and will cause type error. When this flag is set to false, accessing to unknown properties
	// does not cause type error and will be deducted to any type.
	StrictProps bool
}

ObjectType is type for objects, which can hold key-values.

func NewObjectType

func NewObjectType() *ObjectType

NewObjectType creates new ObjectType instance which allows unknown props. When accessing to unknown props, their values will fall back to any.

func NewStrictObjectType

func NewStrictObjectType() *ObjectType

NewStrictObjectType creates new ObjectType instance which does not allow unknown props.

func (*ObjectType) Assignable

func (ty *ObjectType) Assignable(other ExprType) bool

Assignable returns if other type can be assignable to the type.

func (*ObjectType) Equals

func (ty *ObjectType) Equals(other ExprType) bool

Equals returns if the type is equal to the other type.

func (*ObjectType) Fuse

func (ty *ObjectType) Fuse(other ExprType) ExprType

Fuse merges two object types into one. When other object has unknown props, they are merged into current object. When both have same property, when they are assignable, it remains as-is. Otherwise, the property falls back to any type. Note that this method modifies itself destructively for efficiency.

func (*ObjectType) String

func (ty *ObjectType) String() string

type Output

type Output struct {
	// Name is name of output.
	Name *String
	// Value is value of output.
	Value *String
}

Output is output entry of the job. https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idoutputs

type Pass

type Pass interface {
	// VisitStep is callback when visiting Step node. It returns internal error when it cannot continue the process
	VisitStep(node *Step) error
	// VisitJobPre is callback when visiting Job node before visiting its children. It returns internal error when it cannot continue the process
	VisitJobPre(node *Job) error
	// VisitJobPost is callback when visiting Job node after visiting its children. It returns internal error when it cannot continue the process
	VisitJobPost(node *Job) error
	// VisitWorkflowPre is callback when visiting Workflow node before visiting its children. It returns internal error when it cannot continue the process
	VisitWorkflowPre(node *Workflow) error
	// VisitWorkflowPost is callback when visiting Workflow node after visiting its children. It returns internal error when it cannot continue the process
	VisitWorkflowPost(node *Workflow) error
}

Pass is an interface to traverse a workflow syntax tree

type PermKind

type PermKind uint8

PermKind is kind of permissions. https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#permissions

const (
	// PermKindNone represents 'none' permission. No operation is permitted.
	PermKindNone PermKind = iota
	// PermKindRead represents 'read' permission. Only read operations are permitted.
	PermKindRead
	// PermKindWrite represents 'write' permission. Both read and write operations are permitted.
	PermKindWrite
)

type Permission

type Permission struct {
	// Name is name of permission. This value is nil when it represents all scopes (read-all or write-all)
	Name *String
	// Kind is kind of the permission configured in workflow.
	Kind PermKind
	// Pos is a position in source.
	Pos *Pos
}

Permission is configuration for permissions.

type Permissions

type Permissions struct {
	// All represents read-all or write-all, which define permissions of all scopes at once.
	All *Permission
	// Scopes is mappings from permission name to permission value
	Scopes map[string]*Permission
	// Pos is a position in source.
	Pos *Pos
}

Permissions is set of permission configurations in workflow file. All permissions can be set at once. Or each permission can be configured respectively. https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#permissions

type Pos

type Pos struct {
	// Line is a line number of the position. This value is 1-based.
	Line int
	// Col is a column number of the position. This value is 1-based.
	Col int
}

Pos represents position in the file.

func (*Pos) String

func (p *Pos) String() string

type Project

type Project struct {
	// contains filtered or unexported fields
}

Project represents one GitHub project. One Git repository corresponds to one project.

func (*Project) Config

func (p *Project) Config() (*Config, error)

Config returns config object of the GitHub project repository. The config file is read from ".github/actionlint.yaml" or ".github/actionlint.yml".

func (*Project) Knows

func (p *Project) Knows(path string) bool

Knows returns true when the project knows the given file. When a file is included in the project's directory, the project knows the file.

func (*Project) RootDir

func (p *Project) RootDir() string

RootDir returns a root directory path of the GitHub project repository.

func (*Project) WorkflowsDir

func (p *Project) WorkflowsDir() string

WorkflowsDir returns a ".github/workflows" directory path of the GitHub project repository. This method does not check if the directory exists.

type Projects

type Projects struct {
	// contains filtered or unexported fields
}

Projects represents set of projects. It caches Project instances which was created previously and reuses them.

func NewProjects

func NewProjects() *Projects

NewProjects creates new Projects instance.

func (*Projects) At

func (ps *Projects) At(path string) *Project

At returns the Project instance which the path belongs to.

type RawYAMLArray

type RawYAMLArray struct {
	// Elems is list of elements of the array value.
	Elems []RawYAMLValue
	// contains filtered or unexported fields
}

RawYAMLArray is raw YAML sequence value.

func (*RawYAMLArray) Equals

func (a *RawYAMLArray) Equals(other RawYAMLValue) bool

Equals returns if the other value is equal to the value.

func (*RawYAMLArray) Kind

func (a *RawYAMLArray) Kind() RawYAMLValueKind

Kind returns kind of raw YAML value.

func (*RawYAMLArray) Pos

func (a *RawYAMLArray) Pos() *Pos

Pos returns the start position of the value in the source file

func (*RawYAMLArray) String

func (a *RawYAMLArray) String() string

type RawYAMLObject

type RawYAMLObject struct {
	// Props is map from property names to their values.
	Props map[string]RawYAMLValue
	// contains filtered or unexported fields
}

RawYAMLObject is raw YAML mapping value.

func (*RawYAMLObject) Equals

func (o *RawYAMLObject) Equals(other RawYAMLValue) bool

Equals returns if the other value is equal to the value.

func (*RawYAMLObject) Kind

func (o *RawYAMLObject) Kind() RawYAMLValueKind

Kind returns kind of raw YAML value.

func (*RawYAMLObject) Pos

func (o *RawYAMLObject) Pos() *Pos

Pos returns the start position of the value in the source file

func (*RawYAMLObject) String

func (o *RawYAMLObject) String() string

type RawYAMLString

type RawYAMLString struct {

	// Value is string representation of the scalar node.
	Value string
	// contains filtered or unexported fields
}

RawYAMLString is raw YAML scalar value.

func (*RawYAMLString) Equals

func (s *RawYAMLString) Equals(other RawYAMLValue) bool

Equals returns if the other value is equal to the value.

func (*RawYAMLString) Kind

func (s *RawYAMLString) Kind() RawYAMLValueKind

Kind returns kind of raw YAML value.

func (*RawYAMLString) Pos

func (s *RawYAMLString) Pos() *Pos

Pos returns the start position of the value in the source file

func (*RawYAMLString) String

func (s *RawYAMLString) String() string

type RawYAMLValue

type RawYAMLValue interface {
	// Kind returns kind of raw YAML value.
	Kind() RawYAMLValueKind
	// Equals returns if the other value is equal to the value.
	Equals(other RawYAMLValue) bool
	// Pos returns the start position of the value in the source file
	Pos() *Pos
	// String returns string representation of the value
	String() string
}

RawYAMLValue is a value at matrix variation. Any value can be put at matrix variations including mappings and arrays.

type RawYAMLValueKind

type RawYAMLValueKind int

RawYAMLValueKind is kind of raw YAML values

type RepositoryDispatchEvent

type RepositoryDispatchEvent struct {
	// Types is list of types which can trigger workflow.
	Types []*String
	// Pos is a position in source.
	Pos *Pos
}

RepositoryDispatchEvent is repository_dispatch event configuration. https://docs.github.com/en/actions/reference/events-that-trigger-workflows#repository_dispatch

func (*RepositoryDispatchEvent) EventName

func (e *RepositoryDispatchEvent) EventName() string

EventName returns name of the event to trigger this workflow.

type Rule

type Rule interface {
	Pass
	Errs() []*Error
	Name() string
	EnableDebug(out io.Writer)
}

Rule is an interface which all rule structs must meet

type RuleAction

type RuleAction struct {
	RuleBase
	// contains filtered or unexported fields
}

RuleAction is a rule to check running action in steps of jobs. https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstepsuses

func NewRuleAction

func NewRuleAction(repoDir string) *RuleAction

NewRuleAction creates new RuleAction instance.

func (*RuleAction) VisitStep

func (rule *RuleAction) VisitStep(n *Step) error

VisitStep is callback when visiting Step node.

type RuleBase

type RuleBase struct {
	// contains filtered or unexported fields
}

RuleBase is a struct to be a base of rule structs. Embed this struct to define default methods automatically

func (*RuleBase) EnableDebug added in v1.2.0

func (r *RuleBase) EnableDebug(out io.Writer)

EnableDebug enables debug output from the rule. Given io.Writer instance is used to print debug information to console

func (*RuleBase) Errs

func (r *RuleBase) Errs() []*Error

Errs returns errors found by the rule.

func (*RuleBase) Name

func (r *RuleBase) Name() string

Name is name of the rule.

func (*RuleBase) VisitJobPost

func (r *RuleBase) VisitJobPost(node *Job) error

VisitJobPost is callback when visiting Job node after visiting its children.

func (*RuleBase) VisitJobPre

func (r *RuleBase) VisitJobPre(node *Job) error

VisitJobPre is callback when visiting Job node before visiting its children.

func (*RuleBase) VisitStep

func (r *RuleBase) VisitStep(node *Step) error

VisitStep is callback when visiting Step node.

func (*RuleBase) VisitWorkflowPost

func (r *RuleBase) VisitWorkflowPost(node *Workflow) error

VisitWorkflowPost is callback when visiting Workflow node after visiting its children.

func (*RuleBase) VisitWorkflowPre

func (r *RuleBase) VisitWorkflowPre(node *Workflow) error

VisitWorkflowPre is callback when visiting Workflow node before visiting its children.

type RuleCredentials

type RuleCredentials struct {
	RuleBase
}

RuleCredentials is a rule to check credentials in workflows

func NewRuleCredentials

func NewRuleCredentials() *RuleCredentials

NewRuleCredentials creates new RuleCredentials instance

func (*RuleCredentials) VisitJobPre

func (rule *RuleCredentials) VisitJobPre(n *Job) error

VisitJobPre is callback when visiting Job node before visiting its children.

type RuleEnvVar

type RuleEnvVar struct {
	RuleBase
}

RuleEnvVar is a rule checker to check environment variables setup.

func NewRuleEnvVar

func NewRuleEnvVar() *RuleEnvVar

NewRuleEnvVar creates new RuleEnvVar instance.

func (*RuleEnvVar) VisitJobPre

func (rule *RuleEnvVar) VisitJobPre(n *Job) error

VisitJobPre is callback when visiting Job node before visiting its children.

func (*RuleEnvVar) VisitStep

func (rule *RuleEnvVar) VisitStep(n *Step) error

VisitStep is callback when visiting Step node.

func (*RuleEnvVar) VisitWorkflowPre

func (rule *RuleEnvVar) VisitWorkflowPre(n *Workflow) error

VisitWorkflowPre is callback when visiting Workflow node before visiting its children.

type RuleEvents

type RuleEvents struct {
	RuleBase
}

RuleEvents is a rule to check 'on' field in workflow. https://docs.github.com/en/actions/reference/events-that-trigger-workflows

func NewRuleEvents

func NewRuleEvents() *RuleEvents

NewRuleEvents creates new RuleEvents instance.

func (*RuleEvents) VisitWorkflowPre

func (rule *RuleEvents) VisitWorkflowPre(n *Workflow) error

VisitWorkflowPre is callback when visiting Workflow node before visiting its children.

type RuleExpression

type RuleExpression struct {
	RuleBase
	// contains filtered or unexported fields
}

RuleExpression is a rule checker to check expression syntax in string values of workflow syntax. It checks syntax and semantics of the expressions including type checks and functions/contexts definitions. For more details see https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions

func NewRuleExpression

func NewRuleExpression() *RuleExpression

NewRuleExpression creates new RuleExpression instance.

func (*RuleExpression) VisitJobPost

func (rule *RuleExpression) VisitJobPost(n *Job) error

VisitJobPost is callback when visiting Job node after visiting its children

func (*RuleExpression) VisitJobPre

func (rule *RuleExpression) VisitJobPre(n *Job) error

VisitJobPre is callback when visiting Job node before visiting its children.

func (*RuleExpression) VisitStep

func (rule *RuleExpression) VisitStep(n *Step) error

VisitStep is callback when visiting Step node.

func (*RuleExpression) VisitWorkflowPost

func (rule *RuleExpression) VisitWorkflowPost(n *Workflow) error

VisitWorkflowPost is callback when visiting Workflow node after visiting its children

func (*RuleExpression) VisitWorkflowPre

func (rule *RuleExpression) VisitWorkflowPre(n *Workflow) error

VisitWorkflowPre is callback when visiting Workflow node before visiting its children.

type RuleJobNeeds

type RuleJobNeeds struct {
	RuleBase
	// contains filtered or unexported fields
}

RuleJobNeeds is a rule to check 'needs' field in each job conifiguration. For more details, see https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idneeds

func NewRuleJobNeeds

func NewRuleJobNeeds() *RuleJobNeeds

NewRuleJobNeeds creates new RuleJobNeeds instance.

func (*RuleJobNeeds) VisitJobPre

func (rule *RuleJobNeeds) VisitJobPre(n *Job) error

VisitJobPre is callback when visiting Job node before visiting its children.

func (*RuleJobNeeds) VisitWorkflowPost

func (rule *RuleJobNeeds) VisitWorkflowPost(n *Workflow) error

VisitWorkflowPost is callback when visiting Workflow node after visiting its children.

type RuleMatrix

type RuleMatrix struct {
	RuleBase
}

RuleMatrix is a rule checker to check 'matrix' field of job.

func NewRuleMatrix

func NewRuleMatrix() *RuleMatrix

NewRuleMatrix creates new RuleMatrix instance.

func (*RuleMatrix) VisitJobPre

func (rule *RuleMatrix) VisitJobPre(n *Job) error

VisitJobPre is callback when visiting Job node before visiting its children.

type RulePyflakes added in v1.2.0

type RulePyflakes struct {
	RuleBase
	// contains filtered or unexported fields
}

RulePyflakes is a rule to check Python scripts at 'run:' using pyflakes. https://github.com/PyCQA/pyflakes

func NewRulePyflakes added in v1.2.0

func NewRulePyflakes(executable string) (*RulePyflakes, error)

NewRulePyflakes creates new RulePyflakes instance. Parameter executable can be command name or relative/absolute file path. When the given executable is not found in system, it returns an error.

func (*RulePyflakes) VisitJobPost added in v1.2.0

func (rule *RulePyflakes) VisitJobPost(n *Job) error

VisitJobPost is callback when visiting Job node after visiting its children.

func (*RulePyflakes) VisitJobPre added in v1.2.0

func (rule *RulePyflakes) VisitJobPre(n *Job) error

VisitJobPre is callback when visiting Job node before visiting its children.

func (*RulePyflakes) VisitStep added in v1.2.0

func (rule *RulePyflakes) VisitStep(n *Step) error

VisitStep is callback when visiting Step node.

func (*RulePyflakes) VisitWorkflowPost added in v1.2.0

func (rule *RulePyflakes) VisitWorkflowPost(n *Workflow) error

VisitWorkflowPost is callback when visiting Workflow node after visiting its children.

func (*RulePyflakes) VisitWorkflowPre added in v1.2.0

func (rule *RulePyflakes) VisitWorkflowPre(n *Workflow) error

VisitWorkflowPre is callback when visiting Workflow node before visiting its children.

type RuleRunnerLabel

type RuleRunnerLabel struct {
	RuleBase
	// contains filtered or unexported fields
}

RuleRunnerLabel is a rule to check runner label like "ubuntu-latest". There are two types of runners, GitHub-hosted runner and Self-hosted runner. GitHub-hosted runner is described at https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners . And Self-hosted runner is described at https://docs.github.com/en/actions/hosting-your-own-runners/using-self-hosted-runners-in-a-workflow .

func NewRuleRunnerLabel

func NewRuleRunnerLabel(labels []string) *RuleRunnerLabel

NewRuleRunnerLabel creates new RuleRunnerLabel instance.

func (*RuleRunnerLabel) VisitJobPre

func (rule *RuleRunnerLabel) VisitJobPre(n *Job) error

VisitJobPre is callback when visiting Job node before visiting its children.

type RuleShellName

type RuleShellName struct {
	RuleBase
	// contains filtered or unexported fields
}

RuleShellName is a rule to check 'shell' field. For more details, see https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#using-a-specific-shell

func NewRuleShellName

func NewRuleShellName() *RuleShellName

NewRuleShellName creates new RuleShellName instance.

func (*RuleShellName) VisitJobPost

func (rule *RuleShellName) VisitJobPost(n *Job) error

VisitJobPost is callback when visiting Job node after visiting its children.

func (*RuleShellName) VisitJobPre

func (rule *RuleShellName) VisitJobPre(n *Job) error

VisitJobPre is callback when visiting Job node before visiting its children.

func (*RuleShellName) VisitStep

func (rule *RuleShellName) VisitStep(n *Step) error

VisitStep is callback when visiting Step node.

func (*RuleShellName) VisitWorkflowPre

func (rule *RuleShellName) VisitWorkflowPre(n *Workflow) error

VisitWorkflowPre is callback when visiting Workflow node before visiting its children.

type RuleShellcheck

type RuleShellcheck struct {
	RuleBase
	// contains filtered or unexported fields
}

RuleShellcheck is a rule to check shell scripts at 'run:' using shellcheck. https://github.com/koalaman/shellcheck

func NewRuleShellcheck

func NewRuleShellcheck(executable string) (*RuleShellcheck, error)

NewRuleShellcheck craetes new RuleShellcheck instance. Parameter executable can be command name or relative/absolute file path. When the given executable is not found in system, it returns an error as 2nd return value.

func (*RuleShellcheck) VisitJobPost

func (rule *RuleShellcheck) VisitJobPost(n *Job) error

VisitJobPost is callback when visiting Job node after visiting its children.

func (*RuleShellcheck) VisitJobPre

func (rule *RuleShellcheck) VisitJobPre(n *Job) error

VisitJobPre is callback when visiting Job node before visiting its children.

func (*RuleShellcheck) VisitStep

func (rule *RuleShellcheck) VisitStep(n *Step) error

VisitStep is callback when visiting Step node.

func (*RuleShellcheck) VisitWorkflowPost

func (rule *RuleShellcheck) VisitWorkflowPost(n *Workflow) error

VisitWorkflowPost is callback when visiting Workflow node after visiting its children.

func (*RuleShellcheck) VisitWorkflowPre

func (rule *RuleShellcheck) VisitWorkflowPre(n *Workflow) error

VisitWorkflowPre is callback when visiting Workflow node before visiting its children.

type RuleStepID

type RuleStepID struct {
	RuleBase
	// contains filtered or unexported fields
}

RuleStepID is a rule to check step IDs in workflow.

func NewRuleStepID

func NewRuleStepID() *RuleStepID

NewRuleStepID creates a new RuleStepID instance.

func (*RuleStepID) VisitJobPost

func (rule *RuleStepID) VisitJobPost(n *Job) error

VisitJobPost is callback when visiting Job node after visiting its children.

func (*RuleStepID) VisitJobPre

func (rule *RuleStepID) VisitJobPre(n *Job) error

VisitJobPre is callback when visiting Job node before visiting its children.

func (*RuleStepID) VisitStep

func (rule *RuleStepID) VisitStep(n *Step) error

VisitStep is callback when visiting Step node.

type Runner

type Runner struct {
	// Labels is list label names to select a runner to run a job. There are preset labels and user
	// defined labels. Runner matching to the labels is selected.
	Labels []*String
}

Runner is struct for runner configuration. https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on

type ScheduledEvent

type ScheduledEvent struct {
	// Cron is list of cron strings which schedules workflow.
	Cron []*String
	// Pos is a position in source.
	Pos *Pos
}

ScheduledEvent is event scheduled by workflow. https://docs.github.com/en/actions/reference/events-that-trigger-workflows#scheduled-events

func (*ScheduledEvent) EventName

func (e *ScheduledEvent) EventName() string

EventName returns name of the event to trigger this workflow.

type Service

type Service struct {
	// Name is name of the service.
	Name *String
	// Container is configuration of container which runs the service.
	Container *Container
}

Service is configuration to run a service like database. https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idservices

type Strategy

type Strategy struct {
	// Matrix is matrix of combinations of values. Each combination will run the job once.
	Matrix *Matrix
	// FailFast is flag to show if other jobs should stop when one job fails.
	// https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstrategyfail-fast
	FailFast *Bool
	// MaxParallel is how many jobs should be run at once.
	// https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstrategymax-parallel
	MaxParallel *Int
	// Pos is a position in source.
	Pos *Pos
}

Strategy is strategy configuration of how the job is run. https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstrategy

type String

type String struct {
	// Value is a raw value of the string.
	Value string
	// Pos is a position of the string in source.
	Pos *Pos
}

String represents generic string value in YAML file with position.

type StringNode

type StringNode struct {
	// Value is value of the string literal. Escapes are resolved and quotes at both edges are
	// removed.
	Value string
	// contains filtered or unexported fields
}

StringNode is node for string literal.

func (*StringNode) Token

func (n *StringNode) Token() *Token

Token returns the first token of the node. This method is useful to get position of this node.

type StringType

type StringType struct{}

StringType is type for string values.

func (StringType) Assignable

func (ty StringType) Assignable(other ExprType) bool

Assignable returns if other type can be assignable to the type.

func (StringType) Equals

func (ty StringType) Equals(other ExprType) bool

Equals returns if the type is equal to the other type.

func (StringType) Fuse

func (ty StringType) Fuse(other ExprType) ExprType

Fuse merges other type into this type. When other type conflicts with this type, fused result is any type as fallback.

func (StringType) String

func (ty StringType) String() string

type Token

type Token struct {
	// Kind is kind of the token.
	Kind TokenKind
	// Value is string representation of the token.
	Value string
	// Offset is byte offset of token string starting.
	Offset int
	// Line is line number of start position of the token. Note that this value is 1-based.
	Line int
	// Column is column number of start position of the token. Note that this value is 1-based.
	Column int
}

Token is a token lexed from expression syntax. For more details, see https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions

func (*Token) String

func (t *Token) String() string

type TokenKind

type TokenKind int

TokenKind is kind of token.

const (
	// TokenKindUnknown is a default value of token as unknown token value.
	TokenKindUnknown TokenKind = iota
	// TokenKindEnd is a token for end of token sequence. Sequence without this
	// token means invalid.
	TokenKindEnd
	// TokenKindIdent is a token for identifier.
	TokenKindIdent
	// TokenKindString is a token for string literals.
	TokenKindString
	// TokenKindInt is a token for integers including hex integers.
	TokenKindInt
	// TokenKindFloat is a token for float numbers.
	TokenKindFloat
	// TokenKindLeftParen is a token for '('.
	TokenKindLeftParen
	// TokenKindRightParen is a token for ')'.
	TokenKindRightParen
	// TokenKindLeftBracket is a token for '['.
	TokenKindLeftBracket
	// TokenKindRightBracket is a token for ']'.
	TokenKindRightBracket
	// TokenKindDot is a token for '.'.
	TokenKindDot
	// TokenKindNot is a token for '!'.
	TokenKindNot
	// TokenKindLess is a token for '<'.
	TokenKindLess
	// TokenKindLessEq is a token for '<='.
	TokenKindLessEq
	// TokenKindGreater is a token for '>'.
	TokenKindGreater
	// TokenKindGreaterEq is a token for '>='.
	TokenKindGreaterEq
	// TokenKindEq is a token for '=='.
	TokenKindEq
	// TokenKindNotEq is a token for '!='.
	TokenKindNotEq
	// TokenKindAnd is a token for '&&'.
	TokenKindAnd
	// TokenKindOr is a token for '||'.
	TokenKindOr
	// TokenKindStar is a token for '*'.
	TokenKindStar
	// TokenKindComma is a token for ','.
	TokenKindComma
)

func (TokenKind) String

func (t TokenKind) String() string

type VariableNode

type VariableNode struct {
	// Name is name of the variable
	Name string
	// contains filtered or unexported fields
}

VariableNode is node for variable access.

func (*VariableNode) Token

func (n *VariableNode) Token() *Token

Token returns the first token of the node. This method is useful to get position of this node.

type Visitor

type Visitor struct {
	// contains filtered or unexported fields
}

Visitor visits syntax tree from root in depth-first order

func NewVisitor

func NewVisitor() *Visitor

NewVisitor creates Visitor instance

func (*Visitor) AddPass

func (v *Visitor) AddPass(p Pass)

AddPass adds new pass which is called on traversing a syntax tree

func (*Visitor) EnableDebug

func (v *Visitor) EnableDebug(w io.Writer)

EnableDebug enables debug output when non-nil io.Writer value is given. All debug outputs from visitor will be written to the writer.

func (*Visitor) Visit

func (v *Visitor) Visit(n *Workflow) error

Visit visits given syntax tree in depth-first order

type WebhookEvent

type WebhookEvent struct {
	// Hook is a name of the webhook event.
	Hook *String
	// Types is list of types of the webhook event. Only the types enumerated here will trigger
	// the workflow.
	Types []*String
	// Branches is list of branch filters to choose branches.
	Branches []*String
	// BranchesIgnore is list of branch filters to reject some branches.
	BranchesIgnore []*String
	// Tags is list of tag filters to choose tags.
	Tags []*String
	// TagsIgnore is list of tag filters to reject some tags.
	TagsIgnore []*String
	// Paths is list of path filters to choose file paths.
	Paths []*String
	// PathsIgnore is list of path filters to reject some file paths.
	PathsIgnore []*String
	// Workflows is list of workflow names which are triggered by 'workflow_run' event.
	Workflows []*String
	// Pos is a position in source.
	Pos *Pos
}

WebhookEvent represents event type based on webhook events. Some events can't have 'types' field. Only 'push' and 'pull' events can have 'tags', 'tags-ignore', 'paths' and 'paths-ignore' fields. Only 'workflow_run' event can have 'workflows' field. https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#onevent_nametypes

func (*WebhookEvent) EventName

func (e *WebhookEvent) EventName() string

EventName returns name of the event to trigger this workflow.

type Workflow

type Workflow struct {
	// Name is name of the workflow. This field can be nil when user didn't specify the name explicitly.
	// https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#name
	Name *String
	// On is list of events which can trigger this workflow.
	// https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#onpushpull_requestbranchestags
	On []Event
	// Permissions is configuration of permissions of this workflow.
	Permissions *Permissions
	// Env is a default set of environment variables while running this workflow.
	// https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#env
	Env *Env
	// Defaults is default configuration of how to run scripts.
	Defaults *Defaults
	// Concurrency is concurrency configuration of entire workflow. Each jobs also can their own
	// concurrency configurations.
	Concurrency *Concurrency
	// Jobs is mappings from job ID to the job object
	Jobs map[string]*Job
}

Workflow is root of workflow syntax tree, which represents one workflow configuration file. https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions

type WorkflowDispatchEvent

type WorkflowDispatchEvent struct {
	// Inputs is map from input names to input attributes.
	Inputs map[string]*DispatchInput
	// Pos is a position in source.
	Pos *Pos
}

WorkflowDispatchEvent is event on dispatching workflow manually. https://docs.github.com/en/actions/reference/events-that-trigger-workflows#workflow_dispatch

func (*WorkflowDispatchEvent) EventName

func (e *WorkflowDispatchEvent) EventName() string

EventName returns name of the event to trigger this workflow.

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL