diff --git a/.github/workflows/config-docs-in-sync.yml b/.github/workflows/config-docs-in-sync.yml new file mode 100644 index 0000000..89a3796 --- /dev/null +++ b/.github/workflows/config-docs-in-sync.yml @@ -0,0 +1,227 @@ +name: Config Docs In Sync + +# The two config parameter pages per server version are generated by +# owncloud/config-to-docs from owncloud/core's config/config.sample.php and +# config/config.apps.sample.php. Everything below the "header end" marker in +# those pages is machine output, and a hand edit there is silently destroyed the +# next time anyone regenerates. This job regenerates and fails on any +# difference, so the published pages are provably generator output and an edit +# in the wrong place is caught here instead of years later. +# +# Deliberately NOT path-filtered. A required check that is skipped reports as +# perpetually pending and blocks merges - the same trap documented at length in +# lint-pr-title.yml. The cost of that choice is that drift introduced by a *core* +# commit surfaces on the next docs PR, whoever opens it; the nightly run below +# exists so it is usually found before then. + +on: + push: + branches: [main] + pull_request: + schedule: + # Core can drift this repo without touching it, so look once a day. + - cron: '17 4 * * *' + workflow_dispatch: + +permissions: + contents: read + +env: + CORE_REPO: https://github.com/owncloud/core.git + +jobs: + config-docs-in-sync: + runs-on: ubuntu-latest + # owncloud-owned image, so no third-party action is needed to provide PHP. + container: owncloudci/php:7.4 + # Inside a container the default shell is sh, not bash. + defaults: + run: + shell: bash + concurrency: + group: config-docs-in-sync-${{ github.ref }} + cancel-in-progress: true + steps: + - name: Checkout docs + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Checkout config-to-docs + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + repository: owncloud/config-to-docs + path: .config-to-docs + # Deliberately unpinned. This check asks "do the committed pages match + # what a maintainer running ctd.sh today would produce", so it has to + # track the current generator. The composer deps below are pinned + # because the lock file is that generator's own declared contract. + + - name: Install the converter + working-directory: .config-to-docs + # install, not update: the comment parsing lives in + # phpdocumentor/reflection-docblock, which composer.json accepts as + # ^4.3.0 while the lock pins a known-good version. Floating it can + # change the generated output. + run: composer install --no-interaction --no-progress --no-dev --no-scripts + + - name: Regenerate every version from its core branch + run: | + set -eu + + # convert.php exits 0 on both of its own failure paths - unreadable + # input, unwritable output - so nothing here may infer success from an + # exit status. Every file is checked before use, and the pages actually + # regenerated are counted and asserted at the end. Without that, a + # renamed sample in core would leave the pages untouched, the diff + # below would find nothing, and this job would pass having checked + # nothing at all. + versions=0 + generated=0 + + # Driven by the content directories themselves, so a new server + # version cannot be added and silently left unchecked. + for dir in content/server/*/; do + version=$(basename "$dir") + pages="${dir%/}/modules/admin_manual/pages/configuration/server" + + if [ ! -d "$pages" ]; then + echo "::notice::$version has no configuration/server directory, nothing to check" + continue + fi + + # git ls-remote exits 2 for "no such branch" and non-zero otherwise. + # Treating those alike would let a transient network failure resolve + # 10.16 to master and then fail the diff for a baffling reason. + rc=0 + git ls-remote --exit-code --heads "$CORE_REPO" "$version" >/dev/null 2>&1 || rc=$? + case "$rc" in + 0) ref="$version" ;; + 2) ref=master ;; + *) echo "::error::cannot reach owncloud/core to resolve a branch for $version (git ls-remote exit $rc)"; exit 1 ;; + esac + + echo "::group::$version (core $ref)" + rm -rf ".core-$version" + # blob:none matters: a plain --depth 1 --sparse clone still transfers + # the whole tree's blobs (~30 MB), this is ~1.5 MB. + git clone --quiet --depth 1 --branch "$ref" --filter=blob:none --sparse \ + "$CORE_REPO" ".core-$version" + # --no-cone with explicit paths, because cone mode cannot select a + # single root file and version.php is needed for the check below. + git -C ".core-$version" sparse-checkout set --no-cone /config/ /version.php + + # Only the version still in development legitimately has no branch of + # its own. Anything else falling back to master would be regenerated + # from the wrong source, so say so instead. + if [ "$ref" = master ]; then + core_version=$(sed -n 's/^$OC_VersionString = .\([0-9]*\.[0-9]*\).*/\1/p' ".core-$version/version.php") + if [ "$core_version" != "$version" ]; then + echo "::error::core has no $version branch and master is $core_version, so there is no source for content/server/$version" + exit 1 + fi + fi + + for pair in \ + "config.sample.php:config_sample_php_parameters.adoc" \ + "config.apps.sample.php:config_apps_sample_php_parameters.adoc"; do + sample=".core-$version/config/${pair%%:*}" + page="$pages/${pair#*:}" + + if [ ! -r "$sample" ]; then + echo "::error::$sample is missing in core $ref - the converter would report success and change nothing" + exit 1 + fi + # A page that exists in the other versions but not this one means + # either a deletion or a half-finished new version. If a version + # ever legitimately has only one, skip it explicitly rather than + # letting it pass unnoticed. + if [ ! -f "$page" ]; then + echo "::error::$page does not exist, so it cannot be verified" + exit 1 + fi + + # Keep the committed copy to compare against. The comparison + # deliberately does not use git: the pages are just files, and + # inside this container git cannot see the workspace repository. + mkdir -p "$RUNNER_TEMP/committed/$(dirname "$page")" + cp "$page" "$RUNNER_TEMP/committed/$page" + + php .config-to-docs/convert.php config:convert-adoc \ + --input-file="$sample" --output-file="$page" + generated=$((generated + 1)) + done + + rm -rf ".core-$version" + versions=$((versions + 1)) + echo "::endgroup::" + done + + if [ "$versions" -eq 0 ]; then + echo "::error::no server version was checked - has content/server/ moved?" + exit 1 + fi + expected=$((versions * 2)) + if [ "$generated" -ne "$expected" ]; then + echo "::error::regenerated $generated pages for $versions versions, expected $expected" + exit 1 + fi + echo "Regenerated $generated pages across $versions versions." + + - name: Fail if the committed pages differ from the generated output + run: | + set -eu + + # diff, not git diff: see the note in the previous step. Each snapshot + # taken before regeneration is compared with the page as it now stands, + # so the diff reads committed -> generated, i.e. what needs applying. + : > "$RUNNER_TEMP/drift.diff" + drift=0 + compared=0 + while IFS= read -r snapshot; do + page="${snapshot#"$RUNNER_TEMP"/committed/}" + compared=$((compared + 1)) + diff -u "$snapshot" "$page" \ + --label "a/$page" --label "b/$page" >> "$RUNNER_TEMP/drift.diff" || drift=1 + done < <(find "$RUNNER_TEMP/committed" -type f -name '*_sample_php_parameters.adoc' | sort) + + if [ "$compared" -eq 0 ]; then + echo "::error::no snapshots to compare - the previous step cannot have run" + exit 1 + fi + + if [ "$drift" -eq 0 ]; then + echo "All $compared config parameter pages match the generator output." + exit 0 + fi + + { + echo "### Config parameter pages are out of sync" + echo + echo "These pages are generated by [config-to-docs](https://github.com/owncloud/config-to-docs)" + echo "from \`config/config.sample.php\` and \`config/config.apps.sample.php\` in" + echo "[owncloud/core](https://github.com/owncloud/core). Everything below the" + echo "\`header end\` marker is machine output." + echo + echo "* **To document a config key**, change its comment in core, then regenerate." + echo "* **To change a page's introduction**, edit *above* the marker - that part is kept." + echo "* **If core changed and the page is merely stale**, commit the regenerated page." + echo + echo "To regenerate locally: clone core and config-to-docs, check out the core branch" + echo "matching the version, and run \`./ctd.sh\` in config-to-docs." + echo + echo '```diff' + cat "$RUNNER_TEMP/drift.diff" + echo '```' + } >> "$GITHUB_STEP_SUMMARY" + + echo "::error::Committed config parameter pages differ from config-to-docs output - see the job summary for the diff and how to fix it." + grep -E '^(---|\+\+\+|Only in)' "$RUNNER_TEMP/drift.diff" || true + exit 1 + + - name: Upload the regenerated pages + # So the fix can be downloaded rather than copy-pasted out of a log. + if: failure() + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: regenerated-config-pages + path: content/server/*/modules/admin_manual/pages/configuration/server/config_*sample_php_parameters.adoc + if-no-files-found: ignore diff --git a/.gitignore b/.gitignore index e934dac..bac09ac 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,11 @@ docs/superpowers/ # (see the preantora/preantora-local npm scripts) ui/supplemental/js/vendor/ +# scratch checkouts made by the config-docs-in-sync workflow, and by anyone +# reproducing it locally: the converter and one core clone per server version +.config-to-docs/ +.core-*/ + # macOS and IDEs .DS_Store .vscode/ diff --git a/content/server/10.15/modules/admin_manual/pages/configuration/server/config_sample_php_parameters.adoc b/content/server/10.15/modules/admin_manual/pages/configuration/server/config_sample_php_parameters.adoc index a307140..1abdb1d 100644 --- a/content/server/10.15/modules/admin_manual/pages/configuration/server/config_sample_php_parameters.adoc +++ b/content/server/10.15/modules/admin_manual/pages/configuration/server/config_sample_php_parameters.adoc @@ -2310,6 +2310,16 @@ The web based updater is enabled by default. 'upgrade.disable-web' => false, .... +=== Explicitly enable the web updater - used by /updater/ +By default, it is disabled. + +==== Code Sample + +[source,php] +.... +'web-updater.enabled' => false, +.... + === Define whether to enable automatic update of market apps Set to `false` to disable.