Skip to content

XS⚠️ ◾ Fix camera/audio not working - request permissions before enumerating devices #1155

XS⚠️ ◾ Fix camera/audio not working - request permissions before enumerating devices

XS⚠️ ◾ Fix camera/audio not working - request permissions before enumerating devices #1155

Workflow file for this run

name: PR Pre-release
on:
pull_request:
types: [opened, synchronize, reopened, closed]
permissions:
contents: write
pull-requests: write
env:
APP_NAME: SSW.YakShaver
NODE_VERSION: 20
concurrency:
group: pr-pre-release-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
cleanup-release:
if: |
github.event_name != 'pull_request' ||
github.event.action != 'closed'
runs-on: ubuntu-latest
outputs:
pr_number: ${{ steps.pr_info.outputs.pr_number }}
release_tag: ${{ steps.pr_info.outputs.tag }}
channel: ${{ steps.pr_info.outputs.channel }}
version: ${{ steps.pr_info.outputs.version }}
pr_sha: ${{ steps.pr_info.outputs.pr_sha }}
steps:
- uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.ref || github.ref }}
- uses: actions/setup-node@v6
with:
node-version: ${{ env.NODE_VERSION }}
- name: Get PR info
id: pr_info
run: |
PR_NUMBER="${{ github.event.pull_request.number }}"
PR_SHA="${{ github.event.pull_request.head.sha || github.sha }}"
SHORT_SHA="${PR_SHA:0:7}"
BUILD_TIMESTAMP=$(date +%s)
BASE_VERSION=$(node -p 'require("./package.json").version.split("-")[0]')
CHANNEL_NAME="beta.${PR_NUMBER}"
PRE_RELEASE_VERSION="${BASE_VERSION}-${CHANNEL_NAME}.${BUILD_TIMESTAMP}"
TAG_NAME="${PRE_RELEASE_VERSION}"
echo "tag=${TAG_NAME}" >> $GITHUB_OUTPUT
echo "pr_number=${PR_NUMBER}" >> $GITHUB_OUTPUT
echo "channel=${CHANNEL_NAME}" >> $GITHUB_OUTPUT
echo "version=${PRE_RELEASE_VERSION}" >> $GITHUB_OUTPUT
echo "pr_sha=${SHORT_SHA}" >> $GITHUB_OUTPUT
echo "PR: ${PR_NUMBER}, Tag: ${TAG_NAME}, Channel: ${CHANNEL_NAME}, Version: ${PRE_RELEASE_VERSION}"
- name: Delete existing PR releases
continue-on-error: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
PR_NUMBER="${{ steps.pr_info.outputs.pr_number }}"
echo "Finding and deleting existing releases for PR #${PR_NUMBER}"
# Collect both release IDs and tag names BEFORE deleting anything
RELEASES_DATA=$(gh api --paginate /repos/${{ github.repository }}/releases --jq ".[] | select(.body | contains(\"PR #${PR_NUMBER}\")) | {id: .id, tag: .tag_name}")
RELEASE_IDS=$(echo "$RELEASES_DATA" | jq -r '.id')
TAG_NAMES=$(echo "$RELEASES_DATA" | jq -r '.tag')
# Now delete the releases
for id in $RELEASE_IDS; do
if [ -n "$id" ]; then
echo "Deleting release ID: $id"
gh api -X DELETE /repos/${{ github.repository }}/releases/$id || true
fi
done
# Clean up associated tags (collected before deletion)
for tag in $TAG_NAMES; do
if [ -n "$tag" ]; then
echo "Deleting tag: $tag"
gh api -X DELETE /repos/${{ github.repository }}/git/refs/tags/$tag || true
fi
done
echo "Cleanup completed"
build-windows:
needs: cleanup-release
if: |
github.event_name != 'pull_request' ||
github.event.action != 'closed'
runs-on: windows-latest
steps:
- uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.ref || github.ref }}
- uses: actions/setup-node@v6
with:
node-version: ${{ env.NODE_VERSION }}
cache: npm
cache-dependency-path: package-lock.json
# TODO: Remove this step once this PBI is done: https://github.com/SSWConsulting/SSW.YakShaver/issues/3095
- name: Create .env from secrets
shell: pwsh
env:
MCP_CALLBACK_PORT: 8090
MCP_AUTH_TIMEOUT_MS: 60000
PORTAL_API_URL: https://api-staging.yakshaver.ai/api
AZURE_ENTRA_APP_CLIENT_ID: ${{ secrets.AZURE_ENTRA_APP_CLIENT_ID }}
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
AZURE_AUTH_SCOPE: ${{ secrets.AZURE_AUTH_SCOPE }}
AZURE_AUTH_CUSTOM_PROTOCOL: yakshaver-desktop
run: |
Add-Content -Path ".env" -Value "`nMCP_CALLBACK_PORT=$env:MCP_CALLBACK_PORT"
Add-Content -Path ".env" -Value "`nMCP_AUTH_TIMEOUT_MS=$env:MCP_AUTH_TIMEOUT_MS"
Add-Content -Path ".env" -Value "`nPORTAL_API_URL=$env:PORTAL_API_URL"
Add-Content -Path ".env" -Value "`nAZURE_ENTRA_APP_CLIENT_ID=$env:AZURE_ENTRA_APP_CLIENT_ID"
Add-Content -Path ".env" -Value "`nAZURE_TENANT_ID=$env:AZURE_TENANT_ID"
Add-Content -Path ".env" -Value "`nAZURE_AUTH_SCOPE=$env:AZURE_AUTH_SCOPE"
Add-Content -Path ".env" -Value "`nAZURE_AUTH_CUSTOM_PROTOCOL=$env:AZURE_AUTH_CUSTOM_PROTOCOL"
$COMMIT_HASH = git rev-parse HEAD
Add-Content -Path ".env" -Value "`nCOMMIT_HASH=$COMMIT_HASH"
- name: Install dependencies
run: npm ci --prefer-offline
env:
# Prevent youtube-dl-exec from auto-downloading yt-dlp during npm install, which would hit the GitHub API unauthenticated rate limit
YOUTUBE_DL_SKIP_DOWNLOAD: true
# Manual download is needed because the 'youtube-dl-exec' script hits the GitHub API unauthenticated rate limit (60/hr) when attempting to download the binary
- name: Install yt-dlp binary manually
shell: bash
run: |
mkdir -p node_modules/youtube-dl-exec/bin
PATTERN="yt-dlp.exe"
OUTPUT_FILE="node_modules/youtube-dl-exec/bin/yt-dlp.exe"
MAX_ATTEMPTS=3
ATTEMPT=1
until gh release download --repo yt-dlp/yt-dlp --pattern "$PATTERN" --clobber --output "$OUTPUT_FILE"; do
echo "Attempt $ATTEMPT to download yt-dlp binary failed." >&2
if [ $ATTEMPT -ge $MAX_ATTEMPTS ]; then exit 1; fi
ATTEMPT=$((ATTEMPT+1))
sleep 5
done
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Install UI dependencies
run: npm ci --prefer-offline
working-directory: src/ui
- name: Update version for pre-release
shell: pwsh
run: |
$version = "${{ needs.cleanup-release.outputs.version }}"
if (-not $version) {
throw "Missing version output"
}
npm version $version --no-git-tag-version
- name: Publish Windows pre-release
run: npm run publish -- --win --publish never
env:
NODE_ENV: production
CI: true
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CHANNEL: ${{ needs.cleanup-release.outputs.channel }}
# Disable minification for PR preview builds
VITE_DEBUG_BUILD: "true"
- name: Fix update manifest filenames
shell: pwsh
run: |
Get-ChildItem "build/*.yml" | ForEach-Object {
$content = Get-Content $_.FullName -Raw
$content = $content -replace "YakShaver-Setup-", "YakShaver.Setup."
$content | Out-File -FilePath $_.FullName -Encoding utf8 -NoNewline
Write-Host "Fixed $($_.Name)"
}
- name: Upload Windows artifacts
uses: actions/upload-artifact@v6
with:
name: windows-build
path: |
build/*.yml
build/YakShaver*Setup*.exe
build/YakShaver*Setup*.exe.blockmap
retention-days: 1
build-macos:
needs: cleanup-release
if: |
github.event_name != 'pull_request' ||
github.event.action != 'closed'
runs-on: macos-latest
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.ref || github.ref }}
- uses: actions/setup-node@v6
with:
node-version: ${{ env.NODE_VERSION }}
cache: npm
cache-dependency-path: package-lock.json
# TODO: Remove this step once this PBI is done: https://github.com/SSWConsulting/SSW.YakShaver/issues/3095
- name: Create .env from secrets
env:
MCP_CALLBACK_PORT: 8090
MCP_AUTH_TIMEOUT_MS: 60000
PORTAL_API_URL: https://api-staging.yakshaver.ai/api
AZURE_ENTRA_APP_CLIENT_ID: ${{ secrets.AZURE_ENTRA_APP_CLIENT_ID }}
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
AZURE_AUTH_SCOPE: ${{ secrets.AZURE_AUTH_SCOPE }}
AZURE_AUTH_CUSTOM_PROTOCOL: yakshaver-desktop
run: |
printf "MCP_CALLBACK_PORT=%s\n" "$MCP_CALLBACK_PORT" >> .env
printf "MCP_AUTH_TIMEOUT_MS=%s\n" "$MCP_AUTH_TIMEOUT_MS" >> .env
printf "PORTAL_API_URL=%s\n" "$PORTAL_API_URL" >> .env
printf "AZURE_ENTRA_APP_CLIENT_ID=%s\n" "$AZURE_ENTRA_APP_CLIENT_ID" >> .env
printf "AZURE_TENANT_ID=%s\n" "$AZURE_TENANT_ID" >> .env
printf "AZURE_AUTH_SCOPE=%s\n" "$AZURE_AUTH_SCOPE" >> .env
printf "AZURE_AUTH_CUSTOM_PROTOCOL=%s\n" "$AZURE_AUTH_CUSTOM_PROTOCOL" >> .env
- name: Install dependencies
run: npm ci --prefer-offline
env:
YOUTUBE_DL_SKIP_DOWNLOAD: true
# Manual download is needed because the youtube-dl-exec script hits the GitHub API unauthenticated rate limit (60/hr) while attempting to find the yt-dlp binary.
- name: Install yt-dlp binary manually
run: |
mkdir -p node_modules/youtube-dl-exec/bin
PATTERN="yt-dlp_macos"
OUTPUT_FILE="node_modules/youtube-dl-exec/bin/yt-dlp"
MAX_ATTEMPTS=3
ATTEMPT=1
until gh release download \
--repo yt-dlp/yt-dlp \
--pattern "$PATTERN" \
--clobber \
--output "$OUTPUT_FILE"; do
echo "Attempt $ATTEMPT to download yt-dlp binary failed." >&2
if [ $ATTEMPT -ge $MAX_ATTEMPTS ]; then
echo "Failed to download yt-dlp binary after $MAX_ATTEMPTS attempts." >&2
exit 1
fi
ATTEMPT=$((ATTEMPT+1))
sleep 5
done
# Make the binary executable
chmod +x "$OUTPUT_FILE"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Install UI dependencies
run: npm ci --prefer-offline
working-directory: src/ui
- name: Update version for pre-release
run: |
VERSION="${{ needs.cleanup-release.outputs.version }}"
if [[ -z "$VERSION" ]]; then
echo "Missing version output"
exit 1
fi
npm version "$VERSION" --no-git-tag-version
- name: Publish macOS pre-release
run: npm run publish -- --mac --publish never
env:
NODE_ENV: production
CI: true
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CHANNEL: ${{ needs.cleanup-release.outputs.channel }}
# Disable minification for PR preview builds
VITE_DEBUG_BUILD: "true"
- name: Upload macOS artifacts
uses: actions/upload-artifact@v6
with:
name: macos-build
path: |
build/YakShaver-*-mac.zip
build/YakShaver-*-mac.zip.blockmap
build/*-mac.yml
retention-days: 1
create-and-comment-release:
runs-on: ubuntu-latest
needs:
- cleanup-release
- build-windows
- build-macos
if: |
github.event.action != 'closed' &&
needs.cleanup-release.outputs.pr_number != ''
steps:
- name: Download Windows artifacts
uses: actions/download-artifact@v7
with:
name: windows-build
path: artifacts/
- name: Download macOS artifacts
uses: actions/download-artifact@v7
with:
name: macos-build
path: artifacts/
- name: Create single GitHub release with all artifacts
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.cleanup-release.outputs.release_tag }}
name: "Pre-release PR #${{ needs.cleanup-release.outputs.pr_number }} (${{ needs.cleanup-release.outputs.pr_sha }})"
body: |
Pre-release build for PR #${{ needs.cleanup-release.outputs.pr_number }}
Commit: ${{ needs.cleanup-release.outputs.pr_sha }}
PR: ${{ github.event.pull_request.html_url || 'N/A' }}
This is an automated pre-release. It will be updated automatically when new commits are pushed to the PR.
prerelease: true
files: artifacts/**/*
draft: false
token: ${{ secrets.GITHUB_TOKEN }}
- name: Comment release link on PR
uses: peter-evans/create-or-update-comment@v5
with:
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ needs.cleanup-release.outputs.pr_number }}
body: |
🚀 Pre-release build is available for this PR:
https://github.com/${{ github.repository }}/releases/tag/${{ needs.cleanup-release.outputs.release_tag }}
delete-release:
runs-on: ubuntu-latest
if: |
github.event_name == 'pull_request' &&
github.event.action == 'closed'
steps:
- name: Delete PR pre-releases
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
PR_NUMBER="${{ github.event.pull_request.number }}"
echo "Deleting all releases for closed PR #${PR_NUMBER}"
# Collect both release IDs and tag names BEFORE deleting anything
RELEASES_DATA=$(gh api --paginate /repos/${{ github.repository }}/releases --jq ".[] | select(.body | contains(\"PR #${PR_NUMBER}\")) | {id: .id, tag: .tag_name}")
RELEASE_IDS=$(echo "$RELEASES_DATA" | jq -r '.id')
TAG_NAMES=$(echo "$RELEASES_DATA" | jq -r '.tag')
# Delete the releases
for id in $RELEASE_IDS; do
if [ -n "$id" ]; then
echo "Deleting release ID: $id"
gh api -X DELETE /repos/${{ github.repository }}/releases/$id || true
fi
done
# Clean up associated tags (collected before deletion)
for tag in $TAG_NAMES; do
if [ -n "$tag" ]; then
echo "Deleting tag: $tag"
gh api -X DELETE /repos/${{ github.repository }}/git/refs/tags/$tag || true
fi
done
echo "Deletion completed for closed PR"