-
Notifications
You must be signed in to change notification settings - Fork 183
/
actions_ci.py
150 lines (118 loc) · 6.07 KB
/
actions_ci.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#!/usr/bin/env python
import os
import re
import yaml
def actions_ci(self):
"""Checks that the GitHub Actions pipeline CI (Continuous Integration) workflow is valid.
The ``.github/workflows/ci.yml`` GitHub Actions workflow runs the pipeline on a minimal test
dataset using ``-profile test`` to check that no breaking changes have been introduced.
Final result files are not checked, just that the pipeline exists successfully.
This lint test checks this GitHub Actions workflow file for the following:
* Workflow must be triggered on the following events:
.. code-block:: yaml
on:
push:
branches:
- dev
pull_request:
release:
types: [published]
* The minimum Nextflow version specified in the pipeline's ``nextflow.config`` matches that defined by ``nxf_ver`` in the test matrix:
.. code-block:: yaml
:emphasize-lines: 4
strategy:
matrix:
# Nextflow versions: check pipeline minimum and current latest
nxf_ver: ['19.10.0', '']
.. note:: These ``matrix`` variables run the test workflow twice, varying the ``nxf_ver`` variable each time.
This is used in the ``nextflow run`` commands to test the pipeline with both the latest available version
of the pipeline (``''``) and the stated minimum required version.
* The `Docker` container for the pipeline must use the correct pipeline version number:
* Development pipelines:
.. code-block:: bash
docker tag nfcore/<pipeline_name>:dev nfcore/<pipeline_name>:dev
* Released pipelines:
.. code-block:: bash
docker tag nfcore/<pipeline_name>:dev nfcore/<pipeline_name>:<pipeline-version>
* Complete example for a released pipeline called *nf-core/example* with version number ``1.0.0``:
.. code-block:: yaml
:emphasize-lines: 3,8,9
- name: Build new docker image
if: env.GIT_DIFF
run: docker build --no-cache . -t nfcore/example:1.0.0
- name: Pull docker image
if: ${{ !env.GIT_DIFF }}
run: |
docker pull nfcore/example:dev
docker tag nfcore/example:dev nfcore/example:1.0.0
"""
passed = []
failed = []
fn = os.path.join(self.wf_path, ".github", "workflows", "ci.yml")
# Return an ignored status if we can't find the file
if not os.path.isfile(fn):
return {"ignored": ["'.github/workflows/ci.yml' not found"]}
try:
with open(fn, "r") as fh:
ciwf = yaml.safe_load(fh)
except Exception as e:
return {"failed": ["Could not parse yaml file: {}, {}".format(fn, e)]}
# Check that the action is turned on for the correct events
try:
# NB: YAML dict key 'on' is evaluated to a Python dict key True
assert "dev" in ciwf[True]["push"]["branches"]
pr_subtree = ciwf[True]["pull_request"]
assert (
pr_subtree == None
or ("branches" in pr_subtree and "dev" in pr_subtree["branches"])
or ("ignore_branches" in pr_subtree and not "dev" in pr_subtree["ignore_branches"])
)
assert "published" in ciwf[True]["release"]["types"]
except (AssertionError, KeyError, TypeError):
failed.append("'.github/workflows/ci.yml' is not triggered on expected events")
else:
passed.append("'.github/workflows/ci.yml' is triggered on expected events")
# Check that we're pulling the right docker image and tagging it properly
if self.nf_config.get("process.container", ""):
docker_notag = re.sub(r":(?:[\.\d]+|dev)$", "", self.nf_config.get("process.container", "").strip("\"'"))
docker_withtag = self.nf_config.get("process.container", "").strip("\"'")
# docker build
docker_build_cmd = "docker build --no-cache . -t {}".format(docker_withtag)
try:
steps = ciwf["jobs"]["test"]["steps"]
assert any([docker_build_cmd in step["run"] for step in steps if "run" in step.keys()])
except (AssertionError, KeyError, TypeError):
failed.append("CI is not building the correct docker image. Should be: `{}`".format(docker_build_cmd))
else:
passed.append("CI is building the correct docker image: `{}`".format(docker_build_cmd))
# docker pull
docker_pull_cmd = "docker pull {}:dev".format(docker_notag)
try:
steps = ciwf["jobs"]["test"]["steps"]
assert any([docker_pull_cmd in step["run"] for step in steps if "run" in step.keys()])
except (AssertionError, KeyError, TypeError):
failed.append("CI is not pulling the correct docker image. Should be: `{}`".format(docker_pull_cmd))
else:
passed.append("CI is pulling the correct docker image: {}".format(docker_pull_cmd))
# docker tag
docker_tag_cmd = "docker tag {}:dev {}".format(docker_notag, docker_withtag)
try:
steps = ciwf["jobs"]["test"]["steps"]
assert any([docker_tag_cmd in step["run"] for step in steps if "run" in step.keys()])
except (AssertionError, KeyError, TypeError):
failed.append("CI is not tagging docker image correctly. Should be: `{}`".format(docker_tag_cmd))
else:
passed.append("CI is tagging docker image correctly: {}".format(docker_tag_cmd))
# Check that we are testing the minimum nextflow version
try:
matrix = ciwf["jobs"]["test"]["strategy"]["matrix"]["include"]
assert any([i["NXF_VER"] == self.minNextflowVersion for i in matrix])
except (KeyError, TypeError):
failed.append("'.github/workflows/ci.yml' does not check minimum NF version")
except AssertionError:
failed.append(
f"Minimum pipeline NF version '{self.minNextflowVersion}' is not tested in '.github/workflows/ci.yml'"
)
else:
passed.append("'.github/workflows/ci.yml' checks minimum NF version")
return {"passed": passed, "failed": failed}