Skip to content

Commit 44e0643

Browse files
committed
describe JSON syntax check and strong typing for fromJSON as a separate example
1 parent 2256d0b commit 44e0643

File tree

5 files changed

+71
-15
lines changed

5 files changed

+71
-15
lines changed

docs/checks.md

Lines changed: 53 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ List of checks:
3737
- [Permissions](#permissions)
3838
- [Reusable workflows](#check-reusable-workflows)
3939
- [ID naming convention](#id-naming-convention)
40-
- [Contexts and special functions availability](#ctx-spfunc-availability)
40+
- [Availability of contexts and special functions](#ctx-spfunc-availability)
4141
- [Deprecated workflow commands](#check-deprecated-workflow-commands)
4242
- [Conditions always evaluated to true at `if:`](#if-cond-always-true)
4343
- [Action metadata syntax validation](#action-metadata-syntax)
@@ -395,8 +395,6 @@ jobs:
395395
# Function overloads can be handled properly. contains() has string version and array version
396396
- run: echo "${{ contains('hello, world', 'lo,') }}"
397397
- run: echo "${{ contains(github.event.labels.*.name, 'enhancement') }}"
398-
# format() has a special check for formatting string
399-
- run: echo "${{ format('{0}{1}', 1, 2, 3) }}"
400398
```
401399
402400
Output:
@@ -422,13 +420,9 @@ test.yaml:15:51: 2nd argument of function call is not assignable. "object" canno
422420
|
423421
15 | - run: echo "${{ startsWith('hello, world', github.event) }}"
424422
| ^~~~~~~~~~~~~
425-
test.yaml:20:24: format string "{0}{1}" does not contain placeholder {2}. remove argument which is unused in the format string [expression]
426-
|
427-
20 | - run: echo "${{ format('{0}{1}', 1, 2, 3) }}"
428-
| ^~~~~~~~~~~~~~~~
429423
```
430424
431-
[Playground](https://rhysd.github.io/actionlint/#eNqckMFOwzAQRO/9ilGF5IKciMItP8IROWHBAWe3yq4pUuR/Ry4SAqnNoScf5r3xaIU7HLLGzbv02m0AI7X6AnNmbWqe+8yWmxRqdorU6KA/FNBUsgMNUeBulgWZP1iO/DwIG30ZSnGX0LfRYu5b+iQ2vQBuK6gWZnsaLe5cpJTE4yhzenEeLol3tyhlu+rqGfk6y/9bvdpRLxBG1itG/6p/P2tT6Clpe9dymMjDEcfAA03Etl73KvMUbOeW+7Lsi/PYezx4PJ6k7wAAAP//nfWd6A==)
425+
[Playground](https://rhysd.github.io/actionlint/#eNqckEFKxjAQhfc9xVCEqKQ5QC/iUpI6mGo6UzoTK5TcXWJB/OFvF11l8b7v5TFMPcxZYvPBQfoGQFG0vgBLJulqnkMmzV3yNfuNRHGWnQLoKtkDDpHBPGwbZPokXul1YFL8VijFHKHvo8YcHH4hqRyAbQVF/aIvo8ZHEzEltrDykt6MBZPYmicopT115Y58zbI3q0876gX8SHJh9J/6/zOXfMAk7tmRn9CCQYqeBpyQdK/7CQAA//9h6o/Y)
432426
433427
[Contexts][contexts-doc] and [built-in functions][funcs-doc] are strongly typed. Typos in property access of contexts and
434428
function names can be checked. And invalid function calls like wrong number of arguments or type mismatch at parameter also
@@ -440,11 +434,58 @@ The semantics checker can properly handle that
440434
- some parameters are optional (e.g. `join(strings, sep)` and `join(strings)`)
441435
- some parameters are repeatable (e.g. `hashFiles(file1, file2, ...)`)
442436

443-
In addition, `format()` function has a special check for placeholders in the first parameter which represents the formatting
444-
string.
445-
446437
Note that context names and function names are case-insensitive. For example, `toJSON` and `toJson` are the same function.
447438

439+
In addition, actionlint performs special checks on some built-in functions.
440+
441+
- `format()`: Checks placeholders in the first parameter which represents the format string.
442+
- `fromJSON()`: Checks the JSON string is valid and the return value is strongly typed.
443+
444+
Example input:
445+
446+
```yaml
447+
on: push
448+
449+
jobs:
450+
test:
451+
# ERROR: Key 'mac' does not exist in the object returned by the fromJSON()
452+
runs-on: ${{ fromJSON('{"win":"windows-latest","linux":"ubuntul-latest"}')['mac'] }}
453+
steps:
454+
# ERROR: {2} is missing in the first argument of format()
455+
- run: echo "${{ format('{0}{1}', 1, 2, 3) }}"
456+
# ERROR: Argument for {2} is missing in the arguments of format()
457+
- run: echo "${{ format('{0}{1}{2}', 1, 2) }}"
458+
- run: echo This is a special branch!
459+
# ERROR: Broken JSON string. Special check for fromJSON()
460+
if: contains(fromJson('["main","release","dev"'), github.ref_name)
461+
```
462+
463+
Output:
464+
465+
```
466+
test.yaml:6:18: property "mac" is not defined in object type {linux: string; win: string} [expression]
467+
|
468+
6 | runs-on: ${{ fromJSON('{"win":"windows-latest","linux":"ubuntul-latest"}')['mac'] }}
469+
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
470+
test.yaml:9:24: format string "{0}{1}" does not contain placeholder {2}. remove argument which is unused in the format string [expression]
471+
|
472+
9 | - run: echo "${{ format('{0}{1}', 1, 2, 3) }}"
473+
| ^~~~~~~~~~~~~~~~
474+
test.yaml:11:24: format string "{0}{1}{2}" contains placeholder {2} but only 2 arguments are given to format [expression]
475+
|
476+
11 | - run: echo "${{ format('{0}{1}{2}', 1, 2) }}"
477+
| ^~~~~~~~~~~~~~~~~~~
478+
test.yaml:14:31: broken JSON string is passed to fromJSON() at offset 23: unexpected end of JSON input [expression]
479+
|
480+
14 | if: contains(fromJson('["main","release","dev"'), github.ref_name)
481+
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
482+
```
483+
484+
[Playground](https://rhysd.github.io/actionlint/#eNqMj0FL9DAQhu/7K95v+CAtZMVdb/kJHvSgt0Uk7aY20k5KJnGFkP8ure5R8DJzmPeZhzewwZJl3O3eQydmByQnad1AzCz7NfC/FAwxzPdPjw+NKnTxTGad53CR/WRXhDRNnvMnGcpd5pSn66Gq9qRm26sX1Lo9luQW+XYA+9Vj4PoxgDZTiLNNjSq3tRyq0jhoHDXuWtRKf4PK8cr9Bj2PXuAFFrK43tsJXbTcj/9+soAfDPrAyXqWZmsvgRt1otl6Jk3RTc6KI01n90Gq1XjzaczdTXTDK9vZtV8BAAD//8ITaRA=)
485+
486+
GitHub Actions does not provide the syntax to create an array or object constant. It [is popular](https://github.com/search?q=fromJSON%28%27+lang%3Ayaml&type=code)
487+
to create such constants via `fromJSON()`.
488+
448489
<a id="check-contextual-step-object"></a>
449490
## Contextual typing for `steps.<step_id>` objects
450491

@@ -2578,7 +2619,7 @@ IDs must start with a letter or `_` and contain only alphanumeric characters, `-
25782619
convention, and reports invalid IDs as errors.
25792620

25802621
<a id="ctx-spfunc-availability"></a>
2581-
## Contexts and special functions availability
2622+
## Availability of contexts and special functions
25822623

25832624
Example input:
25842625

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
test.yaml:6:18: property "mac" is not defined in object type {linux: string; win: string} [expression]
2+
test.yaml:9:24: format string "{0}{1}" does not contain placeholder {2}. remove argument which is unused in the format string [expression]
3+
test.yaml:11:24: format string "{0}{1}{2}" contains placeholder {2} but only 2 arguments are given to format [expression]
4+
test.yaml:14:31: broken JSON string is passed to fromJSON() at offset 23: unexpected end of JSON input [expression]
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
on: push
2+
3+
jobs:
4+
test:
5+
# ERROR: Key 'mac' does not exist in the object returned by the fromJSON()
6+
runs-on: ${{ fromJSON('{"win":"windows-latest","linux":"ubuntul-latest"}')['mac'] }}
7+
steps:
8+
# ERROR: {2} is missing in the first argument of format()
9+
- run: echo "${{ format('{0}{1}', 1, 2, 3) }}"
10+
# ERROR: Argument for {2} is missing in the arguments of format()
11+
- run: echo "${{ format('{0}{1}{2}', 1, 2) }}"
12+
- run: echo This is special branch!
13+
# ERROR: Broken JSON string. Special check for fromJSON()
14+
if: contains(fromJson('["main","release","dev"'), github.ref_name)

testdata/examples/contexts_and_builtin_funcs.out

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,3 @@ test.yaml:7:24: undefined variable "unknown_context". available variables are "e
33
test.yaml:11:24: undefined function "startWith". available functions are "always", "cancelled", "contains", "endswith", "failure", "format", "fromjson", "hashfiles", "join", "startswith", "success", "tojson" [expression]
44
test.yaml:13:24: number of arguments is wrong. function "startsWith(string, string) -> bool" takes 2 parameters but 1 arguments are given [expression]
55
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]
6-
test.yaml:20:24: format string "{0}{1}" does not contain placeholder {2}. remove argument which is unused in the format string [expression]

testdata/examples/contexts_and_builtin_funcs.yaml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,3 @@ jobs:
1616
# Function overloads can be handled properly. contains() has string version and array version
1717
- run: echo "${{ contains('hello, world', 'lo,') }}"
1818
- run: echo "${{ contains(github.event.labels.*.name, 'enhancement') }}"
19-
# format() has a special check for formatting string
20-
- run: echo "${{ format('{0}{1}', 1, 2, 3) }}"

0 commit comments

Comments
 (0)