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.
Files changed (28) hide show
  1. itw_python_builder-0.2.14/PKG-INFO +338 -0
  2. itw_python_builder-0.2.14/README.md +309 -0
  3. {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder/tasks.py +17 -5
  4. {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder/utils.py +45 -0
  5. itw_python_builder-0.2.14/itw_python_builder.egg-info/PKG-INFO +338 -0
  6. {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/pyproject.toml +1 -1
  7. itw_python_builder-0.2.13/PKG-INFO +0 -166
  8. itw_python_builder-0.2.13/README.md +0 -137
  9. itw_python_builder-0.2.13/itw_python_builder.egg-info/PKG-INFO +0 -166
  10. {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/LICENSE +0 -0
  11. {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder/.pylintrc +0 -0
  12. {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder/__init__.py +0 -0
  13. {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder/_pyruntime/sitecustomize.py +0 -0
  14. {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder/cli.py +0 -0
  15. {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder/notify.py +0 -0
  16. {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder/ssr_tasks.py +0 -0
  17. {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder/task_utils.py +0 -0
  18. {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder/templates/new_version_email.html +0 -0
  19. {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder/templates/server.sitemap.snippet.ts +0 -0
  20. {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder/templates/sitemap.routes.ts +0 -0
  21. {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder/templates/task_template.md +0 -0
  22. {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder/version.py +0 -0
  23. {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder.egg-info/SOURCES.txt +0 -0
  24. {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder.egg-info/dependency_links.txt +0 -0
  25. {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder.egg-info/entry_points.txt +0 -0
  26. {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder.egg-info/requires.txt +0 -0
  27. {itw_python_builder-0.2.13 → itw_python_builder-0.2.14}/itw_python_builder.egg-info/top_level.txt +0 -0
  28. {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 . --tag={container_registry_path}')
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
- version = Version(0, 0, 1, 1)
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.run(f'git rev-parse -q --verify "refs/tags/{version}"', warn=True, hide=True).ok:
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)