newstack 0.1.0__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.
- newstack-0.1.0/.gitignore +19 -0
- newstack-0.1.0/CHANGELOG.md +22 -0
- newstack-0.1.0/LICENSE +21 -0
- newstack-0.1.0/PKG-INFO +197 -0
- newstack-0.1.0/README.md +173 -0
- newstack-0.1.0/pyproject.toml +55 -0
- newstack-0.1.0/src/newstack/__init__.py +4 -0
- newstack-0.1.0/src/newstack/__main__.py +8 -0
- newstack-0.1.0/src/newstack/cli.py +387 -0
- newstack-0.1.0/src/newstack/data/stacks/fastapi/stack.json +42 -0
- newstack-0.1.0/src/newstack/data/stacks/fastapi/template/.github/workflows/ci.yml +30 -0
- newstack-0.1.0/src/newstack/data/stacks/fastapi/template/.gitignore +11 -0
- newstack-0.1.0/src/newstack/data/stacks/fastapi/template/Dockerfile +13 -0
- newstack-0.1.0/src/newstack/data/stacks/fastapi/template/LICENSE +21 -0
- newstack-0.1.0/src/newstack/data/stacks/fastapi/template/README.md +30 -0
- newstack-0.1.0/src/newstack/data/stacks/fastapi/template/pyproject.toml +31 -0
- newstack-0.1.0/src/newstack/data/stacks/fastapi/template/src/{{package_name}}/__init__.py +4 -0
- newstack-0.1.0/src/newstack/data/stacks/fastapi/template/src/{{package_name}}/main.py +50 -0
- newstack-0.1.0/src/newstack/data/stacks/fastapi/template/tests/test_api.py +41 -0
- newstack-0.1.0/src/newstack/data/stacks/node-express-ts/stack.json +14 -0
- newstack-0.1.0/src/newstack/data/stacks/node-express-ts/template/.github/workflows/ci.yml +28 -0
- newstack-0.1.0/src/newstack/data/stacks/node-express-ts/template/.gitignore +6 -0
- newstack-0.1.0/src/newstack/data/stacks/node-express-ts/template/LICENSE +21 -0
- newstack-0.1.0/src/newstack/data/stacks/node-express-ts/template/README.md +24 -0
- newstack-0.1.0/src/newstack/data/stacks/node-express-ts/template/package.json +26 -0
- newstack-0.1.0/src/newstack/data/stacks/node-express-ts/template/src/app.ts +35 -0
- newstack-0.1.0/src/newstack/data/stacks/node-express-ts/template/src/server.ts +7 -0
- newstack-0.1.0/src/newstack/data/stacks/node-express-ts/template/tests/app.test.ts +32 -0
- newstack-0.1.0/src/newstack/data/stacks/node-express-ts/template/tsconfig.json +14 -0
- newstack-0.1.0/src/newstack/data/stacks/python-cli/stack.json +50 -0
- newstack-0.1.0/src/newstack/data/stacks/python-cli/template/.github/workflows/ci.yml +32 -0
- newstack-0.1.0/src/newstack/data/stacks/python-cli/template/.gitignore +11 -0
- newstack-0.1.0/src/newstack/data/stacks/python-cli/template/LICENSE +21 -0
- newstack-0.1.0/src/newstack/data/stacks/python-cli/template/README.md +35 -0
- newstack-0.1.0/src/newstack/data/stacks/python-cli/template/pyproject.toml +32 -0
- newstack-0.1.0/src/newstack/data/stacks/python-cli/template/src/{{package_name}}/__init__.py +4 -0
- newstack-0.1.0/src/newstack/data/stacks/python-cli/template/src/{{package_name}}/__main__.py +6 -0
- newstack-0.1.0/src/newstack/data/stacks/python-cli/template/src/{{package_name}}/cli.py +30 -0
- newstack-0.1.0/src/newstack/data/stacks/python-cli/template/tests/test_cli.py +20 -0
- newstack-0.1.0/src/newstack/data/stacks/python-lib/stack.json +42 -0
- newstack-0.1.0/src/newstack/data/stacks/python-lib/template/.github/workflows/ci.yml +32 -0
- newstack-0.1.0/src/newstack/data/stacks/python-lib/template/.gitignore +11 -0
- newstack-0.1.0/src/newstack/data/stacks/python-lib/template/LICENSE +21 -0
- newstack-0.1.0/src/newstack/data/stacks/python-lib/template/README.md +28 -0
- newstack-0.1.0/src/newstack/data/stacks/python-lib/template/pyproject.toml +34 -0
- newstack-0.1.0/src/newstack/data/stacks/python-lib/template/src/{{package_name}}/__init__.py +6 -0
- newstack-0.1.0/src/newstack/data/stacks/python-lib/template/src/{{package_name}}/core.py +23 -0
- newstack-0.1.0/src/newstack/data/stacks/python-lib/template/tests/test_core.py +31 -0
- newstack-0.1.0/src/newstack/data/stacks/react-vite-ts/stack.json +15 -0
- newstack-0.1.0/src/newstack/data/stacks/react-vite-ts/template/.github/workflows/ci.yml +29 -0
- newstack-0.1.0/src/newstack/data/stacks/react-vite-ts/template/.gitignore +7 -0
- newstack-0.1.0/src/newstack/data/stacks/react-vite-ts/template/LICENSE +21 -0
- newstack-0.1.0/src/newstack/data/stacks/react-vite-ts/template/README.md +25 -0
- newstack-0.1.0/src/newstack/data/stacks/react-vite-ts/template/index.html +12 -0
- newstack-0.1.0/src/newstack/data/stacks/react-vite-ts/template/package.json +28 -0
- newstack-0.1.0/src/newstack/data/stacks/react-vite-ts/template/src/App.test.tsx +20 -0
- newstack-0.1.0/src/newstack/data/stacks/react-vite-ts/template/src/App.tsx +15 -0
- newstack-0.1.0/src/newstack/data/stacks/react-vite-ts/template/src/main.tsx +16 -0
- newstack-0.1.0/src/newstack/data/stacks/react-vite-ts/template/src/styles.css +26 -0
- newstack-0.1.0/src/newstack/data/stacks/react-vite-ts/template/tsconfig.json +16 -0
- newstack-0.1.0/src/newstack/data/stacks/react-vite-ts/template/vite.config.ts +10 -0
- newstack-0.1.0/src/newstack/data/stacks/static-site/stack.json +14 -0
- newstack-0.1.0/src/newstack/data/stacks/static-site/template/.github/workflows/deploy-pages.yml +30 -0
- newstack-0.1.0/src/newstack/data/stacks/static-site/template/.gitignore +2 -0
- newstack-0.1.0/src/newstack/data/stacks/static-site/template/LICENSE +21 -0
- newstack-0.1.0/src/newstack/data/stacks/static-site/template/README.md +21 -0
- newstack-0.1.0/src/newstack/data/stacks/static-site/template/index.html +34 -0
- newstack-0.1.0/src/newstack/data/stacks/static-site/template/main.js +15 -0
- newstack-0.1.0/src/newstack/data/stacks/static-site/template/styles.css +74 -0
- newstack-0.1.0/src/newstack/data/stacks/static-site/template/tests/site.test.mjs +22 -0
- newstack-0.1.0/src/newstack/registry.py +137 -0
- newstack-0.1.0/src/newstack/render.py +163 -0
- newstack-0.1.0/src/newstack/verify.py +133 -0
- newstack-0.1.0/tests/test_cli.py +106 -0
- newstack-0.1.0/tests/test_registry.py +86 -0
- newstack-0.1.0/tests/test_render.py +110 -0
- newstack-0.1.0/tests/test_stacks.py +152 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.venv/
|
|
6
|
+
build/
|
|
7
|
+
dist/
|
|
8
|
+
.pytest_cache/
|
|
9
|
+
.ruff_cache/
|
|
10
|
+
.coverage
|
|
11
|
+
htmlcov/
|
|
12
|
+
|
|
13
|
+
# Node (used when checking the node stacks locally)
|
|
14
|
+
node_modules/
|
|
15
|
+
|
|
16
|
+
# tooling
|
|
17
|
+
.DS_Store
|
|
18
|
+
.idea/
|
|
19
|
+
.vscode/
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project adheres to
|
|
5
|
+
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.1.0] - 2026-11-02
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `newstack new <stack> <path>` — render a stack, initialise git, first commit.
|
|
14
|
+
- `newstack new … --github [OWNER/REPO]` — create the GitHub repository and push.
|
|
15
|
+
- `newstack list` — every stack with its toolchain requirements, `--json` supported.
|
|
16
|
+
- `newstack check <stack…> | --all` — generate into a temp dir and run the stack's own
|
|
17
|
+
verification steps (`install`, `lint`, `test`, `build`), reported per step.
|
|
18
|
+
- `newstack doctor` — which toolchains are installed, which stacks can be verified here.
|
|
19
|
+
- Six stacks: `python-lib`, `python-cli`, `fastapi`, `react-vite-ts`, `node-express-ts`,
|
|
20
|
+
`static-site`.
|
|
21
|
+
- Stack registry is extensible through the `NEWSTACK_STACKS` environment variable.
|
|
22
|
+
- Zero runtime dependencies: standard library only.
|
newstack-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Priyansh Kansara
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
newstack-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: newstack
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Scaffold a new project on any popular stack — every generated starter is proven green in CI.
|
|
5
|
+
Project-URL: Homepage, https://github.com/DawnofGenX/newstack
|
|
6
|
+
Project-URL: Repository, https://github.com/DawnofGenX/newstack
|
|
7
|
+
Project-URL: Issues, https://github.com/DawnofGenX/newstack/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/DawnofGenX/newstack/blob/main/CHANGELOG.md
|
|
9
|
+
Author-email: Priyansh Kansara <pkansara0412@gmail.com>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: boilerplate,cli,generator,scaffold,scaffolding,starter,template
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Software Development :: Code Generators
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# newstack
|
|
26
|
+
|
|
27
|
+
[](https://github.com/DawnofGenX/newstack/actions/workflows/ci.yml)
|
|
28
|
+

|
|
29
|
+

|
|
30
|
+
[](LICENSE)
|
|
31
|
+
|
|
32
|
+
**Scaffold a new project on any popular stack — and every starter it emits is proven green in CI.**
|
|
33
|
+
|
|
34
|
+
```console
|
|
35
|
+
$ newstack new python-lib ~/code/mylib
|
|
36
|
+
newstack 0.1.0 · python-lib → /home/you/code/mylib
|
|
37
|
+
|
|
38
|
+
created 8 files
|
|
39
|
+
git initialised on main, first commit made
|
|
40
|
+
|
|
41
|
+
next:
|
|
42
|
+
cd /home/you/code/mylib
|
|
43
|
+
uv sync
|
|
44
|
+
uv run pytest
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Why this exists
|
|
48
|
+
|
|
49
|
+
`cookiecutter`, `copier`, `yeoman`, `degit`, `npm create …` and `gh repo create --template`
|
|
50
|
+
all solve *part* of the problem. Two things are still missing in practice:
|
|
51
|
+
|
|
52
|
+
1. **One tool for every stack.** Python templates are Python-only, JS templates are
|
|
53
|
+
JS-only, and `gh repo create --template` clones a whole repository with no variables.
|
|
54
|
+
2. **A guarantee that the template still works.** Templates rot silently. You find out
|
|
55
|
+
the starter is broken *after* you have already started building on top of it.
|
|
56
|
+
|
|
57
|
+
`newstack` fixes both. It is one zero-dependency CLI that carries a curated stack
|
|
58
|
+
registry, and **every stack in that registry is generated and checked on every push**
|
|
59
|
+
(`newstack check --all` in CI). If a starter breaks, the badge goes red — not your
|
|
60
|
+
first day of work.
|
|
61
|
+
|
|
62
|
+
## Install
|
|
63
|
+
|
|
64
|
+
Not on PyPI yet — install straight from the repository:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
uv tool install git+https://github.com/DawnofGenX/newstack
|
|
68
|
+
# or, without installing:
|
|
69
|
+
uvx --from git+https://github.com/DawnofGenX/newstack newstack list
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
From a clone:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
git clone https://github.com/DawnofGenX/newstack && cd newstack
|
|
76
|
+
uv sync && uv run newstack list
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Use
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
newstack list # what is available, and what each stack needs
|
|
83
|
+
newstack new react-vite-ts ~/code/app
|
|
84
|
+
newstack new fastapi ~/code/api -d "Billing service" --author "Your Name"
|
|
85
|
+
newstack new python-lib ~/code/lib --dry-run # preview, write nothing
|
|
86
|
+
newstack new python-cli ~/code/tool --github # create the repo and push it too
|
|
87
|
+
newstack check --all # prove every stack on this machine
|
|
88
|
+
newstack doctor # which toolchains do I have?
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Every command takes `--json` where it makes sense, so the tool is scriptable.
|
|
92
|
+
|
|
93
|
+
`newstack new` renders variables, initialises git with a first commit, and (with
|
|
94
|
+
`--github`) creates the remote repository and pushes — one command from empty
|
|
95
|
+
directory to CI-ready project.
|
|
96
|
+
|
|
97
|
+
## Stacks
|
|
98
|
+
|
|
99
|
+
| Stack | What you get | Toolchain |
|
|
100
|
+
| --- | --- | --- |
|
|
101
|
+
| `python-lib` | src layout, hatchling build, pytest, ruff, 4-version CI matrix | `uv` |
|
|
102
|
+
| `python-cli` | console entry point on argparse, zero runtime deps, tested CLI | `uv` |
|
|
103
|
+
| `fastapi` | typed JSON API, pydantic models, TestClient tests, Dockerfile | `uv` |
|
|
104
|
+
| `react-vite-ts` | React 19 + Vite + TS, Vitest + Testing Library, typecheck + build | `node`, `npm` |
|
|
105
|
+
| `node-express-ts` | Express 5 API, typed handlers, supertest tests | `node`, `npm` |
|
|
106
|
+
| `static-site` | HTML/CSS/JS page with a GitHub Pages deploy workflow | `node` |
|
|
107
|
+
|
|
108
|
+
Each generated project ships its own `.github/workflows/` that is ready to run, plus a
|
|
109
|
+
README, an MIT licence and a `.gitignore`.
|
|
110
|
+
|
|
111
|
+
## The green guarantee
|
|
112
|
+
|
|
113
|
+
A template is only as good as its last successful run, so `newstack` treats
|
|
114
|
+
verification as a first-class command:
|
|
115
|
+
|
|
116
|
+
```console
|
|
117
|
+
$ newstack check --all
|
|
118
|
+
fastapi PASS 1.0s 3 step(s)
|
|
119
|
+
node-express-ts PASS 2.2s 3 step(s)
|
|
120
|
+
python-cli PASS 0.5s 4 step(s)
|
|
121
|
+
python-lib PASS 0.4s 3 step(s)
|
|
122
|
+
react-vite-ts PASS 3.2s 4 step(s)
|
|
123
|
+
static-site PASS 0.1s 3 step(s)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
(Real timings from a warm package cache — a cold run takes about a minute because
|
|
127
|
+
`npm install` and `uv pip install` have to fetch packages.)
|
|
128
|
+
|
|
129
|
+
`check` generates the stack into a throwaway directory, runs the commands listed in its
|
|
130
|
+
manifest (`install → lint → test → build`), reports per-step timings, and deletes the
|
|
131
|
+
directory unless you pass `--keep`. The same command runs in this repository's CI, once
|
|
132
|
+
per stack, on every push.
|
|
133
|
+
|
|
134
|
+
## How it compares
|
|
135
|
+
|
|
136
|
+
| | newstack | cookiecutter | copier | yeoman | degit / `npm create` | `gh repo create --template` |
|
|
137
|
+
| --- | --- | --- | --- | --- | --- | --- |
|
|
138
|
+
| Cross-language stacks in one tool | **yes** | no | no | partial | no | n/a |
|
|
139
|
+
| Runtime dependencies | **0** | Python | Python + git | Node | Node | gh |
|
|
140
|
+
| Generated starter verified in CI | **yes, per stack** | no | no | no | no | no |
|
|
141
|
+
| Template updates after generation | no (roadmap) | no | **yes** (`copier update`) | no | no | no |
|
|
142
|
+
| Creates the git repo + remote | **yes** (`--github`) | no | via hooks | no | no | yes |
|
|
143
|
+
|
|
144
|
+
Pick `copier` if you need `copier update` three-way merges against a single template you
|
|
145
|
+
own. Pick `newstack` when you want the same standard applied across several languages
|
|
146
|
+
without maintaining one template per stack.
|
|
147
|
+
|
|
148
|
+
## Adding a stack
|
|
149
|
+
|
|
150
|
+
A stack is a directory with a manifest and a template tree:
|
|
151
|
+
|
|
152
|
+
```text
|
|
153
|
+
src/newstack/data/stacks/my-stack/
|
|
154
|
+
├── stack.json
|
|
155
|
+
└── template/
|
|
156
|
+
├── README.md
|
|
157
|
+
└── ... # {{ project_name }}, {{ package_name }}, {{ npm_name }},
|
|
158
|
+
# {{ title }}, {{ description }}, {{ author }}, {{ email }},
|
|
159
|
+
# {{ year }}, {{ date }}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
```json
|
|
163
|
+
{
|
|
164
|
+
"name": "my-stack",
|
|
165
|
+
"title": "My stack",
|
|
166
|
+
"language": "python",
|
|
167
|
+
"blurb": "One line shown by `newstack list`",
|
|
168
|
+
"requires": ["uv"],
|
|
169
|
+
"next_steps": ["cd {path}", "uv run pytest"],
|
|
170
|
+
"verify": [
|
|
171
|
+
{"name": "test", "cmd": "uv run pytest", "tools": ["uv"], "timeout": 600}
|
|
172
|
+
]
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
`{{!` escapes a literal `{{`, and `${{ ... }}` (GitHub Actions) is left untouched.
|
|
177
|
+
Point `NEWSTACK_STACKS` at a directory of your own stacks to use private ones — same
|
|
178
|
+
manifest format, no fork required.
|
|
179
|
+
|
|
180
|
+
## Design
|
|
181
|
+
|
|
182
|
+
- **Zero runtime dependencies.** `argparse` and the standard library only, so `uvx newstack`
|
|
183
|
+
starts instantly and works offline.
|
|
184
|
+
- **Templates are plain files.** No Jinja, no DSL — a reviewer can read a template and know
|
|
185
|
+
exactly what gets written.
|
|
186
|
+
- **Verification is a product feature, not an afterthought.** `check` is the same code path
|
|
187
|
+
CI uses.
|
|
188
|
+
|
|
189
|
+
## Roadmap
|
|
190
|
+
|
|
191
|
+
- `newstack update` — re-apply upstream template changes to an existing project.
|
|
192
|
+
- More stacks: Go service, Rust CLI, Django, Vue, SvelteKit.
|
|
193
|
+
- `--license apache-2.0|bsd-3` and other variable choices beyond the current defaults.
|
|
194
|
+
|
|
195
|
+
## Licence
|
|
196
|
+
|
|
197
|
+
MIT — see [LICENSE](LICENSE).
|
newstack-0.1.0/README.md
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# newstack
|
|
2
|
+
|
|
3
|
+
[](https://github.com/DawnofGenX/newstack/actions/workflows/ci.yml)
|
|
4
|
+

|
|
5
|
+

|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
**Scaffold a new project on any popular stack — and every starter it emits is proven green in CI.**
|
|
9
|
+
|
|
10
|
+
```console
|
|
11
|
+
$ newstack new python-lib ~/code/mylib
|
|
12
|
+
newstack 0.1.0 · python-lib → /home/you/code/mylib
|
|
13
|
+
|
|
14
|
+
created 8 files
|
|
15
|
+
git initialised on main, first commit made
|
|
16
|
+
|
|
17
|
+
next:
|
|
18
|
+
cd /home/you/code/mylib
|
|
19
|
+
uv sync
|
|
20
|
+
uv run pytest
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Why this exists
|
|
24
|
+
|
|
25
|
+
`cookiecutter`, `copier`, `yeoman`, `degit`, `npm create …` and `gh repo create --template`
|
|
26
|
+
all solve *part* of the problem. Two things are still missing in practice:
|
|
27
|
+
|
|
28
|
+
1. **One tool for every stack.** Python templates are Python-only, JS templates are
|
|
29
|
+
JS-only, and `gh repo create --template` clones a whole repository with no variables.
|
|
30
|
+
2. **A guarantee that the template still works.** Templates rot silently. You find out
|
|
31
|
+
the starter is broken *after* you have already started building on top of it.
|
|
32
|
+
|
|
33
|
+
`newstack` fixes both. It is one zero-dependency CLI that carries a curated stack
|
|
34
|
+
registry, and **every stack in that registry is generated and checked on every push**
|
|
35
|
+
(`newstack check --all` in CI). If a starter breaks, the badge goes red — not your
|
|
36
|
+
first day of work.
|
|
37
|
+
|
|
38
|
+
## Install
|
|
39
|
+
|
|
40
|
+
Not on PyPI yet — install straight from the repository:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
uv tool install git+https://github.com/DawnofGenX/newstack
|
|
44
|
+
# or, without installing:
|
|
45
|
+
uvx --from git+https://github.com/DawnofGenX/newstack newstack list
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
From a clone:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
git clone https://github.com/DawnofGenX/newstack && cd newstack
|
|
52
|
+
uv sync && uv run newstack list
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Use
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
newstack list # what is available, and what each stack needs
|
|
59
|
+
newstack new react-vite-ts ~/code/app
|
|
60
|
+
newstack new fastapi ~/code/api -d "Billing service" --author "Your Name"
|
|
61
|
+
newstack new python-lib ~/code/lib --dry-run # preview, write nothing
|
|
62
|
+
newstack new python-cli ~/code/tool --github # create the repo and push it too
|
|
63
|
+
newstack check --all # prove every stack on this machine
|
|
64
|
+
newstack doctor # which toolchains do I have?
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Every command takes `--json` where it makes sense, so the tool is scriptable.
|
|
68
|
+
|
|
69
|
+
`newstack new` renders variables, initialises git with a first commit, and (with
|
|
70
|
+
`--github`) creates the remote repository and pushes — one command from empty
|
|
71
|
+
directory to CI-ready project.
|
|
72
|
+
|
|
73
|
+
## Stacks
|
|
74
|
+
|
|
75
|
+
| Stack | What you get | Toolchain |
|
|
76
|
+
| --- | --- | --- |
|
|
77
|
+
| `python-lib` | src layout, hatchling build, pytest, ruff, 4-version CI matrix | `uv` |
|
|
78
|
+
| `python-cli` | console entry point on argparse, zero runtime deps, tested CLI | `uv` |
|
|
79
|
+
| `fastapi` | typed JSON API, pydantic models, TestClient tests, Dockerfile | `uv` |
|
|
80
|
+
| `react-vite-ts` | React 19 + Vite + TS, Vitest + Testing Library, typecheck + build | `node`, `npm` |
|
|
81
|
+
| `node-express-ts` | Express 5 API, typed handlers, supertest tests | `node`, `npm` |
|
|
82
|
+
| `static-site` | HTML/CSS/JS page with a GitHub Pages deploy workflow | `node` |
|
|
83
|
+
|
|
84
|
+
Each generated project ships its own `.github/workflows/` that is ready to run, plus a
|
|
85
|
+
README, an MIT licence and a `.gitignore`.
|
|
86
|
+
|
|
87
|
+
## The green guarantee
|
|
88
|
+
|
|
89
|
+
A template is only as good as its last successful run, so `newstack` treats
|
|
90
|
+
verification as a first-class command:
|
|
91
|
+
|
|
92
|
+
```console
|
|
93
|
+
$ newstack check --all
|
|
94
|
+
fastapi PASS 1.0s 3 step(s)
|
|
95
|
+
node-express-ts PASS 2.2s 3 step(s)
|
|
96
|
+
python-cli PASS 0.5s 4 step(s)
|
|
97
|
+
python-lib PASS 0.4s 3 step(s)
|
|
98
|
+
react-vite-ts PASS 3.2s 4 step(s)
|
|
99
|
+
static-site PASS 0.1s 3 step(s)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
(Real timings from a warm package cache — a cold run takes about a minute because
|
|
103
|
+
`npm install` and `uv pip install` have to fetch packages.)
|
|
104
|
+
|
|
105
|
+
`check` generates the stack into a throwaway directory, runs the commands listed in its
|
|
106
|
+
manifest (`install → lint → test → build`), reports per-step timings, and deletes the
|
|
107
|
+
directory unless you pass `--keep`. The same command runs in this repository's CI, once
|
|
108
|
+
per stack, on every push.
|
|
109
|
+
|
|
110
|
+
## How it compares
|
|
111
|
+
|
|
112
|
+
| | newstack | cookiecutter | copier | yeoman | degit / `npm create` | `gh repo create --template` |
|
|
113
|
+
| --- | --- | --- | --- | --- | --- | --- |
|
|
114
|
+
| Cross-language stacks in one tool | **yes** | no | no | partial | no | n/a |
|
|
115
|
+
| Runtime dependencies | **0** | Python | Python + git | Node | Node | gh |
|
|
116
|
+
| Generated starter verified in CI | **yes, per stack** | no | no | no | no | no |
|
|
117
|
+
| Template updates after generation | no (roadmap) | no | **yes** (`copier update`) | no | no | no |
|
|
118
|
+
| Creates the git repo + remote | **yes** (`--github`) | no | via hooks | no | no | yes |
|
|
119
|
+
|
|
120
|
+
Pick `copier` if you need `copier update` three-way merges against a single template you
|
|
121
|
+
own. Pick `newstack` when you want the same standard applied across several languages
|
|
122
|
+
without maintaining one template per stack.
|
|
123
|
+
|
|
124
|
+
## Adding a stack
|
|
125
|
+
|
|
126
|
+
A stack is a directory with a manifest and a template tree:
|
|
127
|
+
|
|
128
|
+
```text
|
|
129
|
+
src/newstack/data/stacks/my-stack/
|
|
130
|
+
├── stack.json
|
|
131
|
+
└── template/
|
|
132
|
+
├── README.md
|
|
133
|
+
└── ... # {{ project_name }}, {{ package_name }}, {{ npm_name }},
|
|
134
|
+
# {{ title }}, {{ description }}, {{ author }}, {{ email }},
|
|
135
|
+
# {{ year }}, {{ date }}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
"name": "my-stack",
|
|
141
|
+
"title": "My stack",
|
|
142
|
+
"language": "python",
|
|
143
|
+
"blurb": "One line shown by `newstack list`",
|
|
144
|
+
"requires": ["uv"],
|
|
145
|
+
"next_steps": ["cd {path}", "uv run pytest"],
|
|
146
|
+
"verify": [
|
|
147
|
+
{"name": "test", "cmd": "uv run pytest", "tools": ["uv"], "timeout": 600}
|
|
148
|
+
]
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
`{{!` escapes a literal `{{`, and `${{ ... }}` (GitHub Actions) is left untouched.
|
|
153
|
+
Point `NEWSTACK_STACKS` at a directory of your own stacks to use private ones — same
|
|
154
|
+
manifest format, no fork required.
|
|
155
|
+
|
|
156
|
+
## Design
|
|
157
|
+
|
|
158
|
+
- **Zero runtime dependencies.** `argparse` and the standard library only, so `uvx newstack`
|
|
159
|
+
starts instantly and works offline.
|
|
160
|
+
- **Templates are plain files.** No Jinja, no DSL — a reviewer can read a template and know
|
|
161
|
+
exactly what gets written.
|
|
162
|
+
- **Verification is a product feature, not an afterthought.** `check` is the same code path
|
|
163
|
+
CI uses.
|
|
164
|
+
|
|
165
|
+
## Roadmap
|
|
166
|
+
|
|
167
|
+
- `newstack update` — re-apply upstream template changes to an existing project.
|
|
168
|
+
- More stacks: Go service, Rust CLI, Django, Vue, SvelteKit.
|
|
169
|
+
- `--license apache-2.0|bsd-3` and other variable choices beyond the current defaults.
|
|
170
|
+
|
|
171
|
+
## Licence
|
|
172
|
+
|
|
173
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.27"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "newstack"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Scaffold a new project on any popular stack — every generated starter is proven green in CI."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
authors = [{ name = "Priyansh Kansara", email = "pkansara0412@gmail.com" }]
|
|
14
|
+
keywords = ["scaffold", "scaffolding", "boilerplate", "template", "generator", "cli", "starter"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 4 - Beta",
|
|
17
|
+
"Environment :: Console",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3.10",
|
|
21
|
+
"Programming Language :: Python :: 3.11",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Programming Language :: Python :: 3.13",
|
|
24
|
+
"Topic :: Software Development :: Code Generators",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[project.scripts]
|
|
28
|
+
newstack = "newstack.cli:main"
|
|
29
|
+
|
|
30
|
+
[project.urls]
|
|
31
|
+
Homepage = "https://github.com/DawnofGenX/newstack"
|
|
32
|
+
Repository = "https://github.com/DawnofGenX/newstack"
|
|
33
|
+
Issues = "https://github.com/DawnofGenX/newstack/issues"
|
|
34
|
+
Changelog = "https://github.com/DawnofGenX/newstack/blob/main/CHANGELOG.md"
|
|
35
|
+
|
|
36
|
+
[dependency-groups]
|
|
37
|
+
dev = ["pytest>=8.0", "ruff>=0.6"]
|
|
38
|
+
|
|
39
|
+
[tool.hatch.build.targets.wheel]
|
|
40
|
+
packages = ["src/newstack"]
|
|
41
|
+
|
|
42
|
+
[tool.hatch.build.targets.sdist]
|
|
43
|
+
include = ["src/newstack", "tests", "README.md", "LICENSE", "CHANGELOG.md"]
|
|
44
|
+
|
|
45
|
+
[tool.ruff]
|
|
46
|
+
line-length = 100
|
|
47
|
+
target-version = "py310"
|
|
48
|
+
extend-exclude = ["src/newstack/data"]
|
|
49
|
+
|
|
50
|
+
[tool.ruff.lint]
|
|
51
|
+
select = ["E", "F", "W", "I", "UP", "B", "SIM"]
|
|
52
|
+
|
|
53
|
+
[tool.pytest.ini_options]
|
|
54
|
+
testpaths = ["tests"]
|
|
55
|
+
addopts = "-q"
|