Repository: python-jsonschema/check-jsonschema

Issue:
[BUG] `github-workflows-require-timeout.json`: `timeout-minutes` should allow expressions
$sbj. I want to have `timeout-minutes: ${{ inputs.qemu && '60' || '20' }}` set for a job. The `inputs` is a context that exists in reusable workflows. Here's the table of context availability FTR: https://docs.github.com/en/actions/learn-github-actions/contexts.

Here's how it fails for me:
```console
  .github/workflows/reusable-build-wheel.yml::$.jobs.build-wheel: {'name': 'Build wheels on ${{ inputs.os }} ${{ inputs.qemu }}', 'runs-on': '${{ inputs.os }}-latest', 'timeout-minutes': '${{ inputs.qemu && 60 || 20 }}', 'steps': [{'name': 'Retrieve the project source from an sdist inside the GHA artifact', 'uses': 're-actors/checkout-python-sdist@release/v1', 'with': {'source-tarball-name': '${{ inputs.source-tarball-name }}', 'workflow-artifact-name': '${{ inputs.dists-artifact-name }}'}}, {'name': 'Set up QEMU', 'if': 'inputs.qemu', 'uses': 'docker/setup-qemu-action@v3', 'with': {'platforms': 'all'}, 'id': 'qemu'}, {'name': 'Prepare emulation', 'if': 'inputs.qemu', 'run': '# Build emulated architectures only if QEMU is set,\n# use default "auto" otherwise\necho "CIBW_ARCHS_LINUX=${{ inputs.qemu }}" >> "${GITHUB_ENV}"\n', 'shell': 'bash'}, {'name': 'Setup Python', 'uses': 'actions/setup-python@v4'}, {'name': 'Build wheels', 'uses': 'pypa/cibuildwheel@v2.16.2', 'env': {'CIBW_ARCHS_MACOS': 'x86_64 arm64 universal2'}}, {'name': 'Upload built artifacts for testing and publishing', 'uses': 'actions/upload-artifact@v3', 'with': {'name': '${{ inputs.dists-artifact-name }}', 'path': './wheelhouse/*.whl'}}]} is not valid under any of the given schemas
  Underlying errors caused this.

  Best Match:
    $.jobs.build-wheel: 'uses' is a required property
  Best Deep Match:
    $.jobs.build-wheel.timeout-minutes: '${{ inputs.qemu && 60 || 20 }}' is not of type 'number'
```

Approximate reusable workflow look:
```yaml
# partial file, specific bit that is failing
on:
  workflow-call:
    inputs:
      ...
      qemu:
          default: ''
          ...
          required: false
          ...
      ...
...
jobs:
  job-id:
    ...
    timeout-minutes: ${{ inputs.qemu && '60' || '20' }}
    ...
```

Haven't looked into how to fix this, but the upstream [`github-workflow.json`](https://github.com/webknjaz/schemastore/blob/master/src/schemas/json/github-workflow.json) doesn't error out, so this custom schema must be too strict...

Comments:

Patch:
diff --git a/src/check_jsonschema/builtin_schemas/custom/github-workflows-require-timeout.json b/src/check_jsonschema/builtin_schemas/custom/github-workflows-require-timeout.json
index 59f427a..7d92081 100644
--- a/src/check_jsonschema/builtin_schemas/custom/github-workflows-require-timeout.json
+++ b/src/check_jsonschema/builtin_schemas/custom/github-workflows-require-timeout.json
@@ -1,6 +1,13 @@
 {
   "$schema": "http://json-schema.org/draft-07/schema",
   "$comment": "A schema which requires that github workflow jobs define job timeouts",
+  "definitions": {
+    "expressionSyntax": {
+      "type": "string",
+      "$comment": "pattern definition taken from schemastore 'github-workflow.json'",
+      "pattern": "^\\$\\{\\{(.|[\r\n])*\\}\\}$"
+    }
+  },
   "properties": {
     "jobs": {
       "$comment": "https://help.github.com/en/github/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions#jobs",
@@ -15,8 +22,15 @@
                 "timeout-minutes": {
                   "$comment": "https://help.github.com/en/actions/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions#jobsjob_idtimeout-minutes",
                   "description": "The maximum number of minutes to let a workflow run before GitHub automatically cancels it. Default: 360",
-                  "type": "number",
-                  "default": 360
+                  "default": 360,
+                  "oneOf": [
+                    {
+                      "type": "number"
+                    },
+                    {
+                      "$ref": "#/definitions/expressionSyntax"
+                    }
+                  ]
                 }
               },
               "required": [


Test patch:
diff --git a/tests/acceptance/test_example_files.py b/tests/acceptance/test_example_files.py
index 3b23e2c..94980f8 100644
--- a/tests/acceptance/test_example_files.py
+++ b/tests/acceptance/test_example_files.py
@@ -64,7 +64,7 @@ def test_hook_positive_examples(case_name, run_line):
 
     hook_id = POSITIVE_HOOK_CASES[case_name]
     ret = run_line(HOOK_CONFIG[hook_id] + [rcase.path] + rcase.add_args)
-    assert ret.exit_code == 0
+    assert ret.exit_code == 0, _format_cli_result(rcase, ret)
 
 
 @pytest.mark.parametrize("case_name", NEGATIVE_HOOK_CASES.keys())
@@ -73,7 +73,7 @@ def test_hook_negative_examples(case_name, run_line):
 
     hook_id = NEGATIVE_HOOK_CASES[case_name]
     ret = run_line(HOOK_CONFIG[hook_id] + [rcase.path] + rcase.add_args)
-    assert ret.exit_code == 1
+    assert ret.exit_code == 1, _format_cli_result(rcase, ret)
 
 
 @pytest.mark.parametrize("case_name", _get_explicit_cases("positive"))
@@ -167,3 +167,13 @@ def _package_is_installed(pkg: str) -> bool:
     if spec is None:
         return False
     return True
+
+
+def _format_cli_result(rcase: ResolvedCase, result) -> str:
+    return (
+        "\n"
+        f"config.add_args={rcase.add_args}\n"
+        f"{result.exit_code=}\n"
+        f"result.stdout={result.output}\n"
+        f"{result.stderr=}"
+    )
diff --git a/tests/example-files/hooks/negative/jsonschema/_config.yaml b/tests/example-files/hooks/negative/jsonschema/_config.yaml
new file mode 100644
index 0000000..68e9596
--- /dev/null
+++ b/tests/example-files/hooks/negative/jsonschema/_config.yaml
@@ -0,0 +1,3 @@
+files:
+  github-workflow-timeout-minutes-expression.yaml:
+    add_args: ["--builtin-schema", "custom.github-workflows-require-timeout"]
diff --git a/tests/example-files/hooks/negative/jsonschema/github-workflow-timeout-minutes-expression.yaml b/tests/example-files/hooks/negative/jsonschema/github-workflow-timeout-minutes-expression.yaml
new file mode 100644
index 0000000..3a7324a
--- /dev/null
+++ b/tests/example-files/hooks/negative/jsonschema/github-workflow-timeout-minutes-expression.yaml
@@ -0,0 +1,12 @@
+on:
+  workflow-call:
+    inputs:
+      qemu:
+          default: ''
+          required: false
+
+jobs:
+  job-id:
+    runs-on: ubuntu-latest
+    # missing trailing '}'
+    timeout-minutes: ${{ inputs.qemu && '60' || '20' }
diff --git a/tests/example-files/hooks/positive/jsonschema/_config.yaml b/tests/example-files/hooks/positive/jsonschema/_config.yaml
new file mode 100644
index 0000000..68e9596
--- /dev/null
+++ b/tests/example-files/hooks/positive/jsonschema/_config.yaml
@@ -0,0 +1,3 @@
+files:
+  github-workflow-timeout-minutes-expression.yaml:
+    add_args: ["--builtin-schema", "custom.github-workflows-require-timeout"]
diff --git a/tests/example-files/hooks/positive/jsonschema/github-workflow-timeout-minutes-expression.yaml b/tests/example-files/hooks/positive/jsonschema/github-workflow-timeout-minutes-expression.yaml
new file mode 100644
index 0000000..4b30a1c
--- /dev/null
+++ b/tests/example-files/hooks/positive/jsonschema/github-workflow-timeout-minutes-expression.yaml
@@ -0,0 +1,11 @@
+on:
+  workflow-call:
+    inputs:
+      qemu:
+          default: ''
+          required: false
+
+jobs:
+  job-id:
+    runs-on: ubuntu-latest
+    timeout-minutes: ${{ inputs.qemu && '60' || '20' }}