Skip to content

Commit 8cdc3ae

Browse files
committed
ci: automate marketplace PR submission
1 parent d3b8119 commit 8cdc3ae

3 files changed

Lines changed: 108 additions & 2 deletions

File tree

.github/workflows/release.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,52 @@ jobs:
2828
- run: pnpm pack:zip
2929
- run: pnpm pack:tgz
3030
- run: pnpm -s marketplace:snippet > marketplace-index-snippet.json
31+
- id: marketplace-meta
32+
run: |
33+
node --input-type=module -e "import fs from 'fs'; const pkg = JSON.parse(fs.readFileSync('package.json','utf8')); const meta = JSON.parse(fs.readFileSync('napgram-plugin.json','utf8')); const id = (meta.id || pkg.name); console.log(`id=${id}`); console.log(`version=${pkg.version}`);" >> $GITHUB_OUTPUT
34+
- if: ${{ secrets.MARKETPLACE_PR_TOKEN != '' }}
35+
name: Ensure marketplace fork
36+
uses: actions/github-script@v7
37+
with:
38+
github-token: ${{ secrets.MARKETPLACE_PR_TOKEN }}
39+
script: |
40+
const upstream = { owner: 'NapGram', repo: 'marketplace' };
41+
const forkOwner = context.actor;
42+
try {
43+
await github.rest.repos.get({ owner: forkOwner, repo: upstream.repo });
44+
return;
45+
} catch (error) {
46+
if (error.status !== 404) throw error;
47+
}
48+
await github.rest.repos.createFork({ owner: upstream.owner, repo: upstream.repo });
49+
for (let i = 0; i < 10; i++) {
50+
try {
51+
await github.rest.repos.get({ owner: forkOwner, repo: upstream.repo });
52+
return;
53+
} catch {
54+
await new Promise(resolve => setTimeout(resolve, 3000));
55+
}
56+
}
57+
core.setFailed('marketplace fork not ready');
58+
- if: ${{ secrets.MARKETPLACE_PR_TOKEN != '' }}
59+
uses: actions/checkout@v4
60+
with:
61+
repository: ${{ github.actor }}/marketplace
62+
token: ${{ secrets.MARKETPLACE_PR_TOKEN }}
63+
path: marketplace
64+
- if: ${{ secrets.MARKETPLACE_PR_TOKEN != '' }}
65+
run: node scripts/marketplace-upsert.mjs --index marketplace/index.json --snippet marketplace-index-snippet.json
66+
- if: ${{ secrets.MARKETPLACE_PR_TOKEN != '' }}
67+
uses: peter-evans/create-pull-request@v6
68+
with:
69+
token: ${{ secrets.MARKETPLACE_PR_TOKEN }}
70+
path: marketplace
71+
commit-message: "marketplace: update ${{ steps.marketplace-meta.outputs.id }} ${{ steps.marketplace-meta.outputs.version }}"
72+
branch: "marketplace/${{ steps.marketplace-meta.outputs.id }}-${{ steps.marketplace-meta.outputs.version }}"
73+
title: "marketplace: update ${{ steps.marketplace-meta.outputs.id }} ${{ steps.marketplace-meta.outputs.version }}"
74+
body: "Auto-generated marketplace submission."
75+
base: main
76+
push-to-fork: ${{ github.actor }}/marketplace
3177
- uses: softprops/action-gh-release@v2
3278
with:
3379
files: |

scripts/marketplace-snippet.mjs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,20 @@ async function readSha(file) {
3131
return raw.split(/\s+/)[0].trim();
3232
}
3333

34+
const repo = process.env.GITHUB_REPOSITORY;
35+
const tag = process.env.GITHUB_REF_NAME;
36+
const distHost = process.env.MARKETPLACE_DIST_HOST;
37+
38+
function buildUrl(file) {
39+
if (distHost) {
40+
return `${distHost.replace(/\/$/, '')}/${file}`;
41+
}
42+
if (repo && tag) {
43+
return `https://github.com/${repo}/releases/download/${tag}/${file}`;
44+
}
45+
return `https://YOUR_HOST/${file}`;
46+
}
47+
3448
const out = {
3549
schemaVersion: 1,
3650
kind: "native",
@@ -42,8 +56,8 @@ const out = {
4256
{
4357
version,
4458
entry: { type: 'file', path: String(meta.entry || 'dist/index.mjs') },
45-
dist: zip ? { type: 'zip', url: `https://YOUR_HOST/${zip}`, sha256: await readSha(zip) }
46-
: tgz ? { type: 'tgz', url: `https://YOUR_HOST/${tgz}`, sha256: await readSha(tgz) }
59+
dist: zip ? { type: 'zip', url: buildUrl(zip), sha256: await readSha(zip) }
60+
: tgz ? { type: 'tgz', url: buildUrl(tgz), sha256: await readSha(tgz) }
4761
: { type: 'zip', url: 'https://YOUR_HOST/FILE.zip', sha256: '...sha256...' },
4862
permissions: meta.permissions || { network: [], fs: [], instances: [0] }
4963
}

scripts/marketplace-upsert.mjs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import fs from 'node:fs/promises';
2+
import path from 'node:path';
3+
4+
function argValue(name) {
5+
const index = process.argv.indexOf(name);
6+
if (index === -1) return undefined;
7+
return process.argv[index + 1];
8+
}
9+
10+
const indexPath = argValue('--index') || 'index.json';
11+
const snippetPath = argValue('--snippet') || 'marketplace-index-snippet.json';
12+
13+
const indexRaw = await fs.readFile(path.resolve(indexPath), 'utf8');
14+
const snippetRaw = await fs.readFile(path.resolve(snippetPath), 'utf8');
15+
16+
const indexData = JSON.parse(indexRaw);
17+
const snippet = JSON.parse(snippetRaw);
18+
const plugin = snippet?.plugins?.[0];
19+
20+
if (!plugin) {
21+
throw new Error('snippet missing plugins[0]');
22+
}
23+
24+
if (!Array.isArray(indexData.plugins)) {
25+
indexData.plugins = [];
26+
}
27+
28+
const existing = indexData.plugins.find(item => item.id === plugin.id);
29+
const version = plugin.versions?.[0];
30+
31+
if (!existing) {
32+
indexData.plugins.push(plugin);
33+
} else {
34+
if (plugin.name) existing.name = plugin.name;
35+
if (!Array.isArray(existing.versions)) existing.versions = [];
36+
if (version) {
37+
const idx = existing.versions.findIndex(item => item.version === version.version);
38+
if (idx >= 0) {
39+
existing.versions[idx] = version;
40+
} else {
41+
existing.versions.push(version);
42+
}
43+
}
44+
}
45+
46+
await fs.writeFile(path.resolve(indexPath), `${JSON.stringify(indexData, null, 2)}\n`, 'utf8');

0 commit comments

Comments
 (0)