Skip to content

Commit de21be9

Browse files
authored
Merge pull request #695 from w3lld1/feat/github-workflow-timeout-hook
Add GitHub workflow timeout pre-commit hook
2 parents c9b1ca5 + 3e0fde4 commit de21be9

6 files changed

Lines changed: 79 additions & 19 deletions

File tree

.pre-commit-hooks.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,3 +352,14 @@
352352
^\.woodpecker/.+\.(yml|yaml)$
353353
)$
354354
types: [yaml]
355+
356+
# this hook is autogenerated from a script
357+
# to modify this hook, update `src/check_jsonschema/catalog.py`
358+
# and run `just generate-hooks` or `tox run -e generate-hooks-config`
359+
- id: check-github-workflows-require-timeout
360+
name: Require timeout-minutes in GitHub Workflows
361+
description: 'Validate that all GitHub Workflow jobs set timeout-minutes'
362+
entry: check-jsonschema --builtin-schema custom.github-workflows-require-timeout
363+
language: python
364+
files: ^\.github/workflows/[^/]+$
365+
types: [yaml]

CHANGELOG.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ Unreleased
1010

1111
.. vendor-insert-here
1212
13+
- Add a dedicated ``check-github-workflows-require-timeout`` pre-commit hook for
14+
requiring ``timeout-minutes`` on all GitHub Workflow jobs. (:issue:`639`)
15+
1316
0.37.4
1417
------
1518

docs/precommit_usage.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,20 @@ Validate Woodpecker Config against the schema provided by SchemaStore
407407
- id: check-woodpecker-ci
408408
409409
410+
``check-github-workflows-require-timeout``
411+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
412+
413+
Validate that all GitHub Workflow jobs set timeout-minutes
414+
415+
.. code-block:: yaml
416+
:caption: example config
417+
418+
- repo: https://github.com/python-jsonschema/check-jsonschema
419+
rev: 0.37.4
420+
hooks:
421+
- id: check-github-workflows-require-timeout
422+
423+
410424
.. generated-hook-list-end
411425
412426

scripts/generate-hooks-config.py

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,31 @@
44
import importlib.metadata
55
import typing as t
66

7-
from check_jsonschema.catalog import SCHEMA_CATALOG
7+
from check_jsonschema.catalog import CUSTOM_SCHEMA_CATALOG, SCHEMA_CATALOG
88

99
version = importlib.metadata.version("check_jsonschema")
1010

1111

1212
def iter_catalog_hooks():
13-
for name in SCHEMA_CATALOG:
14-
# copy config (new dict)
15-
config = dict(SCHEMA_CATALOG[name]["hook_config"])
16-
# set computed attributes
17-
config["schema_name"] = name
18-
config["id"] = f"check-{name}"
19-
config["description"] = (
20-
config.get("description")
21-
or f"{config['name']} against the schema provided by SchemaStore"
22-
)
23-
if "types" in config and isinstance(config["types"], str):
24-
config["types"] = [config["types"]]
25-
yield config
13+
catalogs = (
14+
("vendor", SCHEMA_CATALOG),
15+
("custom", CUSTOM_SCHEMA_CATALOG),
16+
)
17+
for schema_namespace, catalog in catalogs:
18+
for name in catalog:
19+
# copy config (new dict)
20+
config = dict(catalog[name]["hook_config"])
21+
# set computed attributes
22+
config["schema_name"] = name
23+
config["schema_namespace"] = schema_namespace
24+
config["id"] = f"check-{name}"
25+
config["description"] = (
26+
config.get("description")
27+
or f"{config['name']} against the schema provided by SchemaStore"
28+
)
29+
if "types" in config and isinstance(config["types"], str):
30+
config["types"] = [config["types"]]
31+
yield config
2632

2733

2834
def update_hook_config(new_config: str) -> None:
@@ -54,7 +60,7 @@ def generate_hook_lines(config) -> t.Iterator[str]:
5460
add_args = " " + add_args
5561
yield (
5662
" entry: check-jsonschema --builtin-schema "
57-
f"vendor.{config['schema_name']}{add_args}"
63+
f"{config['schema_namespace']}.{config['schema_name']}{add_args}"
5864
)
5965

6066
yield " language: python"

src/check_jsonschema/catalog.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,20 @@ def _githubusercontent_url(owner: str, repo: str, ref: str, path: str) -> str:
1111
return f"https://raw.githubusercontent.com/{owner}/{repo}/{ref}/{path}"
1212

1313

14-
# this lists custom schemas which are *not* part of the catalog
15-
CUSTOM_SCHEMA_NAMES = [
16-
"github-workflows-require-timeout",
17-
]
14+
# this lists custom schemas which are *not* part of the vendored schema catalog
15+
CUSTOM_SCHEMA_CATALOG: dict[str, dict[str, t.Any]] = {
16+
"github-workflows-require-timeout": {
17+
"hook_config": {
18+
"name": "Require timeout-minutes in GitHub Workflows",
19+
"description": (
20+
"Validate that all GitHub Workflow jobs set timeout-minutes"
21+
),
22+
"files": r"^\.github/workflows/[^/]+$",
23+
"types": "yaml",
24+
},
25+
},
26+
}
27+
CUSTOM_SCHEMA_NAMES = list(CUSTOM_SCHEMA_CATALOG)
1828

1929
# Known configs. The SchemaCatalog lists known schema URLs with their names.
2030
# kept in alphabetical order by name

tests/unit/test_catalog.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,19 @@ def test_hooks_cover_catalog():
2121
config_hook_ids = {x["id"] for x in config}
2222
catalog_hook_ids = {f"check-{name}" for name in SCHEMA_CATALOG}
2323
assert catalog_hook_ids <= config_hook_ids
24+
25+
26+
def test_github_workflows_require_timeout_hook_uses_custom_schema():
27+
with open(CONFIG_FILE, "rb") as fp:
28+
config = yaml.load(fp)
29+
30+
hook = next(
31+
item
32+
for item in config
33+
if item["id"] == "check-github-workflows-require-timeout"
34+
)
35+
assert hook["entry"] == (
36+
"check-jsonschema --builtin-schema custom.github-workflows-require-timeout"
37+
)
38+
assert hook["files"] == r"^\.github/workflows/[^/]+$"
39+
assert hook["types"] == ["yaml"]

0 commit comments

Comments
 (0)