Merge pull request 'docs: OPS checklist for npm publish + Outline scopes' (#6) from docs/ops-outstanding-checklist into main
This commit was merged in pull request #6.
This commit is contained in:
@@ -87,7 +87,7 @@ test('sign-out stays on public host', async ({ page, playkitConfig, timings }) =
|
|||||||
| `interceptNetworkCall` | Spy or mock the next matching page network call |
|
| `interceptNetworkCall` | Spy or mock the next matching page network call |
|
||||||
| `playkit` CLI | `init` scaffold + `smoke` post-deploy gate |
|
| `playkit` CLI | `init` scaffold + `smoke` post-deploy gate |
|
||||||
|
|
||||||
See also `docs/NETWORK.md`, `docs/SELFTEST.md`, `docs/NPM_REGISTRY.md`, `docs/IDEAS.md`, `docs/OUTLINE.md`.
|
See also `docs/NETWORK.md`, `docs/SELFTEST.md`, `docs/NPM_REGISTRY.md`, `docs/OPS.md`, `docs/IDEAS.md`, `docs/OUTLINE.md`.
|
||||||
|
|
||||||
## Network (page traffic)
|
## Network (page traffic)
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -14,7 +14,8 @@ Living plan for making `@levkin/playkit` more useful across Levkin repos.
|
|||||||
|
|
||||||
- [ ] End adoption pause — migrate first extra consumer (`screening` candidate)
|
- [ ] End adoption pause — migrate first extra consumer (`screening` candidate)
|
||||||
- [ ] Evaluate `playwright-exporter` for scheduled synthetics (may supersede bespoke cron wrappers around `playkit smoke`)
|
- [ ] Evaluate `playwright-exporter` for scheduled synthetics (may supersede bespoke cron wrappers around `playkit smoke`)
|
||||||
- [ ] **Wire `NPM_PUBLISH_TOKEN` / `write:package`** — `v0.4.0` git release OK; first npm publish hit E401 (token scope). Soft-fail in CI until fixed.
|
- [ ] **Wire `NPM_PUBLISH_TOKEN` / `write:package`** — `v0.4.0` git release OK; first npm publish hit E401. Soft-fail in CI until fixed. Checklist: `docs/OPS.md`
|
||||||
|
- [ ] **Outline API key scopes** — vault key needs `documents.update` (+ delete/archive). Living page synced to v0.4.0 via UI; script thereafter. Checklist: `docs/OPS.md`
|
||||||
|
|
||||||
## Adoption pause
|
## Adoption pause
|
||||||
|
|
||||||
|
|||||||
+11
-11
@@ -27,13 +27,16 @@ npm i git+https://git.levkin.ca/ilia/playkit.git#v0.4.0
|
|||||||
|
|
||||||
On `vX.Y.Z` tag, `.gitea/workflows/ci.yml` `release` job:
|
On `vX.Y.Z` tag, `.gitea/workflows/ci.yml` `release` job:
|
||||||
|
|
||||||
1. Creates the Gitea Release + attaches `npm pack` tarball (existing)
|
1. Creates the Gitea Release + attaches `npm pack` tarball
|
||||||
2. Runs `npm publish` to `https://git.levkin.ca/api/packages/ilia/npm/`
|
2. Runs `npm publish` to `https://git.levkin.ca/api/packages/ilia/npm/`
|
||||||
using `RELEASE_TOKEN` (needs **`write:package`** in addition to release scopes)
|
using `NPM_PUBLISH_TOKEN` if set, else `RELEASE_TOKEN`
|
||||||
|
(needs **`write:package`**)
|
||||||
|
|
||||||
One-time: edit the `RELEASE_TOKEN` personal access token / app token on Gitea
|
Manual one-shot:
|
||||||
to include package write, or add a dedicated `NPM_PUBLISH_TOKEN` secret and
|
|
||||||
wire it in CI (preferred if you want least privilege).
|
```bash
|
||||||
|
NPM_PUBLISH_TOKEN=… ./scripts/publish-gitea-npm.sh
|
||||||
|
```
|
||||||
|
|
||||||
## Verify
|
## Verify
|
||||||
|
|
||||||
@@ -41,10 +44,7 @@ wire it in CI (preferred if you want least privilege).
|
|||||||
npm view @levkin/playkit versions --registry https://git.levkin.ca/api/packages/ilia/npm/
|
npm view @levkin/playkit versions --registry https://git.levkin.ca/api/packages/ilia/npm/
|
||||||
```
|
```
|
||||||
|
|
||||||
## Outstanding ops
|
## Token setup
|
||||||
|
|
||||||
First `v0.4.0` Gitea Release succeeded; `npm publish` returned **E401** because `RELEASE_TOKEN` lacks `write:package`. Create/refresh a token with package write (or add `NPM_PUBLISH_TOKEN`) and either re-run the release job or publish once by hand:
|
See **`docs/OPS.md`** (Outstanding → Gitea npm publish token). First `v0.4.0`
|
||||||
|
publish hit E401 until a package-scoped token is stored as `NPM_PUBLISH_TOKEN`.
|
||||||
```bash
|
|
||||||
npm publish --registry https://git.levkin.ca/api/packages/ilia/npm/
|
|
||||||
```
|
|
||||||
|
|||||||
+61
@@ -0,0 +1,61 @@
|
|||||||
|
# Ops checklist (playkit)
|
||||||
|
|
||||||
|
Living ops/status after releases. Update when an item closes.
|
||||||
|
|
||||||
|
## Done
|
||||||
|
|
||||||
|
| Item | Status |
|
||||||
|
|------|--------|
|
||||||
|
| Pushgateway + `live-playkit` Grafana board | Applied (`10.0.10.24:9091`) |
|
||||||
|
| Tag release workflow + `RELEASE_TOKEN` | Working (`v0.3.1`, `v0.4.0` Gitea releases) |
|
||||||
|
| Selftest CI | Green (Playwright image pinned to package version) |
|
||||||
|
| Outline **QA & Dev → Playkit** content @ v0.4.0 | Updated 2026-07-15 (browser sync); keep in sync via script once API scopes fixed |
|
||||||
|
| v0.4 CLI / retry presets / registry wiring | Shipped on `main` |
|
||||||
|
|
||||||
|
## Outstanding (needs human UI once)
|
||||||
|
|
||||||
|
### 1. Gitea npm publish token (`write:package`)
|
||||||
|
|
||||||
|
`v0.4.0` **Gitea Release** succeeded; `npm publish` failed with **E401** because
|
||||||
|
Actions `RELEASE_TOKEN` lacks package scopes.
|
||||||
|
|
||||||
|
1. Gitea → **Settings → Applications → Generate New Token**
|
||||||
|
2. Scopes: **`write:package`** (implies read) + keep `write:repository` if this token also cuts releases
|
||||||
|
3. Prefer a dedicated token named `playkit-npm-publish`
|
||||||
|
4. Store as repo Action secret **`NPM_PUBLISH_TOKEN`** on `ilia/playkit`
|
||||||
|
(optional: also `vault_playkit_npm_token` in ansible vault — see ansible `docs/hardening/SECRETS.md`)
|
||||||
|
5. Publish once:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /path/to/playkit # on main @ v0.4.0
|
||||||
|
npm ci && npm run build
|
||||||
|
npm publish --registry https://git.levkin.ca/api/packages/ilia/npm/
|
||||||
|
# or: ./scripts/publish-gitea-npm.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
6. Verify: `npm view @levkin/playkit version --registry https://git.levkin.ca/api/packages/ilia/npm/`
|
||||||
|
|
||||||
|
Until then consumers use the git pin: `#v0.4.0`.
|
||||||
|
|
||||||
|
### 2. Outline API key scopes
|
||||||
|
|
||||||
|
Vault `vault_outline_api_key` can **list/create/info/export** but **not**
|
||||||
|
`documents.update` / `delete` / `archive` (HTTP 403).
|
||||||
|
|
||||||
|
1. Outline → **Settings → API** (API & Access)
|
||||||
|
2. Edit/recreate key with scopes at least:
|
||||||
|
|
||||||
|
```
|
||||||
|
collections.list documents.list documents.info documents.create documents.update documents.delete documents.archive documents.search
|
||||||
|
```
|
||||||
|
|
||||||
|
(Full recommended list: ansible `docs/guides/authentik-apps.md` → Outline API key)
|
||||||
|
|
||||||
|
3. Update vault + `make vault-export-env`
|
||||||
|
4. `python3 scripts/outline-sync-playkit.py`
|
||||||
|
5. Delete leftover **QA & Dev → Playkit sync probe** if still present
|
||||||
|
|
||||||
|
### 3. Adoption soak
|
||||||
|
|
||||||
|
Keep **no new consumer repos** until punimtag e2e + kit CI + metrics stay green
|
||||||
|
for a few days. Then prefer `screening` as the next adopter.
|
||||||
+12
-20
@@ -2,14 +2,17 @@
|
|||||||
|
|
||||||
Canonical prose stays in git (`README.md`, `docs/*`, `ROADMAP.md`).
|
Canonical prose stays in git (`README.md`, `docs/*`, `ROADMAP.md`).
|
||||||
Browsable front door: **Outline** → collection **QA & Dev** → doc **Playkit**
|
Browsable front door: **Outline** → collection **QA & Dev** → doc **Playkit**
|
||||||
(`https://notes.levkin.ca`).
|
(`https://notes.levkin.ca/doc/playkit-3ekU0eghbV`).
|
||||||
|
|
||||||
|
Ops status for this page (scopes, last sync): **`docs/OPS.md`**.
|
||||||
|
|
||||||
## Sync script (preferred)
|
## Sync script (preferred)
|
||||||
|
|
||||||
From this repo, with Outline credentials loaded:
|
From this repo, with Outline credentials loaded:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# from ansible: make vault-export-env && set -a && source .env && set +a
|
# from ansible: make vault-export-env
|
||||||
|
# then export OUTLINE_URL / OUTLINE_API_KEY (safe parse — .env may contain shell-special chars)
|
||||||
python3 scripts/outline-sync-playkit.py
|
python3 scripts/outline-sync-playkit.py
|
||||||
python3 scripts/outline-sync-playkit.py --dry-run
|
python3 scripts/outline-sync-playkit.py --dry-run
|
||||||
```
|
```
|
||||||
@@ -19,8 +22,13 @@ version, install pin, what’s-in-the-box digest, and links to repo docs.
|
|||||||
|
|
||||||
**Required API scopes** (Outline → Settings → API & Access): at least
|
**Required API scopes** (Outline → Settings → API & Access): at least
|
||||||
`collections.list`, `documents.list`, `documents.info`, `documents.create`,
|
`collections.list`, `documents.list`, `documents.info`, `documents.create`,
|
||||||
`documents.update`. Without `documents.update` the script can create a first
|
`documents.update`, and preferably `documents.delete` / `documents.archive`.
|
||||||
doc but cannot refresh an existing Playkit page (HTTP 403).
|
Without `documents.update` the script can create a first doc but cannot refresh
|
||||||
|
an existing Playkit page (HTTP 403).
|
||||||
|
|
||||||
|
As of 2026-07-15 the living page was synced to **v0.4.0** via signed-in UI
|
||||||
|
because the vault API key still lacked `documents.update`. Fix the key scopes,
|
||||||
|
then prefer this script for every future release.
|
||||||
|
|
||||||
## When to update Outline
|
## When to update Outline
|
||||||
|
|
||||||
@@ -33,19 +41,3 @@ changes consumer behavior:
|
|||||||
3. Spot-check in Outline (search “Playkit” under QA & Dev)
|
3. Spot-check in Outline (search “Playkit” under QA & Dev)
|
||||||
4. Optional: `make outline-setup` from ansible only if collections are missing —
|
4. Optional: `make outline-setup` from ansible only if collections are missing —
|
||||||
prefer the sync script for the living Playkit page
|
prefer the sync script for the living Playkit page
|
||||||
|
|
||||||
Paste template (if editing by hand — adjust version):
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
# @levkin/playkit
|
|
||||||
|
|
||||||
Shared Playwright + API e2e kit. **Source of truth is the git repo.**
|
|
||||||
|
|
||||||
- Repo: https://git.levkin.ca/ilia/playkit
|
|
||||||
- Current: vX.Y.Z
|
|
||||||
- Consumers: punimtag (e2e/) — *pause further adoption until soak completes*
|
|
||||||
|
|
||||||
## Quick links
|
|
||||||
- README · CONSUMER.md · NETWORK.md · IDEAS.md · SELFTEST.md · ROADMAP · CHANGELOG
|
|
||||||
- Metrics: dash.levkin.ca → Live — Playkit e2e
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -32,14 +32,15 @@ def load_package_version() -> str:
|
|||||||
|
|
||||||
|
|
||||||
def playkit_markdown(version: str) -> str:
|
def playkit_markdown(version: str) -> str:
|
||||||
return f"""# @levkin/playkit
|
# Do not start with a second H1 — Outline already uses document title "Playkit".
|
||||||
|
return f"""Shared Playwright + API e2e kit for Levkin repos. **Source of truth is the git repo** — this page is the browsable front door.
|
||||||
Shared Playwright + API e2e kit for Levkin repos. **Source of truth is the git repo** — this page is the browsable front door.
|
|
||||||
|
|
||||||
- **Repo:** https://git.levkin.ca/ilia/playkit
|
- **Repo:** https://git.levkin.ca/ilia/playkit
|
||||||
- **Current:** v{version}
|
- **Current:** v{version}
|
||||||
- **Consumers:** punimtag (`e2e/`) — *pause further adoption until soak completes*
|
- **Consumers:** punimtag (`e2e/`) — *pause further adoption until soak completes*
|
||||||
- **Install (git pin):** `npm i git+https://git.levkin.ca/ilia/playkit.git#v{version}`
|
- **Install (npm):** `npm i @levkin/playkit@{version}` — see docs/NPM_REGISTRY.md
|
||||||
|
- **Fallback (git pin):** `npm i git+https://git.levkin.ca/ilia/playkit.git#v{version}`
|
||||||
|
- **CLI:** `npx @levkin/playkit init` · `playkit smoke`
|
||||||
|
|
||||||
## What's in the box
|
## What's in the box
|
||||||
|
|
||||||
@@ -49,6 +50,8 @@ Shared Playwright + API e2e kit for Levkin repos. **Source of truth is the git r
|
|||||||
- Mail: `createMailInbox()` (Mailpit default, Mailtrap optional)
|
- Mail: `createMailInbox()` (Mailpit default, Mailtrap optional)
|
||||||
- Auth helpers: `saveStorageState` / `storageStateUse`, `playkitFailureArtifacts()`
|
- Auth helpers: `saveStorageState` / `storageStateUse`, `playkitFailureArtifacts()`
|
||||||
- Metrics: `TimingCollector` → Prometheus Pushgateway → Grafana **Live — Playkit e2e**
|
- Metrics: `TimingCollector` → Prometheus Pushgateway → Grafana **Live — Playkit e2e**
|
||||||
|
- Retry presets: `PLAYKIT_RETRY_PRESET=strictCi|flakyNetwork|default`
|
||||||
|
- Kit selftest CI against a fake site — docs/SELFTEST.md
|
||||||
|
|
||||||
## Quick links (in-repo)
|
## Quick links (in-repo)
|
||||||
|
|
||||||
@@ -57,10 +60,12 @@ Shared Playwright + API e2e kit for Levkin repos. **Source of truth is the git r
|
|||||||
| `README.md` | Install, env vars, release steps |
|
| `README.md` | Install, env vars, release steps |
|
||||||
| `docs/CONSUMER.md` | How to wire a consumer `e2e/` |
|
| `docs/CONSUMER.md` | How to wire a consumer `e2e/` |
|
||||||
| `docs/NETWORK.md` | Page traffic spy / error monitor |
|
| `docs/NETWORK.md` | Page traffic spy / error monitor |
|
||||||
|
| `docs/NPM_REGISTRY.md` | Gitea npm install / publish |
|
||||||
|
| `docs/OPS.md` | Ops soak + outstanding UI one-timers |
|
||||||
| `docs/IDEAS.md` | OSS-borrowed backlog |
|
| `docs/IDEAS.md` | OSS-borrowed backlog |
|
||||||
| `docs/OUTLINE.md` | When / how to re-sync this page |
|
| `docs/OUTLINE.md` | When / how to re-sync this page |
|
||||||
| `docs/SELFTEST.md` | Kit CI fake-site self-test |
|
| `docs/SELFTEST.md` | Kit CI fake-site self-test |
|
||||||
| `ROADMAP.md` | v0.4+ plan |
|
| `ROADMAP.md` | Living plan |
|
||||||
| `CHANGELOG.md` | Per-version notes |
|
| `CHANGELOG.md` | Per-version notes |
|
||||||
|
|
||||||
## Metrics
|
## Metrics
|
||||||
@@ -71,9 +76,10 @@ Shared Playwright + API e2e kit for Levkin repos. **Source of truth is the git r
|
|||||||
|
|
||||||
## Release checklist (operators)
|
## Release checklist (operators)
|
||||||
|
|
||||||
1. Tag `vX.Y.Z` (must match `package.json` + CHANGELOG section) → Gitea `release` job uses `RELEASE_TOKEN`
|
1. Tag `vX.Y.Z` (must match `package.json` + CHANGELOG section) → Gitea `release` job
|
||||||
2. Re-run this script: `python3 scripts/outline-sync-playkit.py`
|
2. Ensure `NPM_PUBLISH_TOKEN` has `write:package` (docs/OPS.md) so registry publish succeeds
|
||||||
3. Confirm Grafana board + Pushgateway scrape after `make deploy-observability` (ansible)
|
3. Re-run this script: `python3 scripts/outline-sync-playkit.py`
|
||||||
|
4. Confirm Grafana board + Pushgateway scrape (`make deploy-observability` in ansible)
|
||||||
|
|
||||||
_Last synced by `scripts/outline-sync-playkit.py` for v{version}._
|
_Last synced by `scripts/outline-sync-playkit.py` for v{version}._
|
||||||
"""
|
"""
|
||||||
|
|||||||
Executable
+26
@@ -0,0 +1,26 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Publish @levkin/playkit to the Gitea npm registry.
|
||||||
|
# Usage:
|
||||||
|
# NPM_PUBLISH_TOKEN=… ./scripts/publish-gitea-npm.sh
|
||||||
|
# # or export from vault: vault_playkit_npm_token / RELEASE_TOKEN with write:package
|
||||||
|
set -euo pipefail
|
||||||
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
|
cd "$ROOT"
|
||||||
|
|
||||||
|
TOKEN="${NPM_PUBLISH_TOKEN:-${PLAYKIT_NPM_TOKEN:-${RELEASE_TOKEN:-}}}"
|
||||||
|
if [[ -z "${TOKEN}" ]]; then
|
||||||
|
echo "Set NPM_PUBLISH_TOKEN (Gitea token with write:package). See docs/OPS.md" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
REG="https://git.levkin.ca/api/packages/ilia/npm/"
|
||||||
|
npm run build
|
||||||
|
TMP="$(mktemp)"
|
||||||
|
cat >"$TMP" <<EOF
|
||||||
|
@levkin:registry=${REG}
|
||||||
|
//git.levkin.ca/api/packages/ilia/npm/:_authToken=${TOKEN}
|
||||||
|
EOF
|
||||||
|
echo "Publishing $(node -p "require('./package.json').version") to ${REG}"
|
||||||
|
npm publish --userconfig "$TMP" --access restricted
|
||||||
|
rm -f "$TMP"
|
||||||
|
npm view @levkin/playkit version --registry "$REG" || true
|
||||||
Reference in New Issue
Block a user