@geonosis/release 1.1.0
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/LICENSE +202 -0
- package/README.md +233 -0
- package/bin/geonosis-release.mjs +27 -0
- package/dist/chunk-2JLVQK7Y.js +941 -0
- package/dist/index.d.ts +252 -0
- package/dist/index.js +62 -0
- package/dist/release-cli.js +160 -0
- package/dist/stub-runner.js +31 -0
- package/package.json +51 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
|
|
2
|
+
Apache License
|
|
3
|
+
Version 2.0, January 2004
|
|
4
|
+
http://www.apache.org/licenses/
|
|
5
|
+
|
|
6
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
7
|
+
|
|
8
|
+
1. Definitions.
|
|
9
|
+
|
|
10
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
11
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
12
|
+
|
|
13
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
14
|
+
the copyright owner that is granting the License.
|
|
15
|
+
|
|
16
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
17
|
+
other entities that control, are controlled by, or are under common
|
|
18
|
+
control with that entity. For the purposes of this definition,
|
|
19
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
20
|
+
direction or management of such entity, whether by contract or
|
|
21
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
22
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
23
|
+
|
|
24
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
25
|
+
exercising permissions granted by this License.
|
|
26
|
+
|
|
27
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
28
|
+
including but not limited to software source code, documentation
|
|
29
|
+
source, and configuration files.
|
|
30
|
+
|
|
31
|
+
"Object" form shall mean any form resulting from mechanical
|
|
32
|
+
transformation or translation of a Source form, including but
|
|
33
|
+
not limited to compiled object code, generated documentation,
|
|
34
|
+
and conversions to other media types.
|
|
35
|
+
|
|
36
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
37
|
+
Object form, made available under the License, as indicated by a
|
|
38
|
+
copyright notice that is included in or attached to the work
|
|
39
|
+
(an example is provided in the Appendix below).
|
|
40
|
+
|
|
41
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
42
|
+
form, that is based on (or derived from) the Work and for which the
|
|
43
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
44
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
45
|
+
of this License, Derivative Works shall not include works that remain
|
|
46
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
47
|
+
the Work and Derivative Works thereof.
|
|
48
|
+
|
|
49
|
+
"Contribution" shall mean any work of authorship, including
|
|
50
|
+
the original version of the Work and any modifications or additions
|
|
51
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
52
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
53
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
54
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
55
|
+
means any form of electronic, verbal, or written communication sent
|
|
56
|
+
to the Licensor or its representatives, including but not limited to
|
|
57
|
+
communication on electronic mailing lists, source code control systems,
|
|
58
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
59
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
60
|
+
excluding communication that is conspicuously marked or otherwise
|
|
61
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
62
|
+
|
|
63
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
64
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
65
|
+
subsequently incorporated within the Work.
|
|
66
|
+
|
|
67
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
68
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
69
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
70
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
71
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
72
|
+
Work and such Derivative Works in Source or Object form.
|
|
73
|
+
|
|
74
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
75
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
76
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
77
|
+
(except as stated in this section) patent license to make, have made,
|
|
78
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
79
|
+
where such license applies only to those patent claims licensable
|
|
80
|
+
by such Contributor that are necessarily infringed by their
|
|
81
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
82
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
83
|
+
institute patent litigation against any entity (including a
|
|
84
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
85
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
86
|
+
or contributory patent infringement, then any patent licenses
|
|
87
|
+
granted to You under this License for that Work shall terminate
|
|
88
|
+
as of the date such litigation is filed.
|
|
89
|
+
|
|
90
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
91
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
92
|
+
modifications, and in Source or Object form, provided that You
|
|
93
|
+
meet the following conditions:
|
|
94
|
+
|
|
95
|
+
(a) You must give any other recipients of the Work or
|
|
96
|
+
Derivative Works a copy of this License; and
|
|
97
|
+
|
|
98
|
+
(b) You must cause any modified files to carry prominent notices
|
|
99
|
+
stating that You changed the files; and
|
|
100
|
+
|
|
101
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
102
|
+
that You distribute, all copyright, patent, trademark, and
|
|
103
|
+
attribution notices from the Source form of the Work,
|
|
104
|
+
excluding those notices that do not pertain to any part of
|
|
105
|
+
the Derivative Works; and
|
|
106
|
+
|
|
107
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
108
|
+
distribution, then any Derivative Works that You distribute must
|
|
109
|
+
include a readable copy of the attribution notices contained
|
|
110
|
+
within such NOTICE file, excluding those notices that do not
|
|
111
|
+
pertain to any part of the Derivative Works, in at least one
|
|
112
|
+
of the following places: within a NOTICE text file distributed
|
|
113
|
+
as part of the Derivative Works; within the Source form or
|
|
114
|
+
documentation, if provided along with the Derivative Works; or,
|
|
115
|
+
within a display generated by the Derivative Works, if and
|
|
116
|
+
wherever such third-party notices normally appear. The contents
|
|
117
|
+
of the NOTICE file are for informational purposes only and
|
|
118
|
+
do not modify the License. You may add Your own attribution
|
|
119
|
+
notices within Derivative Works that You distribute, alongside
|
|
120
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
121
|
+
that such additional attribution notices cannot be construed
|
|
122
|
+
as modifying the License.
|
|
123
|
+
|
|
124
|
+
You may add Your own copyright statement to Your modifications and
|
|
125
|
+
may provide additional or different license terms and conditions
|
|
126
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
127
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
128
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
129
|
+
the conditions stated in this License.
|
|
130
|
+
|
|
131
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
132
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
133
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
134
|
+
this License, without any additional terms or conditions.
|
|
135
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
136
|
+
the terms of any separate license agreement you may have executed
|
|
137
|
+
with Licensor regarding such Contributions.
|
|
138
|
+
|
|
139
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
140
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
141
|
+
except as required for reasonable and customary use in describing the
|
|
142
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
143
|
+
|
|
144
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
145
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
146
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
147
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
148
|
+
implied, including, without limitation, any warranties or conditions
|
|
149
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
150
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
151
|
+
appropriateness of using or redistributing the Work and assume any
|
|
152
|
+
risks associated with Your exercise of permissions under this License.
|
|
153
|
+
|
|
154
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
155
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
156
|
+
unless required by applicable law (such as deliberate and grossly
|
|
157
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
158
|
+
liable to You for damages, including any direct, indirect, special,
|
|
159
|
+
incidental, or consequential damages of any character arising as a
|
|
160
|
+
result of this License or out of the use or inability to use the
|
|
161
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
162
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
163
|
+
other commercial damages or losses), even if such Contributor
|
|
164
|
+
has been advised of the possibility of such damages.
|
|
165
|
+
|
|
166
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
167
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
168
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
169
|
+
or other liability obligations and/or rights consistent with this
|
|
170
|
+
License. However, in accepting such obligations, You may act only
|
|
171
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
172
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
173
|
+
defend, and hold each Contributor harmless for any liability
|
|
174
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
175
|
+
of your accepting any such warranty or additional liability.
|
|
176
|
+
|
|
177
|
+
END OF TERMS AND CONDITIONS
|
|
178
|
+
|
|
179
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
180
|
+
|
|
181
|
+
To apply the Apache License to your work, attach the following
|
|
182
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
183
|
+
replaced with your own identifying information. (Don't include
|
|
184
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
185
|
+
comment syntax for the file format. We also recommend that a
|
|
186
|
+
file or class name and description of purpose be included on the
|
|
187
|
+
same "printed page" as the copyright notice for easier
|
|
188
|
+
identification within third-party archives.
|
|
189
|
+
|
|
190
|
+
Copyright [yyyy] [name of copyright owner]
|
|
191
|
+
|
|
192
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
193
|
+
you may not use this file except in compliance with the License.
|
|
194
|
+
You may obtain a copy of the License at
|
|
195
|
+
|
|
196
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
197
|
+
|
|
198
|
+
Unless required by applicable law or agreed to in writing, software
|
|
199
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
200
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
201
|
+
See the License for the specific language governing permissions and
|
|
202
|
+
limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# @geonosis/release
|
|
2
|
+
|
|
3
|
+
The release contract with its proofs.
|
|
4
|
+
|
|
5
|
+
A release proves its **code** before serving it. Its **schema** serves immediately, to 100 % of
|
|
6
|
+
traffic, while the previous version is still running — and no rollback undoes it. That sentence is
|
|
7
|
+
the whole reason this package exists, and it is the sentence one consumer's adversarial review
|
|
8
|
+
found its own runbook had inverted.
|
|
9
|
+
|
|
10
|
+
Nothing here invokes a platform. There is no wrangler, no Railway, no `psql`. Which workers exist,
|
|
11
|
+
in which order they promote, what a smoke asserts and how a version is uploaded all stay with the
|
|
12
|
+
consumer; this package holds the contract, the refusals and the proofs.
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
geonosis-release migrations --since <ref> [--dialect <name>] [--root <dir>] [--json]
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Exit **0** clean · **1** refusals · **2** the run could not be made.
|
|
19
|
+
|
|
20
|
+
## `migrations` — expand-only, enforced
|
|
21
|
+
|
|
22
|
+
For every file the diff ADDED under a directory `geonosis.json` names, in the dialect it names it
|
|
23
|
+
in. A migration that already existed at the base already ran; the only SQL a release gate has an
|
|
24
|
+
opinion about is the SQL it is proposing to run now.
|
|
25
|
+
|
|
26
|
+
```jsonc
|
|
27
|
+
{
|
|
28
|
+
"release": {
|
|
29
|
+
"migrations": [
|
|
30
|
+
{ "dir": "packages/db/migrations", "dialect": "sqlite" },
|
|
31
|
+
{
|
|
32
|
+
"dir": "packages/db/migrations-tenant",
|
|
33
|
+
"dialect": "postgres",
|
|
34
|
+
"squawk": { "exclude": ["prefer-robust-stmts", "prefer-bigint-over-int"] }
|
|
35
|
+
},
|
|
36
|
+
{ "dir": "packages/plugins", "dialect": "mikro-orm-ts", "phases": ["up"] }
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Every field is an option and every default is empty. A repo that has named no directory gets exit
|
|
43
|
+
2 and one line saying so — never a green run over nothing.
|
|
44
|
+
|
|
45
|
+
### The dialects
|
|
46
|
+
|
|
47
|
+
| `dialect` | Files | What runs |
|
|
48
|
+
|---|---|---|
|
|
49
|
+
| `sqlite` | `*.sql` under `dir` | the narrowing-verb check. D1 is not Postgres, and squawk cannot parse `CREATE TABLE \`account\`` at all |
|
|
50
|
+
| `postgres` | `*.sql` under `dir` | `squawk-cli`, its exit code and output surfaced verbatim — it knows six things a verb list does not, three of them ways to stall a live database |
|
|
51
|
+
| `mikro-orm-ts` | `*.ts` under `dir` | the SQL extracted from `addSql(…)` inside the phases, then BOTH the verb check and squawk |
|
|
52
|
+
|
|
53
|
+
### The five narrowing verbs
|
|
54
|
+
|
|
55
|
+
`DROP TABLE` · `DROP COLUMN` · `RENAME` · `ALTER COLUMN … TYPE` · `SET NOT NULL`.
|
|
56
|
+
|
|
57
|
+
Each removes something a version that is still serving — or one a rollback could put back — may
|
|
58
|
+
still be reading or writing. A refusal prints `path: verb (line)`.
|
|
59
|
+
|
|
60
|
+
String literals are blanked before the search, because a verb inside one is data:
|
|
61
|
+
`insert into audit values ('drop table orders')` narrows nothing. Comments are NOT blanked, because
|
|
62
|
+
that is where the marker lives.
|
|
63
|
+
|
|
64
|
+
### The marker
|
|
65
|
+
|
|
66
|
+
```sql
|
|
67
|
+
-- contract-migration: <what expanded it, and why nothing reads it any more> since:<ref>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`//` in a TypeScript migration. It excuses a narrowing only when **all** of the following hold, and
|
|
71
|
+
names which one failed when they do not:
|
|
72
|
+
|
|
73
|
+
| | |
|
|
74
|
+
|---|---|
|
|
75
|
+
| a reason | a marker with nothing after the colon is a comment. `\s` swallows a newline and adopts the next line as the reason, which is how a bare marker once excused the statement under it |
|
|
76
|
+
| a `since:<ref>` | an expand nobody can date excuses nothing |
|
|
77
|
+
| `git merge-base --is-ancestor <ref> <since>` | **the across-releases rule.** A contract is safe only once the version that still read the old shape has drained, so the ref that expanded must already be in history at this release's base. A marker naming a commit inside this very diff says "the code that stopped needing this column shipped" about code that has not shipped |
|
|
78
|
+
|
|
79
|
+
A marker the gate cannot believe excuses nothing, and the narrowing it was written over is still
|
|
80
|
+
reported — otherwise a typo in a ref would read as "your migration is fine".
|
|
81
|
+
|
|
82
|
+
The marker is an argument about **drain**. It says nothing about locks or timeouts, so squawk's
|
|
83
|
+
findings stand on an excused file: a repo that has decided about `require-lock-timeout` says so once
|
|
84
|
+
in `squawk.exclude`, rather than by writing a sentence into every migration.
|
|
85
|
+
|
|
86
|
+
### `phases`
|
|
87
|
+
|
|
88
|
+
Default `["up"]`. In the corpus this was built from, `down()` holds the `drop table` in every single
|
|
89
|
+
migration file — reading it would refuse every migration in the repo, for SQL a release never runs.
|
|
90
|
+
|
|
91
|
+
### The `addSql` shapes the reader handles
|
|
92
|
+
|
|
93
|
+
A template literal, a quoted string, either opening on the line after the call, a literal that
|
|
94
|
+
itself spans lines, and adjacent literals joined by `+`.
|
|
95
|
+
|
|
96
|
+
An **identifier** argument (`this.addSql(dropOperationChecks)`) and a **template interpolation**
|
|
97
|
+
are refused BY NAME with exit 2. Resolving either is name resolution — a TypeScript parser — and
|
|
98
|
+
this package will not grow one. A migration nobody could read is not a migration that passed.
|
|
99
|
+
|
|
100
|
+
### squawk
|
|
101
|
+
|
|
102
|
+
`squawk-cli` is a pinned dependency of this package, spawned from its own `node_modules/.bin`. Its
|
|
103
|
+
bin is called `squawk`, and `squawk` on a public registry is an unrelated package that exits 0 on
|
|
104
|
+
anything — a gate that passes because it linted nothing. Nothing here asks a resolver.
|
|
105
|
+
|
|
106
|
+
Exit 0 is clean and exit 1 is findings. **Anything else is exit 2**, one line naming it: a linter
|
|
107
|
+
that could not start has not measured, and a gate that cannot measure has not passed.
|
|
108
|
+
|
|
109
|
+
## `plan` — the contract as data
|
|
110
|
+
|
|
111
|
+
```jsonc
|
|
112
|
+
{
|
|
113
|
+
"release": {
|
|
114
|
+
"steps": ["upload", "park", "prove", "promote"],
|
|
115
|
+
"proof": { "mustAssertVersion": true },
|
|
116
|
+
"workers": ["api", "edge", "web"]
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
`upload` moves no traffic. `park` puts the new version into the deployment at 0 %, which is the only
|
|
122
|
+
thing that makes it reachable by an override at all. `prove` reaches it and asks it who it is.
|
|
123
|
+
`promote` swaps the pointer. Those four, in that order, and no other — a promote before its proof
|
|
124
|
+
serves code nothing answered for, and a park before an upload is nothing.
|
|
125
|
+
|
|
126
|
+
`proof.mustAssertVersion` is on unless a repo writes `false`, and writing `false` is refused unless
|
|
127
|
+
the run also carries `--i-accept-an-unproven-smoke`, which prints why it matters.
|
|
128
|
+
|
|
129
|
+
## `prove` — the runner protocol
|
|
130
|
+
|
|
131
|
+
The runner is a **consumer executable** speaking JSON on stdio, one request per line and one reply
|
|
132
|
+
per line. This is the whole seam: every platform call lives on the far side of it, in the repo that
|
|
133
|
+
has the credentials and knows which workers exist. Nothing on this side has heard of Cloudflare.
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
→ {"step":"upload"} ← {"versionId":"…"}
|
|
137
|
+
→ {"step":"smoke","versionId":"…"} ← {"ok":true,"answeredVersionId":"…"}
|
|
138
|
+
→ {"step":"promote","versionId":"…"} ← {"ok":true} (may carry "promotedVersionId")
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
The gate REFUSES, and the refusal means the next request is never written:
|
|
142
|
+
|
|
143
|
+
| | |
|
|
144
|
+
|---|---|
|
|
145
|
+
| `answeredVersionId !== versionId` | the override did not apply and the smoke certified the version it was replacing |
|
|
146
|
+
| no `answeredVersionId` at all | a smoke that cannot say who answered has proved nothing |
|
|
147
|
+
| `ok: false` | the smoke failed |
|
|
148
|
+
| `promotedVersionId !== versionId` | a promote went to a version nothing proved |
|
|
149
|
+
|
|
150
|
+
With **no** `--runner`, the package plants each of those into its own stub runner and requires every
|
|
151
|
+
one to be caught — and requires the honest runner to pass, because a gate that refused everything
|
|
152
|
+
would be as useless as one that refused nothing.
|
|
153
|
+
|
|
154
|
+
A runner that never answers is exit 2 inside the time it was given: a job that hangs until CI's own
|
|
155
|
+
timeout kills it leaves no line anybody reads.
|
|
156
|
+
|
|
157
|
+
## What this package does not cover
|
|
158
|
+
|
|
159
|
+
Overrides never reach **Durable Objects**. Each DO instance is assigned a version by the deployment
|
|
160
|
+
percentages, so at 0 % every workflow instance, queue consumer and cron runs the OLD code. `prove`
|
|
161
|
+
proves the stateless fetch path and claims nothing more; the durable path's proof is a test suite,
|
|
162
|
+
a drain discipline, and post-promotion observation.
|
|
163
|
+
|
|
164
|
+
## `deployed --check` — declared ≠ deployed
|
|
165
|
+
|
|
166
|
+
`versions upload` applies **no triggers**. A cron or a route edited in a wrangler config is
|
|
167
|
+
therefore silently ignored in production for ever, with a green pipeline. And `wrangler secret put`
|
|
168
|
+
creates AND deploys a version immediately, outside the gate entirely — which is why the versioned
|
|
169
|
+
form is `wrangler versions secret put`, and why secret names are an option here rather than a key
|
|
170
|
+
read out of a config that never holds them.
|
|
171
|
+
|
|
172
|
+
`.geonosis/deployed.json` is what the consumer's pipeline writes **after promote**:
|
|
173
|
+
|
|
174
|
+
```json
|
|
175
|
+
{
|
|
176
|
+
"at": "2026-08-30T12:00:00.000Z",
|
|
177
|
+
"versions": { "api": "…" },
|
|
178
|
+
"triggers": { "crons": ["0 4 * * *"], "routes": ["api.example.test"] },
|
|
179
|
+
"secrets": ["AUTH_SECRET"],
|
|
180
|
+
"bindings": ["DB", "AUTH_KV"]
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
```jsonc
|
|
185
|
+
{
|
|
186
|
+
"release": {
|
|
187
|
+
"wrangler": ["apps/api/wrangler.jsonc", "apps/web/wrangler.toml"],
|
|
188
|
+
"wranglerEnv": "production",
|
|
189
|
+
"secrets": ["AUTH_SECRET", "EDGE_SECRET"]
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Drift in either direction is exit 1, listing `declared but not deployed` and
|
|
195
|
+
`deployed but not declared` per kind. **The file being absent is exit 2**, not a pass: nothing there
|
|
196
|
+
says what is deployed.
|
|
197
|
+
|
|
198
|
+
`wranglerEnv` selects an `env.<name>` block, because named environments inherit nothing per
|
|
199
|
+
binding — every block repeats what it needs, and reading the top level instead would report a
|
|
200
|
+
deployment's own crons as drift.
|
|
201
|
+
|
|
202
|
+
`.json` and `.jsonc` are read fully (comments and trailing commas included). `.toml` is read for
|
|
203
|
+
exactly the keys this check needs — `[triggers] crons`, `routes`, and the binding lists — because
|
|
204
|
+
`wrangler.toml` is wrangler's default and refusing it outright would make the command unusable;
|
|
205
|
+
it is not a TOML implementation.
|
|
206
|
+
|
|
207
|
+
`@geonosis/doctor` asks the same question of the same file as its `deployed` line. It reads the
|
|
208
|
+
file; it does not import this package. A repo can install either one alone.
|
|
209
|
+
|
|
210
|
+
## What stays with the consumer
|
|
211
|
+
|
|
212
|
+
Everything that touches a platform, and everything that is a fact about one repo:
|
|
213
|
+
|
|
214
|
+
| | |
|
|
215
|
+
|---|---|
|
|
216
|
+
| which workers exist, and in what order they promote | callee first, and the gate never learns their names |
|
|
217
|
+
| how a version is uploaded, parked, overridden to, promoted | the runner, on the far side of the JSON protocol |
|
|
218
|
+
| what the smoke asserts | a positive marker, a status, a signed-in render — the gate only requires that it says which version answered |
|
|
219
|
+
| canary percentages, version affinity, OpenNext | not the gate's subject |
|
|
220
|
+
| writing `.geonosis/deployed.json` after promote | the pipeline knows what it applied; this reads what it wrote |
|
|
221
|
+
| which squawk rules a repo has decided about | `squawk.exclude`, once, in config |
|
|
222
|
+
|
|
223
|
+
## Exit codes
|
|
224
|
+
|
|
225
|
+
| | |
|
|
226
|
+
|---|---|
|
|
227
|
+
| **0** | clean |
|
|
228
|
+
| **1** | refused — a narrowing, a marker nobody can believe, a smoke that certified the wrong version, drift |
|
|
229
|
+
| **2** | the run could not be made: an option that was never configured, a shape the reader cannot read, a linter that would not start, a runner that never answered, no `.geonosis/deployed.json` |
|
|
230
|
+
|
|
231
|
+
A gate that cannot measure has not passed. Nothing here answers 0 by default.
|
|
232
|
+
|
|
233
|
+
Apache-2.0.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Committed, so `pnpm install` can link the bin on a fresh clone — before `pnpm build` has
|
|
3
|
+
// produced dist/. A bin that only exists after a build is a bin that is missing when you need it.
|
|
4
|
+
//
|
|
5
|
+
// In the repo, `src/` sits beside `dist/`, and a dist older than src answered for a fix it did not
|
|
6
|
+
// carry once (#62). The published package ships no src, so there the check is skipped.
|
|
7
|
+
import { existsSync, readdirSync, statSync } from 'node:fs'
|
|
8
|
+
import { dirname, join } from 'node:path'
|
|
9
|
+
import { fileURLToPath } from 'node:url'
|
|
10
|
+
|
|
11
|
+
const here = dirname(fileURLToPath(import.meta.url))
|
|
12
|
+
const newest = (dir) =>
|
|
13
|
+
existsSync(dir)
|
|
14
|
+
? readdirSync(dir, { withFileTypes: true }).reduce((most, entry) => {
|
|
15
|
+
const at = join(dir, entry.name)
|
|
16
|
+
return Math.max(most, entry.isDirectory() ? newest(at) : statSync(at).mtimeMs)
|
|
17
|
+
}, 0)
|
|
18
|
+
: 0
|
|
19
|
+
const src = join(here, '..', 'src')
|
|
20
|
+
if (existsSync(src) && newest(src) > newest(join(here, '..', 'dist'))) {
|
|
21
|
+
process.stderr.write(
|
|
22
|
+
'geonosis-release: dist is older than src — run pnpm build before trusting this bin.\n',
|
|
23
|
+
)
|
|
24
|
+
process.exit(2)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
await import('../dist/release-cli.js')
|