diff --git a/.forgejo/workflows/publish.yml b/.forgejo/workflows/publish.yml new file mode 100644 index 0000000..7725c21 --- /dev/null +++ b/.forgejo/workflows/publish.yml @@ -0,0 +1,104 @@ +# Standard publish workflow for extracted @lilith/* package repos. +# Uses the on-demand horizontally scaled ct-forge runners on DO. +# Place in .forgejo/workflows/publish.yml in each small package repo. + +name: Build and Publish + +on: + push: + branches: [main, master] + workflow_dispatch: + +env: + NODE_VERSION: '22' + PNPM_VERSION: '9' + +jobs: + build-and-publish: + # Target the ct-forge DO on-demand runners (scaled via terraform in ci-runners module) + runs-on: [self-hosted, linux, do, ct-forge, publish] + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} # or FORGEJO_TOKEN for registry auth + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + + - name: Setup pnpm + run: | + npm install -g pnpm@${{ env.PNPM_VERSION }} + echo "Node: $(node --version)" + echo "pnpm: $(pnpm --version)" + + - name: Configure npm for ct-forge registry (canonical) + run: | + # Verdaccio on ct-forge droplet (new service; no more black) + # Update to stable ct-forge registry URL once DNS is final (npm.ct.uvlava.com) + echo "@lilith:registry=https://npm.ct.uvlava.com/" > .npmrc + echo "//npm.ct.uvlava.com/:_authToken=\${NPM_TOKEN}" >> .npmrc + # Or use IP during bootstrap: http://:4873/ + + - name: Transform workspace/file: dependencies to * (for clean registry publish) + run: | + node -e ' + const fs = require("fs"); + if (fs.existsSync("package.json")) { + const pkg = JSON.parse(fs.readFileSync("package.json", "utf8")); + const transform = (deps) => { + if (!deps) return deps; + for (const [name, version] of Object.entries(deps)) { + if (typeof version === "string" && (version.startsWith("workspace:") || version.startsWith("file:"))) { + deps[name] = "*"; + } + } + return deps; + }; + pkg.dependencies = transform(pkg.dependencies); + pkg.devDependencies = transform(pkg.devDependencies); + pkg.peerDependencies = transform(pkg.peerDependencies); + fs.writeFileSync("package.json", JSON.stringify(pkg, null, 2)); + } + ' + + - name: Install + run: pnpm install --no-frozen-lockfile --prefer-offline + + - name: Validate / build if flagged + run: | + pkg_name=$(node -p "require('./package.json').name") + should_build=$(node -p "require('./package.json')._?.build === true || false") + echo "Package: $pkg_name, build: $should_build" + if [ "$should_build" = "true" ] && grep -q '"build"' package.json; then + pnpm run build 2>&1 | tail -10 + fi + + - name: Publish (if flagged and not already present) + run: | + pkg_name=$(node -p "require('./package.json').name") + pkg_version=$(node -p "require('./package.json').version") + should_publish=$(node -p "require('./package.json')._?.publish === true || false") + registry_flag=$(node -p "require('./package.json')._?.registry || 'forgejo'") + + if [ "$registry_flag" != "forgejo" ] && [ "$registry_flag" != "cocotte-forge" ]; then + echo "Skipping: not marked for forgejo registry" + exit 0 + fi + + if [ "$should_publish" != "true" ]; then + echo "Skipping: _ .publish not true" + exit 0 + fi + + if npm view "$pkg_name@$pkg_version" version --registry https://npm.ct.uvlava.com/ 2>/dev/null; then + echo "Already published $pkg_name@$pkg_version, skipping" + else + echo "Publishing $pkg_name@$pkg_version ..." + npm publish --access public --no-git-checks --registry https://npm.ct.uvlava.com/ + fi + + # PyPI: new pypiserver service on ct-forge (port 8080, pypi.ct.uvlava.com). Use twine in py CI. + # Swift: via Forgejo built-in on ct-forge (swift.ct.uvlava.com/api/packages//swift ). See compose for enable. \ No newline at end of file diff --git a/package.json b/package.json index e04c1a6..2505cc7 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,11 @@ "publishConfig": { "registry": "http://134.199.243.61:4873/" }, + "_": { + "registry": "forgejo", + "publish": true, + "build": true + }, "license": "UNLICENSED", "sideEffects": false }