gitlink-cli/.github/workflows/release.yml

199 lines
7.2 KiB
YAML

name: Release
on:
push:
tags:
- 'v*'
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.22'
- uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: Build binaries
run: |
mkdir -p dist
VERSION=${GITHUB_REF#refs/tags/v}
for pair in "darwin amd64" "darwin arm64" "linux amd64" "linux arm64"; do
GOOS=$(echo $pair | cut -d' ' -f1)
GOARCH=$(echo $pair | cut -d' ' -f2)
echo "Building ${GOOS}-${GOARCH}..."
GOOS=$GOOS GOARCH=$GOARCH go build -ldflags "-s -w -X 'github.com/gitlink-org/gitlink-cli/cmd.Version=${VERSION}'" -o dist/gitlink-cli .
cd dist
tar -czf "gitlink-cli_${VERSION}_${GOOS}_${GOARCH}.tar.gz" gitlink-cli
rm gitlink-cli
cd ..
done
- name: Create Release
uses: softprops/action-gh-release@v2
with:
files: dist/*.tar.gz
generate_release_notes: true
- name: Build npm package
run: |
VERSION=${GITHUB_REF#refs/tags/v}
mkdir -p npm-pkg/bin npm-pkg/scripts npm-pkg/skills
# Copy skills
cp -r skills/* npm-pkg/skills/
# Copy bin wrappers
cp bin/cli.js npm-pkg/bin/ 2>/dev/null || cat > npm-pkg/bin/cli.js << 'NODEEOF'
#!/usr/bin/env node
const {execFileSync} = require("child_process");
const path = require("path");
const bin = path.join(__dirname, "..", "bin", "gitlink-cli");
try { process.exit(execFileSync(bin, process.argv.slice(2), {stdio:"inherit"}).status); }
catch(e) { process.exit(e.status || 1); }
NODEEOF
cat > npm-pkg/bin/install-skills.js << 'NODEEOF'
#!/usr/bin/env node
const {execSync} = require("child_process");
const path = require("path");
const skillsDir = path.join(__dirname, "..", "skills");
try {
execSync(`npx skills add "${skillsDir}" -y -g`, {stdio:"inherit"});
} catch(e) {
console.error("Failed to install skills:", e.message);
process.exit(1);
}
NODEEOF
# Copy install.js
cp scripts/install.js npm-pkg/scripts/ 2>/dev/null || cat > npm-pkg/scripts/install.js << 'NODEEOF'
#!/usr/bin/env node
"use strict";
const os = require("os");
const path = require("path");
const fs = require("fs");
const https = require("https");
const http = require("http");
const {execSync} = require("child_process");
const PACKAGE = require("../package.json");
const VERSION = PACKAGE.version;
const BINARY_NAME = "gitlink-cli";
const RELEASE_BASE = "https://github.com";
const REPO_OWNER = "ccfos";
const REPO_NAME = "gitlink-cli";
function getPlatformInfo() {
const platform = os.platform();
const arch = os.arch();
const pmap = {darwin:"darwin",linux:"linux",win32:"windows"};
const amap = {x64:"amd64",arm64:"arm64"};
const p=pmap[platform], a=amap[arch];
if(!p||!a) throw new Error(`Unsupported: ${platform}-${arch}`);
return {platform:p,arch:a};
}
function fetch(url) {
return new Promise((resolve,reject) => {
const mod=url.startsWith("https")?https:http;
let count=0;
function req(u) {
if(++count>5) return reject(new Error("Too many redirects"));
mod.get(u,(res) => {
if([301,302,307,308].includes(res.statusCode)&&res.headers.location){
let loc=res.headers.location;
if(loc.startsWith("/")){const p=new URL(u);loc=p.protocol+"//"+p.host+loc}
return req(loc);
}
if(res.statusCode!==200) return reject(new Error(`HTTP ${res.statusCode}`));
const c=[];res.on("data",d=>c.push(d));res.on("end",()=>resolve(Buffer.concat(c)));
}).on("error",reject);
}
req(url);
});
}
async function main() {
try {
const {platform,arch} = getPlatformInfo();
const binDir = path.join(__dirname,"..","bin");
if(!fs.existsSync(binDir)) fs.mkdirSync(binDir,{recursive:true});
const binaryPath = path.join(binDir,BINARY_NAME);
if(fs.existsSync(binaryPath)) {
try {
const out = execSync(`"${binaryPath}" version`,{encoding:"utf-8",timeout:5000});
if(out.includes(VERSION)) { console.log(`${BINARY_NAME} v${VERSION} already installed.`); return; }
} catch(e) {}
fs.unlinkSync(binaryPath);
}
const assetName = `gitlink-cli_${VERSION}_${platform}_${arch}.tar.gz`;
const url = `${RELEASE_BASE}/${REPO_OWNER}/${REPO_NAME}/releases/download/v${VERSION}/${assetName}`;
console.log(`Downloading ${url}...`);
const data = await fetch(url);
const tmp = path.join(binDir,"dl.tar.gz");
fs.writeFileSync(tmp,data);
execSync(`tar -xzf "${tmp}" -C "${binDir}"`,{stdio:"pipe"});
fs.unlinkSync(tmp);
fs.chmodSync(binaryPath,0o755);
console.log(`${BINARY_NAME} v${VERSION} installed.`);
} catch(err) {
console.warn(`⚠ Binary download failed: ${err.message}`);
console.warn(`Skills are installed. Install binary manually:`);
console.warn(`npm run postinstall`);
}
}
main();
NODEEOF
# Create README
cp README.md npm-pkg/
# Create package.json
cat > npm-pkg/package.json << PKGEOF
{
"name": "@gitlink-ai/cli",
"version": "${VERSION}",
"description": "GitLink CLI — 面向 AI Agent 的 GitLink 命令行工具",
"main": "bin/cli.js",
"bin": {
"gitlink-cli": "./bin/cli.js",
"gitlink-cli-install-skills": "./bin/install-skills.js"
},
"scripts": {
"postinstall": "node scripts/install.js"
},
"files": [
"bin/",
"scripts/",
"skills/",
"README.md",
"package.json"
],
"repository": {
"type": "git",
"url": "https://github.com/ccfos/gitlink-cli.git"
},
"keywords": ["gitlink", "cli", "ai-agent", "skills"],
"author": "",
"license": "MulanPSL-2.0"
}
PKGEOF
cd npm-pkg
npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}