mirror of
https://github.com/podman-container-tools/podman.git
synced 2026-08-05 00:15:44 +00:00
validate ci.yml file
Add some basic test checks for the new ci.yml to ensure all job dependencies are set up right. We can expand this with more checks later. Signed-off-by: Paul Holzinger <pholzing@redhat.com>
This commit is contained in:
parent
c4d895b07c
commit
66e7c06073
3 changed files with 47 additions and 98 deletions
6
Makefile
6
Makefile
|
|
@ -276,6 +276,10 @@ help: ## (Default) Print listing of key targets with their descriptions
|
|||
@echo "Validating vs commit '$(call err_if_empty,EPOCH_TEST_COMMIT)'"
|
||||
hack/commit-subject-check.sh $(EPOCH_TEST_COMMIT)..$(HEAD)
|
||||
|
||||
.PHONY: .check-ci-yaml
|
||||
.check-ci-yaml:
|
||||
hack/ci/ci_yaml_test.py
|
||||
|
||||
.PHONY: lint
|
||||
lint: golangci-lint
|
||||
ifeq ($(PRE_COMMIT),)
|
||||
|
|
@ -319,7 +323,7 @@ codespell:
|
|||
|
||||
# Code validation target that **DOES NOT** require building podman binaries
|
||||
.PHONY: validate-source
|
||||
validate-source: lint .commit-subject-check swagger-check tests-expect-exit pr-removes-fixed-skips
|
||||
validate-source: lint .commit-subject-check .check-ci-yaml swagger-check tests-expect-exit pr-removes-fixed-skips
|
||||
|
||||
# Code validation target that **DOES** require building podman binaries
|
||||
.PHONY: validate-binaries
|
||||
|
|
|
|||
42
hack/ci/ci_yaml_test.py
Executable file
42
hack/ci/ci_yaml_test.py
Executable file
|
|
@ -0,0 +1,42 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Verify contents of .github/workflows/ci.yml meet specific expectations
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import unittest
|
||||
import yaml
|
||||
|
||||
# Assumes directory structure of this file relative to repo.
|
||||
SCRIPT_DIRPATH = os.path.dirname(os.path.realpath(__file__))
|
||||
REPO_ROOT = os.path.realpath(os.path.join(SCRIPT_DIRPATH, '../', '../'))
|
||||
|
||||
|
||||
class TestCaseBase(unittest.TestCase):
|
||||
|
||||
CI_YAML = None
|
||||
|
||||
def setUp(self):
|
||||
with open(os.path.join(REPO_ROOT, '.github/workflows/ci.yml')) as ci_yaml:
|
||||
self.CI_YAML = yaml.safe_load(ci_yaml.read())
|
||||
|
||||
|
||||
class TestDependsOn(TestCaseBase):
|
||||
|
||||
ALL_TASK_NAMES = None
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.ALL_TASK_NAMES = list(self.CI_YAML['jobs'].keys())
|
||||
|
||||
|
||||
def test_success_deps(self):
|
||||
"""Specific success task depends on all others"""
|
||||
all_tasks = self.ALL_TASK_NAMES.remove('success')
|
||||
needs = self.CI_YAML['jobs']['success']['needs']
|
||||
self.assertCountEqual(needs, self.ALL_TASK_NAMES)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Verify contents of .cirrus.yml meet specific expectations
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import unittest
|
||||
import yaml
|
||||
|
||||
# Assumes directory structure of this file relative to repo.
|
||||
SCRIPT_DIRPATH = os.path.dirname(os.path.realpath(__file__))
|
||||
REPO_ROOT = os.path.realpath(os.path.join(SCRIPT_DIRPATH, '../', '../'))
|
||||
|
||||
|
||||
class TestCaseBase(unittest.TestCase):
|
||||
|
||||
CIRRUS_YAML = None
|
||||
|
||||
def setUp(self):
|
||||
with open(os.path.join(REPO_ROOT, '.cirrus.yml')) as cirrus_yaml:
|
||||
self.CIRRUS_YAML = yaml.safe_load(cirrus_yaml.read())
|
||||
|
||||
|
||||
class TestDependsOn(TestCaseBase):
|
||||
|
||||
ALL_TASK_NAMES = None
|
||||
# All tasks must be listed as a dependency of one/more of these tasks
|
||||
SUCCESS_DEPS_EXCLUDE = set(['build_success', 'success'])
|
||||
# Tasks which do not influence any success aggregator (above)
|
||||
NONSUCCESS_TASKS = set(['artifacts', 'release', 'release_test'])
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.ALL_TASK_NAMES = set([key.replace('_task', '')
|
||||
for key, _ in self.CIRRUS_YAML.items()
|
||||
if key.endswith('_task')])
|
||||
|
||||
def test_dicts(self):
|
||||
"""Specific tasks exist and always have non-empty depends_on"""
|
||||
for task_name in self.SUCCESS_DEPS_EXCLUDE | self.NONSUCCESS_TASKS:
|
||||
with self.subTest(task_name=task_name):
|
||||
msg = ('Expecting to find a "{0}" task'.format(task_name))
|
||||
self.assertIn(task_name, self.ALL_TASK_NAMES, msg=msg)
|
||||
task = self.CIRRUS_YAML[task_name + '_task']
|
||||
self.assertGreater(len(task['depends_on']), 0)
|
||||
|
||||
def test_task(self):
|
||||
"""There is no task named 'task'"""
|
||||
self.assertNotIn('task', self.ALL_TASK_NAMES)
|
||||
|
||||
def test_depends(self):
|
||||
"""Success aggregator tasks contain dependencies for all other tasks"""
|
||||
success_deps = set()
|
||||
for task_name in self.SUCCESS_DEPS_EXCLUDE:
|
||||
success_deps |= set(self.CIRRUS_YAML[task_name + '_task']['depends_on'])
|
||||
for task_name in self.ALL_TASK_NAMES - self.SUCCESS_DEPS_EXCLUDE - self.NONSUCCESS_TASKS:
|
||||
with self.subTest(task_name=task_name):
|
||||
msg=('No success aggregation task depends_on "{0}"'.format(task_name))
|
||||
self.assertIn(task_name, success_deps, msg=msg)
|
||||
|
||||
def test_duplicate_depends(self):
|
||||
"""Check for duplicate names in depends_on"""
|
||||
for task_name in self.ALL_TASK_NAMES:
|
||||
task = self.CIRRUS_YAML[task_name + '_task']
|
||||
if 'depends_on' in task:
|
||||
depends_on = task['depends_on']
|
||||
seen = set()
|
||||
for x in depends_on:
|
||||
self.assertNotIn(x,seen, msg=f"depends_on contains duplicated names in task {task_name}")
|
||||
seen.add(x)
|
||||
|
||||
def test_only_if(self):
|
||||
"""2024-07 PR#23174: ugly but necessary duplication in only_if conditions. Prevent typos or unwanted changes."""
|
||||
# N/B: This giant string is white space sensitive, take care when updating/modifying
|
||||
beginning = ("$CIRRUS_PR == '' || $CIRRUS_CHANGE_TITLE =~ '.*CI:ALL.*' || changesInclude('.cirrus.yml',"
|
||||
" 'Makefile', 'hack/ci/**', 'vendor/**', 'test/tools/**', 'test/registries*.conf',"
|
||||
" 'hack/**', 'version/rawversion/*') || ")
|
||||
real_source_changes = " || (changesInclude('**/*.go', '**/*.c', '**/*.h') && !changesIncludeOnly('test/**', 'pkg/machine/e2e/**'))"
|
||||
|
||||
for task_name in self.ALL_TASK_NAMES:
|
||||
task = self.CIRRUS_YAML[task_name + '_task']
|
||||
if 'only_if' in task:
|
||||
only_if = task['only_if']
|
||||
if 'changesInclude' in only_if:
|
||||
msg = ('{0}: invalid only_if'.format(task_name))
|
||||
self.assertEqual(only_if[:len(beginning)], beginning, msg=msg+": beginning part is wrong")
|
||||
if 'changesIncludeOnly' in only_if:
|
||||
self.assertEqual(only_if[len(only_if)-len(real_source_changes):], real_source_changes, msg=msg+": changesIncludeOnly() part is wrong")
|
||||
|
||||
def not_task(self):
|
||||
"""Ensure no task is named 'task'"""
|
||||
self.assertNotIn('task', self.ALL_TASK_NAMES)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Loading…
Add table
Reference in a new issue