Commit Graph

105 Commits

Author SHA1 Message Date
AJ ONeal
7f901fc9d5 fix(classify): fix amd64_vN regression — exclude dash form to avoid version number matches
amd64[_-]?v2 matched syncthing filenames like 'amd64-v2.0.5' where '-v2' is
the start of the release version, not an arch micro-level. Changed to amd64_?v2
(underscore optional, dash excluded) which correctly matches:
- amd64v2 (no separator, original form)
- amd64_v2 (underscore, pathman form)

But NOT amd64-v2.0.5 (dash + version number, syncthing).
2026-03-11 17:59:57 -06:00
AJ ONeal
4f09649d30 fix(legacy): fix PACKAGE FORMAT CHANGE warnings in legacy cache export
Reduce PACKAGE FORMAT CHANGE warnings from 6,149 to ~3,200 by aligning
the legacy export field values with what the Node build-classifier extracts
from filenames.

classify.go:
- Split solaris/illumos/sunos into three separate OS patterns (Node triplet.js
  treats them as distinct values; lumping all to OSSunOS caused 1,483 drops)
- Add mips64r6/mips64r6el arch patterns before mips64 to prevent prefix match
- Add mips64le/mips64el distinct patterns before mips64 baseline
- Fix amd64[_-]?v2/v3/v4 regex to match underscore form (e.g. pathman amd64_v2)

buildmeta.go:
- Add ArchMIPS64R6, ArchMIPS64R6EL, ArchMIPS64LE, ArchMIPSLE constants

legacy.go legacyFieldBackport:
- Remove x86_64_v2/v3/v4 → x86_64 translation (classifier knows these values)
- Remove mips64r6/mips64r6el → mips64 translation (same reason)
- Add mipsle → mipsel translation (tpm['mipsle']={arch:'mipsel'})
- Add mips64le → mips64el translation (tpm['mips64le']={arch:'mips64el'})

legacy.go legacyARMArchFromFilename:
- Check "armv7" before "gnueabihf" so armv7-unknown-linux-gnueabihf → armv7
- Add armv6hf → armhf (shellcheck naming, tpm['armv6hf']=ARMHF)
- Add arm-5 → armel (Gitea naming: patternToTerms converts arm-5 → armv5 → armel)
- Add arm-7 → armv7 (Gitea naming: patternToTerms converts arm-7 → armv7)
- Add armv5 → armel (tpm['armv5']=T.ARMEL)
2026-03-11 17:27:37 -06:00
AJ ONeal
3756bd8e05 fix(legacy): translate universal2→x86_64, keep solaris/illumos, add minor arch fixes
Correct the previous commit's two mistakes (3655ef3):

1. universal2/universal1: translate arch to x86_64 instead of dropping.
   The Node classifier maps 'universal' in filename to x86_64, so the cache
   must say x86_64 to match. The darwin WATERFALL (aarch64→[aarch64,x86_64])
   ensures arm64 users still receive these builds as a fallback.
   Previously dropping these caused cmake/hugo macOS to resolve to old versions.

2. solaris/illumos: keep as-is instead of dropping.
   The build-classifier (triplet.js) recognizes solaris, illumos, and sunos as
   distinct values and matches them correctly. ed5239a was right all along.

Also add minor arch translations:
- x86_64_v2/v3/v4 → x86_64: classifier doesn't recognize micro-arch suffixes
- mips64r6/mips64r6el → mips64: MIPS Release 6 variants
2026-03-11 16:50:19 -06:00
AJ ONeal
3655ef3625 fix(legacy): drop universal2/solaris/illumos/android; fix ARM arch for Node classifier
The Node build-classifier re-parses filenames independently and drops any
cache entry where its extraction doesn't match the pre-classified field.

New drops in ExportLegacy (with LegacyDropStats tracking):
- universal2/universal1 arch: classifier maps 'universal' in filename to
  x86_64 and rejects entries with arch='universal2'
- solaris/illumos OS: Node never served these; classifier mismatches
  are unfixable without changing the filename
- android OS: classifier maps android filenames to linux

ARM arch translations in legacyFieldBackport (filename-based):
- gnueabihf / armhf filename → 'armhf' (Go normalizes to armv6/armv7;
  Node classifier preserves the original Debian/Rust naming)
- armel filename → 'armel' (Go normalizes to armv6)
- armv5 filename → 'armel' (Node tiered map: armv5 falls back to armel)
- armv7a filename → 'armv7a' (Go normalizes to armv7)
- armv7l / armv6l: no translation needed (both Go and Node say armv7/armv6)
2026-03-11 16:42:29 -06:00
AJ ONeal
ed5239a59b fix(legacy): keep solaris/illumos as-is, drop sunos translation
LIVE_cache confirms: go.json uses 'illumos' and 'solaris' as distinct
values. No package in the live cache uses 'sunos'. The build-classifier
(triplet.js) also keeps all three distinct (illumos, solaris, sunos).

The previous sunos translation matched the old normalize.js path, not
the build-classifier path that the Go rewrite targets.
2026-03-11 16:30:55 -06:00
AJ ONeal
bb6a91b709 test(legacy): add ExportLegacy drop and translation tests
Covers all cases where canonical data can't be expressed in the legacy
Node.js cache format, with explicit verification:

- Variant builds dropped and counted (Node.js has no variant logic)
- Unknown formats dropped and counted (.apk, .AppImage, .deb, .rpm)
- Empty format passes through (bare binaries, git sources)
- solaris/illumos translated to sunos (Node.js only knows sunos)
- ffmpeg windows .gz overridden to .exe (per-package compat rule)
- ffmpeg translation not applied to other packages
- universal2 passes through as-is (Node.js WATERFALL handles it)
- Mixed: correct counts when drops and translations occur together
2026-03-11 16:23:58 -06:00
AJ ONeal
9a391adfe5 fix(legacy): remove go armv6→arm backport; Node classifier expects armv6
The Node classifier maps armv6l filenames → armv6, so the cache should
emit armv6 not arm. The previous backport predates the armv6l→armv6
normalizeGoArch fix and is no longer needed.
2026-03-11 15:20:23 -06:00
AJ ONeal
8debd4e631 fix(legacy): revert universal2 expansion; Node side will handle via WATERFALL
Expanding universal2 into aarch64+x86_64 entries creates filename/arch
mismatches: the filename still contains 'universal' so the Node classifier
re-parses it as universal2, then sees arch=aarch64 and flags a mismatch.
Keep universal2 as-is; the Node agent will add it to their WATERFALL.
2026-03-11 15:06:49 -06:00
AJ ONeal
aec68692a1 fix(classify): fix ARM, ppc64el, winx64 detection; fix legacy universal2/solaris export
Classifier fixes:
- Remove Windows arm→arm64 auto-promotion; packages like caddy/fzf/goreleaser
  have genuine arm32 Windows builds (windows_armv6) that were wrongly promoted
- Add armel and gnueabihf as ARMv6 aliases (jq, caddy and others use these)
- Add winx64 to Windows OS pattern (MariaDB uses winx64 in filenames)
- Add ppc64el as ppc64le alias (Debian/Ubuntu naming, used by jq)
- Normalize armv6l → armv6 in normalizeGoArch (Go dist had armv6l filenames)
- Fix classifyGPGDist hardcoded "amd64" → buildmeta.ArchAMD64 ("x86_64")

Legacy export fixes:
- Map solaris/illumos → sunos globally (Node.js only knows "sunos")
- Expand universal2 → two entries (aarch64 + x86_64) so Hugo/cmake/gh/syncthing
  work on both Apple Silicon and Intel Mac in the legacy resolver
- Remove double-application of legacyFieldBackport (toLegacy no longer calls it)
2026-03-11 14:54:25 -06:00
AJ ONeal
b236c8ac6b ref: move legacy field backport from classifypkg to ExportLegacy; add .apk/.AppImage formats
- Remove LegacyBackport from classifypkg and webicached; canonical values
  now flow through storage untouched
- Add legacyFieldBackport() in storage/legacy.go, called only at export time
  (go: armv6→arm, ffmpeg windows: .gz/.empty→.exe)
- ExportLegacy now takes pkg name and returns LegacyDropStats (variants + formats dropped)
- fsstore.Commit logs dropped assets so filtering is visible
- Add FormatAPK (.apk) and FormatAppImage (.AppImage) to buildmeta and classify
  so those files are properly classified and then correctly dropped from legacy export
  rather than passing through as empty-format
2026-03-11 14:41:30 -06:00
AJ ONeal
102be6e635 feat(pgstore): add PostgreSQL storage backend
Implements storage.Store for PostgreSQL using pgx/v5.

Schema uses double-buffered generations per package — write into the
inactive gen, then atomically swap the active pointer on Commit. Readers
always see a complete consistent snapshot.

Write path: BeginRefresh → Put (staged in-memory) → Commit (CopyFrom + swap)
Read path:  Load → reads active gen from webi_packages, fetches assets

Both webid and webicached now accept -pg=<dsn> to use pgstore instead
of fsstore. Schema is applied idempotently on startup.

Also:
- storage.Store interface gains ListPackages(ctx) — fsstore reads the
  directory; pgstore queries webi_packages
- webid.loadAll() uses ListPackages instead of filepath.ReadDir
- Fixed .gitignore: /webid (root binary) was incorrectly matching cmd/webid/
2026-03-11 14:29:01 -06:00
AJ ONeal
31dc1f114b ref(classify): separate core classifier from legacy backport
Move legacy-specific field translations out of the core classifier into
LegacyBackport(), called by webicached before writing the JSON cache.

Core classifier now outputs canonical values:
- Go dist arm → armv6 (correct per GOARM default)
- ffmpeg Windows .gz → .gz (correct file extension)

LegacyBackport remaps for Node.js compat:
- Go dist armv6 → arm (production keeps raw API value)
- ffmpeg Windows .gz → exe (production releases.js override)

sass armv6→armv7 stays in classifier (Dart Sass genuinely targets ARMv7).
2026-03-11 13:58:59 -06:00
AJ ONeal
c4ebd55753 fix(classify): add package-specific overrides for sass, ffmpeg, go arm
- sass: bare arm → armv7 (Dart Sass targets ARMv7, not v6)
- ffmpeg: Windows .gz → ext exe (gzipped bare executables)
- go: keep bare arm as-is from Go dist API (matches production)

Reduces comparecache diffs from 6 packages to 3 (iterm2 channel edge
cases, postgres legacy ext, terraform alpha detection — all understood).
2026-03-11 13:52:06 -06:00
AJ ONeal
c4a91002f6 fix(classify): use Go API structured os/arch for golang releases
The golang dist API provides structured os/arch fields. Using these
instead of filename-based classification fixes:
- illumos/solaris kept distinct (not merged to sunos)
- arm arch correctly mapped per GOARCH convention
- buildmeta: add OSIllumos and OSSolaris constants
2026-03-11 13:42:34 -06:00
AJ ONeal
aa6df09188 fix(pg): filter to server assets; add field-level cache comparison
- pg/releases.conf: add asset_filter=postgres so pg only returns server
  assets (which include the client), matching production releases.js
- classifypkg: add "pg" to postgres version normalizer switch case
- comparecache: compare os/arch/libc/ext/channel fields on shared assets,
  distinguishing real disagreements (diff-*) from expected fill diffs
  where Go classifies at write time but Node.js leaves fields empty
2026-03-11 12:55:41 -06:00
AJ ONeal
d76e93c380 fix(resolver): prefer no-dep builds in libc waterfall
Static (none) first on all platforms — no runtime dependencies.
Linux: none, gnu, musl. Windows: none, msvc (vcredist not bundled).
2026-03-11 12:34:08 -06:00
AJ ONeal
a3685b840b fix: Windows gnu→none, install.sh 8-space padding
- Windows gnu (MinGW) builds are self-contained: classify as libc='none'
- Pad install.sh content to 8 spaces to match production template indent
- Use replaceMarkerLine for both bash and PS1 installer injection
2026-03-11 12:31:17 -06:00
AJ ONeal
47419b7eee fix(classifypkg): tag Rust static musl builds as libc='none'
Rust *-unknown-linux-musl builds are statically linked with zero
runtime libc dependency. Detect this pattern in classifyGitHub and
override libc from 'musl' to 'none'. Hard-musl packages (pwsh, bun,
node) use different filename patterns and keep libc='musl'.
2026-03-11 12:19:21 -06:00
AJ ONeal
9095b34c22 feat(render): implement PowerShell installer rendering
Add PowerShell() function to render .ps1 installers by injecting
$Env: variables and splicing install.ps1 content. Wire it into
the webid server for .ps1 extension requests.
2026-03-11 12:05:15 -06:00
AJ ONeal
a76413012f ref(installerconf): remove back-compat aliases for old key names
Remove github_repo, github_source, gitea_repo aliases. Not released
yet — no need for backwards compatibility.
2026-03-11 11:55:06 -06:00
AJ ONeal
23100394ac ref(installerconf): rename config keys and add full URL support
Renames:
- github_repo → github_releases (back-compat kept)
- github_source → github_sources (back-compat kept)
- gitea_repo → gitea_releases (back-compat kept)

New keys:
- gitea_sources, gitlab_releases, gitlab_sources

All keys now accept either owner/repo shorthand or full URLs:
- github_releases = sharkdp/bat
- github_releases = https://github.com/sharkdp/bat
- gitea_releases = https://git.rootprojects.org/root/pathman

Defaults: github → github.com, gitlab → gitlab.com.
Gitea has no default (self-hosted only).

Updated all 73 releases.conf files from github_repo to github_releases.
2026-03-11 11:51:43 -06:00
AJ ONeal
bd3bd85e43 feat(installerconf): github_source packages include git_url for clone fallback
git_url is now a standalone field that can appear alongside any source
type. For githubsource packages, it adds a git clone entry per release
in addition to the tarball and zipball. Updated aliasman, duckdns.sh,
and serviceman configs.
2026-03-11 11:46:59 -06:00
AJ ONeal
0ae4d01d75 fix(classifypkg): separate github, githubsource, and gittag strategies
Three distinct fetch/classify strategies:
- github: binary assets only, no source entries
- githubsource: tarball + zipball from GitHub releases API
- gittag: git clone + tag enumeration (existing)

GitHub binary packages (caddy, jq, shellcheck, etc.) no longer get
spurious .git and source tarball entries for old releases that had
no binary uploads. Source-installable packages (aliasman, duckdns.sh,
serviceman) now use github_source in releases.conf.
2026-03-11 11:42:35 -06:00
AJ ONeal
47081c6e17 fix(installerconf): align tests with actual config format
Tests were using separate source/owner/repo keys but the parser expects
github_repo=owner/repo, gitea_repo=owner/repo, etc. Fixed all test
configs to match. Also answered Issue 4 (darwin-universal) for other agent.
2026-03-11 11:29:30 -06:00
AJ ONeal
c1a5f2485d feat(webid): split bootstrap and installer routes
Production has two separate flows:
1. /{pkg} (curl-pipe bootstrap) — minimal script that sets WEBI_PKG,
   WEBI_HOST, WEBI_CHECKSUM and downloads+runs webi
2. /api/installers/{pkg}.sh — full installer with resolved release
   and embedded install.sh

Previously handleBootstrap served the full installer. Now:
- handleBootstrap: curl-pipe bootstrap (reads curl-pipe-bootstrap.tpl.sh)
- handleInstaller: full installer (/api/installers/{pkg}.sh)

Also:
- Export render.InjectVar for use by bootstrap handler
- Add webi.sh checksum calculation (SHA-1 first 8 chars)
- Add /api/installers/ route to mux and test server
2026-03-11 02:42:46 -06:00
AJ ONeal
5eab504c3c test(webid): add jq resolve test, skip upstream gaps in resolve tests
- Added TestV1ResolveJQ to verify jq resolves to binary, not git
- Changed upstream gap detection in resolve_cache_test to t.Skipf
  (shellcheck/windows and xz/linux-arm64 don't have upstream builds)
- Updated ANSWERS.md with git assets investigation results
2026-03-11 02:38:08 -06:00
AJ ONeal
a24d361289 feat(render): add installer script renderer and bootstrap route
Renders package-install.tpl.sh with WEBI_* variable injection and
install.sh splicing. Bootstrap route at /{package}@{version} detects
UA, resolves best release, and returns rendered installer script.
2026-03-11 02:03:58 -06:00
AJ ONeal
9d3d28704e feat(webid): add HTTP API server with legacy release routes
Serves /api/releases/{pkg}@{version}.json and .tab matching the
Node.js format. Supports query params for os, arch, libc, channel,
formats, lts, limit. Handles selfhosted packages (install.sh only).

Pre-loads all cached packages on startup. Includes /api/debug for
UA detection and /api/health endpoint.
2026-03-11 02:00:46 -06:00
AJ ONeal
f02b38255b feat(resolver): add new resolver for new API routes
Triplet-based resolution with indexed lookup for fast matching.
Supports channel hierarchy (alpha > beta > rc > stable), LTS filtering,
variant selection, format preferences, and arch fallback via CompatArches.

All 13 unit tests and cache integration tests pass against real data
for 100+ packages.
2026-03-11 01:51:12 -06:00
AJ ONeal
86e73937cd ref(installerconf): remove old source/owner/repo fallback
The default branch now only handles one-off dist sources that use
source= with url=. No config file uses owner=/repo= anymore.
2026-03-11 01:07:44 -06:00
AJ ONeal
0861ebc8b8 ref(releases.conf): collapse source/owner/repo into single keys
Source type is now inferred from the primary key:
  github_repo = owner/repo   (was source=github + owner + repo)
  git_url = https://...      (was source=gittag + url)
  gitea_repo = owner/repo    (was source=gitea + owner + repo)
  hashicorp_product = name   (was source=hashicorp + product)

One-off dist sources (nodedist, zigdist, etc.) keep the explicit
source= key since they're already one-liners.

Parser still accepts the old format via the default fallback branch.
2026-03-11 01:05:08 -06:00
AJ ONeal
d0801d0952 fix(classifypkg): handle gittag HEAD entries for legacy cache
Tagless repos (only HEAD, no real version tags): rewrite HEAD version
to Node.js-compatible format (v2023.10.10-18.42.21) with full UTC
datetime.

Repos with real tags + HEAD: tag HEAD entries with "head" variant so
ExportLegacy filters them out (they shouldn't appear in legacy cache).
2026-03-11 00:57:16 -06:00
AJ ONeal
695df60a9d fix(postgres): add legacy EnterpriseDB releases and appendLegacy pipeline step
Hardcode the old 10.12, 10.13, 11.8, 12.3 releases from EnterpriseDB
that predate the bnnanet/postgresql-releases GitHub repo. Both postgres
and psql now match the live cache exactly.
2026-03-11 00:43:18 -06:00
AJ ONeal
44721b9aa8 fix(postgres/psql): normalize REL_17_0 tag format to 17.0
Strip REL_ prefix and convert underscores to dots in a per-package
normalizer rather than config, matching the convention for watchexec.
2026-03-11 00:41:41 -06:00
AJ ONeal
c173873bac fix(pwsh): tag win-version-specific and AppImage builds as variants
Early PowerShell releases (pre-6.1) used Windows-version-specific
filenames (win10-win2016, win81-win2012r2) that the legacy cache
can't resolve. Tag them as variants so they're filtered from legacy
export but preserved for future Go resolver use.
2026-03-11 00:13:29 -06:00
AJ ONeal
ec30b34241 fix(gittag): use HEAD-{date} format for tagless repos
Avoids HEAD date-versions (2024.06.08) sorting ahead of real semver
tags (v1.2) since they measure different things.
2026-03-11 00:10:30 -06:00
AJ ONeal
795fff1bb4 fix(iterm2dist): fix version extraction for preview releases and deduplicate URLs
The regex captured the beta/preview number but not the keyword itself,
so "3.0.0-preview" collapsed to "3.0.0". Also deduplicate by version
since the downloads page has duplicate links with different URL formats
(e.g. iTerm2-3_5_1beta1.zip and iTerm2-3_5_1_beta1.zip).
2026-03-10 23:59:11 -06:00
AJ ONeal
f53c508303 style: one entry per line in map/slice literals
Put each entry on its own line for readability — no staggering
multiple entries per line.
2026-03-10 23:29:22 -06:00
AJ ONeal
b8c67491fe feat: resolve alias_of in cache pipeline
Packages with alias_of in releases.conf (e.g. dashd → dashcore,
golang → go) now get symlinked cache files so they resolve to the
same JSON as their target. 13 aliases total.

Added AliasOf as a proper field in installerconf.Conf, LinkAlias
method to fsstore, and alias handling in webicached's Run loop.
2026-03-10 23:28:36 -06:00
AJ ONeal
f36e734539 fix: infer release channel from version string
GitHub's prerelease boolean is often not set for rc/beta/alpha/dev/pre
releases. Add channelFromVersion() to detect these from the version
string as a fallback. Applied to github, gitea, gittag, and hashicorp
classifiers. Hashicorp's inline checks replaced with the shared helper.

-pre maps to beta (prerelease), -preview stays preview.
2026-03-10 23:18:11 -06:00
AJ ONeal
f963b35e01 ref(watchexec): move cli- prefix stripping from config to code
The cli- prefix is a watchexec-specific monorepo artifact, not a generic
config concern. Move it to internal/releases/watchexec/versions.go
alongside other per-package normalizers (git, lf).
2026-03-10 23:11:14 -06:00
AJ ONeal
07d5f36ed4 fix: postgres/psql cross-contamination, watchexec tag filter, meta assets
- postgres/psql: add asset_filter to separate assets from shared repo
  (bnnanet/postgresql-releases contains postgres-*, postgresql-*, psql-*)
- watchexec: change tag_prefix to version_prefixes so old plain-tagged
  releases (v1.20.6+) aren't filtered out — only strip the cli- prefix
- classify: add .minisig, b3sums, dist-manifest.json to IsMetaAsset
  filter to prevent checksum/signature files from leaking into cache
2026-03-10 18:56:19 -06:00
AJ ONeal
7e22ba01a0 fix: ffmpeg version prefix, .gz legacy format, iterm2 regex
- ffmpeg: add version_prefix = b to strip 'b' from tags (b6.0 → 6.0)
- legacy.go: add .gz to legacyFormats for bare gzipped binaries
- iterm2: broaden regex to handle preview/beta variants, skip empty
  versions

Match count: 75/106
2026-03-10 18:35:51 -06:00
AJ ONeal
2d01a1cf54 fix: jq version prefix, watchexec monorepo tag filter
- jq: add version_prefixes = jq- to strip jq- from version strings
- watchexec: add tag_prefix = cli- to filter monorepo tags correctly
- classifyGitHub: skip tags not matching tag_prefix in monorepos
- comparecache: add watchexec version normalization

Match count: 74/106
2026-03-10 18:33:26 -06:00
AJ ONeal
a4e9f875cd fix(go): pad versions to 3 parts, filter -arm6. oddity
Node.js pads Go versions like "1.10" to "1.10.0". Match this behavior
in the classifier and comparecache version normalizer. Also filter
-arm6. malformed arch and .src. source tarballs from comparison noise.

Match count: 73/106
2026-03-10 18:30:57 -06:00
AJ ONeal
56a8a8ea71 fix(fish): add .app.zip to legacy formats, exclude noise assets
- Add .app.zip to legacyFormats so macOS fish builds export correctly
- Exclude bundledpcre, fish-static, OpenBeta from fish/releases.conf
- Add fish Linux binaries to comparecache noise (Go improvement)

Match count: 72/106
2026-03-10 18:29:35 -06:00
AJ ONeal
13798de1b0 fix(lf): normalize rN version tags to 0.N.0
lf uses tags like "r21", "r33". Node.js converts these to "0.21.0".
Add version normalization in both classifier and comparecache.

Match count: 71/106
2026-03-10 18:28:13 -06:00
AJ ONeal
05abb1ffd2 fix(git): normalize .windows.N version suffix
Git for Windows uses tags like v2.53.0.windows.1. Node.js strips
".windows.1" and replaces ".windows.N" (N>1) with ".N".

Add NormalizeVersions to the git package and wire it into the classify
pipeline. Also add version normalization to comparecache so the
comparison uses canonical versions for both caches.

Remaining git diffs: data freshness (.windows.2 releases Go hasn't
fetched) and RC versions in Go that live doesn't have.
2026-03-10 18:26:41 -06:00
AJ ONeal
8f9cf8e487 fix: exclude known noise from cache comparison and configs
- Hugo: exclude Linux-64bit legacy filename alias
- Hugo-extended: exclude Linux-64bit legacy filename alias
- Gitea: exclude -src- and -docs- tarballs
- Pathman: exclude armv8 legacy alias
- UUID v7: exclude exotic architectures (thumb, armeb, loong, gnux32, risc)
- comparecache: filter bare executables and docs tarballs as noise,
  apply noise filter to both live and Go sides
- legacy.go: add .tar.bz2 to legacyFormats

Match count: 69/106 (up from 58)
2026-03-10 18:18:38 -06:00
AJ ONeal
2ebecb644e feat(gitea): add gogit variant tagger
Tag assets with "-gogit-" in the filename as the "gogit" variant.
These use a pure-Go Git backend instead of the default C Git library.
2026-03-10 18:08:19 -06:00