Skip to content

Release: merge development into beta - #22

Open
github-actions[bot] wants to merge 296 commits into
betafrom
development
Open

Release: merge development into beta#22
github-actions[bot] wants to merge 296 commits into
betafrom
development

Conversation

@github-actions

@github-actions github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Automated PR to sync development changes to beta for beta release.

Merging this PR will trigger the beta release workflow.

Reminder: Add a major, minor, or patch label to this PR to control the version bump. Default is patch.

SudoThijn and others added 30 commits June 30, 2026 17:34
Replace the unassociated standalone <label> in CreateGroupDashboardModal
and TileEditor with CnIconBrowser's :label prop, and drop the now-dead
.tile-editor__label rule.

Note: in inline mode the library still renders the label's for= against
the popup-only trigger id, so full programmatic association needs a
follow-up fix in @conduction/nextcloud-vue.
- ICON_CATALOGUE: assert frozen array and { key, label, value, search,
  path } entry shape
- TileEditor: cover onIcon iconType derivation (svg vs url) and the
  isUrlIcon computed
- OrgNavigationItem: cover the CnDashboardIcon SVG-path branch and the
  legacy-name -> path resolution, alongside the existing URL-icon test
…owser into development

Reviewed-on: https://codeberg.org/Conduction/launchpad/pulls/123
Reviewed-by: WilcoLouwerse <wilcolouwerse@noreply.codeberg.org>
The Conduction and Sendent default tiles hardcoded
/apps/launchpad/img/<logo>.png. That URL only resolves when the app is
mounted under the default apps directory; on instances serving launchpad
from a secondary apps path (e.g. custom_apps) the logos 404 and render
broken.

Inject IURLGenerator and resolve the logo paths via imagePath('launchpad',
...) so they carry the app's real web prefix regardless of install
location. Falls back to the app-relative path when no generator is wired
(unit-test construction).
Standardizes the strict gate onto the canonical php:8.3-cli + node20 version
(fixes the 404 ci-php image where present); validated on the pilot apps.
Fix 8 phpcs errors surfaced by the newly-enforced strict gate:
- phpcbf autofix (blank line after control structure, long-condition
  closing comment) in DashboardService
- named-parameter calls to appImagePath() (CustomSniffs NamedParameters)
- replace disallowed inline-if ternaries with if/else in
  DashboardApiController::getActive() and WidgetPlacement::jsonSerialize()
- capitalise inline comment in WidgetPlacement
launchpad was the last v1-shaped manifest in the fleet (2026-07-06
manifest audit, item 3): unpkg @latest v1 $schema, v1 top-level
widgets[], '@runtime' string sentinels where v2 wants arrays, null
register/schema on an index page, and a _note-less custom page.

Migrated by hand (the manifest-migrate codemod cannot express these
shapes):
- $schema -> pinned Codeberg v2 URL; version 0.1.0 -> 0.2.0
- dashboard-detail: empty page-level widgets[] + _note documenting the
  ADR-036 Decision-8 runtime-manifest stub role (the real per-user
  pages come from GET /apps/launchpad/api/manifest)
- admin-templates-index: type index (null register/schema) -> type
  custom with component TemplatesPage + _note (no OR register backs
  this data, so the declarative index contract cannot apply)
- admin-settings: _note added
- v1 top-level widgets[] block removed; the spend-analytics widget is
  registered in the JS registry, and its data contract lives in
  openspec/specs/launchpad-spend-analytics-widget
- observability block (ADR-040) unchanged

Validates against both the hydra-vendored canonical schema (gate-22
PASS) and current nextcloud-vue (manifest-migrate --validate-only:
Valid (v2 schema)).
…2 (gate-22 green)' (#127) from feat/manifest-v2 into development
Fleet audit item 21: stale nc-vue pin. Bumps ^1.0.0-beta.143 -> ^1.0.0-beta.155,
which bundles manifest schema 2.13.0 (top-level runtime key) plus the
sideEffects/precompiled-validator perf fixes. Verified: installed schema
2.13.0, npm run build green, check_manifest.js gate exit 0.

First half of the fix for #129: the bundled schema now accepts the
top-level runtime key; the remaining blocker is the widget-entry shape
(widgetId -> widgetKey), tracked in #129.
…ta.155 (audit item 21)' (#130) from chore/nc-vue-pin-155 into development
- website/bugs/repository/documentation github -> codeberg
- drop github-only <discussion> (no codeberg equivalent)
- point <screenshot> at real in-repo screenshots

Part of fleet-wide App Store audit 2026-07-07.
Replace SPDX-License-Identifier AGPL-3.0-or-later with EUPL-1.2 across all
LaunchPad-authored source (lib/ PHP, src/ Vue/JS, appinfo/info.xml docblock),
and normalise SPDX-FileCopyrightText from "LaunchPad Contributors" to
"2024 Conduction B.V. <info@conduction.nl>" to match REUSE.toml, composer.json,
publiccode.yml and the PHPDoc @copyright/@license. Leaves the info.xml
<licence>agpl</licence> app-store token unchanged (documented fleet convention).

Fix README licence badge AGPL-3.0 -> EUPL-1.2 to match README §License prose.
Add scripts/check-license-headers.sh regression guard (composer lint:licenses,
wired into check:strict) that fails the build if an AGPL-3.0 SPDX identifier
returns, naming the offending file.

Archives openspec change align-source-license-headers-to-eupl.
… (apply fix-group-dashboard-admin-auth-attribute)
…ompulsory widgets

Adds an acknowledgement read-gate on compulsory dashboard widgets with per-user
read receipts and an admin read-receipt report. Local-first (ADR-049 widgets-as-config),
no OpenRegister install dependency. Includes Acknowledgement entity/mapper/migration,
AcknowledgementService + Controller, AcknowledgementPrompt + report modal, activity
integration, PHPUnit + vitest + e2e specs, EN/NL i18n.
…ad rename

The "LaunchPad" menu tile opened OpenBuild: the nav <route> was
mydash.page.index, which never resolved (NC registers the app under its
folder name "launchpad") and fell through to OpenBuild's dashboard
catch-all route. The frontend also called /apps/mydash/api/manifest (404).

- appinfo/info.xml: nav route mydash.page.index → launchpad.page.index;
  <id> mydash → launchpad
- backend: route names (launchpad.kiosk.render, launchpad.publicShare.show),
  log contexts, and the two straggler occ commands (launchpad:storage:*)
- frontend: i18n domain t('launchpad'), loadState, and /apps/launchpad URLs
  across 36 files; rebrand two user-visible "MyDash" strings to "LaunchPad"
- add src/publicPath.js (generateFilePath) imported first in main.js/admin.js
  so dynamically-imported chunks load from the served js dir — fixes
  "Refused to execute script (MIME text/html)" on launchpad-cn-manifest-validator.js
- add PublicShareContext::isBearer() getter (test expected it)
- reconcile kiosk/demo-showcase unit test assertions to the launchpad app id

DB tables (oc_mydash_*), migrations, and cache prefixes are intentionally
left as mydash_ — they are the physical schema created by already-run
migrations.
…ed js dir

Dynamically-imported chunks (e.g. launchpad-cn-manifest-validator.js) were
requested from /apps/launchpad/js/ — a path Nextcloud answers with the
app-shell HTML — because webpack's default 'auto' publicPath does not match
where NC serves the app's JS (e.g. /custom_apps/launchpad/js/ in a dev
checkout). Result: "Refused to execute script (MIME type text/html)" and the
chunk never loads.

Add src/publicPath.js which sets __webpack_public_path__ via
generateFilePath('launchpad', 'js', ''), resolved against NC's per-app web
root (OC.appswebroots) so it is correct for both apps/ and custom_apps/
layouts. Imported first in main.js and admin.js so it runs before any lazy
import(). Verified live: validator chunk → 200 text/javascript, 0 console
errors.
# Conflicts:
#	appinfo/info.xml
#	docs/migration/widget-library-to-ncvue.md
#	lib/Service/DashboardService.php
#	lib/Service/PublicShareContext.php
#	src/components/Dashboard/__tests__/IconPicker.spec.js
#	src/components/Widgets/Renderers/CalendarWidget.vue
#	src/components/Widgets/Renderers/FilesWidget.vue
#	src/components/Widgets/Renderers/LinkButtonWidget.vue
#	src/components/Widgets/Renderers/NewsWidget.vue
#	src/components/Widgets/Renderers/PeopleWidget.vue
#	src/components/Widgets/Renderers/__tests__/FilesWidget.spec.js
#	src/components/Widgets/VisibilityRulesModal.vue
#	src/components/Widgets/WidgetContextMenu.vue
#	src/components/admin/AdminDemoData.vue
#	src/components/admin/AdminSettings.vue
#	src/components/admin/RoleLayoutDefaultsSection.vue
#	src/components/admin/tabs/TemplatesPage.vue
#	src/dialogs/PublicSharePasswordDialog.vue
#	src/stores/__tests__/kioskPlaylists.spec.js
#	src/stores/kioskPlaylists.js
#	src/stores/publicShares.js
#	src/views/DashboardPublicShareView.vue
#	src/views/Views.vue
…RLGenerator' (#124) from fix/launchpad-default-tile-logo-path into development
…ses (#104)

FeedRefreshServiceTest::testRefreshFeed500RecordsFailurePreservesItems stubs
IResponse::getStatusCode() to 503 and asserts the recorded failure reason
starts with "503". The name and the docblock both said 500 — a status nothing
in the test produces or checks.

The test itself is sound and load-bearing; only the label was wrong.
REQ-FRJ-006 is written about per-feed failure tolerance generally and does not
single out a status, so 503 is a faithful representative and no coverage
changes hands. Renamed, docblock corrected, and the reason for the old label
recorded so it is not "fixed" back.

Behaviour unchanged; this is a rename plus comments.

Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/launchpad @ 962cdcd

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
composer ✅ 102/102
npm ✅ 548/548
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-12 08:32 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/launchpad @ 962cdcd

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
composer ✅ 102/102
npm ✅ 548/548
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-12 18:28 UTC

Download the full PDF report from the workflow artifacts.

* chore: adopt nextcloud/coding-standard, .editorconfig and NC 34

Configuration only. The reformat is the next commit on purpose, so
.git-blame-ignore-revs can name a revision containing nothing but whitespace.

- .php-cs-fixer.dist.php + conduction/coding-standard, which extends
  nextcloud/coding-standard and can only ADD to it — enforced by that package's
  invariant test, not by review.
- cs:check / cs:fix now run php-cs-fixer. They were aliases for phpcs/phpcbf,
  so the documented Nextcloud command reformatted code AWAY from Nextcloud's
  standard.
- nextcloud/coding-standard dropped as a direct dependency. It arrives
  transitively at a version conduction/coding-standard has tested against;
  declared directly it was a dead dependency with no config and no invocation.
- phpcs.xml is now a stub over the shared semantics-only ruleset, and the local
  phpcs-custom-sniffs/ copy is gone. The fleet was carrying six divergent
  versions of NamedParametersSniff.php — a custom RULE, not a setting.
- .editorconfig, verbatim from nextcloud/server. No fleet app had one, so an
  editor configured by someone's previous Nextcloud work defaulted to tabs,
  which the old ruleset then rejected.
- nextcloud/ocp -> ^34.0 and PHPUnit -> stable34. This app declared support for
  NC 34 while being analysed against 31, so a symbol REMOVED in 32/33/34 was
  invisible to the type checker. That is why the NC 34 removal of \OC::$server
  needed a hand-written PHPCS sniff.
- the stylelint glob is quoted, so stylelint expands it rather than the shell.
  Unquoted, src/**/ matches exactly one directory level and nested components
  are silently unlinted.

gate-65 (coding-standard-adoption) enforces all of the above from
ConductionNL/.github@main. This app failed it; with this commit it passes.

* style: reformat with nextcloud/coding-standard — whitespace only

Applied by php-cs-fixer with conduction/coding-standard. Tabs, same-line braces,
(int)$x, single-space concatenation, ordered imports — Nextcloud's dialect, which
this app now passes unchanged. 476 file(s), no behaviour change.

Isolated from the configuration change so .git-blame-ignore-revs can name a
revision that touches nothing but formatting. Reviewing it line by line is not a
useful activity; the previous commit is the review.

* chore: ignore the reformat commit in git blame

46e028e touches 476 files and changes no behaviour. Without this, every line it
reflowed attributes to it and the real author is one --skip away.

GitHub honours the file automatically; locally it needs
`git config blame.ignoreRevsFile .git-blame-ignore-revs` once.

* fix: regenerate composer.lock for the new constraints

The previous commit changed composer.json without touching the lock, so
`composer install` refused with exit 4 and EVERY PHP job failed:

    Required (in require-dev) package "conduction/coding-standard" is not
    present in the lock file.
    Required (in require-dev) package "conduction/hydra-gates" is not present
    in the lock file.
    Required (in require-dev) package "nextcloud/ocp" is in the lock file as
    "v31.0.9" but that does not satisfy your constraint "^34.0".

Nothing was wrong with the reformat or the ruleset — the jobs never got as far
as running a tool. Measured on larpingapp#313 before this fix: phpcs, psalm,
phpstan and both PHPUnit legs red, all of them at `composer install`. Hydra
Gates passed in the same run, because it does not install composer
dependencies.

Now locked at conduction/coding-standard v1.0.0, conduction/hydra-gates v1.7.0,
nextcloud/ocp v34.0.2 — the last of which is the point of the exercise: this app
declares support for NC 34 and is now analysed against it.

* fix(appinfo): order info.xml elements per the App Store xs:sequence

The App Store's info.xsd declares <info> and its children as xs:sequence, so
element ORDER is significant. This file was rejected by
`xmllint --noout --schema info.xsd appinfo/info.xml`. Nextcloud's
lint-info-xml workflow validates against exactly that schema, and
ConductionNL/.github#383 adds the same check to the shared pipeline.

Elements were moved into the schema's order. <version> and the <nextcloud>
min/max-version declaration are unchanged.

<commands> now precedes <settings>, and <navigations> follows <activity>;
inside <repair-steps>, <post-migration> precedes <install> (the schema's order
is pre-migration, post-migration, live-migration, install, uninstall - it does
not reflect execution order, which Nextcloud selects by event).

Two content fixes were unavoidable, as neither is an ordering problem.

<types><search/></types> is not a valid app type at any position: the schema
allows only prelogin, filesystem, authentication, extended_authentication,
logging, dav, prevent_group_restriction and session, and Nextcloud does
nothing with an unrecognised one. Unified search is already wired properly -
Application.php calls registerSearchProvider(LaunchPadSearchProvider) - so the
element was decorative. Replaced by a comment pointing at that registration.

<activity><provider> had to be wrapped in <providers>. The direct child is
what the schema rejects, and Nextcloud reads the provider list from
$info['activity']['providers']['provider'], so the Activity provider
(REQ-ACT-001) was in fact not being registered at all. The wrapping is
therefore a behaviour change: OCA\LaunchPad\Activity\Extension now actually
registers, which is what the requirement asked for.

Verified: `xmllint --noout --schema info.xsd appinfo/info.xml` reports
"validates" (libxml2 2.12.10). The pre-change file failed the same command.

* fix(deps): pin nextcloud/ocp to ^34.0 instead of dev-master

dev-master has advanced to the Nextcloud 35 development stubs, where
ISchemaWrapper::createTable()/getTable() return the new
OCP\DB\Schema\ITable (@SInCE 35.0.0) rather than being documented as
returning \Doctrine\DBAL\Schema\Table. That made PHPStan report 17
genuine parameter-type mismatches in the Migration table builders, which
type-hint Doctrine\DBAL\Schema\Table.

The app declares <nextcloud min-version="32" max-version="34"/>, so
analysing against NC 35 development stubs was wrong regardless. Pinning
to ^34.0 matches the constraint used by every other app in this
migration (softwarecatalog, hermiq, pipelinq) and by the merged
reference larpingapp#313.

PHPStan is now clean; no application code changes.

* ci: re-trigger Code Quality

The previous run produced zero jobs and concluded failure: it started
inside the window where ConductionNL/.github@main carried the broken
quality.yml splice from b745bf2f, repaired at 4118bca8. Nothing in this
PR touches the workflow.

* fix(tests): make the ICache test doubles match the real interface

OCP\ICache is untyped on every Nextcloud version this app supports —
'get($key)', 'set($key, $value, $ttl = 0)', 'hasKey($key)',
'remove($key)', 'clear($prefix = "")' — identical in server stable32 and
stable34. The three in-test fakes narrowed every parameter to string/int,
which PHP rejects as an incompatible declaration:

  PHP Fatal error: Declaration of Unit\Activity\FakeDebounceCache::get(
  string $key) must be compatible with OCP\ICache::get($key)

They only ever loaded because the app resolved nextcloud/ocp at
dev-master, which has advanced to the NC 35 development stubs where
ICache::get() IS typed. Pinning ocp to ^34.0 lines the stub up with the
servers this app actually declares support for, and the fakes then have to
line up too. Return types are left in place — widening a parent's absent
return type is covariant and legal.

Parameter types only; no test behaviour changes. The three affected files
run green: OK (39 tests, 80 assertions).

* fix(ci): test the whole declared Nextcloud range, not only the ceiling

appinfo/info.xml declares <nextcloud min-version="32" max-version="34"/>, but
nextcloud-test-refs was '["stable34"]' — so the declared floor and the middle
major were advertised to the App Store with no job touching either.

This is the coding-standard migration's own defect: its rollout REPLACED the
ref list instead of extending it. The programme opened by reporting that
nothing was tested on NC 34 and, in fixing that, made 32 and 33 the untested
end. Same drift, other direction.

stable34 stays first because newman, playwright and journeydoc-capture all read
fromJSON(inputs.nextcloud-test-refs)[0] as their single server.

Verified green on all three refs against nextcloud/ocp ^34 on portaliq
(run 31599055849, six PHPUnit legs: 32/33/34 x PHP 8.3/8.4).
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/launchpad @ b74955f

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
composer ✅ 104/104
npm ✅ 548/548
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-12 18:57 UTC

Download the full PDF report from the workflow artifacts.

rubenvdlinde and others added 2 commits August 12, 2026 23:51
phpmd.xml becomes a stub referencing
vendor/conduction/hydra-gates/quality-config/phpmd.xml, and the local
phpmd-unusedparams.xml is deleted in favour of the central copy.

ExcessiveClassLength 1050 is preserved via <exclude> plus a re-declaration.
DevelopmentCodeFragment with ignore-namespaces=false is NOT carried over: with
that setting PDepend namespace-qualifies every unqualified call, so the rule
matched nothing in this fully namespaced codebase. The central true takes over
and the rule becomes live at no cost - phpmd output is byte-identical.

The second leg also gains an explicit --baseline-file, because PHPMD
auto-discovers phpmd.baseline.xml next to the FIRST ruleset argument and the
ruleset has moved into vendor/.

Co-authored-by: Ruben van der Linde <release-bot@conduction.nl>
phpstan.neon now includes the shared base shipped in
conduction/hydra-gates (quality-config/phpstan-base.neon) and keeps only
what is genuinely local to this app.

Requires hydra-gates v1.7.1 — v1.7.0's base declared bare relative paths,
which PHPStan resolves against the file that declares them, so the run
aborted before analysing anything. composer.lock is updated accordingly;
no other package moved.

Verified with phpstan dump-parameters before and after: level, paths,
excludePaths, bootstrapFiles and scanDirectories resolve byte-identically,
the same number of files is analysed on both sides, and the finding count
is unchanged.
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/launchpad @ f58b182

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
composer ✅ 104/104
npm ✅ 548/548
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-12 22:08 UTC

Download the full PDF report from the workflow artifacts.

Moves the pin from 2.2.0-vue3.9 to the current vue3 dist-tag.

The lockfile was regenerated with npm 10.8.2 to match the npm version CI
runs (engines: npm ^10.0.0); npm ci was verified from a clean
node_modules.

Verified locally: npm ci, build, 58 vitest files / 641 tests, lint
(eslint plus the manifest, initial-state and translation-domain
checks), stylelint — all pass.

Co-authored-by: Ruben van der Linde <juan.claude@conduction.nl>
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/launchpad @ 313fd4a

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
composer ✅ 104/104
npm ✅ 548/548
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-12 22:33 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/launchpad @ cc10bff

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
composer ✅ 104/104
npm ✅ 548/548
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-12 23:01 UTC

Download the full PDF report from the workflow artifacts.

…110)

Lock-only. composer.json is untouched: the ^1.0 constraint is correct and
stays floating.

v1.7.3 removes two conditional paths from the shared phpstan-base.neon
(%cwd%/vendor-bin and %cwd%/lib/Resources/template). A conditional path in a
shared base has no spelling that is safe on both PHPStan majors: plain is
validated and ABORTS on PHPStan 2.x, the '(?)' marker is parsed as a NEON
entity after a %...% expansion and crashes 2.x, and quoting it stops 1.x from
stripping the marker so the exclusion silently matches nothing.

This app is on PHPStan 1.12.x, so it is not broken today, but it carries the
landmine until it moves to PHPStan 2. It has neither vendor-bin nor
lib/Resources/template, so no phpstan.neon change is needed.
…eck covers (#113)

`stylelint` was quoted; `stylelint:fix` was not. Unquoted, the SHELL expands the
glob, and without globstar `src/**/` matches exactly one directory level.

Measured in this repo: the unquoted form reaches 32 files, the quoted form 83. So
`npm run stylelint:fix` reported done while 51 files were never touched — exactly
the files `npm run stylelint` then flags.

Found by gate-65's stylelint-glob-unquoted rule, which now inspects BOTH scripts
(.github#406). It previously read only the check script and so read this app as
clean.
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/launchpad @ e035ada

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
composer ✅ 104/104
npm ✅ 548/548
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-12 23:41 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/launchpad @ 2648757

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
composer ✅ 104/104
npm ✅ 548/548
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-13 00:13 UTC

Download the full PDF report from the workflow artifacts.

Adopts @nextcloud/prettier-config (useTabs: true, tabWidth: 4), the tool
Nextcloud itself uses, which unlike stylelint covers CSS/SCSS.

eslint-config-prettier is spread LAST in eslint.config.js so the two formatters
cannot demand opposite things.

Measured first: this app's styles were already 84 tab-lines / 0 space-lines, so
there was no drift to correct — the value here is the JS/Vue side plus a
standing guarantee for the styles.

l10n/ is in .prettierignore: 37 generated l10n/*.js translation bundles.

Co-authored-by: Ruben van der Linde <juan.claude@conduction.nl>
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/launchpad @ e69c128

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
composer ✅ 104/104
npm ✅ 548/548
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-13 09:48 UTC

Download the full PDF report from the workflow artifacts.

This repo carries `@nextcloud/prettier-config` and a `format` script, but
nothing ever ran that script in CI. The shared `quality.yml` has NO prettier
job of its own — it mentions prettier ZERO times (eslint 9, stylelint 10) —
and `frontend-checks` is the only opt-in that can invoke a repo's own npm
scripts. So prettier was active in developers' editors and inert everywhere
else: exactly the state the fleet's old `.prettierrc` was deleted for.

Appending "format" to the existing `frontend-checks` array adds one
`Frontend Check (format)` job. Every pre-existing entry and its order are
unchanged.

Measured on this tree before enabling, with the same prettier version and the
same resolved config CI uses; the per-app scope and result are recorded in the
comment above the input.

Centralising the config never stopped drift; the gate does.
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/launchpad @ f9d3de4

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
format
composer ✅ 104/104
npm ✅ 548/548
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-13 11:22 UTC

Download the full PDF report from the workflow artifacts.

The glob was src/**/*.{vue,scss,css}, so css/header-override.css and
css/launchpad.css had never been linted. Both globs (check and fix) widened
together — a stylelint:fix narrower than its check reports done while leaving
violations the check flags, which was a real finding on this app earlier.

Coverage 83 -> 85 files, zero new findings: prettier had already normalised
those stylesheets fleet-wide.
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/launchpad @ 2a248c1

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
format
composer ✅ 104/104
npm ✅ 548/548
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-14 07:21 UTC

Download the full PDF report from the workflow artifacts.

rubenvdlinde and others added 4 commits August 14, 2026 14:39
Same migration as the pilot (ConductionNL/larpingapp#325) and the template
(ConductionNL/nextcloud-app-template#146). eslint.config.mjs is the canonical
copy; only the app-specific blocks at the end differ.

Requires Node 22 — @nextcloud/eslint-config@9 declares
engines.node ^22.14 || ^24 || >=26 and imports findPackageJSON from
node:module, first available in 22.14. The shared workflows already default
to 22 (ConductionNL/.github#450).

Stale eslint-8-era direct deps and overrides are removed, and the two peers
the config needs are declared at the right major (vue-eslint-parser ^10.3.0,
@typescript-eslint/parser ^8.67.0). An overrides entry resolves nc-vue's
OPTIONAL eslint peer against eslint 10 — optional means npm will not install
it, not that a mismatched version is accepted.

Coverage: all 82 .vue files parse, 0 fatal errors.

209 PRE-EXISTING VIOLATIONS ARE RECORDED, NOT FIXED
------------------------------------------------------
v9 enables rules this app has never run. --fix and prettier resolved the
mechanical ones; 209 findings across 62 files remain and are recorded in
eslint-suppressions.json using eslint's own bulk suppressions (--suppress-all),
NOT by loosening any rule. Every rule keeps the severity
@nextcloud/eslint-config gives it, the debt is counted per file, and
--prune-suppressions shrinks it as it is paid down. A NEW violation still
fails the run — verified on openconnector by appending a console.log after
suppressing.

   127  no-console
   31  @typescript-eslint/no-unused-vars
   24  vue/custom-event-name-casing
   9  no-unused-vars
   6  n/no-unpublished-import
   5  eqeqeq
   2  jsdoc/check-tag-names
   1  no-useless-assignment
   1  @nextcloud/no-deprecated-library-props
   1  jsdoc/require-param-type
   1  no-undef
   1  vue/multi-word-component-names

TWO AUTOFIXES ARE DELIBERATELY WITHHELD (recorded as debt instead)
-----------------------------------------------------------------
- @nextcloud/l10n-enforce-ellipsis rewrites '...' to the typographic '…'
  INSIDE translatable strings. That changes the translation KEY and orphans
  every l10n/*.json entry for it; on openconnector it turned the l10n parity
  check red while it was green on development. The migration must not
  silently drop translations, so the source strings are left alone.
- vue/prefer-define-options rewrites 'export default {…}' in a plain <script>
  into 'defineOptions({…})' inside <script setup>, carrying
  props/data/computed across the block boundary. @vue/compiler-sfc then
  rejects the result outright (defineOptions() cannot declare props), which
  broke the build in softwarecatalog and docudesk. It is a semantic refactor,
  not a lint fix.

TEST GLOBALS ARE DECLARED, NOT SUPPRESSED
-----------------------------------------
Spec files that live under src/ have no framework globals, so no-undef
reported every describe/it/expect as undefined — 1203 findings in
openregister from just 7 identifiers. Declaring the environment removed
~1900 phantom findings fleet-wide. Suppressing them instead would have
buried any REAL no-undef, which is the rule that catches a typo'd identifier.

VERIFIED
--------
  npm run lint  PASS    npm run stylelint  PASS
  npm run format PASS   npm run build      PASS
`@nextcloud/no-deprecated-library-props` autofixed NcButton's deprecated
`type="primary"` to `variant="primary"`. The rule is right — @nextcloud/vue v9
did repurpose `type` as the native button type and moved the visual style to
`variant` — but the rename changes the RENDERED DOM, and tests assert on it:

  openbuild  10 tests failed on `button[data-nc-button-type="primary"]`
             returning undefined; 1375/1375 pass on `development`.

So this is a runtime change, not a formatting one, and it belongs in its own
PR together with the test updates it requires. It joins the two autofixes
already withheld for the same reason:

  @nextcloud/l10n-enforce-ellipsis  edits the CONTENT of translatable strings,
                                    changing the translation key
  vue/prefer-define-options         moves options across SFC block boundaries
                                    and breaks the build

All three keep their @nextcloud/eslint-config severity and are recorded in
eslint-suppressions.json, so the debt is counted and any NEW occurrence still
fails the run.

Verified after the change: openbuild is back to 1375/1375, and lint / format /
stylelint / build pass on every app touched here.
`@nextcloud/l10n-non-breaking-space` replaced the ordinary space before a
typographic ellipsis with U+00A0 INSIDE a translatable string:

  -  t("hermiq", "name: my-skill, description: …, version: 0.1.0")
  +  t("hermiq", "name: my-skill, description: …, version: 0.1.0")

The rule is NC house style and correct in itself, but the string IS the
translation key, so the edit orphans every l10n entry for it. It turned
`test:l10n` red on hermiq, shillinq, decidesk and docudesk while all four are
green on `development`.

🔑 The two branches reported IDENTICAL scan totals — same file count, same
number of distinct keys, same en.json size — and still disagreed. The only
difference was two bytes inside one key, found by comparing the line as hex.
A count that matches is not the same as content that matches.

This is the fourth autofix withheld for the same underlying reason: it edits
meaning rather than layout. The others are l10n-enforce-ellipsis (same key
problem), vue/prefer-define-options (moves options across SFC blocks and
breaks the build) and @nextcloud/no-deprecated-library-props (renames a
rendered prop and breaks DOM assertions).

All four keep their configured severity and are recorded in
eslint-suppressions.json, so the debt is counted and any NEW occurrence still
fails the run.

Verified: test:l10n passes again on all four apps; docudesk unit tests
45/45.
build(lint): migrate to eslint 10 + @nextcloud/eslint-config 9
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/launchpad @ 577bc50

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
format
composer ✅ 104/104
npm ✅ 536/536
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-14 14:57 UTC

Download the full PDF report from the workflow artifacts.

launchpad's last two unthrottled #[PublicPage] endpoints. It now reports
ZERO.

These were MISSED by the fleet sweep, and the reason is worth recording: an
early check reported launchpad as having no git repository, so it was written
off as a deployed copy and excluded from every later measurement. It is a
normal checkout on development. The app that was already the fleet's BEST at
brute-force protection -- PublicShareService is the only service-level
IThrottler implementation in the fleet, and the whole sweep copied its shape
-- was the one left with unthrottled endpoints.

No brute-force counter on either. The share TOKEN is checked by
PublicShareController, which already registers failed attempts through
PublicShareService; publicShare() is only the shell that hosts it. 120/60 on
both, deliberately generous -- a recipient reloading a shared dashboard must
not be what trips it.

NOT verified locally: launchpad has no vendor/bin/phpunit in this
environment, so there is no suite to run. Lint-clean only; CI is the first
real run.
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/launchpad @ 70d52a6

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
format
composer ✅ 104/104
npm ✅ 536/536
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-14 15:50 UTC

Download the full PDF report from the workflow artifacts.

* ci: fast structural checks on every branch

* ci: close the branch-trigger gap
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/launchpad @ d1c29d6

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
format
composer ✅ 104/104
npm ✅ 536/536
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-14 18:39 UTC

Download the full PDF report from the workflow artifacts.

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.

5 participants