feat:移除了弹窗,服务器添加sls

This commit is contained in:
2026-09-08 22:39:45 +08:00
commit 6a295f9a7a
4082 changed files with 1322534 additions and 0 deletions

3
.github/workflows/COPYING.md vendored Normal file
View File

@ -0,0 +1,3 @@
# Copying
Modrinth's Github workflows are licensed under the MIT License, which is provided in the file [LICENSE](./LICENSE).

7
.github/workflows/LICENSE vendored Normal file
View File

@ -0,0 +1,7 @@
Copyright 2025 Rinth, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

130
.github/workflows/axolotl-ci.yml vendored Normal file
View File

@ -0,0 +1,130 @@
name: Axolotl desktop CI
on:
push:
branches: [main]
paths-ignore:
- 'apps/telemetry-dashboard/**'
- 'apps/telemetry-worker/**'
pull_request:
paths-ignore:
- 'apps/telemetry-dashboard/**'
- 'apps/telemetry-worker/**'
workflow_dispatch:
permissions:
contents: read
jobs:
guardrails:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- uses: pnpm/action-setup@008330803749db0355799c700092d9a85fd074e9 # v6.0.9
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version-file: .nvmrc
cache: pnpm
- run: pnpm install --frozen-lockfile
- name: Check immutable database migrations
env:
MIGRATION_BASE_REF: ${{ github.event.pull_request.base.sha || github.event.before }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
node scripts/axolotl/check-migrations.mjs --base "${MIGRATION_BASE_REF:-HEAD^}"
node scripts/axolotl/check-migrations.mjs --release
- run: node scripts/axolotl/brand-guard.mjs
- run: node scripts/axolotl/i18n-check.mjs
- run: cargo fmt --all --check
desktop:
needs: guardrails
strategy:
fail-fast: false
matrix:
os: [windows-latest, macos-latest, ubuntu-latest]
runs-on: ${{ matrix.os }}
env:
SQLX_OFFLINE: true
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
submodules: recursive
- uses: pnpm/action-setup@008330803749db0355799c700092d9a85fd074e9 # v6.0.9
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version-file: .nvmrc
cache: pnpm
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
- name: Set up Rust compiler cache
if: runner.os == 'Windows'
uses: mozilla-actions/sccache-action@2df7dbab909c49ab7d3382d05da469f3f975c2d6 # v0.0.7
- name: Check Rust compiler cache availability
id: sccache
if: runner.os == 'Windows'
continue-on-error: true
shell: bash
env:
SCCACHE_GHA_ENABLED: 'true'
run: ${SCCACHE_PATH} rustc -vV
- name: Enable Rust compiler cache
if: runner.os == 'Windows' && steps.sccache.outcome == 'success'
shell: bash
run: |
echo 'RUSTC_WRAPPER=sccache' >> "$GITHUB_ENV"
echo 'SCCACHE_GHA_ENABLED=true' >> "$GITHUB_ENV"
echo 'SCCACHE_CACHE_SIZE=4G' >> "$GITHUB_ENV"
- if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
- run: pnpm install --frozen-lockfile
- name: Install Blockbench skin editor dependencies
run: npm ci
working-directory: third-party/blockbench
- uses: ./.github/actions/replace-gradle-mirror
- run: pnpm --filter @modrinth/app-frontend build
- name: Test version metadata writes
run: cargo test --package theseus writing_version_info_creates_missing_parent_directory
- run: cargo check --package theseus_gui --features updater
- name: Build modern Windows installer
if: runner.os == 'Windows'
run: pnpm --filter @modrinth/app tauri build --config tauri-release.conf.json --config tauri-modern.conf.json
- name: Verify modern Windows installer
if: runner.os == 'Windows'
shell: pwsh
run: |
$installers = @(Get-ChildItem target/release/bundle/nsis -Filter '*-setup.exe' -File)
if ($installers.Count -ne 1) {
throw "Expected one modern NSIS installer, found $($installers.Count)"
}
Write-Output "Built modern installer: $($installers[0].Name)"
- name: Build native NSIS Windows installer
if: runner.os == 'Windows'
run: pnpm --filter @modrinth/app tauri build
- name: Verify native NSIS Windows installer
if: runner.os == 'Windows'
shell: pwsh
run: |
$installers = @(Get-ChildItem target/release/bundle/nsis -Filter '*-setup.exe' -File)
if ($installers.Count -ne 1) {
throw "Expected one native NSIS installer, found $($installers.Count)"
}
Write-Output "Built native NSIS installer: $($installers[0].Name)"
- name: Show Rust compiler cache statistics
if: runner.os == 'Windows' && steps.sccache.outcome == 'success' && always()
shell: bash
run: ${SCCACHE_PATH} --show-stats
website:
needs: guardrails
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: pnpm/action-setup@008330803749db0355799c700092d9a85fd074e9 # v6.0.9
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version-file: .nvmrc
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm --filter @axolotl/website build

400
.github/workflows/axolotl-release.yml vendored Normal file
View File

@ -0,0 +1,400 @@
name: Axolotl release
on:
push:
tags:
- 'v*'
permissions:
contents: write
concurrency:
group: axolotl-release-${{ github.ref }}
cancel-in-progress: false
jobs:
preflight:
name: Release preflight
runs-on: ubuntu-24.04
env:
SQLX_OFFLINE: true
steps:
- name: Check out source
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
submodules: recursive
- name: Set up pnpm
uses: pnpm/action-setup@008330803749db0355799c700092d9a85fd074e9 # v6.0.9
- name: Set up Node.js
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version-file: .nvmrc
cache: pnpm
- name: Set up Rust
uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Install Blockbench skin editor dependencies
run: npm ci
working-directory: third-party/blockbench
- name: Run release guardrails
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
node scripts/axolotl/check-migrations.mjs --release
node scripts/axolotl/brand-guard.mjs
node scripts/axolotl/i18n-check.mjs
cargo fmt --all --check
- name: Prepare draft release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
release_notes="${RUNNER_TEMP}/axolotl-release-notes.md"
node scripts/axolotl/create-release-notes.mjs "${GITHUB_REF_NAME}" "$release_notes"
existing_release="$(
gh release list --limit 100 --json tagName \
--jq ".[] | select(.tagName == \"${GITHUB_REF_NAME}\") | .tagName"
)"
if [[ -n "$existing_release" ]]; then
echo "Release ${GITHUB_REF_NAME} already exists"
gh release edit "${GITHUB_REF_NAME}" --notes-file "$release_notes"
exit 0
fi
release_args=(
--draft
--notes-file "$release_notes"
--title "Axolotl Launcher ${GITHUB_REF_NAME}"
)
if [[ "${GITHUB_REF_NAME}" == *-* ]]; then
release_args+=(--prerelease)
fi
gh release create "${GITHUB_REF_NAME}" "${release_args[@]}"
build:
name: Build (${{ matrix.name }})
needs: preflight
strategy:
fail-fast: true
max-parallel: 4
matrix:
include:
- name: Linux x64
runner: ubuntu-24.04
args: --config tauri-release.conf.json --config tauri-updater.conf.json
- name: Linux arm64
runner: ubuntu-24.04-arm
args: --config tauri-release.conf.json --config tauri-updater.conf.json
- name: Windows x64
runner: windows-2025
args: --config tauri-release.conf.json --config tauri-modern.conf.json --config tauri-updater.conf.json
- name: macOS universal
runner: macos-15
args: --target universal-apple-darwin --config tauri-release.conf.json --config tauri-updater.conf.json
runs-on: ${{ matrix.runner }}
env:
SQLX_OFFLINE: true
steps:
- name: Check out source
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
submodules: recursive
- name: Set up pnpm
uses: pnpm/action-setup@008330803749db0355799c700092d9a85fd074e9 # v6.0.9
- name: Set up Node.js
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version-file: .nvmrc
cache: pnpm
- name: Set up Rust
uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable
- name: Set up Rust compiler cache
if: runner.os == 'Windows'
uses: mozilla-actions/sccache-action@2df7dbab909c49ab7d3382d05da469f3f975c2d6 # v0.0.7
- name: Check Rust compiler cache availability
id: sccache
if: runner.os == 'Windows'
continue-on-error: true
shell: bash
env:
SCCACHE_GHA_ENABLED: 'true'
run: ${SCCACHE_PATH} rustc -vV
- name: Enable Rust compiler cache
if: runner.os == 'Windows' && steps.sccache.outcome == 'success'
shell: bash
run: |
echo 'RUSTC_WRAPPER=sccache' >> "$GITHUB_ENV"
echo 'SCCACHE_GHA_ENABLED=true' >> "$GITHUB_ENV"
echo 'SCCACHE_CACHE_SIZE=4G' >> "$GITHUB_ENV"
- name: Add macOS universal targets
if: runner.os == 'macOS'
run: rustup target add aarch64-apple-darwin x86_64-apple-darwin
- name: Install Linux dependencies
if: runner.os == 'Linux'
run: sudo apt-get -o Acquire::ForceIPv4=true update && sudo apt-get -o Acquire::ForceIPv4=true install -y libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev patchelf xdg-utils
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Install Blockbench skin editor dependencies
run: npm ci
working-directory: third-party/blockbench
- uses: ./.github/actions/replace-gradle-mirror
- name: Set release version
run: node scripts/axolotl/set-version.mjs "${{ github.ref_name }}"
- name: Build and upload release assets
uses: tauri-apps/tauri-action@1ddc7b49b13c3038297360482fcb3e058764d7c9 # v0.6.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CURSEFORGE_API_KEY: ${{ secrets.CURSEFORGE_API_KEY }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
TAURI_BUNDLER_DMG_IGNORE_CI: ${{ runner.os == 'macOS' && 'true' || '' }}
with:
projectPath: apps/app
tauriScript: pnpm tauri
args: ${{ matrix.args }}
tagName: ${{ github.ref_name }}
releaseName: Axolotl Launcher ${{ github.ref_name }}
releaseDraft: true
prerelease: ${{ contains(github.ref_name, '-') }}
generateReleaseNotes: false
includeUpdaterJson: false
updaterJsonPreferNsis: true
retryAttempts: 2
- name: Show Rust compiler cache statistics
if: runner.os == 'Windows' && steps.sccache.outcome == 'success' && always()
shell: bash
run: ${SCCACHE_PATH} --show-stats
- name: Publish Windows distribution variants
if: runner.os == 'Windows'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CURSEFORGE_API_KEY: ${{ secrets.CURSEFORGE_API_KEY }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
shell: pwsh
run: |
$version = "${{ github.ref_name }}" -replace '^v', ''
$appName = "Axolotl Launcher"
$outDir = "target/release/bundle/nsis"
$buildDir = "target/portable-build"
$publishDir = Join-Path $env:RUNNER_TEMP "windows-assets"
New-Item -ItemType Directory -Force -Path $publishDir | Out-Null
$modernInstallers = @(Get-ChildItem $outDir -Filter '*-setup.exe' -File)
if ($modernInstallers.Count -ne 1) {
throw "Expected one modern installer, found $($modernInstallers.Count)"
}
$modernName = "Axolotl_Launcher_${version}_x64_modern-setup.exe"
$modernPath = Join-Path $publishDir $modernName
Copy-Item -Force $modernInstallers[0].FullName $modernPath
gh release upload "${{ github.ref_name }}" $modernPath --clobber
$modernSignature = "$($modernInstallers[0].FullName).sig"
if (Test-Path $modernSignature) {
$modernSignaturePath = "$modernPath.sig"
Copy-Item -Force $modernSignature $modernSignaturePath
gh release upload "${{ github.ref_name }}" $modernSignaturePath --clobber
gh release delete-asset "${{ github.ref_name }}" "$($modernInstallers[0].Name).sig" --yes
}
gh release delete-asset "${{ github.ref_name }}" $modernInstallers[0].Name --yes
pnpm --filter @modrinth/app tauri build --config tauri-release.conf.json --config tauri-native.conf.json
$nativeInstallers = @(Get-ChildItem $outDir -Filter '*-setup.exe' -File)
if ($nativeInstallers.Count -ne 1) {
throw "Expected one native NSIS installer, found $($nativeInstallers.Count)"
}
$nativeName = "Axolotl_Launcher_${version}_x64_nsis-setup.exe"
$nativePath = Join-Path $publishDir $nativeName
Copy-Item -Force $nativeInstallers[0].FullName $nativePath
gh release upload "${{ github.ref_name }}" $nativePath --clobber
$nativeSignature = "$($nativeInstallers[0].FullName).sig"
if (Test-Path $nativeSignature) {
$nativeSignaturePath = "$nativePath.sig"
Copy-Item -Force $nativeSignature $nativeSignaturePath
gh release upload "${{ github.ref_name }}" $nativeSignaturePath --clobber
}
# Reuse the binary already built by tauri-action
$appExe = "target/release/${appName}.exe"
if (Test-Path $appExe) {
New-Item -ItemType Directory -Force -Path "$buildDir\Axolotl" | Out-Null
Copy-Item -Force $appExe "$buildDir\Axolotl\"
# Create empty .Axolotl folder to trigger portable mode
New-Item -ItemType Directory -Force -Path "$buildDir\Axolotl\.Axolotl" | Out-Null
# Create portable zip (for manual download)
$zipName = "Axolotl_Launcher_${version}_x64_portable.zip"
$zipPath = Join-Path $publishDir $zipName
Compress-Archive -Path "$buildDir\Axolotl" -DestinationPath $zipPath -Force
Write-Output "Created portable zip: $zipPath"
# Upload portable zip (for manual download only)
gh release upload "${{ github.ref_name }}" "$zipPath" --clobber
} else {
throw "Binary not found at $appExe"
}
verify-and-publish:
name: Verify and publish
needs: build
runs-on: ubuntu-24.04
steps:
- name: Check out source
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
ref: main
- name: Download updater signatures
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh release download "${GITHUB_REF_NAME}" --pattern '*.sig' --dir release-check/signatures
- name: Download release metadata
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
release_id="$(
gh api "repos/${GITHUB_REPOSITORY}/releases" \
--paginate \
--jq ".[] | select(.tag_name == \"${GITHUB_REF_NAME}\") | .id"
)"
if [[ -z "$release_id" ]]; then
echo "Release ${GITHUB_REF_NAME} was not found"
exit 1
fi
gh api "repos/${GITHUB_REPOSITORY}/releases/${release_id}" > release-check/release.json
- name: Generate update manifest
run: node scripts/axolotl/create-update-manifest.mjs release-check/release.json release-check/signatures "${GITHUB_REF_NAME}" release-check/latest.json
- name: Verify update manifest
run: node scripts/axolotl/verify-update-manifest.mjs release-check/latest.json "${GITHUB_REF_NAME}"
- name: Upload update manifest
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh release upload "${GITHUB_REF_NAME}" release-check/latest.json --clobber
- name: Publish release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
if [[ "${GITHUB_REF_NAME}" == *-* ]]; then
gh release edit "${GITHUB_REF_NAME}" --draft=false --prerelease
else
gh release edit "${GITHUB_REF_NAME}" --draft=false --latest
fi
- name: Refresh published GitHub release metadata
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
release_id="$(
gh api "repos/${GITHUB_REPOSITORY}/releases" \
--paginate \
--jq ".[] | select(.tag_name == \"${GITHUB_REF_NAME}\") | .id"
)"
if [[ -z "$release_id" ]]; then
echo "Published release ${GITHUB_REF_NAME} was not found"
exit 1
fi
gh api "repos/${GITHUB_REPOSITORY}/releases/${release_id}" > release-check/release.json
- name: Build Update Server artifact catalog
run: |
node scripts/axolotl/create-update-server-catalog.mjs \
release-check/release.json \
"${GITHUB_REF_NAME}" \
release-check/update-server-catalog.json
node scripts/axolotl/create-update-server-catalog.test.mjs
- name: Notify Update Server to publish release assets
env:
UPDATE_SERVER_URL: ${{ secrets.UPDATE_SERVER_URL }}
UPDATE_SERVER_WEBHOOK_SECRET: ${{ secrets.UPDATE_SERVER_WEBHOOK_SECRET }}
UPDATE_SERVER_FORCE_UPDATE: 'false'
run: |
node scripts/axolotl/publish-update-server.mjs \
release-check/update-server-catalog.json \
release-check/release.json \
"${GITHUB_REF_NAME}"
- name: Publish website download metadata
if: ${{ !contains(github.ref_name, '-') }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
node scripts/axolotl/create-website-release-metadata.mjs \
release-check/release.json \
apps/website/releases/latest.json
node scripts/axolotl/create-website-release-catalog.mjs \
apps/website/releases/catalog.json
git config user.name "Axolotl Release Bot"
git config user.email "release@axolotl.local"
git add apps/website/releases/latest.json apps/website/releases/catalog.json
if git diff --cached --quiet; then
echo "Website metadata is unchanged"
else
git commit -m "chore(website): update download metadata to ${GITHUB_REF_NAME} [skip ci]"
git push origin main
fi
- name: Mirror published release to CNB
env:
CNB_REPO_URL_HTTPS: ${{ secrets.CNB_REPO_URL_HTTPS }}
CNB_TOKEN: ${{ secrets.CNB_TOKEN }}
CNB_TOKEN_USER_NAME: ${{ secrets.CNB_TOKEN_USER_NAME }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
if [[ -z "${CNB_TOKEN:-}" ]]; then
echo "CNB_TOKEN is not configured"
exit 1
fi
cnb_url="${CNB_REPO_URL_HTTPS:-https://cnb.cool/axlmc/Axolotl.git}"
token_user="${CNB_TOKEN_USER_NAME:-cnb}"
auth="$(printf '%s:%s' "$token_user" "$CNB_TOKEN" | base64 -w0)"
git_cnb() {
git -c "http.extraHeader=Authorization: Basic $auth" "$@"
}
git fetch origin "refs/tags/${GITHUB_REF_NAME}:refs/tags/${GITHUB_REF_NAME}"
git_cnb push --force "$cnb_url" \
"refs/tags/${GITHUB_REF_NAME}:refs/tags/${GITHUB_REF_NAME}"
node scripts/axolotl/cnb-release.mjs finalize "${GITHUB_REF_NAME}" cnb-release/final
node scripts/axolotl/verify-update-manifest.mjs \
cnb-release/final/latest.json "${GITHUB_REF_NAME}" cnb

View File

@ -0,0 +1,22 @@
name: Cancel PR Workflows on Merge
on:
pull_request_target:
types:
- closed
permissions:
actions: write
jobs:
cancel:
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@85880fa0301c86cca9da44039ee3bb12d3bedbfa # 0.12.1
with:
workflow_id: all
access_token: ${{ secrets.GITHUB_TOKEN }}
ignore_sha: true
pr_number: ${{ github.event.pull_request.number }}

123
.github/workflows/changelog-comment.yml vendored Normal file
View File

@ -0,0 +1,123 @@
name: Changelog Comment
on:
pull_request_target:
types: [opened, reopened]
workflow_dispatch:
inputs:
pr_number:
description: 'PR number to post the changelog comment on (for testing)'
required: true
type: number
permissions:
issues: write
pull-requests: read
jobs:
comment:
name: Post changelog comment
runs-on: ubuntu-latest
steps:
- name: Post or update changelog comment
uses: actions/github-script@d746ffe35508b1917358783b479e04febd2b8f71 # v9.0.0
with:
github-token: ${{ github.token }}
script: |
const marker = '<!-- changelog -->';
const mergedMarker = '<!-- changelog-merged -->';
const sections = ['### Added', '', '### Changed', '', '### Deprecated', '', '### Removed', '', '### Fixed', '', '### Security'].join('\n');
const productBlock = (name) => `<details>\n<summary>${name}</summary>\n\n${sections}\n\n</details>`;
const template = [
marker,
'## Pull request changelog',
'',
'<!-- Fill in the changelog under each product area this PR affects.',
' Empty sections are ignored. Leave a product collapsed/empty',
' if it doesn\'t apply. -->',
'',
productBlock('App'),
'',
productBlock('Website'),
].join('\n');
// Resolve PR number from event or workflow_dispatch input
const prNumber = context.payload.pull_request?.number
?? parseInt('${{ github.event.inputs.pr_number }}', 10);
if (!prNumber || isNaN(prNumber)) {
core.setFailed('Could not determine PR number');
return;
}
// Get PR details (need base ref for child PR detection)
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber,
});
// Check if bot comment already exists
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
});
const existingComment = comments.find(c => c.body.includes(marker));
if (existingComment) {
core.info('Changelog comment already exists, skipping');
return;
}
// Post the template comment
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: template,
});
core.info(`Posted changelog comment on PR #${prNumber}`);
// Detect child PR: check if this PR's base branch is another open PR's head branch
const baseRef = pr.base.ref;
if (baseRef === 'main' || baseRef === 'prod') {
return;
}
// Look for a parent PR whose head branch matches our base branch
const { data: candidatePRs } = await github.rest.pulls.list({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
head: `${context.repo.owner}:${baseRef}`,
});
if (candidatePRs.length === 0) {
return;
}
const parentPR = candidatePRs[0];
core.info(`Detected parent PR #${parentPR.number} for child PR #${prNumber}`);
// Add admonition to child PR's changelog comment
const { data: childComments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
});
const childChangelogComment = childComments.find(c => c.body.includes(marker));
if (childChangelogComment && !childChangelogComment.body.includes(mergedMarker)) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: childChangelogComment.id,
body: `${mergedMarker}\n> [!NOTE]\n> This changelog has been merged into the changelog for #${parentPR.number}\n\n${childChangelogComment.body}`,
});
}

29
.github/workflows/check-generic.yml vendored Normal file
View File

@ -0,0 +1,29 @@
name: Repository checks
on:
pull_request:
push:
branches:
- main
env:
CARGO_TERM_COLOR: always
SQLX_OFFLINE: true
jobs:
typos:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: crate-ci/typos@6ac2ebd1b93eade61faf7e12688ad87a073fea59 # v1.46.0
# see <https://github.com/influxdata/datafusion-udf-wasm/pull/275>
tombi:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: taiki-e/install-action@fd2f5e3d644b484055ebf4268f474c565f148f25 # v2.81.9
with:
tool: tombi@1.1.2
- run: tombi lint
- run: tombi fmt --check

26
.github/workflows/check-rust.yml vendored Normal file
View File

@ -0,0 +1,26 @@
name: Rust checks
on:
pull_request:
push:
branches:
- main
env:
CARGO_TERM_COLOR: always
SQLX_OFFLINE: true
jobs:
shear:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
submodules: recursive
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version-file: .nvmrc
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
- uses: cargo-bins/cargo-binstall@dc19f1e48450eefe5a29b8da6c6b00a87d730b37 # v1.18.1
- run: cargo binstall --no-confirm cargo-shear
- run: cargo shear

View File

@ -0,0 +1,34 @@
name: Deploy telemetry dashboard
on:
push:
branches: [main]
paths:
- 'apps/telemetry-dashboard/**'
workflow_dispatch:
permissions:
contents: read
concurrency:
group: telemetry-dashboard-deploy
cancel-in-progress: false
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: pnpm/action-setup@008330803749db0355799c700092d9a85fd074e9 # v6.0.9
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version-file: .nvmrc
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm --filter @axolotl/telemetry-dashboard build
- uses: cloudflare/wrangler-action@ebbaa1584979971c8614a24965b4405ff95890e0 # v4.0.0
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
workingDirectory: apps/telemetry-dashboard
packageManager: pnpm
command: deploy

View File

@ -0,0 +1,40 @@
name: Prepare pnpm cache
on:
push:
paths:
- .github/workflows/prepare-pnpm-cache.yml
- package.json
- pnpm-lock.yaml
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && github.ref != 'refs/heads/prod' }}
jobs:
prepare:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Node
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version-file: .nvmrc
- name: Enable Corepack
run: corepack enable
- name: Get pnpm store path
id: pnpm-store
run: echo "store-path=$(pnpm store path --silent)" >> $GITHUB_OUTPUT
- name: Cache pnpm
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ${{ steps.pnpm-store.outputs.store-path }}
key: pnpm-cache-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/pnpm-lock.yaml') }}
- name: Install dependencies
run: pnpm recursive install --frozen-lockfile

69
.github/workflows/sync-cnb-source.yml vendored Normal file
View File

@ -0,0 +1,69 @@
name: Sync source to CNB
on:
push:
branches:
- '**'
tags:
- '**'
delete:
workflow_dispatch:
permissions:
contents: read
concurrency:
group: sync-cnb-source-${{ github.event_name == 'delete' && format('{0}/{1}', github.event.ref_type, github.event.ref) || github.ref }}
cancel-in-progress: false
jobs:
sync:
name: Sync Git ref
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- name: Check out source
if: ${{ github.event_name != 'delete' }}
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
filter: blob:none
- name: Push Git ref to CNB
env:
CNB_REPO_URL_HTTPS: ${{ secrets.CNB_REPO_URL_HTTPS }}
CNB_TOKEN: ${{ secrets.CNB_TOKEN }}
CNB_TOKEN_USER_NAME: ${{ secrets.CNB_TOKEN_USER_NAME }}
DELETED_REF: ${{ github.event.ref }}
DELETED_REF_TYPE: ${{ github.event.ref_type }}
run: |
set -euo pipefail
if [[ -z "${CNB_TOKEN:-}" ]]; then
echo "CNB_TOKEN is not configured"
exit 1
fi
cnb_url="${CNB_REPO_URL_HTTPS:-https://cnb.cool/axlmc/Axolotl.git}"
token_user="${CNB_TOKEN_USER_NAME:-cnb}"
auth="$(printf '%s:%s' "$token_user" "$CNB_TOKEN" | base64 -w0)"
git_cnb() {
git -c "http.extraHeader=Authorization: Basic $auth" "$@"
}
if [[ "$GITHUB_EVENT_NAME" == "delete" ]]; then
git init
if [[ "$DELETED_REF_TYPE" == "tag" ]]; then
ref="refs/tags/$DELETED_REF"
else
ref="refs/heads/$DELETED_REF"
fi
git_cnb push "$cnb_url" --delete "$ref"
else
if [[ "$GITHUB_REF" == refs/tags/* ]]; then
git fetch --force origin "$GITHUB_REF:$GITHUB_REF"
source_ref="$GITHUB_REF"
else
source_ref="HEAD"
fi
git_cnb push --force "$cnb_url" "$source_ref:$GITHUB_REF"
fi

View File

@ -0,0 +1,101 @@
name: Sync LobeHub models
on:
schedule:
- cron: '17 3 * * *'
workflow_dispatch:
permissions:
contents: write
pull-requests: write
concurrency:
group: sync-lobehub-models
cancel-in-progress: false
jobs:
sync:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout Axolotl Launcher
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
persist-credentials: false
- name: Setup Node
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version-file: .nvmrc
- name: Checkout LobeHub
id: upstream
run: |
set -euo pipefail
git clone --depth 1 --branch main https://github.com/lobehub/lobehub.git "$RUNNER_TEMP/lobehub"
sha="$(git -C "$RUNNER_TEMP/lobehub" rev-parse HEAD)"
echo "sha=$sha" >> "$GITHUB_OUTPUT"
- name: Generate model catalog
run: >-
node --disable-warning=ExperimentalWarning --experimental-vm-modules
scripts/axolotl/sync-lobehub-models.mjs
--upstream "$RUNNER_TEMP/lobehub"
--commit "${{ steps.upstream.outputs.sha }}"
- name: Detect changes
id: changes
run: |
if git diff --quiet -- packages/app-lib/src/api/ai.rs packages/app-lib/src/api/lobehub_text_models.json; then
echo "changed=false" >> "$GITHUB_OUTPUT"
else
echo "changed=true" >> "$GITHUB_OUTPUT"
fi
- name: Close obsolete pull request
if: steps.changes.outputs.changed == 'false'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
base="${{ github.event.repository.default_branch }}"
branch="automation/sync-lobehub-models"
pr_number="$(gh pr list --state open --base "$base" --head "$branch" --json number --jq '.[0].number // empty')"
if [ -n "$pr_number" ]; then
gh pr close "$pr_number" --delete-branch --comment "Closing because the current LobeHub model catalog no longer differs from $base."
fi
- name: Push model update and create pull request
if: steps.changes.outputs.changed == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
base="${{ github.event.repository.default_branch }}"
branch="automation/sync-lobehub-models"
upstream_sha="${{ steps.upstream.outputs.sha }}"
short_sha="${upstream_sha:0:12}"
title="chore(ai): sync LobeHub models"
body="Automated synchronization of supported chat models from [LobeHub](https://github.com/lobehub/lobehub/tree/${upstream_sha}/packages/model-bank/src/aiModels) at \`${upstream_sha}\`."
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
gh auth setup-git
expected=""
if git ls-remote --exit-code --heads origin "refs/heads/$branch" >/dev/null 2>&1; then
git fetch --no-tags origin "refs/heads/$branch:refs/remotes/origin/$branch"
expected="$(git rev-parse "refs/remotes/origin/$branch")"
fi
git switch -C "$branch"
git add packages/app-lib/src/api/ai.rs packages/app-lib/src/api/lobehub_text_models.json
git commit -m "chore(ai): sync LobeHub models at $short_sha"
git push --force-with-lease="refs/heads/$branch:$expected" origin "HEAD:refs/heads/$branch"
pr_number="$(gh pr list --state open --base "$base" --head "$branch" --json number --jq '.[0].number // empty')"
if [ -n "$pr_number" ]; then
gh api --method PATCH "repos/$GITHUB_REPOSITORY/pulls/$pr_number" -f title="$title" -f body="$body" >/dev/null
else
gh pr create --base "$base" --head "$branch" --title "$title" --body "$body"
fi