fix(npm): improve missing binary diagnostics
This commit is contained in:
parent
c4ec40ab8b
commit
cdca68ff3e
|
|
@ -27,171 +27,68 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
mkdir -p dist
|
mkdir -p dist
|
||||||
VERSION=${GITHUB_REF#refs/tags/v}
|
VERSION=${GITHUB_REF#refs/tags/v}
|
||||||
|
MODULE="github.com/gitlink-org/gitlink-cli"
|
||||||
for pair in "darwin amd64" "darwin arm64" "linux amd64" "linux arm64"; do
|
LDFLAGS="-s -w -X ${MODULE}/cmd.Version=${VERSION}"
|
||||||
GOOS=$(echo $pair | cut -d' ' -f1)
|
|
||||||
GOARCH=$(echo $pair | cut -d' ' -f2)
|
for pair in \
|
||||||
|
"darwin amd64" \
|
||||||
|
"darwin arm64" \
|
||||||
|
"linux amd64" \
|
||||||
|
"linux arm64" \
|
||||||
|
"windows amd64" \
|
||||||
|
"windows arm64"; do
|
||||||
|
GOOS=$(echo "$pair" | cut -d' ' -f1)
|
||||||
|
GOARCH=$(echo "$pair" | cut -d' ' -f2)
|
||||||
|
OUT="gitlink-cli"
|
||||||
|
if [ "$GOOS" = "windows" ]; then
|
||||||
|
OUT="gitlink-cli.exe"
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Building ${GOOS}-${GOARCH}..."
|
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 .
|
BUILD_DIR="dist/gitlink-cli_${VERSION}_${GOOS}_${GOARCH}"
|
||||||
cd dist
|
mkdir -p "$BUILD_DIR"
|
||||||
tar -czf "gitlink-cli_${VERSION}_${GOOS}_${GOARCH}.tar.gz" gitlink-cli
|
CGO_ENABLED=0 GOOS=$GOOS GOARCH=$GOARCH go build -ldflags "$LDFLAGS" -o "$BUILD_DIR/$OUT" .
|
||||||
rm gitlink-cli
|
|
||||||
cd ..
|
if [ "$GOOS" = "windows" ]; then
|
||||||
|
(cd "$BUILD_DIR" && zip -q "../gitlink-cli_${VERSION}_${GOOS}_${GOARCH}.zip" "$OUT")
|
||||||
|
else
|
||||||
|
tar -czf "dist/gitlink-cli_${VERSION}_${GOOS}_${GOARCH}.tar.gz" -C "$BUILD_DIR" "$OUT"
|
||||||
|
fi
|
||||||
|
rm -rf "$BUILD_DIR"
|
||||||
done
|
done
|
||||||
|
|
||||||
|
ls -lh dist
|
||||||
|
|
||||||
- name: Create Release
|
- name: Create Release
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
files: dist/*.tar.gz
|
files: |
|
||||||
|
dist/*.tar.gz
|
||||||
|
dist/*.zip
|
||||||
generate_release_notes: true
|
generate_release_notes: true
|
||||||
|
|
||||||
- name: Build npm package
|
- name: Build npm package
|
||||||
run: |
|
run: |
|
||||||
VERSION=${GITHUB_REF#refs/tags/v}
|
VERSION=${GITHUB_REF#refs/tags/v}
|
||||||
mkdir -p npm-pkg/bin npm-pkg/scripts npm-pkg/skills
|
export VERSION
|
||||||
|
rm -rf npm-pkg
|
||||||
# Copy skills
|
mkdir -p npm-pkg
|
||||||
cp -r skills/* npm-pkg/skills/
|
cp -R npm/. npm-pkg/
|
||||||
|
cp README.md npm-pkg/README.md
|
||||||
# Copy bin wrappers
|
rm -rf npm-pkg/skills
|
||||||
cp bin/cli.js npm-pkg/bin/ 2>/dev/null || cat > npm-pkg/bin/cli.js << 'NODEEOF'
|
cp -R skills npm-pkg/skills
|
||||||
#!/usr/bin/env node
|
|
||||||
const {execFileSync} = require("child_process");
|
node <<'NODE'
|
||||||
const path = require("path");
|
const fs = require('fs');
|
||||||
const bin = path.join(__dirname, "..", "bin", "gitlink-cli");
|
const pkgPath = 'npm-pkg/package.json';
|
||||||
try { process.exit(execFileSync(bin, process.argv.slice(2), {stdio:"inherit"}).status); }
|
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
||||||
catch(e) { process.exit(e.status || 1); }
|
pkg.version = process.env.VERSION;
|
||||||
NODEEOF
|
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
|
||||||
|
NODE
|
||||||
cat > npm-pkg/bin/install-skills.js << 'NODEEOF'
|
|
||||||
#!/usr/bin/env node
|
chmod +x npm-pkg/bin/cli.js
|
||||||
const {execSync} = require("child_process");
|
chmod +x npm-pkg/bin/install-skills.js
|
||||||
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
|
cd npm-pkg
|
||||||
npm publish --access public
|
npm publish --access public
|
||||||
env:
|
env:
|
||||||
|
|
|
||||||
10
README.md
10
README.md
|
|
@ -407,6 +407,16 @@ gitlink-cli auth status # Shows "✓ Logged in via GITLINK_TOKEN environment v
|
||||||
|
|
||||||
Priority: `GITLINK_TOKEN` env var > keyring/file stored token. When the env var is not set, the original interactive login flow works as before.
|
Priority: `GITLINK_TOKEN` env var > keyring/file stored token. When the env var is not set, the original interactive login flow works as before.
|
||||||
|
|
||||||
|
### Q: What if npm installs successfully but `gitlink-cli` reports a missing binary?
|
||||||
|
|
||||||
|
Reinstall first:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install -g @gitlink-ai/cli
|
||||||
|
```
|
||||||
|
|
||||||
|
If the error persists, check whether the release page contains the asset for your platform, for example `gitlink-cli_<version>_windows_amd64.zip` on Windows x64. You can also download the binary manually from the release page or build from source with `go install .`.
|
||||||
|
|
||||||
### Q: Where are credentials stored on Windows?
|
### Q: Where are credentials stored on Windows?
|
||||||
|
|
||||||
gitlink-cli uses Windows Credential Manager for secure token storage. If Credential Manager is unavailable, it automatically falls back to file storage (`~/.config/gitlink-cli/credentials`).
|
gitlink-cli uses Windows Credential Manager for secure token storage. If Credential Manager is unavailable, it automatically falls back to file storage (`~/.config/gitlink-cli/credentials`).
|
||||||
|
|
|
||||||
|
|
@ -386,6 +386,16 @@ gitlink-cli auth status # 显示 "✓ Logged in via GITLINK_TOKEN environment
|
||||||
|
|
||||||
Token 优先级:`GITLINK_TOKEN` 环境变量 > keyring/文件存储的 token。不设置环境变量时完全兼容原有交互式登录。
|
Token 优先级:`GITLINK_TOKEN` 环境变量 > keyring/文件存储的 token。不设置环境变量时完全兼容原有交互式登录。
|
||||||
|
|
||||||
|
### Q: npm 安装成功但 `gitlink-cli` 提示缺少二进制怎么办?
|
||||||
|
|
||||||
|
先尝试重新安装:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install -g @gitlink-ai/cli
|
||||||
|
```
|
||||||
|
|
||||||
|
如果仍然失败,请检查 Release 页面是否包含当前平台的资产,例如 Windows x64 对应 `gitlink-cli_<version>_windows_amd64.zip`。也可以从 Release 页面手动下载二进制,或使用 `go install .` 从源码构建。
|
||||||
|
|
||||||
### Q: Windows 上凭证存储在哪里?
|
### Q: Windows 上凭证存储在哪里?
|
||||||
|
|
||||||
gitlink-cli 使用 Windows Credential Manager 安全存储 Token。如果 Credential Manager 不可用,会自动降级到文件存储(`~/.config/gitlink-cli/credentials`)。
|
gitlink-cli 使用 Windows Credential Manager 安全存储 Token。如果 Credential Manager 不可用,会自动降级到文件存储(`~/.config/gitlink-cli/credentials`)。
|
||||||
|
|
|
||||||
|
|
@ -2,21 +2,78 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
const fs = require("fs");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const { execFileSync } = require("child_process");
|
const { execFileSync } = require("child_process");
|
||||||
|
|
||||||
const ext = process.platform === "win32" ? ".exe" : "";
|
const BINARY_NAME = "gitlink-cli";
|
||||||
const binaryPath = path.join(__dirname, "gitlink-cli" + ext);
|
|
||||||
|
|
||||||
try {
|
function getBinaryName(platform = process.platform) {
|
||||||
execFileSync(binaryPath, process.argv.slice(2), { stdio: "inherit" });
|
return platform === "win32" ? `${BINARY_NAME}.exe` : BINARY_NAME;
|
||||||
} catch (err) {
|
|
||||||
if (err.status !== undefined) {
|
|
||||||
process.exit(err.status);
|
|
||||||
}
|
|
||||||
console.error(`Failed to run gitlink-cli: ${err.message}`);
|
|
||||||
console.error(
|
|
||||||
"Binary may not be installed. Try reinstalling: npm install -g @gitlink-ai/cli"
|
|
||||||
);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getBinaryPath(platform = process.platform, baseDir = __dirname) {
|
||||||
|
return path.join(baseDir, getBinaryName(platform));
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatMissingBinaryError(
|
||||||
|
binaryPath,
|
||||||
|
platform = process.platform,
|
||||||
|
arch = process.arch
|
||||||
|
) {
|
||||||
|
return [
|
||||||
|
`Error: ${BINARY_NAME} binary not found at ${binaryPath}`,
|
||||||
|
`Platform: ${platform}/${arch}`,
|
||||||
|
"",
|
||||||
|
"The npm package was installed, but the native binary is missing.",
|
||||||
|
"This usually means the release asset for your platform is unavailable or postinstall failed.",
|
||||||
|
"",
|
||||||
|
"Try reinstalling:",
|
||||||
|
" npm install -g @gitlink-ai/cli",
|
||||||
|
"",
|
||||||
|
"If the problem persists, check the GitLink CLI release assets:",
|
||||||
|
" https://www.gitlink.org.cn/Gitlink/gitlink-cli/releases",
|
||||||
|
].join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
function run(args = process.argv.slice(2), options = {}) {
|
||||||
|
const platform = options.platform || process.platform;
|
||||||
|
const arch = options.arch || process.arch;
|
||||||
|
const binaryPath = options.binaryPath || getBinaryPath(platform);
|
||||||
|
const execFile = options.execFileSync || execFileSync;
|
||||||
|
const stderr = options.stderr || process.stderr;
|
||||||
|
const exit = options.exit || process.exit;
|
||||||
|
|
||||||
|
function failMissingBinary() {
|
||||||
|
stderr.write(`${formatMissingBinaryError(binaryPath, platform, arch)}\n`);
|
||||||
|
return exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fs.existsSync(binaryPath)) {
|
||||||
|
return failMissingBinary();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
execFile(binaryPath, args, { stdio: "inherit" });
|
||||||
|
} catch (err) {
|
||||||
|
if (err.code === "ENOENT") {
|
||||||
|
return failMissingBinary();
|
||||||
|
}
|
||||||
|
if (err.status !== undefined) {
|
||||||
|
return exit(err.status);
|
||||||
|
}
|
||||||
|
stderr.write(`Failed to run ${BINARY_NAME}: ${err.message}\n`);
|
||||||
|
return exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (require.main === module) {
|
||||||
|
run();
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getBinaryName,
|
||||||
|
getBinaryPath,
|
||||||
|
formatMissingBinaryError,
|
||||||
|
run,
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,8 @@
|
||||||
"gitlink-cli-install-skills": "bin/install-skills.js"
|
"gitlink-cli-install-skills": "bin/install-skills.js"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"postinstall": "node scripts/install.js"
|
"postinstall": "node scripts/install.js",
|
||||||
|
"test": "node test/install.test.js && node test/cli.test.js"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"gitlink",
|
"gitlink",
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,7 @@ const RELEASE_BASE = "https://www.gitlink.org.cn";
|
||||||
const REPO_OWNER = "Gitlink";
|
const REPO_OWNER = "Gitlink";
|
||||||
const REPO_NAME = "gitlink-cli";
|
const REPO_NAME = "gitlink-cli";
|
||||||
|
|
||||||
function getPlatformInfo() {
|
function getPlatformInfo(platform = os.platform(), arch = os.arch()) {
|
||||||
const platform = os.platform();
|
|
||||||
const arch = os.arch();
|
|
||||||
|
|
||||||
const platformMap = {
|
const platformMap = {
|
||||||
darwin: "darwin",
|
darwin: "darwin",
|
||||||
linux: "linux",
|
linux: "linux",
|
||||||
|
|
@ -123,6 +120,7 @@ function fetch(url, options = {}) {
|
||||||
|
|
||||||
async function findReleaseAsset(platform, arch) {
|
async function findReleaseAsset(platform, arch) {
|
||||||
const archiveName = getArchiveName(platform, arch);
|
const archiveName = getArchiveName(platform, arch);
|
||||||
|
const tagName = `v${VERSION}`;
|
||||||
|
|
||||||
// Try fetching release info from GitLink API
|
// Try fetching release info from GitLink API
|
||||||
const apiUrl = `${RELEASE_BASE}/api/${REPO_OWNER}/${REPO_NAME}/releases.json`;
|
const apiUrl = `${RELEASE_BASE}/api/${REPO_OWNER}/${REPO_NAME}/releases.json`;
|
||||||
|
|
@ -133,7 +131,6 @@ async function findReleaseAsset(platform, arch) {
|
||||||
|
|
||||||
// Find the release matching our version
|
// Find the release matching our version
|
||||||
let release = null;
|
let release = null;
|
||||||
const tagName = `v${VERSION}`;
|
|
||||||
|
|
||||||
if (Array.isArray(releases)) {
|
if (Array.isArray(releases)) {
|
||||||
release = releases.find(
|
release = releases.find(
|
||||||
|
|
@ -234,9 +231,15 @@ async function downloadAndExtract(url, destDir, platform) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
|
let platformInfo = null;
|
||||||
|
let archiveName = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { platform, arch } = getPlatformInfo();
|
platformInfo = getPlatformInfo();
|
||||||
|
const { platform, arch } = platformInfo;
|
||||||
|
archiveName = getArchiveName(platform, arch);
|
||||||
console.log(`Platform: ${platform}-${arch}`);
|
console.log(`Platform: ${platform}-${arch}`);
|
||||||
|
console.log(`Expected release asset: ${archiveName}`);
|
||||||
|
|
||||||
const binDir = path.join(__dirname, "..", "bin");
|
const binDir = path.join(__dirname, "..", "bin");
|
||||||
if (!fs.existsSync(binDir)) {
|
if (!fs.existsSync(binDir)) {
|
||||||
|
|
@ -264,6 +267,12 @@ async function main() {
|
||||||
await downloadAndExtract(downloadUrl, binDir, platform);
|
await downloadAndExtract(downloadUrl, binDir, platform);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(`\nFailed to install ${BINARY_NAME}: ${err.message}`);
|
console.error(`\nFailed to install ${BINARY_NAME}: ${err.message}`);
|
||||||
|
if (platformInfo) {
|
||||||
|
console.error(`Platform: ${platformInfo.platform}/${platformInfo.arch}`);
|
||||||
|
}
|
||||||
|
if (archiveName) {
|
||||||
|
console.error(`Expected release asset: ${archiveName}`);
|
||||||
|
}
|
||||||
console.error(
|
console.error(
|
||||||
`\nYou can install manually:\n` +
|
`\nYou can install manually:\n` +
|
||||||
` 1. Download from https://www.gitlink.org.cn/${REPO_OWNER}/${REPO_NAME}/releases\n` +
|
` 1. Download from https://www.gitlink.org.cn/${REPO_OWNER}/${REPO_NAME}/releases\n` +
|
||||||
|
|
@ -274,4 +283,13 @@ async function main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
main();
|
if (require.main === module) {
|
||||||
|
main();
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getPlatformInfo,
|
||||||
|
getBinaryName,
|
||||||
|
getArchiveName,
|
||||||
|
findReleaseAsset,
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const assert = require("assert");
|
||||||
|
const path = require("path");
|
||||||
|
const os = require("os");
|
||||||
|
const cli = require("../bin/cli.js");
|
||||||
|
|
||||||
|
assert.equal(cli.getBinaryName("win32"), "gitlink-cli.exe");
|
||||||
|
assert.equal(cli.getBinaryName("linux"), "gitlink-cli");
|
||||||
|
assert.equal(cli.getBinaryName("darwin"), "gitlink-cli");
|
||||||
|
|
||||||
|
assert.equal(
|
||||||
|
cli.getBinaryPath("win32", "C:\\tmp\\gitlink"),
|
||||||
|
path.join("C:\\tmp\\gitlink", "gitlink-cli.exe")
|
||||||
|
);
|
||||||
|
|
||||||
|
const message = cli.formatMissingBinaryError(
|
||||||
|
"C:\\tmp\\gitlink-cli.exe",
|
||||||
|
"win32",
|
||||||
|
"x64"
|
||||||
|
);
|
||||||
|
assert.match(message, /binary not found/);
|
||||||
|
assert.match(message, /Platform: win32\/x64/);
|
||||||
|
assert.match(message, /npm install -g @gitlink-ai\/cli/);
|
||||||
|
|
||||||
|
let exitCode = null;
|
||||||
|
const stderr = {
|
||||||
|
output: "",
|
||||||
|
write(text) {
|
||||||
|
this.output += text;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
cli.run(["version"], {
|
||||||
|
binaryPath: path.join(os.tmpdir(), "gitlink-cli-test-missing-binary"),
|
||||||
|
platform: "win32",
|
||||||
|
arch: "x64",
|
||||||
|
stderr,
|
||||||
|
exit(code) {
|
||||||
|
exitCode = code;
|
||||||
|
return code;
|
||||||
|
},
|
||||||
|
execFileSync() {
|
||||||
|
throw new Error("execFileSync should not be called for a missing binary");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(exitCode, 1);
|
||||||
|
assert.match(stderr.output, /gitlink-cli binary not found/);
|
||||||
|
assert.match(stderr.output, /Platform: win32\/x64/);
|
||||||
|
|
||||||
|
console.log("cli wrapper tests passed");
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const assert = require("assert");
|
||||||
|
const install = require("../scripts/install.js");
|
||||||
|
const pkg = require("../package.json");
|
||||||
|
|
||||||
|
assert.deepStrictEqual(install.getPlatformInfo("win32", "x64"), {
|
||||||
|
platform: "windows",
|
||||||
|
arch: "amd64",
|
||||||
|
isWindows: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepStrictEqual(install.getPlatformInfo("win32", "arm64"), {
|
||||||
|
platform: "windows",
|
||||||
|
arch: "arm64",
|
||||||
|
isWindows: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepStrictEqual(install.getPlatformInfo("darwin", "arm64"), {
|
||||||
|
platform: "darwin",
|
||||||
|
arch: "arm64",
|
||||||
|
isWindows: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepStrictEqual(install.getPlatformInfo("linux", "x64"), {
|
||||||
|
platform: "linux",
|
||||||
|
arch: "amd64",
|
||||||
|
isWindows: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(install.getBinaryName("windows"), "gitlink-cli.exe");
|
||||||
|
assert.equal(install.getBinaryName("linux"), "gitlink-cli");
|
||||||
|
assert.equal(install.getBinaryName("darwin"), "gitlink-cli");
|
||||||
|
|
||||||
|
assert.equal(
|
||||||
|
install.getArchiveName("windows", "amd64"),
|
||||||
|
`gitlink-cli_${pkg.version}_windows_amd64.zip`
|
||||||
|
);
|
||||||
|
assert.equal(
|
||||||
|
install.getArchiveName("windows", "arm64"),
|
||||||
|
`gitlink-cli_${pkg.version}_windows_arm64.zip`
|
||||||
|
);
|
||||||
|
assert.equal(
|
||||||
|
install.getArchiveName("linux", "amd64"),
|
||||||
|
`gitlink-cli_${pkg.version}_linux_amd64.tar.gz`
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.throws(
|
||||||
|
() => install.getPlatformInfo("freebsd", "x64"),
|
||||||
|
/Unsupported platform/
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log("install helper tests passed");
|
||||||
|
|
@ -74,13 +74,14 @@ rm -rf "$NPM_DIR/skills"
|
||||||
cp -r "$PROJECT_DIR/skills" "$NPM_DIR/skills"
|
cp -r "$PROJECT_DIR/skills" "$NPM_DIR/skills"
|
||||||
|
|
||||||
# Ensure bin dir exists and wrapper is executable
|
# Ensure bin dir exists and wrapper is executable
|
||||||
chmod +x "$NPM_DIR/bin/gitlink-cli"
|
chmod +x "$NPM_DIR/bin/cli.js"
|
||||||
|
chmod +x "$NPM_DIR/bin/install-skills.js"
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "=== Done ==="
|
echo "=== Done ==="
|
||||||
echo ""
|
echo ""
|
||||||
echo "Next steps:"
|
echo "Next steps:"
|
||||||
echo " 1. Upload dist/*.tar.gz to GitLink Release v${VERSION}"
|
echo " 1. Upload dist/*.tar.gz and dist/*.zip to GitLink Release v${VERSION}"
|
||||||
echo " URL: https://www.gitlink.org.cn/Gitlink/gitlink-cli/releases"
|
echo " URL: https://www.gitlink.org.cn/Gitlink/gitlink-cli/releases"
|
||||||
echo ""
|
echo ""
|
||||||
echo " 2. Publish npm package:"
|
echo " 2. Publish npm package:"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue