Skip to content

Publish CLIProxyAPI Pro Management #120

Publish CLIProxyAPI Pro Management

Publish CLIProxyAPI Pro Management #120

name: Publish CLIProxyAPI Pro Management
on:
workflow_dispatch:
schedule:
- cron: '0 20 * * *'
jobs:
check-version:
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
should_release: ${{ steps.compare.outputs.should_release }}
target_release_tag: ${{ steps.compare.outputs.target_release_tag }}
current_management_tag: ${{ steps.compare.outputs.current_management_tag }}
upstream_tag: ${{ steps.compare.outputs.upstream_tag }}
upstream_sha: ${{ steps.compare.outputs.upstream_sha }}
upstream_base_version: ${{ steps.compare.outputs.upstream_base_version }}
build_version: ${{ steps.compare.outputs.build_version }}
steps:
- name: Compare latest management release
id: compare
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CURRENT_REPO: ${{ github.repository }}
UPSTREAM_REPO: router-for-me/Cli-Proxy-API-Management-Center
run: |
set -euo pipefail
normalize_version() {
local version="$1"
version="${version#v}"
version="${version%-pro}"
echo "${version}"
}
version_gt() {
local left="$1"
local right="$2"
[ "$(printf '%s\n%s\n' "${right}" "${left}" | sort -V | tail -n 1)" = "${left}" ] && [ "${left}" != "${right}" ]
}
target_release_tag="$(gh release view --repo "${CURRENT_REPO}" --json tagName --jq '.tagName' 2>/dev/null || true)"
upstream_tag="$(gh release view --repo "${UPSTREAM_REPO}" --json tagName --jq '.tagName')"
if [ -z "${upstream_tag}" ]; then
echo "No upstream latest release found." >&2
exit 1
fi
upstream_sha="$(gh api "repos/${UPSTREAM_REPO}/commits/${upstream_tag}" --jq '.sha')"
if [ -z "${target_release_tag}" ]; then
echo "No current Pro release found. Management-only update will wait for the core release workflow."
echo "should_release=false" >> "${GITHUB_OUTPUT}"
echo "target_release_tag=" >> "${GITHUB_OUTPUT}"
echo "current_management_tag=" >> "${GITHUB_OUTPUT}"
echo "upstream_tag=${upstream_tag}" >> "${GITHUB_OUTPUT}"
echo "upstream_sha=${upstream_sha}" >> "${GITHUB_OUTPUT}"
echo "upstream_base_version=$(normalize_version "${upstream_tag}")" >> "${GITHUB_OUTPUT}"
echo "build_version=v$(normalize_version "${upstream_tag}")-pro" >> "${GITHUB_OUTPUT}"
exit 0
fi
current_body="$(gh release view "${target_release_tag}" --repo "${CURRENT_REPO}" --json body --jq '.body // ""')"
current_management_tag="$(printf '%s\n' "${current_body}" | sed -n 's/^- Management upstream release: //p' | head -n 1)"
has_management_asset="$(gh release view "${target_release_tag}" --repo "${CURRENT_REPO}" --json assets --jq 'any(.assets[]; .name == "management.html")')"
upstream_base_version="$(normalize_version "${upstream_tag}")"
current_base_version="0.0.0"
if [ -n "${current_management_tag}" ]; then
current_base_version="$(normalize_version "${current_management_tag}")"
fi
build_version="v${upstream_base_version}-pro"
should_release="false"
if [ "${GITHUB_EVENT_NAME}" = "workflow_dispatch" ]; then
should_release="true"
elif [ "${has_management_asset}" != "true" ]; then
should_release="true"
elif version_gt "${upstream_base_version}" "${current_base_version}"; then
should_release="true"
fi
echo "target_release_tag=${target_release_tag}"
echo "current_management_tag=${current_management_tag:-none}"
echo "current_base_version=${current_base_version}"
echo "upstream_tag=${upstream_tag}"
echo "upstream_sha=${upstream_sha}"
echo "upstream_base_version=${upstream_base_version}"
echo "build_version=${build_version}"
echo "has_management_asset=${has_management_asset}"
echo "should_release=${should_release}"
echo "target_release_tag=${target_release_tag}" >> "${GITHUB_OUTPUT}"
echo "current_management_tag=${current_management_tag}" >> "${GITHUB_OUTPUT}"
echo "upstream_tag=${upstream_tag}" >> "${GITHUB_OUTPUT}"
echo "upstream_sha=${upstream_sha}" >> "${GITHUB_OUTPUT}"
echo "upstream_base_version=${upstream_base_version}" >> "${GITHUB_OUTPUT}"
echo "build_version=${build_version}" >> "${GITHUB_OUTPUT}"
echo "should_release=${should_release}" >> "${GITHUB_OUTPUT}"
validate-repository:
needs: check-version
if: needs.check-version.outputs.should_release == 'true'
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout customizations
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.x'
- name: Set up Go for actionlint
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: stable
cache: false
- name: Install actionlint
env:
GOBIN: ${{ runner.temp }}/validation-bin
run: |
go install github.com/rhysd/actionlint/cmd/[email protected]
echo "${GOBIN}" >> "${GITHUB_PATH}"
- name: Validate repository sources
env:
VALIDATION_REQUIRE_TOOLS: "1"
run: bash scripts/validation/repo.sh
validate-management:
needs: check-version
if: needs.check-version.outputs.should_release == 'true'
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: read
steps:
- name: Checkout customizations
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: customizations-repo
- name: Checkout Management upstream release
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: router-for-me/Cli-Proxy-API-Management-Center
ref: ${{ needs.check-version.outputs.upstream_sha }}
path: upstream
- name: Set up Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version-file: upstream/package.json
- name: Cache Bun dependencies
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.bun/install/cache
key: ${{ runner.os }}-bun-${{ hashFiles('upstream/bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-
- name: Validate Management customization
env:
VERSION: ${{ needs.check-version.outputs.build_version }}
run: bash customizations-repo/scripts/validation/management.sh upstream
build-and-release:
needs:
- check-version
- validate-repository
- validate-management
if: needs.check-version.outputs.should_release == 'true'
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout customizations
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: customizations-repo
fetch-depth: 0
fetch-tags: true
- name: Checkout management upstream release
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: router-for-me/Cli-Proxy-API-Management-Center
ref: ${{ needs.check-version.outputs.upstream_sha }}
path: upstream
fetch-depth: 0
fetch-tags: true
- name: Apply Pro customizations
run: bash customizations-repo/cliproxyapi-pro-management/apply.sh upstream
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version-file: upstream/package.json
- name: Cache Bun dependencies
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.bun/install/cache
key: ${{ runner.os }}-bun-${{ hashFiles('upstream/bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-
- name: Install dependencies
working-directory: upstream
run: bun install --frozen-lockfile
- name: Build all-in-one HTML
working-directory: upstream
env:
VERSION: ${{ needs.check-version.outputs.build_version }}
run: bun run build
- name: Prepare release asset
working-directory: upstream
run: |
set -euo pipefail
cd dist
mv index.html management.html
ls -lh management.html
- name: Update release notes and upload management asset
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CURRENT_REPO: ${{ github.repository }}
TARGET_RELEASE_TAG: ${{ needs.check-version.outputs.target_release_tag }}
MANAGEMENT_TAG: ${{ needs.check-version.outputs.upstream_tag }}
MANAGEMENT_BUILD_VERSION: ${{ needs.check-version.outputs.build_version }}
MANAGEMENT_SHA: ${{ github.sha }}
run: |
set -euo pipefail
gh release view "${TARGET_RELEASE_TAG}" --repo "${CURRENT_REPO}" --json body --jq '.body // ""' > current-release-notes.md
gh release view "${MANAGEMENT_TAG}" --repo router-for-me/Cli-Proxy-API-Management-Center --json body --jq '.body // ""' > management-upstream-notes.md
management_sha="$(git -C upstream rev-parse HEAD)"
customization_sha="$(git -C customizations-repo rev-parse HEAD)"
export MANAGEMENT_SHA="${management_sha}"
export CUSTOMIZATION_SHA="${customization_sha}"
python3 - <<'PY'
from pathlib import Path
import os
body = Path('current-release-notes.md').read_text()
upstream_notes = Path('management-upstream-notes.md').read_text().strip()
management_tag = os.environ['MANAGEMENT_TAG']
management_build_version = os.environ['MANAGEMENT_BUILD_VERSION']
management_sha = os.environ['MANAGEMENT_SHA']
customization_sha = os.environ['CUSTOMIZATION_SHA']
def replace_line(text, prefix, line):
lines = text.splitlines()
replaced = False
for index, current in enumerate(lines):
if current.startswith(prefix):
lines[index] = line
replaced = True
break
if not replaced:
lines.append(line)
return '\n'.join(lines) + ('\n' if text.endswith('\n') or lines else '')
body = replace_line(body, '- Management upstream release:', f'- Management upstream release: {management_tag}')
body = replace_line(body, '- Management build version:', f'- Management build version: {management_build_version}')
body = replace_line(body, '- Management upstream commit:', f'- Management upstream commit: {management_sha}')
body = replace_line(body, '- Customization commit:', f'- Customization commit: {customization_sha}')
start = '<!-- cli-proxyapi-pro-management-start -->'
end = '<!-- cli-proxyapi-pro-management-end -->'
section = (
f'{start}\n'
'## Management upstream release notes\n\n'
f'{upstream_notes if upstream_notes else "No management upstream release notes were provided."}\n'
f'{end}'
)
if start in body and end in body:
before = body.split(start, 1)[0].rstrip()
after = body.split(end, 1)[1].lstrip()
body = f'{before}\n\n{section}\n'
if after:
body += f'\n{after}'
else:
body = body.rstrip() + f'\n\n{section}\n'
Path('release-notes.md').write_text(body)
PY
gh release edit "${TARGET_RELEASE_TAG}" \
--repo "${CURRENT_REPO}" \
--notes-file release-notes.md
gh release upload "${TARGET_RELEASE_TAG}" \
upstream/dist/management.html \
--repo "${CURRENT_REPO}" \
--clobber
cleanup-runs:
runs-on: ubuntu-latest
needs: build-and-release
permissions:
actions: write
contents: read
steps:
- name: Delete old workflow runs
uses: Mattraks/delete-workflow-runs@0cf693bc9909e5e867ee8f27b813224ba862939c # v2
with:
token: ${{ secrets.GITHUB_TOKEN }}
repository: ${{ github.repository }}
retain_days: 7
keep_minimum_runs: 6