1 Commits

Author SHA1 Message Date
Benjamin Diedrichsen fcc181700e test release nopy-alpha5
Release / release (push) Successful in 1m0s
2026-07-27 17:07:18 +02:00
37 changed files with 66 additions and 66 deletions
+2 -2
View File
@@ -1,7 +1,7 @@
# Every commit that lands on `main` publishes a prerelease of both packages to
# the Gitea npm registry under the `main` dist-tag:
#
# pnpm add @bitstack/nopy@main
# pnpm add @bitsquare/nopy@main
#
# The verification gate runs here rather than in ci.yml so a snapshot can never
# be published from a red `main`. Versions are derived, never committed —
@@ -87,7 +87,7 @@ jobs:
fi
install -m 600 /dev/null "$NPMRC"
{
printf '@bitstack:registry=%s\n' "$REGISTRY"
printf '@bitsquare:registry=%s\n' "$REGISTRY"
printf '//%s:_authToken=%s\n' "${REGISTRY#*://}" "$REGISTRY_TOKEN"
} >> "$NPMRC"
+3 -3
View File
@@ -9,7 +9,7 @@
# of `latest`.
#
# Required secrets:
# NPM_TOKEN npmjs granular token, read-and-write on @bitstack/*, 2FA
# NPM_TOKEN npmjs granular token, read-and-write on @bitsquare/*, 2FA
# not required. Expires after 90 days — rotate it.
# MYGITEA_NPM_TOKEN Gitea PAT with write:package. The automatic GITEA_TOKEN is
# a repo-scoped task token and the package registry rejects it.
@@ -131,7 +131,7 @@ jobs:
set -euo pipefail
install -m 600 /dev/null "$NPMRC"
{
printf '@bitstack:registry=%s\n' "$GITEA_REGISTRY"
printf '@bitsquare:registry=%s\n' "$GITEA_REGISTRY"
printf '//%s:_authToken=%s\n' "${GITEA_REGISTRY#*://}" "$GITEA_REGISTRY_TOKEN"
} >> "$NPMRC"
export npm_config_userconfig="$NPMRC"
@@ -152,7 +152,7 @@ jobs:
set -euo pipefail
install -m 600 /dev/null "$NPMRC"
{
printf '@bitstack:registry=%s\n' "$NPMJS_REGISTRY"
printf '@bitsquare:registry=%s\n' "$NPMJS_REGISTRY"
printf '//%s:_authToken=%s\n' "${NPMJS_REGISTRY#*://}" "$NPMJS_TOKEN"
} >> "$NPMRC"
export npm_config_userconfig="$NPMRC"
+19 -19
View File
@@ -23,8 +23,8 @@ shipped. If you only want to cut a release, jump to
| Directory | Package | Binary |
| ----------------- | ------------------ | -------- |
| `packages/nopy` | `@bitstack/nopy` | `nopy` |
| `packages/keyman` | `@bitstack/keyman` | `keyman` |
| `packages/nopy` | `@bitsquare/nopy` | `nopy` |
| `packages/keyman` | `@bitsquare/keyman` | `keyman` |
Both are ESM, both declare `engines.node >= 22`, and both expose a single
executable through `bin`, so `npm install -g` puts `nopy` / `keyman` on the
@@ -155,7 +155,7 @@ semver even when the abbreviated sha happens to be all digits. The run number is
monotonic, so every push produces a version that has never existed before.
```sh
pnpm add @bitstack/nopy@main
pnpm add @bitsquare/nopy@main
```
Snapshots never reach npmjs and never move `latest`. The version is written into
@@ -175,7 +175,7 @@ edit is discarded with the workspace and is never committed.
```
The tag name is `<directory>-v<version>` — the directory under `packages/`, not
the npm name. `nopy-v1.2.0`, not `@bitstack/nopy-v1.2.0`.
the npm name. `nopy-v1.2.0`, not `@bitsquare/nopy-v1.2.0`.
The tag decides **which** package ships; `package.json` decides the **version**.
The workflow re-reads the manifest and refuses to continue if the two disagree:
@@ -193,7 +193,7 @@ a coincidence, not a requirement.
What a successful run leaves behind:
- `@bitstack/<pkg>@<version>` on the Gitea registry
- `@bitsquare/<pkg>@<version>` on the Gitea registry
- the same tarball on npmjs, public, under `latest` or `next`
- a Gitea release on the tag, with notes and an install snippet
- a step summary with both install commands
@@ -228,7 +228,7 @@ organisation to share across repos.
| Secret | Required | Purpose |
| ----------------- | -------- | --------------------------------------------------------- |
| `NPM_TOKEN` | yes | npmjs granular token, read-and-write on `@bitstack/*` |
| `NPM_TOKEN` | yes | npmjs granular token, read-and-write on `@bitsquare/*` |
| `MYGITEA_NPM_TOKEN` | yes | Gitea PAT with `write:package` |
`GITEA_TOKEN` is injected into every run by Gitea itself, and the workflows fall
@@ -241,12 +241,12 @@ practice. Create it under **Settings → Applications → Access Tokens** with t
`package` scope set to read-and-write; its owner needs package-write on the
`BitSquare` organisation, since the registry path is org-owned.
For npmjs, create a **granular access token** scoped to `@bitstack/*` with
For npmjs, create a **granular access token** scoped to `@bitsquare/*` with
read-and-write permission, and set 2FA to not-required so it works
unattended. npm warns against that combination and points at Trusted Publishing
instead — but Trusted Publishing federates only GitHub Actions and GitLab CI/CD
over OIDC, and Gitea is not a provider it accepts. A token is the only route
from this runner. Scoping the token to `@bitstack/*` is what keeps the exposure
from this runner. Scoping the token to `@bitsquare/*` is what keeps the exposure
small: a leak lets someone publish to that scope, not touch the account.
> npm caps granular token lifetime at 90 days, so `NPM_TOKEN` needs rotating
@@ -264,7 +264,7 @@ small: a leak lets someone publish to that scope, not touch the account.
## Registry authentication in the workflows
`release.yml` has to talk to two different registries about the same `@bitstack`
`release.yml` has to talk to two different registries about the same `@bitsquare`
scope inside one job. It does that without ever mutating `~/.npmrc`:
- each publish step writes its own credentials file, created with
@@ -284,20 +284,20 @@ file written into the workspace can never be committed by accident.
From npmjs — public, no configuration:
```sh
npm install -g @bitstack/nopy @bitstack/keyman
npm install -g @bitsquare/nopy @bitsquare/keyman
```
From the Gitea registry, which holds every snapshot plus a mirror of every
release. Per-project, in the repo's `.npmrc`:
```ini
@bitstack:registry=https://gitea.bitsquare.dev/api/packages/BitSquare/npm/
@bitsquare:registry=https://gitea.bitsquare.dev/api/packages/BitSquare/npm/
```
Globally with credentials, in `~/.npmrc`:
```ini
@bitstack:registry=https://gitea.bitsquare.dev/api/packages/BitSquare/npm/
@bitsquare:registry=https://gitea.bitsquare.dev/api/packages/BitSquare/npm/
//gitea.bitsquare.dev/api/packages/BitSquare/npm/:_authToken=<your gitea token>
```
@@ -308,7 +308,7 @@ instance and organisation automatically.
To track snapshots in another project:
```sh
pnpm add @bitstack/nopy@main
pnpm add @bitsquare/nopy@main
```
## Design decisions
@@ -360,14 +360,14 @@ Try the binary as an end user would get it, without publishing:
```sh
cd packages/nopy && pnpm run link:local # build + npm link
nopy --help
npm unlink -g @bitstack/nopy
npm unlink -g @bitsquare/nopy
```
Check that a version is not already taken before you tag:
```sh
npm view @bitstack/nopy@1.2.0 version # npmjs
npm view @bitstack/nopy@1.2.0 version \
npm view @bitsquare/nopy@1.2.0 version # npmjs
npm view @bitsquare/nopy@1.2.0 version \
--registry https://gitea.bitsquare.dev/api/packages/BitSquare/npm/
```
@@ -391,14 +391,14 @@ npm view @bitstack/nopy@1.2.0 version \
Meanwhile:
```sh
npm dist-tag add @bitstack/nopy@1.1.9 latest # point users back
npm deprecate @bitstack/nopy@1.2.0 "Broken build, use 1.2.1"
npm dist-tag add @bitsquare/nopy@1.1.9 latest # point users back
npm deprecate @bitsquare/nopy@1.2.0 "Broken build, use 1.2.1"
```
`npm unpublish` is only possible within 72 hours and burns the version number
forever; a deprecation with a working `latest` is almost always the better move.
**On Gitea**, delete the version under **Packages → @bitstack/… → Settings**
**On Gitea**, delete the version under **Packages → @bitsquare/… → Settings**
before that exact version can be published again.
**A bad tag** can be moved, but only before the release workflow has published
+4 -4
View File
@@ -5,12 +5,12 @@ they deploy.
| Path | Package | Binary | What it is |
| ----------------- | ------------------ | -------- | --------------------------------------------------- |
| `packages/nopy` | `@bitstack/nopy` | `nopy` | interactive pyinfra script management and execution |
| `packages/keyman` | `@bitstack/keyman` | `keyman` | SSH key management with `age` encryption |
| `packages/nopy` | `@bitsquare/nopy` | `nopy` | interactive pyinfra script management and execution |
| `packages/keyman` | `@bitsquare/keyman` | `keyman` | SSH key management with `age` encryption |
| `cubes/` | — | — | the deployment units `nopy` runs |
```sh
npm install -g @bitstack/nopy @bitstack/keyman
npm install -g @bitsquare/nopy @bitsquare/keyman
```
See each package's README for usage, and
@@ -37,7 +37,7 @@ pnpm install
`typescript` is on the 7.x native compiler, so `tsc` *is* the fast one — there is
no separate `tsgo` binary to keep in sync. Each package also has a dev-run script
(`pnpm --filter @bitstack/nopy run nopy`) that executes the TypeScript sources
(`pnpm --filter @bitsquare/nopy run nopy`) that executes the TypeScript sources
directly through `tsx`.
## Git hooks
+1 -1
View File
@@ -1,4 +1,4 @@
import { cubes } from '@bitstack/nopy';
import { cubes } from '@bitsquare/nopy';
export default cubes.Manifest({
id: 'admin:cockpit',
+1 -1
View File
@@ -1,4 +1,4 @@
import { cubes, uniqid } from '@bitstack/nopy';
import { cubes, uniqid } from '@bitsquare/nopy';
import { z } from 'zod';
/**
+1 -1
View File
@@ -12,7 +12,7 @@ Configures system keyboard layout permanently by updating `/etc/default/keyboard
## Usage
```javascript
import { cubes } from '@bitstack/nopy';
import { cubes } from '@bitsquare/nopy';
export default cubes.Manifest({
name: 'My Host Setup',
+1 -1
View File
@@ -1,4 +1,4 @@
import { cubes } from '@bitstack/nopy';
import { cubes } from '@bitsquare/nopy';
import { z } from 'zod';
export default cubes.Manifest({
+1 -1
View File
@@ -1,4 +1,4 @@
import { cubes } from '@bitstack/nopy';
import { cubes } from '@bitsquare/nopy';
import { z } from 'zod';
export default cubes.Manifest({
+1 -1
View File
@@ -1,4 +1,4 @@
import { cubes } from '@bitstack/nopy';
import { cubes } from '@bitsquare/nopy';
import { z } from 'zod';
export default cubes.Manifest({
+1 -1
View File
@@ -1,4 +1,4 @@
import { cubes } from '@bitstack/nopy';
import { cubes } from '@bitsquare/nopy';
export default cubes.Manifest({
id: 'armor:fail2ban',
+1 -1
View File
@@ -1,4 +1,4 @@
import { cubes } from '@bitstack/nopy';
import { cubes } from '@bitsquare/nopy';
import { z } from 'zod';
export default cubes.Manifest({
+1 -1
View File
@@ -1,4 +1,4 @@
import { cubes } from '@bitstack/nopy';
import { cubes } from '@bitsquare/nopy';
import { z } from 'zod';
export default cubes.Manifest({
+1 -1
View File
@@ -1,4 +1,4 @@
import { cubes } from '@bitstack/nopy';
import { cubes } from '@bitsquare/nopy';
import { z } from 'zod';
export default cubes.Manifest({
+1 -1
View File
@@ -1,4 +1,4 @@
import { cubes } from '@bitstack/nopy';
import { cubes } from '@bitsquare/nopy';
import { z } from 'zod';
export default cubes.Manifest({
+1 -1
View File
@@ -1,4 +1,4 @@
import { cubes } from '@bitstack/nopy';
import { cubes } from '@bitsquare/nopy';
import { z } from 'zod';
export default cubes.Manifest({
+1 -1
View File
@@ -1,4 +1,4 @@
import { cubes } from '@bitstack/nopy';
import { cubes } from '@bitsquare/nopy';
import { z } from 'zod';
export default cubes.Manifest({
+1 -1
View File
@@ -1,4 +1,4 @@
import { cubes } from '@bitstack/nopy';
import { cubes } from '@bitsquare/nopy';
import { z } from 'zod';
export default cubes.Manifest({
+1 -1
View File
@@ -1,4 +1,4 @@
import { cubes } from '@bitstack/nopy';
import { cubes } from '@bitsquare/nopy';
import { z } from 'zod';
// [agnt://cogen/cogen/network-wifi-connection-1]{cartridge: "ansiblings/cubes", action: "generated", status: "generated"}
+1 -1
View File
@@ -1,4 +1,4 @@
import { cubes } from '@bitstack/nopy';
import { cubes } from '@bitsquare/nopy';
import { z } from 'zod';
export default cubes.Manifest({
+1 -1
View File
@@ -1,4 +1,4 @@
import { cubes } from '@bitstack/nopy';
import { cubes } from '@bitsquare/nopy';
import { z } from 'zod';
export default cubes.Manifest({
+1 -1
View File
@@ -1,4 +1,4 @@
import { cubes } from '@bitstack/nopy';
import { cubes } from '@bitsquare/nopy';
import { z } from 'zod';
export default cubes.Manifest({
+1 -1
View File
@@ -1,4 +1,4 @@
import { cubes } from '@bitstack/nopy';
import { cubes } from '@bitsquare/nopy';
import { z } from 'zod';
export default cubes.Manifest({
+1 -1
View File
@@ -1,4 +1,4 @@
import { cubes } from '@bitstack/nopy';
import { cubes } from '@bitsquare/nopy';
import { z } from 'zod';
export default cubes.Manifest({
+1 -1
View File
@@ -1,4 +1,4 @@
import { cubes } from '@bitstack/nopy';
import { cubes } from '@bitsquare/nopy';
import { z } from 'zod';
export default cubes.Manifest({
+1 -1
View File
@@ -1,4 +1,4 @@
import { cubes } from '@bitstack/nopy';
import { cubes } from '@bitsquare/nopy';
import { z } from 'zod';
export default cubes.Manifest({
+1 -1
View File
@@ -1,4 +1,4 @@
import { cubes } from '@bitstack/nopy';
import { cubes } from '@bitsquare/nopy';
import { z } from 'zod';
// [agnt://cogen/cogen/user-edit-1]{cartridge: "ansiblings/cubes", action: "generated", status: "generated"}
+1 -1
View File
@@ -1,5 +1,5 @@
{
"name": "@bitstack/keyman",
"name": "@bitsquare/keyman",
"version": "1.0.0",
"description": "A system to simplify ssh key management",
"keywords": [
+3 -3
View File
@@ -20,7 +20,7 @@ Self-contained deployment units consisting of:
```javascript
import { z } from 'zod'
import { cubes } from '@bitstack/nopy'
import { cubes } from '@bitsquare/nopy'
export default cubes.Manifest({
id: 'apt:install',
@@ -209,7 +209,7 @@ This package is part of a yarn workspace monorepo. Install from the repository r
```bash
# From repository root (/ansiblings)
yarn install
yarn workspace @bitstack/nopy build
yarn workspace @bitsquare/nopy build
```
To use the `nopy` command globally, you can:
@@ -217,7 +217,7 @@ To use the `nopy` command globally, you can:
1. **Use yarn workspace command**:
```bash
yarn workspace @bitstack/nopy nopy
yarn workspace @bitsquare/nopy nopy
```
2. **Link the package globally**:
+1 -1
View File
@@ -1,4 +1,4 @@
import { cubes } from '@bitstack/nopy';
import { cubes } from '@bitsquare/nopy';
export default cubes.Manifest({
name: '[apt-all] Test dependencies',
@@ -1,4 +1,4 @@
import { cubes } from '@bitstack/nopy';
import { cubes } from '@bitsquare/nopy';
import { z } from 'zod';
export default cubes.Manifest({
+1 -1
View File
@@ -1,4 +1,4 @@
import { cubes } from '@bitstack/nopy';
import { cubes } from '@bitsquare/nopy';
export default cubes.Manifest({
name: '[apt-more] Test dependencies',
+2 -2
View File
@@ -24,7 +24,7 @@ This document describes the public API for the nopy package.
Main entry point for nopy deployments.
```typescript
import { nopy } from '@bitstack/nopy';
import { nopy } from '@bitsquare/nopy';
const result = await nopy({
useDefaults: false,
@@ -608,7 +608,7 @@ cubes/
```javascript
// my-cube.manifest.mjs
import { createManifest } from '@bitstack/nopy';
import { createManifest } from '@bitsquare/nopy';
import { z } from 'zod';
export default createManifest({
+1 -1
View File
@@ -15,7 +15,7 @@ Hooks are defined as an array of functions in the cube manifest.
```javascript
import { z } from 'zod';
import { cubes } from '@bitstack/nopy';
import { cubes } from '@bitsquare/nopy';
export default cubes.Manifest({
name: 'my-cube',
+1 -1
View File
@@ -252,7 +252,7 @@ generateSession({
Both formats are loaded the same way:
```javascript
import { loadSession } from '@bitstack/nopy';
import { loadSession } from '@bitsquare/nopy';
// Load JSON
const jsonSession = await loadSession('./my-session.session.json');
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@bitstack/nopy",
"version": "1.0.0-alpha4",
"name": "@bitsquare/nopy",
"version": "1.0.0-alpha5",
"description": "A system to simplify pyinfra script management and execution.",
"keywords": [
"pyinfra",
+2 -2
View File
@@ -12,8 +12,8 @@
"skipLibCheck": true,
"resolveJsonModule": true,
"paths": {
"@bitstack/nopy": ["./packages/nopy/src"],
"@bitstack/keyman": ["./packages/keyman/src"]
"@bitsquare/nopy": ["./packages/nopy/src"],
"@bitsquare/keyman": ["./packages/keyman/src"]
}
},
"exclude": ["coverage", "node_modules", "dist"]