Set version to v4.1.3-alpha.5 #149
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Package and Release | |
| on: | |
| push: | |
| branches: [main] | |
| tags: ['v*'] | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: 'Tag to build (e.g. v1.0.0-beta.1). Leave empty for alpha build.' | |
| required: false | |
| permissions: | |
| contents: write | |
| jobs: | |
| release: | |
| runs-on: ubuntu-latest | |
| if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/') | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ inputs.tag || github.ref }} | |
| fetch-depth: 0 | |
| - name: Check if build is needed | |
| id: guard | |
| run: | | |
| # Tags and workflow_dispatch always build | |
| if [[ "$GITHUB_REF" == refs/tags/* ]] || [[ -n "${{ inputs.tag }}" ]] || [[ "$GITHUB_EVENT_NAME" == "workflow_dispatch" ]]; then | |
| echo "skip=false" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| # Branch pushes: skip if only docs/CI files changed | |
| DOMINATED=true | |
| for f in $(git diff --name-only HEAD~1..HEAD 2>/dev/null); do | |
| case "$f" in | |
| *.md|*.sh|.github/*|.gitignore|.pkgmeta|Changelog.lua) ;; | |
| *) DOMINATED=false; break ;; | |
| esac | |
| done | |
| echo "skip=$DOMINATED" >> $GITHUB_OUTPUT | |
| - name: Generate Changelog.lua | |
| if: steps.guard.outputs.skip != 'true' | |
| id: changelog | |
| run: | | |
| chmod +x generate_changelog.sh | |
| if [[ "$GITHUB_REF" == refs/heads/* ]] && [[ -z "${{ inputs.tag }}" ]]; then | |
| export FORCE_ALPHA=true | |
| fi | |
| if [[ "$GITHUB_REF" == refs/tags/* ]]; then | |
| export OVERRIDE_TAG="${GITHUB_REF#refs/tags/}" | |
| elif [[ -n "${{ inputs.tag }}" ]]; then | |
| export OVERRIDE_TAG="${{ inputs.tag }}" | |
| fi | |
| ./generate_changelog.sh | |
| VERSION=$(grep '^## Version:' DandersFrames.toc | sed 's/^## Version: //') | |
| CHANNEL=$(grep 'DF.RELEASE_CHANNEL' Changelog.lua | sed 's/.*= "\(.*\)"/\1/') | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "channel=$CHANNEL" >> $GITHUB_OUTPUT | |
| NOTES=$(awk '/^## / { count++; if (count > 1) exit } count >= 1 { print }' CHANGELOG.md | sed -e :a -e '/^[[:space:]-]*$/{ $d; N; ba; }') | |
| { | |
| echo "notes<<NOTES_EOF" | |
| echo "$NOTES" | |
| echo "NOTES_EOF" | |
| } >> $GITHUB_OUTPUT | |
| - name: Create local tag for clean zip naming | |
| if: steps.guard.outputs.skip != 'true' | |
| run: | | |
| VERSION="${{ steps.changelog.outputs.version }}" | |
| # Create a local-only tag so the packager uses a clean name | |
| # e.g. v4.0.5-alpha.3 -> zip becomes DandersFrames-v4.0.5-alpha.3 | |
| if ! git tag --list | grep -qx "$VERSION"; then | |
| git tag "$VERSION" | |
| fi | |
| - name: Package and Release | |
| if: steps.guard.outputs.skip != 'true' | |
| uses: BigWigsMods/packager@v2 | |
| env: | |
| CF_API_KEY: ${{ secrets.CF_API_KEY }} | |
| GITHUB_OAUTH: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Notify Discord (dev channel — alpha/beta) | |
| if: steps.guard.outputs.skip != 'true' && success() && steps.changelog.outputs.channel != 'release' | |
| env: | |
| DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_DEV }} | |
| VERSION: ${{ steps.changelog.outputs.version }} | |
| CHANNEL: ${{ steps.changelog.outputs.channel }} | |
| NOTES: ${{ steps.changelog.outputs.notes }} | |
| run: | | |
| if [ -z "$DISCORD_WEBHOOK_URL" ]; then | |
| echo "No dev Discord webhook configured, skipping." | |
| exit 0 | |
| fi | |
| CHANNEL_UPPER=$(echo "$CHANNEL" | sed 's/.*/\u&/') | |
| case "$CHANNEL" in | |
| beta) EMOJI="🧪"; LABEL="Beta ${VERSION} Available for Testing!" ;; | |
| *) EMOJI="🧪"; LABEL="Alpha ${VERSION} Available for Testing!" ;; | |
| esac | |
| BODY=$(echo "$NOTES" | sed '1{/^## /d}' | sed '/^[[:space:]]*$/d') | |
| HEADER="### ${EMOJI} ${LABEL} | |
| **Download:** [CurseForge](<https://www.curseforge.com/wow/addons/danders-frames>) *(select \"${CHANNEL_UPPER}\" from the dropdown)* • [GitHub Releases](<https://github.com/DanderBot/DandersFrames/releases>) | |
| **Support Development:** [PayPal](<https://paypal.me/dandersframesaddon>)" | |
| HEADER=$(echo "$HEADER" | sed 's/^ //') | |
| FOOTER="*${CHANNEL_UPPER} builds are available on CurseForge by selecting \"${CHANNEL_UPPER}\" in the file dropdown, or from [GitHub Releases](<https://github.com/DanderBot/DandersFrames/releases>).*" | |
| # Split body into chunks that fit Discord's 2000 char limit | |
| # Reserve space for header/footer text in first/last messages | |
| HEADER_LEN=${#HEADER} | |
| FOOTER_LEN=${#FOOTER} | |
| FIRST_BUDGET=$((1900 - HEADER_LEN)) | |
| MIDDLE_BUDGET=1900 | |
| LAST_BUDGET=$((1900 - FOOTER_LEN)) | |
| MESSAGES=() | |
| CURRENT="" | |
| FIRST=true | |
| while IFS= read -r line; do | |
| BUDGET=$MIDDLE_BUDGET | |
| if [ "$FIRST" = true ]; then | |
| BUDGET=$FIRST_BUDGET | |
| fi | |
| CANDIDATE="${CURRENT:+$CURRENT | |
| }${line}" | |
| if [ ${#CANDIDATE} -gt "$BUDGET" ] && [ -n "$CURRENT" ]; then | |
| MESSAGES+=("$CURRENT") | |
| CURRENT="$line" | |
| FIRST=false | |
| else | |
| CURRENT="$CANDIDATE" | |
| fi | |
| done <<< "$BODY" | |
| [ -n "$CURRENT" ] && MESSAGES+=("$CURRENT") | |
| TOTAL=${#MESSAGES[@]} | |
| for i in "${!MESSAGES[@]}"; do | |
| MSG="" | |
| if [ "$i" -eq 0 ]; then | |
| MSG="${HEADER} | |
| ${MESSAGES[$i]}" | |
| else | |
| MSG="${MESSAGES[$i]}" | |
| fi | |
| if [ "$i" -eq $((TOTAL - 1)) ]; then | |
| MSG="${MSG} | |
| ${FOOTER}" | |
| fi | |
| MSG=$(echo "$MSG" | sed 's/^ //') | |
| PAYLOAD=$(jq -n --arg content "$MSG" '{ content: $content }') | |
| HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \ | |
| -H "Content-Type: application/json" \ | |
| -d "$PAYLOAD" \ | |
| "$DISCORD_WEBHOOK_URL") | |
| echo "Message $((i+1))/${TOTAL}: HTTP ${HTTP_CODE}" | |
| # Small delay between messages to preserve ordering | |
| if [ "$i" -lt $((TOTAL - 1)) ]; then | |
| sleep 1 | |
| fi | |
| done | |
| - name: Notify Discord (release channel — stable only) | |
| if: steps.guard.outputs.skip != 'true' && success() && steps.changelog.outputs.channel == 'release' | |
| env: | |
| DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_RELEASE }} | |
| VERSION: ${{ steps.changelog.outputs.version }} | |
| NOTES: ${{ steps.changelog.outputs.notes }} | |
| ROLE_MENTION: "<@&1444387824005808128>" | |
| run: | | |
| if [ -z "$DISCORD_WEBHOOK_URL" ]; then | |
| echo "No release Discord webhook configured, skipping." | |
| exit 0 | |
| fi | |
| BODY=$(echo "$NOTES" | sed '1{/^## /d}' | sed '/^[[:space:]]*$/d') | |
| HEADER="${ROLE_MENTION} | |
| ### 🔔 Update ${VERSION} is Live! | |
| **Download:** [CurseForge](<https://www.curseforge.com/wow/addons/danders-frames>) • [Wago](<https://addons.wago.io/addons/danders-frames>) • [GitHub Releases](<https://github.com/DanderBot/DandersFrames/releases>) | |
| **Support Development:** [PayPal](<https://paypal.me/dandersframesaddon>)" | |
| HEADER=$(echo "$HEADER" | sed 's/^ //') | |
| FOOTER="*Note: It may take 15-30 minutes to appear on the CurseForge client.*" | |
| HEADER_LEN=${#HEADER} | |
| FOOTER_LEN=${#FOOTER} | |
| ROLE_LEN=${#ROLE_MENTION} | |
| FIRST_BUDGET=$((1900 - HEADER_LEN)) | |
| MIDDLE_BUDGET=$((1900 - ROLE_LEN - 1)) | |
| LAST_BUDGET=$((1900 - FOOTER_LEN - ROLE_LEN - 1)) | |
| MESSAGES=() | |
| CURRENT="" | |
| FIRST=true | |
| while IFS= read -r line; do | |
| BUDGET=$MIDDLE_BUDGET | |
| if [ "$FIRST" = true ]; then | |
| BUDGET=$FIRST_BUDGET | |
| fi | |
| CANDIDATE="${CURRENT:+$CURRENT | |
| }${line}" | |
| if [ ${#CANDIDATE} -gt "$BUDGET" ] && [ -n "$CURRENT" ]; then | |
| MESSAGES+=("$CURRENT") | |
| CURRENT="$line" | |
| FIRST=false | |
| else | |
| CURRENT="$CANDIDATE" | |
| fi | |
| done <<< "$BODY" | |
| [ -n "$CURRENT" ] && MESSAGES+=("$CURRENT") | |
| TOTAL=${#MESSAGES[@]} | |
| for i in "${!MESSAGES[@]}"; do | |
| MSG="" | |
| if [ "$i" -eq 0 ]; then | |
| MSG="${HEADER} | |
| ${MESSAGES[$i]}" | |
| else | |
| MSG="${ROLE_MENTION} | |
| ${MESSAGES[$i]}" | |
| fi | |
| if [ "$i" -eq $((TOTAL - 1)) ]; then | |
| MSG="${MSG} | |
| ${FOOTER}" | |
| fi | |
| MSG=$(echo "$MSG" | sed 's/^ //') | |
| PAYLOAD=$(jq -n --arg content "$MSG" '{ content: $content }') | |
| HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \ | |
| -H "Content-Type: application/json" \ | |
| -d "$PAYLOAD" \ | |
| "$DISCORD_WEBHOOK_URL") | |
| echo "Message $((i+1))/${TOTAL}: HTTP ${HTTP_CODE}" | |
| if [ "$i" -lt $((TOTAL - 1)) ]; then | |
| sleep 1 | |
| fi | |
| done |