diff --git a/.github/workflows/goreleaser.yml b/.github/workflows/goreleaser.yml index 91a54f0..7e7c05f 100644 --- a/.github/workflows/goreleaser.yml +++ b/.github/workflows/goreleaser.yml @@ -11,6 +11,8 @@ permissions: jobs: goreleaser: runs-on: ubuntu-latest + outputs: + version: ${{ steps.get-version.outputs.version }} steps: - name: Checkout repository uses: actions/checkout@v5 @@ -34,3 +36,121 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GO_VERSION: ${{ steps.setup-go.outputs.go-version }} + + - name: Extract version from tag + id: get-version + run: | + VERSION="${GITHUB_REF_NAME#v}" + echo "version=${VERSION}" >> $GITHUB_OUTPUT + echo "Version: ${VERSION}" + + - name: Upload binaries as artifacts + uses: actions/upload-artifact@v4 + with: + name: binaries + path: | + dist/CodeGPT-* + !dist/*.xz + retention-days: 1 + + publish-npm: + name: Publish to npm - ${{ matrix.scope && format('{0}/', matrix.scope) || '' }}${{ matrix.name }} + needs: goreleaser + runs-on: ubuntu-latest + + permissions: + id-token: write + + strategy: + matrix: + include: + - name: codegpt + scope: "@appleboy" + + steps: + - name: Checkout + uses: actions/checkout@v5 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Setup Node.js + uses: actions/setup-node@v5 + with: + node-version: 22 + registry-url: https://registry.npmjs.org + + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + name: binaries + path: cli/nodejs/binaries + + - name: Verify downloaded binaries + run: | + echo "Downloaded binaries:" + ls -lh cli/nodejs/binaries/ + + - name: Update package.json version and name + working-directory: cli/nodejs + run: | + VERSION="${{ needs.goreleaser.outputs.version }}" + PACKAGE_NAME="${{ matrix.name }}" + SCOPE="${{ matrix.scope }}" + + # Update version + npm version ${VERSION} --no-git-tag-version + + # Update package name with scope if present + if [ -n "${SCOPE}" ]; then + FULL_NAME="${SCOPE}/${PACKAGE_NAME}" + else + FULL_NAME="${PACKAGE_NAME}" + fi + + # Use jq to update package name + cat package.json | jq --arg name "${FULL_NAME}" '.name = $name' > package.json.tmp + mv package.json.tmp package.json + + echo "Updated package.json:" + cat package.json | jq '{name, version}' + + - name: Copy README for npm + run: | + cp README.md cli/nodejs/README.md + cp README.zh-cn.md cli/nodejs/README.zh-cn.md + cp README.zh-tw.md cli/nodejs/README.zh-tw.md + + - name: Publish to npm with provenance + working-directory: cli/nodejs + env: + NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }} + run: | + npm publish --provenance --access public + + - name: Verify publication + working-directory: cli/nodejs + run: | + VERSION="${{ needs.goreleaser.outputs.version }}" + PACKAGE_NAME="${{ matrix.name }}" + SCOPE="${{ matrix.scope }}" + + if [ -n "${SCOPE}" ]; then + FULL_NAME="${SCOPE}/${PACKAGE_NAME}" + else + FULL_NAME="${PACKAGE_NAME}" + fi + + echo "Waiting for npm registry to update..." + sleep 10 + + # Check if version is available + PUBLISHED_VERSION=$(npm view ${FULL_NAME}@${VERSION} version 2>/dev/null || echo "") + + if [ "${PUBLISHED_VERSION}" = "${VERSION}" ]; then + echo "✓ Successfully published ${FULL_NAME}@${VERSION}" + echo "Install with: npm install -g ${FULL_NAME}" + else + echo "Warning: Could not immediately verify publication" + echo "Please check: https://www.npmjs.com/package/${FULL_NAME}" + fi diff --git a/.gitignore b/.gitignore index 8e5ab26..fe3290b 100644 --- a/.gitignore +++ b/.gitignore @@ -17,5 +17,6 @@ coverage.txt dist **/.DS_Store bin +!cli/nodejs/bin/ release .codegpt.yaml diff --git a/README.md b/README.md index 86971d6..872d81d 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ [![Lint and Testing](https://github.com/appleboy/CodeGPT/actions/workflows/testing.yml/badge.svg?branch=main)](https://github.com/appleboy/CodeGPT/actions/workflows/testing.yml) [![codecov](https://codecov.io/gh/appleboy/CodeGPT/branch/main/graph/badge.svg)](https://codecov.io/gh/appleboy/CodeGPT) [![Go Report Card](https://goreportcard.com/badge/github.com/appleboy/CodeGPT)](https://goreportcard.com/report/github.com/appleboy/CodeGPT) +[![npm version](https://img.shields.io/npm/v/@appleboy/codegpt?logo=npm&style=flat-square&color=CB3837)](https://www.npmjs.com/package/@appleboy/codegpt) +[![npm downloads](https://img.shields.io/npm/dt/@appleboy/codegpt?logo=npm&style=flat-square)](https://www.npmjs.com/package/@appleboy/codegpt) A CLI tool written in [Go](https://go.dev) that generates git commit messages or provides code review summaries using ChatGPT AI (gpt-5, gpt-4o, gpt-4 model). It also automatically installs a [git prepare-commit-msg hook](https://git-scm.com/docs/githooks). @@ -87,6 +89,16 @@ Install via [Chocolatey](https://chocolatey.org/install): choco install codegpt ``` +### Node.js/npm + +Install via [npm](https://www.npmjs.com/): + +```sh +npm install -g @appleboy/codegpt +``` + +The npm package automatically downloads and installs the correct binary for your platform during installation. + ### Install via Script or Binary For most systems, you can use an install script **or** manually download a pre-compiled binary. diff --git a/README.zh-cn.md b/README.zh-cn.md index a7bd98f..7382e0a 100644 --- a/README.zh-cn.md +++ b/README.zh-cn.md @@ -3,6 +3,8 @@ [![Lint and Testing](https://github.com/appleboy/CodeGPT/actions/workflows/testing.yml/badge.svg?branch=main)](https://github.com/appleboy/CodeGPT/actions/workflows/testing.yml) [![codecov](https://codecov.io/gh/appleboy/CodeGPT/branch/main/graph/badge.svg)](https://codecov.io/gh/appleboy/CodeGPT) [![Go Report Card](https://goreportcard.com/badge/github.com/appleboy/CodeGPT)](https://goreportcard.com/report/github.com/appleboy/CodeGPT) +[![npm version](https://img.shields.io/npm/v/@appleboy/codegpt?logo=npm&style=flat-square&color=CB3837)](https://www.npmjs.com/package/@appleboy/codegpt) +[![npm downloads](https://img.shields.io/npm/dt/@appleboy/codegpt?logo=npm&style=flat-square)](https://www.npmjs.com/package/@appleboy/codegpt) 一个用 [Go](https://go.dev) 编写的 CLI 工具,它使用 ChatGPT AI(gpt-4o,gpt-4 模型)为你编写 git 提交信息或提供代码审查摘要,并自动安装 [git prepare-commit-msg hook](https://git-scm.com/docs/githooks)。 @@ -82,6 +84,16 @@ brew install codegpt choco install codegpt ``` +### Node.js/npm + +通过 [npm](https://www.npmjs.com/) 安装: + +```sh +npm install -g @appleboy/codegpt +``` + +npm 套件会在安装时自动下载并安装适合您平台的二进制文件。 + ### 脚本与二进制安装 大多数系统推荐使用自动化脚本安装(推荐),也可手动下载二进制文件。 diff --git a/README.zh-tw.md b/README.zh-tw.md index 9f7cde7..ec65b07 100644 --- a/README.zh-tw.md +++ b/README.zh-tw.md @@ -3,6 +3,8 @@ [![Lint and Testing](https://github.com/appleboy/CodeGPT/actions/workflows/testing.yml/badge.svg?branch=main)](https://github.com/appleboy/CodeGPT/actions/workflows/testing.yml) [![codecov](https://codecov.io/gh/appleboy/CodeGPT/branch/main/graph/badge.svg)](https://codecov.io/gh/appleboy/CodeGPT) [![Go Report Card](https://goreportcard.com/badge/github.com/appleboy/CodeGPT)](https://goreportcard.com/report/github.com/appleboy/CodeGPT) +[![npm version](https://img.shields.io/npm/v/@appleboy/codegpt?logo=npm&style=flat-square&color=CB3837)](https://www.npmjs.com/package/@appleboy/codegpt) +[![npm downloads](https://img.shields.io/npm/dt/@appleboy/codegpt?logo=npm&style=flat-square)](https://www.npmjs.com/package/@appleboy/codegpt) 一個用 [Go](https://go.dev) 編寫的 CLI 工具,使用 ChatGPT AI (gpt-4o, gpt-4 模型) 生成 git 提交訊息或提供代碼審查摘要。它還會自動安裝 [git prepare-commit-msg hook](https://git-scm.com/docs/githooks)。 @@ -86,6 +88,16 @@ brew install codegpt choco install codegpt ``` +### Node.js/npm + +透過 [npm](https://www.npmjs.com/) 安裝: + +```sh +npm install -g @appleboy/codegpt +``` + +npm 套件會在安裝時自動下載並安裝適合您平台的二進位檔案。 + ### 腳本與二進位安裝 大多數系統推薦使用安裝腳本自動安裝(推薦),亦可手動下載執行檔。 diff --git a/cli/nodejs/.npmignore b/cli/nodejs/.npmignore new file mode 100644 index 0000000..b7f08e9 --- /dev/null +++ b/cli/nodejs/.npmignore @@ -0,0 +1,5 @@ +*.xz +*.tar.gz +*.zip +node_modules/ +.DS_Store diff --git a/cli/nodejs/bin/codegpt b/cli/nodejs/bin/codegpt new file mode 100755 index 0000000..7a9df6e --- /dev/null +++ b/cli/nodejs/bin/codegpt @@ -0,0 +1,19 @@ +#!/usr/bin/env node + +const path = require('path'); +const { spawn } = require('child_process'); + +const binaryPath = path.join(__dirname, 'codegpt-bin'); + +const child = spawn(binaryPath, process.argv.slice(2), { + stdio: 'inherit', + windowsHide: true, +}); + +child.on('exit', (code, signal) => { + if (signal) { + process.kill(process.pid, signal); + } else { + process.exit(code); + } +}); diff --git a/cli/nodejs/install.js b/cli/nodejs/install.js new file mode 100644 index 0000000..46a3b76 --- /dev/null +++ b/cli/nodejs/install.js @@ -0,0 +1,114 @@ +#!/usr/bin/env node + +const fs = require('fs'); +const path = require('path'); +const { execSync } = require('child_process'); + +function getPlatform() { + const platform = process.platform; + const arch = process.arch; + + let platformName; + let archName; + let armVersion = ''; + + // Map platform + switch (platform) { + case 'darwin': + platformName = 'darwin'; + break; + case 'linux': + platformName = 'linux'; + break; + case 'win32': + platformName = 'windows'; + break; + case 'freebsd': + platformName = 'freebsd'; + break; + default: + throw new Error(`Unsupported platform: ${platform}`); + } + + // Map architecture + switch (arch) { + case 'x64': + archName = 'amd64'; + break; + case 'arm': + archName = 'arm'; + // Try to detect ARM version + try { + if (platform === 'linux') { + const cpuinfo = fs.readFileSync('/proc/cpuinfo', 'utf8'); + if (cpuinfo.includes('ARMv7')) { + armVersion = '-7'; + } else if (cpuinfo.includes('ARMv6')) { + armVersion = '-6'; + } else { + armVersion = '-5'; + } + } + } catch (e) { + armVersion = '-7'; // Default to ARMv7 + } + break; + case 'arm64': + archName = 'arm64'; + break; + default: + throw new Error(`Unsupported architecture: ${arch}`); + } + + return { platformName, archName, armVersion }; +} + +function getVersion() { + const packageJson = require('./package.json'); + return packageJson.version; +} + +function getBinaryName() { + const { platformName, archName, armVersion } = getPlatform(); + const version = getVersion(); + const ext = platformName === 'windows' ? '.exe' : ''; + + return `CodeGPT-${version}-${platformName}-${archName}${armVersion}${ext}`; +} + +function install() { + try { + const binaryName = getBinaryName(); + const binaryPath = path.join(__dirname, 'binaries', binaryName); + const targetPath = path.join(__dirname, 'bin', 'codegpt-bin'); + + if (!fs.existsSync(binaryPath)) { + console.error(`Error: Binary not found for your platform: ${binaryName}`); + console.error('Supported platforms:'); + console.error(' - darwin (macOS): x64, arm64'); + console.error(' - linux: x64, arm, arm64'); + console.error(' - windows: x64'); + console.error(' - freebsd: x64'); + process.exit(1); + } + + // Copy binary to bin directory + fs.copyFileSync(binaryPath, targetPath); + + // Make it executable on Unix-like systems + if (process.platform !== 'win32') { + fs.chmodSync(targetPath, 0o755); + } + + console.log(`✓ CodeGPT installed successfully for ${process.platform}-${process.arch}`); + } catch (error) { + console.error('Installation failed:', error.message); + process.exit(1); + } +} + +if (require.main === module) { + install(); +} + +module.exports = { install }; diff --git a/cli/nodejs/package.json b/cli/nodejs/package.json new file mode 100644 index 0000000..c64bf18 --- /dev/null +++ b/cli/nodejs/package.json @@ -0,0 +1,49 @@ +{ + "name": "codegpt", + "version": "0.0.0", + "description": "A CLI tool that uses AI models to help write commit messages, code review, summary code, and more", + "main": "install.js", + "bin": { + "codegpt": "bin/codegpt" + }, + "scripts": { + "postinstall": "node install.js" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/appleboy/CodeGPT.git" + }, + "keywords": [ + "codegpt", + "ai", + "cli", + "openai", + "gemini", + "anthropic", + "commit", + "code-review" + ], + "author": "Bo-Yi Wu", + "license": "MIT", + "bugs": { + "url": "https://github.com/appleboy/CodeGPT/issues" + }, + "homepage": "https://github.com/appleboy/CodeGPT#readme", + "files": [ + "binaries/", + "bin/", + "install.js", + "README.md" + ], + "os": [ + "darwin", + "linux", + "win32", + "freebsd" + ], + "cpu": [ + "x64", + "arm", + "arm64" + ] +}