From 43b5f05a4cdec2b48324b38709d3c062fc7fe768 Mon Sep 17 00:00:00 2001 From: Florian Berthold Date: Sat, 23 May 2026 00:14:38 +0200 Subject: [PATCH 01/10] fix: pcall-guard C_ClassInfo.GetSpecInfo in Types.lua spec iteration Same CoA client issue as coa-details: GetAllSpecs(class) returns items that GetSpecInfo rejects with 'Expected string' at arg #2. Wrap the addSpec(class, GetSpecInfo(class, spec)) call in pcall so bad iterations skip silently rather than spamming Error.txt. --- WeakAuras/Types.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/WeakAuras/Types.lua b/WeakAuras/Types.lua index 68573c7..428e594 100644 --- a/WeakAuras/Types.lua +++ b/WeakAuras/Types.lua @@ -3839,7 +3839,10 @@ do local specs = C_ClassInfo.GetAllSpecs(class) if specs then for _, spec in ipairs(specs) do - addSpec(class, C_ClassInfo.GetSpecInfo(class, spec)) + local ok, info = pcall(C_ClassInfo.GetSpecInfo, class, spec) + if ok and info then + addSpec(class, info) + end end end end From 6078989cb106d398cb0cedcc933da18a07b557fe Mon Sep 17 00:00:00 2001 From: Florian Berthold Date: Sun, 24 May 2026 17:38:22 +0200 Subject: [PATCH 02/10] fix(login): defer downgrade popup, guard data, include CoA classes Three fixes addressing the reported 'auras silently vanish on next save' bug, plus collateral robustness in the same code path: 1. WeakAuras.lua PLAYER_LOGIN handler (~L1297-1308): the downgrade branch fired StaticPopup_Show('WEAKAURAS_CONFIRM_REPAIR', ...) synchronously inside the event handler. On the CoA reworked StaticPopup system this fires too early and silently fails to show the dialog, which means neither OnAccept nor OnCancel ever runs, so Private.Login() is never called. With no displays loaded, the next PLAYER_LOGOUT serializes an empty table over WeakAurasSaved and the user loses all their auras. Wrap the call in C_Timer.After(0, ...) so it fires after the event frame stack has unwound and the popup system is ready. This is the most likely root cause of the user report 'my auras don't save anymore' that surfaced on the PTR last week. 2. WeakAuras.lua WEAKAURAS_CONFIRM_REPAIR popup (~L2263-2277): OnShow and OnCancel both unconditionally dereferenced self.data.reason. If the popup is ever fired with nil or malformed data this throws and blocks Private.Login() from running via the OnCancel fallback. Guard with a nil check and default reason to 'unknown' (treated as the automatic / downgrade path, which is the safe default that still invokes Login). 3. Types.lua WeakAuras.class_types (~L1187): only populated from CLASS_SORT_ORDER, which on CoA contains only the 11 vanilla classes. The 21 custom CoA classes were silently missing from every class filter dropdown in the options UI. Add a fallback loop over LOCALIZED_CLASS_NAMES_MALE for anything CLASS_SORT_ORDER didn't already register, mirroring the pattern the spec builder uses at ~L3829. --- WeakAuras/Types.lua | 10 ++++++++++ WeakAuras/WeakAuras.lua | 27 +++++++++++++++++++++++---- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/WeakAuras/Types.lua b/WeakAuras/Types.lua index 428e594..214b6e3 100644 --- a/WeakAuras/Types.lua +++ b/WeakAuras/Types.lua @@ -1187,6 +1187,16 @@ WeakAuras.class_types = {} for i, class in ipairs(CLASS_SORT_ORDER) do WeakAuras.class_types[class] = WrapTextInColorCode(LOCALIZED_CLASS_NAMES_MALE[class], WA_GetClassColor(class)) end +-- CoA: CLASS_SORT_ORDER only contains the 11 vanilla classes, missing the 21 +-- custom CoA classes. Fall back to LOCALIZED_CLASS_NAMES_MALE for anything not +-- yet registered. Same pattern used by the spec builder further down this file. +if LOCALIZED_CLASS_NAMES_MALE then + for class in pairs(LOCALIZED_CLASS_NAMES_MALE) do + if not WeakAuras.class_types[class] then + WeakAuras.class_types[class] = WrapTextInColorCode(LOCALIZED_CLASS_NAMES_MALE[class], WA_GetClassColor(class)) + end + end +end if WeakAuras.IsClassicPlus() then WeakAuras.class_types["DEATHKNIGHT"] = nil end diff --git a/WeakAuras/WeakAuras.lua b/WeakAuras/WeakAuras.lua index df00e53..0358bb2 100644 --- a/WeakAuras/WeakAuras.lua +++ b/WeakAuras/WeakAuras.lua @@ -1304,8 +1304,16 @@ loadedFrame:SetScript("OnEvent", function(self, event, ...) if dbIsValid then Private.Login(takeNewSnapshots) else - -- db isn't valid. Request permission to run repair tool before logging in - StaticPopup_Show("WEAKAURAS_CONFIRM_REPAIR", nil, nil, {reason = "downgrade"}) + -- db isn't valid. Request permission to run repair tool before logging in. + -- CoA: defer the StaticPopup_Show by one frame so it fires after the + -- PLAYER_LOGIN event-frame stack has unwound. On the CoA reworked + -- StaticPopup system, firing this synchronously during PLAYER_LOGIN + -- silently fails to show the popup, which means Private.Login() is + -- never invoked, no auras load, and the next logout writes an empty + -- WeakAurasSaved over the user's profile. + C_Timer.After(0, function() + StaticPopup_Show("WEAKAURAS_CONFIRM_REPAIR", nil, nil, {reason = "downgrade"}) + end) end elseif event == "PLAYER_LOGOUT" then for id in pairs(db.displays) do @@ -2264,14 +2272,25 @@ StaticPopupDialogs["WEAKAURAS_CONFIRM_REPAIR"] = { local AutomaticRepairText = L["WeakAuras has detected that it has been downgraded.\nYour saved auras may no longer work properly.\nWould you like to run the |cffff0000EXPERIMENTAL|r repair tool? This will overwrite any changes you have made since the last database upgrade.\nLast upgrade: %s\n\n|cffff0000You should BACKUP your WTF folder BEFORE pressing this button.|r"] local ManualRepairText = L["Are you sure you want to run the |cffff0000EXPERIMENTAL|r repair tool?\nThis will overwrite any changes you have made since the last database upgrade.\nLast upgrade: %s"] - if self.data.reason == "user" then + -- CoA: guard against malformed data; default reason to "unknown" so the + -- popup can't error out and block Private.Login() from ever running. + local reason = "unknown" + if self.data then + reason = self.data.reason or "unknown" + end + + if reason == "user" then self.text:SetText(ManualRepairText:format(LastUpgrade())) else self.text:SetText(AutomaticRepairText:format(LastUpgrade())) end end, OnCancel = function(self) - if self.data.reason ~= "user" then + local reason = "unknown" + if self.data then + reason = self.data.reason or "unknown" + end + if reason ~= "user" then Private.Login() end end, From 40cd0f684fb770d28e7857a32a8dc64271a3ffce Mon Sep 17 00:00:00 2001 From: Florian Berthold Date: Mon, 25 May 2026 10:59:33 +0200 Subject: [PATCH 03/10] chore: align with Exiles fork-layout convention (standard .gitignore + .gitattributes) --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 3552451..97b6215 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .idea +.idea From 5c369f788687b702b5415e648262ea8b4f80f4b5 Mon Sep 17 00:00:00 2001 From: Florian Berthold Date: Mon, 25 May 2026 11:02:53 +0200 Subject: [PATCH 04/10] chore: remove .github/ (upstream templates, not relevant on Gitea) --- .github/FUNDING.yml | 14 --- .github/ISSUE_TEMPLATE/bug_report.yml | 123 ---------------------- .github/ISSUE_TEMPLATE/config.yml | 5 - .github/ISSUE_TEMPLATE/feature_request.md | 20 ---- .github/workflows/autoclose.yaml | 115 -------------------- .github/workflows/lint-pr.yml | 62 ----------- .github/workflows/lint.yml | 66 ------------ 7 files changed, 405 deletions(-) delete mode 100644 .github/FUNDING.yml delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml delete mode 100644 .github/ISSUE_TEMPLATE/config.yml delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.md delete mode 100644 .github/workflows/autoclose.yaml delete mode 100644 .github/workflows/lint-pr.yml delete mode 100644 .github/workflows/lint.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index 2ac83fa..0000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,14 +0,0 @@ -# These are supported funding model platforms - -github: [NoM0Re] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] -patreon: # Replace with a single Patreon username -open_collective: # Replace with a single Open Collective username -ko_fi: # Replace with a single Ko-fi username -tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel -community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry -liberapay: # Replace with a single Liberapay username -issuehunt: # Replace with a single IssueHunt username -otechie: # Replace with a single Otechie username -lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry -custom: https://streamelements.com/nom0ree/tip - diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml deleted file mode 100644 index 0665220..0000000 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ /dev/null @@ -1,123 +0,0 @@ -name: "Bug Report" -description: Create a report to help us improve -labels: ['🐛 Bug'] -body: -- type: checkboxes - attributes: - label: Is there an existing issue for this? - description: Please [search for existing issues](https://github.com/Ascension-Addons/WeakAuras-Ascension/issues) to see if an open or closed one already exists for the bug you encountered. If a bug exists and it is closed as complete it may not yet be in a stable release. - options: - - label: I have searched the existing open and closed issues. - required: true - -- type: textarea - attributes: - label: Description - description: What did you expect to happen and what happened instead? - validations: - required: true - -- type: input - attributes: - label: WeakAuras Version - description: | - You can see the current version in the title bar of the options window, if the options do not open, check the `## Version:` field in the WeakAuras.toc file. - placeholder: "WeakAuras 5.0.0" - validations: - required: true - -- type: dropdown - id: flavor - attributes: - label: World of Warcraft Flavor - description: What version of World of Warcraft are are you running? - options: - - WotLK 3.3.5a - validations: - required: true - -- type: dropdown - id: language - attributes: - label: World of Warcraft Language - description: In which language do you play World of Warcraft? - options: - - enGB/enUS - - deDE - - frFR - - itIT - - esES - - esMX - - koKR - - ptBR - - ruRU - - zhCN - - zhTW - validations: - required: true - -- type: input - id: server - attributes: - label: Server - description: On which server/realm are you playing? - placeholder: Warmane-Icecrown - validations: - required: true - -- type: checkboxes - id: testing - attributes: - label: Tested with only WeakAuras - description: Sometimes, other addons can interfere with WeakAuras. We recommend testing with only WeakAuras enabled to see if the issue persists. - options: - - label: I got this issue with only WeakAuras enabled - required: true - -- type: textarea - attributes: - label: Lua Error - description: | - Do you have an error log of what happened? If you don't see any errors, make sure that error reporting is enabled (`/console scriptErrors 1`) or install [BugSack](https://www.curseforge.com/wow/addons/bugsack) & [BugGrabber](https://www.curseforge.com/wow/addons/bug-grabber), yes both are needed. - Note that if the error looks like `[string "--[[ Error in ' my awesome aura' ]` then the bug is in the aura that got mentioned, not in WeakAuras itself. - render: Text - validations: - required: false - -- type: textarea - attributes: - label: Reproduction Steps - description: Please list out the steps to reproduce your bug. Please verify that your reproduction steps are enough to reproduce the problem. - placeholder: | - 1. Go to '...' - 2. Click on '....' - 3. Scroll down to '....' - 4. See error - validations: - required: true - -- type: input - attributes: - label: Last Good Version - description: | - Was it working in a previous version? If yes, which was the last good one? - placeholder: "WeakAuras 5.0.0" - validations: - required: false - -- type: textarea - attributes: - label: Screenshots - description: If applicable, add screenshots to help explain your problem. - placeholder: Click here to attach your screenshots via the editor button in the top right. - validations: - required: false - -- type: textarea - attributes: - label: Export String - description: If you do not know which aura is causing issues for you, please attach a ZIP archive of your WeakAuras SavedVariables file, it's the `WeakAuras.lua` file in `World of Warcraft\_retail_\WTF\Account\YOUR_ACCOUNT\SavedVariables\`. In case you do, please export the string and paste it below. - placeholder: Paste your exported WeakAuras string here. - render: Text - validations: - required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index 6498af8..0000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,5 +0,0 @@ -blank_issues_enabled: false -contact_links: - - name: Question - url: https://discord.gg/classlesswow - about: Please ask and answer questions here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 5e0fb3a..0000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: "\U0001F3A8 Feature Request" -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/.github/workflows/autoclose.yaml b/.github/workflows/autoclose.yaml deleted file mode 100644 index 5dc7272..0000000 --- a/.github/workflows/autoclose.yaml +++ /dev/null @@ -1,115 +0,0 @@ -name: Autoclose after 2 days - -on: - schedule: - - cron: '0 0 * * *' - issues: - types: [labeled] - pull_request: - types: [labeled] - -permissions: - issues: write - pull-requests: write - -jobs: - autoclose: - runs-on: ubuntu-latest - steps: - - name: Close Issues/PRs labeled 'Auto Close' after 2 days, if label set by collaborator and no recent comments - uses: actions/github-script@v7 - with: - script: | - const { owner, repo } = context.repo; - const labelName = '⏳Auto Close'; - const maxAgeDays = 2; - const now = new Date(); - - const issues = await github.paginate(github.rest.issues.listForRepo, { - owner, - repo, - labels: labelName, - state: 'open', - per_page: 100, - }); - - for (const issue of issues) { - const issue_number = issue.number; - - const events = await github.paginate(github.rest.issues.listEventsForTimeline, { - owner, - repo, - issue_number, - per_page: 100, - }); - - const labelEvent = events.find(event => - event.event === 'labeled' && - event.label?.name === labelName - ); - - if (!labelEvent) continue; - - let labelDate = new Date(labelEvent.created_at); - - const comments = await github.paginate( - issue.pull_request - ? github.rest.pulls.listReviewComments - : github.rest.issues.listComments, - { - owner, - repo, - issue_number, - per_page: 100, - } - ); - - const recentCommentsAfterLabel = comments - .filter(c => new Date(c.created_at) > labelDate); - - let latestDate = labelDate; - if (recentCommentsAfterLabel.length > 0) { - latestDate = new Date(Math.max(...recentCommentsAfterLabel.map(c => new Date(c.created_at).getTime()))); - } - - const diffDays = (now - latestDate) / (1000 * 60 * 60 * 24); - - if (diffDays < maxAgeDays) continue; - - const actor = labelEvent.actor?.login; - if (!actor) continue; - - try { - await github.rest.repos.checkCollaborator({ - owner, - repo, - username: actor, - }); - } catch (error) { - if (error.status === 404) { - await github.rest.issues.removeLabel({ - owner, - repo, - issue_number, - name: labelName, - }); - continue; - } else { - throw error; - } - } - - await github.rest.issues.update({ - owner, - repo, - issue_number, - state: 'closed', - }); - - await github.rest.issues.removeLabel({ - owner, - repo, - issue_number, - name: labelName, - }); - } diff --git a/.github/workflows/lint-pr.yml b/.github/workflows/lint-pr.yml deleted file mode 100644 index af43ec7..0000000 --- a/.github/workflows/lint-pr.yml +++ /dev/null @@ -1,62 +0,0 @@ -name: lint - -on: - pull_request: - paths: - - '**.lua' - -jobs: - lint: - runs-on: ubuntu-latest - - env: - LUA_VERSION: 5.1.5 - LUAROCKS_VERSION: 3.11.1 - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Cache Lua - uses: actions/cache@v3 - id: luacache - with: - path: .lua - key: ${{ runner.os }}-lua-${{ env.LUA_VERSION }} - restore-keys: | - ${{ runner.os }}-lua-${{ env.LUA_VERSION }} - - - name: Cache LuaRocks - uses: actions/cache@v3 - id: luarockscache - with: - path: .luarocks - key: ${{ runner.os }}-luarocks-${{ env.LUAROCKS_VERSION }} - restore-keys: | - ${{ runner.os }}-luarocks-${{ env.LUAROCKS_VERSION }} - - - name: Install Lua - if: steps.luacache.outputs.cache-hit != 'true' - run: | - sudo apt-get install libreadline-dev libncurses-dev - wget https://www.lua.org/ftp/lua-${{ env.LUA_VERSION }}.tar.gz -O - | tar -xzf - - cd lua-${{ env.LUA_VERSION }} - make linux - make -j INSTALL_TOP=$GITHUB_WORKSPACE/.lua install - rm -rf $GITHUB_WORKSPACE/lua-${{ env.LUA_VERSION }} - - - name: Install LuaRocks and Luacheck - if: steps.luarockscache.outputs.cache-hit != 'true' - run: | - wget https://luarocks.org/releases/luarocks-${{ env.LUAROCKS_VERSION }}.tar.gz -O - | tar -xzf - - cd luarocks-${{ env.LUAROCKS_VERSION }} - ./configure --with-lua-bin=$GITHUB_WORKSPACE/.lua/bin --prefix=$GITHUB_WORKSPACE/.luarocks - make build - make install - PATH=$PATH:$GITHUB_WORKSPACE/.luarocks/bin - luarocks install luacheck - luarocks install lanes - rm -rf $GITHUB_WORKSPACE/luarocks-${{ env.LUAROCKS_VERSION }} - - - name: Luacheck - run: .luarocks/bin/luacheck . -q diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml deleted file mode 100644 index cb8c310..0000000 --- a/.github/workflows/lint.yml +++ /dev/null @@ -1,66 +0,0 @@ -name: lint - -on: - push: - paths: - - '.github/workflows/**.yml' - - '**.lua' - pull_request: - paths: - - '**.lua' - -jobs: - lint: - runs-on: ubuntu-latest - - env: - LUA_VERSION: 5.1.5 - LUAROCKS_VERSION: 3.11.1 - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Cache Lua - uses: actions/cache@v3 - id: luacache - with: - path: .lua - key: ${{ runner.os }}-lua-${{ env.LUA_VERSION }} - restore-keys: | - ${{ runner.os }}-lua-${{ env.LUA_VERSION }} - - - name: Cache LuaRocks - uses: actions/cache@v3 - id: luarockscache - with: - path: .luarocks - key: ${{ runner.os }}-luarocks-${{ env.LUAROCKS_VERSION }} - restore-keys: | - ${{ runner.os }}-luarocks-${{ env.LUAROCKS_VERSION }} - - - name: Install Lua - if: steps.luacache.outputs.cache-hit != 'true' - run: | - sudo apt-get install libreadline-dev libncurses-dev - wget https://www.lua.org/ftp/lua-${{ env.LUA_VERSION }}.tar.gz -O - | tar -xzf - - cd lua-${{ env.LUA_VERSION }} - make linux - make -j INSTALL_TOP=$GITHUB_WORKSPACE/.lua install - rm -rf $GITHUB_WORKSPACE/lua-${{ env.LUA_VERSION }} - - - name: Install LuaRocks and Luacheck - if: steps.luarockscache.outputs.cache-hit != 'true' - run: | - wget https://luarocks.org/releases/luarocks-${{ env.LUAROCKS_VERSION }}.tar.gz -O - | tar -xzf - - cd luarocks-${{ env.LUAROCKS_VERSION }} - ./configure --with-lua-bin=$GITHUB_WORKSPACE/.lua/bin --prefix=$GITHUB_WORKSPACE/.luarocks - make build - make install - PATH=$PATH:$GITHUB_WORKSPACE/.luarocks/bin - luarocks install luacheck - luarocks install lanes - rm -rf $GITHUB_WORKSPACE/luarocks-${{ env.LUAROCKS_VERSION }} - - - name: Luacheck - run: .luarocks/bin/luacheck . From a842d5b7617448590583dd5eb809b5fa1298aa15 Mon Sep 17 00:00:00 2001 From: Florian Berthold Date: Mon, 25 May 2026 12:01:47 +0200 Subject: [PATCH 05/10] ci: add Gitea Actions release workflow (per-addon git-archive zip) --- .gitea/workflows/release.yml | 49 +++++++++++++++++++++++++++++ .gitignore | 2 ++ tools/build_zip.sh | 60 ++++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+) create mode 100644 .gitea/workflows/release.yml create mode 100755 tools/build_zip.sh diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml new file mode 100644 index 0000000..7c1ffe1 --- /dev/null +++ b/.gitea/workflows/release.yml @@ -0,0 +1,49 @@ +name: release + +on: + push: + tags: + - '*-coa.*' # Asc-1.1.6-coa.2, 9.1.40-coa.3, etc. + - 'v*' # v0.3.0 for repos without an upstream version + +jobs: + release: + runs-on: linux-amd64 + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 # build_zip uses git archive HEAD; full history is fine + + - name: Build per-addon zip(s) + run: bash tools/build_zip.sh + + - name: Publish release (Gitea API direct; no action dependency) + env: + GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO: ${{ github.repository }} + TAG: ${{ github.ref_name }} + API: ${{ github.server_url }}/api/v1 + run: | + set -euo pipefail + # Create the release (or reuse if it already exists for this tag). + RID=$(curl -s -H "Authorization: token $GITEA_TOKEN" \ + "$API/repos/$REPO/releases/tags/$TAG" 2>/dev/null \ + | jq -r '.id // empty') + if [ -z "$RID" ]; then + RID=$(curl -sf -X POST -H "Authorization: token $GITEA_TOKEN" \ + -H "Content-Type: application/json" \ + "$API/repos/$REPO/releases" \ + -d "$(jq -nc --arg t "$TAG" '{tag_name:$t,name:$t,draft:false,prerelease:false}')" \ + | jq -r '.id') + fi + echo "release id: $RID" + # Upload every dist/*.zip + for f in dist/*.zip; do + name=$(basename "$f") + echo "uploading $name" + curl -sf -X POST -H "Authorization: token $GITEA_TOKEN" \ + -F "attachment=@$f" \ + "$API/repos/$REPO/releases/$RID/assets?name=$name" \ + | jq -r '" -> " + .browser_download_url' + done diff --git a/.gitignore b/.gitignore index 97b6215..b11d5da 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ .idea .idea + +dist/ diff --git a/tools/build_zip.sh b/tools/build_zip.sh new file mode 100755 index 0000000..f9c2d68 --- /dev/null +++ b/tools/build_zip.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash +# Build per-addon zip artefacts from HEAD via git-archive. +# +# - Discovers top-level addon folders (Foo/Foo.toc). +# - Re-creates dist/ each run. +# - Always archives HEAD, so the working tree state is irrelevant. +# - If more than one addon folder is present, also emits -all.zip +# with every addon folder side-by-side at the zip root. +set -euo pipefail + +root=$(git rev-parse --show-toplevel) +cd "$root" + +repo_name=$(basename "$root") +dist="$root/dist" + +# Find Foo/Foo.toc pairs at depth 1; ignore libs nested deeper. +addons=() +while IFS= read -r toc; do + dir=$(dirname "$toc") + folder=$(basename "$dir") + base=$(basename "$toc" .toc) + # Accept Foo.toc and Foo_Wrath.toc style flavour variants; folder must match + # at least one toc basename prefix (Foo). + case "$base" in + "$folder"|"$folder"_*) addons+=("$folder") ;; + esac +done < <(command find . -mindepth 2 -maxdepth 2 -type f -name '*.toc' | sed 's|^\./||' | sort) + +# Dedupe (a folder with Foo.toc + Foo_Wrath.toc shows up twice). +if [ ${#addons[@]} -gt 0 ]; then + mapfile -t addons < <(printf '%s\n' "${addons[@]}" | awk '!seen[$0]++') +fi + +if [ ${#addons[@]} -eq 0 ]; then + echo "no addon folders found (looking for */Foo.toc with matching folder name)" >&2 + exit 1 +fi + +rm -rf "$dist" +mkdir -p "$dist" + +for folder in "${addons[@]}"; do + out="$dist/$folder.zip" + # No --prefix: the folder already sits at the repo root, so git-archive + # emits entries as /... which is exactly what + # Interface/AddOns/ expects after extraction. + git archive HEAD --format=zip -o "$out" -- "$folder" + echo "built dist/$folder.zip" +done + +# Combined bundle only makes sense when there are multiple addons. +if [ ${#addons[@]} -gt 1 ]; then + tmp=$(mktemp -d) + trap 'rm -rf "$tmp"' EXIT + git archive HEAD --format=tar -- "${addons[@]}" | tar -x -C "$tmp" + out="$dist/$repo_name-all.zip" + ( cd "$tmp" && zip -qr "$out" "${addons[@]}" ) + echo "built dist/$repo_name-all.zip" +fi From 5e67e7ef9ced22895a497f6b29b8df05394e2513 Mon Sep 17 00:00:00 2001 From: Florian Berthold Date: Mon, 25 May 2026 12:17:01 +0200 Subject: [PATCH 06/10] ci: respect GITHUB_REPOSITORY + tolerate per-asset upload failures --- .gitea/workflows/release.yml | 34 ++++++++++++++++++++++++++++------ tools/build_zip.sh | 13 ++++++++++++- 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 7c1ffe1..709a7cd 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -24,6 +24,9 @@ jobs: REPO: ${{ github.repository }} TAG: ${{ github.ref_name }} API: ${{ github.server_url }}/api/v1 + # Gitea attachment ceiling is 200 MiB (see roles/gitea config). + # Skip anything larger so one oversized asset doesn't fail the job. + MAX_BYTES: 209715200 run: | set -euo pipefail # Create the release (or reuse if it already exists for this tag). @@ -38,12 +41,31 @@ jobs: | jq -r '.id') fi echo "release id: $RID" - # Upload every dist/*.zip + # Upload every dist/*.zip. Per-asset failures don't fail the job — + # we want partial releases to still publish rather than block the + # whole pipeline on one big file. + failed=0 + uploaded=0 for f in dist/*.zip; do name=$(basename "$f") - echo "uploading $name" - curl -sf -X POST -H "Authorization: token $GITEA_TOKEN" \ - -F "attachment=@$f" \ - "$API/repos/$REPO/releases/$RID/assets?name=$name" \ - | jq -r '" -> " + .browser_download_url' + size=$(stat -c '%s' "$f") + if [ "$size" -gt "$MAX_BYTES" ]; then + echo "::warning::skip $name (${size} B > ${MAX_BYTES} B Gitea limit; host on CDN instead)" + failed=$((failed+1)) + continue + fi + echo "uploading $name ($(numfmt --to=iec "$size"))" + if curl -sf -X POST -H "Authorization: token $GITEA_TOKEN" \ + -F "attachment=@$f" \ + "$API/repos/$REPO/releases/$RID/assets?name=$name" \ + | jq -r '" -> " + .browser_download_url'; then + uploaded=$((uploaded+1)) + else + echo "::warning::upload failed for $name" + failed=$((failed+1)) + fi done + echo "release published: $uploaded uploaded, $failed skipped/failed" + # Only fail the job if NO assets uploaded — a release with zero + # attachments isn't useful to anyone. + [ "$uploaded" -gt 0 ] diff --git a/tools/build_zip.sh b/tools/build_zip.sh index f9c2d68..45d1400 100755 --- a/tools/build_zip.sh +++ b/tools/build_zip.sh @@ -6,12 +6,23 @@ # - Always archives HEAD, so the working tree state is irrelevant. # - If more than one addon folder is present, also emits -all.zip # with every addon folder side-by-side at the zip root. +# - When run inside Gitea Actions the working tree lives under a +# per-job dir like /var/lib/act_runner/work/.../hostexecutor, so the +# repo name comes from $GITHUB_REPOSITORY (set by the runner) and +# only falls back to the toplevel basename for local invocations. set -euo pipefail root=$(git rev-parse --show-toplevel) cd "$root" -repo_name=$(basename "$root") +# Gitea Actions sets GITHUB_REPOSITORY=owner/repo. The basename of +# `git rev-parse --show-toplevel` inside the runner is the worker dir +# (e.g. `hostexecutor`), which would name the bundle wrong. +if [ -n "${GITHUB_REPOSITORY:-}" ]; then + repo_name="${GITHUB_REPOSITORY##*/}" +else + repo_name=$(basename "$root") +fi dist="$root/dist" # Find Foo/Foo.toc pairs at depth 1; ignore libs nested deeper. From 4dd03eebc223726be1ca3a2f06217fe8a22b9c20 Mon Sep 17 00:00:00 2001 From: Florian Berthold Date: Fri, 29 May 2026 10:43:54 +0200 Subject: [PATCH 07/10] fix(Types): build custom-class specs via LOCALIZED_CLASS_NAMES_MALE fallback --- WeakAuras/Types.lua | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/WeakAuras/Types.lua b/WeakAuras/Types.lua index 214b6e3..db21db5 100644 --- a/WeakAuras/Types.lua +++ b/WeakAuras/Types.lua @@ -3842,6 +3842,28 @@ do end table.sort(classOrder) end + else + -- CoA: CLASS_SORT_ORDER only contains the 11 vanilla classes. Append any + -- keys present in LOCALIZED_CLASS_NAMES_MALE that are not already in the + -- list (custom classes such as Witchdoctor, Templar, etc.). Build a fresh + -- local copy — do NOT mutate the global CLASS_SORT_ORDER. + if LOCALIZED_CLASS_NAMES_MALE then + local inOrder = {} + for _, class in ipairs(classOrder) do + inOrder[class] = true + end + classOrder = {unpack(classOrder)} + local extra = {} + for class in pairs(LOCALIZED_CLASS_NAMES_MALE) do + if not inOrder[class] then + extra[#extra + 1] = class + end + end + table.sort(extra) + for _, class in ipairs(extra) do + classOrder[#classOrder + 1] = class + end + end end if C_ClassInfo and C_ClassInfo.GetAllSpecs and C_ClassInfo.GetSpecInfo then From 53053520da577c8c9805f8d474a26461580ffdc6 Mon Sep 17 00:00:00 2001 From: Florian Berthold Date: Fri, 29 May 2026 20:51:20 +0200 Subject: [PATCH 08/10] ci(release): hide auto-generated source archives (hide_archive_links) --- .gitea/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 709a7cd..1b1b66b 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -37,7 +37,7 @@ jobs: RID=$(curl -sf -X POST -H "Authorization: token $GITEA_TOKEN" \ -H "Content-Type: application/json" \ "$API/repos/$REPO/releases" \ - -d "$(jq -nc --arg t "$TAG" '{tag_name:$t,name:$t,draft:false,prerelease:false}')" \ + -d "$(jq -nc --arg t "$TAG" '{tag_name:$t,name:$t,draft:false,prerelease:false,hide_archive_links:true}')" \ | jq -r '.id') fi echo "release id: $RID" From fd49cbdf07e3e9d69b6f476d52a5d05d18c13fbc Mon Sep 17 00:00:00 2001 From: Florian Berthold Date: Wed, 10 Jun 2026 02:11:47 +0200 Subject: [PATCH 09/10] ci(release): sync release.yml from coa-template MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hide_archive_links is only honored by Gitea on release edit, not create — add the PATCH step after create/lookup so auto-generated source archive links actually stay hidden (coa-template 90874c5). --- .gitea/workflows/release.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 1b1b66b..2f93975 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -41,6 +41,10 @@ jobs: | jq -r '.id') fi echo "release id: $RID" + # Gitea honors hide_archive_links only on edit, not create — PATCH it + # so the auto-generated Source Code (zip/tar.gz) links stay hidden. + curl -sf -X PATCH -H "Authorization: token $GITEA_TOKEN" -H "Content-Type: application/json" \ + "$API/repos/$REPO/releases/$RID" -d '{"hide_archive_links":true}' >/dev/null || true # Upload every dist/*.zip. Per-asset failures don't fail the job — # we want partial releases to still publish rather than block the # whole pipeline on one big file. From 27c77ed7ec84f50da0154cf646070615fd911cd2 Mon Sep 17 00:00:00 2001 From: Florian Berthold Date: Wed, 10 Jun 2026 02:13:24 +0200 Subject: [PATCH 10/10] fix: sync Init.lua versionString with 5.22.0 toc to stop false restart nag --- WeakAuras/Init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WeakAuras/Init.lua b/WeakAuras/Init.lua index e5948b5..791daaf 100644 --- a/WeakAuras/Init.lua +++ b/WeakAuras/Init.lua @@ -9,7 +9,7 @@ WeakAuras.halfWidth = WeakAuras.normalWidth / 2 WeakAuras.doubleWidth = WeakAuras.normalWidth * 2 local versionStringFromToc = GetAddOnMetadata("WeakAuras", "Version") -local versionString = "5.21.2 Beta" +local versionString = "5.22.0 Beta" -- Year, Month, Day, Hour, Minute, Seconds local buildTime = "2025".."11".."29".."04".."45".."00" local isTTSEnabled = C_VoiceChat and C_VoiceChat.SpeakText and true or false