itw-python-builder 0.1.38__tar.gz → 0.1.39__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 (20) hide show
  1. {itw_python_builder-0.1.38 → itw_python_builder-0.1.39}/PKG-INFO +1 -1
  2. {itw_python_builder-0.1.38 → itw_python_builder-0.1.39}/itw_python_builder/tasks.py +18 -13
  3. {itw_python_builder-0.1.38 → itw_python_builder-0.1.39}/itw_python_builder/utils.py +39 -0
  4. {itw_python_builder-0.1.38 → itw_python_builder-0.1.39}/itw_python_builder.egg-info/PKG-INFO +1 -1
  5. {itw_python_builder-0.1.38 → itw_python_builder-0.1.39}/pyproject.toml +1 -1
  6. {itw_python_builder-0.1.38 → itw_python_builder-0.1.39}/LICENSE +0 -0
  7. {itw_python_builder-0.1.38 → itw_python_builder-0.1.39}/README.md +0 -0
  8. {itw_python_builder-0.1.38 → itw_python_builder-0.1.39}/itw_python_builder/.pylintrc +0 -0
  9. {itw_python_builder-0.1.38 → itw_python_builder-0.1.39}/itw_python_builder/__init__.py +0 -0
  10. {itw_python_builder-0.1.38 → itw_python_builder-0.1.39}/itw_python_builder/cli.py +0 -0
  11. {itw_python_builder-0.1.38 → itw_python_builder-0.1.39}/itw_python_builder/ssr_tasks.py +0 -0
  12. {itw_python_builder-0.1.38 → itw_python_builder-0.1.39}/itw_python_builder/templates/server.sitemap.snippet.ts +0 -0
  13. {itw_python_builder-0.1.38 → itw_python_builder-0.1.39}/itw_python_builder/templates/sitemap.routes.ts +0 -0
  14. {itw_python_builder-0.1.38 → itw_python_builder-0.1.39}/itw_python_builder/version.py +0 -0
  15. {itw_python_builder-0.1.38 → itw_python_builder-0.1.39}/itw_python_builder.egg-info/SOURCES.txt +0 -0
  16. {itw_python_builder-0.1.38 → itw_python_builder-0.1.39}/itw_python_builder.egg-info/dependency_links.txt +0 -0
  17. {itw_python_builder-0.1.38 → itw_python_builder-0.1.39}/itw_python_builder.egg-info/entry_points.txt +0 -0
  18. {itw_python_builder-0.1.38 → itw_python_builder-0.1.39}/itw_python_builder.egg-info/requires.txt +0 -0
  19. {itw_python_builder-0.1.38 → itw_python_builder-0.1.39}/itw_python_builder.egg-info/top_level.txt +0 -0
  20. {itw_python_builder-0.1.38 → itw_python_builder-0.1.39}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: itw_python_builder
3
- Version: 0.1.38
3
+ Version: 0.1.39
4
4
  Summary: Standardized Django deployment pipeline with Docker, testing, and SonarQube integration
5
5
  Author-email: IT-Works <contact@it-works.io>
6
6
  License: MIT
@@ -12,6 +12,9 @@ from itw_python_builder.utils import (
12
12
  get_gitlab_username,
13
13
  _parse_gitlab_remote,
14
14
  is_ssr_project,
15
+ install_sigint_guard,
16
+ abort_if_interrupted,
17
+ step,
15
18
  )
16
19
  from itw_python_builder.ssr_tasks import * # noqa: F401,F403 — exposes ssr-init
17
20
 
@@ -124,21 +127,22 @@ def pushimage(ctx: Context):
124
127
 
125
128
 
126
129
  def tag_build_push(ctx: Context, version: Version, skip_pipeline: bool = False, ssr: bool = False) -> None:
130
+ install_sigint_guard()
127
131
  project_type = detect_project_type()
128
132
  if not skip_pipeline:
129
- test(ctx)
130
- analyze(ctx)
131
- tag(ctx, version)
133
+ step('tests', test, ctx)
134
+ step('analyze', analyze, ctx)
135
+ step('tag', tag, ctx, version)
132
136
  if project_type == 'backend':
133
- buildimage(ctx)
134
- pushimage(ctx)
137
+ step('build image', buildimage, ctx)
138
+ step('push image', pushimage, ctx)
135
139
  else:
136
140
  branch = get_current_branch(ctx)
137
- build_frontend(ctx, branch, ssr=ssr)
138
- package_dist(ctx)
139
- upload_dist(ctx, version)
140
- changelog(ctx, version)
141
- push(ctx)
141
+ step('build', build_frontend, ctx, branch, ssr=ssr)
142
+ step('package', package_dist, ctx)
143
+ step('upload', upload_dist, ctx, version)
144
+ step('changelog', changelog, ctx, version)
145
+ step('push', push, ctx)
142
146
 
143
147
 
144
148
  @task(name='tag-init')
@@ -355,23 +359,24 @@ def analyzelocal(ctx: Context):
355
359
  @task
356
360
  def pipelinelocal(ctx: Context, settings='backend.test_settings', pylintrc=None):
357
361
  """Local pipeline: (lint →) test → analyze"""
362
+ install_sigint_guard()
358
363
  project_type = detect_project_type()
359
364
  if project_type == 'backend':
360
365
  detect_and_activate_venv()
361
366
  print("=" * 60)
362
367
  print("Step 1: Running lint...")
363
368
  print("=" * 60)
364
- lint(ctx, pylintrc=pylintrc)
369
+ step('lint', lint, ctx, pylintrc=pylintrc)
365
370
 
366
371
  print("\n" + "=" * 60)
367
372
  print(f"Step {'2' if project_type == 'backend' else '1'}: Running tests...")
368
373
  print("=" * 60)
369
- testlocal(ctx, settings)
374
+ step('tests', testlocal, ctx, settings)
370
375
 
371
376
  print("\n" + "=" * 60)
372
377
  print(f"Step {'3' if project_type == 'backend' else '2'}: Running SonarQube analysis...")
373
378
  print("=" * 60)
374
- analyzelocal(ctx)
379
+ step('analyze', analyzelocal, ctx)
375
380
 
376
381
  print("\n" + "=" * 60)
377
382
  print("✓ Local pipeline completed successfully!")
@@ -7,6 +7,8 @@ import io
7
7
  import json
8
8
  import os
9
9
  import re
10
+ import signal
11
+ import sys
10
12
  from pathlib import Path
11
13
 
12
14
  from invoke import Context
@@ -15,6 +17,43 @@ from itw_python_builder.version import Version
15
17
 
16
18
  _venv_activated = False
17
19
 
20
+ _INTERRUPTED = False
21
+ _SIGINT_INSTALLED = False
22
+
23
+
24
+ def _sigint_handler(signum, frame):
25
+ global _INTERRUPTED
26
+ _INTERRUPTED = True
27
+ raise KeyboardInterrupt
28
+
29
+
30
+ def install_sigint_guard() -> None:
31
+ """Install a process-wide SIGINT trap."""
32
+ global _SIGINT_INSTALLED
33
+ if _SIGINT_INSTALLED:
34
+ return
35
+ signal.signal(signal.SIGINT, _sigint_handler)
36
+ _SIGINT_INSTALLED = True
37
+
38
+
39
+ def abort_if_interrupted(step: str = '') -> None:
40
+ """Exit 130 if a SIGINT was received since the last call."""
41
+ if _INTERRUPTED:
42
+ where = f' during {step}' if step else ''
43
+ print(f'\n[itw] Aborted by user (Ctrl+C){where}.')
44
+ sys.exit(130)
45
+
46
+
47
+ def step(label: str, fn, *args, **kwargs):
48
+ """Run `fn(*args, **kwargs)`, swallow KeyboardInterrupt, then bail if SIGINT was seen."""
49
+ result = None
50
+ try:
51
+ result = fn(*args, **kwargs)
52
+ except KeyboardInterrupt:
53
+ pass
54
+ abort_if_interrupted(label)
55
+ return result
56
+
18
57
 
19
58
  def detect_project_type() -> str:
20
59
  """Detect whether the current directory is a 'frontend' or 'backend' project."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: itw_python_builder
3
- Version: 0.1.38
3
+ Version: 0.1.39
4
4
  Summary: Standardized Django deployment pipeline with Docker, testing, and SonarQube integration
5
5
  Author-email: IT-Works <contact@it-works.io>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "itw_python_builder"
7
- version = "0.1.38"
7
+ version = "0.1.39"
8
8
  description = "Standardized Django deployment pipeline with Docker, testing, and SonarQube integration"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"