Skip to content

Commit 145cc3a

Browse files
committed
update and add table menu
1 parent 509a7f5 commit 145cc3a

File tree

1 file changed

+59
-34
lines changed

1 file changed

+59
-34
lines changed

article/article.md

Lines changed: 59 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,82 @@
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.
1+
Hello everyone, I am a Data Platform or DataOps Engineer at [FreshBooks](https://www.freshbooks.com/). In this article I would like to share my experience on configure best practices in CI/CD pipelines. We had a linter configuration that developers could run before submitting PR. We understand that we want to integrate that checks into our regular CI/CD pipeline. This adoption helps to eliminate potential errors, bugs, stylistic errors, and basically have the common code style across the team.
32

4-
As we are in FreshBooks using GitHub, so we would like to use it as much as possible.
3+
We are in FreshBooks using GitHub as a home for our code base, so we would like to use it as much as possible. Recently I finished this configuration so linter and its checks are now part of GitHub actions CI/CD workflow.
54

6-
Recently I was involved in configuring linters as a part of CI/CD in GitHub actions.
5+
This article has two major parts: the first one is linter configuration, and the second one is GitHub workflow configuration itself. Feel free to read all the parts, or skip some and jump into specific one you are interested in.
6+
7+
- [Linters configuration](#linters-configuration)
8+
* [Disable unwanted checks](#disable-unwanted-checks)
9+
+ [Documentation](#documentation)
10+
+ [Import error](#import-error)
11+
+ [Tweaks for airflow code](#tweaks-for-airflow-code)
12+
- [GitHub workflow actions CI/CD configurations](#github-workflow-actions-ci-cd-configurations)
13+
* [When to run it](#when-to-run-it)
14+
* [What files does it run against to](#what-files-does-it-run-against-to)
15+
* [Run linter itself](#run-linter-itself)
16+
- [Conclusion](#conclusion)
717

818
## Linters configuration
919

20+
**Disclaimer**: author assumes you are familiar with the above-mentioned linters, tools, and checks.
21+
22+
Here are the linters and checks we are going to use:
23+
24+
- [flake8](https://flake8.pycqa.org/en/latest/)
25+
- [flakeheaven](https://flakeheaven.readthedocs.io/en/latest/)
26+
- [black](https://github.com/psf/black)
27+
- [isort](https://github.com/PyCQA/isort)
28+
1029
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).
1130

12-
We use flakeheaven as a 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
31+
We use flakeheaven as a flake8 wrapper, which is very easy to configure in one single `pyproject.toml`. The whole `pyproject.toml` configuration file could be found in
1432
a [repo](https://github.com/iamtodor/github-actions-python-configuration-demo/blob/main/pyproject.toml).
1533

1634
![pyproject.toml](https://github.com/iamtodor/github-actions-python-configuration-demo/blob/main/article/img/flakeheaven-pyproject-config.png?raw=true)
1735

18-
Disclaimer: author assumes you are familiar with the 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.
36+
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.
37+
38+
### Disable unwanted checks
2039

2140
A few checks that we don't want to see complain about:
2241

23-
### Documentation
42+
#### Documentation
2443

2544
We are ok if not every module will be documented. We are ok if not every function or method will be documented.
2645

2746
![flakeheaven disable docs](https://github.com/iamtodor/github-actions-python-configuration-demo/blob/main/article/img/flakeheaven-disable-docs.png?raw=true)
2847

29-
### Import issues
48+
#### Import error
49+
50+
Our linter requirements live in a separate file, and we don't aim to mix it with our main production requirements. Hence, linter would complain about import libraries as linter env does not have production libraries, quite obvious.
51+
52+
```
53+
>>> python -m flakeheaven lint .
54+
55+
dags/dummy.py
56+
3: 1 E0401 Unable to import 'airflow' (import-error) [pylint]
57+
from airflow import DAG
58+
^
59+
4: 1 E0401 Unable to import 'airflow.operators.dummy_operator' (import-error) [pylint]
60+
from airflow.operators.dummy_operator import DummyOperator
61+
^
62+
```
3063

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.
64+
So we need to disable this check:
3665

3766
![flakeheaven disable import checks](https://github.com/iamtodor/github-actions-python-configuration-demo/blob/main/article/img/flakeheaven-disable-import-checks.png?raw=true)
3867

39-
### Tweaks for airflow code
68+
We assume that the developer who writes the code and imports the libs is responsible for the writing reliable tests. So if the test does not pass it means that it's something with import or a code (logic) itself. Import check is not something we would like to put as a linter job.
69+
70+
#### Tweaks for airflow code
4071

4172
To configure code for Airflow DAGs there are also a few tweaks. Here is the dummy example `dummy.py`.
4273

4374
![python dummy DAG](https://github.com/iamtodor/github-actions-python-configuration-demo/blob/main/article/img/python-airflow-tasks-order.png?raw=true)
4475

45-
If we run flakeheaven with the default configuration we would see the following error:
76+
If we run `flakeheaven` with the default configuration we would see the following error:
4677

4778
```
48-
python -m flakeheaven lint .
79+
>>> python -m flakeheaven lint .
4980
5081
dags/dummy.py
5182
17: 9 W503 line break before binary operator [pycodestyle]
@@ -59,49 +90,43 @@ dags/dummy.py
5990
^
6091
```
6192

62-
However, we want to keep each task specified in a new line, hence we need to disable `W503` from pycodestyle: Disable
63-
line break before binary operator.
93+
However, we want to keep each task specified in a new line, hence we need to disable `W503` from pycodestyle.
6494

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

6797
Next, with the default configuration we would get the next warning:
6898

6999
```
70-
python -m flakeheaven lint .
100+
>>> python -m flakeheaven lint .
71101
72102
dags/dummy.py
73103
15: 5 W0104 Statement seems to have no effect (pointless-statement) [pylint]
74104
(
75105
^
76106
```
77107

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.
108+
This is about how we specify task order. The workaround here is to exclude `W0104` from pylint.
80109

81110
![disable W0104](https://github.com/iamtodor/github-actions-python-configuration-demo/blob/main/article/img/flakeheaven-disable-statement-no-effect-W0104.png?raw=true)
82111

83-
## GitHub actions configurations
112+
## GitHub workflow actions CI/CD configurations
84113

85114
**Disclaimer**: author assumes you are familiar with [GitHub actions](https://github.com/features/actions).
86115

87116
We configure GitHub Workflow to be triggered on every PR against the main (master) branch.
88117

89-
Here are the linters and checks we are going to use:
90-
91-
- [flake8](https://flake8.pycqa.org/en/latest/)
92-
- [flakeheaven](https://flakeheaven.readthedocs.io/en/latest/)
93-
- [black](https://github.com/psf/black)
94-
- [isort](https://github.com/PyCQA/isort)
95-
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.
118+
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). I will walk you thru it step by step.
98119

99120
![py_linter.yml](https://github.com/iamtodor/github-actions-python-configuration-demo/blob/main/article/img/gh-config-full.png?raw=true)
100121

122+
### When to run it
123+
101124
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.
102125

103126
![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)
104127

128+
### What files does it run against to
129+
105130
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), which is very flexible.
106131

107132
![Paths Filter GitHub Action](https://github.com/iamtodor/github-actions-python-configuration-demo/blob/main/article/img/gh-config-paths-filter.png?raw=true)
@@ -116,7 +141,7 @@ I define the variable where I can find the output (the only `.py` files) from th
116141

117142
![list files shell](https://github.com/iamtodor/github-actions-python-configuration-demo/blob/main/article/img/gh-config-list-files-shell.png?raw=true)
118143

119-
### Run linter
144+
### Run linter itself
120145

121146
The next and last step is to run the linter itself.
122147

0 commit comments

Comments
 (0)