Files
TanTan fa9c73363d
Dev Build / cleanup (push) Waiting to run
Dev Build / typecheck (push) Waiting to run
Publish MCP to npm / Build, test, and publish MCP (push) Waiting to run
Publish SDK to npm / Build, test, and publish SDK (push) Waiting to run
Sync action catalog to docs / sync (push) Waiting to run
Publish UI to npm / Build and publish UI (push) Waiting to run
Build and Release / preflight (push) Waiting to run
SnowLuma v2.4.2 source snapshot
2026-11-13 09:02:00 +08:00

279 lines
10 KiB
YAML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: Dev Build
on:
push:
branches:
- '**'
tags-ignore:
- 'v*'
# Only `dev` gets a shared, self-cancelling group so a newer dev commit
# supersedes the in-flight one (and its Docker dispatch) before it publishes.
# Every other branch falls back to a unique per-run group (github.run_id), so
# their concurrency behavior is unchanged — no shared-group pending-run
# replacement, no accidental serialization.
concurrency:
group: ${{ github.ref == 'refs/heads/dev' && format('{0}-{1}', github.workflow, github.ref) || github.run_id }}
cancel-in-progress: ${{ github.ref == 'refs/heads/dev' }}
jobs:
cleanup:
runs-on: ubuntu-latest
permissions:
actions: write
contents: read
steps:
# Delete only artifacts older than 24h. The dev Docker hand-off relies on
# this run's fresh `snowluma-dev-docker-*` artifact still existing when the
# downstream (cross-repo) Docker build downloads it; a blanket "delete all"
# here — which also runs on every other branch's push — could race-delete
# an in-flight hand-off artifact. Age-gating keeps recent ones safe while
# still reaping the backlog.
- name: Delete old artifacts
uses: actions/github-script@v8
with:
script: |
const cutoff = Date.now() - 24 * 60 * 60 * 1000;
// Collect every artifact first, THEN delete — deleting mid-pagination
// shifts the list and would skip ~a page of old artifacts per delete.
const all = [];
let page = 1;
while (true) {
const { data: { artifacts } } = await github.rest.actions.listArtifactsForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
per_page: 100,
page,
});
if (artifacts.length === 0) break;
all.push(...artifacts);
page++;
}
for (const artifact of all) {
if (new Date(artifact.created_at).getTime() >= cutoff) {
continue; // keep recent artifacts (may be in-flight dev hand-offs)
}
await github.rest.actions.deleteArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: artifact.id,
});
console.log(`Deleted artifact: ${artifact.name}`);
}
typecheck:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup pnpm
uses: pnpm/action-setup@v6
with:
version: 11.25.0
run_install: false
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version-file: '.node-version'
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
# Runs `tsc --noEmit` (or `tsc -b`) in every workspace package that
# exposes a `typecheck` script. Platform-independent, so a single
# ubuntu runner is sufficient.
- name: Type check all packages
run: pnpm typecheck
build:
needs: [cleanup, typecheck]
permissions:
contents: read
strategy:
fail-fast: false
matrix:
include:
- name: win-x64
os: windows-latest
target: win32-x64
- name: linux-x64
os: ubuntu-latest
target: linux-x64
- name: linux-arm64
os: ubuntu-24.04-arm
target: linux-arm64
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup pnpm
uses: pnpm/action-setup@v6
with:
version: 11.25.0
run_install: false
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version-file: '.node-version'
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run native smoke tests
run: pnpm test:native
# Always builds the WebUI flavor — no separate "core-only" artifact.
- name: Build project
env:
SNOWLUMA_TARGET: ${{ matrix.target }}
run: pnpm run build:all
- name: Verify release layout
run: pnpm check:release-layout
# Naming convention:
# SnowLuma-dev-<arch>.zip|tar.gz – zero-install (node bundled)
# SnowLuma-dev-<arch>-lite.zip|tar.gz – user provides Node ^24.22.1 or >=26.12.1
- name: Package (windows)
if: matrix.os == 'windows-latest'
shell: pwsh
run: |
Compress-Archive -Path "dist\*" -DestinationPath "SnowLuma-dev-${{ matrix.name }}-lite.zip"
Copy-Item (Get-Command node).Source -Destination "dist\node.exe"
Compress-Archive -Path "dist\*" -DestinationPath "SnowLuma-dev-${{ matrix.name }}.zip"
- name: Package (linux)
if: startsWith(matrix.os, 'ubuntu')
run: |
chmod +x dist/launcher.sh
tar -czf "SnowLuma-dev-${{ matrix.name }}-lite.tar.gz" -C dist .
cp "$(command -v node)" dist/node
chmod +x dist/node
tar -czf "SnowLuma-dev-${{ matrix.name }}.tar.gz" -C dist .
# Single upload step — glob picks up both variants (.zip on Windows,
# .tar.gz on Linux) for this matrix row.
- name: Upload artifacts
uses: actions/upload-artifact@v7
with:
name: SnowLuma-dev-${{ github.sha }}-${{ matrix.name }}
path: SnowLuma-dev-${{ matrix.name }}*
retention-days: 3
overwrite: true
if-no-files-found: error
# Deterministic-name hand-off artifact consumed by the cross-repo dev
# Docker build (SnowLuma.Docker.Framework/docker-image.yml downloads it by
# this exact name). linux-x64 only — dev images are amd64-only. Just the
# lite tarball; the container already ships its own Node runtime.
- name: Upload dev Docker hand-off artifact
if: matrix.name == 'linux-x64' && github.ref == 'refs/heads/dev'
uses: actions/upload-artifact@v7
with:
name: snowluma-dev-docker-linux-x64
path: SnowLuma-dev-linux-x64-lite.tar.gz
retention-days: 3
overwrite: true
if-no-files-found: error
# Fire the "latest dev" Docker build on SnowLuma.Docker.Framework — but only
# for `dev`. Mirrors release.yml's dispatch-docker, parameterized for dev:
# tag=dev (rolling) + sha_tag=dev-<12sha> (immutable), also_latest=false so it
# never touches the stable :latest, platforms=amd64, and artifact_run_id so the
# downstream build pulls THIS run's hand-off artifact instead of a Release.
dispatch-dev-docker:
needs: [build]
if: github.ref == 'refs/heads/dev'
runs-on: ubuntu-latest
environment: SnowLuma
permissions:
contents: read
steps:
- name: Compute short SHA
id: sha
run: echo "short=${GITHUB_SHA:0:12}" >> "$GITHUB_OUTPUT"
- name: Dispatch dev Docker build
uses: actions/github-script@v8
env:
RELEASE_REPOSITORY: ${{ vars.DOCKER_RELEASE_REPOSITORY }}
DOCKER_IMAGE: ${{ vars.DOCKER_IMAGE }}
DOCKER_WORKFLOW: ${{ vars.DOCKER_WORKFLOW }}
DOCKER_REF: ${{ vars.DOCKER_REF }}
SHA_TAG: dev-${{ steps.sha.outputs.short }}
ARTIFACT_RUN_ID: ${{ github.run_id }}
with:
github-token: ${{ secrets.SNOWLUMA_TOKEN }}
script: |
const target = process.env.RELEASE_REPOSITORY;
if (!target || !target.includes('/')) {
throw new Error('Set SnowLuma environment variable DOCKER_RELEASE_REPOSITORY to owner/repo.');
}
const [owner, repo] = target.split('/');
const sourceRepo = context.repo.owner + '/' + context.repo.repo;
const image = process.env.DOCKER_IMAGE || 'motricseven7/snowluma';
const workflowId = process.env.DOCKER_WORKFLOW || 'docker-image.yml';
const ref = process.env.DOCKER_REF || 'main';
const runId = String(process.env.ARTIFACT_RUN_ID);
const shaTag = process.env.SHA_TAG;
await github.rest.actions.createWorkflowDispatch({
owner,
repo,
workflow_id: workflowId,
ref,
inputs: {
image,
tag: 'dev',
push: 'true',
platforms: 'linux/amd64',
also_latest: 'false',
snowluma_repository: sourceRepo,
artifact_run_id: runId,
sha_tag: shaTag,
},
});
core.info(`Dispatched ${workflowId}@${ref} on ${target} for dev (image=${image}:dev + :${shaTag}, src run ${runId}).`);
// Best-effort: resolve the dispatched run by its unique run-name
// marker so the summary links straight to it (every dev dispatch is
// tag=dev, so we key on the source run id, not the tag).
const marker = `(src-run ${runId})`;
let runUrl = '';
for (let i = 0; i < 6 && !runUrl; i++) {
await new Promise((r) => setTimeout(r, 5000));
try {
const { data } = await github.rest.actions.listWorkflowRuns({
owner,
repo,
workflow_id: workflowId,
event: 'workflow_dispatch',
per_page: 30,
});
const hit = data.workflow_runs.find(
(r) => (r.display_title || r.name || '').includes(marker),
);
if (hit) runUrl = hit.html_url;
} catch (e) {
core.warning(`Downstream run lookup failed: ${e.message}`);
}
}
const workflowUrl = `https://github.com/${owner}/${repo}/actions/workflows/${workflowId}`;
await core.summary
.addHeading('dev Docker dispatch', 3)
.addList([
`source SHA: ${context.sha}`,
`source run id: ${runId}`,
`image: ${image}:dev + ${image}:${shaTag}`,
`downstream run: ${runUrl || `(not resolved yet — see ${workflowUrl}, look for ${marker})`}`,
])
.write();