Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
227 changes: 227 additions & 0 deletions .github/workflows/config-docs-in-sync.yml
Original file line number Diff line number Diff line change
@@ -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
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
Loading