itw-python-builder 0.1.31__tar.gz → 0.1.32__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.31 → itw_python_builder-0.1.32}/PKG-INFO +1 -1
  2. {itw_python_builder-0.1.31 → itw_python_builder-0.1.32}/itw_python_builder/ssr_tasks.py +136 -25
  3. {itw_python_builder-0.1.31 → itw_python_builder-0.1.32}/itw_python_builder.egg-info/PKG-INFO +1 -1
  4. {itw_python_builder-0.1.31 → itw_python_builder-0.1.32}/pyproject.toml +1 -1
  5. {itw_python_builder-0.1.31 → itw_python_builder-0.1.32}/LICENSE +0 -0
  6. {itw_python_builder-0.1.31 → itw_python_builder-0.1.32}/README.md +0 -0
  7. {itw_python_builder-0.1.31 → itw_python_builder-0.1.32}/itw_python_builder/.pylintrc +0 -0
  8. {itw_python_builder-0.1.31 → itw_python_builder-0.1.32}/itw_python_builder/__init__.py +0 -0
  9. {itw_python_builder-0.1.31 → itw_python_builder-0.1.32}/itw_python_builder/cli.py +0 -0
  10. {itw_python_builder-0.1.31 → itw_python_builder-0.1.32}/itw_python_builder/tasks.py +0 -0
  11. {itw_python_builder-0.1.31 → itw_python_builder-0.1.32}/itw_python_builder/templates/server.sitemap.snippet.ts +0 -0
  12. {itw_python_builder-0.1.31 → itw_python_builder-0.1.32}/itw_python_builder/templates/sitemap.routes.ts +0 -0
  13. {itw_python_builder-0.1.31 → itw_python_builder-0.1.32}/itw_python_builder/utils.py +0 -0
  14. {itw_python_builder-0.1.31 → itw_python_builder-0.1.32}/itw_python_builder/version.py +0 -0
  15. {itw_python_builder-0.1.31 → itw_python_builder-0.1.32}/itw_python_builder.egg-info/SOURCES.txt +0 -0
  16. {itw_python_builder-0.1.31 → itw_python_builder-0.1.32}/itw_python_builder.egg-info/dependency_links.txt +0 -0
  17. {itw_python_builder-0.1.31 → itw_python_builder-0.1.32}/itw_python_builder.egg-info/entry_points.txt +0 -0
  18. {itw_python_builder-0.1.31 → itw_python_builder-0.1.32}/itw_python_builder.egg-info/requires.txt +0 -0
  19. {itw_python_builder-0.1.31 → itw_python_builder-0.1.32}/itw_python_builder.egg-info/top_level.txt +0 -0
  20. {itw_python_builder-0.1.31 → itw_python_builder-0.1.32}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: itw_python_builder
3
- Version: 0.1.31
3
+ Version: 0.1.32
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
@@ -43,6 +43,132 @@ def _angular_core_installed_version() -> str:
43
43
  return json.load(fp).get('version', '')
44
44
 
45
45
 
46
+ def _read_angular_json() -> dict:
47
+ """Read angular.json from cwd. Returns empty dict if missing/invalid."""
48
+ path = os.path.join(os.getcwd(), 'angular.json')
49
+ if not os.path.isfile(path):
50
+ return {}
51
+ try:
52
+ with open(path, 'r', encoding='utf-8') as fp:
53
+ return json.load(fp)
54
+ except (OSError, json.JSONDecodeError):
55
+ return {}
56
+
57
+
58
+ def _detect_angular_project(angular_json: dict) -> tuple:
59
+ """Return (project_name, project_data) for the project SSR was scaffolded into.
60
+
61
+ Priority: package.json `name` match → defaultProject → only project in repo.
62
+ Returns (None, None) if angular.json has no usable projects.
63
+ """
64
+ projects = angular_json.get('projects') or {}
65
+ if not projects:
66
+ return (None, None)
67
+ try:
68
+ pkg_name = _read_package_name()
69
+ if pkg_name in projects:
70
+ return (pkg_name, projects[pkg_name])
71
+ except Exception:
72
+ pass
73
+ default = angular_json.get('defaultProject')
74
+ if default and default in projects:
75
+ return (default, projects[default])
76
+ if len(projects) == 1:
77
+ name = next(iter(projects))
78
+ return (name, projects[name])
79
+ return (None, None)
80
+
81
+
82
+ def _maybe_add_ssr_scripts(ctx: Context) -> None:
83
+ """Add build:ssr, build:ssr:staging, build:ssr:dev npm scripts based on angular.json.
84
+
85
+ Reads angular.json to detect:
86
+ - The builder (legacy `:browser` + separate `server` target, or modern `:application`)
87
+ - The project name (for `ng run <name>:server:<config>` in the legacy form)
88
+ - Which configurations exist (only writes scripts for configs that exist in both
89
+ `build` and, for legacy, `server` targets)
90
+
91
+ Never overwrites a script that already exists in package.json. Prints a summary
92
+ of what was added vs preserved vs skipped (no matching config).
93
+ """
94
+ angular_json = _read_angular_json()
95
+ if not angular_json:
96
+ print('[itw] No angular.json found — skipping SSR script setup.')
97
+ return
98
+
99
+ project_name, project = _detect_angular_project(angular_json)
100
+ if not project:
101
+ print('[itw] Could not detect Angular project in angular.json — skipping SSR script setup.')
102
+ return
103
+
104
+ arch = project.get('architect') or project.get('targets') or {}
105
+ build = arch.get('build') or {}
106
+ server = arch.get('server') or {}
107
+ builder = build.get('builder', '')
108
+
109
+ is_legacy = builder == '@angular-devkit/build-angular:browser' and bool(server)
110
+ is_modern = builder == '@angular-devkit/build-angular:application'
111
+ if not (is_legacy or is_modern):
112
+ print(f'[itw] Unrecognized build builder {builder!r} — skipping SSR script setup.')
113
+ return
114
+
115
+ build_configs = set((build.get('configurations') or {}).keys())
116
+ if is_legacy:
117
+ server_configs = set((server.get('configurations') or {}).keys())
118
+ usable_configs = build_configs & server_configs
119
+ builder_label = 'legacy (browser + server targets)'
120
+ else:
121
+ usable_configs = build_configs
122
+ builder_label = 'modern (application builder)'
123
+
124
+ print(f"[itw] Detected {builder_label} for project '{project_name}'.")
125
+
126
+ def cmd_for(config: str) -> str:
127
+ if is_legacy:
128
+ return f'ng build --configuration={config} && ng run {project_name}:server:{config}'
129
+ return f'ng build --configuration={config}'
130
+
131
+ script_map = {
132
+ 'production': 'build:ssr',
133
+ 'staging': 'build:ssr:staging',
134
+ 'development': 'build:ssr:dev',
135
+ }
136
+
137
+ pkg_path = os.path.join(os.getcwd(), 'package.json')
138
+ with open(pkg_path, 'r', encoding='utf-8') as fp:
139
+ data = json.load(fp)
140
+ scripts = data.setdefault('scripts', {})
141
+
142
+ added, preserved, skipped = [], [], []
143
+ for config_name, script_name in script_map.items():
144
+ if config_name not in usable_configs:
145
+ skipped.append((script_name, config_name))
146
+ continue
147
+ if script_name in scripts:
148
+ preserved.append(script_name)
149
+ continue
150
+ scripts[script_name] = cmd_for(config_name)
151
+ added.append((script_name, scripts[script_name]))
152
+
153
+ if added:
154
+ with open(pkg_path, 'w', encoding='utf-8') as fp:
155
+ json.dump(data, fp, indent=2)
156
+ fp.write('\n')
157
+
158
+ print('[itw] SSR npm scripts:')
159
+ if added:
160
+ for name, cmd in added:
161
+ print(f' + added: {name} → {cmd}')
162
+ if preserved:
163
+ for name in preserved:
164
+ print(f' = preserved: {name} (already in package.json, not overwritten)')
165
+ if skipped:
166
+ for name, cfg in skipped:
167
+ print(f" - skipped: {name} (no '{cfg}' config in angular.json)")
168
+ if not (added or preserved):
169
+ print(' (nothing added)')
170
+
171
+
46
172
  def _pin_ssr_deps_in_package_json(target_version: str) -> list:
47
173
  """Pin @angular/ssr and @angular/platform-server in package.json to exact target_version.
48
174
 
@@ -182,29 +308,12 @@ def _print_next_steps(project_name: str) -> None:
182
308
  print()
183
309
  print(' 1. Add `NgxSeoModule` to your AppModule imports.')
184
310
  print(' 2. Fill in src/sitemap.routes.ts with your route tree.')
185
- print(' 3. Add `staging` (and optionally `development`) configurations to')
186
- print(' angular.json under projects.' + project_name + '.architect.build.configurations.')
187
- print(' ng add @angular/ssr only creates the `production` configuration.')
188
- print()
189
- print(' 4. Add these two npm scripts to package.json — the deploy pipeline')
190
- print(' calls them by name:')
191
- print()
192
- print(' "build:ssr": "<build command for production>"')
193
- print(' "build:ssr:staging": "<build command for staging>"')
194
- print()
195
- print(' The exact command depends on which builder angular.json uses:')
196
- print()
197
- print(' • Modern application builder (default for fresh ng add @angular/ssr):')
198
- print(' "build:ssr": "ng build --configuration=production"')
199
- print(' "build:ssr:staging": "ng build --configuration=staging"')
200
- print()
201
- print(' • Legacy browser builder (older projects with a separate server target):')
202
- print(f' "build:ssr": "ng build --configuration=production && ng run {project_name}:server:production"')
203
- print(f' "build:ssr:staging": "ng build --configuration=staging && ng run {project_name}:server:staging"')
204
- print()
205
- print(' 5. Verify locally: npm run build:ssr && npm run serve:ssr')
206
- print(' 6. Commit the new files.')
207
- print(' 7. Deploy with: itw incrementrc --ssr (or incrementpatch/release --ssr)')
311
+ print(' 3. If `build:ssr:staging` was skipped above, add a `staging` configuration')
312
+ print(f' to angular.json (and the `server` target, if legacy builder), then re-run')
313
+ print(' `itw ssr-init --force` to add the missing scripts.')
314
+ print(' 4. Verify locally: npm run build:ssr && npm run serve:ssr')
315
+ print(' 5. Commit the new files.')
316
+ print(' 6. Deploy with: itw incrementrc --ssr (or incrementpatch/release --ssr)')
208
317
  print('=' * 70)
209
318
 
210
319
 
@@ -212,8 +321,9 @@ def _print_next_steps(project_name: str) -> None:
212
321
  def ssr_init(ctx: Context, force: bool = False) -> None:
213
322
  """One-time SSR scaffold: ng add @angular/ssr, ngx-seo-helper, sitemap stub, server.ts patch.
214
323
 
215
- Does NOT write package.json scripts those depend on which builder Angular
216
- chose. The post-run message tells you the two scripts the pipeline expects.
324
+ Auto-adds the build:ssr / build:ssr:staging / build:ssr:dev npm scripts based
325
+ on angular.json (detects builder type and available configs). Existing scripts
326
+ are never overwritten.
217
327
  """
218
328
  if detect_project_type() != 'frontend':
219
329
  raise RuntimeError('ssr-init only runs on frontend (Angular) projects.')
@@ -230,6 +340,7 @@ def ssr_init(ctx: Context, force: bool = False) -> None:
230
340
  if not is_ssr_project():
231
341
  _run_ng_add_ssr(ctx)
232
342
 
343
+ _maybe_add_ssr_scripts(ctx)
233
344
  _install_ngx_seo_helper(ctx)
234
345
  _write_sitemap_template()
235
346
  _patch_server_ts()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: itw_python_builder
3
- Version: 0.1.31
3
+ Version: 0.1.32
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.31"
7
+ version = "0.1.32"
8
8
  description = "Standardized Django deployment pipeline with Docker, testing, and SonarQube integration"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"