From d4dfa3a2f0189dc37940f1be48a89d68e5df180e Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Tue, 25 Nov 2025 17:02:24 -0600 Subject: [PATCH 01/12] create release script --- apps/desktop/create-release.sh | 135 +++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100755 apps/desktop/create-release.sh diff --git a/apps/desktop/create-release.sh b/apps/desktop/create-release.sh new file mode 100755 index 00000000000..0b936038c20 --- /dev/null +++ b/apps/desktop/create-release.sh @@ -0,0 +1,135 @@ +#!/usr/bin/env bash + +# Desktop App Release Script +# Based on apps/desktop/RELEASE.md +# +# Usage: +# ./create-release-0.0.1.sh +# Example: ./create-release-0.0.1.sh 0.0.1 +# +# This script will: +# 1. Verify prerequisites (clean git, build works) +# 2. Update package.json version +# 3. Create and push a git tag to trigger the release workflow +# 4. The GitHub Action will build for macOS (arm64) and create a draft release + +set -e # Exit on error + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Helper functions +info() { + echo -e "${BLUE}ℹ ${NC}$1" +} + +success() { + echo -e "${GREEN}✓${NC} $1" +} + +warn() { + echo -e "${YELLOW}⚠${NC} $1" +} + +error() { + echo -e "${RED}✗${NC} $1" + exit 1 +} + +# Check if version argument is provided +if [ -z "$1" ]; then + error "Usage: $0 \nExample: $0 0.0.1" +fi + +VERSION="$1" +TAG_NAME="desktop-v${VERSION}" +DESKTOP_DIR="apps/desktop" + +info "Starting release process for version ${VERSION}" +echo "" + +# Check if we're in the monorepo root +if [ ! -f "package.json" ] || [ ! -d "apps/desktop" ]; then + error "Please run this script from the monorepo root directory" +fi + +# Navigate to desktop app directory +cd "${DESKTOP_DIR}" + +# 1. Check for uncommitted changes +info "Checking for uncommitted changes..." +if ! git diff-index --quiet HEAD --; then + error "You have uncommitted changes. Please commit or stash them first." +fi +success "Working directory is clean" + +# 2. Check if tag already exists +info "Checking if tag ${TAG_NAME} already exists..." +if git rev-parse "${TAG_NAME}" >/dev/null 2>&1; then + error "Tag ${TAG_NAME} already exists. Use a different version or delete the existing tag." +fi +success "Tag ${TAG_NAME} is available" + +# 3. Update version in package.json +info "Updating version in package.json..." +CURRENT_VERSION=$(node -p "require('./package.json').version") +if [ "${CURRENT_VERSION}" == "${VERSION}" ]; then + warn "package.json already has version ${VERSION}" +else + # Use bun to update the version + bun version "${VERSION}" --no-git-tag-version + success "Updated package.json from ${CURRENT_VERSION} to ${VERSION}" + + # Commit the version change + git add package.json + git commit -m "chore(desktop): bump version to ${VERSION}" + success "Committed version change" +fi + +# 4. Verify build works locally +info "Testing build locally (this may take a few minutes)..." +info "Running: bun run package" +if ! bun run package; then + error "Build failed. Please fix the issues before releasing." +fi +success "Build completed successfully" + +# 5. Push changes +info "Pushing changes to remote..." +CURRENT_BRANCH=$(git branch --show-current) +git push origin "${CURRENT_BRANCH}" +success "Changes pushed to ${CURRENT_BRANCH}" + +# 6. Create and push tag +info "Creating tag ${TAG_NAME}..." +git tag "${TAG_NAME}" +success "Tag ${TAG_NAME} created" + +info "Pushing tag to trigger release workflow..." +git push origin "${TAG_NAME}" +success "Tag pushed to remote" + +echo "" +echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" +echo -e "${GREEN}🎉 Release process initiated successfully!${NC}" +echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" +echo "" +info "Next steps:" +echo " 1. Monitor the GitHub Actions workflow at:" +echo " https://github.com/$(git remote get-url origin | sed 's/.*github.com[:/]\(.*\)\.git/\1/')/actions" +echo "" +echo " 2. Once the workflow completes, a draft release will be created" +echo "" +echo " 3. Review the draft release at:" +echo " https://github.com/$(git remote get-url origin | sed 's/.*github.com[:/]\(.*\)\.git/\1/')/releases" +echo "" +echo " 4. Edit the release notes if needed and publish the release" +echo "" +info "Release artifacts will include:" +echo " • Superset-${VERSION}-arm64.dmg (macOS DMG installer)" +echo " • Superset-${VERSION}-arm64-mac.zip (macOS zipped app bundle)" +echo "" From ad7d830edf2702b35282ea0a55d85ccdb288c990 Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Tue, 25 Nov 2025 17:57:21 -0600 Subject: [PATCH 02/12] feat(desktop): add workflow monitoring and draft release URL to create-release script - Add GitHub CLI validation and authentication checks - Monitor GitHub Actions workflow in real-time - Display draft release URL when ready - Add retry logic for workflow and release detection - Improve error handling and user feedback --- apps/desktop/create-release.sh | 122 +++++++++++++++++++++++++++++---- 1 file changed, 109 insertions(+), 13 deletions(-) diff --git a/apps/desktop/create-release.sh b/apps/desktop/create-release.sh index 0b936038c20..c6bb76696c1 100755 --- a/apps/desktop/create-release.sh +++ b/apps/desktop/create-release.sh @@ -4,14 +4,21 @@ # Based on apps/desktop/RELEASE.md # # Usage: -# ./create-release-0.0.1.sh -# Example: ./create-release-0.0.1.sh 0.0.1 +# ./create-release.sh +# Example: ./create-release.sh 0.0.1 # # This script will: -# 1. Verify prerequisites (clean git, build works) +# 1. Verify prerequisites (clean git, GitHub CLI authenticated) # 2. Update package.json version -# 3. Create and push a git tag to trigger the release workflow -# 4. The GitHub Action will build for macOS (arm64) and create a draft release +# 3. Verify build works locally +# 4. Create and push a git tag to trigger the release workflow +# 5. Monitor the GitHub Actions workflow in real-time +# 6. Display the draft release URL when ready +# +# Requirements: +# - GitHub CLI (gh) installed and authenticated +# - Clean working directory +# - Running from monorepo root set -e # Exit on error @@ -49,6 +56,16 @@ VERSION="$1" TAG_NAME="desktop-v${VERSION}" DESKTOP_DIR="apps/desktop" +# Check if gh CLI is installed +if ! command -v gh &> /dev/null; then + error "GitHub CLI (gh) is required but not installed.\nInstall it from: https://cli.github.com/" +fi + +# Check if authenticated with gh +if ! gh auth status &> /dev/null; then + error "Not authenticated with GitHub CLI.\nRun: gh auth login" +fi + info "Starting release process for version ${VERSION}" echo "" @@ -118,16 +135,95 @@ echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━ echo -e "${GREEN}🎉 Release process initiated successfully!${NC}" echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" echo "" -info "Next steps:" -echo " 1. Monitor the GitHub Actions workflow at:" -echo " https://github.com/$(git remote get-url origin | sed 's/.*github.com[:/]\(.*\)\.git/\1/')/actions" -echo "" -echo " 2. Once the workflow completes, a draft release will be created" + +# Get repository information +REPO=$(git remote get-url origin | sed 's/.*github.com[:/]\(.*\)\.git/\1/') + +# 7. Monitor the workflow +info "Monitoring GitHub Actions workflow..." +echo " Waiting for workflow to start (this may take a few seconds)..." + +# Wait and retry to find the workflow run +MAX_RETRIES=6 +RETRY_COUNT=0 +WORKFLOW_RUN="" + +while [ $RETRY_COUNT -lt $MAX_RETRIES ] && [ -z "$WORKFLOW_RUN" ]; do + sleep 5 + WORKFLOW_RUN=$(gh run list --workflow=release-desktop.yml --json databaseId,headBranch,status --jq ".[] | select(.headBranch == \"${TAG_NAME}\") | .databaseId" | head -1) + RETRY_COUNT=$((RETRY_COUNT + 1)) + + if [ -z "$WORKFLOW_RUN" ] && [ $RETRY_COUNT -lt $MAX_RETRIES ]; then + echo " Still waiting... (attempt $RETRY_COUNT/$MAX_RETRIES)" + fi +done + +if [ -z "$WORKFLOW_RUN" ]; then + warn "Could not find workflow run automatically" + echo " Manual monitoring URL:" + echo " https://github.com/${REPO}/actions" + echo "" + warn "The workflow may still be starting. Check the URL above in a few moments." +else + success "Found workflow run: ${WORKFLOW_RUN}" + echo "" + info "Watching workflow progress..." + echo " View in browser: https://github.com/${REPO}/actions/runs/${WORKFLOW_RUN}" + echo "" + + # Watch the workflow (this will stream the status) + gh run watch "${WORKFLOW_RUN}" || warn "Workflow monitoring interrupted" + + # Check final status + WORKFLOW_STATUS=$(gh run view "${WORKFLOW_RUN}" --json conclusion --jq .conclusion) + + if [ "$WORKFLOW_STATUS" == "success" ]; then + success "Workflow completed successfully!" + elif [ "$WORKFLOW_STATUS" == "failure" ]; then + error "Workflow failed. Please check the logs at: https://github.com/${REPO}/actions/runs/${WORKFLOW_RUN}" + else + warn "Workflow ended with status: ${WORKFLOW_STATUS}" + fi +fi + echo "" -echo " 3. Review the draft release at:" -echo " https://github.com/$(git remote get-url origin | sed 's/.*github.com[:/]\(.*\)\.git/\1/')/releases" + +# 8. Get and display draft release URL +info "Fetching draft release..." + +# Retry logic for draft release (it may take time to be created) +MAX_RELEASE_RETRIES=10 +RELEASE_RETRY_COUNT=0 +RELEASE_FOUND="" + +while [ $RELEASE_RETRY_COUNT -lt $MAX_RELEASE_RETRIES ] && [ -z "$RELEASE_FOUND" ]; do + sleep 3 + RELEASE_FOUND=$(gh release list --json tagName,isDraft --jq ".[] | select(.tagName == \"${TAG_NAME}\" and .isDraft == true) | .tagName") + RELEASE_RETRY_COUNT=$((RELEASE_RETRY_COUNT + 1)) + + if [ -z "$RELEASE_FOUND" ] && [ $RELEASE_RETRY_COUNT -lt $MAX_RELEASE_RETRIES ]; then + echo " Waiting for draft release to be created... (attempt $RELEASE_RETRY_COUNT/$MAX_RELEASE_RETRIES)" + fi +done + +if [ -z "$RELEASE_FOUND" ]; then + warn "Draft release not found yet. It may still be processing." + echo " Check releases at: https://github.com/${REPO}/releases" +else + RELEASE_URL="https://github.com/${REPO}/releases/tag/${TAG_NAME}" + success "Draft release created!" + echo "" + echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" + echo -e "${BLUE}📦 Draft Release URL:${NC}" + echo -e "${GREEN}${RELEASE_URL}${NC}" + echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" + echo "" +fi + echo "" -echo " 4. Edit the release notes if needed and publish the release" +info "Next steps:" +echo " 1. Review the draft release and edit release notes if needed" +echo " 2. Publish the release when ready" echo "" info "Release artifacts will include:" echo " • Superset-${VERSION}-arm64.dmg (macOS DMG installer)" From 78ba905f6e0371f7bdebbe8fa7c086e5e10d64ff Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Tue, 25 Nov 2025 17:57:49 -0600 Subject: [PATCH 03/12] fix(desktop): use npm version instead of bun version in release script --- apps/desktop/create-release.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/desktop/create-release.sh b/apps/desktop/create-release.sh index c6bb76696c1..75b21afb9bc 100755 --- a/apps/desktop/create-release.sh +++ b/apps/desktop/create-release.sh @@ -97,8 +97,8 @@ CURRENT_VERSION=$(node -p "require('./package.json').version") if [ "${CURRENT_VERSION}" == "${VERSION}" ]; then warn "package.json already has version ${VERSION}" else - # Use bun to update the version - bun version "${VERSION}" --no-git-tag-version + # Update the version using npm (which bun supports) + npm version "${VERSION}" --no-git-tag-version --allow-same-version success "Updated package.json from ${CURRENT_VERSION} to ${VERSION}" # Commit the version change From c5bc85d304ae45b88b1b72bbdd804f17a78217b1 Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Tue, 25 Nov 2025 17:58:22 -0600 Subject: [PATCH 04/12] fix(desktop): use jq to update version in package.json npm version doesn't work with workspace dependencies, so use jq instead to directly modify the version field. --- apps/desktop/create-release.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/desktop/create-release.sh b/apps/desktop/create-release.sh index 75b21afb9bc..9a20fcff1e6 100755 --- a/apps/desktop/create-release.sh +++ b/apps/desktop/create-release.sh @@ -97,8 +97,9 @@ CURRENT_VERSION=$(node -p "require('./package.json').version") if [ "${CURRENT_VERSION}" == "${VERSION}" ]; then warn "package.json already has version ${VERSION}" else - # Update the version using npm (which bun supports) - npm version "${VERSION}" --no-git-tag-version --allow-same-version + # Update the version using jq to handle workspace dependencies + TMP_FILE=$(mktemp) + jq ".version = \"${VERSION}\"" package.json > "${TMP_FILE}" && mv "${TMP_FILE}" package.json success "Updated package.json from ${CURRENT_VERSION} to ${VERSION}" # Commit the version change From 65bad36021d61bdeac0cb599b6ba5035b12bc841 Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Tue, 25 Nov 2025 18:11:53 -0600 Subject: [PATCH 05/12] fix(desktop): remove unnecessary local build step from release script The CI/CD pipeline handles the build, so building locally is unnecessary and can cause issues with notarization credentials. --- apps/desktop/create-release.sh | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/apps/desktop/create-release.sh b/apps/desktop/create-release.sh index 9a20fcff1e6..5dfb85e1584 100755 --- a/apps/desktop/create-release.sh +++ b/apps/desktop/create-release.sh @@ -10,10 +10,9 @@ # This script will: # 1. Verify prerequisites (clean git, GitHub CLI authenticated) # 2. Update package.json version -# 3. Verify build works locally -# 4. Create and push a git tag to trigger the release workflow -# 5. Monitor the GitHub Actions workflow in real-time -# 6. Display the draft release URL when ready +# 3. Create and push a git tag to trigger the release workflow +# 4. Monitor the GitHub Actions workflow in real-time +# 5. Display the draft release URL when ready # # Requirements: # - GitHub CLI (gh) installed and authenticated @@ -108,21 +107,13 @@ else success "Committed version change" fi -# 4. Verify build works locally -info "Testing build locally (this may take a few minutes)..." -info "Running: bun run package" -if ! bun run package; then - error "Build failed. Please fix the issues before releasing." -fi -success "Build completed successfully" - -# 5. Push changes +# 4. Push changes info "Pushing changes to remote..." CURRENT_BRANCH=$(git branch --show-current) git push origin "${CURRENT_BRANCH}" success "Changes pushed to ${CURRENT_BRANCH}" -# 6. Create and push tag +# 5. Create and push tag info "Creating tag ${TAG_NAME}..." git tag "${TAG_NAME}" success "Tag ${TAG_NAME} created" @@ -140,7 +131,7 @@ echo "" # Get repository information REPO=$(git remote get-url origin | sed 's/.*github.com[:/]\(.*\)\.git/\1/') -# 7. Monitor the workflow +# 6. Monitor the workflow info "Monitoring GitHub Actions workflow..." echo " Waiting for workflow to start (this may take a few seconds)..." @@ -189,7 +180,7 @@ fi echo "" -# 8. Get and display draft release URL +# 7. Get and display draft release URL info "Fetching draft release..." # Retry logic for draft release (it may take time to be created) From fd49f51ea694aa33add8eb816d9c0389c8bf27c0 Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Tue, 25 Nov 2025 18:12:07 -0600 Subject: [PATCH 06/12] chore(desktop): bump version to 0.0.1 --- apps/desktop/package.json | 222 +++++++++++++++++++------------------- 1 file changed, 111 insertions(+), 111 deletions(-) diff --git a/apps/desktop/package.json b/apps/desktop/package.json index c8a3266dff6..9ff5111bedf 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -1,113 +1,113 @@ { - "name": "@superset/desktop", - "productName": "Superset", - "description": "The last developer tool you'll ever need", - "version": "0.0.0", - "main": "./dist/main/index.js", - "resources": "src/resources", - "repository": { - "type": "git", - "url": "https://github.com/superset-sh/superset.git" - }, - "author": { - "name": "Superset", - "email": "hi@superset.sh" - }, - "scripts": { - "start": "electron-vite preview", - "predev": "bun run clean:dev", - "dev": "cross-env NODE_ENV=development electron-vite dev --watch", - "compile:app": "electron-vite build", - "prebuild": "bun run clean:dev && bun run compile:app", - "build": "electron-builder", - "package": "electron-builder --config electron-builder.ts", - "install:deps": "electron-builder install-app-deps", - "make:release": "tsx ./src/lib/electron-app/release/modules/release.ts", - "release": "electron-builder --publish always", - "clean:dev": "rimraf ./node_modules/.dev", - "typecheck": "tsc --noEmit", - "lint": "biome check --no-errors-on-unmatched", - "lint:fix": "biome check --write --no-errors-on-unmatched --assist-enabled=true", - "format": "biome format --write --no-errors-on-unmatched", - "format:check": "biome format --no-errors-on-unmatched" - }, - "dependencies": { - "@dnd-kit/core": "^6.3.1", - "@dnd-kit/sortable": "^10.0.0", - "@dnd-kit/utilities": "^3.2.2", - "@radix-ui/react-dialog": "^1.1.15", - "@radix-ui/react-label": "^2.1.8", - "@superset/ui": "workspace:*", - "@tanstack/react-query": "^5.90.10", - "@trpc/client": "^11.7.1", - "@trpc/react-query": "^11.7.1", - "@trpc/server": "^11.7.1", - "@types/express": "^5.0.5", - "@xterm/addon-clipboard": "^0.1.0", - "@xterm/addon-fit": "^0.10.0", - "@xterm/addon-image": "^0.8.0", - "@xterm/addon-search": "^0.15.0", - "@xterm/addon-serialize": "^0.13.0", - "@xterm/addon-unicode11": "^0.8.0", - "@xterm/addon-web-links": "^0.11.0", - "@xterm/addon-webgl": "^0.18.0", - "@xterm/xterm": "^5.5.0", - "clsx": "^2.1.1", - "dotenv": "^17.2.3", - "electron-router-dom": "^2.1.0", - "electron-store": "^11.0.2", - "execa": "^9.6.0", - "express": "^5.1.0", - "fast-glob": "^3.3.3", - "framer-motion": "^12.23.24", - "http-proxy": "^1.18.1", - "line-column-path": "^3.0.0", - "lodash": "^4.17.21", - "lowdb": "^7.0.1", - "nanoid": "^5.1.6", - "node-pty": "1.1.0-beta30", - "react": "^19.1.1", - "react-arborist": "^3.4.3", - "react-dnd": "^16.0.1", - "react-dnd-html5-backend": "^16.0.1", - "react-dom": "^19.1.1", - "react-hotkeys-hook": "^5.2.1", - "react-icons": "^5.5.0", - "react-mosaic-component": "^6.1.1", - "react-resizable-panels": "^3.0.6", - "react-router-dom": "^7.8.2", - "react-syntax-highlighter": "^16.1.0", - "simple-git": "^3.30.0", - "superjson": "^2.2.5", - "tailwind-merge": "^2.6.0", - "trpc-electron": "^0.1.2", - "zod": "^4.1.12", - "zustand": "^5.0.8" - }, - "devDependencies": { - "@biomejs/biome": "^2.2.6", - "@tailwindcss/vite": "^4.0.9", - "@types/http-proxy": "^1.17.17", - "@types/lodash": "^4.17.20", - "@types/node": "^24.9.1", - "@types/react": "^19.1.11", - "@types/react-dom": "^19.1.7", - "@types/react-syntax-highlighter": "^15.5.13", - "@types/semver": "^7.7.1", - "@vitejs/plugin-react": "^5.0.1", - "code-inspector-plugin": "^1.2.2", - "cross-env": "^10.0.0", - "electron": "39.1.2", - "electron-builder": "^26.0.12", - "electron-extension-installer": "^2.0.0", - "electron-vite": "^4.0.0", - "rimraf": "^6.0.1", - "rollup-plugin-inject-process-env": "^1.3.1", - "tailwindcss": "^4.0.9", - "tailwindcss-animate": "^1.0.7", - "tsx": "^4.19.3", - "typescript": "^5.9.3", - "vite": "^7.1.3", - "vite-tsconfig-paths": "^5.1.4" - } + "name": "@superset/desktop", + "productName": "Superset", + "description": "The last developer tool you'll ever need", + "version": "0.0.1", + "main": "./dist/main/index.js", + "resources": "src/resources", + "repository": { + "type": "git", + "url": "https://github.com/superset-sh/superset.git" + }, + "author": { + "name": "Superset", + "email": "hi@superset.sh" + }, + "scripts": { + "start": "electron-vite preview", + "predev": "bun run clean:dev", + "dev": "cross-env NODE_ENV=development electron-vite dev --watch", + "compile:app": "electron-vite build", + "prebuild": "bun run clean:dev && bun run compile:app", + "build": "electron-builder", + "package": "electron-builder --config electron-builder.ts", + "install:deps": "electron-builder install-app-deps", + "make:release": "tsx ./src/lib/electron-app/release/modules/release.ts", + "release": "electron-builder --publish always", + "clean:dev": "rimraf ./node_modules/.dev", + "typecheck": "tsc --noEmit", + "lint": "biome check --no-errors-on-unmatched", + "lint:fix": "biome check --write --no-errors-on-unmatched --assist-enabled=true", + "format": "biome format --write --no-errors-on-unmatched", + "format:check": "biome format --no-errors-on-unmatched" + }, + "dependencies": { + "@dnd-kit/core": "^6.3.1", + "@dnd-kit/sortable": "^10.0.0", + "@dnd-kit/utilities": "^3.2.2", + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-label": "^2.1.8", + "@superset/ui": "workspace:*", + "@tanstack/react-query": "^5.90.10", + "@trpc/client": "^11.7.1", + "@trpc/react-query": "^11.7.1", + "@trpc/server": "^11.7.1", + "@types/express": "^5.0.5", + "@xterm/addon-clipboard": "^0.1.0", + "@xterm/addon-fit": "^0.10.0", + "@xterm/addon-image": "^0.8.0", + "@xterm/addon-search": "^0.15.0", + "@xterm/addon-serialize": "^0.13.0", + "@xterm/addon-unicode11": "^0.8.0", + "@xterm/addon-web-links": "^0.11.0", + "@xterm/addon-webgl": "^0.18.0", + "@xterm/xterm": "^5.5.0", + "clsx": "^2.1.1", + "dotenv": "^17.2.3", + "electron-router-dom": "^2.1.0", + "electron-store": "^11.0.2", + "execa": "^9.6.0", + "express": "^5.1.0", + "fast-glob": "^3.3.3", + "framer-motion": "^12.23.24", + "http-proxy": "^1.18.1", + "line-column-path": "^3.0.0", + "lodash": "^4.17.21", + "lowdb": "^7.0.1", + "nanoid": "^5.1.6", + "node-pty": "1.1.0-beta30", + "react": "^19.1.1", + "react-arborist": "^3.4.3", + "react-dnd": "^16.0.1", + "react-dnd-html5-backend": "^16.0.1", + "react-dom": "^19.1.1", + "react-hotkeys-hook": "^5.2.1", + "react-icons": "^5.5.0", + "react-mosaic-component": "^6.1.1", + "react-resizable-panels": "^3.0.6", + "react-router-dom": "^7.8.2", + "react-syntax-highlighter": "^16.1.0", + "simple-git": "^3.30.0", + "superjson": "^2.2.5", + "tailwind-merge": "^2.6.0", + "trpc-electron": "^0.1.2", + "zod": "^4.1.12", + "zustand": "^5.0.8" + }, + "devDependencies": { + "@biomejs/biome": "^2.2.6", + "@tailwindcss/vite": "^4.0.9", + "@types/http-proxy": "^1.17.17", + "@types/lodash": "^4.17.20", + "@types/node": "^24.9.1", + "@types/react": "^19.1.11", + "@types/react-dom": "^19.1.7", + "@types/react-syntax-highlighter": "^15.5.13", + "@types/semver": "^7.7.1", + "@vitejs/plugin-react": "^5.0.1", + "code-inspector-plugin": "^1.2.2", + "cross-env": "^10.0.0", + "electron": "39.1.2", + "electron-builder": "^26.0.12", + "electron-extension-installer": "^2.0.0", + "electron-vite": "^4.0.0", + "rimraf": "^6.0.1", + "rollup-plugin-inject-process-env": "^1.3.1", + "tailwindcss": "^4.0.9", + "tailwindcss-animate": "^1.0.7", + "tsx": "^4.19.3", + "typescript": "^5.9.3", + "vite": "^7.1.3", + "vite-tsconfig-paths": "^5.1.4" + } } From e677f1bb69c4814e8525e2f87be2a7d1e885a13a Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Wed, 26 Nov 2025 18:31:49 -0600 Subject: [PATCH 07/12] release --- apps/desktop/package.json | 222 +++++++++--------- .../src/main/lib/terminal-history.test.ts | 3 +- 2 files changed, 112 insertions(+), 113 deletions(-) diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 9ff5111bedf..a423af4bc7a 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -1,113 +1,113 @@ { - "name": "@superset/desktop", - "productName": "Superset", - "description": "The last developer tool you'll ever need", - "version": "0.0.1", - "main": "./dist/main/index.js", - "resources": "src/resources", - "repository": { - "type": "git", - "url": "https://github.com/superset-sh/superset.git" - }, - "author": { - "name": "Superset", - "email": "hi@superset.sh" - }, - "scripts": { - "start": "electron-vite preview", - "predev": "bun run clean:dev", - "dev": "cross-env NODE_ENV=development electron-vite dev --watch", - "compile:app": "electron-vite build", - "prebuild": "bun run clean:dev && bun run compile:app", - "build": "electron-builder", - "package": "electron-builder --config electron-builder.ts", - "install:deps": "electron-builder install-app-deps", - "make:release": "tsx ./src/lib/electron-app/release/modules/release.ts", - "release": "electron-builder --publish always", - "clean:dev": "rimraf ./node_modules/.dev", - "typecheck": "tsc --noEmit", - "lint": "biome check --no-errors-on-unmatched", - "lint:fix": "biome check --write --no-errors-on-unmatched --assist-enabled=true", - "format": "biome format --write --no-errors-on-unmatched", - "format:check": "biome format --no-errors-on-unmatched" - }, - "dependencies": { - "@dnd-kit/core": "^6.3.1", - "@dnd-kit/sortable": "^10.0.0", - "@dnd-kit/utilities": "^3.2.2", - "@radix-ui/react-dialog": "^1.1.15", - "@radix-ui/react-label": "^2.1.8", - "@superset/ui": "workspace:*", - "@tanstack/react-query": "^5.90.10", - "@trpc/client": "^11.7.1", - "@trpc/react-query": "^11.7.1", - "@trpc/server": "^11.7.1", - "@types/express": "^5.0.5", - "@xterm/addon-clipboard": "^0.1.0", - "@xterm/addon-fit": "^0.10.0", - "@xterm/addon-image": "^0.8.0", - "@xterm/addon-search": "^0.15.0", - "@xterm/addon-serialize": "^0.13.0", - "@xterm/addon-unicode11": "^0.8.0", - "@xterm/addon-web-links": "^0.11.0", - "@xterm/addon-webgl": "^0.18.0", - "@xterm/xterm": "^5.5.0", - "clsx": "^2.1.1", - "dotenv": "^17.2.3", - "electron-router-dom": "^2.1.0", - "electron-store": "^11.0.2", - "execa": "^9.6.0", - "express": "^5.1.0", - "fast-glob": "^3.3.3", - "framer-motion": "^12.23.24", - "http-proxy": "^1.18.1", - "line-column-path": "^3.0.0", - "lodash": "^4.17.21", - "lowdb": "^7.0.1", - "nanoid": "^5.1.6", - "node-pty": "1.1.0-beta30", - "react": "^19.1.1", - "react-arborist": "^3.4.3", - "react-dnd": "^16.0.1", - "react-dnd-html5-backend": "^16.0.1", - "react-dom": "^19.1.1", - "react-hotkeys-hook": "^5.2.1", - "react-icons": "^5.5.0", - "react-mosaic-component": "^6.1.1", - "react-resizable-panels": "^3.0.6", - "react-router-dom": "^7.8.2", - "react-syntax-highlighter": "^16.1.0", - "simple-git": "^3.30.0", - "superjson": "^2.2.5", - "tailwind-merge": "^2.6.0", - "trpc-electron": "^0.1.2", - "zod": "^4.1.12", - "zustand": "^5.0.8" - }, - "devDependencies": { - "@biomejs/biome": "^2.2.6", - "@tailwindcss/vite": "^4.0.9", - "@types/http-proxy": "^1.17.17", - "@types/lodash": "^4.17.20", - "@types/node": "^24.9.1", - "@types/react": "^19.1.11", - "@types/react-dom": "^19.1.7", - "@types/react-syntax-highlighter": "^15.5.13", - "@types/semver": "^7.7.1", - "@vitejs/plugin-react": "^5.0.1", - "code-inspector-plugin": "^1.2.2", - "cross-env": "^10.0.0", - "electron": "39.1.2", - "electron-builder": "^26.0.12", - "electron-extension-installer": "^2.0.0", - "electron-vite": "^4.0.0", - "rimraf": "^6.0.1", - "rollup-plugin-inject-process-env": "^1.3.1", - "tailwindcss": "^4.0.9", - "tailwindcss-animate": "^1.0.7", - "tsx": "^4.19.3", - "typescript": "^5.9.3", - "vite": "^7.1.3", - "vite-tsconfig-paths": "^5.1.4" - } + "name": "@superset/desktop", + "productName": "Superset", + "description": "The last developer tool you'll ever need", + "version": "0.0.1", + "main": "./dist/main/index.js", + "resources": "src/resources", + "repository": { + "type": "git", + "url": "https://github.com/superset-sh/superset.git" + }, + "author": { + "name": "Superset", + "email": "hi@superset.sh" + }, + "scripts": { + "start": "electron-vite preview", + "predev": "bun run clean:dev", + "dev": "cross-env NODE_ENV=development electron-vite dev --watch", + "compile:app": "electron-vite build", + "prebuild": "bun run clean:dev && bun run compile:app", + "build": "electron-builder", + "package": "electron-builder --config electron-builder.ts", + "install:deps": "electron-builder install-app-deps", + "make:release": "tsx ./src/lib/electron-app/release/modules/release.ts", + "release": "electron-builder --publish always", + "clean:dev": "rimraf ./node_modules/.dev", + "typecheck": "tsc --noEmit", + "lint": "biome check --no-errors-on-unmatched", + "lint:fix": "biome check --write --no-errors-on-unmatched --assist-enabled=true", + "format": "biome format --write --no-errors-on-unmatched", + "format:check": "biome format --no-errors-on-unmatched" + }, + "dependencies": { + "@dnd-kit/core": "^6.3.1", + "@dnd-kit/sortable": "^10.0.0", + "@dnd-kit/utilities": "^3.2.2", + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-label": "^2.1.8", + "@superset/ui": "workspace:*", + "@tanstack/react-query": "^5.90.10", + "@trpc/client": "^11.7.1", + "@trpc/react-query": "^11.7.1", + "@trpc/server": "^11.7.1", + "@types/express": "^5.0.5", + "@xterm/addon-clipboard": "^0.1.0", + "@xterm/addon-fit": "^0.10.0", + "@xterm/addon-image": "^0.8.0", + "@xterm/addon-search": "^0.15.0", + "@xterm/addon-serialize": "^0.13.0", + "@xterm/addon-unicode11": "^0.8.0", + "@xterm/addon-web-links": "^0.11.0", + "@xterm/addon-webgl": "^0.18.0", + "@xterm/xterm": "^5.5.0", + "clsx": "^2.1.1", + "dotenv": "^17.2.3", + "electron-router-dom": "^2.1.0", + "electron-store": "^11.0.2", + "execa": "^9.6.0", + "express": "^5.1.0", + "fast-glob": "^3.3.3", + "framer-motion": "^12.23.24", + "http-proxy": "^1.18.1", + "line-column-path": "^3.0.0", + "lodash": "^4.17.21", + "lowdb": "^7.0.1", + "nanoid": "^5.1.6", + "node-pty": "1.1.0-beta30", + "react": "^19.1.1", + "react-arborist": "^3.4.3", + "react-dnd": "^16.0.1", + "react-dnd-html5-backend": "^16.0.1", + "react-dom": "^19.1.1", + "react-hotkeys-hook": "^5.2.1", + "react-icons": "^5.5.0", + "react-mosaic-component": "^6.1.1", + "react-resizable-panels": "^3.0.6", + "react-router-dom": "^7.8.2", + "react-syntax-highlighter": "^16.1.0", + "simple-git": "^3.30.0", + "superjson": "^2.2.5", + "tailwind-merge": "^2.6.0", + "trpc-electron": "^0.1.2", + "zod": "^4.1.12", + "zustand": "^5.0.8" + }, + "devDependencies": { + "@biomejs/biome": "^2.2.6", + "@tailwindcss/vite": "^4.0.9", + "@types/http-proxy": "^1.17.17", + "@types/lodash": "^4.17.20", + "@types/node": "^24.9.1", + "@types/react": "^19.1.11", + "@types/react-dom": "^19.1.7", + "@types/react-syntax-highlighter": "^15.5.13", + "@types/semver": "^7.7.1", + "@vitejs/plugin-react": "^5.0.1", + "code-inspector-plugin": "^1.2.2", + "cross-env": "^10.0.0", + "electron": "39.1.2", + "electron-builder": "^26.0.12", + "electron-extension-installer": "^2.0.0", + "electron-vite": "^4.0.0", + "rimraf": "^6.0.1", + "rollup-plugin-inject-process-env": "^1.3.1", + "tailwindcss": "^4.0.9", + "tailwindcss-animate": "^1.0.7", + "tsx": "^4.19.3", + "typescript": "^5.9.3", + "vite": "^7.1.3", + "vite-tsconfig-paths": "^5.1.4" + } } diff --git a/apps/desktop/src/main/lib/terminal-history.test.ts b/apps/desktop/src/main/lib/terminal-history.test.ts index 5c935bb984a..3c9c8233bed 100644 --- a/apps/desktop/src/main/lib/terminal-history.test.ts +++ b/apps/desktop/src/main/lib/terminal-history.test.ts @@ -166,8 +166,7 @@ describe("HistoryWriter", () => { ); // Mix of printable, control chars, and unicode - const binaryLikeData = - "Hello\x00World\x1b[31m红色\x1b[0m\t\r\n\x07Bell🔔"; + const binaryLikeData = "Hello\x00World\x1b[31m红色\x1b[0m\t\r\n\x07Bell🔔"; await writer.init(); writer.write(binaryLikeData); From f1e2ef9c03c05dd5b57ac96f30be95a35410da71 Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Wed, 26 Nov 2025 18:41:00 -0600 Subject: [PATCH 08/12] fix(desktop): disable auto-publish and add workflow permissions --- .github/workflows/release-desktop.yml | 3 +++ apps/desktop/electron-builder.ts | 3 +++ 2 files changed, 6 insertions(+) diff --git a/.github/workflows/release-desktop.yml b/.github/workflows/release-desktop.yml index 85fa8f8edc7..fb1a88faeb7 100644 --- a/.github/workflows/release-desktop.yml +++ b/.github/workflows/release-desktop.yml @@ -11,6 +11,9 @@ on: required: false type: string +permissions: + contents: write + jobs: build: name: Build - macOS (${{ matrix.arch }}) diff --git a/apps/desktop/electron-builder.ts b/apps/desktop/electron-builder.ts index 26b96698d86..11b119f0789 100644 --- a/apps/desktop/electron-builder.ts +++ b/apps/desktop/electron-builder.ts @@ -19,6 +19,9 @@ const config: Configuration = { copyright: `Copyright © ${currentYear} — ${author}`, electronVersion: pkg.devDependencies.electron.replace(/^\^/, ""), + // Disable auto-publish - handled by separate workflow step + publish: null, + // Directories directories: { output: "release", From c704e5e89ce3445ce41f2ae8c3e080ad2d58d814 Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Wed, 26 Nov 2025 18:51:56 -0600 Subject: [PATCH 09/12] feat(desktop): auto-publish releases and support republishing same version --- apps/desktop/create-release.sh | 75 ++++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 26 deletions(-) diff --git a/apps/desktop/create-release.sh b/apps/desktop/create-release.sh index 5dfb85e1584..2233e72c653 100755 --- a/apps/desktop/create-release.sh +++ b/apps/desktop/create-release.sh @@ -9,10 +9,15 @@ # # This script will: # 1. Verify prerequisites (clean git, GitHub CLI authenticated) -# 2. Update package.json version -# 3. Create and push a git tag to trigger the release workflow -# 4. Monitor the GitHub Actions workflow in real-time -# 5. Display the draft release URL when ready +# 2. Delete existing release/tag if republishing same version +# 3. Update package.json version +# 4. Create and push a git tag to trigger the release workflow +# 5. Monitor the GitHub Actions workflow in real-time +# 6. Auto-publish the release when build completes +# +# Features: +# - Supports republishing: Running with same version will clean up and rebuild +# - Auto-publishes release (no manual publish step needed) # # Requirements: # - GitHub CLI (gh) installed and authenticated @@ -83,10 +88,27 @@ if ! git diff-index --quiet HEAD --; then fi success "Working directory is clean" -# 2. Check if tag already exists +# 2. Check if tag/release already exists and clean up if needed info "Checking if tag ${TAG_NAME} already exists..." if git rev-parse "${TAG_NAME}" >/dev/null 2>&1; then - error "Tag ${TAG_NAME} already exists. Use a different version or delete the existing tag." + warn "Tag ${TAG_NAME} already exists. Cleaning up for republish..." + + # Delete the GitHub release if it exists + if gh release view "${TAG_NAME}" &>/dev/null; then + info "Deleting existing GitHub release..." + gh release delete "${TAG_NAME}" --yes + success "Deleted existing release" + fi + + # Delete remote tag + info "Deleting remote tag..." + git push origin --delete "${TAG_NAME}" 2>/dev/null || true + success "Deleted remote tag" + + # Delete local tag + info "Deleting local tag..." + git tag -d "${TAG_NAME}" 2>/dev/null || true + success "Deleted local tag" fi success "Tag ${TAG_NAME} is available" @@ -180,8 +202,8 @@ fi echo "" -# 7. Get and display draft release URL -info "Fetching draft release..." +# 7. Wait for release and publish it +info "Waiting for draft release to be created..." # Retry logic for draft release (it may take time to be created) MAX_RELEASE_RETRIES=10 @@ -190,34 +212,35 @@ RELEASE_FOUND="" while [ $RELEASE_RETRY_COUNT -lt $MAX_RELEASE_RETRIES ] && [ -z "$RELEASE_FOUND" ]; do sleep 3 - RELEASE_FOUND=$(gh release list --json tagName,isDraft --jq ".[] | select(.tagName == \"${TAG_NAME}\" and .isDraft == true) | .tagName") + RELEASE_FOUND=$(gh release list --json tagName,isDraft --jq ".[] | select(.tagName == \"${TAG_NAME}\") | .tagName") RELEASE_RETRY_COUNT=$((RELEASE_RETRY_COUNT + 1)) if [ -z "$RELEASE_FOUND" ] && [ $RELEASE_RETRY_COUNT -lt $MAX_RELEASE_RETRIES ]; then - echo " Waiting for draft release to be created... (attempt $RELEASE_RETRY_COUNT/$MAX_RELEASE_RETRIES)" + echo " Waiting for release to be created... (attempt $RELEASE_RETRY_COUNT/$MAX_RELEASE_RETRIES)" fi done if [ -z "$RELEASE_FOUND" ]; then - warn "Draft release not found yet. It may still be processing." + warn "Release not found yet. It may still be processing." echo " Check releases at: https://github.com/${REPO}/releases" else + # Publish the release + info "Publishing release..." + gh release edit "${TAG_NAME}" --draft=false + success "Release published!" + RELEASE_URL="https://github.com/${REPO}/releases/tag/${TAG_NAME}" - success "Draft release created!" + LATEST_URL="https://github.com/${REPO}/releases/latest" echo "" - echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" - echo -e "${BLUE}📦 Draft Release URL:${NC}" - echo -e "${GREEN}${RELEASE_URL}${NC}" - echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" + echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" + echo -e "${GREEN}🎉 Release Published!${NC}" + echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" + echo "" + echo -e "${BLUE}Release URL:${NC} ${RELEASE_URL}" + echo -e "${BLUE}Latest URL:${NC} ${LATEST_URL}" + echo "" + echo -e "${BLUE}Direct downloads:${NC}" + echo " • ${LATEST_URL}/download/Superset-${VERSION}-arm64.dmg" + echo " • ${LATEST_URL}/download/Superset-${VERSION}-arm64-mac.zip" echo "" fi - -echo "" -info "Next steps:" -echo " 1. Review the draft release and edit release notes if needed" -echo " 2. Publish the release when ready" -echo "" -info "Release artifacts will include:" -echo " • Superset-${VERSION}-arm64.dmg (macOS DMG installer)" -echo " • Superset-${VERSION}-arm64-mac.zip (macOS zipped app bundle)" -echo "" From 47f54084c93119303ccc0f8bafcee29453283fa8 Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Wed, 26 Nov 2025 18:54:53 -0600 Subject: [PATCH 10/12] feat(desktop): prompt user before republishing existing release --- apps/desktop/create-release.sh | 57 +++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/apps/desktop/create-release.sh b/apps/desktop/create-release.sh index 2233e72c653..dc151411b9e 100755 --- a/apps/desktop/create-release.sh +++ b/apps/desktop/create-release.sh @@ -88,27 +88,54 @@ if ! git diff-index --quiet HEAD --; then fi success "Working directory is clean" -# 2. Check if tag/release already exists and clean up if needed +# 2. Check if tag/release already exists info "Checking if tag ${TAG_NAME} already exists..." if git rev-parse "${TAG_NAME}" >/dev/null 2>&1; then - warn "Tag ${TAG_NAME} already exists. Cleaning up for republish..." + echo "" + warn "Tag ${TAG_NAME} already exists!" - # Delete the GitHub release if it exists + # Check if there's also a GitHub release if gh release view "${TAG_NAME}" &>/dev/null; then - info "Deleting existing GitHub release..." - gh release delete "${TAG_NAME}" --yes - success "Deleted existing release" + RELEASE_STATUS=$(gh release view "${TAG_NAME}" --json isDraft --jq 'if .isDraft then "draft" else "published"' 2>/dev/null || echo "unknown") + echo -e " GitHub release: ${YELLOW}${RELEASE_STATUS}${NC}" + else + echo -e " GitHub release: ${YELLOW}none${NC}" fi + echo "" - # Delete remote tag - info "Deleting remote tag..." - git push origin --delete "${TAG_NAME}" 2>/dev/null || true - success "Deleted remote tag" - - # Delete local tag - info "Deleting local tag..." - git tag -d "${TAG_NAME}" 2>/dev/null || true - success "Deleted local tag" + # Ask user what to do + echo "What would you like to do?" + echo " 1) Republish - Delete existing release/tag and create new one" + echo " 2) Cancel - Exit without changes" + echo "" + read -p "Enter choice [1-2]: " choice + + case $choice in + 1) + info "Cleaning up for republish..." + + # Delete the GitHub release if it exists + if gh release view "${TAG_NAME}" &>/dev/null; then + info "Deleting existing GitHub release..." + gh release delete "${TAG_NAME}" --yes + success "Deleted existing release" + fi + + # Delete remote tag + info "Deleting remote tag..." + git push origin --delete "${TAG_NAME}" 2>/dev/null || true + success "Deleted remote tag" + + # Delete local tag + info "Deleting local tag..." + git tag -d "${TAG_NAME}" 2>/dev/null || true + success "Deleted local tag" + ;; + 2|*) + info "Cancelled. No changes made." + exit 0 + ;; + esac fi success "Tag ${TAG_NAME} is available" From 1aed654533efeb8d9b7de0da08653ee48c95bb98 Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Wed, 26 Nov 2025 19:23:53 -0600 Subject: [PATCH 11/12] fix(desktop): upload DMG and ZIP as separate artifacts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split the single artifact upload into separate DMG and ZIP uploads to avoid the nested zip issue when downloading from GitHub Actions. Also use merge-multiple for cleaner artifact handling in releases. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .github/workflows/release-desktop.yml | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release-desktop.yml b/.github/workflows/release-desktop.yml index fb1a88faeb7..ce9bbd037d0 100644 --- a/.github/workflows/release-desktop.yml +++ b/.github/workflows/release-desktop.yml @@ -69,14 +69,19 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: bun run package - # Upload artifacts - - name: Upload artifacts + # Upload artifacts separately to avoid nested zips + - name: Upload DMG artifact uses: actions/upload-artifact@v4 with: - name: desktop-mac-${{ matrix.arch }} - path: | - apps/desktop/release/*.dmg - apps/desktop/release/*.zip + name: desktop-mac-${{ matrix.arch }}-dmg + path: apps/desktop/release/*.dmg + retention-days: 30 + + - name: Upload ZIP artifact + uses: actions/upload-artifact@v4 + with: + name: desktop-mac-${{ matrix.arch }}-zip + path: apps/desktop/release/*.zip retention-days: 30 # Create GitHub Release after builds complete @@ -94,11 +99,12 @@ jobs: uses: actions/download-artifact@v4 with: path: release-artifacts + merge-multiple: true - name: Create Release uses: softprops/action-gh-release@v1 with: - files: release-artifacts/**/* + files: release-artifacts/* draft: true generate_release_notes: true name: Superset Desktop ${{ github.ref_name }} From 89a974129b328a8ad0e4709385df801970704f37 Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Wed, 26 Nov 2025 22:55:46 -0600 Subject: [PATCH 12/12] feat(desktop): add stable download URLs for latest release MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add stable-named copies of release assets (without version numbers) to enable GitHub's /releases/latest/download/ URL pattern. Users can now use stable URLs like: - https://github.com/.../releases/latest/download/Superset-arm64.dmg - https://github.com/.../releases/latest/download/Superset-arm64-mac.zip Versioned filenames are still available for users who need specific versions. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .github/workflows/release-desktop.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/.github/workflows/release-desktop.yml b/.github/workflows/release-desktop.yml index ce9bbd037d0..5d3a5752b67 100644 --- a/.github/workflows/release-desktop.yml +++ b/.github/workflows/release-desktop.yml @@ -101,6 +101,29 @@ jobs: path: release-artifacts merge-multiple: true + - name: Create stable-named copies for latest download URLs + run: | + cd release-artifacts + # Create stable-named copies (without version) for /releases/latest/download/ URLs + for file in *.dmg; do + if [[ -f "$file" ]]; then + # Extract architecture from filename (e.g., Superset-0.0.1-arm64.dmg -> arm64) + arch=$(echo "$file" | sed -E 's/.*-([^-]+)\.dmg$/\1/') + cp "$file" "Superset-${arch}.dmg" + echo "Created stable copy: Superset-${arch}.dmg" + fi + done + for file in *-mac.zip; do + if [[ -f "$file" ]]; then + # Extract architecture from filename (e.g., Superset-0.0.1-arm64-mac.zip -> arm64) + arch=$(echo "$file" | sed -E 's/.*-([^-]+)-mac\.zip$/\1/') + cp "$file" "Superset-${arch}-mac.zip" + echo "Created stable copy: Superset-${arch}-mac.zip" + fi + done + echo "Release artifacts:" + ls -la + - name: Create Release uses: softprops/action-gh-release@v1 with: