Skip to content

Build & Release

Build & Release #72

Workflow file for this run

name: Build & Release
on:
workflow_run:
workflows: ["Security & Quality"]
types: [completed]
branches: [master]
permissions:
contents: write
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
security-gate:
name: Security Gate
runs-on: ubuntu-latest
if: "github.event.workflow_run.conclusion == 'success' && !startsWith(github.event.workflow_run.head_commit.message, 'chore: bump version')"
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 22
- name: Clone core dependency
run: |
git clone https://github.com/CallMeTechie/gatecontrol-client-core.git .core
node -e "const p=require('./package.json'); p.dependencies['@gatecontrol/client-core']='file:.core'; require('fs').writeFileSync('package.json',JSON.stringify(p,null,2)+'\n')"
- run: npm install --no-audit --no-fund
- name: npm audit (high/critical)
run: |
CRITICAL=$(npm audit --json 2>/dev/null | node -e "try{const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));console.log((d.metadata?.vulnerabilities?.critical||0))}catch{console.log(0)}")
if [ "$CRITICAL" -gt 0 ]; then echo "::error::Critical vulnerabilities found"; exit 1; fi
test-gate:
name: Test Gate
runs-on: ubuntu-latest
if: "github.event.workflow_run.conclusion == 'success' && !startsWith(github.event.workflow_run.head_commit.message, 'chore: bump version')"
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 22
- run: npm install --ignore-scripts --no-audit --no-fund
- run: npm test
release:
needs: [security-gate, test-gate]
runs-on: windows-latest
# Skip version-bump commits to prevent infinite loop
if: "github.event.workflow_run.conclusion == 'success' && !startsWith(github.event.workflow_run.head_commit.message, 'chore: bump version')"
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
fetch-tags: true
token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/setup-node@v6
with:
node-version: 22
cache: npm
- name: Determine version bump
id: bump
shell: bash
env:
COMMIT_MSG: ${{ github.event.head_commit.message }}
run: |
CURRENT=$(node -p "require('./package.json').version")
IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT"
FIRST_LINE=$(echo "$COMMIT_MSG" | head -1)
if echo "$FIRST_LINE" | grep -qE "^feat(\(.+\))?:"; then
MINOR=$((MINOR + 1))
PATCH=0
BUMP="minor"
else
PATCH=$((PATCH + 1))
BUMP="patch"
fi
NEW="${MAJOR}.${MINOR}.${PATCH}"
echo "current=$CURRENT" >> "$GITHUB_OUTPUT"
echo "new=$NEW" >> "$GITHUB_OUTPUT"
echo "bump=$BUMP" >> "$GITHUB_OUTPUT"
echo "tag=v$NEW" >> "$GITHUB_OUTPUT"
echo "Version: $CURRENT → $NEW ($BUMP)"
- name: Check if tag already exists
id: check_tag
shell: bash
env:
TAG: ${{ steps.bump.outputs.tag }}
run: |
if git rev-parse "$TAG" >/dev/null 2>&1; then
echo "exists=true" >> "$GITHUB_OUTPUT"
else
echo "exists=false" >> "$GITHUB_OUTPUT"
fi
- name: Update version in package.json
if: steps.check_tag.outputs.exists == 'false'
shell: bash
env:
NEW_VERSION: ${{ steps.bump.outputs.new }}
run: npm version "$NEW_VERSION" --no-git-tag-version
- name: Update CHANGELOG.md
if: steps.check_tag.outputs.exists == 'false'
shell: bash
env:
NEW_VERSION: ${{ steps.bump.outputs.new }}
BUMP_TYPE: ${{ steps.bump.outputs.bump }}
COMMIT_MSG: ${{ github.event.head_commit.message }}
run: |
FIRST_LINE=$(echo "$COMMIT_MSG" | head -1)
DATE=$(date +%Y-%m-%d)
if echo "$FIRST_LINE" | grep -qE "^feat"; then
SECTION="Features"
ENTRY=$(echo "$FIRST_LINE" | sed 's/^feat[^:]*: //')
elif echo "$FIRST_LINE" | grep -qE "^fix"; then
SECTION="Fixes"
ENTRY=$(echo "$FIRST_LINE" | sed 's/^fix[^:]*: //')
elif echo "$FIRST_LINE" | grep -qE "^docs"; then
SECTION="Dokumentation"
ENTRY=$(echo "$FIRST_LINE" | sed 's/^docs[^:]*: //')
else
SECTION="Änderungen"
ENTRY=$(echo "$FIRST_LINE" | sed 's/^[a-z]*[^:]*: //')
fi
NEW_BLOCK="## [$NEW_VERSION] — $DATE
### $SECTION
- $ENTRY"
# Remove leading whitespace from heredoc
NEW_BLOCK=$(echo "$NEW_BLOCK" | sed 's/^ //')
if [ -f CHANGELOG.md ]; then
TEMP=$(mktemp)
awk -v block="$NEW_BLOCK" '
/^# Changelog/ { print; print ""; print block; print ""; print "---"; next }
{ print }
' CHANGELOG.md > "$TEMP"
mv "$TEMP" CHANGELOG.md
fi
- name: Commit version bump
if: steps.check_tag.outputs.exists == 'false'
shell: bash
env:
TAG: ${{ steps.bump.outputs.tag }}
NEW_VERSION: ${{ steps.bump.outputs.new }}
run: |
git config user.name "github-actions"
git config user.email "github-actions@github.com"
git add package.json package-lock.json CHANGELOG.md 2>/dev/null || true
git add package.json
git commit -m "chore: bump version to $NEW_VERSION"
git tag "$TAG"
git push origin master --tags
- name: Clone gatecontrol-client-core (shared dependency)
if: steps.check_tag.outputs.exists == 'false'
shell: bash
run: |
git clone "https://x-access-token:${GH_TOKEN}@github.com/CallMeTechie/gatecontrol-client-core.git" .core
node -e "const p=require('./package.json'); p.dependencies['@gatecontrol/client-core']='file:.core'; require('fs').writeFileSync('package.json',JSON.stringify(p,null,2)+'\n')"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Install dependencies
if: steps.check_tag.outputs.exists == 'false'
shell: bash
run: npm install --no-audit --no-fund
- name: Build installer
if: steps.check_tag.outputs.exists == 'false'
run: npm run build:installer
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Build portable
if: steps.check_tag.outputs.exists == 'false'
shell: bash
run: |
npx electron-builder --win dir --config.win.requestedExecutionLevel=asInvoker
curl -sL https://github.com/electron/rcedit/releases/download/v2.0.0/rcedit-x64.exe -o rcedit.exe
./rcedit.exe "dist/win-unpacked/GateControl Community Client.exe" --set-requested-execution-level requireAdministrator
echo "Patched with requireAdministrator"
cd dist && powershell Compress-Archive -Path "win-unpacked/*" -DestinationPath "GateControl-Community-Client-Portable.zip" -Force
echo "Portable ZIP created"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Create GitHub Release
if: steps.check_tag.outputs.exists == 'false'
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ steps.bump.outputs.tag }}
name: GateControl Community Client ${{ steps.bump.outputs.tag }}
generate_release_notes: true
files: |
dist/*.exe
dist/*.zip