Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 126 additions & 0 deletions .github/workflows/pr-artifact.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
name: PR Build Artifact

on:
pull_request:
branches: [master]

permissions:
contents: read
pull-requests: write

jobs:
build-artifact:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
registry-url: https://registry.npmjs.org

- run: npm ci

- run: npm run build

- name: Publish to npm with PR tag
run: |
PR_NUMBER="${{ github.event.pull_request.number }}"
RUN_NUMBER="${{ github.run_number }}"
BASE_VERSION=$(node -p "require('./package.json').version")
# Strip any existing prerelease suffix
BASE_VERSION=$(echo "$BASE_VERSION" | sed 's/-.*//')
PR_VERSION="${BASE_VERSION}-pr.${PR_NUMBER}.${RUN_NUMBER}"

echo "Publishing version $PR_VERSION with tag pr-${PR_NUMBER}"
npm version "$PR_VERSION" --no-git-tag-version
npm publish --tag "pr-${PR_NUMBER}" --access public --ignore-scripts
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

- name: Create installable tarball
run: |
npm pack
PR_NUM="${{ github.event.pull_request.number }}"
TARBALL=$(ls opencode-acp-*.tgz | head -1)
if [ -n "$PR_NUM" ] && [ -n "$TARBALL" ]; then
cp "$TARBALL" "opencode-acp-pr${PR_NUM}.tgz"
fi

- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: opencode-acp-pr-${{ github.event.pull_request.number }}
path: |
opencode-acp-pr*.tgz
dist/
retention-days: 30

- name: Comment on PR with install instructions
uses: actions/github-script@v7
with:
script: |
const prNumber = context.payload.pull_request.number;
const sha = context.payload.pull_request.head.sha.slice(0, 7);
const branch = context.payload.pull_request.head.ref;
const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;

const body = [
'## 📦 Built Plugin Artifact',
'',
`**Branch:** \`${branch}\` (${sha})`,
'',
'### Option A — Install from npm PR tag (recommended)',
'',
'```bash',
'opencode plugin opencode-acp@pr-' + prNumber + ' --global',
'```',
'',
'Each push to this PR publishes a new version under the `pr-' + prNumber + '` npm tag.',
'',
'### Option B — Install from GitHub',
'',
'```bash',
'opencode plugin "github:ranxianglei/opencode-acp#' + branch + '" --global',
'```',
'',
'### Option C — Download artifact',
'',
`1. Download the artifact from the [Actions run](${runUrl})`,
'2. Extract the tarball and install:',
'',
'```bash',
'tar xzf opencode-acp-pr' + prNumber + '.tgz',
'cp -r package/dist ~/.cache/opencode/packages/opencode-acp@latest/node_modules/opencode-acp/dist',
'```',
'',
'3. **Restart opencode** to pick up changes.',
'',
'---',
'*This comment is automatically updated on each push.*',
].join('\n');

// Find and update existing comment, or create new one
const comments = await github.rest.issues.listComments({
...context.repo,
issue_number: prNumber,
});

const existing = comments.data.find(c =>
c.user.type === 'Bot' && c.body.includes('📦 Built Plugin Artifact')
);

if (existing) {
await github.rest.issues.updateComment({
...context.repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
...context.repo,
issue_number: prNumber,
body,
});
}
82 changes: 82 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
Expand Down Expand Up @@ -148,3 +149,84 @@ jobs:
prerelease: ${{ steps.version.outputs.is_prerelease }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Report published version on PR
if: steps.check.outputs.is_release == 'true' && success()
uses: actions/github-script@v7
with:
script: |
const version = '${{ steps.version.outputs.version }}';
const npmTag = '${{ steps.version.outputs.npm_tag }}';
const isPrerelease = '${{ steps.version.outputs.is_prerelease }}' === 'true';

// Find the merged PR associated with this commit
const prs = await github.rest.repos.listPullRequestsAssociatedWithCommit({
owner: context.repo.owner,
repo: context.repo.repo,
commit_sha: context.sha
});

const prNumber = prs.data[0]?.number;
if (!prNumber) {
core.info('No associated PR found — skipping comment');
return;
}

const installCmd = isPrerelease
? 'opencode plugin opencode-acp@dev --global'
: 'opencode plugin opencode-acp@latest --global';

const body = [
`✅ **Published \`opencode-acp@${version}\`** to npm \`${npmTag}\` tag.`,
'',
'```bash',
installCmd,
'```',
'',
`[npm](https://www.npmjs.com/package/opencode-acp/v/${version}) | [GitHub Release](https://github.com/${context.repo.owner}/${context.repo.repo}/releases/tag/v${version})`
].join('\n');

await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body
});

core.info(`Commented on PR #${prNumber}: published ${version} to ${npmTag}`);

- name: Report promote-stable on PR
if: steps.check.outputs.is_promote_stable == 'true' && success()
uses: actions/github-script@v7
with:
script: |
const version = '${{ steps.check.outputs.stable_version }}';

const prs = await github.rest.repos.listPullRequestsAssociatedWithCommit({
owner: context.repo.owner,
repo: context.repo.repo,
commit_sha: context.sha
});

const prNumber = prs.data[0]?.number;
if (!prNumber) {
core.info('No associated PR found — skipping comment');
return;
}

const body = [
`✅ **Promoted \`opencode-acp@${version}\`** to npm \`stable\` tag.`,
'',
'```bash',
'opencode plugin opencode-acp@stable --global',
'```'
].join('\n');

await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body
});

core.info(`Commented on PR #${prNumber}: promoted ${version} to stable`);
27 changes: 27 additions & 0 deletions devlog/2026-08-13_pr-build-artifact/REQ.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# REQ — PR Build Artifact CI

## Problem

Users have no easy way to test PR changes locally before merge. They have to clone the branch, install dependencies, build, and manually deploy — too many steps for casual testing.

## Solution

1. New GitHub Actions workflow (`pr-artifact.yml`) that runs on every PR to master:
- Builds `dist/`
- Creates an installable tarball via `npm pack`
- Uploads both as a GitHub Actions artifact (30-day retention)
- Comments on the PR with install instructions (updated on each push)

2. Add `"prepare": "npm run build"` to `package.json` so `npm install github:...#branch` auto-builds `dist/`.

## Install Options for Testers

**Option A** — Install from GitHub (recommended):
```bash
opencode plugin "github:ranxianglei/opencode-acp#branch-name" --global
```

**Option B** — Download artifact from Actions tab:
1. Download the artifact from the PR's CI run
2. Extract tarball and copy to cache dir
3. Restart opencode
16 changes: 16 additions & 0 deletions devlog/2026-08-13_pr-build-artifact/WORKLOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# WORKLOG — PR Build Artifact CI

## Changes

1. `.github/workflows/pr-artifact.yml` (new) — CI workflow that:
- Triggers on `pull_request` to master
- Builds `dist/`, creates `npm pack` tarball
- Uploads artifact (tarball + dist/) with 30-day retention
- Comments on PR with install instructions (idempotent — updates existing comment)

2. `package.json` — Added `"prepare": "npm run build"` script so `npm install github:...#branch` auto-builds `dist/`

## Verification

- Workflow YAML validated manually
- `prepare` script confirmed: runs on git install + before publish, does NOT run on `npm ci`
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"scripts": {
"clean": "rm -rf dist",
"build": "npm run clean && tsup && tsc --emitDeclarationOnly",
"prepare": "npm run build",
"verify:package": "node scripts/verify-package.mjs",
"check:package": "npm run build && npm run verify:package",
"prepublishOnly": "npm run check:package",
Expand Down
Loading