hotfix(docker): select Alpine-compatible CLIProxy asset

This commit is contained in:
Tam Nhu Tran committed 2026-07-18 19:55:07 -04:00
1 parent a31f1ec79c
commit 003342f604
5 files changed
+108 -3

No files matched your search

+10 -2
View File
@@ -365,6 +365,14 @@ jobs:
-p 18317:8317 \
"${{ steps.image.outputs.ref }}"
print_service_logs() {
docker logs "${CONTAINER_NAME}" --tail 100 >&2 || true
docker exec "${CONTAINER_NAME}" \
sh -c 'tail -n 100 /var/log/ccs/cliproxy.log' >&2 || true
docker exec "${CONTAINER_NAME}" \
sh -c 'tail -n 100 /var/log/ccs/ccs-dashboard.log' >&2 || true
}
echo "[i] Waiting for container healthcheck (up to 60s)..."
HEALTHY=0
for i in $(seq 1 12); do
@@ -376,7 +384,7 @@ jobs:
fi
if [[ "${STATUS}" == "unhealthy" ]]; then
echo "[X] Container marked unhealthy"
docker logs "${CONTAINER_NAME}" --tail 50 >&2
print_service_logs
exit 1
fi
echo " [${i}/12] status=${STATUS}, waiting 5s..."
@@ -384,7 +392,7 @@ jobs:
done
if [[ "${HEALTHY}" -ne 1 ]]; then
echo "[X] Container did not become healthy within 60s (last status: ${STATUS})" >&2
docker logs "${CONTAINER_NAME}" --tail 100 >&2
print_service_logs
docker inspect "${CONTAINER_NAME}" --format='{{json .State}}' >&2 || true
exit 1
fi
+2
View File
@@ -7,6 +7,8 @@ FROM eceasy/cli-proxy-api:latest@sha256:4fa722b9ff83adfbe6e350d433b7dcb754756aa6
ARG CCS_NPM_VERSION=latest
ENV CCS_CLIPROXY_NO_PLUGIN_ASSET=1
# CCS integrated image: CCS CLI + CLIProxy + supervisord.
# Design choice (issue #1251 final scope): single-image strategy. The originally-
# proposed `:full` variant bundling claude-code/gemini-cli/grok-cli/opencode was
+11 -1
View File
@@ -166,7 +166,17 @@ export function detectPlatform(
const ver = version || config.fallbackVersion;
const extension: ArchiveExtension = os === 'windows' ? 'zip' : 'tar.gz';
const assetArch = getReleaseArchForBackend(backend, ver, arch, releaseArch);
const assetVariant = backend === 'plus' && usesPlusNoPluginAsset(ver, os) ? '_no-plugin' : '';
// The integrated Alpine image opts into the portable static upstream asset.
// Normal Linux installs keep plugin-capable archives for backward compatibility.
const usesOriginalNoPluginAsset =
process.env.CCS_CLIPROXY_NO_PLUGIN_ASSET === '1' &&
backend === 'original' &&
os === 'linux' &&
isAtLeastVersion(ver, '7.1.52');
const assetVariant =
usesOriginalNoPluginAsset || (backend === 'plus' && usesPlusNoPluginAsset(ver, os))
? '_no-plugin'
: '';
const binaryName = `${config.binaryPrefix}_${ver}_${os}_${assetArch}${assetVariant}.${extension}`;
return {
@@ -24,6 +24,26 @@ describe('Backend Selection', () => {
}
}
function withEnvironmentVariable(name, value, callback) {
const originalValue = process.env[name];
if (value === undefined) {
delete process.env[name];
} else {
process.env[name] = value;
}
try {
callback();
} finally {
if (originalValue === undefined) {
delete process.env[name];
} else {
process.env[name] = originalValue;
}
}
}
describe('BACKEND_CONFIG', () => {
it('has correct configuration for original backend', () => {
const config = platformDetector.BACKEND_CONFIG.original;
@@ -73,6 +93,62 @@ describe('Backend Selection', () => {
assert(!info.binaryName.includes('CLIProxyAPIPlus'));
});
it('uses static no-plugin assets when the integrated Linux image opts in', () => {
withEnvironmentVariable('CCS_CLIPROXY_NO_PLUGIN_ASSET', '1', () => {
withMockedProcessPlatform('linux', 'x64', () => {
assert.strictEqual(
platformDetector.detectPlatform('7.2.88', 'original').binaryName,
'CLIProxyAPI_7.2.88_linux_amd64_no-plugin.tar.gz'
);
assert.strictEqual(
platformDetector.getDownloadUrl('7.2.88', 'original'),
'https://github.com/router-for-me/CLIProxyAPI/releases/download/v7.2.88/CLIProxyAPI_7.2.88_linux_amd64_no-plugin.tar.gz'
);
});
withMockedProcessPlatform('linux', 'arm64', () => {
assert.strictEqual(
platformDetector.detectPlatform('7.2.88', 'original').binaryName,
'CLIProxyAPI_7.2.88_linux_aarch64_no-plugin.tar.gz'
);
});
});
});
it('keeps plugin-capable original archives for normal Linux installs', () => {
withMockedProcessPlatform('linux', 'arm64', () => {
assert.strictEqual(
platformDetector.detectPlatform('7.2.88', 'original').binaryName,
'CLIProxyAPI_7.2.88_linux_aarch64.tar.gz'
);
});
});
it('keeps original archive names compatible before Linux no-plugin assets existed', () => {
withEnvironmentVariable('CCS_CLIPROXY_NO_PLUGIN_ASSET', '1', () => {
withMockedProcessPlatform('linux', 'x64', () => {
assert.strictEqual(
platformDetector.detectPlatform('7.1.51', 'original').binaryName,
'CLIProxyAPI_7.1.51_linux_amd64.tar.gz'
);
});
});
withMockedProcessPlatform('darwin', 'arm64', () => {
assert.strictEqual(
platformDetector.detectPlatform('7.2.88', 'original').binaryName,
'CLIProxyAPI_7.2.88_darwin_aarch64.tar.gz'
);
});
withMockedProcessPlatform('win32', 'x64', () => {
assert.strictEqual(
platformDetector.detectPlatform('7.2.88', 'original').binaryName,
'CLIProxyAPI_7.2.88_windows_amd64.zip'
);
});
});
it('keeps old plus non-Windows archive names unsuffixed', () => {
withMockedProcessPlatform('darwin', 'arm64', () => {
assert.strictEqual(
@@ -43,6 +43,15 @@ describe('docker release workflow context', () => {
expect(dockerfile).toContain('HEALTHCHECK');
expect(dockerfile).toContain('127.0.0.1:3000');
expect(dockerfile).toContain('127.0.0.1:8317');
expect(dockerfile).toContain('ENV CCS_CLIPROXY_NO_PLUGIN_ASSET=1');
});
test('prints service logs when the integrated image fails its healthcheck', () => {
const workflow = readFileSync(join(repoRoot, '.github/workflows/docker-release.yml'), 'utf8');
expect(workflow).toContain('docker logs "${CONTAINER_NAME}"');
expect(workflow).toContain('/var/log/ccs/cliproxy.log');
expect(workflow).toContain('/var/log/ccs/ccs-dashboard.log');
});
test('lets network-contract smoke tests avoid fixed host port collisions', () => {