@doikayt/typescript-build-config 0.1.32 → 0.1.37
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.
- package/README.md +74 -34
- package/package.json +6 -6
- package/src/canonical-scripts.js +1 -1
- package/src/init.js +32 -3
- package/src/new-package.js +10 -1
- package/src/pipeline/woodpecker.yml +50 -0
- package/src/postinstall.js +28 -9
- package/src/templates/LICENSE +21 -0
- package/src/templates/demo/README.md +3 -1
- package/src/templates/demo/src/math-engine/_COMPONENT_INFO.md +1 -0
- package/src/pipeline/release.yml +0 -72
- package/src/pipeline/verify-npm-token.yml +0 -17
package/README.md
CHANGED
|
@@ -50,7 +50,7 @@ via the pipeline files it installs into each consumer repo and the canonical rel
|
|
|
50
50
|
These steps set up — in a fresh "new-developer" environment — a local git repo
|
|
51
51
|
with a skeleton demo app plus all the standard Doikayt build configuration:
|
|
52
52
|
tooling that auto-documents the code in the repo and lets it be pushed to
|
|
53
|
-
|
|
53
|
+
Codeberg, built by Woodpecker CI, and (for a library) published to npm. Steps
|
|
54
54
|
are minimal here — each links to the section that explains _what_ and _why_.
|
|
55
55
|
|
|
56
56
|
### 1. One-time machine setup (once per machine)
|
|
@@ -59,13 +59,34 @@ Clone this base repo and install the shared team
|
|
|
59
59
|
[shell aliases](#team-shell-aliases). This only sets up the aliases
|
|
60
60
|
(`dk-scaffold`, `mkrepo`); it does **not** configure any project:
|
|
61
61
|
|
|
62
|
+
🛑 **STOP here if you are a contributor/maintainer of `typescript-build-config` itself** If you intend to
|
|
63
|
+
push commits back to *this* repo, you're in the wrong place — the clone below is
|
|
64
|
+
HTTPS, read-only for this repo. Start here instead: [For Maintainers](#for-maintainers).
|
|
65
|
+
|
|
62
66
|
```bash
|
|
63
|
-
git clone https://
|
|
67
|
+
git clone https://codeberg.org/doikayt/typescript-build-config.git # HTTPS: no SSH key needed
|
|
68
|
+
#
|
|
69
|
+
## Alternative using ssh key: git clone ssh://git@codeberg.org/doikayt/typescript-build-config.git
|
|
70
|
+
#
|
|
71
|
+
#
|
|
72
|
+
#
|
|
64
73
|
cd typescript-build-config
|
|
65
74
|
./assets/shell/install.sh # adds `source assets/shell/aliases.sh` to your rc (idempotent)
|
|
66
|
-
exec $SHELL #
|
|
75
|
+
exec $SHELL # replaces this shell with a fresh one that reloads your rc
|
|
67
76
|
```
|
|
68
77
|
|
|
78
|
+
The aliases are now active in this shell. Run `tools-help` to confirm — it prints every
|
|
79
|
+
command you now have available (`dk-scaffold`, `mkrepo`, and more) with a one-line
|
|
80
|
+
summary of what each does. From here, go to
|
|
81
|
+
[2. Create a new project](#2-create-a-new-project-repeatable) below.
|
|
82
|
+
|
|
83
|
+
**Re-running this after `aliases.sh` changed?** Always use `exec $SHELL` (a fresh
|
|
84
|
+
shell), not `source assets/shell/aliases.sh` in your existing terminal. If a function
|
|
85
|
+
it defines shares a name with something your shell already has loaded (an old alias
|
|
86
|
+
from a previous version, for instance), sourcing directly can fail with a confusing
|
|
87
|
+
`syntax error near unexpected token`. A fresh shell never had the stale definition to
|
|
88
|
+
begin with.
|
|
89
|
+
|
|
69
90
|
### 2. Create a new project (repeatable)
|
|
70
91
|
|
|
71
92
|
The two paths below are **alternatives that reach the same result** — a project
|
|
@@ -74,7 +95,7 @@ wired to this base package.
|
|
|
74
95
|
#### dk-scaffold
|
|
75
96
|
|
|
76
97
|
`dk-scaffold` is the one-command wrapper that also (optionally) creates the
|
|
77
|
-
|
|
98
|
+
Codeberg repo and pushes it. Just run it with a first argument naming your project
|
|
78
99
|
and a second indicating `lib` (a published library) or `app` (a standalone
|
|
79
100
|
app/utility, the default) — see [library vs app](#usage) and
|
|
80
101
|
[Packaging concepts](docs/packaging-concepts.md):
|
|
@@ -83,6 +104,16 @@ app/utility, the default) — see [library vs app](#usage) and
|
|
|
83
104
|
dk-scaffold my-project lib
|
|
84
105
|
```
|
|
85
106
|
|
|
107
|
+
**Where the project lands.** `dk-scaffold <name>` creates a `<name>/` subdirectory in the
|
|
108
|
+
directory you ran it from (for example `~/projects/my-project/`) and leaves your shell
|
|
109
|
+
inside it. Two variants scaffold in place instead of creating a subdirectory:
|
|
110
|
+
|
|
111
|
+
- run it from inside an empty directory that is already named `<name>`
|
|
112
|
+
- pass `.` as the name, which uses the current directory's name as the project name
|
|
113
|
+
|
|
114
|
+
`dk-scaffold` will look like it is prompting you, but just wait a moment: the script
|
|
115
|
+
fills in the appropriate answers itself. It prints a note saying so; pass `-q` to hide it.
|
|
116
|
+
|
|
86
117
|
#### Run dk-scaffold's steps individually
|
|
87
118
|
|
|
88
119
|
The steps below mirror the work `dk-scaffold` does under the hood — either for a
|
|
@@ -105,8 +136,8 @@ throwaway **app** (nothing publishes) unless noted. Do the one-time
|
|
|
105
136
|
[machine setup](#1-one-time-machine-setup-once-per-machine) first so `dk-scaffold`
|
|
106
137
|
is on your PATH.
|
|
107
138
|
|
|
108
|
-
**Level 0 — local (no external
|
|
109
|
-
the same gate CI runs — no
|
|
139
|
+
**Level 0 — local (no external Codeberg/npm accounts needed).** Scaffold and run
|
|
140
|
+
the same gate CI runs — no Codeberg repo, no push:
|
|
110
141
|
|
|
111
142
|
```bash
|
|
112
143
|
dk-scaffold my-demo --local
|
|
@@ -118,20 +149,24 @@ declarations, and `update-all-format` fill the README's TOC + UML markers
|
|
|
118
149
|
(mermaid **source** — rendered at Level 1). `npm publish --dry-run` **refuses** —
|
|
119
150
|
proof the app archetype never publishes.
|
|
120
151
|
|
|
121
|
-
|
|
122
|
-
|
|
152
|
+
The project is created in `./my-demo/` (a subdirectory of wherever you ran the command),
|
|
153
|
+
and your shell's CWD (current working directory) gets set to the root of this new project.
|
|
154
|
+
This means you can run `npm test` or `npm run build` right away.
|
|
155
|
+
|
|
156
|
+
**Level 1 — push to your own Codeberg.** Bring a Codeberg account and an API token.
|
|
157
|
+
Export the token, point the wrapper at your account, and drop `--local`:
|
|
123
158
|
|
|
124
159
|
```bash
|
|
125
|
-
|
|
126
|
-
export REPO_OWNER=<your-
|
|
127
|
-
dk-scaffold my-demo # app (
|
|
160
|
+
export CODEBERG_TOKEN=<your-codeberg-token> # repository-creation token
|
|
161
|
+
export REPO_OWNER=<your-codeberg-org> # target owner for the repo
|
|
162
|
+
dk-scaffold my-demo # app (public repo) — no npm creds
|
|
128
163
|
```
|
|
129
164
|
|
|
130
165
|
Now it creates the repo and pushes — and you see what Level 0 couldn't: the
|
|
131
166
|
**mermaid diagrams rendered** (example
|
|
132
167
|
[here](https://github.com/doikayt/build-tools/blob/main/javascript/tooling-core/README.md#package-structure))
|
|
133
|
-
and the **CI job
|
|
134
|
-
[this project's runs](https://
|
|
168
|
+
and the **CI job goes green** in Woodpecker CI (example:
|
|
169
|
+
[this project's runs](https://ci.codeberg.org/repos/doikayt/typescript-build-config)).
|
|
135
170
|
Push a follow-up **`feat:`** commit and the **release job** version-bumps + tags —
|
|
136
171
|
nothing published (app). (The initial `chore: scaffold` push releases nothing;
|
|
137
172
|
`feat:` / `fix:` triggers it.)
|
|
@@ -139,14 +174,14 @@ nothing published (app). (The initial `chore: scaffold` push releases nothing;
|
|
|
139
174
|
|
|
140
175
|
The screen cast below shows the process for Level 1. Note:
|
|
141
176
|
|
|
142
|
-
- When we log in to our test account (associated with a dummy
|
|
177
|
+
- When we log in to our test account (associated with a dummy Codeberg account,
|
|
143
178
|
not doikayt) we see:
|
|
144
179
|
- no repos initially
|
|
145
180
|
- no doikayt aliases registered in `.bashrc`
|
|
146
|
-
- After we run `dk-scaffold demo`,
|
|
181
|
+
- After we run `dk-scaffold demo`, the install proceeds automatically, then we see:
|
|
147
182
|
- lots of output showing the project being configured and built
|
|
148
|
-
- a push to
|
|
149
|
-
- a build and release triggered
|
|
183
|
+
- a push to Codeberg
|
|
184
|
+
- a build and release triggered by Woodpecker CI
|
|
150
185
|
- since we did not select `lib`, we got an app build profile, for which
|
|
151
186
|
there is no publish to npm
|
|
152
187
|
|
|
@@ -158,14 +193,14 @@ The screen cast below shows the process for Level 1. Note:
|
|
|
158
193
|
alt="update-markdown-toc demo">
|
|
159
194
|
</p>
|
|
160
195
|
|
|
161
|
-
After we ran the screen cast steps we were able to screenshot how our push triggered a build
|
|
162
|
-
|
|
196
|
+
After we ran the screen cast steps we were able to screenshot how our push triggered a build on
|
|
197
|
+
Woodpecker CI.
|
|
163
198
|
|
|
164
199
|
<p align="center">
|
|
165
200
|
<img
|
|
166
201
|
src="docs/github-actions.png"
|
|
167
202
|
width="720"
|
|
168
|
-
alt="
|
|
203
|
+
alt="woodpecker-ci-view">
|
|
169
204
|
</p>
|
|
170
205
|
|
|
171
206
|
|
|
@@ -208,7 +243,7 @@ is _why_.)
|
|
|
208
243
|
| **Stubs** — `src/top-level/*` seeded into the project root | Zero-config entry points that only `extends` the presets | Minimal setup |
|
|
209
244
|
| **Pipeline** — `src/pipeline/*` copied on install | A working release + changeset workflow with no hand-wiring; drift is diff-warned | Both |
|
|
210
245
|
| **Convention checks** — postinstall warns on missing `ci` / `update-all-format` | An install-time nudge toward the shared command surface | Consistency |
|
|
211
|
-
| **`ci` gate** —
|
|
246
|
+
| **`ci` gate** — `.woodpecker.yml` runs `npm run ci` | Fail-closed enforcement: a repo that ignores the convention cannot release | Consistency (hard teeth) |
|
|
212
247
|
| **Policy doc** — `docs/RELEASE-PROCESS.md`, linked never copied | One canonical release policy, impossible to drift | Consistency |
|
|
213
248
|
| **Assets** — `assets/image/*` seeded into `docs/assets/` | Shared brand logos with no per-repo copies to maintain | Minimal setup |
|
|
214
249
|
| **Shell aliases** — `assets/shell/aliases.sh`, cloned + sourced (never shipped to npm) | One standard way for the team to create and scaffold repos (`mkrepo`, `dk-*`) | Consistency |
|
|
@@ -335,10 +370,10 @@ versions of these tools may produce peer dependency conflicts.
|
|
|
335
370
|
- TypeScript config (`tsconfig.json`, `tsconfig.test.json`, `tsconfig.eslint.json`)
|
|
336
371
|
- Postinstall script that copies starter top-level config files into your
|
|
337
372
|
project root, extending the configs installed under `node_modules`
|
|
338
|
-
-
|
|
373
|
+
- Woodpecker CI release workflow (`.woodpecker.yml`)
|
|
339
374
|
- Changeset config (`.changeset/config.json`)
|
|
340
375
|
- Auto-changeset script (`scripts/auto-changeset.sh`)
|
|
341
|
-
- NPM token diagnostic
|
|
376
|
+
- NPM token diagnostic instructions — see
|
|
342
377
|
[Troubleshooting Publish Auth](docs/RELEASE-PROCESS.md#troubleshooting-publish-auth)
|
|
343
378
|
- Playwright config helper (`@doikayt/typescript-build-config/playwright`) — `nixChromiumLaunchOptions()`
|
|
344
379
|
discovers the system Chromium on quirky NixOS; `definePlaywrightConfig()` wraps `defineConfig` and
|
|
@@ -410,7 +445,7 @@ components.
|
|
|
410
445
|
│ │ prettier.config.js … │
|
|
411
446
|
│ └────extends────► presets living in │
|
|
412
447
|
│ node_modules (chan. 1) │
|
|
413
|
-
│ owned pipeline: .
|
|
448
|
+
│ owned pipeline: .woodpecker.yml │
|
|
414
449
|
│ scripts/auto-changeset.sh │
|
|
415
450
|
│ owned assets: docs/assets/doikayt-logo.* │
|
|
416
451
|
│ CONTRIBUTING.md ─cites URL─► RELEASE-PROCESS.md│
|
|
@@ -502,9 +537,7 @@ On `npm update`, the behavior per file is:
|
|
|
502
537
|
This means local customisations are never silently overwritten, but you are
|
|
503
538
|
notified when your copy has drifted from the upstream version.
|
|
504
539
|
|
|
505
|
-
The release pipeline requires
|
|
506
|
-
level. All repos under the org inherit it automatically — no per-repo secret
|
|
507
|
-
configuration is needed.
|
|
540
|
+
The release pipeline requires `NPM` and `CODEBERG_TOKEN` secrets in Woodpecker.
|
|
508
541
|
|
|
509
542
|
## Conventions Every Project Must Adhere To
|
|
510
543
|
|
|
@@ -601,7 +634,7 @@ directly.
|
|
|
601
634
|
|
|
602
635
|
## Publishing
|
|
603
636
|
|
|
604
|
-
Releases are automated via Changesets and
|
|
637
|
+
Releases are automated via Changesets and Woodpecker CI. The full policy —
|
|
605
638
|
commit-prefix → bump mapping, forcing or suppressing a release, resolving
|
|
606
639
|
`changeset status` errors, verifying a release, troubleshooting publish auth —
|
|
607
640
|
is documented in [docs/RELEASE-PROCESS.md](docs/RELEASE-PROCESS.md). That
|
|
@@ -620,28 +653,32 @@ present. For majors this is mandatory: a breaking-change commit (`feat!:` or
|
|
|
620
653
|
`BREAKING CHANGE` in the body) with no handwritten changeset fails the
|
|
621
654
|
release job until one is committed.
|
|
622
655
|
|
|
623
|
-
**Manual publish (emergency):** trigger the
|
|
624
|
-
**GitHub Actions → CI / Release → Run workflow** on the `main` branch.
|
|
656
|
+
**Manual publish (emergency):** trigger a Woodpecker pipeline on the `main` branch.
|
|
625
657
|
|
|
626
658
|
## Team shell aliases
|
|
627
659
|
|
|
628
660
|
Installed by [Quick start](#quick-start) step 1 (or manually: add
|
|
629
|
-
`source <clone-path>/assets/shell/aliases.sh` to your shell rc). They require
|
|
630
|
-
|
|
661
|
+
`source <clone-path>/assets/shell/aliases.sh` to your shell rc). They require
|
|
662
|
+
`curl`, `CODEBERG_TOKEN`, and `node`/`npm`.
|
|
631
663
|
|
|
632
664
|
| Alias | What it does |
|
|
633
665
|
| --- | --- |
|
|
634
666
|
| `mkrepo <name>` | Create a public repo in the `doikayt` org (guards against duplicates). |
|
|
667
|
+
| `addpush [name]` | Wire up the current directory to an existing Codeberg repo (create it first with `mkrepo`) and push. Defaults `name` to the current directory. |
|
|
635
668
|
| `dk-new` | `npm init -y` + `@doikayt` scope. |
|
|
636
669
|
| `dk-init` | Scaffold the build config into the current project. |
|
|
637
|
-
| `dk-scaffold <name>\|. [lib\|app]` | Create the repo, scaffold, and push — one command (defaults to app). Pass `.` to scaffold in the current directory, using its leaf name as `@doikayt/<package-name>`. |
|
|
670
|
+
| `dk-scaffold <name>\|. [lib\|app] [--local] [-q]` | Create the repo, scaffold, and push — one command (defaults to app). Pass `.` to scaffold in the current directory, using its leaf name as `@doikayt/<package-name>`. `--local` skips the repo and push; `-q` hides the auto-answered-prompts note. |
|
|
671
|
+
| `gp` | Pull with rebase, then push the current branch. The everyday git sync command — requires the branch to already track a remote. |
|
|
672
|
+
| `gpu` | First push of a new local branch: sets it up to track `origin` and pushes (or just wires up tracking if `origin` already has a same-named branch). |
|
|
673
|
+
| `trackify` | Set the upstream tracking branch for the current branch to the same-named branch on `origin`, without pushing. Fails if that remote branch doesn't exist yet. |
|
|
674
|
+
| `tools-help` | Print every alias/function in `aliases.sh`, grouped, with a one-line summary parsed from each one's own doc comment — the full, always-current list (diff helpers, cleanup helpers, etc.) lives there instead of being duplicated in this table. |
|
|
638
675
|
|
|
639
676
|
## For Maintainers
|
|
640
677
|
|
|
641
678
|
### Clone and install
|
|
642
679
|
|
|
643
680
|
```bash
|
|
644
|
-
git clone git@
|
|
681
|
+
git clone git@codeberg.org:doikayt/typescript-build-config.git
|
|
645
682
|
cd typescript-build-config
|
|
646
683
|
npm install
|
|
647
684
|
```
|
|
@@ -679,3 +716,6 @@ by hand, with what to look for at each step — follow
|
|
|
679
716
|
MIT
|
|
680
717
|
|
|
681
718
|
|
|
719
|
+
|
|
720
|
+
[](https://techforpalestine.org/learn-more)
|
|
721
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@doikayt/typescript-build-config",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.37",
|
|
4
4
|
"description": "Shared build configuration for TypeScript projects — ESLint, Prettier, tsconfig, and Playwright presets",
|
|
5
5
|
"_comments": {
|
|
6
6
|
"exports": "This block lists the config files that will be extended by files in in src/toplevel - which are copied to consuming project root folder. An example: eslint.config.js imports from '@doikayt/typescript-build-config/eslint'.",
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
"@playwright/test": "^1.40.0"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
47
|
-
"@typescript-eslint/parser": "^8.
|
|
46
|
+
"@typescript-eslint/eslint-plugin": "^8.57.1",
|
|
47
|
+
"@typescript-eslint/parser": "^8.57.1",
|
|
48
48
|
"eslint": "^9.0.0",
|
|
49
49
|
"prettier": "^3.0.0"
|
|
50
50
|
},
|
|
@@ -59,12 +59,12 @@
|
|
|
59
59
|
"license": "MIT",
|
|
60
60
|
"repository": {
|
|
61
61
|
"type": "git",
|
|
62
|
-
"url": "git+ssh://git@
|
|
62
|
+
"url": "git+ssh://git@codeberg.org/doikayt/typescript-build-config.git"
|
|
63
63
|
},
|
|
64
64
|
"peerDependencies": {
|
|
65
|
+
"@playwright/test": ">=1.40.0",
|
|
65
66
|
"@typescript-eslint/eslint-plugin": "^8.57.1",
|
|
66
|
-
"@typescript-eslint/parser": "^8.57.1"
|
|
67
|
-
"@playwright/test": ">=1.40.0"
|
|
67
|
+
"@typescript-eslint/parser": "^8.57.1"
|
|
68
68
|
},
|
|
69
69
|
"peerDependenciesMeta": {
|
|
70
70
|
"@playwright/test": {
|
package/src/canonical-scripts.js
CHANGED
|
@@ -31,7 +31,7 @@ export function canonicalScripts({ ui = false, library = false } = {}) {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
export function devDependencyNames({ ui = false } = {}) {
|
|
34
|
-
// @changesets/cli is required by the release pipeline (
|
|
34
|
+
// @changesets/cli is required by the release pipeline (.woodpecker.yml runs
|
|
35
35
|
// `npx changeset version` / `publish`), so every consumer needs it installed —
|
|
36
36
|
// otherwise `npx changeset` can't resolve the `changeset` bin and the release
|
|
37
37
|
// job fails with "could not determine executable to run".
|
package/src/init.js
CHANGED
|
@@ -28,6 +28,17 @@ function seedFile(src, destPath) {
|
|
|
28
28
|
return "seeded";
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
// Write an MIT LICENSE from the template when the project has none. The holder
|
|
32
|
+
// is the owning org (REPO_OWNER); without one, a neutral "project contributors".
|
|
33
|
+
function seedLicense(destPath, { holder, year }) {
|
|
34
|
+
if (existsSync(destPath)) return "skipped";
|
|
35
|
+
const text = readFileSync(resolve(templatesDir, "LICENSE"), "utf8")
|
|
36
|
+
.replace("{{YEAR}}", String(year))
|
|
37
|
+
.replace("{{HOLDER}}", holder);
|
|
38
|
+
writeFileSync(destPath, text);
|
|
39
|
+
return "seeded";
|
|
40
|
+
}
|
|
41
|
+
|
|
31
42
|
// Recursively copy a template directory tree into the project.
|
|
32
43
|
function copyDir(srcDir, destDir) {
|
|
33
44
|
mkdirSync(destDir, { recursive: true });
|
|
@@ -83,6 +94,8 @@ export async function runInit({
|
|
|
83
94
|
promptText,
|
|
84
95
|
resolveDevVersions = resolveVersions,
|
|
85
96
|
log = console.log,
|
|
97
|
+
licenseHolder = process.env.REPO_OWNER,
|
|
98
|
+
licenseYear = new Date().getFullYear(),
|
|
86
99
|
} = {}) {
|
|
87
100
|
// One readline interface for all prompts (see createAskYesNo); close it even
|
|
88
101
|
// on error so a leftover interface never keeps the process alive.
|
|
@@ -98,6 +111,8 @@ export async function runInit({
|
|
|
98
111
|
askText,
|
|
99
112
|
resolveDevVersions,
|
|
100
113
|
log,
|
|
114
|
+
licenseHolder,
|
|
115
|
+
licenseYear,
|
|
101
116
|
});
|
|
102
117
|
} finally {
|
|
103
118
|
ownAsk?.close();
|
|
@@ -110,6 +125,8 @@ async function collectAndScaffold({
|
|
|
110
125
|
askText,
|
|
111
126
|
resolveDevVersions,
|
|
112
127
|
log,
|
|
128
|
+
licenseHolder,
|
|
129
|
+
licenseYear,
|
|
113
130
|
}) {
|
|
114
131
|
const pkgPath = resolve(cwd, "package.json");
|
|
115
132
|
const raw = readFileSync(pkgPath, "utf8");
|
|
@@ -146,12 +163,13 @@ async function collectAndScaffold({
|
|
|
146
163
|
const scripts = canonicalScripts({ ui, library });
|
|
147
164
|
const devDependencies = resolveDevVersions(devDependencyNames({ ui }));
|
|
148
165
|
|
|
149
|
-
const fields = packageFields({ library });
|
|
166
|
+
const fields = { ...packageFields({ library }), license: "MIT" };
|
|
150
167
|
// `npm init -y` seeds these placeholders; treat them as unset so the canonical
|
|
151
|
-
// `test` script and (for a library) `main` replace them instead of
|
|
168
|
+
// `test` script, `license` and (for a library) `main` replace them instead of
|
|
169
|
+
// shadowing.
|
|
152
170
|
const replaceDefaults = {
|
|
153
171
|
scripts: { test: 'echo "Error: no test specified" && exit 1' },
|
|
154
|
-
fields: { main: "index.js" },
|
|
172
|
+
fields: { main: "index.js", license: "ISC" },
|
|
155
173
|
};
|
|
156
174
|
if (library) {
|
|
157
175
|
// The chosen name is a deliberate publish decision, so it replaces whatever
|
|
@@ -177,6 +195,17 @@ async function collectAndScaffold({
|
|
|
177
195
|
(result === "seeded" ? seededConfigs : keptConfigs).push(name);
|
|
178
196
|
}
|
|
179
197
|
|
|
198
|
+
// Codeberg's CI access request requires a LICENSE file. Seed one only when
|
|
199
|
+
// the project's license is MIT (the canonical one), so a consumer who chose a
|
|
200
|
+
// different license is never handed a contradicting file.
|
|
201
|
+
if (JSON.parse(text).license === "MIT") {
|
|
202
|
+
const result = seedLicense(resolve(cwd, "LICENSE"), {
|
|
203
|
+
holder: licenseHolder || "the project contributors",
|
|
204
|
+
year: licenseYear,
|
|
205
|
+
});
|
|
206
|
+
(result === "seeded" ? seededConfigs : keptConfigs).push("LICENSE");
|
|
207
|
+
}
|
|
208
|
+
|
|
180
209
|
const demo = wantDemo
|
|
181
210
|
? scaffoldDemo({ cwd })
|
|
182
211
|
: {
|
package/src/new-package.js
CHANGED
|
@@ -3,9 +3,18 @@ import { resolve } from "path";
|
|
|
3
3
|
import { spawnSync } from "child_process";
|
|
4
4
|
import { scopeName } from "./scope-name.js";
|
|
5
5
|
|
|
6
|
+
export function npmExecutableName() {
|
|
7
|
+
return process.platform === "win32" ? "npm.cmd" : "npm";
|
|
8
|
+
}
|
|
9
|
+
|
|
6
10
|
// Default `npm init -y` runner. Injectable so runNew is testable without npm.
|
|
7
11
|
function npmInitY(cwd) {
|
|
8
|
-
const
|
|
12
|
+
const npmCommand = npmExecutableName();
|
|
13
|
+
const res = spawnSync(npmCommand, ["init", "-y"], {
|
|
14
|
+
cwd,
|
|
15
|
+
stdio: "inherit",
|
|
16
|
+
shell: process.platform === "win32",
|
|
17
|
+
});
|
|
9
18
|
if (res.error) throw res.error;
|
|
10
19
|
if (res.status !== 0)
|
|
11
20
|
throw new Error(`npm init -y exited with ${res.status}`);
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Canonical pipeline is maintained in src/pipeline/woodpecker.yml.
|
|
2
|
+
# Keep this root copy in sync for this repository.
|
|
3
|
+
steps:
|
|
4
|
+
ci:
|
|
5
|
+
image: node:22
|
|
6
|
+
commands:
|
|
7
|
+
- npm ci
|
|
8
|
+
- npm run ci
|
|
9
|
+
- if [ "$CI_PIPELINE_EVENT" = "pull_request" ]; then npx changeset status; fi
|
|
10
|
+
when:
|
|
11
|
+
- event: [push, pull_request, tag]
|
|
12
|
+
|
|
13
|
+
verify-npm-token:
|
|
14
|
+
image: node:22
|
|
15
|
+
commands:
|
|
16
|
+
- 'echo "//registry.npmjs.org/:_authToken=$NPM" > ~/.npmrc'
|
|
17
|
+
- npm whoami
|
|
18
|
+
environment:
|
|
19
|
+
NPM:
|
|
20
|
+
from_secret: NPM
|
|
21
|
+
when:
|
|
22
|
+
- event: manual
|
|
23
|
+
|
|
24
|
+
release:
|
|
25
|
+
image: node:22
|
|
26
|
+
depends_on:
|
|
27
|
+
- ci
|
|
28
|
+
commands:
|
|
29
|
+
- apt-get update && apt-get install -y --no-install-recommends git bash
|
|
30
|
+
- npm ci
|
|
31
|
+
- 'if [ "$(git rev-parse --is-shallow-repository)" = true ]; then git fetch --unshallow --tags --force; else git fetch --tags --force; fi'
|
|
32
|
+
- git config user.name "doikayt-release-bot"
|
|
33
|
+
- git config user.email "doikayt-release-bot@codeberg.org"
|
|
34
|
+
- bash scripts/auto-changeset.sh
|
|
35
|
+
- npx changeset version
|
|
36
|
+
- git add .
|
|
37
|
+
- 'git diff --staged --quiet || git commit -m "chore: release [CI SKIP]"'
|
|
38
|
+
- git remote set-url origin "https://$CODEBERG_TOKEN@codeberg.org/$CI_REPO.git"
|
|
39
|
+
- git push origin HEAD:main
|
|
40
|
+
- 'echo "//registry.npmjs.org/:_authToken=$NPM" > ~/.npmrc'
|
|
41
|
+
- npx changeset publish
|
|
42
|
+
- git push origin --tags
|
|
43
|
+
environment:
|
|
44
|
+
CODEBERG_TOKEN:
|
|
45
|
+
from_secret: CODEBERG_TOKEN
|
|
46
|
+
NPM:
|
|
47
|
+
from_secret: NPM
|
|
48
|
+
when:
|
|
49
|
+
- event: push
|
|
50
|
+
branch: main
|
package/src/postinstall.js
CHANGED
|
@@ -9,12 +9,35 @@ import { resolve, dirname } from "path";
|
|
|
9
9
|
import { execSync } from "child_process";
|
|
10
10
|
import { tmpdir } from "os";
|
|
11
11
|
import { join } from "path";
|
|
12
|
+
import { fileURLToPath } from "url";
|
|
12
13
|
|
|
13
14
|
const PREFIX = "[@doikayt/typescript-build-config]";
|
|
14
15
|
|
|
16
|
+
export function normalizeProjectRoot(rawPath) {
|
|
17
|
+
if (!rawPath) return rawPath;
|
|
18
|
+
|
|
19
|
+
let normalized = rawPath.replace(/^[A-Za-z]:\\C:\\/, "C:\\");
|
|
20
|
+
normalized = normalized.replace(
|
|
21
|
+
/^\/([A-Za-z])\//,
|
|
22
|
+
(_, drive) => `${drive.toUpperCase()}:\\`,
|
|
23
|
+
);
|
|
24
|
+
normalized = normalized.replace(/^\//, "");
|
|
25
|
+
normalized = normalized.replace(/\\+/g, "\\");
|
|
26
|
+
|
|
27
|
+
if (/^([A-Za-z]):\\/.test(normalized)) {
|
|
28
|
+
return normalized.replace(/\\+/g, "\\");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (/^([A-Za-z]):\//.test(normalized)) {
|
|
32
|
+
return normalized.replace(/\//g, "\\");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return normalized;
|
|
36
|
+
}
|
|
37
|
+
|
|
15
38
|
console.log(`${PREFIX} Running postinstall...`);
|
|
16
39
|
|
|
17
|
-
const projectRoot = process.env.INIT_CWD ?? process.cwd();
|
|
40
|
+
const projectRoot = normalizeProjectRoot(process.env.INIT_CWD ?? process.cwd());
|
|
18
41
|
const projectPkgPath = resolve(projectRoot, "package.json");
|
|
19
42
|
|
|
20
43
|
// Installed via `npx @doikayt/... new` into a bare dir (or otherwise before a
|
|
@@ -34,8 +57,8 @@ if (projectPkg.name === "@doikayt/typescript-build-config") {
|
|
|
34
57
|
process.exit(0);
|
|
35
58
|
}
|
|
36
59
|
|
|
37
|
-
const srcDir = new URL("top-level", import.meta.url)
|
|
38
|
-
const pipelineDir = new URL("pipeline", import.meta.url)
|
|
60
|
+
const srcDir = fileURLToPath(new URL("top-level", import.meta.url));
|
|
61
|
+
const pipelineDir = fileURLToPath(new URL("pipeline", import.meta.url));
|
|
39
62
|
|
|
40
63
|
// --- Top-level config files: all-or-nothing ---
|
|
41
64
|
|
|
@@ -72,13 +95,9 @@ if (alreadyExist.length > 0) {
|
|
|
72
95
|
// --- Pipeline files: per-file copy/warn/diff ---
|
|
73
96
|
|
|
74
97
|
const pipelineFiles = [
|
|
75
|
-
{ src: "
|
|
98
|
+
{ src: "woodpecker.yml", dest: ".woodpecker.yml" },
|
|
76
99
|
{ src: "changeset-config.json", dest: ".changeset/config.json" },
|
|
77
100
|
{ src: "auto-changeset.sh", dest: "scripts/auto-changeset.sh" },
|
|
78
|
-
{
|
|
79
|
-
src: "verify-npm-token.yml",
|
|
80
|
-
dest: ".github/workflows/verify-npm-token.yml",
|
|
81
|
-
},
|
|
82
101
|
];
|
|
83
102
|
|
|
84
103
|
for (const { src, dest } of pipelineFiles) {
|
|
@@ -111,7 +130,7 @@ for (const { src, dest } of pipelineFiles) {
|
|
|
111
130
|
|
|
112
131
|
// --- Asset files: seeded into docs/assets/, same per-file copy/warn as pipeline ---
|
|
113
132
|
|
|
114
|
-
const assetDir = new URL("../assets/image", import.meta.url)
|
|
133
|
+
const assetDir = fileURLToPath(new URL("../assets/image", import.meta.url));
|
|
115
134
|
|
|
116
135
|
const assetFiles = [
|
|
117
136
|
{ src: "doikayt-logo.png", dest: "docs/assets/doikayt-logo.png" },
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) {{YEAR}} {{HOLDER}}
|
|
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.
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
> before you write any code. Replace them with your own whenever you like —
|
|
10
10
|
> `init` printed the exact paths to delete.
|
|
11
11
|
|
|
12
|
-
Run `npm run update-all-format` to fill the blocks below;
|
|
12
|
+
Run `npm run update-all-format` to fill the blocks below; Codeberg renders the
|
|
13
13
|
Mermaid diagrams inline from the fenced blocks.
|
|
14
14
|
|
|
15
15
|
## Build Pipeline
|
|
@@ -40,3 +40,5 @@ npm test # the seeded vitest test passes
|
|
|
40
40
|
npm run update-all-format # fills the doc blocks above
|
|
41
41
|
git commit -am "feat: initial version" && git push # feat:/fix: cut a release (npm publish if a library)
|
|
42
42
|
```
|
|
43
|
+
|
|
44
|
+
[](https://techforpalestine.org/learn-more)
|
package/src/pipeline/release.yml
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
name: CI / Release
|
|
2
|
-
|
|
3
|
-
permissions:
|
|
4
|
-
contents: write
|
|
5
|
-
|
|
6
|
-
on:
|
|
7
|
-
workflow_dispatch:
|
|
8
|
-
push:
|
|
9
|
-
branches: [main]
|
|
10
|
-
pull_request:
|
|
11
|
-
|
|
12
|
-
jobs:
|
|
13
|
-
ci:
|
|
14
|
-
runs-on: ubuntu-latest
|
|
15
|
-
steps:
|
|
16
|
-
- uses: actions/checkout@v5
|
|
17
|
-
- uses: actions/setup-node@v5
|
|
18
|
-
with:
|
|
19
|
-
node-version: 22
|
|
20
|
-
cache: npm
|
|
21
|
-
- run: npm ci
|
|
22
|
-
- run: npm run ci
|
|
23
|
-
- name: Check Changesets (PR only)
|
|
24
|
-
if: github.event_name == 'pull_request'
|
|
25
|
-
run: npx changeset status
|
|
26
|
-
|
|
27
|
-
release:
|
|
28
|
-
needs: ci
|
|
29
|
-
if: github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
|
|
30
|
-
permissions:
|
|
31
|
-
contents: write
|
|
32
|
-
id-token: write
|
|
33
|
-
concurrency:
|
|
34
|
-
group: release
|
|
35
|
-
cancel-in-progress: false
|
|
36
|
-
runs-on: ubuntu-latest
|
|
37
|
-
steps:
|
|
38
|
-
- uses: actions/checkout@v5
|
|
39
|
-
with:
|
|
40
|
-
fetch-depth: 0
|
|
41
|
-
- uses: actions/setup-node@v5
|
|
42
|
-
with:
|
|
43
|
-
node-version: 22
|
|
44
|
-
registry-url: https://registry.npmjs.org
|
|
45
|
-
cache: npm
|
|
46
|
-
- run: npm ci
|
|
47
|
-
- name: Configure git
|
|
48
|
-
run: |
|
|
49
|
-
git config user.name "github-actions[bot]"
|
|
50
|
-
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
51
|
-
- name: Auto-generate changeset from commits
|
|
52
|
-
run: bash scripts/auto-changeset.sh
|
|
53
|
-
- name: Apply version bumps
|
|
54
|
-
run: npx changeset version
|
|
55
|
-
- name: Commit and push version bumps
|
|
56
|
-
run: |
|
|
57
|
-
git add .
|
|
58
|
-
git diff --staged --quiet && echo "No changesets to release" || \
|
|
59
|
-
(git commit -m "chore: release [skip ci]" && git push)
|
|
60
|
-
- name: Publish
|
|
61
|
-
id: publish
|
|
62
|
-
run: npx changeset publish
|
|
63
|
-
env:
|
|
64
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM }}
|
|
65
|
-
- name: Push release tags
|
|
66
|
-
run: git push --tags
|
|
67
|
-
- name: Post-publish hook (optional)
|
|
68
|
-
if: steps.publish.outcome == 'success'
|
|
69
|
-
run: |
|
|
70
|
-
node -e "process.exit(require('./package.json').scripts?.['post-publish'] ? 0 : 1)" \
|
|
71
|
-
&& npm run post-publish \
|
|
72
|
-
|| echo "No post-publish script — skipping"
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
name: Verify NPM Token
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
workflow_dispatch:
|
|
5
|
-
|
|
6
|
-
jobs:
|
|
7
|
-
verify-token:
|
|
8
|
-
runs-on: ubuntu-latest
|
|
9
|
-
steps:
|
|
10
|
-
- uses: actions/setup-node@v5
|
|
11
|
-
with:
|
|
12
|
-
node-version: 22
|
|
13
|
-
registry-url: https://registry.npmjs.org
|
|
14
|
-
- name: Check npm auth
|
|
15
|
-
run: npm whoami
|
|
16
|
-
env:
|
|
17
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM }}
|