diff --git a/.github/workflows/update-post-release-readme-urls.yml b/.github/workflows/update-post-release-readme-urls.yml new file mode 100644 index 000000000..60064b319 --- /dev/null +++ b/.github/workflows/update-post-release-readme-urls.yml @@ -0,0 +1,41 @@ +name: Update (Post Release) README URLs + +on: + release: + types: + - released + workflow_dispatch: + inputs: + tag: + description: 'Release tag (e.g., v0.9.0-alpha.7)' + required: true + type: string + +permissions: + contents: write + +jobs: + update: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - uses: pnpm/action-setup@v4 + with: + run_install: false + - uses: actions/setup-node@v6 + with: + node-version: lts/* + cache: pnpm + - run: pnpm install --frozen-lockfile + + - name: Update README download links + run: pnpm -F @proj-airi/stage-tamagotchi exec tsx scripts/update-readme-download-links.ts ${{ github.event.release.tag_name || inputs.tag }} + + - name: Pull with rebase + run: git pull --rebase --autostash + + - uses: stefanzweifel/git-auto-commit-action@v6 + with: + commit_message: 'chore: update README release artifacts to ${{ github.event.release.tag_name || inputs.tag }}' + commit_author: github-actions[bot] diff --git a/apps/stage-tamagotchi/scripts/update-readme-download-links.ts b/apps/stage-tamagotchi/scripts/update-readme-download-links.ts new file mode 100644 index 000000000..8604740a6 --- /dev/null +++ b/apps/stage-tamagotchi/scripts/update-readme-download-links.ts @@ -0,0 +1,83 @@ +import process from 'node:process' + +import { readdir, readFile, writeFile } from 'node:fs/promises' +import { resolve } from 'node:path' + +import { getFilenames } from './utils' + +const ROOT_DIR = resolve(import.meta.dirname, '..', '..', '..') +const DOCS_DIR = resolve(ROOT_DIR, 'docs') + +// GitHub releases download URLs +const GITHUB_WINDOWS_RE = /https:\/\/github\.com\/moeru-ai\/airi\/releases\/download\/v[^/]+\/AIRI-[^")\s]+-windows-x64-setup\.exe/g +const GITHUB_MACOS_RE = /https:\/\/github\.com\/moeru-ai\/airi\/releases\/download\/v[^/]+\/AIRI-[^")\s]+-darwin-arm64\.dmg/g + +// Aliyun OSS mirror download URLs (used by zh-CN README) +const OSS_WINDOWS_RE = /https:\/\/static-cn-proj-airi\.oss-cn-shanghai\.aliyuncs\.com\/artifacts\/apps\/desktop\/versions\/v[^/]+\/AIRI-[^")\s]+-windows-x64-setup\.exe/g +const OSS_MACOS_RE = /https:\/\/static-cn-proj-airi\.oss-cn-shanghai\.aliyuncs\.com\/artifacts\/apps\/desktop\/versions\/v[^/]+\/AIRI-[^")\s]+-darwin-arm64\.dmg/g + +async function main() { + const version = process.argv[2] + if (!version) { + console.error('Usage: tsx update-readme-download-links.ts ') + console.error('Example: tsx update-readme-download-links.ts v0.9.0-alpha.7') + process.exit(1) + } + + const cleanVersion = version.replace(/^v/, '') + const releaseOptions = { release: true, autoTag: false, tag: [cleanVersion] } + + const windowsFilenames = await getFilenames('x86_64-pc-windows-msvc', releaseOptions) + const macosFilenames = await getFilenames('aarch64-apple-darwin', releaseOptions) + + const windowsExe = windowsFilenames.find(f => f.extension === 'exe')?.releaseArtifactFilename + const macosDmg = macosFilenames.find(f => f.extension === 'dmg')?.releaseArtifactFilename + + if (!windowsExe || !macosDmg) { + console.error('Failed to determine artifact filenames') + process.exit(1) + } + + console.info(`Windows: ${windowsExe}`) + console.info(`macOS: ${macosDmg}`) + + function updateContent(content: string): string { + return content + .replace(GITHUB_WINDOWS_RE, `https://github.com/moeru-ai/airi/releases/download/v${cleanVersion}/${windowsExe}`) + .replace(GITHUB_MACOS_RE, `https://github.com/moeru-ai/airi/releases/download/v${cleanVersion}/${macosDmg}`) + .replace(OSS_WINDOWS_RE, `https://static-cn-proj-airi.oss-cn-shanghai.aliyuncs.com/artifacts/apps/desktop/versions/v${cleanVersion}/${windowsExe}`) + .replace(OSS_MACOS_RE, `https://static-cn-proj-airi.oss-cn-shanghai.aliyuncs.com/artifacts/apps/desktop/versions/v${cleanVersion}/${macosDmg}`) + } + + const readmeFiles: string[] = [ + resolve(ROOT_DIR, 'README.md'), + ] + + const docsFiles = await readdir(DOCS_DIR) + for (const file of docsFiles) { + if (file.startsWith('README') && file.endsWith('.md')) { + readmeFiles.push(resolve(DOCS_DIR, file)) + } + } + + let updatedCount = 0 + for (const filePath of readmeFiles) { + const content = await readFile(filePath, 'utf-8') + const updated = updateContent(content) + if (content !== updated) { + await writeFile(filePath, updated, 'utf-8') + console.info(`Updated: ${filePath}`) + updatedCount++ + } + else { + console.info(`No changes: ${filePath}`) + } + } + + console.info(`\nDone. Updated ${updatedCount} file(s).`) +} + +main().catch((error) => { + console.error('Error:', error) + process.exit(1) +})