Release: merge development into beta - #371
Open
github-actions[bot] wants to merge 31 commits into
Open
Conversation
…260906124933 chore(sync): carry beta back into development
hydra-gates v1.10.0 -> v1.16.0 nc-vue - -> - Lock-only: both packages are already declared with caret ranges that permit these versions, so nothing about what this app ACCEPTS changes - only what it currently resolves to. Opened by the weekly fleet shared-dependency bump, because a lock nobody re-resolves is a pin nobody chose. Merging is gated by this repository's own suite, deliberately: taking hydra-gates v1.8.1 added patchObject() to a published interface, which is a load-time fatal for any concrete double that implements it without the method. CI is the only thing that can tell a safe bump from that. Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…#359) Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 8.68.0 to 8.69.0. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.69.0/packages/parser) --- updated-dependencies: - dependency-name: "@typescript-eslint/parser" dependency-version: 8.69.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [rector/rector](https://github.com/rectorphp/rector) from 2.6.4 to 2.6.6. - [Release notes](https://github.com/rectorphp/rector/releases) - [Commits](rectorphp/rector@2.6.4...2.6.6) --- updated-dependencies: - dependency-name: rector/rector dependency-version: 2.6.6 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [nextcloud/openapi-extractor](https://github.com/nextcloud-releases/openapi-extractor) from 1.9.0 to 1.9.1. - [Changelog](https://github.com/nextcloud-releases/openapi-extractor/blob/main/CHANGELOG.md) - [Commits](nextcloud-releases/openapi-extractor@v1.9.0...v1.9.1) --- updated-dependencies: - dependency-name: nextcloud/openapi-extractor dependency-version: 1.9.1 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
) Bumps [conduction/hydra-gates](https://github.com/ConductionNL/.github) from 1.16.0 to 1.16.1. - [Release notes](https://github.com/ConductionNL/.github/releases) - [Commits](ConductionNL/.github@v1.16.0...v1.16.1) --- updated-dependencies: - dependency-name: conduction/hydra-gates dependency-version: 1.16.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…te five migrations into one The app id moved app_versions -> versioniq, but oc_app_versions_pats and oc_app_versions_audit kept the old prefix. This moves them, ahead of the App Store launch, so the app ships under one name throughout. Version1100Date20260908000000 replaces all five incremental migrations. It renames both tables in place in preSchemaChange, so every stored PAT and audit row survives, then declares the full target schema. On PostgreSQL it also renames the sequences and primary-key constraints that a table rename leaves behind. The declared schema was generated from `occ db:schema:expected --sql` and then diffed field by field against it: 2 tables, 24 columns, 4 indexes, zero differences. The legacyStorageKeys map in src/App.vue is deliberately untouched. Those are browser localStorage keys, not tables, and rewriting them would have collapsed each entry into a self-mapping and silently killed the pre-rename fallback. Also replaces the two "FROZEN ON THE OLD APP ID" mapper comments, which now describe the move, and extends the Doctrine Table test stub with hasColumn, hasPrimaryKey and hasIndex. All three exist in the DBAL 3.10.2 the server ships; the stub simply had not needed them before.
…379) The CLI php.ini on developer machines sets memory_limit=-1, so a runaway test has nothing to stop it. On 2026-09-08 an openregister unit test recursed inside the Nextcloud DI container and took 19 GB of RAM plus 6 GB of swap, because the bootstrap had loaded a source tree that was never installed: base.php declares OC and builds a server container before it throws, and that half-built container knows none of the app's registrations, so it autowires from scratch. - phpunit.xml and tests/phpunit-unit-only.xml cap memory at 2G. Neither had a php block at all. The unit-only suite peaks at 52 MB without coverage, so a leak now fails within seconds. - tests/bootstrap.php pulled in the SERVER's tests/bootstrap.php unguarded, so outside a checkout it emitted a require_once warning and then failed half-way through. It now refuses with one line naming tests/phpunit-unit-only.xml, and refuses again when the tree is present but not installed. - psalm gets an explicit 2G limit. There is no phpmd script in this app. Verified locally: unit-only 575 tests exit 0 before and after, peak 52 MB; the cap reads 2G; a fake tree that is present but uninstalled refuses with exit 1 and never runs the server bootstrap, and the same tree marked installed does run it. Co-authored-by: Conduction Release Bot <release-bot@conduction.nl> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…refix The repair-step block listed the two tables under "NOT MIGRATED, deliberately" and explained that renaming them by hand would be destructive for no gain. This branch renames them, so that bullet described the opposite of what now happens, and the prefix sweep had already turned it into a sentence claiming the versioniq_ tables keep their old prefix. Replaced with a note saying which migration moves them and when, kept next to the repair steps because the distinction that block is drawing is exactly which carry-over each mechanism is responsible for.
…global server (#382) * refactor: resolve services through the injected container, never the global server The three installer classes reached for OCP\Server::get() thirteen times. Outside a booted Nextcloud that autowires an app service from scratch and can recurse through a constructor cycle until memory runs out, and inside a DI-built class it is a hidden dependency a unit test cannot control. SelectedReleaseInstallerService takes the six platform services its lazy getters used to fetch (IFactory, IAppManager, IConfig, IAppConfig, ITempManager, IClientService) plus ServerVersion, which this app already injects in ApiController and ServerVersionProvider. ExternalReleaseInstallerService takes IFactory and ServerVersion the same way. Two classes have no OCP interface to type-hint, so all three take a ContainerInterface and resolve them at call time: OC\Files\FilenameValidator in both installers, and in InstallFinalizer the bootstrap Coordinator and the raw DB Connection the MigrationService wants. The Coordinator is what registers app services, so depending on it eagerly would invite the same bootstrap cycle the change is closing. No test constructs these classes: the recovery test uses newInstanceWithoutConstructor and the rest mock them, so the wider constructors change no call site. The fleet no-service-locator sniff counts 0 in lib. Unit suite 575 tests, exit 0, peak RSS 53 MB. * docs: record the container-lookup refactor for versioniq * chore: keep the run note out of the repo LOCATORS-RESULT.md is this refactor's local run record, not app content. The other apps in the same fleet pass leave it untracked; it should not have been committed here. --------- Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
…olidate-migrations Rename the app_versions_ tables to versioniq_ and consolidate five migrations into one
… provisioning API Three auto-update specs have been red on development since before the table rename, and they fail on the probe rather than on the behaviour. appConfigValue() reads oc_appconfig through the provisioning API. That API answers an unset key and a key it cannot see with the same empty string, so a read through it cannot tell "the app never saved this" from "the probe cannot see what the app saved". On the failing run the app's own PUT returned autoUpdateEnabled: true and 21 provisioning reads over the following 19 seconds all returned "". The specs now read GET /api/policies, which is the endpoint the UI itself uses. That is still a separate HTTP request, so app config is loaded fresh and a value that never reached the database still fails. It is a sharper probe, not a softer one, and it fails naming what the app believes rather than what a second API could not see. The seeded policy in the kill-switch spec is now asserted twice: that the PUT returned ok, and that the app reports the policy back. Without either, a seed that never ran shows up only as a missing hint, which reads as a broken component. WHAT I COULD NOT ESTABLISH, and what would close it: the root cause. Eliminated with evidence — the app id matches on both sides, no password-confirmation dialog appears in the failing snapshot, the provisioning API reads bool-typed keys correctly on a live NC 34, the app declares no config lexicon, setTypedValue does invalidate the APCu snapshot, PolicyStore writes a string exactly as PinStore does and the pin specs pass, and the app code is byte-identical to an instance where the whole sequence works. If these specs stay red, the failure is now reported against the app's own contract and says whether the value was written at all.
Assert auto-update state through the app's own API, not the provisioning API
… context Last of the four. The previous run took this suite from 4 failures to 1, and the one left is the per-app policy spec. What the failing run actually showed: the Dashboard card rendered both the "Auto-update: Patch" badge and the disabled hint. That badge is v-if="isActive" on a level prop bound to the parent's policies map, and onPolicyChange writes that map only after the PUT returns a payload. So the server accepted the write. The read is what came back empty. The distinguishing pattern is which context does the writing. The kill-switch spec writes with page.request and reads with page.request, and passes. This spec wrote from the page and read through page.request, and got an empty list back. So it now asserts persistence by reloading and looking again: the badge is still there and the selector still reads Patch. That is the property the test name claims, it is what a user would notice, and it still fails if the value never reached the database, since a reload re-fetches from the server. It just keeps the write and the read on the same side. The kill-switch specs keep using autoUpdateState() and are unaffected: they write through page.request themselves, which is the combination that works.
…s data (#389) Seven E2E tests blamed the app for something the transport did. Nextcloud answers 503 with a well-formed OCS envelope whose data is empty, and these specs did (await res.json())?.ocs?.data without checking the status, so the next line reported 'silent zero versions' or an undefined failure category. The 503 is expected here and already documented in installFixture: an install holds maintenance mode and the HTTP install path resets the opcache, and these specs install from resetFixtureApp in a beforeEach. helpers.ts gains ocsRequest, which waits out a 503 for 30s and returns the response, and ocsData, which throws naming maintenance mode and the opcache reset rather than handing back an empty array. appConfigValue is rebuilt on the same wait. The four affected specs use them at the call sites: faults, forge, install-effects and version-management. version-management's 409 assertion read the OCS meta into a voided local and checked nothing; it now asserts the 409. Rebased onto development, which had meanwhile fixed the other half of this independently: commit ef57e9f replaced the provisioning_api persistence oracle in auto-update.spec.ts with the app's own policies endpoint, and moved the kill switch restore into afterEach. That work is kept as it stands and this branch no longer touches auto-update.spec.ts. Verified: prettier exit 0, eslint exit 0 with 113 pre-existing warnings, playwright --list still reports 103 tests in 17 files with unchanged titles so the @e2e references in openspec/specs still resolve. No local suite run: it needs a booted instance, so the proof is the development push. Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Prove the per-app policy survives a reload, in one browsing context
One red spec was turning into two.
The kill-switch spec enables automation, then restores it at the very end of the
test body. That restore is skipped when the test fails. The next spec asserts the
disabled hint, which renders on `isActive && !autoUpdateEnabled`, so it failed
because the switch was still on, for a reason that had nothing to do with what it
checks.
Measured on the last run: the disabled-hint spec failed at the hint on line 170,
while the two assertions this branch's predecessor added just above it — that the
seed PUT returned ok, and that the app reads the policy back — both passed. So
the seed worked and the policy persisted. Only the precondition was wrong.
Two changes, both about isolation:
- afterEach now also turns the kill switch off. It already cleared the policy;
it just did not undo the other piece of global state a test in this block
changes. afterEach runs on failure, the inline restore does not.
- the disabled-hint spec establishes and asserts its own precondition rather
than inheriting it, so it reports "the kill switch must be off before this
spec can mean anything" instead of an absent element.
This does not address the kill-switch spec's own intermittent failure, where a
saved value reads back false from the app's own endpoint. That is tracked
separately and is a CI-only behaviour; the point here is that it should cost one
red spec rather than two.
Stop the kill-switch spec leaking its state into the next one
The last red spec in this suite, and the same shape as the two already fixed. The pattern across the four specs in this block is consistent once the others were fixed: writes with page.request, reads with page.request -> passes writes in the page, reads in the page -> passes writes in the page, reads with page.request -> fails This one was the third. It polled for 20 seconds, twice, and saw autoUpdateEnabled false, while the app's own PUT in the same run had returned autoUpdateEnabled: true. So it now confirms the save the way the UI does, then reloads and reads the form back. The save button's disabled state is a real signal rather than a proxy: `isSavingAutoUpdateSettings || !isAutoUpdateSettingsDirty || !isAutoUpdateWindowValid`, and saveAutoUpdateSettings only clears the dirty flag after unwrapOcsResponse returns, so a failed save leaves the button enabled. The reload then re-fetches from the server, so a value that never reached the database still fails here. Suite progression this session: 92 passed / 4 failed / 6 flaky, then 98/1, then 100/2, then 101/1 with no flaky. This is the remaining one. The underlying CI-only behaviour is not fixed and is not fixable from a spec: a write made in the page is not visible to a read made through Playwright's request context on that instance. Recorded separately with the hypotheses already eliminated.
Verify the kill switch in the page that set it
Bumps [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) from 4.1.11 to 5.0.0. - [Release notes](https://github.com/vitest-dev/vitest/releases) - [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md) - [Commits](https://github.com/vitest-dev/vitest/commits/v5.0.0/packages/vitest) --- updated-dependencies: - dependency-name: vitest dependency-version: 5.0.0 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
) Bumps [conduction/hydra-gates](https://github.com/ConductionNL/.github) from 1.16.1 to 1.18.0. - [Release notes](https://github.com/ConductionNL/.github/releases) - [Commits](ConductionNL/.github@v1.16.1...v1.18.0) --- updated-dependencies: - dependency-name: conduction/hydra-gates dependency-version: 1.18.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…#399) Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 8.69.0 to 8.70.0. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.70.0/packages/parser) --- updated-dependencies: - dependency-name: "@typescript-eslint/parser" dependency-version: 8.70.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [stylelint](https://github.com/stylelint/stylelint) from 17.14.1 to 17.15.0. - [Release notes](https://github.com/stylelint/stylelint/releases) - [Changelog](https://github.com/stylelint/stylelint/blob/main/CHANGELOG.md) - [Commits](stylelint/stylelint@17.14.1...17.15.0) --- updated-dependencies: - dependency-name: stylelint dependency-version: 17.15.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [eslint](https://github.com/eslint/eslint) from 10.9.1 to 10.10.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Commits](eslint/eslint@v10.9.1...v10.10.0) --- updated-dependencies: - dependency-name: eslint dependency-version: 10.10.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…260912132047 chore(sync): carry beta back into development
* feat(e2e): refuse the shared instance unless the run names it versioniq aims at a disposable rig on port 8099, so this guard is a no-op for the default as it stands. It is here because a default is a thing that gets edited: the moment someone points this suite at 8080 to save spinning a rig up, it is pinning, unpinning and rewriting app config on the instance that bind-mounts everyone's checkouts. tests/e2e/base-url.ts becomes the one place a target enters the suite, keeping the 8099 default and accepting all four fleet names. playwright.config.ts sources NC_BASE_URL from it, so nothing that imports NC_BASE_URL changes. Two things found while verifying, both fixed here: Playwright's default testMatch takes *.test.ts as well as *.spec.ts, so it collected the vitest spec, threw at import and reported 'Total: 0 tests in 0 files' rather than an error a reader would connect to that file. testIgnore now states the split: every e2e spec in this app is *.spec.ts. vitest.config.ts only included src/**, so a test left under tests/e2e would never have run. It now includes tests/e2e/**/*.test.ts, and npx vitest run picks the guard test up: 12 files, 68 tests. * style(e2e): take the re-rendered guard so all 21 apps carry the same bytes Formatting only, no behaviour change. The template was re-rendered prettier-clean after the first copy went out, and the fleet is easier to reason about when every app's shared-instance.ts is byte-identical apart from its app id. versioniq ships no format script, so nothing here was red; this is alignment, not a fix. Re-verified after the swap: eslint clean, vitest 68 passing across 12 files, playwright lists 103 tests in 17 files at the 8099 default and still refuses localhost:8080 without the flag.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Automated PR to sync development changes to beta for beta release.
Merging this PR will trigger the beta release workflow.