From 6d099f6db14eb932a52f5ab110fc7882ee4390df Mon Sep 17 00:00:00 2001 From: Florian Berthold Date: Sun, 24 May 2026 17:08:21 +0200 Subject: [PATCH 01/10] chore(libs): bump LibDataBroker-1.1 to v4 (from canonical) --- .../LibDataBroker-1.1/LibDataBroker-1.1.lua | 26 ++++++++++++++++++- .../Libs/LibDataBroker-1.1/README.textile | 13 ++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 ProfessionMenu/Libs/LibDataBroker-1.1/README.textile diff --git a/ProfessionMenu/Libs/LibDataBroker-1.1/LibDataBroker-1.1.lua b/ProfessionMenu/Libs/LibDataBroker-1.1/LibDataBroker-1.1.lua index 364602e..f47c0cd 100644 --- a/ProfessionMenu/Libs/LibDataBroker-1.1/LibDataBroker-1.1.lua +++ b/ProfessionMenu/Libs/LibDataBroker-1.1/LibDataBroker-1.1.lua @@ -2,7 +2,7 @@ assert(LibStub, "LibDataBroker-1.1 requires LibStub") assert(LibStub:GetLibrary("CallbackHandler-1.0", true), "LibDataBroker-1.1 requires CallbackHandler-1.0") -local lib, oldminor = LibStub:NewLibrary("LibDataBroker-1.1", 3) +local lib, oldminor = LibStub:NewLibrary("LibDataBroker-1.1", 4) if not lib then return end oldminor = oldminor or 0 @@ -64,3 +64,27 @@ if oldminor < 1 then return self.namestorage[dataobject] end end + +if oldminor < 4 then + local next = pairs(attributestorage) + function lib:pairs(dataobject_or_name) + local t = type(dataobject_or_name) + assert(t == "string" or t == "table", "Usage: ldb:pairs('dataobjectname') or ldb:pairs(dataobject)") + + local dataobj = self.proxystorage[dataobject_or_name] or dataobject_or_name + assert(attributestorage[dataobj], "Data object not found") + + return next, attributestorage[dataobj], nil + end + + local ipairs_iter = ipairs(attributestorage) + function lib:ipairs(dataobject_or_name) + local t = type(dataobject_or_name) + assert(t == "string" or t == "table", "Usage: ldb:ipairs('dataobjectname') or ldb:ipairs(dataobject)") + + local dataobj = self.proxystorage[dataobject_or_name] or dataobject_or_name + assert(attributestorage[dataobj], "Data object not found") + + return ipairs_iter, attributestorage[dataobj], 0 + end +end diff --git a/ProfessionMenu/Libs/LibDataBroker-1.1/README.textile b/ProfessionMenu/Libs/LibDataBroker-1.1/README.textile new file mode 100644 index 0000000..ef16fed --- /dev/null +++ b/ProfessionMenu/Libs/LibDataBroker-1.1/README.textile @@ -0,0 +1,13 @@ +LibDataBroker is a small WoW addon library designed to provide a "MVC":http://en.wikipedia.org/wiki/Model-view-controller interface for use in various addons. +LDB's primary goal is to "detach" plugins for TitanPanel and FuBar from the display addon. +Plugins can provide data into a simple table, and display addons can receive callbacks to refresh their display of this data. +LDB also provides a place for addons to register "quicklaunch" functions, removing the need for authors to embed many large libraries to create minimap buttons. +Users who do not wish to be "plagued" by these buttons simply do not install an addon to render them. + +Due to it's simple generic design, LDB can be used for any design where you wish to have an addon notified of changes to a table. + +h2. Links + +* "API documentation":http://github.com/tekkub/libdatabroker-1-1/wikis/api +* "Data specifications":http://github.com/tekkub/libdatabroker-1-1/wikis/data-specifications +* "Addons using LDB":http://github.com/tekkub/libdatabroker-1-1/wikis/addons-using-ldb From 6ef1f9dab81e50f22f443ab057be5a3a243e1af8 Mon Sep 17 00:00:00 2001 From: Florian Berthold Date: Sun, 24 May 2026 17:40:22 +0200 Subject: [PATCH 02/10] fix: name+guard Woodcutting/Woodworking, drop regex+deprecated this+InterfaceOptions guards ProfessionMenu.lua: - profList: add Name="Woodcutting" (spell 13977860) and Name="Woodworking" (spells 1005008-1005011) so getProfessionRanks can find the matching GetSkillLineInfo entry. Without Name, both fell through GetSpellInfo+match with no result and returned nil,nil. - getProfessionRanks: replace compName:match(name) (regex) with compName == name (plain compare); GetSkillLineInfo names are exact, regex was a bug magnet. - Guard rank concat at lines ~394/397/400: skip the " (rank)" / " (max)" / " (rank/max)" append when getProfessionRanks returns nil so unknown skill lines don't error. - InterfaceOptionsFrame:HookScript: wrap in 'if InterfaceOptionsFrame then'; CoA's reworked FrameXML has no InterfaceOptionsFrame. ProfessionMenuOptions.lua: - Guard InterfaceOptionsFrame / InterfaceOptionsFrame_OpenToCategory / InterfaceOptions_AddCategory call sites (Options_Toggle, ProfessionMenu_ OpenOptions, CreateOptionsUI). All nil on CoA's FrameXML. - TxtSize dropdown func: drop deprecated WoW-2.x global 'this'; use UIDropDownMenu_GetSelectedID(ProfessionMenuOptions_TxtSizeMenu) instead. --- ProfessionMenu/ProfessionMenu.lua | 23 +++++++++++++---------- ProfessionMenu/ProfessionMenuOptions.lua | 19 ++++++++++++------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/ProfessionMenu/ProfessionMenu.lua b/ProfessionMenu/ProfessionMenu.lua index d072ad1..5e0363b 100644 --- a/ProfessionMenu/ProfessionMenu.lua +++ b/ProfessionMenu/ProfessionMenu.lua @@ -197,12 +197,13 @@ local profList = { 3274, -- Journeyman 150 3273, -- Apprentice 75 }, --FIRSTAID - {13977860}, --WOODCUTTING + {13977860, Name = "Woodcutting"}, --WOODCUTTING { 1005011, -- Artisan 300 1005010, -- Expert 225 1005009, -- Journeyman 150 1005008, -- Apprentice 75 + Name = "Woodworking", }, --WOODWORKING } @@ -372,7 +373,7 @@ function PM:AddProfessions() local function getProfessionRanks(compName) for skillIndex = 1, GetNumSkillLines() do local name, _, _, rank, _, _, maxRank, _, _, _, _, _, _ = GetSkillLineInfo(skillIndex) - if compName:match(name) then + if compName == name then return rank, maxRank end end @@ -391,13 +392,13 @@ function PM:AddProfessions() end local rank, maxRank = getProfessionRanks(profName) if not self.db.hideRank and self.db.hideMaxRank then - name = name .. " |cFF00FFFF("..rank..")" + if rank then name = name .. " |cFF00FFFF("..rank..")" end end if not self.db.hideMaxRank and self.db.hideRank then - name = name .. " |cFF00FFFF("..maxRank..")" + if maxRank then name = name .. " |cFF00FFFF("..maxRank..")" end end if not self.db.hideMaxRank and not self.db.hideRank then - name = name .. " |cFF00FFFF("..rank.."/"..maxRank..")" + if rank and maxRank then name = name .. " |cFF00FFFF("..rank.."/"..maxRank..")" end end local secure = { type1 = 'spell', @@ -604,11 +605,13 @@ function PM:CreateUI() end PM:CreateUI() -InterfaceOptionsFrame:HookScript("OnShow", function() - if InterfaceOptionsFrame and ProfessionMenuOptionsFrame:IsVisible() then - ProfessionMenu_OpenOptions() - end -end) +if InterfaceOptionsFrame then + InterfaceOptionsFrame:HookScript("OnShow", function() + if InterfaceOptionsFrame and ProfessionMenuOptionsFrame:IsVisible() then + ProfessionMenu_OpenOptions() + end + end) +end -- toggle the main button frame function PM:ToggleMainFrame() diff --git a/ProfessionMenu/ProfessionMenuOptions.lua b/ProfessionMenu/ProfessionMenuOptions.lua index bf5a1a9..ba86347 100644 --- a/ProfessionMenu/ProfessionMenuOptions.lua +++ b/ProfessionMenu/ProfessionMenuOptions.lua @@ -1,15 +1,18 @@ local PM = LibStub("AceAddon-3.0"):GetAddon("ProfessionMenu") function PM:Options_Toggle() + if not InterfaceOptionsFrame then return end if InterfaceOptionsFrame:IsVisible() then InterfaceOptionsFrame:Hide() else - InterfaceOptionsFrame_OpenToCategory("ProfessionMenu") + if InterfaceOptionsFrame_OpenToCategory then + InterfaceOptionsFrame_OpenToCategory("ProfessionMenu") + end end end function ProfessionMenu_OpenOptions() - if InterfaceOptionsFrame:GetWidth() < 850 then InterfaceOptionsFrame:SetWidth(850) end + if InterfaceOptionsFrame and InterfaceOptionsFrame:GetWidth() < 850 then InterfaceOptionsFrame:SetWidth(850) end ProfessionMenu_DropDownInitialize() UIDropDownMenu_SetText(ProfessionMenuOptions_TxtSizeMenu, PM.db.txtSize) end @@ -17,14 +20,16 @@ end --Creates the options frame and all its assets function PM:CreateOptionsUI() - if InterfaceOptionsFrame:GetWidth() < 850 then InterfaceOptionsFrame:SetWidth(850) end + if InterfaceOptionsFrame and InterfaceOptionsFrame:GetWidth() < 850 then InterfaceOptionsFrame:SetWidth(850) end local mainframe = {} mainframe.panel = CreateFrame("FRAME", "ProfessionMenuOptionsFrame", UIParent, nil) local fstring = mainframe.panel:CreateFontString(mainframe, "OVERLAY", "GameFontNormal") fstring:SetText("Profession Menu Settings") fstring:SetPoint("TOPLEFT", 15, -15) mainframe.panel.name = "ProfessionMenu" - InterfaceOptions_AddCategory(mainframe.panel) + if InterfaceOptions_AddCategory then + InterfaceOptions_AddCategory(mainframe.panel) + end local hideMenu = CreateFrame("CheckButton", "ProfessionMenuOptions_HideMenu", ProfessionMenuOptionsFrame, "UICheckButtonTemplate") hideMenu:SetPoint("TOPLEFT", 15, -60) @@ -143,9 +148,9 @@ PM:CreateOptionsUI() for i = 10, 25 do info = { text = i; - func = function() - PM.db.txtSize = i - local thisID = this:GetID(); + func = function() + PM.db.txtSize = i + local thisID = UIDropDownMenu_GetSelectedID(ProfessionMenuOptions_TxtSizeMenu) UIDropDownMenu_SetSelectedID(ProfessionMenuOptions_TxtSizeMenu, thisID) end; }; From 3ed0021c7b743c3bf519b081292a0c5ae80a7370 Mon Sep 17 00:00:00 2001 From: Florian Berthold Date: Sun, 24 May 2026 19:30:37 +0200 Subject: [PATCH 03/10] fix(libs): pick up coa-ace3 9583952 (AceDB falsy-defaults PR #10 backport) Re-sync after coa-ace3 9583952 backported WoWUIDev/Ace3 PR #10 which fixes the AceDB-3.0 simple-value defaults metatable: previously falsy defaults like ["*"] = false read back as nil because of `k2~=nil and v or nil` short-circuiting. Now they round-trip correctly. --- ProfessionMenu/Libs/AceDB-3.0/AceDB-3.0.lua | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ProfessionMenu/Libs/AceDB-3.0/AceDB-3.0.lua b/ProfessionMenu/Libs/AceDB-3.0/AceDB-3.0.lua index 231196c..f83a715 100644 --- a/ProfessionMenu/Libs/AceDB-3.0/AceDB-3.0.lua +++ b/ProfessionMenu/Libs/AceDB-3.0/AceDB-3.0.lua @@ -111,7 +111,15 @@ local function copyDefaults(dest, src) end else -- Values are not tables, so this is just a simple return - local mt = {__index = function(t,k2) return k2~=nil and v or nil end} + -- (PR #10 backport: the old `k2~=nil and v or nil` short-circuits to + -- nil whenever the default `v` itself is falsy — so `["*"] = false` + -- defaults silently became nil. Make the read explicit instead.) + local mt = { + __index = function(t,k2) + if k2 == nil then return nil end + return v + end, + } setmetatable(dest, mt) end elseif type(v) == "table" then From aa9a4919c920edf09629344251585aa73f5b2b3a Mon Sep 17 00:00:00 2001 From: Florian Berthold Date: Mon, 25 May 2026 10:59:31 +0200 Subject: [PATCH 04/10] chore: align with Exiles fork-layout convention (standard .gitignore + .gitattributes) --- .gitattributes | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitattributes b/.gitattributes index dfe0770..fa1385d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1 @@ -# Auto detect text files and perform LF normalization -* text=auto +* -text From 769a9ee0424051ec8e1b87fb2b4835e409f2da3b Mon Sep 17 00:00:00 2001 From: Florian Berthold Date: Mon, 25 May 2026 11:02:49 +0200 Subject: [PATCH 05/10] chore: remove .github/ (upstream templates, not relevant on Gitea) --- .github/ISSUE_TEMPLATE/bug_report.yml | 77 ----------------------- .github/ISSUE_TEMPLATE/config.yml | 1 - .github/ISSUE_TEMPLATE/feature_request.md | 20 ------ .github/PULL_REQUEST_TEPMLATE.md | 28 --------- 4 files changed, 126 deletions(-) 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/PULL_REQUEST_TEPMLATE.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml deleted file mode 100644 index cb7b432..0000000 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ /dev/null @@ -1,77 +0,0 @@ -name: "Bug Report" -description: Create a report to help us improve this addon -labels: '🐛 Bug' -body: -- type: markdown - attributes: - value: | - Please search for existing issues before creating a new one. - -- type: textarea - attributes: - label: Description - description: What did you expect to happen and what happened instead? - validations: - required: true - -- type: dropdown - id: flavor - attributes: - label: Realm - description: What realm did this occur on? - options: - - Area 52 (Default) - - Seasonal - - Grizzly Hills - - Rexxar - - Other - validations: - required: true - -- type: checkboxes - id: testing - attributes: - label: Tested with only this addon - description: Did you try having just this addon as the only enabled addon and everything else disabled? - options: - - label: "Yes" - - label: "No" - validations: - 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`) - validations: - required: false - -- type: textarea - attributes: - label: Reproduction Steps - description: Please list out the steps to reproduce your bug. - 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 update did it stop working? If you don't know, when was the last date you were aware it was working - placeholder: "MM/DD/YYYY" - 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 \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index ec4bb38..0000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1 +0,0 @@ -blank_issues_enabled: false \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index bbcbbe7..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: '' -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/PULL_REQUEST_TEPMLATE.md b/.github/PULL_REQUEST_TEPMLATE.md deleted file mode 100644 index 30d2afa..0000000 --- a/.github/PULL_REQUEST_TEPMLATE.md +++ /dev/null @@ -1,28 +0,0 @@ -# Description - -Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. - -Fixes #(issue) - -## Type of change - -Please delete options that are not relevant. - -- [ ] Bug fix (non-breaking change which fixes an issue) -- [ ] New feature (non-breaking change which adds functionality) -- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - -## How Has This Been Tested - -Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration - -- [ ] Test A -- [ ] Test B - -## Checklist - - -- [ ] I have performed a self-review of my own code -- [ ] I have commented my code, particularly in hard-to-understand areas - - \ No newline at end of file From f43681df48f4070f5608373d50ed08750d6deeaf Mon Sep 17 00:00:00 2001 From: Florian Berthold Date: Mon, 25 May 2026 12:01:37 +0200 Subject: [PATCH 06/10] ci: add Gitea Actions release workflow (per-addon git-archive zip) --- .gitea/workflows/release.yml | 49 +++++++++++++++++++++++++++++ .gitignore | 3 +- tools/build_zip.sh | 60 ++++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 1 deletion(-) 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 44356e3..ec92999 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ .install .lua/* .vscode -.idea \ No newline at end of file +.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 f10996488034cfa5fea368a689b266b1e8d4e8be Mon Sep 17 00:00:00 2001 From: Florian Berthold Date: Mon, 25 May 2026 12:16:47 +0200 Subject: [PATCH 07/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 ef1003b4c9f6a9fe1fb2fef2ab4ca3554641f664 Mon Sep 17 00:00:00 2001 From: Florian Berthold Date: Fri, 29 May 2026 10:43:54 +0200 Subject: [PATCH 08/10] fix(options): use SetSelectedID so the text-size dropdown selection sticks --- ProfessionMenu/ProfessionMenuOptions.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ProfessionMenu/ProfessionMenuOptions.lua b/ProfessionMenu/ProfessionMenuOptions.lua index ba86347..2a3c2a6 100644 --- a/ProfessionMenu/ProfessionMenuOptions.lua +++ b/ProfessionMenu/ProfessionMenuOptions.lua @@ -150,8 +150,7 @@ PM:CreateOptionsUI() text = i; func = function() PM.db.txtSize = i - local thisID = UIDropDownMenu_GetSelectedID(ProfessionMenuOptions_TxtSizeMenu) - UIDropDownMenu_SetSelectedID(ProfessionMenuOptions_TxtSizeMenu, thisID) + UIDropDownMenu_SetSelectedID(ProfessionMenuOptions_TxtSizeMenu, i - 9) end; }; UIDropDownMenu_AddButton(info); From d8628016c30fe03f1bdc04081f3afc78d4144f3f Mon Sep 17 00:00:00 2001 From: Florian Berthold Date: Fri, 29 May 2026 20:51:17 +0200 Subject: [PATCH 09/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 9735343fed9e43e0fda94ac17ed9430f28de6b26 Mon Sep 17 00:00:00 2001 From: Florian Berthold Date: Wed, 10 Jun 2026 02:11:46 +0200 Subject: [PATCH 10/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.