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
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 Agent Release / Authorize Agent release (push) Canceled after 0s
GoodBuddy Agent Release / Build darwin arm64 compound package (push) Canceled after 0s
GoodBuddy Agent Release / Build linux arm64 compound package (push) Canceled after 0s
GoodBuddy Agent Release / Build linux x64 compound package (push) Canceled after 0s
GoodBuddy Agent Release / Sign cumulative Agent catalog (push) Canceled after 0s
GoodBuddy Agent Release / Publish Agent to GitHub and OSS (push) Canceled after 0s
Prepare bilingual notes and aligned feature lists for the schema-35 history repair, retained tool summaries, Windows DeepSeek workspace paths, and compact project activity navigation. Agent 0.11.25 is a maintenance release with unchanged protocol and runtime pins. Its compound packages require Desktop 0.13.2. Desktop targets the standard six platforms without a LoongArch preview. Make activity interaction tests wait for the loaded conversation and enabled send button, reset response mocks between cases, and wait for completed answer rendering. Accept bilingual maintenance-only Agent notes without inventing features or fixes. Validation: 4,155 tests passed, 66 skipped; typecheck, lint, and release notes verification passed. The affected 20 tests passed three consecutive runs; all 227 App and Agent release-note tests passed. No local production build or packaging was run.
194 lines
6.1 KiB
TypeScript
194 lines
6.1 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).toMatch(/^## (?:功能更新|问题修复|维护更新)$/mu)
|
|
expect(notes).toMatch(/^## (?:Features|Bug Fixes|Maintenance)$/mu)
|
|
expect(notes.includes('## 功能更新')).toBe(notes.includes('## Features'))
|
|
expect(notes.includes('## 问题修复')).toBe(notes.includes('## Bug Fixes'))
|
|
expect(notes.includes('## 维护更新')).toBe(notes.includes('## Maintenance'))
|
|
})
|
|
|
|
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'
|
|
)
|
|
})
|
|
})
|