chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
name: agents-md-guard
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
- reopened
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
close-when-agents-md-changed:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Detect AGENTS.md changes and close PR
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const prNumber = context.payload.pull_request.number;
|
||||
const { owner, repo } = context.repo;
|
||||
|
||||
const files = await github.paginate(github.rest.pulls.listFiles, {
|
||||
owner,
|
||||
repo,
|
||||
pull_number: prNumber,
|
||||
per_page: 100,
|
||||
});
|
||||
|
||||
const touchesAgentsMd = (path) =>
|
||||
typeof path === "string" &&
|
||||
(path === "AGENTS.md" || path.endsWith("/AGENTS.md"));
|
||||
|
||||
const touched = files.filter(
|
||||
(f) => touchesAgentsMd(f.filename) || touchesAgentsMd(f.previous_filename),
|
||||
);
|
||||
|
||||
if (touched.length === 0) {
|
||||
core.info("No AGENTS.md changes detected.");
|
||||
return;
|
||||
}
|
||||
|
||||
const changedList = touched
|
||||
.map((f) =>
|
||||
f.previous_filename && f.previous_filename !== f.filename
|
||||
? `- ${f.previous_filename} -> ${f.filename}`
|
||||
: `- ${f.filename}`,
|
||||
)
|
||||
.join("\n");
|
||||
|
||||
const body = [
|
||||
"This repository does not allow modifying `AGENTS.md` in pull requests.",
|
||||
"",
|
||||
"Detected changes:",
|
||||
changedList,
|
||||
"",
|
||||
"Please revert these changes and open a new PR without touching `AGENTS.md`.",
|
||||
].join("\n");
|
||||
|
||||
try {
|
||||
await github.rest.issues.createComment({
|
||||
owner,
|
||||
repo,
|
||||
issue_number: prNumber,
|
||||
body,
|
||||
});
|
||||
} catch (error) {
|
||||
core.warning(`Failed to comment on PR #${prNumber}: ${error.message}`);
|
||||
}
|
||||
|
||||
await github.rest.pulls.update({
|
||||
owner,
|
||||
repo,
|
||||
pull_number: prNumber,
|
||||
state: "closed",
|
||||
});
|
||||
|
||||
core.setFailed("PR modifies AGENTS.md");
|
||||
@@ -0,0 +1,73 @@
|
||||
name: auto-retarget-main-pr-to-dev
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
- reopened
|
||||
- edited
|
||||
branches:
|
||||
- main
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
retarget:
|
||||
if: github.actor != 'github-actions[bot]'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Retarget PR base to dev
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const pr = context.payload.pull_request;
|
||||
const prNumber = pr.number;
|
||||
const { owner, repo } = context.repo;
|
||||
|
||||
const baseRef = pr.base?.ref;
|
||||
const headRef = pr.head?.ref;
|
||||
const desiredBase = "dev";
|
||||
|
||||
if (baseRef !== "main") {
|
||||
core.info(`PR #${prNumber} base is ${baseRef}; nothing to do.`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (headRef === desiredBase) {
|
||||
core.info(`PR #${prNumber} is ${desiredBase} -> main; skipping retarget.`);
|
||||
return;
|
||||
}
|
||||
|
||||
core.info(`Retargeting PR #${prNumber} base from ${baseRef} to ${desiredBase}.`);
|
||||
|
||||
try {
|
||||
await github.rest.pulls.update({
|
||||
owner,
|
||||
repo,
|
||||
pull_number: prNumber,
|
||||
base: desiredBase,
|
||||
});
|
||||
} catch (error) {
|
||||
core.setFailed(`Failed to retarget PR #${prNumber} to ${desiredBase}: ${error.message}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const body = [
|
||||
`This pull request targeted \`${baseRef}\`.`,
|
||||
"",
|
||||
`The base branch has been automatically changed to \`${desiredBase}\`.`,
|
||||
].join("\n");
|
||||
|
||||
try {
|
||||
await github.rest.issues.createComment({
|
||||
owner,
|
||||
repo,
|
||||
issue_number: prNumber,
|
||||
body,
|
||||
});
|
||||
} catch (error) {
|
||||
core.warning(`Failed to comment on PR #${prNumber}: ${error.message}`);
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
name: docker-image
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v*
|
||||
|
||||
env:
|
||||
APP_NAME: CLIProxyAPI
|
||||
DOCKERHUB_REPO: eceasy/cli-proxy-api
|
||||
|
||||
jobs:
|
||||
docker_amd64:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Refresh models catalog
|
||||
run: |
|
||||
git fetch --depth 1 https://github.com/router-for-me/models.git main
|
||||
git show FETCH_HEAD:models.json > internal/registry/models/models.json
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Generate Build Metadata
|
||||
run: |
|
||||
echo "VERSION=${GITHUB_REF_NAME}" >> $GITHUB_ENV
|
||||
echo COMMIT=`git rev-parse --short HEAD` >> $GITHUB_ENV
|
||||
echo BUILD_DATE=`date -u +%Y-%m-%dT%H:%M:%SZ` >> $GITHUB_ENV
|
||||
- name: Build and push (amd64)
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64
|
||||
push: true
|
||||
build-args: |
|
||||
VERSION=${{ env.VERSION }}
|
||||
COMMIT=${{ env.COMMIT }}
|
||||
BUILD_DATE=${{ env.BUILD_DATE }}
|
||||
tags: |
|
||||
${{ env.DOCKERHUB_REPO }}:latest-amd64
|
||||
${{ env.DOCKERHUB_REPO }}:${{ env.VERSION }}-amd64
|
||||
|
||||
docker_arm64:
|
||||
runs-on: ubuntu-24.04-arm
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Refresh models catalog
|
||||
run: |
|
||||
git fetch --depth 1 https://github.com/router-for-me/models.git main
|
||||
git show FETCH_HEAD:models.json > internal/registry/models/models.json
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Generate Build Metadata
|
||||
run: |
|
||||
echo "VERSION=${GITHUB_REF_NAME}" >> $GITHUB_ENV
|
||||
echo COMMIT=`git rev-parse --short HEAD` >> $GITHUB_ENV
|
||||
echo BUILD_DATE=`date -u +%Y-%m-%dT%H:%M:%SZ` >> $GITHUB_ENV
|
||||
- name: Build and push (arm64)
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/arm64
|
||||
push: true
|
||||
build-args: |
|
||||
VERSION=${{ env.VERSION }}
|
||||
COMMIT=${{ env.COMMIT }}
|
||||
BUILD_DATE=${{ env.BUILD_DATE }}
|
||||
tags: |
|
||||
${{ env.DOCKERHUB_REPO }}:latest-arm64
|
||||
${{ env.DOCKERHUB_REPO }}:${{ env.VERSION }}-arm64
|
||||
|
||||
docker_manifest:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- docker_amd64
|
||||
- docker_arm64
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Generate Build Metadata
|
||||
run: |
|
||||
echo "VERSION=${GITHUB_REF_NAME}" >> $GITHUB_ENV
|
||||
echo COMMIT=`git rev-parse --short HEAD` >> $GITHUB_ENV
|
||||
echo BUILD_DATE=`date -u +%Y-%m-%dT%H:%M:%SZ` >> $GITHUB_ENV
|
||||
- name: Create and push multi-arch manifests
|
||||
run: |
|
||||
docker buildx imagetools create \
|
||||
--tag "${DOCKERHUB_REPO}:latest" \
|
||||
"${DOCKERHUB_REPO}:latest-amd64" \
|
||||
"${DOCKERHUB_REPO}:latest-arm64"
|
||||
docker buildx imagetools create \
|
||||
--tag "${DOCKERHUB_REPO}:${VERSION}" \
|
||||
"${DOCKERHUB_REPO}:${VERSION}-amd64" \
|
||||
"${DOCKERHUB_REPO}:${VERSION}-arm64"
|
||||
- name: Cleanup temporary tags
|
||||
continue-on-error: true
|
||||
env:
|
||||
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
namespace="${DOCKERHUB_REPO%%/*}"
|
||||
repo_name="${DOCKERHUB_REPO#*/}"
|
||||
|
||||
token="$(
|
||||
curl -fsSL \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d "{\"username\":\"${DOCKERHUB_USERNAME}\",\"password\":\"${DOCKERHUB_TOKEN}\"}" \
|
||||
'https://hub.docker.com/v2/users/login/' \
|
||||
| python3 -c 'import json,sys; print(json.load(sys.stdin)["token"])'
|
||||
)"
|
||||
|
||||
delete_tag() {
|
||||
local tag="$1"
|
||||
local url="https://hub.docker.com/v2/repositories/${namespace}/${repo_name}/tags/${tag}/"
|
||||
local http_code
|
||||
http_code="$(curl -sS -o /dev/null -w "%{http_code}" -X DELETE -H "Authorization: JWT ${token}" "${url}" || true)"
|
||||
if [ "${http_code}" = "204" ] || [ "${http_code}" = "404" ]; then
|
||||
echo "Docker Hub tag removed (or missing): ${DOCKERHUB_REPO}:${tag} (HTTP ${http_code})"
|
||||
return 0
|
||||
fi
|
||||
echo "Docker Hub tag delete failed: ${DOCKERHUB_REPO}:${tag} (HTTP ${http_code})"
|
||||
return 0
|
||||
}
|
||||
|
||||
delete_tag "latest-amd64"
|
||||
delete_tag "latest-arm64"
|
||||
delete_tag "${VERSION}-amd64"
|
||||
delete_tag "${VERSION}-arm64"
|
||||
@@ -0,0 +1,28 @@
|
||||
name: translator-path-guard
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
- reopened
|
||||
|
||||
jobs:
|
||||
ensure-no-translator-changes:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Detect internal/translator changes
|
||||
id: changed-files
|
||||
uses: tj-actions/changed-files@v45
|
||||
with:
|
||||
files: |
|
||||
internal/translator/**
|
||||
- name: Fail when restricted paths change
|
||||
if: steps.changed-files.outputs.any_changed == 'true'
|
||||
run: |
|
||||
echo "Changes under internal/translator are not allowed in pull requests."
|
||||
echo "You need to create an issue for our maintenance team to make the necessary changes."
|
||||
exit 1
|
||||
@@ -0,0 +1,27 @@
|
||||
name: pr-test-build
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Refresh models catalog
|
||||
run: |
|
||||
git fetch --depth 1 https://github.com/router-for-me/models.git main
|
||||
git show FETCH_HEAD:models.json > internal/registry/models/models.json
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
cache: true
|
||||
- name: Build
|
||||
run: |
|
||||
go build -o test-output ./cmd/server
|
||||
rm -f test-output
|
||||
@@ -0,0 +1,677 @@
|
||||
name: release
|
||||
|
||||
on:
|
||||
push:
|
||||
# run only against tags
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
env:
|
||||
GH_REPO: ${{ github.repository }}
|
||||
GO_VERSION: '1.26.4'
|
||||
|
||||
jobs:
|
||||
prepare-release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
- name: Create release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
release_notes_file="$(mktemp)"
|
||||
generated_notes_file="$(mktemp)"
|
||||
changelog_entries_file="$(mktemp)"
|
||||
changelog_notes_file="$(mktemp)"
|
||||
updated_notes_file="$(mktemp)"
|
||||
trap 'rm -f "$release_notes_file" "$generated_notes_file" "$changelog_entries_file" "$changelog_notes_file" "$updated_notes_file"' EXIT
|
||||
|
||||
cat > "$release_notes_file" <<'EOF'
|
||||
<!-- cliproxyapi-linux-release-assets:start -->
|
||||
## Linux release assets
|
||||
|
||||
- `CLIProxyAPI_<version>_linux_<arch>.tar.gz` is the default Linux build. It supports dynamic library plugins and is built against a GLIBC 2.17 baseline.
|
||||
- `CLIProxyAPI_<version>_linux_<arch>_no-plugin.tar.gz` is the portable Linux build for musl-based or older systems such as OpenWrt. It does not support dynamic library plugins.
|
||||
|
||||
## FreeBSD release assets
|
||||
|
||||
- `CLIProxyAPI_<version>_freebsd_aarch64_no-plugin.tar.gz` is the FreeBSD arm64 build. It is built without CGO and does not support dynamic library plugins.
|
||||
|
||||
<!-- cliproxyapi-linux-release-assets:end -->
|
||||
EOF
|
||||
|
||||
git fetch --force --tags
|
||||
previous_tag=""
|
||||
if previous_tag_value="$(git describe --tags --abbrev=0 "${GITHUB_REF_NAME}^" 2>/dev/null)"; then
|
||||
previous_tag="$previous_tag_value"
|
||||
changelog_range="${previous_tag}..${GITHUB_REF_NAME}"
|
||||
else
|
||||
changelog_range="$GITHUB_REF_NAME"
|
||||
fi
|
||||
|
||||
git log --reverse --pretty=format:'- %s (%h)' "$changelog_range" |
|
||||
grep -Ev '^- (docs:|test:)' > "$changelog_entries_file" || true
|
||||
|
||||
gh api "repos/${GH_REPO}/releases/generate-notes" \
|
||||
-f tag_name="$GITHUB_REF_NAME" \
|
||||
--jq .body > "$generated_notes_file"
|
||||
if [[ ! -s "$generated_notes_file" ]]; then
|
||||
if [[ -n "$previous_tag" ]]; then
|
||||
printf '**Full Changelog**: https://github.com/%s/compare/%s...%s\n' "$GH_REPO" "$previous_tag" "$GITHUB_REF_NAME" > "$generated_notes_file"
|
||||
else
|
||||
printf '**Full Changelog**: https://github.com/%s/commits/%s\n' "$GH_REPO" "$GITHUB_REF_NAME" > "$generated_notes_file"
|
||||
fi
|
||||
fi
|
||||
|
||||
{
|
||||
if [[ -s "$changelog_entries_file" ]]; then
|
||||
printf '## Changelog\n\n'
|
||||
cat "$changelog_entries_file"
|
||||
printf '\n\n'
|
||||
fi
|
||||
cat "$generated_notes_file"
|
||||
} > "$changelog_notes_file"
|
||||
|
||||
{
|
||||
cat "$release_notes_file"
|
||||
printf '\n'
|
||||
cat "$changelog_notes_file"
|
||||
} > "$updated_notes_file"
|
||||
|
||||
if gh release view "$GITHUB_REF_NAME" >/dev/null 2>&1; then
|
||||
gh release edit "$GITHUB_REF_NAME" --title "$GITHUB_REF_NAME" --notes-file "$updated_notes_file"
|
||||
else
|
||||
gh release create "$GITHUB_REF_NAME" --title "$GITHUB_REF_NAME" --notes-file "$updated_notes_file"
|
||||
fi
|
||||
|
||||
build-hosted:
|
||||
name: build ${{ matrix.target }}
|
||||
needs: prepare-release
|
||||
runs-on: ${{ matrix.runner }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- target: darwin-amd64
|
||||
runner: macos-15-intel
|
||||
goos: darwin
|
||||
goarch: amd64
|
||||
asset_arch: amd64
|
||||
archive_format: tar.gz
|
||||
- target: darwin-arm64
|
||||
runner: macos-15
|
||||
goos: darwin
|
||||
goarch: arm64
|
||||
asset_arch: aarch64
|
||||
archive_format: tar.gz
|
||||
- target: windows-amd64
|
||||
runner: windows-latest
|
||||
goos: windows
|
||||
goarch: amd64
|
||||
asset_arch: amd64
|
||||
archive_format: zip
|
||||
- target: windows-arm64
|
||||
runner: windows-11-arm
|
||||
goos: windows
|
||||
goarch: arm64
|
||||
asset_arch: aarch64
|
||||
archive_format: zip
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Refresh models catalog
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
git fetch --depth 1 https://github.com/router-for-me/models.git main
|
||||
git show FETCH_HEAD:models.json > internal/registry/models/models.json
|
||||
- name: Fetch tags
|
||||
shell: bash
|
||||
run: git fetch --force --tags
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache: true
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: go-${{ runner.os }}-${{ runner.arch }}-${{ matrix.target }}-${{ hashFiles('go.sum') }}
|
||||
restore-keys: |
|
||||
go-${{ runner.os }}-${{ runner.arch }}-${{ matrix.target }}-
|
||||
go-${{ runner.os }}-${{ runner.arch }}-
|
||||
- name: Generate Build Metadata
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
echo "RELEASE_VERSION=${GITHUB_REF_NAME#v}" >> "$GITHUB_ENV"
|
||||
echo "COMMIT=$(git rev-parse --short HEAD)" >> "$GITHUB_ENV"
|
||||
echo "BUILD_DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$GITHUB_ENV"
|
||||
- name: Build archive
|
||||
shell: bash
|
||||
env:
|
||||
TARGET: ${{ matrix.target }}
|
||||
GOOS: ${{ matrix.goos }}
|
||||
GOARCH: ${{ matrix.goarch }}
|
||||
ASSET_ARCH: ${{ matrix.asset_arch }}
|
||||
ARCHIVE_FORMAT: ${{ matrix.archive_format }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
binary_name="cli-proxy-api"
|
||||
if [[ "$GOOS" == "windows" ]]; then
|
||||
binary_name="cli-proxy-api.exe"
|
||||
fi
|
||||
|
||||
archive_dir="dist/${TARGET}/archive"
|
||||
archive_name="CLIProxyAPI_${RELEASE_VERSION}_${GOOS}_${ASSET_ARCH}.${ARCHIVE_FORMAT}"
|
||||
rm -rf "dist/${TARGET}"
|
||||
mkdir -p "$archive_dir"
|
||||
|
||||
CGO_ENABLED=1 GOOS="$GOOS" GOARCH="$GOARCH" go build \
|
||||
-ldflags="-s -w -X main.Version=${RELEASE_VERSION} -X main.Commit=${COMMIT} -X main.BuildDate=${BUILD_DATE}" \
|
||||
-o "$archive_dir/$binary_name" ./cmd/server/
|
||||
|
||||
cp LICENSE README.md README_CN.md config.example.yaml "$archive_dir/"
|
||||
if [[ "$ARCHIVE_FORMAT" == "zip" ]]; then
|
||||
powershell -NoProfile -Command "Compress-Archive -Path '${archive_dir}/*' -DestinationPath 'dist/${archive_name}' -Force"
|
||||
else
|
||||
tar -C "$archive_dir" -czf "dist/$archive_name" "$binary_name" LICENSE README.md README_CN.md config.example.yaml
|
||||
fi
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.target }}
|
||||
path: dist/CLIProxyAPI_*
|
||||
if-no-files-found: error
|
||||
- name: Upload release assets
|
||||
shell: bash
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
shopt -s nullglob
|
||||
assets=(dist/CLIProxyAPI_*.tar.gz dist/CLIProxyAPI_*.zip)
|
||||
if [[ ${#assets[@]} -eq 0 ]]; then
|
||||
printf 'expected archive assets, found %s\n' "${#assets[@]}" >&2
|
||||
printf '%s\n' "${assets[@]}" >&2
|
||||
exit 1
|
||||
fi
|
||||
gh release upload "$GITHUB_REF_NAME" "${assets[@]}" --clobber
|
||||
- name: Refresh release checksums
|
||||
continue-on-error: true
|
||||
shell: bash
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
tmp_dir="$(mktemp -d)"
|
||||
trap 'rm -rf "$tmp_dir"' EXIT
|
||||
gh release download "$GITHUB_REF_NAME" \
|
||||
--pattern 'CLIProxyAPI_*.tar.gz' \
|
||||
--pattern 'CLIProxyAPI_*.zip' \
|
||||
--dir "$tmp_dir" \
|
||||
--clobber
|
||||
(
|
||||
cd "$tmp_dir"
|
||||
shopt -s nullglob
|
||||
archives=(CLIProxyAPI_*.tar.gz CLIProxyAPI_*.zip)
|
||||
if [[ ${#archives[@]} -eq 0 ]]; then
|
||||
echo "No release archives found"
|
||||
exit 0
|
||||
fi
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
sha256sum "${archives[@]}" | sort -k2 > checksums.txt
|
||||
else
|
||||
shasum -a 256 "${archives[@]}" | sort -k2 > checksums.txt
|
||||
fi
|
||||
)
|
||||
gh release upload "$GITHUB_REF_NAME" "$tmp_dir/checksums.txt" --clobber
|
||||
|
||||
build-linux-glibc:
|
||||
name: build linux-${{ matrix.goarch }} glibc
|
||||
needs: prepare-release
|
||||
runs-on: ${{ matrix.runner }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- target: linux-amd64
|
||||
runner: ubuntu-latest
|
||||
goarch: amd64
|
||||
asset_arch: amd64
|
||||
manylinux_image: quay.io/pypa/manylinux2014_x86_64
|
||||
- target: linux-arm64
|
||||
runner: ubuntu-24.04-arm
|
||||
goarch: arm64
|
||||
asset_arch: aarch64
|
||||
manylinux_image: quay.io/pypa/manylinux2014_aarch64
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Refresh models catalog
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
git fetch --depth 1 https://github.com/router-for-me/models.git main
|
||||
git show FETCH_HEAD:models.json > internal/registry/models/models.json
|
||||
- name: Fetch tags
|
||||
shell: bash
|
||||
run: git fetch --force --tags
|
||||
- name: Generate Build Metadata
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
echo "RELEASE_VERSION=${GITHUB_REF_NAME#v}" >> "$GITHUB_ENV"
|
||||
echo "COMMIT=$(git rev-parse --short HEAD)" >> "$GITHUB_ENV"
|
||||
echo "BUILD_DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$GITHUB_ENV"
|
||||
- name: Build archive
|
||||
shell: bash
|
||||
env:
|
||||
TARGET: ${{ matrix.target }}
|
||||
GOARCH: ${{ matrix.goarch }}
|
||||
ASSET_ARCH: ${{ matrix.asset_arch }}
|
||||
MANYLINUX_IMAGE: ${{ matrix.manylinux_image }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
archive_dir="dist/${TARGET}/archive"
|
||||
archive_name="CLIProxyAPI_${RELEASE_VERSION}_linux_${ASSET_ARCH}.tar.gz"
|
||||
rm -rf "dist/${TARGET}"
|
||||
mkdir -p "$archive_dir"
|
||||
|
||||
docker run --rm \
|
||||
-v "$PWD:/src" \
|
||||
-w /src \
|
||||
-e GO_VERSION \
|
||||
-e GOARCH \
|
||||
-e RELEASE_VERSION \
|
||||
-e COMMIT \
|
||||
-e BUILD_DATE \
|
||||
"$MANYLINUX_IMAGE" \
|
||||
bash -euo pipefail -c '
|
||||
go_archive="go${GO_VERSION}.linux-${GOARCH}.tar.gz"
|
||||
curl -fsSL "https://go.dev/dl/${go_archive}" -o "/tmp/${go_archive}"
|
||||
rm -rf /usr/local/go
|
||||
tar -C /usr/local -xzf "/tmp/${go_archive}"
|
||||
export PATH="/usr/local/go/bin:${PATH}"
|
||||
|
||||
CGO_ENABLED=1 GOOS=linux GOARCH="${GOARCH}" go build -buildvcs=false \
|
||||
-ldflags="-s -w -X main.Version=${RELEASE_VERSION} -X main.Commit=${COMMIT} -X main.BuildDate=${BUILD_DATE}" \
|
||||
-o "'"$archive_dir"'/cli-proxy-api" ./cmd/server/
|
||||
|
||||
glibc_versions="$(readelf --version-info "'"$archive_dir"'/cli-proxy-api" | sed -n "s/.*Name: GLIBC_\([0-9.]*\).*/\1/p" | sort -Vu)"
|
||||
if [[ -n "${glibc_versions}" ]]; then
|
||||
printf "GLIBC versions:\n%s\n" "${glibc_versions}"
|
||||
max_glibc="$(printf "%s\n" "${glibc_versions}" | sort -V | tail -n 1)"
|
||||
if [[ "$(printf "2.17\n%s\n" "${max_glibc}" | sort -V | tail -n 1)" != "2.17" ]]; then
|
||||
printf "linux ${GOARCH} binary requires GLIBC_%s, expected GLIBC_2.17 or older\n" "${max_glibc}" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
'
|
||||
|
||||
cp LICENSE README.md README_CN.md config.example.yaml "$archive_dir/"
|
||||
tar -C "$archive_dir" -czf "dist/$archive_name" cli-proxy-api LICENSE README.md README_CN.md config.example.yaml
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.target }}
|
||||
path: dist/CLIProxyAPI_*
|
||||
if-no-files-found: error
|
||||
- name: Upload release assets
|
||||
shell: bash
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
shopt -s nullglob
|
||||
assets=(dist/CLIProxyAPI_*.tar.gz)
|
||||
if [[ ${#assets[@]} -eq 0 ]]; then
|
||||
printf 'expected archive assets, found %s\n' "${#assets[@]}" >&2
|
||||
printf '%s\n' "${assets[@]}" >&2
|
||||
exit 1
|
||||
fi
|
||||
gh release upload "$GITHUB_REF_NAME" "${assets[@]}" --clobber
|
||||
- name: Refresh release checksums
|
||||
continue-on-error: true
|
||||
shell: bash
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
tmp_dir="$(mktemp -d)"
|
||||
trap 'rm -rf "$tmp_dir"' EXIT
|
||||
gh release download "$GITHUB_REF_NAME" \
|
||||
--pattern 'CLIProxyAPI_*.tar.gz' \
|
||||
--pattern 'CLIProxyAPI_*.zip' \
|
||||
--dir "$tmp_dir" \
|
||||
--clobber
|
||||
(
|
||||
cd "$tmp_dir"
|
||||
shopt -s nullglob
|
||||
archives=(CLIProxyAPI_*.tar.gz CLIProxyAPI_*.zip)
|
||||
if [[ ${#archives[@]} -eq 0 ]]; then
|
||||
echo "No release archives found"
|
||||
exit 0
|
||||
fi
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
sha256sum "${archives[@]}" | sort -k2 > checksums.txt
|
||||
else
|
||||
shasum -a 256 "${archives[@]}" | sort -k2 > checksums.txt
|
||||
fi
|
||||
)
|
||||
gh release upload "$GITHUB_REF_NAME" "$tmp_dir/checksums.txt" --clobber
|
||||
|
||||
build-linux-no-plugin:
|
||||
name: build linux-${{ matrix.goarch }} no-plugin
|
||||
needs: prepare-release
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- target: linux-amd64-no-plugin
|
||||
goarch: amd64
|
||||
asset_arch: amd64
|
||||
- target: linux-arm64-no-plugin
|
||||
goarch: arm64
|
||||
asset_arch: aarch64
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Refresh models catalog
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
git fetch --depth 1 https://github.com/router-for-me/models.git main
|
||||
git show FETCH_HEAD:models.json > internal/registry/models/models.json
|
||||
- name: Fetch tags
|
||||
shell: bash
|
||||
run: git fetch --force --tags
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache: true
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: go-linux-no-plugin-${{ matrix.goarch }}-${{ hashFiles('go.sum') }}
|
||||
restore-keys: |
|
||||
go-linux-no-plugin-${{ matrix.goarch }}-
|
||||
go-linux-no-plugin-
|
||||
- name: Generate Build Metadata
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
echo "RELEASE_VERSION=${GITHUB_REF_NAME#v}" >> "$GITHUB_ENV"
|
||||
echo "COMMIT=$(git rev-parse --short HEAD)" >> "$GITHUB_ENV"
|
||||
echo "BUILD_DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$GITHUB_ENV"
|
||||
- name: Build archive
|
||||
shell: bash
|
||||
env:
|
||||
TARGET: ${{ matrix.target }}
|
||||
GOARCH: ${{ matrix.goarch }}
|
||||
ASSET_ARCH: ${{ matrix.asset_arch }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
archive_dir="dist/${TARGET}/archive"
|
||||
archive_name="CLIProxyAPI_${RELEASE_VERSION}_linux_${ASSET_ARCH}_no-plugin.tar.gz"
|
||||
rm -rf "dist/${TARGET}"
|
||||
mkdir -p "$archive_dir"
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH="$GOARCH" go build -buildvcs=false \
|
||||
-ldflags="-s -w -X main.Version=${RELEASE_VERSION} -X main.Commit=${COMMIT} -X main.BuildDate=${BUILD_DATE}" \
|
||||
-o "$archive_dir/cli-proxy-api" ./cmd/server/
|
||||
|
||||
if readelf -l "$archive_dir/cli-proxy-api" | grep -q 'Requesting program interpreter'; then
|
||||
readelf -l "$archive_dir/cli-proxy-api" >&2
|
||||
echo "no-plugin linux binary must not require a dynamic interpreter" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cp LICENSE README.md README_CN.md config.example.yaml "$archive_dir/"
|
||||
tar -C "$archive_dir" -czf "dist/$archive_name" cli-proxy-api LICENSE README.md README_CN.md config.example.yaml
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.target }}
|
||||
path: dist/CLIProxyAPI_*
|
||||
if-no-files-found: error
|
||||
- name: Upload release assets
|
||||
shell: bash
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
shopt -s nullglob
|
||||
assets=(dist/CLIProxyAPI_*.tar.gz)
|
||||
if [[ ${#assets[@]} -eq 0 ]]; then
|
||||
printf 'expected archive assets, found %s\n' "${#assets[@]}" >&2
|
||||
printf '%s\n' "${assets[@]}" >&2
|
||||
exit 1
|
||||
fi
|
||||
gh release upload "$GITHUB_REF_NAME" "${assets[@]}" --clobber
|
||||
- name: Refresh release checksums
|
||||
continue-on-error: true
|
||||
shell: bash
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
tmp_dir="$(mktemp -d)"
|
||||
trap 'rm -rf "$tmp_dir"' EXIT
|
||||
gh release download "$GITHUB_REF_NAME" \
|
||||
--pattern 'CLIProxyAPI_*.tar.gz' \
|
||||
--pattern 'CLIProxyAPI_*.zip' \
|
||||
--dir "$tmp_dir" \
|
||||
--clobber
|
||||
(
|
||||
cd "$tmp_dir"
|
||||
shopt -s nullglob
|
||||
archives=(CLIProxyAPI_*.tar.gz CLIProxyAPI_*.zip)
|
||||
if [[ ${#archives[@]} -eq 0 ]]; then
|
||||
echo "No release archives found"
|
||||
exit 0
|
||||
fi
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
sha256sum "${archives[@]}" | sort -k2 > checksums.txt
|
||||
else
|
||||
shasum -a 256 "${archives[@]}" | sort -k2 > checksums.txt
|
||||
fi
|
||||
)
|
||||
gh release upload "$GITHUB_REF_NAME" "$tmp_dir/checksums.txt" --clobber
|
||||
|
||||
build-freebsd:
|
||||
name: build ${{ matrix.target }}
|
||||
needs: prepare-release
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TARGET: ${{ matrix.target }}
|
||||
GOARCH: ${{ matrix.goarch }}
|
||||
ASSET_ARCH: ${{ matrix.asset_arch }}
|
||||
ASSET_SUFFIX: ${{ matrix.asset_suffix }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- target: freebsd-amd64
|
||||
goarch: amd64
|
||||
asset_arch: amd64
|
||||
asset_suffix: ''
|
||||
cgo_enabled: true
|
||||
- target: freebsd-arm64-no-plugin
|
||||
goarch: arm64
|
||||
asset_arch: aarch64
|
||||
asset_suffix: _no-plugin
|
||||
cgo_enabled: false
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Refresh models catalog
|
||||
run: |
|
||||
git fetch --depth 1 https://github.com/router-for-me/models.git main
|
||||
git show FETCH_HEAD:models.json > internal/registry/models/models.json
|
||||
- name: Fetch tags
|
||||
run: git fetch --force --tags
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache: true
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: go-freebsd-${{ matrix.goarch }}-${{ hashFiles('go.sum') }}
|
||||
restore-keys: |
|
||||
go-freebsd-${{ matrix.goarch }}-
|
||||
go-freebsd-
|
||||
- name: Generate Build Metadata
|
||||
id: metadata
|
||||
run: |
|
||||
set -euo pipefail
|
||||
release_version="${GITHUB_REF_NAME#v}"
|
||||
commit="$(git rev-parse --short HEAD)"
|
||||
build_date="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
echo "RELEASE_VERSION=$release_version" >> "$GITHUB_ENV"
|
||||
echo "COMMIT=$commit" >> "$GITHUB_ENV"
|
||||
echo "BUILD_DATE=$build_date" >> "$GITHUB_ENV"
|
||||
echo "release_version=$release_version" >> "$GITHUB_OUTPUT"
|
||||
echo "commit=$commit" >> "$GITHUB_OUTPUT"
|
||||
echo "build_date=$build_date" >> "$GITHUB_OUTPUT"
|
||||
- name: Prepare FreeBSD output
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
rm -rf "dist/${TARGET}"
|
||||
- name: Install FreeBSD cross-build dependencies
|
||||
if: ${{ matrix.cgo_enabled }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y clang lld wget
|
||||
- name: Build FreeBSD binary with CGO
|
||||
if: ${{ matrix.cgo_enabled }}
|
||||
timeout-minutes: 45
|
||||
uses: go-cross/cgo-actions@v1
|
||||
with:
|
||||
dir: .
|
||||
packages: ./cmd/server/
|
||||
targets: ${{ env.TARGET }}
|
||||
out-dir: dist/${{ env.TARGET }}/bin
|
||||
output: cli-proxy-api
|
||||
flags: >-
|
||||
-ldflags=-s -w
|
||||
-X main.Version=${{ steps.metadata.outputs.release_version }}
|
||||
-X main.Commit=${{ steps.metadata.outputs.commit }}
|
||||
-X main.BuildDate=${{ steps.metadata.outputs.build_date }}
|
||||
- name: Build FreeBSD no-plugin binary
|
||||
if: ${{ !matrix.cgo_enabled }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p "dist/${TARGET}/bin"
|
||||
CGO_ENABLED=0 GOOS=freebsd GOARCH="$GOARCH" go build -buildvcs=false \
|
||||
-ldflags="-s -w -X main.Version=${RELEASE_VERSION} -X main.Commit=${COMMIT} -X main.BuildDate=${BUILD_DATE}" \
|
||||
-o "dist/${TARGET}/bin/cli-proxy-api" ./cmd/server/
|
||||
- name: Package FreeBSD archive
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
archive_dir="dist/${TARGET}/archive"
|
||||
archive_name="CLIProxyAPI_${RELEASE_VERSION}_freebsd_${ASSET_ARCH}${ASSET_SUFFIX}.tar.gz"
|
||||
mkdir -p "$archive_dir"
|
||||
|
||||
echo "Packaging ${archive_name}"
|
||||
cp "dist/${TARGET}/bin/cli-proxy-api" "$archive_dir/cli-proxy-api"
|
||||
cp LICENSE README.md README_CN.md config.example.yaml "$archive_dir/"
|
||||
tar -C "$archive_dir" -czf "dist/$archive_name" cli-proxy-api LICENSE README.md README_CN.md config.example.yaml
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.target }}
|
||||
path: dist/CLIProxyAPI_*
|
||||
if-no-files-found: error
|
||||
- name: Upload release assets
|
||||
shell: bash
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
shopt -s nullglob
|
||||
assets=(dist/CLIProxyAPI_*.tar.gz)
|
||||
if [[ ${#assets[@]} -eq 0 ]]; then
|
||||
printf 'expected archive assets, found %s\n' "${#assets[@]}" >&2
|
||||
printf '%s\n' "${assets[@]}" >&2
|
||||
exit 1
|
||||
fi
|
||||
gh release upload "$GITHUB_REF_NAME" "${assets[@]}" --clobber
|
||||
- name: Refresh release checksums
|
||||
continue-on-error: true
|
||||
shell: bash
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
tmp_dir="$(mktemp -d)"
|
||||
trap 'rm -rf "$tmp_dir"' EXIT
|
||||
gh release download "$GITHUB_REF_NAME" \
|
||||
--pattern 'CLIProxyAPI_*.tar.gz' \
|
||||
--pattern 'CLIProxyAPI_*.zip' \
|
||||
--dir "$tmp_dir" \
|
||||
--clobber
|
||||
(
|
||||
cd "$tmp_dir"
|
||||
shopt -s nullglob
|
||||
archives=(CLIProxyAPI_*.tar.gz CLIProxyAPI_*.zip)
|
||||
if [[ ${#archives[@]} -eq 0 ]]; then
|
||||
echo "No release archives found"
|
||||
exit 0
|
||||
fi
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
sha256sum "${archives[@]}" | sort -k2 > checksums.txt
|
||||
else
|
||||
shasum -a 256 "${archives[@]}" | sort -k2 > checksums.txt
|
||||
fi
|
||||
)
|
||||
gh release upload "$GITHUB_REF_NAME" "$tmp_dir/checksums.txt" --clobber
|
||||
|
||||
publish-checksums:
|
||||
runs-on: ubuntu-latest
|
||||
if: always()
|
||||
needs:
|
||||
- build-hosted
|
||||
- build-linux-glibc
|
||||
- build-linux-no-plugin
|
||||
- build-freebsd
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: dist
|
||||
merge-multiple: true
|
||||
- name: Publish final checksums
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cd dist
|
||||
shopt -s nullglob
|
||||
archives=(CLIProxyAPI_*.tar.gz CLIProxyAPI_*.zip)
|
||||
if [[ ${#archives[@]} -eq 0 ]]; then
|
||||
echo "No release archives found"
|
||||
exit 0
|
||||
fi
|
||||
sha256sum "${archives[@]}" | sort -k2 > checksums.txt
|
||||
gh release upload "$GITHUB_REF_NAME" checksums.txt --clobber
|
||||
Reference in New Issue
Block a user