-
Notifications
You must be signed in to change notification settings - Fork 630
Docs: own and sync ClickHouse documentation #2945
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,212 @@ | ||
| name: 'Sync docs to ClickHouse/ClickHouse' | ||
|
|
||
| # Opens (or refreshes) a pull request on the aggregator docs repo | ||
| # | ||
| # It fires on three events: | ||
| # * a merged PR carrying the `sync-docs` label -> ship docs immediately, | ||
| # without waiting for a release | ||
| # * a published release -> ship docs on release, gated | ||
| # by RELEASE_SCOPE below (major-only by default); | ||
| # * manual dispatch -> force a sync. | ||
| # | ||
| # A single stable branch is force-pushed each run, so the bot keeps exactly one | ||
| # open PR that is always one commit off the target branch. The PR is labelled | ||
| # `pr-autogenerated-docs`, which the aggregator's docs check recognizes for the | ||
| # autogenerated-region edit guard. The generated body includes the changelog | ||
| # metadata required for the target repository's CI to initialize. | ||
|
|
||
| on: | ||
| pull_request_target: | ||
| types: [closed] | ||
| release: | ||
| types: [published] | ||
| workflow_dispatch: | ||
|
|
||
| # --------------------------------------------------------------------------- | ||
| # Configuration -- edit these to reuse this workflow in another client repo. | ||
| # --------------------------------------------------------------------------- | ||
| env: | ||
| # Repo that receives the docs PR, and the branch that PR targets. | ||
| TARGET_REPO: ClickHouse/ClickHouse | ||
| TARGET_BRANCH: master | ||
| # Path inside TARGET_REPO that mirrors this repo's docs. Wiped and replaced on | ||
| # every sync so deletions and renames propagate. | ||
| TARGET_DOCS_PATH: docs/integrations/language-clients/java | ||
| # This repo's docs file or folder (the source of truth). | ||
| SOURCE_DOCS_PATH: docs/clickhouse-docs | ||
| # Stable branch on TARGET_REPO, force-pushed each run. | ||
| SYNC_BRANCH: robot/docs-sync-clickhouse-java | ||
| # Label the sync PR gets on TARGET_REPO. | ||
| PR_LABEL: pr-autogenerated-docs | ||
| # Label on a merged PR in THIS repo that triggers the expedited path. | ||
| SYNC_LABEL: sync-docs | ||
| # Which releases trigger a sync: major (X.0.0), minor (X.Y.0), or all. | ||
| RELEASE_SCOPE: all | ||
|
|
||
| # The cross-repo work is done with a GitHub App token (see the sync job); this | ||
| # workflow only needs to read its own repository. | ||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
| # Gate: decide whether this event should produce a sync, and why. Kept in its | ||
| # own job so the (large) checkout/clone in `sync` only runs when needed. | ||
| decide: | ||
| runs-on: ubuntu-latest | ||
| outputs: | ||
| run: ${{ steps.gate.outputs.run }} | ||
| reason: ${{ steps.gate.outputs.reason }} | ||
| steps: | ||
| - name: Decide whether to sync | ||
| id: gate | ||
| env: | ||
| EVENT_NAME: ${{ github.event_name }} | ||
| PR_MERGED: ${{ github.event.pull_request.merged }} | ||
| PR_NUMBER: ${{ github.event.pull_request.number }} | ||
| PR_LABELS: ${{ toJSON(github.event.pull_request.labels.*.name) }} | ||
| RELEASE_TAG: ${{ github.event.release.tag_name }} | ||
| RELEASE_PRERELEASE: ${{ github.event.release.prerelease }} | ||
| run: | | ||
| set -euo pipefail | ||
| run=false | ||
| reason="" | ||
| case "$EVENT_NAME" in | ||
| workflow_dispatch) | ||
| # Manual runs always sync -- the operator explicitly asked for it. | ||
| run=true | ||
| reason="manual dispatch" | ||
| ;; | ||
| pull_request_target) | ||
| # Expedited path: a merged PR that carries the sync label. | ||
| if [[ "$PR_MERGED" == "true" ]] \ | ||
| && printf '%s' "$PR_LABELS" | jq -e --arg l "$SYNC_LABEL" 'index($l) != null' >/dev/null; then | ||
| run=true | ||
| reason="merged PR #${PR_NUMBER} labeled '${SYNC_LABEL}'" | ||
| fi | ||
| ;; | ||
| release) | ||
| if [[ "$RELEASE_PRERELEASE" == "true" ]]; then | ||
| echo "Release ${RELEASE_TAG} is a prerelease; skipping." | ||
| elif [[ "${RELEASE_TAG#v}" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+) ]]; then | ||
| minor="${BASH_REMATCH[2]}" | ||
| patch="${BASH_REMATCH[3]}" | ||
| case "$RELEASE_SCOPE" in | ||
| all) run=true ;; | ||
| minor) [[ "$patch" == "0" ]] && run=true ;; | ||
| major|*) [[ "$minor" == "0" && "$patch" == "0" ]] && run=true ;; | ||
| esac | ||
| [[ "$run" == "true" ]] && reason="release ${RELEASE_TAG} (scope=${RELEASE_SCOPE})" | ||
| else | ||
| echo "Could not parse release tag '${RELEASE_TAG}'; skipping." | ||
| fi | ||
| ;; | ||
| esac | ||
| echo "Decision: run=${run} reason='${reason}'" | ||
| { | ||
| echo "run=${run}" | ||
| echo "reason=${reason}" | ||
| } >> "$GITHUB_OUTPUT" | ||
|
|
||
| sync: | ||
| needs: decide | ||
| if: needs.decide.outputs.run == 'true' | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Checkout docs source | ||
| uses: actions/checkout@v5 | ||
| with: | ||
| # On a release, take the docs as of the released tag; otherwise take | ||
| # the default checkout (post-merge default branch / dispatched ref). | ||
| ref: ${{ github.event_name == 'release' && github.event.release.tag_name || '' }} | ||
|
chernser marked this conversation as resolved.
|
||
|
|
||
| - name: Parse target repo | ||
| id: parse | ||
| run: | | ||
| set -euo pipefail | ||
| echo "owner=${TARGET_REPO%%/*}" >> "$GITHUB_OUTPUT" | ||
| echo "name=${TARGET_REPO##*/}" >> "$GITHUB_OUTPUT" | ||
|
|
||
| - name: Generate token for target repo | ||
| id: app-token | ||
| uses: actions/create-github-app-token@v3 | ||
| with: | ||
| app-id: ${{ secrets.WORKFLOW_AUTH_PUBLIC_APP_ID }} | ||
| private-key: ${{ secrets.WORKFLOW_AUTH_PUBLIC_PRIVATE_KEY }} | ||
| owner: ${{ steps.parse.outputs.owner }} | ||
| repositories: ${{ steps.parse.outputs.name }} | ||
|
|
||
| - name: Sync docs and open/refresh PR | ||
| env: | ||
| GH_TOKEN: ${{ steps.app-token.outputs.token }} | ||
| REASON: ${{ needs.decide.outputs.reason }} | ||
| SOURCE_REPO: ${{ github.repository }} | ||
| SOURCE_REF: ${{ github.event_name == 'release' && github.event.release.tag_name || github.ref_name }} | ||
| SOURCE_SHA: ${{ github.sha }} | ||
| run: | | ||
| set -euo pipefail | ||
|
|
||
| # Resolve the absolute source path before we cd elsewhere. | ||
| src="$(realpath "$SOURCE_DOCS_PATH")" | ||
|
|
||
| workdir="$(mktemp -d)" | ||
| git clone --depth 1 --branch "$TARGET_BRANCH" \ | ||
| "https://x-access-token:${GH_TOKEN}@github.com/${TARGET_REPO}.git" "$workdir" | ||
| cd "$workdir" | ||
|
|
||
| # Replace the target file or folder with this repo's docs. Wipe first | ||
| # so deletions and renames on our side propagate. | ||
| target="${workdir:?}/${TARGET_DOCS_PATH}" | ||
| rm -rf "$target" | ||
| mkdir -p "$(dirname "$target")" | ||
| if [[ -d "$src" ]]; then | ||
| mkdir -p "$target" | ||
| cp -R "${src}/." "${target}/" | ||
| else | ||
| cp "$src" "$target" | ||
| fi | ||
|
|
||
| git config user.name "clickhouse-docs-bot" | ||
| git config user.email "clickhouse-docs-bot@users.noreply.github.com" | ||
|
|
||
| # Build the single-commit-off-target branch fresh from the target | ||
| # branch so the PR is always exactly one commit ahead. | ||
| git checkout -B "$SYNC_BRANCH" | ||
| git add -A -- "$TARGET_DOCS_PATH" | ||
| if git diff --cached --quiet; then | ||
| echo "No docs changes to sync; nothing to do." | ||
| exit 0 | ||
| fi | ||
|
|
||
| git commit -m "Sync ${SOURCE_REPO} docs (${REASON})" | ||
| git push --force origin "$SYNC_BRANCH" | ||
|
|
||
| title="Docs: Sync ${SOURCE_REPO} docs" | ||
| body=$(cat <<EOF | ||
| Automated one-way docs sync from [\`${SOURCE_REPO}\`](https://github.com/${SOURCE_REPO}). | ||
|
|
||
| - **Source ref:** \`${SOURCE_REF}\` (\`${SOURCE_SHA}\`) | ||
| - **Trigger:** ${REASON} | ||
| - **Replaces:** \`${TARGET_DOCS_PATH}\` | ||
|
|
||
| This PR is generated by the \`Sync docs to ClickHouse/ClickHouse\` workflow in \`${SOURCE_REPO}\`. | ||
| The source repo is the source of truth for these docs; edit them there, not here. | ||
|
|
||
| ### Changelog category (leave one): | ||
| - Documentation (changelog entry is not required) | ||
|
|
||
| ### Changelog entry (a [user-readable short description](https://github.com/ClickHouse/ClickHouse/blob/master/docs/changelog_entry_guidelines.md) of the changes that goes into CHANGELOG.md): | ||
| Sync language client documentation from \`${SOURCE_REPO}\`. | ||
| EOF | ||
| ) | ||
|
chernser marked this conversation as resolved.
|
||
|
|
||
| existing="$(gh pr list --repo "$TARGET_REPO" --head "$SYNC_BRANCH" \ | ||
| --state open --json number --jq '.[0].number // empty')" | ||
| if [[ -n "$existing" ]]; then | ||
| echo "PR #${existing} already open; force-push refreshed it." | ||
| gh pr edit "$existing" --repo "$TARGET_REPO" \ | ||
| --title "$title" --body "$body" --add-label "$PR_LABEL" | ||
| else | ||
| gh pr create --repo "$TARGET_REPO" \ | ||
| --base "$TARGET_BRANCH" --head "$SYNC_BRANCH" \ | ||
| --title "$title" --body "$body" --label "$PR_LABEL" | ||
| fi | ||
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| name: 'Verify Docs' | ||
|
|
||
| on: | ||
| pull_request: | ||
| branches: | ||
| - main | ||
| paths: | ||
| - 'docs/clickhouse-docs/**' | ||
| - '.github/workflows/docs_verify.yml' | ||
| push: | ||
| branches: | ||
| - main | ||
| paths: | ||
| - 'docs/clickhouse-docs/**' | ||
| - '.github/workflows/docs_verify.yml' | ||
|
|
||
| jobs: | ||
| verify: | ||
| runs-on: ubuntu-latest | ||
| name: Mintlify checks | ||
| # Run inside the docs image so every dependency (git, python3, mint, node) | ||
| # is present -- nothing is installed, and this repo vendors no scripts. | ||
| container: | ||
| image: clickhouse/docs-builder | ||
| steps: | ||
| - name: Checkout docs source | ||
| uses: actions/checkout@v5 | ||
|
|
||
| # Fetch the check driver from ClickHouse/ClickHouse rather than vendoring | ||
| # it. The driver shallow/sparse-clones the aggregator docs plus its CI | ||
| # scripts (ci/jobs/scripts/docs), so any check scripts come along for free. | ||
| - name: Fetch the docs check driver | ||
| run: | | ||
| curl -fsSL -o /tmp/mintlify_docs_check.py \ | ||
| https://raw.githubusercontent.com/ClickHouse/ClickHouse/master/ci/jobs/scripts/docs/mintlify_docs_check.py | ||
|
|
||
| # The driver clones the aggregator, replaces the Java client folder with this | ||
| # repo's canonical docs (wiping it first), and | ||
| # runs the checks from the docs root. --scoped swaps the full site-wide | ||
| # `mint validate` (~13 min) for a scoped validate of just the replaced | ||
| # slice (docs.json schema, navigation, MDX parse, snippet imports); | ||
| # link integrity is still checked site-wide by the lychee check. | ||
| # It exits non-zero if any check fails, so a green step means all passed. | ||
| - name: Run Mintlify docs checks | ||
| run: | | ||
| python3 /tmp/mintlify_docs_check.py \ | ||
| --repo https://github.com/ClickHouse/ClickHouse.git \ | ||
| --ref master \ | ||
| --replace docs/clickhouse-docs:integrations/language-clients/java \ | ||
| --scoped |
Oops, something went wrong.
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.