Cross-platform packages / Validate source (push) Canceled after 0s
Cross-platform packages / Authorize desktop packaging (push) Canceled after 0s
Cross-platform packages / linux arm64 (push) Canceled after 0s
Cross-platform packages / macos arm64 (push) Canceled after 0s
Cross-platform packages / windows arm64 (push) Canceled after 0s
Cross-platform packages / linux x64 (push) Canceled after 0s
Cross-platform packages / macos x64 (push) Canceled after 0s
Cross-platform packages / windows x64 (push) Canceled after 0s
Cross-platform packages / Publish GitHub and OSS release (push) Canceled after 0s
GoodBuddy Agents / Validate Agent source (push) Canceled after 0s
GoodBuddy Agents / Build darwin arm64 Agent (push) Canceled after 0s
GoodBuddy Agents / Build linux arm64 Agent (push) Canceled after 0s
GoodBuddy Agents / Build linux x64 Agent (push) Canceled after 0s
Record the approved bilingual release notes, classify long-task limits and premature truncation as fixes, and align both feature matrices with the verified workspace, browser, scheduling and Runtime behavior. Advance the Agent lock to 0.11.23 for remote file and Git management, optional model limits, larger bridge exchanges and the unlimited-duration connection fix. Agent publication reads version-specific approved notes and remains separate from Desktop Latest. Upgrade Desktop to 0.12.11 before updating Hosts. No LoongArch preview is included. Validation: release notes verification, all 3845 tests (66 skipped), typecheck and lint passed. Current-source Linux x64 workspace and bridge checks passed; managed ACP Ask and Execute completed two real model requests, both HTTP 200, with delivered results and cleaned test resources. Native production packages and publication remain subject to GitHub Actions after candidate approval. Release note: 准备 Desktop 0.12.11 与 Agent 0.11.23 发布;远程文件和 Git 管理、长任务限制及连接超时修复需先升级桌面端,再更新 Host 上的 Agent。
193 lines
5.9 KiB
TypeScript
193 lines
5.9 KiB
TypeScript
import { readFileSync } from 'node:fs'
|
|
import { join } from 'node:path'
|
|
import { describe, expect, it } from 'vitest'
|
|
import { parse } from 'yaml'
|
|
|
|
const workflow = readFileSync(
|
|
join(
|
|
process.cwd(),
|
|
'.github',
|
|
'workflows',
|
|
'agent-release.yml'
|
|
),
|
|
'utf8'
|
|
)
|
|
const desktopWorkflow = readFileSync(
|
|
join(process.cwd(), '.github', 'workflows', 'packages.yml'),
|
|
'utf8'
|
|
)
|
|
const parsed = parse(workflow) as {
|
|
jobs: Record<
|
|
string,
|
|
{
|
|
needs?: string | string[]
|
|
environment?: { name?: string }
|
|
strategy?: {
|
|
matrix?: {
|
|
include?: Array<Record<string, unknown>>
|
|
}
|
|
}
|
|
steps?: Array<{
|
|
name?: string
|
|
run?: string
|
|
uses?: string
|
|
with?: Record<string, unknown>
|
|
}>
|
|
}
|
|
>
|
|
}
|
|
|
|
function serializedJob(name: string): string {
|
|
return JSON.stringify(parsed.jobs[name])
|
|
}
|
|
|
|
function scripts(name: string): string {
|
|
return (
|
|
parsed.jobs[name]?.steps
|
|
?.map((step) => step.run ?? '')
|
|
.join('\n') ?? ''
|
|
)
|
|
}
|
|
|
|
describe('independent Agent release workflow', () => {
|
|
it('publishes the checked-in bilingual notes matching the Agent version', () => {
|
|
const { agentVersion } = JSON.parse(
|
|
readFileSync(join(process.cwd(), 'agent-runtime-lock.json'), 'utf8')
|
|
) as { agentVersion: string }
|
|
const notes = readFileSync(
|
|
join(process.cwd(), 'resources/agent-release-notes', `${agentVersion}.md`), 'utf8'
|
|
)
|
|
expect(scripts('publish')).toContain('notes="resources/agent-release-notes/$AGENT_VERSION.md"')
|
|
expect(scripts('publish')).toContain('test -s "$notes"')
|
|
expect(notes).toContain(`# GoodBuddy Agent ${agentVersion} 更新内容`)
|
|
expect(notes).toContain(`# What's New in GoodBuddy Agent ${agentVersion}`)
|
|
expect(notes).toContain('## 功能更新')
|
|
expect(notes).toContain('## 问题修复')
|
|
expect(notes).toContain('## Features')
|
|
expect(notes).toContain('## Bug Fixes')
|
|
})
|
|
|
|
it('uses a separate immutable agent-v tag and never enters desktop packaging', () => {
|
|
expect(() => parse(workflow)).not.toThrow()
|
|
expect(workflow).toContain("- 'agent-v*'")
|
|
expect(workflow).not.toContain('workflow_dispatch:')
|
|
expect(scripts('authorize')).toContain(
|
|
"require('./agent-runtime-lock.json').agentVersion"
|
|
)
|
|
expect(scripts('authorize')).toContain(
|
|
'git cat-file -t "refs/tags/$GITHUB_REF_NAME"'
|
|
)
|
|
expect(scripts('authorize')).toContain(
|
|
'git merge-base --is-ancestor'
|
|
)
|
|
expect(workflow).not.toContain('release:package')
|
|
expect(desktopWorkflow).not.toContain(
|
|
'agent-release.yml'
|
|
)
|
|
})
|
|
|
|
it('builds native x64 and arm64 compound packages in the protected signing environment', () => {
|
|
expect(
|
|
parsed.jobs.build?.strategy?.matrix?.include
|
|
).toEqual(
|
|
expect.arrayContaining([
|
|
expect.objectContaining({
|
|
arch: 'x64',
|
|
runner: 'ubuntu-24.04'
|
|
}),
|
|
expect.objectContaining({
|
|
arch: 'arm64',
|
|
runner: 'ubuntu-24.04-arm'
|
|
})
|
|
])
|
|
)
|
|
expect(parsed.jobs.build?.environment?.name).toBe(
|
|
'agent-signing'
|
|
)
|
|
const build = serializedJob('build')
|
|
const buildScripts = scripts('build')
|
|
expect(buildScripts).toContain(
|
|
'node build/agent-package.cjs build'
|
|
)
|
|
expect(buildScripts).toContain(
|
|
'--registry https://registry.npmjs.org/'
|
|
)
|
|
expect(buildScripts).toContain('--ignore-scripts')
|
|
expect(build).toContain(
|
|
'GOODBUDDY_SIGNING_PRIVATE_KEY'
|
|
)
|
|
expect(workflow).not.toContain(
|
|
'GOODBUDDY_REMOTE_RUNTIME_SIGNING_'
|
|
)
|
|
expect(buildScripts).toContain('.gbagent')
|
|
})
|
|
|
|
it('signs and verifies one cumulative dual-architecture catalog', () => {
|
|
expect(parsed.jobs.catalog?.environment?.name).toBe(
|
|
'agent-signing'
|
|
)
|
|
const catalog = scripts('catalog')
|
|
expect(catalog).toContain(
|
|
'node build/agent-catalog.cjs create'
|
|
)
|
|
expect(catalog).toContain('--x64-package')
|
|
expect(catalog).toContain('--arm64-package')
|
|
expect(catalog).toContain(
|
|
'--previous-catalog dist/agent-release/previous.json'
|
|
)
|
|
expect(catalog).toContain(
|
|
'node build/agent-catalog.cjs verify'
|
|
)
|
|
})
|
|
|
|
it('publishes immutable OSS objects and updates the signed latest pointer last', () => {
|
|
expect(parsed.jobs.publish?.environment?.name).toBe(
|
|
'aliyun-oss-release'
|
|
)
|
|
const publish = scripts('publish')
|
|
const immutable = workflow.indexOf(
|
|
'- name: Upload immutable Agent release to OSS'
|
|
)
|
|
const github = workflow.indexOf(
|
|
'- name: Publish non-Latest GitHub Agent release'
|
|
)
|
|
const latest = workflow.indexOf(
|
|
'- name: Point OSS Agent catalog to published release'
|
|
)
|
|
expect(immutable).toBeGreaterThanOrEqual(0)
|
|
expect(github).toBeGreaterThan(immutable)
|
|
expect(latest).toBeGreaterThan(github)
|
|
expect(serializedJob('publish')).toContain(
|
|
'aliyun/configure-aliyun-credentials-action@v1'
|
|
)
|
|
expect(publish).toContain('--region "$OSS_REGION"')
|
|
expect(publish).toContain(
|
|
'$root/$name" --output "$RUNNER_TEMP/immutable-$name"'
|
|
)
|
|
})
|
|
|
|
it('publishes a normal Agent release without changing desktop Latest', () => {
|
|
const publish = scripts('publish')
|
|
expect(publish).toContain('--latest=false')
|
|
expect(publish).toContain(
|
|
'repos/mesalogo/goodbuddy/releases/latest'
|
|
)
|
|
expect(publish).toContain(
|
|
'test "$(gh api repos/mesalogo/goodbuddy/releases/latest --jq .tag_name)" != "$tag"'
|
|
)
|
|
expect(publish).not.toContain('--latest\n')
|
|
expect(publish).not.toContain('agent-releases/latest.sig')
|
|
expect(publish).toContain(
|
|
'catalog: `v${version}/agent-catalog.json`'
|
|
)
|
|
expect(workflow).not.toContain('prerelease: true')
|
|
})
|
|
|
|
it('keeps private keys out of authorization and public publication jobs', () => {
|
|
expect(serializedJob('authorize')).not.toContain('secrets.')
|
|
expect(serializedJob('publish')).not.toContain(
|
|
'GOODBUDDY_SIGNING_PRIVATE_KEY'
|
|
)
|
|
})
|
|
})
|