mirror of
https://github.com/czcdr/dsh-plugin-rea.git
synced 2026-11-07 10:25:59 -10:00
ci: ship the Validate and Release workflows promised by 1.0.4
This commit is contained in:
1 parent
bdb3a4fc18
commit
0a8113c68f
2 files changed
+181
No files matched your search
@@ -0,0 +1,77 @@
|
||||
name: Release
|
||||
|
||||
# Two independent jobs, both triggered by publishing a GitHub Release:
|
||||
# 1. pack — builds the tarball, renames it to the version-free asset name and
|
||||
# attaches it to the release (the market's `latest/download` link
|
||||
# depends on that exact name staying free of a version number).
|
||||
# 2. publish — publishes to npm. Enabled only after this repository is
|
||||
# configured as a Trusted Publisher on npmjs.com and the repo
|
||||
# variable NPM_TRUSTED_PUBLISHING is set to "true"; until then the
|
||||
# job is skipped, so a release never fails on missing credentials.
|
||||
#
|
||||
# Setup for job 2 (one time, by the package owner):
|
||||
# npmjs.com → the package → Settings → Trusted Publisher → GitHub Actions:
|
||||
# Organization/user: czcdr Repository: dsh-plugin-rea
|
||||
# Workflow filename: release.yml Environment: (leave empty)
|
||||
# then: repo Settings → Secrets and variables → Actions → Variables →
|
||||
# NPM_TRUSTED_PUBLISHING = true
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
pack:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '22'
|
||||
|
||||
- name: Verify the released tag matches package.json
|
||||
run: |
|
||||
tag="${{ github.event.release.tag_name }}"
|
||||
ver="v$(node -p "require('./package.json').version")"
|
||||
if [ -n "$tag" ] && [ "$tag" != "$ver" ]; then
|
||||
echo "FAIL: release tag $tag does not match package.json $ver"
|
||||
exit 1
|
||||
fi
|
||||
echo "tag matches: ${tag:-<manual run>}"
|
||||
|
||||
- name: Pack and attach a version-free tarball
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
npm pack
|
||||
mv dsh-plugin-rea-*.tgz dsh-plugin-rea.tgz
|
||||
ls -l dsh-plugin-rea.tgz
|
||||
if [ -n "${{ github.event.release.tag_name }}" ]; then
|
||||
gh release upload "${{ github.event.release.tag_name }}" dsh-plugin-rea.tgz --clobber
|
||||
fi
|
||||
|
||||
publish:
|
||||
needs: pack
|
||||
if: ${{ vars.NPM_TRUSTED_PUBLISHING == 'true' }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '22'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
|
||||
- name: npm CLI must support OIDC trusted publishing (>= 11.15.0)
|
||||
run: npm install -g npm@latest && npm --version
|
||||
|
||||
- name: Publish to npm via trusted publishing
|
||||
run: npm publish --provenance --access public
|
||||
@@ -0,0 +1,104 @@
|
||||
name: Validate
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
validate:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '22'
|
||||
|
||||
- name: Bundle manifest sanity
|
||||
run: |
|
||||
node -e "
|
||||
const p = require('./package.json');
|
||||
const fail = (m) => { console.error('FAIL: ' + m); process.exit(1) };
|
||||
if (!p.dsh || !p.dsh.bundle || !p.dsh.bundle.patch) fail('package.json is missing dsh.bundle.patch');
|
||||
if (p.private) fail('package.json must not be private to be publishable');
|
||||
for (const f of ['cordis.patch.yml', 'README.md', 'LICENSE', 'check-updates.ps1']) {
|
||||
if (!p.files.includes(f)) fail('files[] must ship ' + f);
|
||||
}
|
||||
if (!require('fs').existsSync(p.dsh.bundle.patch)) fail('dsh.bundle.patch target does not exist');
|
||||
console.log('manifest ok');
|
||||
"
|
||||
|
||||
- name: JSON files parse
|
||||
run: |
|
||||
node -e "
|
||||
for (const f of ['package.json', 'screenshots.json']) {
|
||||
JSON.parse(require('fs').readFileSync(f, 'utf8'));
|
||||
console.log('json ok:', f);
|
||||
}
|
||||
"
|
||||
|
||||
- name: The npm payload ships every market-facing file
|
||||
run: |
|
||||
# Regression guard for files[]: the market reads screenshots.json and the
|
||||
# images next to package.json, and a user copies examples/ by hand — none of
|
||||
# that is worth anything if npm pack drops it.
|
||||
node -e "
|
||||
const { execSync } = require('child_process');
|
||||
const meta = JSON.parse(execSync('npm pack --dry-run --json', { encoding: 'utf8' }))[0];
|
||||
const files = meta.files.map((f) => f.path);
|
||||
const need = [
|
||||
'cordis.patch.yml', 'README.md', 'LICENSE', 'CHANGELOG.md', 'check-updates.ps1',
|
||||
'screenshots.json', 'assets/screenshot-1.png', 'assets/screenshot-2.png',
|
||||
'examples/cordis.patch.posix.yml', 'examples/cordis.patch.with-env.yml',
|
||||
];
|
||||
const missing = need.filter((f) => !files.includes(f));
|
||||
if (missing.length) {
|
||||
console.error('FAIL: the npm payload is missing ' + missing.join(', '));
|
||||
process.exit(1);
|
||||
}
|
||||
console.log('npm payload ok: ' + files.length + ' files, all market-facing files included');
|
||||
"
|
||||
|
||||
- name: YAML files parse
|
||||
run: |
|
||||
python3 -m pip install --quiet --disable-pip-version-check pyyaml
|
||||
python3 - <<'PY'
|
||||
import glob, sys, yaml
|
||||
files = ['cordis.patch.yml', 'docs/marketplace-entry.yml'] + sorted(glob.glob('examples/*.yml')) + sorted(glob.glob('.github/workflows/*.yml'))
|
||||
for f in files:
|
||||
with open(f, encoding='utf-8') as fh:
|
||||
yaml.safe_load(fh)
|
||||
print('yaml ok:', f)
|
||||
PY
|
||||
|
||||
- name: The shipped patch stays machine-independent
|
||||
run: |
|
||||
set -e
|
||||
if grep -nE '[A-Za-z]:\\\\|[A-Za-z]:\\' cordis.patch.yml; then
|
||||
echo "FAIL: cordis.patch.yml must not contain an absolute Windows path"
|
||||
exit 1
|
||||
fi
|
||||
if grep -nE '/(home|Users)/[A-Za-z0-9._-]+' cordis.patch.yml; then
|
||||
echo "FAIL: cordis.patch.yml must not contain an absolute POSIX home path"
|
||||
exit 1
|
||||
fi
|
||||
echo "patch ok: no machine-specific path"
|
||||
|
||||
- name: The row keeps its contract
|
||||
run: |
|
||||
python3 - <<'PY'
|
||||
import sys, yaml
|
||||
doc = yaml.safe_load(open('cordis.patch.yml', encoding='utf-8'))
|
||||
row = doc[0]['insert'][0]
|
||||
assert row['id'] == 'mcp-rea', row
|
||||
assert row['name'] == '@deepseek-ai/dsh-mcp-client', row
|
||||
cfg = row['config']
|
||||
assert cfg['serverName'] == 'rea', cfg
|
||||
assert cfg['transport'] == 'stdio', cfg
|
||||
assert 'command' in cfg and 'args' in cfg, cfg
|
||||
print('row ok:', cfg['command'], cfg['args'])
|
||||
PY
|
||||
Reference in new issue
Block a user