From dd4987a9ac2438cbf7fa180249019964227bcf41 Mon Sep 17 00:00:00 2001 From: Will Chen Date: Mon, 21 Jul 2025 11:07:53 -0700 Subject: [PATCH] Verify release (#679) Context: https://github.com/electron/forge/issues/3965 --- .github/workflows/release.yml | 16 ++++ package.json | 1 + scripts/README.md | 38 +++++++++ scripts/verify-release-assets.js | 128 +++++++++++++++++++++++++++++++ 4 files changed, 183 insertions(+) create mode 100755 scripts/verify-release-assets.js diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b4b2e59..82cbddb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -71,3 +71,19 @@ jobs: APPLE_ID: ${{ secrets.APPLE_ID }} APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }} run: npm run publish + + verify-assets: + name: Verify Release Assets + needs: build + runs-on: ubuntu-latest + steps: + - name: Github checkout + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Use Node.js + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 + with: + node-version: 20 + - name: Verify all release assets are uploaded + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: node scripts/verify-release-assets.js diff --git a/package.json b/package.json index 08c8808..2b6e558 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "package": "npm run clean && electron-forge package", "make": "npm run clean && electron-forge make", "publish": "npm run clean && electron-forge publish", + "verify-release": "node scripts/verify-release-assets.js", "ts": "npm run ts:main && npm run ts:workers", "ts:main": "npx tsc -p tsconfig.app.json --noEmit", "ts:workers": "npx tsc -p workers/tsc/tsconfig.json --noEmit", diff --git a/scripts/README.md b/scripts/README.md index ddd2209..bd9fbf4 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -26,3 +26,41 @@ chmod +x scripts/extract-codebase.ts - Extracts files with extensions: .ts, .tsx, .js, .jsx, .css - Formats output with markdown code blocks, including file paths - Writes all extracted code to a single markdown file + +## verify-release-assets.js + +A script that verifies all expected binary assets are present in the GitHub release for the current version in `package.json`. + +### Usage + +```bash +# Set GITHUB_TOKEN environment variable +export GITHUB_TOKEN=your_github_token + +# Run the verification script +npm run verify-release + +# Or run directly +node scripts/verify-release-assets.js +``` + +### Expected Assets + +The script verifies the presence of these 7 assets for each release: + +1. `dyad-{version}-1.x86_64.rpm` (Linux RPM) +2. `dyad-{version}-full.nupkg` (Windows NuGet package) +3. `dyad-{version}.Setup.exe` (Windows installer) +4. `dyad-darwin-arm64-{version}.zip` (macOS Apple Silicon) +5. `dyad-darwin-x64-{version}.zip` (macOS Intel) +6. `dyad_{version}_amd64.deb` (Linux DEB) +7. `RELEASES` (Windows update manifest) + +### Features + +- Reads version from `package.json` automatically +- Fetches release information from GitHub API +- Lists all expected vs actual assets +- Fails with clear error messages if assets are missing +- Shows warnings for unexpected assets +- Provides detailed release summary on success diff --git a/scripts/verify-release-assets.js b/scripts/verify-release-assets.js new file mode 100755 index 0000000..1c94911 --- /dev/null +++ b/scripts/verify-release-assets.js @@ -0,0 +1,128 @@ +#!/usr/bin/env node + +const fs = require("fs"); +const path = require("path"); + +/** + * Verifies that all expected binary assets are present in the GitHub release + * for the version specified in package.json + */ +async function verifyReleaseAssets() { + try { + // Read version from package.json + const packagePath = path.join(__dirname, "..", "package.json"); + const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf8")); + const version = packageJson.version; + + console.log(`🔍 Verifying release assets for version ${version}...`); + + // GitHub API configuration + const owner = "dyad-sh"; + const repo = "dyad"; + const token = process.env.GITHUB_TOKEN; + + if (!token) { + throw new Error("GITHUB_TOKEN environment variable is required"); + } + + // Fetch all releases (including drafts) + const tagName = `v${version}`; + + console.log(`📡 Fetching all releases to find: ${tagName}`); + + const allReleasesUrl = `https://api.github.com/repos/${owner}/${repo}/releases`; + const response = await fetch(allReleasesUrl, { + headers: { + Authorization: `token ${token}`, + Accept: "application/vnd.github.v3+json", + "User-Agent": "dyad-release-verifier", + }, + }); + + if (!response.ok) { + throw new Error( + `GitHub API error: ${response.status} ${response.statusText}`, + ); + } + + const allReleases = await response.json(); + const release = allReleases.find((r) => r.tag_name === tagName); + + if (!release) { + throw new Error( + `Release ${tagName} not found in published releases or drafts. Make sure the release exists.`, + ); + } + + const assets = release.assets || []; + + console.log(`📦 Found ${assets.length} assets in release ${tagName}`); + console.log(`📄 Release status: ${release.draft ? "DRAFT" : "PUBLISHED"}`); + + // Define expected assets + const expectedAssets = [ + `dyad-${version}-1.x86_64.rpm`, + `dyad-${version}-full.nupkg`, + `dyad-${version}.Setup.exe`, + `dyad-darwin-arm64-${version}.zip`, + `dyad-darwin-x64-${version}.zip`, + `dyad_${version}_amd64.deb`, + "RELEASES", + ]; + + console.log("📋 Expected assets:"); + expectedAssets.forEach((asset) => console.log(` - ${asset}`)); + console.log(""); + + // Get actual asset names + const actualAssets = assets.map((asset) => asset.name); + + console.log("📋 Actual assets:"); + actualAssets.forEach((asset) => console.log(` - ${asset}`)); + console.log(""); + + // Check for missing assets + const missingAssets = expectedAssets.filter( + (expected) => !actualAssets.includes(expected), + ); + + if (missingAssets.length > 0) { + console.error("❌ VERIFICATION FAILED!"); + console.error("📭 Missing assets:"); + missingAssets.forEach((asset) => console.error(` - ${asset}`)); + console.error(""); + console.error( + "Please ensure all platforms have completed their builds and uploads.", + ); + process.exit(1); + } + + // Check for unexpected assets (optional warning) + const unexpectedAssets = actualAssets.filter( + (actual) => !expectedAssets.includes(actual), + ); + + if (unexpectedAssets.length > 0) { + console.warn("⚠️ Unexpected assets found:"); + unexpectedAssets.forEach((asset) => console.warn(` - ${asset}`)); + console.warn(""); + } + + console.log("✅ VERIFICATION PASSED!"); + console.log( + `🎉 All ${expectedAssets.length} expected assets are present in release ${tagName}`, + ); + console.log(""); + console.log("📊 Release Summary:"); + console.log(` Release: ${release.name || tagName}`); + console.log(` Tag: ${release.tag_name}`); + console.log(` Published: ${release.published_at}`); + console.log(` URL: ${release.html_url}`); + } catch (error) { + console.error("❌ Error verifying release assets:", error.message); + process.exit(1); + } +} + +// Run the verification +verifyReleaseAssets();