Skip to content

chore(release): sync beta back into development - #295

Closed
github-actions[bot] wants to merge 18 commits into
developmentfrom
sync/beta-to-development-1.4.4-beta.20260830165931
Closed

chore(release): sync beta back into development#295
github-actions[bot] wants to merge 18 commits into
developmentfrom
sync/beta-to-development-1.4.4-beta.20260830165931

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

Opened by the release workflow after publishing 1.4.4-beta.20260830165931 from beta.

A release commits a version bump onto the branch it ran from. Without carrying
that back, development falls behind beta, and since both branches then
changed the version file independently, the next development -> beta
promotion conflicts on it — every time.

Version files are resolved to development's side, the higher line, so this
cannot move a version backwards. Any other conflict stops the workflow instead
of being resolved automatically.

Merge this, do not squash. A squash copies the files and discards the
relationship: the merge base would not move and the next promotion would
conflict exactly as before. A 0-file diff here is normal and is not a no-op —
recording the ancestry is the whole point.

rubenvdlinde and others added 18 commits May 29, 2026 08:04
… Gitea)

Extends the source-binding model with a third `SourceInterface`
implementation that talks to a Gitea-family release API rooted at
`https://{host}/api/v1/repos/{owner}/{repo}/releases`. The canonical
consumer is Codeberg, but the driver is instance-agnostic and works
for any self-hosted Gitea or Forgejo instance.

The concrete motivation is unblocking canary testing of OpenCatalogi
dev builds: those releases are intentionally published to Codeberg
WITHOUT going through the Nextcloud App Store, so App Versions today
has no way to see them. This PR closes that gap.

Wiring:
- new SourceBinding::KIND_GITEA_RELEASE ("gitea-release") + gitea()
  factory + `gitea:host/owner/repo` identifier shape + getHostOwnerRepo()
- new GiteaReleaseSource driver — mirrors GithubReleaseSource but with
  host as a first-class binding field and no PAT support in this cut
  (public read only; see CHANGELOG for rationale)
- SourceRegistry: registers the new driver, adds it to listAvailable(),
  parseSourceId() accepts `gitea:host/owner/repo`
- TrustedSourceList: extractIdentifier() now recognises both
  `github:owner/repo` and `gitea:host/owner/repo`; default allowlist
  gains `codeberg.org/Conduction/*` alongside the existing
  `ConductionNL/*`
- ApiController::bindSource(): new `gitea-release` match arm accepting
  host/owner/repo/assetPattern

Tests:
- 10 new tests in GiteaReleaseSourceTest covering listVersions
  (sorting, dedup, draft skipping, prerelease inclusion, 404/403/
  network/JSON errors) + resolveRelease (asset match, multi-match,
  unknown version)
- SourceBindingTest: 5 new tests for the gitea factory, roundtrip,
  and validation of host/owner/repo
- SourceRegistryTest: 3 new tests for gitea parseSourceId + rejection
  of missing host / empty segments
- TrustedSourceListTest: 5 new tests for the codeberg.org default,
  host-scoped custom globs, and malformed gitea source-id rejection

Result: 114 tests / 266 assertions, all green.

Bumps app version 1.0.1 → 1.1.0 (minor: additive new feature).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…t hygiene

F1 (blocker) — InstallerService::resolveBinding was gating
assertBindingAllowed() on `kind === KIND_GITHUB_RELEASE` at two spots
(lines 335 and 344), silently disabling the allowlist for the new
KIND_GITEA_RELEASE on the read path. `bindSource()` (write path) was
already unconditional, but `sourceOverride` on the read side and
already-stored gitea bindings both bypassed the trust list — which
broke TrustedSourceList's documented contract for the exact security
control this PR extended.

Fix: drop the kind gate entirely, always call assertBindingAllowed().
The primitive short-circuits appstore internally via extractIdentifier()
returning null, so unconditional invocation is safe and future-proof
against new source kinds.

Regression suite: new tests/unit/Service/Source/InstallerServiceBindingGuardTest
uses ReflectionMethod to exercise the private resolveBinding across 6
scenarios: untrusted gitea + github overrides both throw; trusted
gitea override passes; stored untrusted gitea binding is rejected on
read; stored trusted gitea binding is accepted; appstore fallback
skips the guard.

Non-blocking follow-ups from the same review:

F2 — Doc-comment on the `limit=50` cap in GiteaReleaseSource::fetchReleases
explaining that Gitea/Forgejo caps `limit` at 50 for /releases where
GitHub allows 100 via `per_page`, and that a repo with >50 releases
would truncate here (Nextcloud apps ship <20 in practice).

F3 — CHANGELOG [1.1.0] gets its release date (2026-07-09) per
Keep-a-Changelog convention.

F4 — New test `testEndpointUrlIsBuiltFromBindingHost` uses
$client->expects->with->stringContains to lock in three properties of
the built endpoint: `https://` scheme, host propagation from the
binding, and `/api/v1/repos/…/releases` path prefix.

F5 — SourceInterface::resolveRelease docstring updated to document
the gitea-release payload shape alongside App Store and GitHub.

F6 — Inline comments in listVersions() and resolveRelease() explain
why we filter `draft: true` where GithubReleaseSource doesn't
(GitHub hides drafts server-side to anonymous consumers; some Gitea/
Forgejo versions surface them, so defensive parity with the release-
page UI).

Suite: 121 tests / 283 assertions, all green (was 114 / 266).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…odeberg, self-hosted Gitea)' (#21) from feat/gitea-release-source into main

Reviewed-on: https://codeberg.org/Conduction/app-versions/pulls/21
Four coordinated documentation additions after the 1.1.0 release
introduced the gitea-release source kind — the API surface, the
tutorial content, and the README landing page were still on the
template stubs from initial scaffolding.

Changes:

- **README.md** — replaced the template stub ("A template to get
  started with Nextcloud app development") with a product-oriented
  README describing what App Versions does, the three source kinds
  (`appstore`, `github-release`, `gitea-release`) side by side with
  their identifier shapes and default allowlist patterns, quickstart
  install + UI walkthrough, API summary with common calls, and
  pointers to the OpenAPI spec and admin tutorials.

- **openapi.json** — regenerated via `composer openapi` from the
  current `#[ApiRoute]` attributes. Previously the file only shipped
  a single placeholder ("An example API endpoint"); it now documents
  all 12 real endpoints including `POST /api/source/{appId}/bind`
  with the new `gitea-release` kind, `GET /api/app/{appId}/versions`,
  the install endpoint, PAT management, and discovery. Generator
  reported 41 PHPDoc-completeness warnings (pre-existing debt on
  Api#patchPat, listPats, discover, patDeeplink — all lacking
  @return / description); addressing those is a separate concern,
  the routes themselves are correctly generated.

- **docs/tutorials/admin/02-bind-alternate-source.md** — new
  step-by-step admin tutorial. Covers when to use an alternate
  source (per-push dev builds, private repos, forks), a comparison
  table of the three source kinds, five walkthrough steps (verify
  trust allowlist, find the source identifier, POST the bind, verify
  in the UI, install a version), the exact curl/PowerShell one-liners
  with expected JSON responses, and a common-issues table covering
  the mistakes we hit while shipping this (HTTP 404 on wrong URL
  prefix — OCS routes live under /ocs/v2.php/... — HTTP 403 on trust
  list, cross-app class-not-found on upgrade).

- **CHANGELOG.md** — new `[Unreleased]` section pointing to all three
  additions above.

Motivation: shipping the gitea-release source without documenting
how to use it is only half a feature. The tutorial's worked example
(bind opencatalogi to codeberg.org/Conduction/opencatalogi, install
a dev-release) matches the exact WOO-493 canary flow we ran through
manually the same day.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…he fallback

Ordering-only change to signal to admins that Codeberg is the current
canonical Conduction release channel (post ConductionNL → Codeberg
org migration). No source kind was removed and no trust pattern was
dropped, so existing bindings and custom allowlists keep working.

Changes:

- **SourceRegistry::listAvailable()** — picker order is now App Store
  → Gitea → GitHub. The Gitea entry's label is updated to "Codeberg /
  Gitea / Forgejo Releases (recommended)"; GitHub's label is
  simplified to "GitHub Releases" (was "GitHub Releases (public)" —
  the "(public)" qualifier confusingly implied private wasn't
  supported, which was never the case).

- **TrustedSourceList::DEFAULT_PATTERNS** — reordered so
  codeberg.org/Conduction/* is first and ConductionNL/* second.
  Ordering is cosmetic for fnmatch (all patterns are still evaluated)
  but signals intent in `occ config:app:get app_versions
  trusted_sources` output and in the tutorial.

- **README.md** — Supported-sources table reordered to match:
  App Store → gitea-release (recommended) → github-release.

- **docs/tutorials/admin/02-bind-alternate-source.md** — three tables
  reordered (source-kinds overview, bind fields, default trust
  patterns) with a short paragraph explaining why: "For Conduction
  apps, gitea-release pointed at codeberg.org/Conduction/<app> is the
  recommended default — that's the source of truth after the
  ConductionNL GitHub → Codeberg migration. github-release is
  retained for apps that still publish releases to GitHub."

- **CHANGELOG.md** — new `Changed` entry under `[Unreleased]`.

Tests: 121/283 unchanged (order isn't asserted anywhere).

Stacked on top of PR #23 (docs) — the docs tables live in that branch,
this PR reorders them; if #23 merges first, this rebases cleanly onto
main, if this merges first #23 auto-updates.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… alternate, GitHub the fallback' (#24) from feat/codeberg-first-defaults into docs/api-and-onboarding

Reviewed-on: https://codeberg.org/Conduction/app-versions/pulls/24
Adds an admin-only UI affordance to switch an installed app's release
source between App Store, Codeberg/Gitea, and GitHub without leaving the
picker — the /api/source/{appId}/bind endpoint was already there since
PR #21 but had no frontend.

**Info panel (per selected app)**

- New "Version source" card showing the current binding label, e.g.
  `Codeberg / Gitea (codeberg.org/Conduction/opencatalogi)`.
- Four buttons: App Store · Codeberg · GitHub · Advanced… — active
  binding gets a highlight (Codeberg quick-switch has a blue accent to
  signal "recommended" per PR #24).
- Codeberg quick-switch posts `{host:codeberg.org, owner:Conduction,
  repo:{appId}}`; GitHub quick-switch posts `{owner:ConductionNL,
  repo:{appId}}`; both use assetPattern `*.tar.gz`.

**Advanced dialog (NcDialog)**

- Full form for overrides: source kind, host (Gitea only), owner, repo,
  assetPattern. Pre-populates from the current binding when one exists;
  otherwise defaults to Codeberg + {appId}.
- Inline validation hint + error surface for the bind response.

**Wiring**

- New helpers: loadSources, loadCurrentBinding, submitBind,
  quickBindCodeberg / quickBindGithub / quickBindAppStore.
- Honors PasswordConfirmationRequired via the existing
  ensurePasswordConfirmation helper.
- On successful bind, re-runs checkVersions so the picker immediately
  reflects the new source.

**Notes**

- Pure frontend change — no PHP or spec changes; the /bind route was
  already fully documented in openapi.json and the admin tutorial added
  in PR #23.
- Backwards-compatible: if /api/source/{appId}/binding returns null
  (never bound), the UI shows "Nextcloud App Store" and the App Store
  quick-switch button as active.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…kind dropdown

Follow-up on the source-binding UI now that #23 (docs) and #24 (Codeberg-first
ordering) are merged into main. Three coordinated updates:

**Dialog options now driven by /api/sources**

- `bindKindOptions` computed reads from `availableSources` (populated by
  `loadSources()` on mount from `GET /api/sources`).
- Labels + ordering therefore inherit from `SourceRegistry::listAvailable()`
  so the "(recommended)" suffix on Gitea introduced by #24 appears without
  the frontend hardcoding it.
- Hardcoded three-option list retained as a fallback for when `/api/sources`
  fails (network hiccup, forbidden, etc.), with ordering matching #24.

**Bind-alternate-source tutorial (docs/tutorials/admin/02-…)**

- New "Which path — UI or API?" section immediately after "When to use
  this" — both routes hit the same endpoint; pick whichever fits.
- Step 3 gains two subsections: "Path A — via the UI" (quick-switch
  buttons + Advanced… dialog) and "Path B — via the OCS API" (the
  existing curl / PowerShell examples, unchanged).
- Step 4 (Verify in the UI) split by path — Path A needs no refresh, Path
  B calls out the hard-refresh + relabels the confirmation string to
  match the new card copy.
- Sidebar description + Goal step 3 updated to acknowledge both paths.

**README.md**

- "What it does" bullet on non-App-Store binding gains a one-liner
  pointing at the Version source card and the OCS endpoint side by
  side.
- Quickstart step 3 rewritten: the UI is now the primary suggestion,
  with the tutorial linked for the automation/CI path.

**CHANGELOG.md** — new "In-app source-binding UI" entry under
[Unreleased] Added; the tutorial entry gets a trailing sentence noting
the step-3 side-by-side rewrite.

No PHP or spec changes; pure follow-up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bumps appinfo/info.xml from 1.1.0 → 1.2.0 and closes the
CHANGELOG [Unreleased] block into a [1.2.0] - 2026-07-10
section.

1.2.0 is a semver minor — additive-only:

- **Added** In-app source-binding UI (this PR).
- **Added** Admin tutorial + product README + full OpenAPI spec (#23).
- **Changed** Codeberg/Gitea is now the recommended alternate source
  order in `SourceRegistry::listAvailable()` + `TrustedSourceList`
  defaults (#24) — ordering-only, no source kind or trust pattern
  removed.

No breaking API changes; existing bindings, custom trust allowlists,
and installed apps are unaffected.

The tutorial text already reads "ships a first-class UI for source
binding as of 1.2.0" — this bump makes that statement true.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… / GitHub quick buttons' (#25) from feat/source-binding-ui into main

Reviewed-on: https://codeberg.org/Conduction/app-versions/pulls/25
Inhoud exact Codeberg-main (tree ongewijzigd); banner-commit alleen als
ancestor zodat de push fast-forward is. Migratie 16-07.
Release: merge development into beta
main held 15 commit(s) beta did not. Merged with -s ours: beta's
tree is kept BYTE FOR BYTE and only the ancestry is recorded, so the
beta -> main promotion stops conflicting on files where beta is simply
newer.

Not brought over -- beta is hundreds of commits ahead of main, so these
are the OLDER copies, and several are dead Forgejo/Codeberg CI that
development deliberately removed:

  .forgejo/workflows/release-stable.yml CHANGELOG.md README.md appinfo/info.xml docs/tutorials/admin/02-bind-alternate-source.md lib/Controller/ApiController.php lib/Service/InstallerService.php lib/Service/Source/GiteaReleaseSource.php lib/Service/Source/SourceBinding.php lib/Service/Source/SourceInterface.php lib/Service/Source/SourceRegistry.php lib/Service/Source/TrustedSourceList.php openapi.json src/App.vue tests/unit/Service/Source/GiteaReleaseSourceTest.php tests/unit/Service/Source/InstallerServiceBindingGuardTest.php tests/unit/Service/Source/SourceBindingTest.php tests/unit/Service/Source/SourceRegistryTest.php tests/unit/Service/Source/TrustedSourceListTest.php
The 1.4.4-beta.20260830165931 release bumped the version on beta. Without this,
development stays behind beta and the next development -> beta promotion
conflicts on the version file.

Version files resolve to development's side, which is the higher line,
so this never moves a version backwards.
@rubenvdlinde

Copy link
Copy Markdown
Contributor

Superseded. fleet-back-merge.yml could not merge these while it waited for green on branches red for unrelated reasons, so one accumulated per run (107 open across the fleet). ConductionNL/.github#648 removed that wait, and the sweep that followed carried and merged the same ancestry immediately. This pull request changes zero files, so closing it loses nothing: the ancestry it recorded is already on the branch.

@rubenvdlinde
rubenvdlinde deleted the sync/beta-to-development-1.4.4-beta.20260830165931 branch August 30, 2026 17:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants