Compare commits

...

10 commits

Author SHA1 Message Date
9735343fed ci(release): sync release.yml from coa-template
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).
2026-06-10 02:11:46 +02:00
d8628016c3 ci(release): hide auto-generated source archives (hide_archive_links) 2026-05-29 20:51:17 +02:00
ef1003b4c9 fix(options): use SetSelectedID so the text-size dropdown selection sticks
All checks were successful
release / release (push) Successful in 2s
2026-05-29 10:43:54 +02:00
f109964880 ci: respect GITHUB_REPOSITORY + tolerate per-asset upload failures
All checks were successful
release / release (push) Successful in 2s
2026-05-25 12:16:47 +02:00
f43681df48 ci: add Gitea Actions release workflow (per-addon git-archive zip) 2026-05-25 12:01:37 +02:00
769a9ee042 chore: remove .github/ (upstream templates, not relevant on Gitea) 2026-05-25 11:02:49 +02:00
aa9a4919c9 chore: align with Exiles fork-layout convention (standard .gitignore + .gitattributes) 2026-05-25 10:59:31 +02:00
3ed0021c7b 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.
2026-05-24 19:31:44 +02:00
6ef1f9dab8 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.
2026-05-24 17:40:22 +02:00
6d099f6db1 chore(libs): bump LibDataBroker-1.1 to v4 (from canonical) 2026-05-24 17:08:21 +02:00
13 changed files with 221 additions and 149 deletions

3
.gitattributes vendored
View file

@ -1,2 +1 @@
# Auto detect text files and perform LF normalization
* text=auto
* -text

View file

@ -0,0 +1,75 @@
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
# 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).
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,hide_archive_links:true}')" \
| 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.
failed=0
uploaded=0
for f in dist/*.zip; do
name=$(basename "$f")
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 ]

View file

@ -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

View file

@ -1 +0,0 @@
blank_issues_enabled: false

View file

@ -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.

View file

@ -1,28 +0,0 @@
# Description
Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context.
<!-- A #issueNumber will be sufficient. -->
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
<!-- These can be checked off after the pull request is submitted, in case you want discussion before they are completely ready -->
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
<!-- Is there any additional work that needs to be done? If so, add it to the above list -->

3
.gitignore vendored
View file

@ -4,4 +4,5 @@
.install
.lua/*
.vscode
.idea
.idea
dist/

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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()

View file

@ -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,10 +148,9 @@ PM:CreateOptionsUI()
for i = 10, 25 do
info = {
text = i;
func = function()
PM.db.txtSize = i
local thisID = this:GetID();
UIDropDownMenu_SetSelectedID(ProfessionMenuOptions_TxtSizeMenu, thisID)
func = function()
PM.db.txtSize = i
UIDropDownMenu_SetSelectedID(ProfessionMenuOptions_TxtSizeMenu, i - 9)
end;
};
UIDropDownMenu_AddButton(info);

71
tools/build_zip.sh Executable file
View file

@ -0,0 +1,71 @@
#!/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 <repo>-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"
# 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.
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 <folder>/... 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