From 7fc2ce62ddf340934c61bc54615aecb115621bb6 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Fri, 5 Dec 2025 01:38:04 +0900 Subject: [PATCH] feat: add npm publish workflow with Trusted Publishing --- .github/workflows/publish.yml | 55 ++++++++++++++++++ package.json | 2 +- script/publish.ts | 105 ++++++++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/publish.yml create mode 100644 script/publish.ts diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..57d5085 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,55 @@ +name: publish +run-name: "${{ format('release {0}', inputs.bump) }}" + +on: + workflow_dispatch: + inputs: + bump: + description: "Bump major, minor, or patch" + required: true + type: choice + options: + - major + - minor + - patch + version: + description: "Override version (optional)" + required: false + type: string + +concurrency: ${{ github.workflow }}-${{ github.ref }} + +permissions: + contents: write + id-token: write + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - run: git fetch --force --tags + + - uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + + - uses: actions/setup-node@v4 + with: + node-version: "20" + registry-url: "https://registry.npmjs.org" + + - name: Install dependencies + run: bun install + + - name: Publish + run: ./script/publish.ts + env: + BUMP: ${{ inputs.bump }} + VERSION: ${{ inputs.version }} + CI: true + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NPM_CONFIG_PROVENANCE: true diff --git a/package.json b/package.json index 5add7e6..1c38589 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "oh-my-opencode", - "version": "0.1.0", + "version": "0.0.0", "description": "OpenCode plugin - custom agents (oracle, librarian) and enhanced features", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/script/publish.ts b/script/publish.ts new file mode 100644 index 0000000..ede1446 --- /dev/null +++ b/script/publish.ts @@ -0,0 +1,105 @@ +#!/usr/bin/env bun + +import { $ } from "bun" + +const PACKAGE_NAME = "oh-my-opencode" +const bump = process.env.BUMP as "major" | "minor" | "patch" | undefined +const versionOverride = process.env.VERSION + +console.log("=== Publishing oh-my-opencode ===\n") + +async function fetchPreviousVersion(): Promise { + try { + const res = await fetch(`https://registry.npmjs.org/${PACKAGE_NAME}/latest`) + if (!res.ok) throw new Error(`Failed to fetch: ${res.statusText}`) + const data = (await res.json()) as { version: string } + console.log(`Previous version: ${data.version}`) + return data.version + } catch { + console.log("No previous version found, starting from 0.0.0") + return "0.0.0" + } +} + +function bumpVersion(version: string, type: "major" | "minor" | "patch"): string { + const [major, minor, patch] = version.split(".").map(Number) + switch (type) { + case "major": + return `${major + 1}.0.0` + case "minor": + return `${major}.${minor + 1}.0` + case "patch": + return `${major}.${minor}.${patch + 1}` + } +} + +async function updatePackageVersion(newVersion: string): Promise { + const pkgPath = new URL("../package.json", import.meta.url).pathname + let pkg = await Bun.file(pkgPath).text() + pkg = pkg.replace(/"version": "[^"]+"/, `"version": "${newVersion}"`) + await Bun.file(pkgPath).write(pkg) + console.log(`Updated: ${pkgPath}`) +} + +async function generateChangelog(previous: string): Promise { + try { + const log = await $`git log v${previous}..HEAD --oneline --format="%h %s"`.text() + const commits = log + .split("\n") + .filter((line) => line && !line.match(/^\w+ (ignore:|test:|chore:|ci:|release:)/i)) + + if (commits.length > 0) { + const changelog = commits.map((c) => `- ${c}`).join("\n") + console.log("\n--- Changelog ---") + console.log(changelog) + console.log("-----------------\n") + return changelog + } + } catch { + console.log("No previous tags found, skipping changelog generation") + } + return "" +} + +async function buildAndPublish(): Promise { + console.log("Building...") + await $`bun run build` + + console.log("\nPublishing to npm...") + if (process.env.CI) { + await $`npm publish --access public --provenance` + } else { + await $`npm publish --access public` + } +} + +async function gitTagAndRelease(newVersion: string, changelog: string): Promise { + if (!process.env.CI) return + + console.log("\nCommitting and tagging...") + await $`git config user.email "github-actions[bot]@users.noreply.github.com"` + await $`git config user.name "github-actions[bot]"` + await $`git add package.json` + await $`git commit -m "release: v${newVersion}"` + await $`git tag v${newVersion}` + await $`git push origin HEAD --tags` + + console.log("\nCreating GitHub release...") + const releaseNotes = changelog || "No notable changes" + await $`gh release create v${newVersion} --title "v${newVersion}" --notes ${releaseNotes}` +} + +async function main() { + const previous = await fetchPreviousVersion() + const newVersion = versionOverride || (bump ? bumpVersion(previous, bump) : bumpVersion(previous, "patch")) + console.log(`New version: ${newVersion}\n`) + + await updatePackageVersion(newVersion) + const changelog = await generateChangelog(previous) + await buildAndPublish() + await gitTagAndRelease(newVersion, changelog) + + console.log(`\n=== Successfully published ${PACKAGE_NAME}@${newVersion} ===`) +} + +main()