itw-python-builder 0.2.13__tar.gz → 0.2.14__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- itw_python_builder-0.2.14/PKG-INFO +338 -0
- itw_python_builder-0.2.14/README.md +309 -0
- {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder/tasks.py +17 -5
- {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder/utils.py +45 -0
- itw_python_builder-0.2.14/itw_python_builder.egg-info/PKG-INFO +338 -0
- {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/pyproject.toml +1 -1
- itw_python_builder-0.2.13/PKG-INFO +0 -166
- itw_python_builder-0.2.13/README.md +0 -137
- itw_python_builder-0.2.13/itw_python_builder.egg-info/PKG-INFO +0 -166
- {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/LICENSE +0 -0
- {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder/.pylintrc +0 -0
- {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder/__init__.py +0 -0
- {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder/_pyruntime/sitecustomize.py +0 -0
- {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder/cli.py +0 -0
- {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder/notify.py +0 -0
- {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder/ssr_tasks.py +0 -0
- {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder/task_utils.py +0 -0
- {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder/templates/new_version_email.html +0 -0
- {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder/templates/server.sitemap.snippet.ts +0 -0
- {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder/templates/sitemap.routes.ts +0 -0
- {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder/templates/task_template.md +0 -0
- {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder/version.py +0 -0
- {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder.egg-info/SOURCES.txt +0 -0
- {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder.egg-info/dependency_links.txt +0 -0
- {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder.egg-info/entry_points.txt +0 -0
- {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder.egg-info/requires.txt +0 -0
- {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder.egg-info/top_level.txt +0 -0
- {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/setup.cfg +0 -0
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: itw_python_builder
|
|
3
|
+
Version: 0.2.14
|
|
4
|
+
Summary: Standardized Django deployment pipeline with Docker, testing, and SonarQube integration
|
|
5
|
+
Author-email: IT-Works <contact@it-works.io>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://git.it-works.io/
|
|
8
|
+
Project-URL: Repository, https://git.it-works.io/
|
|
9
|
+
Project-URL: Issues, https://git.it-works.io/
|
|
10
|
+
Keywords: django,deployment,docker,ci-cd,sonarqube
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: invoke>=2.0.0
|
|
24
|
+
Requires-Dist: pylint>=3.0.0
|
|
25
|
+
Requires-Dist: pylint-django>=2.5.0
|
|
26
|
+
Requires-Dist: python-decouple>=3.8
|
|
27
|
+
Requires-Dist: requests>=2.28.0
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
# ITW Python Builder
|
|
31
|
+
|
|
32
|
+
Standardized Django and Angular deployment pipeline with Docker, testing, SonarQube integration, automatic changelog generation, GitLab issue creation, and code quality enforcement.
|
|
33
|
+
|
|
34
|
+
## Features
|
|
35
|
+
|
|
36
|
+
- Automated deployment with semantic versioning
|
|
37
|
+
- Docker/Podman-based build and push pipeline (backend)
|
|
38
|
+
- Angular build, packaging and upload to the GitLab Package Registry (frontend)
|
|
39
|
+
- Angular SSR scaffolding and SSR builds
|
|
40
|
+
- Automated testing with coverage
|
|
41
|
+
- SonarQube static code analysis
|
|
42
|
+
- Pylint linting with SonarQube integration
|
|
43
|
+
- Quality gates - deploy only when tests pass
|
|
44
|
+
- Automatic changelog generation from commit trailers
|
|
45
|
+
- Automatic `CHANGELOG.md` creation and propagation to `staging`/`develop`
|
|
46
|
+
- GitLab issue creation from a markdown file
|
|
47
|
+
- Cached GitLab authentication
|
|
48
|
+
- Support for local and production pipelines
|
|
49
|
+
- Global CLI tool
|
|
50
|
+
- Automatic venv detection per project
|
|
51
|
+
|
|
52
|
+
## Installation
|
|
53
|
+
```bash
|
|
54
|
+
pip install itw-python-builder
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Install globally (outside any project venv). The `itw` command becomes available system-wide.
|
|
58
|
+
|
|
59
|
+
Check the installed version:
|
|
60
|
+
```bash
|
|
61
|
+
itw --version
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Quick Start
|
|
65
|
+
|
|
66
|
+
1. Navigate to your project directory (Django projects must have a `.venv` or `venv`):
|
|
67
|
+
|
|
68
|
+
2. Authenticate with GitLab:
|
|
69
|
+
```bash
|
|
70
|
+
itw login
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
3. Initialize versioning — run it on `staging` first, then on `master`:
|
|
74
|
+
```bash
|
|
75
|
+
git checkout staging && itw tag-init # creates v.0.0.1-rc1
|
|
76
|
+
git checkout master && itw tag-init # promotes the latest staging RC to -release
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
4. Run local pipeline:
|
|
80
|
+
```bash
|
|
81
|
+
itw pipelinelocal
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
5. Deploy to staging:
|
|
85
|
+
```bash
|
|
86
|
+
itw incrementrc
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
6. Deploy to production:
|
|
90
|
+
```bash
|
|
91
|
+
itw incrementpatch
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Available Commands
|
|
95
|
+
|
|
96
|
+
### Deployment Commands
|
|
97
|
+
|
|
98
|
+
- `itw incrementpatch` — Increment patch version and deploy
|
|
99
|
+
- `itw incrementminor` — Increment minor version and deploy
|
|
100
|
+
- `itw incrementmajor` — Increment major version and deploy
|
|
101
|
+
- `itw incrementrc` — Increment release candidate (staging)
|
|
102
|
+
- `itw release` — Promote RC to stable release (master)
|
|
103
|
+
|
|
104
|
+
### Authentication Commands
|
|
105
|
+
|
|
106
|
+
- `itw login` — Capture and cache a GitLab token (backend also logs into the container registry)
|
|
107
|
+
- `itw logout` — Forget the cached token and log out of the container registry
|
|
108
|
+
|
|
109
|
+
### GitLab Issue Commands
|
|
110
|
+
|
|
111
|
+
- `itw task-init` — Create a `TASK.md` template in the current directory
|
|
112
|
+
- `itw task --file=TASK.md` — Create GitLab issues from a markdown file
|
|
113
|
+
|
|
114
|
+
### Local Development Commands
|
|
115
|
+
|
|
116
|
+
- `itw pipelinelocal` — Run full local pipeline (lint → test → analyze → build)
|
|
117
|
+
- `itw lintlocal` — Run pylint with human-readable output
|
|
118
|
+
- `itw lint` — Run pylint and generate SonarQube report files
|
|
119
|
+
- `itw buildlocal` — Build Docker image locally
|
|
120
|
+
- `itw test` — Run tests with coverage
|
|
121
|
+
- `itw analyze` — Run SonarQube analysis
|
|
122
|
+
- `itw changelog` — Generate changelog manually
|
|
123
|
+
- `itw tag-init` — Initialize version tagging (see below)
|
|
124
|
+
- `itw ssr-init` — Scaffold Angular SSR (one-time, frontend only)
|
|
125
|
+
|
|
126
|
+
### Version Initialization
|
|
127
|
+
|
|
128
|
+
`itw tag-init` is branch-aware and must be run from `staging` or `master`:
|
|
129
|
+
|
|
130
|
+
- On **staging** it creates the first release candidate, `v.0.0.1-rc1`.
|
|
131
|
+
- On **master** it reads the latest `-rc` tag reachable from `staging` (local or `origin/staging`, after fetching tags) and creates that same version as a release. For example `v.0.0.2-rc10` on staging becomes `v.0.0.2-release` on master.
|
|
132
|
+
|
|
133
|
+
The `VERSION` file is written with the tag that was created. The command stops with a clear error when there is no staging branch, no release candidate to promote, or when the tag already exists.
|
|
134
|
+
|
|
135
|
+
### Skip Pipeline
|
|
136
|
+
```bash
|
|
137
|
+
itw incrementpatch --skip-pipeline
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Run a Subset of Tests
|
|
141
|
+
```bash
|
|
142
|
+
# Django: an app or a single test module
|
|
143
|
+
itw test --target=users
|
|
144
|
+
itw test --target=users.test_views
|
|
145
|
+
|
|
146
|
+
# Angular: a directory or a spec name
|
|
147
|
+
itw test --target=core
|
|
148
|
+
itw test --target=core.service
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### SSR Builds
|
|
152
|
+
|
|
153
|
+
Frontend projects scaffolded with `itw ssr-init` build through the SSR npm scripts when `--ssr` is passed:
|
|
154
|
+
```bash
|
|
155
|
+
itw incrementrc --ssr
|
|
156
|
+
itw incrementpatch --ssr
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Virtual Environment Detection
|
|
160
|
+
|
|
161
|
+
`itw` is installed globally but automatically detects the project's virtual environment (`.venv` or `venv`) in the current directory. Tasks that need Python/Django dependencies (test, lint, analyze) activate the venv automatically — no need to manually activate it.
|
|
162
|
+
|
|
163
|
+
If no venv is found, those tasks will error with a clear message. Tasks that only use git (like `changelog`, `tag-init`, `buildlocal`) work without a venv.
|
|
164
|
+
|
|
165
|
+
## Linting
|
|
166
|
+
|
|
167
|
+
The pipeline runs pylint automatically on every deployment and generates report files for SonarQube. The `.pylintrc` configuration is shipped with the package — no config files needed in your project.
|
|
168
|
+
```bash
|
|
169
|
+
# Review issues with human-readable output
|
|
170
|
+
itw lintlocal
|
|
171
|
+
|
|
172
|
+
# Generate report files for SonarQube
|
|
173
|
+
itw lint
|
|
174
|
+
|
|
175
|
+
# Use a custom pylint configuration
|
|
176
|
+
itw lint --pylintrc=.pylintrc
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Add this to your `sonar-project.properties`:
|
|
180
|
+
```properties
|
|
181
|
+
sonar.python.pylint.reportPaths=pylint-report.txt
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Changelog Generation
|
|
185
|
+
|
|
186
|
+
Changelog entries are generated automatically on every deployment based on commit messages. To categorize a commit, add a `Changelog:` trailer to the commit body:
|
|
187
|
+
```
|
|
188
|
+
add user authentication
|
|
189
|
+
|
|
190
|
+
Changelog: added
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Available categories: `added`, `fixed`, `changed`, `deprecated`, `removed`, `security`, `performance`, `tests`, `docs`, `refactor`
|
|
194
|
+
|
|
195
|
+
Commits without a trailer appear under `Other Changes`. The `CHANGELOG.md` file is committed and pushed automatically with each deployment.
|
|
196
|
+
|
|
197
|
+
If `CHANGELOG.md` does not exist in the current directory it is created automatically — including when there are no new commits since the last tag, so the deployment never fails on a missing file.
|
|
198
|
+
|
|
199
|
+
### Changelog Propagation
|
|
200
|
+
|
|
201
|
+
After a successful deployment the changelog is synced forward through a temporary git worktree:
|
|
202
|
+
|
|
203
|
+
- from `master` → `staging` and `develop`
|
|
204
|
+
- from `staging` → `develop`
|
|
205
|
+
|
|
206
|
+
Propagation is skipped when the working tree is not clean or when there is nothing new to sync.
|
|
207
|
+
|
|
208
|
+
## GitLab Issue Creation
|
|
209
|
+
|
|
210
|
+
Create GitLab issues from a markdown file instead of the web UI.
|
|
211
|
+
|
|
212
|
+
Generate the template:
|
|
213
|
+
```bash
|
|
214
|
+
itw task-init
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Then fill it in and run:
|
|
218
|
+
```bash
|
|
219
|
+
itw task --file=TASK.md
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
`task-init` refuses to overwrite an existing `TASK.md`.
|
|
223
|
+
|
|
224
|
+
### Template
|
|
225
|
+
|
|
226
|
+
```markdown
|
|
227
|
+
<!-- OPTIONAL -->
|
|
228
|
+
/glab_host
|
|
229
|
+
/glab_username
|
|
230
|
+
/glab_token
|
|
231
|
+
|
|
232
|
+
<!-- REQUIRED -->
|
|
233
|
+
/title
|
|
234
|
+
|
|
235
|
+
<!-- OPTIONAL -->
|
|
236
|
+
/repo
|
|
237
|
+
/milestone
|
|
238
|
+
/milestone-start YYYY-MM-DD
|
|
239
|
+
/milestone-end YYYY-MM-DD
|
|
240
|
+
/assignee
|
|
241
|
+
/label
|
|
242
|
+
/estimate
|
|
243
|
+
/due YYYY-MM-DD
|
|
244
|
+
|
|
245
|
+
<!-- OPTIONAL -->
|
|
246
|
+
## Acceptance Criteria
|
|
247
|
+
- [ ]
|
|
248
|
+
- [ ]
|
|
249
|
+
## Acceptance Criteria
|
|
250
|
+
|
|
251
|
+
<!-- OPTIONAL -->
|
|
252
|
+
## Comment
|
|
253
|
+
|
|
254
|
+
## Comment
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Every key except `/title` is optional. Leaving a key empty is allowed — empty keys are simply not sent to GitLab. The date keys keep the `YYYY-MM-DD` format in the template and are treated as empty until you replace them.
|
|
258
|
+
|
|
259
|
+
Any text outside the directives becomes the issue description. Create several issues from one file by separating the blocks with a line containing only `===`.
|
|
260
|
+
|
|
261
|
+
### Directives
|
|
262
|
+
|
|
263
|
+
| Directive | Description |
|
|
264
|
+
| --- | --- |
|
|
265
|
+
| `/glab_host` | GitLab host to authenticate against |
|
|
266
|
+
| `/glab_username` | GitLab username |
|
|
267
|
+
| `/glab_token` | GitLab personal access token |
|
|
268
|
+
| `/title` | Issue title (required) |
|
|
269
|
+
| `/repo` | Target project path |
|
|
270
|
+
| `/milestone` | Milestone title |
|
|
271
|
+
| `/milestone-start` | Milestone start date, used only when the milestone is created |
|
|
272
|
+
| `/milestone-end` | Milestone due date, used only when the milestone is created |
|
|
273
|
+
| `/assignee` | Username to assign the issue to |
|
|
274
|
+
| `/label` | Comma-separated labels |
|
|
275
|
+
| `/estimate` | Time estimate (e.g. `3h`) |
|
|
276
|
+
| `/due` | Issue due date |
|
|
277
|
+
|
|
278
|
+
### Authentication
|
|
279
|
+
|
|
280
|
+
Either provide all three of `/glab_host`, `/glab_username` and `/glab_token`, or none of them. Providing only some of them is an error.
|
|
281
|
+
|
|
282
|
+
When no credentials are given, `itw` uses the `.git` directory in the current folder to detect the GitLab host and project, and the token cached by `itw login`.
|
|
283
|
+
|
|
284
|
+
### Target Repository
|
|
285
|
+
|
|
286
|
+
With no `/repo`, the target is resolved by walking the current repository's namespace upward looking for a `_pm` project. If several are found you are prompted to pick one.
|
|
287
|
+
|
|
288
|
+
With `/repo`, leading and trailing slashes are stripped automatically, and full URLs or SSH remotes are accepted:
|
|
289
|
+
|
|
290
|
+
```
|
|
291
|
+
/repo /tools/itw_python_builder/ → tools/itw_python_builder
|
|
292
|
+
/repo https://git.it-works.io/tools/x.git → tools/x
|
|
293
|
+
/repo git@git.it-works.io:tools/x.git → tools/x
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Milestones, Labels and Duplicates
|
|
297
|
+
|
|
298
|
+
Milestones, labels and issue titles are matched with a shared fuzzy comparison at 95% similarity, so small differences in spacing or casing still count as a match. The threshold is a single constant (`SIMILARITY_THRESHOLD` in `task_utils.py`) if you need to tune it.
|
|
299
|
+
|
|
300
|
+
- **Milestone** — a similar existing milestone is reused; otherwise it is created (with the start/end dates when both are given).
|
|
301
|
+
- **Label** — a similar existing label is linked and logged in white; a new one is created and logged in green. An empty `/label` is never sent to GitLab.
|
|
302
|
+
- **Duplicate issues** — before creating, the target project is checked for a similar title *within the same milestone* (or among issues with no milestone). If one exists the issue is not created and a white log line reports it.
|
|
303
|
+
|
|
304
|
+
### Acceptance Criteria and Comments
|
|
305
|
+
|
|
306
|
+
The `## Acceptance Criteria` section must be opened and closed with the same header. When omitted or left with empty checkboxes, a default checklist is applied.
|
|
307
|
+
|
|
308
|
+
The `## Comment` section, opened and closed the same way, is posted as a note on the issue after it is created.
|
|
309
|
+
|
|
310
|
+
## Requirements
|
|
311
|
+
|
|
312
|
+
- Python 3.10+
|
|
313
|
+
- Podman
|
|
314
|
+
- Git
|
|
315
|
+
- SonarQube server
|
|
316
|
+
- Node.js and npm (frontend projects)
|
|
317
|
+
|
|
318
|
+
## Configuration
|
|
319
|
+
|
|
320
|
+
### Environment Variables
|
|
321
|
+
|
|
322
|
+
Add to your project `.env`:
|
|
323
|
+
```
|
|
324
|
+
SONAR_HOST_URL=https://your-sonar-server
|
|
325
|
+
SONAR_TOKEN=your-token
|
|
326
|
+
GIT_DEPTH=0
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### Project Files Required
|
|
330
|
+
|
|
331
|
+
- Git repository with `develop`, `staging`, and `master` branches
|
|
332
|
+
- `VERSION` file in project root (backend) or `package.json` (frontend)
|
|
333
|
+
- `Dockerfile` (backend)
|
|
334
|
+
- `sonar-project.properties`
|
|
335
|
+
|
|
336
|
+
## License
|
|
337
|
+
|
|
338
|
+
MIT
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
# ITW Python Builder
|
|
2
|
+
|
|
3
|
+
Standardized Django and Angular deployment pipeline with Docker, testing, SonarQube integration, automatic changelog generation, GitLab issue creation, and code quality enforcement.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Automated deployment with semantic versioning
|
|
8
|
+
- Docker/Podman-based build and push pipeline (backend)
|
|
9
|
+
- Angular build, packaging and upload to the GitLab Package Registry (frontend)
|
|
10
|
+
- Angular SSR scaffolding and SSR builds
|
|
11
|
+
- Automated testing with coverage
|
|
12
|
+
- SonarQube static code analysis
|
|
13
|
+
- Pylint linting with SonarQube integration
|
|
14
|
+
- Quality gates - deploy only when tests pass
|
|
15
|
+
- Automatic changelog generation from commit trailers
|
|
16
|
+
- Automatic `CHANGELOG.md` creation and propagation to `staging`/`develop`
|
|
17
|
+
- GitLab issue creation from a markdown file
|
|
18
|
+
- Cached GitLab authentication
|
|
19
|
+
- Support for local and production pipelines
|
|
20
|
+
- Global CLI tool
|
|
21
|
+
- Automatic venv detection per project
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
```bash
|
|
25
|
+
pip install itw-python-builder
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Install globally (outside any project venv). The `itw` command becomes available system-wide.
|
|
29
|
+
|
|
30
|
+
Check the installed version:
|
|
31
|
+
```bash
|
|
32
|
+
itw --version
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Quick Start
|
|
36
|
+
|
|
37
|
+
1. Navigate to your project directory (Django projects must have a `.venv` or `venv`):
|
|
38
|
+
|
|
39
|
+
2. Authenticate with GitLab:
|
|
40
|
+
```bash
|
|
41
|
+
itw login
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
3. Initialize versioning — run it on `staging` first, then on `master`:
|
|
45
|
+
```bash
|
|
46
|
+
git checkout staging && itw tag-init # creates v.0.0.1-rc1
|
|
47
|
+
git checkout master && itw tag-init # promotes the latest staging RC to -release
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
4. Run local pipeline:
|
|
51
|
+
```bash
|
|
52
|
+
itw pipelinelocal
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
5. Deploy to staging:
|
|
56
|
+
```bash
|
|
57
|
+
itw incrementrc
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
6. Deploy to production:
|
|
61
|
+
```bash
|
|
62
|
+
itw incrementpatch
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Available Commands
|
|
66
|
+
|
|
67
|
+
### Deployment Commands
|
|
68
|
+
|
|
69
|
+
- `itw incrementpatch` — Increment patch version and deploy
|
|
70
|
+
- `itw incrementminor` — Increment minor version and deploy
|
|
71
|
+
- `itw incrementmajor` — Increment major version and deploy
|
|
72
|
+
- `itw incrementrc` — Increment release candidate (staging)
|
|
73
|
+
- `itw release` — Promote RC to stable release (master)
|
|
74
|
+
|
|
75
|
+
### Authentication Commands
|
|
76
|
+
|
|
77
|
+
- `itw login` — Capture and cache a GitLab token (backend also logs into the container registry)
|
|
78
|
+
- `itw logout` — Forget the cached token and log out of the container registry
|
|
79
|
+
|
|
80
|
+
### GitLab Issue Commands
|
|
81
|
+
|
|
82
|
+
- `itw task-init` — Create a `TASK.md` template in the current directory
|
|
83
|
+
- `itw task --file=TASK.md` — Create GitLab issues from a markdown file
|
|
84
|
+
|
|
85
|
+
### Local Development Commands
|
|
86
|
+
|
|
87
|
+
- `itw pipelinelocal` — Run full local pipeline (lint → test → analyze → build)
|
|
88
|
+
- `itw lintlocal` — Run pylint with human-readable output
|
|
89
|
+
- `itw lint` — Run pylint and generate SonarQube report files
|
|
90
|
+
- `itw buildlocal` — Build Docker image locally
|
|
91
|
+
- `itw test` — Run tests with coverage
|
|
92
|
+
- `itw analyze` — Run SonarQube analysis
|
|
93
|
+
- `itw changelog` — Generate changelog manually
|
|
94
|
+
- `itw tag-init` — Initialize version tagging (see below)
|
|
95
|
+
- `itw ssr-init` — Scaffold Angular SSR (one-time, frontend only)
|
|
96
|
+
|
|
97
|
+
### Version Initialization
|
|
98
|
+
|
|
99
|
+
`itw tag-init` is branch-aware and must be run from `staging` or `master`:
|
|
100
|
+
|
|
101
|
+
- On **staging** it creates the first release candidate, `v.0.0.1-rc1`.
|
|
102
|
+
- On **master** it reads the latest `-rc` tag reachable from `staging` (local or `origin/staging`, after fetching tags) and creates that same version as a release. For example `v.0.0.2-rc10` on staging becomes `v.0.0.2-release` on master.
|
|
103
|
+
|
|
104
|
+
The `VERSION` file is written with the tag that was created. The command stops with a clear error when there is no staging branch, no release candidate to promote, or when the tag already exists.
|
|
105
|
+
|
|
106
|
+
### Skip Pipeline
|
|
107
|
+
```bash
|
|
108
|
+
itw incrementpatch --skip-pipeline
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Run a Subset of Tests
|
|
112
|
+
```bash
|
|
113
|
+
# Django: an app or a single test module
|
|
114
|
+
itw test --target=users
|
|
115
|
+
itw test --target=users.test_views
|
|
116
|
+
|
|
117
|
+
# Angular: a directory or a spec name
|
|
118
|
+
itw test --target=core
|
|
119
|
+
itw test --target=core.service
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### SSR Builds
|
|
123
|
+
|
|
124
|
+
Frontend projects scaffolded with `itw ssr-init` build through the SSR npm scripts when `--ssr` is passed:
|
|
125
|
+
```bash
|
|
126
|
+
itw incrementrc --ssr
|
|
127
|
+
itw incrementpatch --ssr
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Virtual Environment Detection
|
|
131
|
+
|
|
132
|
+
`itw` is installed globally but automatically detects the project's virtual environment (`.venv` or `venv`) in the current directory. Tasks that need Python/Django dependencies (test, lint, analyze) activate the venv automatically — no need to manually activate it.
|
|
133
|
+
|
|
134
|
+
If no venv is found, those tasks will error with a clear message. Tasks that only use git (like `changelog`, `tag-init`, `buildlocal`) work without a venv.
|
|
135
|
+
|
|
136
|
+
## Linting
|
|
137
|
+
|
|
138
|
+
The pipeline runs pylint automatically on every deployment and generates report files for SonarQube. The `.pylintrc` configuration is shipped with the package — no config files needed in your project.
|
|
139
|
+
```bash
|
|
140
|
+
# Review issues with human-readable output
|
|
141
|
+
itw lintlocal
|
|
142
|
+
|
|
143
|
+
# Generate report files for SonarQube
|
|
144
|
+
itw lint
|
|
145
|
+
|
|
146
|
+
# Use a custom pylint configuration
|
|
147
|
+
itw lint --pylintrc=.pylintrc
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Add this to your `sonar-project.properties`:
|
|
151
|
+
```properties
|
|
152
|
+
sonar.python.pylint.reportPaths=pylint-report.txt
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Changelog Generation
|
|
156
|
+
|
|
157
|
+
Changelog entries are generated automatically on every deployment based on commit messages. To categorize a commit, add a `Changelog:` trailer to the commit body:
|
|
158
|
+
```
|
|
159
|
+
add user authentication
|
|
160
|
+
|
|
161
|
+
Changelog: added
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Available categories: `added`, `fixed`, `changed`, `deprecated`, `removed`, `security`, `performance`, `tests`, `docs`, `refactor`
|
|
165
|
+
|
|
166
|
+
Commits without a trailer appear under `Other Changes`. The `CHANGELOG.md` file is committed and pushed automatically with each deployment.
|
|
167
|
+
|
|
168
|
+
If `CHANGELOG.md` does not exist in the current directory it is created automatically — including when there are no new commits since the last tag, so the deployment never fails on a missing file.
|
|
169
|
+
|
|
170
|
+
### Changelog Propagation
|
|
171
|
+
|
|
172
|
+
After a successful deployment the changelog is synced forward through a temporary git worktree:
|
|
173
|
+
|
|
174
|
+
- from `master` → `staging` and `develop`
|
|
175
|
+
- from `staging` → `develop`
|
|
176
|
+
|
|
177
|
+
Propagation is skipped when the working tree is not clean or when there is nothing new to sync.
|
|
178
|
+
|
|
179
|
+
## GitLab Issue Creation
|
|
180
|
+
|
|
181
|
+
Create GitLab issues from a markdown file instead of the web UI.
|
|
182
|
+
|
|
183
|
+
Generate the template:
|
|
184
|
+
```bash
|
|
185
|
+
itw task-init
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Then fill it in and run:
|
|
189
|
+
```bash
|
|
190
|
+
itw task --file=TASK.md
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
`task-init` refuses to overwrite an existing `TASK.md`.
|
|
194
|
+
|
|
195
|
+
### Template
|
|
196
|
+
|
|
197
|
+
```markdown
|
|
198
|
+
<!-- OPTIONAL -->
|
|
199
|
+
/glab_host
|
|
200
|
+
/glab_username
|
|
201
|
+
/glab_token
|
|
202
|
+
|
|
203
|
+
<!-- REQUIRED -->
|
|
204
|
+
/title
|
|
205
|
+
|
|
206
|
+
<!-- OPTIONAL -->
|
|
207
|
+
/repo
|
|
208
|
+
/milestone
|
|
209
|
+
/milestone-start YYYY-MM-DD
|
|
210
|
+
/milestone-end YYYY-MM-DD
|
|
211
|
+
/assignee
|
|
212
|
+
/label
|
|
213
|
+
/estimate
|
|
214
|
+
/due YYYY-MM-DD
|
|
215
|
+
|
|
216
|
+
<!-- OPTIONAL -->
|
|
217
|
+
## Acceptance Criteria
|
|
218
|
+
- [ ]
|
|
219
|
+
- [ ]
|
|
220
|
+
## Acceptance Criteria
|
|
221
|
+
|
|
222
|
+
<!-- OPTIONAL -->
|
|
223
|
+
## Comment
|
|
224
|
+
|
|
225
|
+
## Comment
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Every key except `/title` is optional. Leaving a key empty is allowed — empty keys are simply not sent to GitLab. The date keys keep the `YYYY-MM-DD` format in the template and are treated as empty until you replace them.
|
|
229
|
+
|
|
230
|
+
Any text outside the directives becomes the issue description. Create several issues from one file by separating the blocks with a line containing only `===`.
|
|
231
|
+
|
|
232
|
+
### Directives
|
|
233
|
+
|
|
234
|
+
| Directive | Description |
|
|
235
|
+
| --- | --- |
|
|
236
|
+
| `/glab_host` | GitLab host to authenticate against |
|
|
237
|
+
| `/glab_username` | GitLab username |
|
|
238
|
+
| `/glab_token` | GitLab personal access token |
|
|
239
|
+
| `/title` | Issue title (required) |
|
|
240
|
+
| `/repo` | Target project path |
|
|
241
|
+
| `/milestone` | Milestone title |
|
|
242
|
+
| `/milestone-start` | Milestone start date, used only when the milestone is created |
|
|
243
|
+
| `/milestone-end` | Milestone due date, used only when the milestone is created |
|
|
244
|
+
| `/assignee` | Username to assign the issue to |
|
|
245
|
+
| `/label` | Comma-separated labels |
|
|
246
|
+
| `/estimate` | Time estimate (e.g. `3h`) |
|
|
247
|
+
| `/due` | Issue due date |
|
|
248
|
+
|
|
249
|
+
### Authentication
|
|
250
|
+
|
|
251
|
+
Either provide all three of `/glab_host`, `/glab_username` and `/glab_token`, or none of them. Providing only some of them is an error.
|
|
252
|
+
|
|
253
|
+
When no credentials are given, `itw` uses the `.git` directory in the current folder to detect the GitLab host and project, and the token cached by `itw login`.
|
|
254
|
+
|
|
255
|
+
### Target Repository
|
|
256
|
+
|
|
257
|
+
With no `/repo`, the target is resolved by walking the current repository's namespace upward looking for a `_pm` project. If several are found you are prompted to pick one.
|
|
258
|
+
|
|
259
|
+
With `/repo`, leading and trailing slashes are stripped automatically, and full URLs or SSH remotes are accepted:
|
|
260
|
+
|
|
261
|
+
```
|
|
262
|
+
/repo /tools/itw_python_builder/ → tools/itw_python_builder
|
|
263
|
+
/repo https://git.it-works.io/tools/x.git → tools/x
|
|
264
|
+
/repo git@git.it-works.io:tools/x.git → tools/x
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Milestones, Labels and Duplicates
|
|
268
|
+
|
|
269
|
+
Milestones, labels and issue titles are matched with a shared fuzzy comparison at 95% similarity, so small differences in spacing or casing still count as a match. The threshold is a single constant (`SIMILARITY_THRESHOLD` in `task_utils.py`) if you need to tune it.
|
|
270
|
+
|
|
271
|
+
- **Milestone** — a similar existing milestone is reused; otherwise it is created (with the start/end dates when both are given).
|
|
272
|
+
- **Label** — a similar existing label is linked and logged in white; a new one is created and logged in green. An empty `/label` is never sent to GitLab.
|
|
273
|
+
- **Duplicate issues** — before creating, the target project is checked for a similar title *within the same milestone* (or among issues with no milestone). If one exists the issue is not created and a white log line reports it.
|
|
274
|
+
|
|
275
|
+
### Acceptance Criteria and Comments
|
|
276
|
+
|
|
277
|
+
The `## Acceptance Criteria` section must be opened and closed with the same header. When omitted or left with empty checkboxes, a default checklist is applied.
|
|
278
|
+
|
|
279
|
+
The `## Comment` section, opened and closed the same way, is posted as a note on the issue after it is created.
|
|
280
|
+
|
|
281
|
+
## Requirements
|
|
282
|
+
|
|
283
|
+
- Python 3.10+
|
|
284
|
+
- Podman
|
|
285
|
+
- Git
|
|
286
|
+
- SonarQube server
|
|
287
|
+
- Node.js and npm (frontend projects)
|
|
288
|
+
|
|
289
|
+
## Configuration
|
|
290
|
+
|
|
291
|
+
### Environment Variables
|
|
292
|
+
|
|
293
|
+
Add to your project `.env`:
|
|
294
|
+
```
|
|
295
|
+
SONAR_HOST_URL=https://your-sonar-server
|
|
296
|
+
SONAR_TOKEN=your-token
|
|
297
|
+
GIT_DEPTH=0
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Project Files Required
|
|
301
|
+
|
|
302
|
+
- Git repository with `develop`, `staging`, and `master` branches
|
|
303
|
+
- `VERSION` file in project root (backend) or `package.json` (frontend)
|
|
304
|
+
- `Dockerfile` (backend)
|
|
305
|
+
- `sonar-project.properties`
|
|
306
|
+
|
|
307
|
+
## License
|
|
308
|
+
|
|
309
|
+
MIT
|
|
@@ -29,6 +29,8 @@ from itw_python_builder.utils import (
|
|
|
29
29
|
TOKEN_CACHE_PATH,
|
|
30
30
|
maybe_override_release_version,
|
|
31
31
|
ensure_gitlab_token,
|
|
32
|
+
tag_exists,
|
|
33
|
+
latest_staging_rc,
|
|
32
34
|
)
|
|
33
35
|
from itw_python_builder.task_utils import (
|
|
34
36
|
resolve_pm_repo,
|
|
@@ -453,9 +455,11 @@ def push(ctx: Context):
|
|
|
453
455
|
|
|
454
456
|
|
|
455
457
|
def buildimage(ctx: Context):
|
|
458
|
+
token = load_cached_token()
|
|
459
|
+
username = get_gitlab_username(ctx)
|
|
456
460
|
current_branch = get_current_branch(ctx)
|
|
457
461
|
container_registry_path = generate_image_path(ctx, current_branch)
|
|
458
|
-
ctx.run(f'podman build
|
|
462
|
+
ctx.run(f'podman build --build-arg GITLAB_USERNAME={username} --build-arg GITLAB_TOKEN={token} --tag={container_registry_path} .')
|
|
459
463
|
|
|
460
464
|
|
|
461
465
|
def pushimage(ctx: Context):
|
|
@@ -499,16 +503,24 @@ def tag_build_push(ctx: Context, version: Version, skip_pipeline: bool = False,
|
|
|
499
503
|
|
|
500
504
|
@task(name='tag-init')
|
|
501
505
|
def taginit(ctx: Context) -> None:
|
|
502
|
-
"""Initialize version tagging"""
|
|
503
|
-
check_branch(ctx)
|
|
504
|
-
|
|
506
|
+
"""Initialize version tagging — release candidate on staging, release on master."""
|
|
507
|
+
production = check_branch(ctx)
|
|
508
|
+
if production:
|
|
509
|
+
version = latest_staging_rc(ctx)
|
|
510
|
+
log_info(f'Latest release candidate on staging: {version}')
|
|
511
|
+
version.reset_release_candidate(release=True)
|
|
512
|
+
else:
|
|
513
|
+
version = Version(0, 0, 1, 1)
|
|
514
|
+
if tag_exists(ctx, version):
|
|
515
|
+
raise RuntimeError(f'Tag {version} already exists — nothing to initialize.')
|
|
505
516
|
tag(ctx, version)
|
|
506
517
|
save_version(version)
|
|
518
|
+
log_green(f'Initialized {version} on {get_current_branch(ctx)}')
|
|
507
519
|
|
|
508
520
|
|
|
509
521
|
def _ensure_unique_tag(ctx: Context, version: Version) -> None:
|
|
510
522
|
"""If the tag already exists, auto-increment RC (RC tags) or patch (release tags)."""
|
|
511
|
-
while ctx
|
|
523
|
+
while tag_exists(ctx, version):
|
|
512
524
|
if version.release_candidate == 0:
|
|
513
525
|
print(f"[itw] Tag {version} already exists, auto-incrementing patch...")
|
|
514
526
|
version.increment_patch(release=True)
|