Skip to content

Shard v0.1.21

Shard v0.1.21 #24

Workflow file for this run

name: Store publish
# Publishes to AUR, Homebrew, Scoop, Flathub, and Winget when a release is published
on:
release:
types: [published]
workflow_dispatch:
inputs:
tag:
description: "Release tag to publish (e.g. v0.1.6)"
required: true
type: string
permissions:
contents: read
jobs:
aur:
runs-on: ubuntu-latest
steps:
- name: Check secret
id: check
run: |
if [ -z "${{ secrets.AUR_SSH_PRIVATE_KEY }}" ]; then
echo "skip=true" >> "$GITHUB_OUTPUT"
else
echo "skip=false" >> "$GITHUB_OUTPUT"
fi
- name: Collect release info
if: steps.check.outputs.skip != 'true'
id: release
shell: bash
run: |
set -euo pipefail
TAG="${{ github.event.release.tag_name || inputs.tag || github.ref_name }}"
VERSION="${TAG#v}"
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
- name: Download checksums
if: steps.check.outputs.skip != 'true'
shell: bash
run: |
set -euo pipefail
TAG="${{ steps.release.outputs.tag }}"
curl -sL "https://github.com/th0rgal/shard/releases/download/${TAG}/SHA256SUMS.txt" -o SHA256SUMS.txt
- name: Prepare shard PKGBUILD
if: steps.check.outputs.skip != 'true'
shell: bash
run: |
set -euo pipefail
VERSION="${{ steps.release.outputs.version }}"
CLI_SHA=$(grep "shard-cli-linux-x64.tar.gz" SHA256SUMS.txt | cut -d' ' -f1)
if [ -z "$CLI_SHA" ]; then
echo "Missing shard-cli-linux-x64.tar.gz hash in SHA256SUMS.txt" >&2
exit 1
fi
mkdir -p shard
cat > shard/PKGBUILD << 'PKGEOF'
# Maintainer: Thomas Marchand <thomas@thomas.md>
pkgname=shard
pkgver=PKGVER_PLACEHOLDER
pkgrel=1
pkgdesc="A minimal, content-addressed Minecraft launcher (CLI)"
arch=('x86_64')
url="https://shard.thomas.md"
license=('MIT')
depends=('gcc-libs')
source=("https://github.com/th0rgal/shard/releases/download/v${pkgver}/shard-cli-linux-x64.tar.gz")
sha256sums=('SHA256_PLACEHOLDER')
package() {
install -Dm755 shard "${pkgdir}/usr/bin/shard"
}
PKGEOF
sed -i "s/PKGVER_PLACEHOLDER/${VERSION}/" shard/PKGBUILD
sed -i "s/SHA256_PLACEHOLDER/${CLI_SHA}/" shard/PKGBUILD
- name: Prepare shard-launcher-bin PKGBUILD
if: steps.check.outputs.skip != 'true'
shell: bash
run: |
set -euo pipefail
VERSION="${{ steps.release.outputs.version }}"
DESKTOP_SHA=$(grep "shard-launcher-linux-x64.deb" SHA256SUMS.txt | cut -d' ' -f1)
if [ -z "$DESKTOP_SHA" ]; then
echo "Missing shard-launcher-linux-x64.deb hash in SHA256SUMS.txt" >&2
exit 1
fi
mkdir -p shard-launcher-bin
cat > shard-launcher-bin/PKGBUILD << 'PKGEOF'
# Maintainer: Thomas Marchand <thomas@thomas.md>
pkgname=shard-launcher-bin
pkgver=PKGVER_PLACEHOLDER
pkgrel=1
pkgdesc="A minimal, content-addressed Minecraft launcher (Desktop App)"
arch=('x86_64')
url="https://shard.thomas.md"
license=('MIT')
depends=('webkit2gtk-4.1' 'libappindicator-gtk3')
provides=('shard-launcher')
conflicts=('shard-launcher')
source=("https://github.com/th0rgal/shard/releases/download/v${pkgver}/shard-launcher-linux-x64.deb")
sha256sums=('SHA256_PLACEHOLDER')
package() {
bsdtar -xf data.tar.* -C "${pkgdir}/"
}
PKGEOF
sed -i "s/PKGVER_PLACEHOLDER/${VERSION}/" shard-launcher-bin/PKGBUILD
sed -i "s/SHA256_PLACEHOLDER/${DESKTOP_SHA}/" shard-launcher-bin/PKGBUILD
- name: Publish shard to AUR
if: steps.check.outputs.skip != 'true'
uses: KSXGitHub/github-actions-deploy-aur@v3
with:
pkgname: shard
pkgbuild: shard/PKGBUILD
commit_username: 'Thomas Marchand'
commit_email: 'thomas@thomas.md'
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
commit_message: "Update to ${{ steps.release.outputs.tag }}"
- name: Publish shard-launcher-bin to AUR
if: steps.check.outputs.skip != 'true'
uses: KSXGitHub/github-actions-deploy-aur@v3
with:
pkgname: shard-launcher-bin
pkgbuild: shard-launcher-bin/PKGBUILD
commit_username: 'Thomas Marchand'
commit_email: 'thomas@thomas.md'
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
commit_message: "Update to ${{ steps.release.outputs.tag }}"
homebrew:
runs-on: ubuntu-latest
steps:
- name: Check secret
id: check
run: |
if [ -z "${{ secrets.PACKAGE_REPOS_TOKEN }}" ]; then
echo "skip=true" >> "$GITHUB_OUTPUT"
else
echo "skip=false" >> "$GITHUB_OUTPUT"
fi
- name: Collect release info
if: steps.check.outputs.skip != 'true'
id: release
shell: bash
run: |
set -euo pipefail
TAG="${{ github.event.release.tag_name || inputs.tag || github.ref_name }}"
VERSION="${TAG#v}"
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
- name: Fetch SHA256SUMS
if: steps.check.outputs.skip != 'true'
id: hashes
shell: bash
run: |
set -euo pipefail
TAG="${{ steps.release.outputs.tag }}"
curl -fsSL "https://github.com/th0rgal/shard/releases/download/${TAG}/SHA256SUMS.txt" -o /tmp/SHA256SUMS.txt
# CLI hashes
CLI_MACOS_ARM64=$(grep 'shard-cli-macos-arm64.tar.gz$' /tmp/SHA256SUMS.txt | awk '{print $1}')
CLI_MACOS_X64=$(grep 'shard-cli-macos-x64.tar.gz$' /tmp/SHA256SUMS.txt | awk '{print $1}')
CLI_LINUX_X64=$(grep 'shard-cli-linux-x64.tar.gz$' /tmp/SHA256SUMS.txt | awk '{print $1}')
# Desktop hashes (DMG)
DESKTOP_MACOS_ARM64=$(grep 'shard-launcher-macos-arm64.dmg$' /tmp/SHA256SUMS.txt | awk '{print $1}')
DESKTOP_MACOS_X64=$(grep 'shard-launcher-macos-x64.dmg$' /tmp/SHA256SUMS.txt | awk '{print $1}')
echo "cli_macos_arm64=${CLI_MACOS_ARM64}" >> "$GITHUB_OUTPUT"
echo "cli_macos_x64=${CLI_MACOS_X64}" >> "$GITHUB_OUTPUT"
echo "cli_linux_x64=${CLI_LINUX_X64}" >> "$GITHUB_OUTPUT"
echo "desktop_macos_arm64=${DESKTOP_MACOS_ARM64}" >> "$GITHUB_OUTPUT"
echo "desktop_macos_x64=${DESKTOP_MACOS_X64}" >> "$GITHUB_OUTPUT"
- name: Update Homebrew tap
if: steps.check.outputs.skip != 'true'
shell: bash
env:
GH_TOKEN: ${{ secrets.PACKAGE_REPOS_TOKEN }}
run: |
set -euo pipefail
TAG="${{ steps.release.outputs.tag }}"
VERSION="${{ steps.release.outputs.version }}"
git clone "https://x-access-token:${GH_TOKEN}@github.com/Th0rgal/homebrew-shard.git" homebrew-tap
cd homebrew-tap
# Update Formula/shard.rb
cat > Formula/shard.rb << EOF
class Shard < Formula
desc "A minimal, content-addressed Minecraft launcher"
homepage "https://shard.thomas.md"
version "${VERSION}"
license "MIT"
on_macos do
if Hardware::CPU.arm?
url "https://github.com/th0rgal/shard/releases/download/${TAG}/shard-cli-macos-arm64.tar.gz"
sha256 "${{ steps.hashes.outputs.cli_macos_arm64 }}"
else
url "https://github.com/th0rgal/shard/releases/download/${TAG}/shard-cli-macos-x64.tar.gz"
sha256 "${{ steps.hashes.outputs.cli_macos_x64 }}"
end
end
on_linux do
url "https://github.com/th0rgal/shard/releases/download/${TAG}/shard-cli-linux-x64.tar.gz"
sha256 "${{ steps.hashes.outputs.cli_linux_x64 }}"
end
def install
bin.install "shard"
end
test do
assert_match "shard", shell_output("#{bin}/shard --version")
end
end
EOF
# Update Casks/shard-launcher.rb
cat > Casks/shard-launcher.rb << EOF
cask "shard-launcher" do
version "${VERSION}"
on_arm do
url "https://github.com/th0rgal/shard/releases/download/${TAG}/shard-launcher-macos-arm64.dmg"
sha256 "${{ steps.hashes.outputs.desktop_macos_arm64 }}"
end
on_intel do
url "https://github.com/th0rgal/shard/releases/download/${TAG}/shard-launcher-macos-x64.dmg"
sha256 "${{ steps.hashes.outputs.desktop_macos_x64 }}"
end
name "Shard Launcher"
desc "A minimal, content-addressed Minecraft launcher"
homepage "https://shard.thomas.md"
app "Shard Launcher.app"
zap trash: [
"~/.shard",
"~/Library/Application Support/md.thomas.shard-launcher",
"~/Library/Caches/md.thomas.shard-launcher",
"~/Library/Preferences/md.thomas.shard-launcher.plist",
]
livecheck do
url :url
strategy :github_latest
end
end
EOF
git add Formula/shard.rb Casks/shard-launcher.rb
git -c user.name="github-actions" -c user.email="github-actions@github.com" commit -m "Update to ${VERSION}" || echo "No changes to commit"
git push
scoop:
runs-on: ubuntu-latest
steps:
- name: Check secret
id: check
run: |
if [ -z "${{ secrets.PACKAGE_REPOS_TOKEN }}" ]; then
echo "skip=true" >> "$GITHUB_OUTPUT"
else
echo "skip=false" >> "$GITHUB_OUTPUT"
fi
- name: Collect release info
if: steps.check.outputs.skip != 'true'
id: release
shell: bash
run: |
set -euo pipefail
TAG="${{ github.event.release.tag_name || inputs.tag || github.ref_name }}"
VERSION="${TAG#v}"
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
- name: Fetch SHA256SUMS
if: steps.check.outputs.skip != 'true'
id: hashes
shell: bash
run: |
set -euo pipefail
TAG="${{ steps.release.outputs.tag }}"
curl -fsSL "https://github.com/th0rgal/shard/releases/download/${TAG}/SHA256SUMS.txt" -o /tmp/SHA256SUMS.txt
WINDOWS_ZIP_HASH=$(grep 'shard-cli-windows-x64.zip$' /tmp/SHA256SUMS.txt | awk '{print $1}')
echo "windows_zip=${WINDOWS_ZIP_HASH}" >> "$GITHUB_OUTPUT"
- name: Update Scoop bucket
if: steps.check.outputs.skip != 'true'
shell: bash
env:
GH_TOKEN: ${{ secrets.PACKAGE_REPOS_TOKEN }}
run: |
set -euo pipefail
TAG="${{ steps.release.outputs.tag }}"
VERSION="${{ steps.release.outputs.version }}"
HASH="${{ steps.hashes.outputs.windows_zip }}"
git clone "https://x-access-token:${GH_TOKEN}@github.com/Th0rgal/scoop-shard.git" scoop-bucket
cd scoop-bucket
# Update bucket/shard.json
cat > bucket/shard.json << EOF
{
"version": "${VERSION}",
"description": "A minimal, content-addressed Minecraft launcher (CLI)",
"homepage": "https://shard.thomas.md",
"license": "MIT",
"url": "https://github.com/th0rgal/shard/releases/download/${TAG}/shard-cli-windows-x64.zip",
"hash": "${HASH}",
"bin": "shard.exe",
"checkver": {
"github": "https://github.com/th0rgal/shard"
},
"autoupdate": {
"url": "https://github.com/th0rgal/shard/releases/download/v\$version/shard-cli-windows-x64.zip"
}
}
EOF
git add bucket/shard.json
git -c user.name="github-actions" -c user.email="github-actions@github.com" commit -m "Update to ${VERSION}" || echo "No changes to commit"
git push
flathub:
runs-on: ubuntu-latest
steps:
- name: Check secret
id: check
run: |
if [ -z "${{ secrets.PACKAGE_REPOS_TOKEN }}" ]; then
echo "skip=true" >> "$GITHUB_OUTPUT"
else
echo "skip=false" >> "$GITHUB_OUTPUT"
fi
- name: Checkout shard repo
if: steps.check.outputs.skip != 'true'
uses: actions/checkout@v4
- name: Setup Node.js
if: steps.check.outputs.skip != 'true'
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Setup Python
if: steps.check.outputs.skip != 'true'
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install Python dependencies
if: steps.check.outputs.skip != 'true'
run: |
pip install aiohttp toml tomlkit
# Install flatpak-node-generator (it's now a Python package, not a standalone script)
pip install "git+https://github.com/flatpak/flatpak-builder-tools.git#subdirectory=node"
- name: Collect release info
if: steps.check.outputs.skip != 'true'
id: release
shell: bash
run: |
set -euo pipefail
TAG="${{ github.event.release.tag_name || inputs.tag || github.ref_name }}"
VERSION="${TAG#v}"
if [ -n "${{ github.event.release.published_at }}" ]; then
DATE="${{ github.event.release.published_at }}"
DATE="${DATE%%T*}"
else
DATE="$(date -u +%Y-%m-%d)"
fi
# Get commit SHA for the tag
COMMIT_SHA=$(git rev-list -n 1 "${TAG}" 2>/dev/null || git rev-parse HEAD)
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
echo "date=${DATE}" >> "$GITHUB_OUTPUT"
echo "commit=${COMMIT_SHA}" >> "$GITHUB_OUTPUT"
- name: Clone flatpak-builder-tools
if: steps.check.outputs.skip != 'true'
run: |
git clone --depth 1 https://github.com/flatpak/flatpak-builder-tools.git /tmp/flatpak-builder-tools
- name: Generate cargo-sources.json
if: steps.check.outputs.skip != 'true'
run: |
# Use root Cargo.lock which contains all workspace dependencies
# (including 'keyring' from the launcher crate)
python3 /tmp/flatpak-builder-tools/cargo/flatpak-cargo-generator.py \
Cargo.lock \
-o /tmp/cargo-sources.json
- name: Generate package-lock.json and node-sources.json
if: steps.check.outputs.skip != 'true'
run: |
cd desktop
# Temporarily remove Playwright from package.json to prevent flatpak-node-generator
# from trying to download Playwright browser binaries (which fails in CI)
# We can't use --no-devel because it excludes build-time dependencies like Babel
jq 'del(.devDependencies["@playwright/test"])' package.json > package.json.tmp
mv package.json.tmp package.json
# Generate package-lock.json from package.json (npm format for flatpak-node-generator)
npm install --package-lock-only --ignore-scripts
# Generate node sources using the installed flatpak-node-generator package
flatpak-node-generator npm package-lock.json -o /tmp/node-sources.json
- name: Clone and update Flathub repo
if: steps.check.outputs.skip != 'true'
shell: bash
env:
GH_TOKEN: ${{ secrets.PACKAGE_REPOS_TOKEN }}
run: |
set -euo pipefail
TAG="${{ steps.release.outputs.tag }}"
VERSION="${{ steps.release.outputs.version }}"
DATE="${{ steps.release.outputs.date }}"
COMMIT="${{ steps.release.outputs.commit }}"
git clone --branch md.thomas.shard.launcher "https://x-access-token:${GH_TOKEN}@github.com/Th0rgal/flathub.git" flathub-repo
cd flathub-repo
# Copy generated sources (these are JSON arrays of source entries)
cp /tmp/cargo-sources.json .
cp /tmp/node-sources.json .
# Copy package-lock.json for npm ci in the build
cp ../desktop/package-lock.json .
# Generate the build-from-source manifest
# Note: cargo-sources.json and node-sources.json contain arrays of source entries
# that flatpak-builder will process to download and extract dependencies
cat > md.thomas.shard.launcher.yml << 'MANIFEST_EOF'
id: md.thomas.shard.launcher
runtime: org.freedesktop.Platform
runtime-version: '25.08'
sdk: org.freedesktop.Sdk
sdk-extensions:
- org.freedesktop.Sdk.Extension.rust-stable
- org.freedesktop.Sdk.Extension.node20
- org.freedesktop.Sdk.Extension.openjdk21
command: shard-launcher
finish-args:
- --socket=wayland
- --socket=fallback-x11
- --device=dri
- --share=ipc
- --share=network
- --persist=.shard
- --env=FLATPAK=1
- --env=PATH=/app/jre/bin:/app/bin:/usr/bin
build-options:
append-path: /usr/lib/sdk/rust-stable/bin:/usr/lib/sdk/node20/bin
env:
CARGO_HOME: /run/build/shard-launcher/cargo
XDG_CACHE_HOME: /run/build/shard-launcher/flatpak-node/cache
npm_config_cache: /run/build/shard-launcher/flatpak-node/npm-cache
npm_config_nodedir: /usr/lib/sdk/node20
npm_config_offline: 'true'
modules:
# Install OpenJDK 21 for running Minecraft
- name: openjdk
buildsystem: simple
build-commands:
- /usr/lib/sdk/openjdk21/install.sh
- name: shard-launcher
buildsystem: simple
build-options:
env:
CARGO_NET_OFFLINE: 'true'
sources:
- type: git
url: https://github.com/th0rgal/shard.git
tag: TAG_PLACEHOLDER
commit: COMMIT_PLACEHOLDER
# Cargo vendored sources (generated by flatpak-cargo-generator)
- cargo-sources.json
# Node vendored sources (generated by flatpak-node-generator)
- node-sources.json
# Cargo config to use vendored sources
- type: inline
contents: |
[source.crates-io]
replace-with = "vendored-sources"
[source.vendored-sources]
directory = "cargo-sources"
dest: .cargo
dest-filename: config.toml
# package-lock.json for npm ci
- type: file
path: package-lock.json
dest: desktop
build-commands:
# Build frontend
- cd desktop && npm ci --offline --legacy-peer-deps
- cd desktop && npm run build
# Build Tauri/Rust backend
- cd desktop/src-tauri && cargo build --release --offline
# Install binary
- install -Dm755 desktop/src-tauri/target/release/shard-launcher /app/bin/shard-launcher
# Install desktop file from upstream
- install -Dm644 packaging/flathub/md.thomas.shard.launcher.desktop /app/share/applications/md.thomas.shard.launcher.desktop
# Install icons
- install -Dm644 desktop/src-tauri/icons/icon.png /app/share/icons/hicolor/256x256/apps/md.thomas.shard.launcher.png
- install -Dm644 desktop/src-tauri/icons/128x128.png /app/share/icons/hicolor/128x128/apps/md.thomas.shard.launcher.png
- install -Dm644 desktop/src-tauri/icons/32x32.png /app/share/icons/hicolor/32x32/apps/md.thomas.shard.launcher.png
# Install metainfo from upstream
- install -Dm644 packaging/flathub/md.thomas.shard.launcher.metainfo.xml /app/share/metainfo/md.thomas.shard.launcher.metainfo.xml
MANIFEST_EOF
# Replace placeholders in manifest
sed -i "s|TAG_PLACEHOLDER|${TAG}|g" md.thomas.shard.launcher.yml
sed -i "s|COMMIT_PLACEHOLDER|${COMMIT}|g" md.thomas.shard.launcher.yml
# Remove separate desktop and metainfo files from flathub repo (they're now installed from upstream)
rm -f md.thomas.shard.launcher.desktop md.thomas.shard.launcher.metainfo.xml
git add -A
git -c user.name="github-actions" -c user.email="github-actions@github.com" commit -m "Update Shard Launcher to ${VERSION}" || echo "No changes to commit"
git push
winget:
runs-on: ubuntu-latest
steps:
- name: Check secret
id: check
run: |
if [ -z "${{ secrets.PACKAGE_REPOS_TOKEN }}" ]; then
echo "skip=true" >> "$GITHUB_OUTPUT"
else
echo "skip=false" >> "$GITHUB_OUTPUT"
fi
- name: Checkout repo
if: steps.check.outputs.skip != 'true'
uses: actions/checkout@v4
- name: Collect release info
if: steps.check.outputs.skip != 'true'
id: release
shell: bash
run: |
set -euo pipefail
TAG="${{ github.event.release.tag_name || inputs.tag || github.ref_name }}"
VERSION="${TAG#v}"
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
- name: Fetch SHA256SUMS
if: steps.check.outputs.skip != 'true'
id: hashes
shell: bash
run: |
set -euo pipefail
TAG="${{ steps.release.outputs.tag }}"
curl -fsSL "https://github.com/th0rgal/shard/releases/download/${TAG}/SHA256SUMS.txt" -o /tmp/SHA256SUMS.txt
MSI_HASH="$(grep 'shard-launcher-windows-x64.msi$' /tmp/SHA256SUMS.txt | awk '{print $1}')"
if [ -z "$MSI_HASH" ]; then
echo "Missing shard-launcher-windows-x64.msi hash in SHA256SUMS.txt" >&2
exit 1
fi
echo "msi_hash=${MSI_HASH}" >> "$GITHUB_OUTPUT"
- name: Update winget manifests and open PR
if: steps.check.outputs.skip != 'true'
shell: bash
env:
GH_TOKEN: ${{ secrets.PACKAGE_REPOS_TOKEN }}
run: |
set -euo pipefail
TAG="${{ steps.release.outputs.tag }}"
VERSION="${{ steps.release.outputs.version }}"
MSI_HASH="${{ steps.hashes.outputs.msi_hash }}"
WINGET_FORK="Th0rgal/winget-pkgs"
WINGET_BASE="microsoft/winget-pkgs"
git clone "https://x-access-token:${GH_TOKEN}@github.com/${WINGET_FORK}.git" winget-pkgs
cd winget-pkgs
# Sync fork with upstream
git remote add upstream "https://github.com/${WINGET_BASE}.git"
git fetch upstream master
git checkout -B master upstream/master
git push origin master --force
BRANCH="shardlauncher-${VERSION}"
git checkout -b "$BRANCH"
TARGET_DIR="manifests/t/Th0rgal/ShardLauncher/${VERSION}"
mkdir -p "$TARGET_DIR"
cp -R "$GITHUB_WORKSPACE/packaging/winget/Th0rgal.ShardLauncher/0.1.4/." "$TARGET_DIR/"
# Update version and hash in manifest files
find "$TARGET_DIR" -name "*.yaml" -exec sed -i "s/PackageVersion: 0.1.4/PackageVersion: ${VERSION}/" {} \;
find "$TARGET_DIR" -name "*.yaml" -exec sed -i "s|/download/v0.1.4/|/download/${TAG}/|" {} \;
find "$TARGET_DIR" -name "*.yaml" -exec sed -i "s/InstallerSha256: 5245BE2EDD1E83660B4B0F4C9B4ECFE974B94F9F64DDE570939A957B7D8938EB/InstallerSha256: ${MSI_HASH}/" {} \;
git add "$TARGET_DIR"
git -c user.name="github-actions" -c user.email="github-actions@github.com" commit -m "Add Shard Launcher ${VERSION}"
git push -u origin "$BRANCH" --force
# Check if PR already exists before trying to create
FORK_OWNER="${WINGET_FORK%%/*}"
# Note: gh pr list uses just branch name, not owner:branch format
EXISTING_PR=$(gh pr list --repo "$WINGET_BASE" --head "$BRANCH" --json number,url --jq '.[0]' 2>/dev/null || true)
if [ -n "$EXISTING_PR" ] && [ "$EXISTING_PR" != "null" ]; then
PR_URL=$(echo "$EXISTING_PR" | jq -r '.url')
PR_NUM=$(echo "$EXISTING_PR" | jq -r '.number')
echo "PR #$PR_NUM already exists for this version: $PR_URL"
exit 0
fi
gh pr create \
--repo "$WINGET_BASE" \
--head "${FORK_OWNER}:$BRANCH" \
--title "Shard Launcher ${VERSION}" \
--body "Automated update for Shard Launcher ${VERSION}." \
--base master