Skip to content

Commit e270897

Browse files
committed
add text
1 parent 1ef1a89 commit e270897

File tree

1 file changed

+84
-24
lines changed

1 file changed

+84
-24
lines changed

article/article.md

Lines changed: 84 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,88 @@
1-
Linter helps and advises us about code quality by running sanity checks and displaying warnings and errors about code smells. Also, potentially it helps to prevent bugs in a project.
1+
Linter helps and advises us about code quality by running sanity checks and displaying warnings and errors about code
2+
smells. Also, potentially it helps to prevent bugs in a project.
23

34
As we are in FreshBooks using GitHub, so we would like to use it as much as possible.
45

56
Recently I was involved in configuring linters as a part of CI/CD in GitHub actions.
67

78
## Linters configuration
89

9-
I would like to share how to configure it for the python project. I prepared a full [
10-
github actions python configuration demo repository](https://github.com/iamtodor/github-actions-python-demo).
10+
I would like to share how to configure it for the python project. I prepared a full [github actions python configuration demo repository](https://github.com/iamtodor/github-actions-python-demo).
1111

12-
We use flakeheaven as flake8 wrapper, which is very easy to configure in one single `pyproject.toml` configuration file. The whole `pyproject.toml` configuration file could be found in a [repo](https://github.com/iamtodor/github-actions-python-configuration-demo/blob/main/pyproject.toml).
12+
We use flakeheaven as flake8 wrapper, which is very easy to configure in one single `pyproject.toml` configuration file.
13+
The whole `pyproject.toml` configuration file could be found in
14+
a [repo](https://github.com/iamtodor/github-actions-python-configuration-demo/blob/main/pyproject.toml).
1315

14-
![pyproject.toml](https://i.imgur.com/nNDptBv.png)
16+
![pyproject.toml](https://github.com/iamtodor/github-actions-python-configuration-demo/blob/main/article/img/flakeheaven-pyproject-config.png?raw=true)
1517

16-
Disclaimer: author assumes you are familiar with above-mentioned linters, tools, and checks. I would say the config file is self-explainable, so I will not stop here for a while. Just a few notes about tiny tweaks.
18+
Disclaimer: author assumes you are familiar with above-mentioned linters, tools, and checks. I would say the config file
19+
is self-explainable, so I will not stop here for a while. Just a few notes about tiny tweaks.
1720

1821
A few checks that we don't want to see complain about:
1922

2023
### Documentation
2124

2225
We are ok if not every module will be documented. We are ok if not every function or method will be documented.
2326

24-
![flakeheaven disable docs](https://i.imgur.com/pVfPuJJ.png)
27+
![flakeheaven disable docs](https://github.com/iamtodor/github-actions-python-configuration-demo/blob/main/article/img/flakeheaven-disable-docs.png?raw=true)
2528

2629
### Import issues
2730

28-
Our linter requirements live in a separate file, and we don't aim to mix it with our main production requirements. Hence, linter could complain about import libraries as linter env does not have production libraries, quite obvious. So we need to disable this check. We assume that the developer who writes the code and imports the libs is responsible for the tests. So if the test does not pass it means that it's something with import or a code itself. Import checks it's not something we would like to put as a linter job.
31+
Our linter requirements live in a separate file, and we don't aim to mix it with our main production requirements.
32+
Hence, linter could complain about import libraries as linter env does not have production libraries, quite obvious. So
33+
we need to disable this check. We assume that the developer who writes the code and imports the libs is responsible for
34+
the tests. So if the test does not pass it means that it's something with import or a code itself. Import checks it's
35+
not something we would like to put as a linter job.
2936

30-
![flakeheaven disable import checks](https://i.imgur.com/mYVC7fj.png)
37+
![flakeheaven disable import checks](https://github.com/iamtodor/github-actions-python-configuration-demo/blob/main/article/img/flakeheaven-disable-import-checks.png?raw=true)
3138

32-
### Airflow
39+
### Tweaks for airflow code
3340

3441
In order to configure code for Airflow DAGs there are also a few tweaks. Here is the dummy example `dummy.py`.
3542

36-
## TODO
37-
![flakeheaven disable import checks](https://i.imgur.com/mYVC7fj.png)
43+
![python dummy DAG](https://github.com/iamtodor/github-actions-python-configuration-demo/blob/main/article/img/python-airflow-tasks-order.png?raw=true)
3844

39-
Firstly, we need to exclude `W0104` from pylint: Statement seems to have no effect (pointless-statement). This is about how we specify task order.
45+
If we run flakeheaven with the default configuration we would see the following error:
4046

41-
## TODO
42-
![flakeheaven disable import checks](https://i.imgur.com/mYVC7fj.png)
47+
```
48+
python -m flakeheaven lint .
4349
44-
Then we want to have each task be specified in a new line, hence we need to disable `W503` from pycodestyle: Disable line break before binary operator.
50+
dags/dummy.py
51+
17: 9 W503 line break before binary operator [pycodestyle]
52+
>> dummy_operator_2
53+
^
54+
18: 9 W503 line break before binary operator [pycodestyle]
55+
>> dummy_operator_3
56+
^
57+
19: 9 W503 line break before binary operator [pycodestyle]
58+
>> [dummy_operator_4, dummy_operator_5, dummy_operator_6, dummy_operator_7]
59+
^
60+
```
61+
62+
However, we want to keep each task be specified in a new line, hence we need to disable `W503` from pycodestyle: Disable
63+
line break before binary operator.
4564

4665
![disable W503](https://github.com/iamtodor/github-actions-python-configuration-demo/blob/main/artricle/img/diable-line-break.png?raw=true)
4766

67+
Next, with default configuration we would get the next warning:
68+
69+
```
70+
python -m flakeheaven lint .
71+
72+
dags/dummy.py
73+
15: 5 W0104 Statement seems to have no effect (pointless-statement) [pylint]
74+
(
75+
^
76+
```
77+
78+
The workaround here is to exclude `W0104` from pylint: Statement seems to have no effect (pointless-statement). This is about how we
79+
specify task order.
80+
81+
![disable W0104](https://github.com/iamtodor/github-actions-python-configuration-demo/blob/main/article/img/flakeheaven-disable-statement-no-effect-W0104.png?raw=true)
82+
4883
## GitHub actions configurations
4984

50-
Disclaimer: author assumes you are familiar with [GitHub actions](https://github.com/features/actions)
85+
**Disclaimer**: author assumes you are familiar with [GitHub actions](https://github.com/features/actions).
5186

5287
We configure GitHub Workflow to be triggered on every PR against main (master) branch.
5388

@@ -58,26 +93,51 @@ Here are the linters and checks we are going to use:
5893
- [black](https://github.com/psf/black)
5994
- [isort](https://github.com/PyCQA/isort)
6095

61-
The whole `py_linter.yml` config could be found in a [repo](https://github.com/iamtodor/github-actions-python-demo/blob/main/.github/workflows/py_linter.yml). We will walk thru it step by step.
96+
The whole `py_linter.yml` config could be found in
97+
a [repo](https://github.com/iamtodor/github-actions-python-demo/blob/main/.github/workflows/py_linter.yml). I will walk you thru it step by step.
6298

63-
![py_linter.yml](https://i.imgur.com/UkErWeG.png)
99+
![py_linter.yml](https://github.com/iamtodor/github-actions-python-configuration-demo/blob/main/article/img/gh-config-full.png?raw=true)
64100

65101
We are interested in running linter only when PR has `.py` files. For instance, when we update `README.md` there is no sense to run python linter.
66102

67-
![configure run workflow on PRs and push](https://i.imgur.com/4B5JLqi.png)
103+
![configure run workflow on PRs and push](https://github.com/iamtodor/github-actions-python-configuration-demo/blob/main/article/img/gh-config-py-push-pr.png?raw=true)
68104

69105
We are interested in running a linter only against the modified files. Let's say, we take a look at the provided repo, if I update `dags/dummy.py` I don't want to waste a time and resources running linter against `main.py`. For this purpose we use [Paths Filter GitHub Action](https://github.com/dorny/paths-filter), that is very flexible.
70106

71107
![Paths Filter GitHub Action](https://github.com/iamtodor/github-actions-python-configuration-demo/blob/main/artricle/img/check-for-python-file-changes.png?raw=true)
72108

73-
If we have in one PR modified `.py` and any other files such as `.toml`, we don't want to run linter against not `.py`, so we use where we configured filtering only for `.py` files no matter its location: root, tests, src, etc.
109+
If we have in one PR modified `.py` and any other files such as `.toml`, we don't want to run linter against not `.py`, so we use where we configured filtering only for `.py` files no matter its location: root, tests, src, etc.
74110

75111
Changed file can have the following statuses `added`, `modified`, or `deleted`. There is no reason to run a linter against deleted file as your workflow would simply fail, because there is no more that particular changed file in repo. So we need to configure what changes we consider to trigger linter.
76112

77113
![added|modified](https://github.com/iamtodor/github-actions-python-configuration-demo/blob/main/artricle/img/added-modified.png?raw=true)
78114

79-
I define the variable where I can find the output (the only `.py` files) from the previous filter. This variable would contain modified `.py` files, that I can further pass to a `flakeheaven`, `black`, and `isort`. By default, the output is disabled, and Paths Changes Filter allows to customize it: you can list the files in `.csv`, `.json` or in a `shell` mode. Linters accept files separated simply by space, so our choise here is `shell` mode.
115+
I define the variable where I can find the output (the only `.py` files) from the previous filter. This variable would contain modified `.py` files, that I can further pass to a `flakeheaven`, `black`, and `isort`. By default, the output is disabled, and Paths Changes Filter allows to customize it: you can list the files in `.csv`, `.json` or in a `shell` mode. Linters accept files separated simply by space, so our choice here is `shell` mode.
116+
117+
![list files shell](https://github.com/iamtodor/github-actions-python-configuration-demo/blob/main/article/img/gh-config-list-files-shell.png?raw=true)
118+
119+
### Run linter
120+
121+
The next and last step is to run the linter itself.
122+
123+
![run linter step](https://github.com/iamtodor/github-actions-python-configuration-demo/blob/main/article/img/gh-run-linter.png?raw=true)
124+
125+
Before we run linter on changed files we run a check if there is an actual changes in `.py` files, if there are any `.py` files from the previous step than we can use.
126+
127+
![check if there are .py files](https://github.com/iamtodor/github-actions-python-configuration-demo/blob/main/article/img/gh-config-check-for-changes.png?raw=true)
128+
129+
Next, using the before-mentioned output variable we can safety pass the content from this `steps.filter.outputs.py_scripts_filter_files` variable to linter.
130+
131+
![linter commands](https://github.com/iamtodor/github-actions-python-configuration-demo/blob/main/article/img/gh-config-run-linter-commands.png?raw=true)
132+
133+
## Conclusion
134+
135+
That's all I would like to share. I hope it is useful for you, and you can utilize this experience and knowledge.
136+
137+
I wish you to see this success checks every time you push your code :)
138+
139+
![success linter](https://github.com/iamtodor/github-actions-python-configuration-demo/blob/main/article/img/linter-success.png?raw=true)
80140

81-
![list files shell](https://i.imgur.com/0HjT6Wg.png)
141+
If you have any questions feel free to ask in a comment section, I will do my best to provide compherensive answer for you.
82142

83-
## TODO add usage output
143+
Question to you: do you have a linter checks as a part of your CI/CD?

0 commit comments

Comments
 (0)