Compare commits
2 Commits
7e59aa8803
...
ai-fix/wge
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
acfa7ec0fa | ||
|
|
c30629aa8b |
@@ -254,38 +254,13 @@ without your involvement — another reason a shared checkout goes stale mid-tas
|
||||
**Reviewers**: CodeRabbit (deepest — often runs scripts to prove a claim; reviews ~9 minutes
|
||||
after the PR opens, or on `@coderabbitai review`), chatgpt-codex-connector, Copilot, Codacy.
|
||||
|
||||
**Codacy is red on essentially every add-on PR and gates nothing.** `gh pr checks` reports it as
|
||||
`fail` (older runs showed `action_required`); #3019, #3044 and #3050 all merged with it failing,
|
||||
and `master` carries no branch protection, so no check is required in the GitHub sense. It exposes
|
||||
no annotations via the API, so its findings are only visible in the maintainer's Codacy account.
|
||||
Note it and move on rather than guessing. `pr_review.sh watch` therefore prints it every poll but
|
||||
keeps it out of the verdict — the one check on that list, which is a denylist of known noise, not
|
||||
an allowlist of gates, so a job added to CI later counts as blocking until someone exempts it.
|
||||
**Codacy `action_required` is this repo's normal state.** Other open PRs show the same. It
|
||||
exposes no annotations via the API, so its findings are only visible in the maintainer's Codacy
|
||||
account. Note it and move on rather than guessing.
|
||||
|
||||
**Resolving a review thread requires GraphQL** (`resolveReviewThread`); the REST API cannot do it.
|
||||
`scripts/pr_review.sh` wraps fetch / reply / resolve.
|
||||
|
||||
**`gh pr checks` output is TAB-separated, and every blocking gate here has spaces in its name.**
|
||||
Parsing it with awk's default field splitting truncates each check to its first word and reads the
|
||||
wrong column as the state: `Codacy Static Code Analysis<TAB>fail` becomes `Codacy=Static`, and
|
||||
`Test addon build (wger)<TAB>pending` becomes `Test=addon`. A `case` over that string then matches
|
||||
neither `*fail*` nor `*pending*` and falls through to the "all passing" branch — the failure mode
|
||||
that makes a CI-reporting command lie. `pr_review.sh watch` called #3044 green while Codacy was
|
||||
red, and on #3042 printed "settled — all passing" while the HA add-on linter was failing; it would
|
||||
also have called a build that had not started a pass. Use `awk -F'\t'`, judge the state column
|
||||
alone (never the joined `name=state` text, or a check named `flaky-fail-detector` reads as a
|
||||
failure), and treat an unrecognised state as a failure instead of letting it reach the passing
|
||||
branch. Fixed in #3052.
|
||||
|
||||
The TSV is gh's *non-TTY* renderer, which is what `$(gh pr checks ... | awk)` always gets; attached
|
||||
to a terminal the same command prints a coloured, aligned table with a summary line, so never
|
||||
sanity-check the format by eye in a shell and assume the script sees that. `gh pr checks --json`
|
||||
would be sturdier, and Copilot recommends it (#3052), but it does not exist before gh 2.36 and the
|
||||
add-on ships 2.23 — it fails with `unknown flag: --json`. The parse is therefore built to fail
|
||||
safe instead: states are allowlisted, so a header row would land in the failure branch and a
|
||||
space-aligned table would parse to zero rows and keep `watch` waiting. Either way it cannot
|
||||
return a false pass.
|
||||
|
||||
**CHANGELOG heading dates are ISO, whatever the bots' defaults say.** Match the format already in
|
||||
the add-on's file. Repo-wide that is `## <version> (YYYY-MM-DD)`: 7705 dated headings against 363
|
||||
in `DD-MM-YYYY`, and the newest entry is ISO in 125 of 135 add-ons. Copilot flags an ISO file that
|
||||
|
||||
@@ -8,10 +8,6 @@
|
||||
# pr_review.sh resolve <PR> <THREAD_ID...|--all> --all = every unresolved, asks first
|
||||
# pr_review.sh watch <PR> [minutes] poll checks (run this backgrounded)
|
||||
#
|
||||
# watch exits 0 when every blocking check passed *or was skipped* — a PR touching no add-on
|
||||
# skips all three gates, and it says so — 1 on failure, 2 if it ran out of minutes. Codacy is
|
||||
# advisory here: printed every poll, excluded from the verdict.
|
||||
#
|
||||
# Reviewers seen here: coderabbitai (deepest; reviews ~9 min after open, or on
|
||||
# "@coderabbitai review"), chatgpt-codex-connector, Copilot, Codacy.
|
||||
#
|
||||
@@ -25,7 +21,7 @@ REPO="${HASSIO_REPO:-}"
|
||||
[ -z "$REPO" ] && { echo "cannot determine repo; set HASSIO_REPO=owner/name" >&2; exit 1; }
|
||||
echo "repo: $REPO" >&2
|
||||
CMD="${1:-}"; PR="${2:-}"
|
||||
[ -z "$CMD" ] || [ -z "$PR" ] && { sed -n '2,20p' "$0" | sed 's/^# \?//'; exit 1; }
|
||||
[ -z "$CMD" ] || [ -z "$PR" ] && { sed -n '2,16p' "$0" | sed 's/^# \?//'; exit 1; }
|
||||
|
||||
case "$CMD" in
|
||||
list)
|
||||
@@ -94,72 +90,25 @@ resolve)
|
||||
;;
|
||||
watch)
|
||||
MINS="${3:-180}" # the addon build alone has taken ~3h; 20 was far too short
|
||||
# Checks that are red on essentially every add-on PR here and gate nothing: master carries no
|
||||
# branch protection, and #3019, #3044 and #3050 all merged with Codacy failing. They are kept
|
||||
# out of the verdict but always printed, so the reader still sees them and can judge. This is
|
||||
# deliberately a denylist of known noise, not an allowlist of blocking checks — a job added to
|
||||
# CI later counts as blocking until someone puts it here on purpose.
|
||||
ADVISORY_CHECKS="Codacy Static Code Analysis" # one per line if more are ever added
|
||||
wfail=2 # not 0: running out of minutes with checks still pending is not a pass
|
||||
c=""; bstates=""; adv=""
|
||||
for i in $(seq 1 "$MINS"); do
|
||||
# gh pr checks emits TAB-separated columns with no header when its output is not a TTY,
|
||||
# which inside this $(... | awk) it never is. (Attached to a terminal it prints a wholly
|
||||
# different ANSI table; --json would be sturdier still but does not exist before gh 2.36,
|
||||
# and 2.23 ships here.) Every blocking gate has spaces in its name — "Addon linting
|
||||
# (wger)", "Test addon build (wger)" — so awk's default separator split them on
|
||||
# whitespace: "Codacy Static Code Analysis<TAB>fail" became "Codacy=Static" and the state
|
||||
# column was never read at all. watch printed "all passing" on a red #3044 and on #3042
|
||||
# with the linter failing, and could not see a pending build either.
|
||||
# If that format ever does change, the allowlist below fails safe rather than passing: a
|
||||
# header row lands in the failure branch, and a space-aligned table parses to no rows,
|
||||
# which keeps watch waiting instead of returning 0.
|
||||
rows=$(gh pr checks "$PR" 2> /dev/null | awk -F'\t' -v ADV="$ADVISORY_CHECKS" '
|
||||
BEGIN { n = split(ADV, a, "\n"); for (j = 1; j <= n; j++) adv[a[j]] = 1 }
|
||||
NF >= 2 { print (($1 in adv) ? "A" : "B") "\t" $1 "=" $2 "\t" $2 }')
|
||||
if [ -z "$rows" ]; then
|
||||
c=$(gh pr checks "$PR" 2> /dev/null | awk '{print $1"="$2}' | tr '\n' ' ')
|
||||
if [ -z "$c" ]; then
|
||||
# Normal in the first minutes after `gh pr create`, and also whenever gh errors.
|
||||
# Calling that "settled" would report success for checks that never ran.
|
||||
echo "[$i] no checks reported yet (gh returned nothing) — still waiting"
|
||||
sleep 60; continue
|
||||
fi
|
||||
c=$(printf '%s\n' "$rows" | cut -f2 | tr '\n' ' ')
|
||||
echo "[$i] $c"
|
||||
# Judge the state column only, never the joined name=state line: a check whose NAME
|
||||
# contains "fail" must not read as a failure.
|
||||
bstates=$(printf '%s\n' "$rows" | awk -F'\t' '$1 == "B" { print $3 }' | tr '\n' ' ')
|
||||
adv=$(printf '%s\n' "$rows" | awk -F'\t' '$1 == "A" { print $2 }' | tr '\n' ' ')
|
||||
if [ -z "$bstates" ]; then
|
||||
echo " only advisory checks have reported — no blocking check has run yet"
|
||||
sleep 60; continue
|
||||
fi
|
||||
# Allowlist the good states rather than denylisting the bad ones: an unrecognised state
|
||||
# must land in the failure branch, because falling through to "passing" is this command's
|
||||
# worst outcome.
|
||||
nbad=0; npend=0
|
||||
for s in $bstates; do
|
||||
case "$s" in
|
||||
pass | skipping) ;;
|
||||
pending) npend=$((npend + 1)) ;;
|
||||
*) nbad=$((nbad + 1)) ;;
|
||||
esac
|
||||
done
|
||||
if [ "$nbad" -gt 0 ]; then
|
||||
echo "settled — blocking checks FAILED:"
|
||||
printf '%s\n' "$rows" |
|
||||
awk -F'\t' '$1 == "B" && $3 != "pass" && $3 != "skipping" && $3 != "pending" { print " " $2 }'
|
||||
wfail=1; break
|
||||
elif [ "$npend" -gt 0 ]; then
|
||||
sleep 60; continue
|
||||
else
|
||||
echo "settled — blocking checks passing"; wfail=0; break
|
||||
fi
|
||||
case "$c" in
|
||||
*pending*) sleep 60 ;;
|
||||
*fail* | *error* | *cancel*) echo "settled — with FAILURES (see above)"; wfail=1; break ;;
|
||||
*) echo "settled — all passing"; wfail=0; break ;;
|
||||
esac
|
||||
done
|
||||
[ "$wfail" -eq 2 ] && echo "gave up after ${MINS}m, checks still unsettled — NOT a pass"
|
||||
# Printed on pass and on failure alike: it is excluded from the verdict, not hidden.
|
||||
[ -n "$adv" ] && echo " advisory (non-blocking, not counted in the verdict): $adv"
|
||||
# A PR touching no */config.* skips the CHANGELOG, linter and build jobs outright (#3018).
|
||||
case " $bstates " in *" skipping "*) echo " ...of which some were SKIPPED — a skipped job tested nothing" ;; esac
|
||||
case "${c:-}" in *skipping*) echo " ...of which some were SKIPPED — a skipped job tested nothing" ;; esac
|
||||
echo "note: long queues here are usually account runner contention, not your diff."
|
||||
exit "$wfail"
|
||||
;;
|
||||
|
||||
6
.github/stargazer_countries.csv
vendored
@@ -418,7 +418,6 @@ KuchenKavalier,,2026-08-10
|
||||
KuerbisK,,2026-08-10
|
||||
Kvasenok,,2026-08-10
|
||||
KyleGolfer,,2026-08-10
|
||||
L00PERY,,2026-09-06
|
||||
L0rdShrek,Germany,
|
||||
L1nKinc,Germany,
|
||||
LaLaBer,,2026-08-10
|
||||
@@ -445,7 +444,6 @@ LoginByCall,,2026-08-10
|
||||
Lolekpolek,,2026-08-10
|
||||
LonelySoul7X,,2026-08-10
|
||||
Loong-He,China,2026-08-30
|
||||
Loong-OvO,China,2026-09-06
|
||||
Lorsel,Italy,
|
||||
Luca2165801154,,2026-08-10
|
||||
Lucius-Waverly,,2026-08-16
|
||||
@@ -1392,7 +1390,6 @@ flostingapplesauce,,2026-08-10
|
||||
flozi00,Germany,
|
||||
flue17,,2026-08-10
|
||||
fmcglinn,Australia,
|
||||
foodstampou812,United States,2026-09-06
|
||||
forming,,2026-08-10
|
||||
forreggbor,Hungary,
|
||||
foundbobby,United States,
|
||||
@@ -1837,7 +1834,6 @@ m1kethai,Canada,
|
||||
m23l,,2026-08-10
|
||||
m2sh,"Iran, Islamic Republic of",
|
||||
m4rcSA,,2026-08-10
|
||||
m4rkolson,United States,2026-09-06
|
||||
mProwler,United States,
|
||||
mStrangers,,2026-08-10
|
||||
mabt,,2026-08-10
|
||||
@@ -2089,7 +2085,6 @@ p0wertiger,Poland,
|
||||
paalwilliams,Germany,
|
||||
pace6666,,2026-08-10
|
||||
pafnow,France,
|
||||
pahanitsch,Germany,2026-09-06
|
||||
pandabreads,,2026-08-10
|
||||
pankaj151,India,
|
||||
papafrank66,,2026-08-10
|
||||
@@ -2669,7 +2664,6 @@ yycsdm,,2026-08-10
|
||||
yyll2233,,2026-08-10
|
||||
z2833,,2026-08-10
|
||||
z307917424,,2026-08-10
|
||||
zacharee,Panama,2026-09-06
|
||||
zachgilliam,United States,
|
||||
zanyraspi,,2026-08-10
|
||||
zdaar,,2026-08-10
|
||||
|
||||
|
BIN
.github/stargazer_map.png
vendored
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 64 KiB |
BIN
.github/stats.png
vendored
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 3.9 KiB |
BIN
.github/stats_addons.png
vendored
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 10 KiB |
2
.github/workflows/daily_ai_fix.yaml
vendored
@@ -125,7 +125,7 @@ jobs:
|
||||
|
||||
- name: Analyse and fix
|
||||
if: steps.batch.outputs.count != '0'
|
||||
uses: anthropics/claude-code-action@d75b94d5ad426cb8546e6628b6f5f19b84e5cce1 # v1
|
||||
uses: anthropics/claude-code-action@a874e9ecd7bb36efdad65429c6b35815f5a08f10 # v1
|
||||
with:
|
||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||
# Skip the OIDC -> Claude App token exchange. The scheduled path
|
||||
|
||||
2
.github/workflows/on_claude_mention.yml
vendored
@@ -64,7 +64,7 @@ jobs:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Run Claude Code
|
||||
uses: anthropics/claude-code-action@d75b94d5ad426cb8546e6628b6f5f19b84e5cce1 # v1
|
||||
uses: anthropics/claude-code-action@a874e9ecd7bb36efdad65429c6b35815f5a08f10 # v1
|
||||
with:
|
||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||
# AI_PR_TOKEN, not GITHUB_TOKEN, so a PR Claude opens triggers CI.
|
||||
|
||||
2
.github/workflows/on_issue_approved.yaml
vendored
@@ -135,7 +135,7 @@ jobs:
|
||||
|
||||
- name: Execute the plan
|
||||
if: steps.bundle.outputs.has_plan == 'true'
|
||||
uses: anthropics/claude-code-action@d75b94d5ad426cb8546e6628b6f5f19b84e5cce1 # v1
|
||||
uses: anthropics/claude-code-action@a874e9ecd7bb36efdad65429c6b35815f5a08f10 # v1
|
||||
with:
|
||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||
# Skip the OIDC -> Claude App token exchange, which 401s whenever
|
||||
|
||||
2
.github/workflows/on_issues_ai_triage.yaml
vendored
@@ -166,7 +166,7 @@ jobs:
|
||||
id: classify
|
||||
if: github.event_name != 'issue_comment' || steps.claim.outputs.go == 'true'
|
||||
continue-on-error: true
|
||||
uses: anthropics/claude-code-action@d75b94d5ad426cb8546e6628b6f5f19b84e5cce1 # v1
|
||||
uses: anthropics/claude-code-action@a874e9ecd7bb36efdad65429c6b35815f5a08f10 # v1
|
||||
with:
|
||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||
# Without this the action falls back to the OIDC -> Claude App token
|
||||
|
||||
2
.github/workflows/on_pr_coderabbit.yml
vendored
@@ -79,7 +79,7 @@ jobs:
|
||||
|
||||
- name: Address CodeRabbit comments
|
||||
if: steps.claim.outputs.go == 'true'
|
||||
uses: anthropics/claude-code-action@d75b94d5ad426cb8546e6628b6f5f19b84e5cce1 # v1
|
||||
uses: anthropics/claude-code-action@a874e9ecd7bb36efdad65429c6b35815f5a08f10 # v1
|
||||
with:
|
||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||
# Skip the OIDC -> Claude App token exchange, which 401s whenever
|
||||
|
||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 2.6 KiB |
BIN
aurral/stats.png
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 3.2 KiB |
BIN
baikal/stats.png
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 3.1 KiB |
BIN
bazarr/stats.png
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 4.1 KiB |
@@ -1,19 +1,3 @@
|
||||
## 20260909.4 (09-09-2026)
|
||||
- Minor bugs fixed
|
||||
## 20260909.3 (09-09-2026)
|
||||
- Minor bugs fixed
|
||||
## 20260909.2 (09-09-2026)
|
||||
- Minor bugs fixed
|
||||
## 20260909 (09-09-2026)
|
||||
- Minor bugs fixed
|
||||
## 20260908.2 (08-09-2026)
|
||||
- Minor bugs fixed
|
||||
## 20260908.1 (08-09-2026)
|
||||
- Synced with upstream birdnet-go (4 commits); re-merges the open fork PRs, adding fork PR #62 (reanalyze a clip with every loaded model + one-click correction)
|
||||
## 20260908 (08-09-2026)
|
||||
- Synced with upstream birdnet-go (7 commits); re-merges the open fork PRs
|
||||
## 20260907 (07-09-2026)
|
||||
- Rebuild: re-merges the open fork PRs, picking up the updated fork PR #57
|
||||
## 20260901.4 (01-09-2026)
|
||||
- Minor bugs fixed
|
||||
## 20260901.3 (01-09-2026)
|
||||
|
||||
@@ -127,5 +127,5 @@ slug: birdnet-go-dev
|
||||
udev: true
|
||||
url: https://github.com/alexbelgium/hassio-addons
|
||||
usb: true
|
||||
version: "20260909.4"
|
||||
version: "20260901.4"
|
||||
video: true
|
||||
|
||||
@@ -11,15 +11,6 @@
|
||||
# stamping) is written to the directory given as $1 so the Docker build can
|
||||
# compile it.
|
||||
#
|
||||
# With --check the script does not build anything: it performs the exact same
|
||||
# merge sequence, skips (instead of failing on) every conflicting PR, and prints
|
||||
# one "!!! CONFLICT pr=#N conflicts-with=... files=... " line per offender before
|
||||
# exiting 2. Use it to find conflicts *before* a build burns on them. This is a
|
||||
# different question from GitHub's `mergeable` field, which compares a PR against
|
||||
# its own base ref - for a stacked PR that base is another feature branch (often
|
||||
# stale, sometimes belonging to a closed PR), so GitHub can report CLEAN for a PR
|
||||
# that does not merge onto main at all.
|
||||
#
|
||||
# Environment:
|
||||
# BIRDNET_FORK owner/repo of the fork (default alexbelgium/birdnet-go)
|
||||
# BIRDNET_UPSTREAM owner/repo of the upstream (default tphakala/birdnet-go)
|
||||
@@ -28,26 +19,7 @@
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
CHECK_ONLY="${MERGE_PRS_CHECK:-0}"
|
||||
TARGET_DIR=""
|
||||
while [ "$#" -gt 0 ]; do
|
||||
case "$1" in
|
||||
--check) CHECK_ONLY=1 ;;
|
||||
-*) echo "unknown option: $1" >&2; exit 64 ;;
|
||||
*)
|
||||
# Last-one-wins would silently clone into the wrong directory if a caller ever
|
||||
# appended an argument; the pre-flag script used "${1}", so refuse rather than
|
||||
# quietly change which operand counts.
|
||||
if [ -n "${TARGET_DIR}" ]; then
|
||||
echo "usage: merge-prs.sh [--check] <target-dir>" >&2
|
||||
exit 64
|
||||
fi
|
||||
TARGET_DIR="$1"
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
: "${TARGET_DIR:?usage: merge-prs.sh [--check] <target-dir>}"
|
||||
TARGET_DIR="${1:?usage: merge-prs.sh <target-dir>}"
|
||||
|
||||
FORK="${BIRDNET_FORK:-alexbelgium/birdnet-go}"
|
||||
UPSTREAM="${BIRDNET_UPSTREAM:-tphakala/birdnet-go}"
|
||||
@@ -61,52 +33,6 @@ GH_TOKEN="${GH_TOKEN:-${GITHUB_TOKEN:-}}"
|
||||
|
||||
log() { echo ">>> $*"; }
|
||||
|
||||
# Conflicting PRs collected in --check mode: "number|scope|files|title".
|
||||
conflicting=()
|
||||
|
||||
LOCKFILE="frontend/package-lock.json"
|
||||
|
||||
# The single place that decides whether a conflicted merge is still acceptable.
|
||||
# package-lock.json is generated content and stacked PRs can carry an older copy even when
|
||||
# their source changes merge cleanly, so keep the lockfile already assembled on the base side
|
||||
# — but only when it is the sole conflict. Any source conflict stays fatal.
|
||||
# Returns 0 when it resolved and committed such a merge, 1 when the conflict is real.
|
||||
# BOTH the real merge and the --check probe must go through here: when only the real merge
|
||||
# applied the policy, the probe called a PR "conflicts-with=main" that the build would have
|
||||
# merged fine, and printed the opposite remediation to the true one.
|
||||
resolve_sole_lockfile() {
|
||||
local dir="$1"
|
||||
local -a conflicted
|
||||
mapfile -t conflicted < <(git -C "${dir}" diff --name-only --diff-filter=U)
|
||||
if [ "${#conflicted[@]}" -ne 1 ] || [ "${conflicted[0]}" != "${LOCKFILE}" ]; then
|
||||
return 1
|
||||
fi
|
||||
log "Resolving generated ${LOCKFILE} conflict using the base tree"
|
||||
git -C "${dir}" checkout --ours -- "${LOCKFILE}" || return 1
|
||||
git -C "${dir}" add "${LOCKFILE}" || return 1
|
||||
git -C "${dir}" commit --no-edit > /dev/null || return 1
|
||||
}
|
||||
|
||||
# Does ${1} merge cleanly onto the pristine upstream-synced main? Probed in a
|
||||
# throwaway worktree so the accumulated tree is left untouched. Tells apart a PR
|
||||
# that is simply stale against main (fixable inside that PR's own branch) from
|
||||
# one that only clashes with another open PR (needs a cross-PR decision).
|
||||
merges_onto_main() {
|
||||
local sha="$1" tmpdir probe rc=0
|
||||
tmpdir="$(mktemp -d)"
|
||||
probe="${tmpdir}/probe"
|
||||
git worktree add --quiet --detach "${probe}" "${MAIN_SYNCED}"
|
||||
if ! git -C "${probe}" merge --no-edit --no-ff -m probe "${sha}" > /dev/null 2>&1; then
|
||||
# Same policy as the real merge, or this misclassifies a lockfile-only clash.
|
||||
resolve_sole_lockfile "${probe}" > /dev/null 2>&1 || rc=1
|
||||
fi
|
||||
git worktree remove --force "${probe}" > /dev/null 2>&1 || true
|
||||
# worktree remove only takes the child back; without this the mktemp parent is left behind
|
||||
# on every checked conflict.
|
||||
rmdir "${tmpdir}" > /dev/null 2>&1 || true
|
||||
return "${rc}"
|
||||
}
|
||||
|
||||
git config --global user.email "addon-builder@users.noreply.github.com"
|
||||
git config --global user.name "BirdNET-Go Addon Builder"
|
||||
git config --global advice.detachedHead false
|
||||
@@ -121,7 +47,6 @@ git remote add upstream "${UPSTREAM_URL}"
|
||||
git fetch --no-tags upstream main
|
||||
# --no-ff keeps an explicit sync commit; a no-op when main is already current.
|
||||
git merge --no-edit --no-ff upstream/main
|
||||
MAIN_SYNCED="$(git rev-parse HEAD)"
|
||||
|
||||
log "Querying open non-draft PRs from ${FORK}"
|
||||
auth_header=()
|
||||
@@ -154,43 +79,27 @@ for entry in "${prs[@]}"; do
|
||||
if ! git merge --no-edit --no-ff -m "Merge PR #${number}: ${title}" "${sha}"; then
|
||||
mapfile -t conflicted_files < <(git diff --name-only --diff-filter=U)
|
||||
|
||||
if resolve_sole_lockfile .; then
|
||||
: # generated lockfile only - the merge is committed and the build continues
|
||||
# package-lock.json is generated content and stacked PRs can carry an
|
||||
# older copy even when their source changes merge cleanly. Keep the
|
||||
# lockfile already assembled from upstream and earlier PRs, but only
|
||||
# when it is the sole conflict. Any source conflict remains fatal.
|
||||
if [ "${#conflicted_files[@]}" -eq 1 ] \
|
||||
&& [ "${conflicted_files[0]}" = "frontend/package-lock.json" ]; then
|
||||
log "Resolving generated frontend/package-lock.json conflict using the accumulated tree"
|
||||
git checkout --ours -- frontend/package-lock.json
|
||||
git add frontend/package-lock.json
|
||||
git commit --no-edit
|
||||
else
|
||||
echo "!!! Merge conflict while merging PR #${number} (${title})." >&2
|
||||
if [ "${#conflicted_files[@]}" -gt 0 ]; then
|
||||
printf '!!! Conflicting file: %s\n' "${conflicted_files[@]}" >&2
|
||||
fi
|
||||
git merge --abort || true
|
||||
|
||||
if [ "${CHECK_ONLY}" = "1" ]; then
|
||||
scope="accumulated"
|
||||
merges_onto_main "${sha}" || scope="main"
|
||||
conflicting+=("${number}|${scope}|${conflicted_files[*]:-}|${title}")
|
||||
log "check mode: skipping PR #${number}, continuing with the rest"
|
||||
continue
|
||||
fi
|
||||
|
||||
echo "!!! Resolve the conflict in the fork or pause this PR, then rebuild." >&2
|
||||
git merge --abort || true
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "${CHECK_ONLY}" = "1" ]; then
|
||||
if [ "${#conflicting[@]}" -eq 0 ]; then
|
||||
log "CHECK OK: every open non-draft PR merges into the combined build tree"
|
||||
exit 0
|
||||
fi
|
||||
echo "!!! CHECK FAILED: ${#conflicting[@]} PR(s) would break the add-on build" >&2
|
||||
for entry in "${conflicting[@]}"; do
|
||||
IFS='|' read -r number scope files title <<<"${entry}"
|
||||
echo "!!! CONFLICT pr=#${number} conflicts-with=${scope} files=${files} title=${title}" >&2
|
||||
done
|
||||
echo "!!! conflicts-with=main -> the PR is stale against main; merge main into its branch and resolve there." >&2
|
||||
echo "!!! conflicts-with=accumulated -> the PR only clashes with another open PR; decide which one owns the hunk." >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
log "Merged HEAD: $(git rev-parse --short HEAD)"
|
||||
log "Source tree ready at ${TARGET_DIR}"
|
||||
|
||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 2.9 KiB |
BIN
codex/stats.png
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 3.5 KiB |
BIN
emby/stats.png
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 3.5 KiB |
BIN
ente/stats.png
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 3.4 KiB |
BIN
gitea/stats.png
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 2.8 KiB |
BIN
grav/stats.png
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 3.4 KiB |
BIN
immich/stats.png
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 3.1 KiB |
BIN
inadyn/stats.png
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 2.7 KiB |
BIN
joal/stats.png
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 3.4 KiB |
BIN
joplin/stats.png
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 3.4 KiB |
BIN
kometa/stats.png
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 3.0 KiB |
BIN
komga/stats.png
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 3.2 KiB |
BIN
lidarr/stats.png
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 2.6 KiB |
@@ -1,8 +1,4 @@
|
||||
|
||||
## v3.25.1 (2026-09-05)
|
||||
- Update to latest version from mealie-recipes/mealie (changelog : https://github.com/mealie-recipes/mealie/releases)
|
||||
- Build the ingress frontend with pnpm and the upstream lockfile: upstream dropped frontend/yarn.lock in v3.24.0, so the previous yarn install resolved dependencies unpinned and the build broke on a vuetify release without "vuetify/labs/rules"
|
||||
|
||||
## v3.24.0 (2026-08-29)
|
||||
- Update to latest version from mealie-recipes/mealie (changelog : https://github.com/mealie-recipes/mealie/releases)
|
||||
|
||||
|
||||
@@ -15,30 +15,24 @@
|
||||
#################
|
||||
|
||||
# Stage 1: Build Frontend with SUB_PATH
|
||||
# Mirrors upstream docker/Dockerfile: node:24 + pnpm, installing from the
|
||||
# committed pnpm-lock.yaml. Upstream dropped frontend/yarn.lock in v3.24.0, so a
|
||||
# yarn install here resolved every dependency fresh and eventually picked a
|
||||
# vuetify release without "vuetify/labs/rules", breaking "nuxt generate".
|
||||
FROM node:24 AS frontend-builder
|
||||
FROM node:22 AS frontend-builder
|
||||
|
||||
# Set the SUB_PATH environment variable
|
||||
ARG SUB_PATH="/mealie/"
|
||||
ENV SUB_PATH=$SUB_PATH
|
||||
|
||||
ENV MEALIE_VERSION="v3.25.1"
|
||||
|
||||
RUN npm install --global pnpm@11
|
||||
ENV MEALIE_VERSION="v3.24.0"
|
||||
|
||||
# Clone the Mealie repository to get the frontend source code
|
||||
WORKDIR /frontend
|
||||
# hadolint ignore=DL3003
|
||||
RUN mkdir -p /frontend/tempdir && cd /frontend/tempdir && \
|
||||
git clone --depth 1 --branch "$MEALIE_VERSION" https://github.com/mealie-recipes/mealie.git . && \
|
||||
cp -a frontend/. /frontend/ && cd /frontend && rm -rf tempdir && \
|
||||
pnpm install --frozen-lockfile
|
||||
git clone --branch "$MEALIE_VERSION" https://github.com/mealie-recipes/mealie.git . && \
|
||||
cp -rf frontend/* /frontend && cd /frontend && rm -rf tempdir && \
|
||||
yarn install --prefer-offline --frozen-lockfile --non-interactive --production=false --network-timeout 1000000
|
||||
|
||||
# Build the frontend
|
||||
RUN pnpm generate
|
||||
RUN yarn generate
|
||||
|
||||
# Stage 2: Build the Final Image
|
||||
FROM hkotel/mealie:latest
|
||||
|
||||
@@ -114,4 +114,4 @@ schema:
|
||||
slug: mealie
|
||||
udev: true
|
||||
url: https://github.com/alexbelgium/hassio-addons
|
||||
version: "v3.25.1"
|
||||
version: "v3.24.0"
|
||||
|
||||
BIN
mealie/stats.png
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 3.2 KiB |
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"github_beta": "true",
|
||||
"github_fulltag": "true",
|
||||
"last_update": "2026-09-05",
|
||||
"last_update": "2026-08-29",
|
||||
"paused": "false",
|
||||
"repository": "alexbelgium/hassio-addons",
|
||||
"slug": "mealie",
|
||||
"source": "github",
|
||||
"upstream_repo": "mealie-recipes/mealie",
|
||||
"upstream_version": "v3.25.1"
|
||||
"upstream_version": "v3.24.0"
|
||||
}
|
||||
|
||||
BIN
monica/stats.png
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 3.1 KiB |
BIN
mylar3/stats.png
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 2.9 KiB |
BIN
nzbget/stats.png
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 2.6 KiB |
@@ -1,6 +1,3 @@
|
||||
## 0.6.1.1 (2026-09-07)
|
||||
- Fix the add-on refusing to stop: Home Assistant reported an Error status after a few seconds and the container kept running and serving the web UI. `cont-init.d/99-run.sh` started nginx in the foreground, and `ha_entrypoint.sh` runs every cont-init script in the foreground, so the entrypoint never reached the point where it installs the `terminate()` handler that forwards SIGTERM to the application on shutdown. The application is now started in the background, and `init: false` makes the entrypoint run as PID 1 so the orphaned process is reparented to it and receives that signal. Closes #3049.
|
||||
|
||||
|
||||
## 0.6.1 (2025-11-18)
|
||||
- Added `env_vars` option to allow passing custom environment variables from the add-on configuration.
|
||||
|
||||
@@ -5,7 +5,6 @@ description:
|
||||
Self-hosted collection of powerful web-based tools for everyday tasks.
|
||||
No ads, no tracking, just fast, accessible utilities right from your browser
|
||||
image: ghcr.io/alexbelgium/omni-tools-{arch}
|
||||
init: false
|
||||
map:
|
||||
- addon_config:rw
|
||||
name: Omni Tools
|
||||
@@ -21,5 +20,5 @@ schema:
|
||||
value: str?
|
||||
slug: omni-tools
|
||||
url: https://github.com/alexbelgium/hassio-addons
|
||||
version: 0.6.1.1
|
||||
version: 0.6.1
|
||||
webui: "[PROTO:ssl]://[HOST]:[PORT:80]"
|
||||
|
||||
@@ -7,10 +7,4 @@
|
||||
|
||||
# Start omni-tools container content
|
||||
bashio::log.info "Starting application"
|
||||
# Backgrounded on purpose. ha_entrypoint.sh runs every cont-init.d script in the
|
||||
# foreground, so launching nginx here in the foreground never lets it reach the
|
||||
# terminate() handler that forwards SIGTERM on shutdown -- the add-on then could
|
||||
# not be stopped at all (#3049). Backgrounded, this script returns, nginx is
|
||||
# reparented to the entrypoint as PID 1, and terminate() signals it directly.
|
||||
# Requires init: false in config.yaml, which is what makes the entrypoint PID 1.
|
||||
/./docker-entrypoint.sh nginx -g "daemon off;" &> /proc/1/fd/1 &
|
||||
/./docker-entrypoint.sh nginx -g "daemon off;" &> /proc/1/fd/1
|
||||
|
||||
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 3.3 KiB |