diff --git a/.github/workflows/formatting.yml b/.github/workflows/lint-and-format.yml similarity index 79% rename from .github/workflows/formatting.yml rename to .github/workflows/lint-and-format.yml index a33813b167..ec3b825f9e 100644 --- a/.github/workflows/formatting.yml +++ b/.github/workflows/lint-and-format.yml @@ -1,4 +1,4 @@ -name: Check formatting +name: Lint and format on: [push, pull_request] @@ -20,7 +20,10 @@ jobs: run: | npm install --global prettier pipx install cfengine black - - name: Run formatting command to (hopefully not) make changes + - name: Run cfengine format --check + run: | + cfengine format --check + - name: Run cfengine dev format-docs to (hopefully not) make changes run: | cfengine dev format-docs - name: Check if there are changes diff --git a/.gitignore b/.gitignore index 4e585782da..17db7b7d1b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ # Build artifacts cfdoc_log.markdown +/tmp/ +/output/ + # emacs *~ diff --git a/README.md b/README.md index 18371cdbfe..67320d196b 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,18 @@ It is in general advisable to make small commits that are submitted through pull requests frequently. Otherwise any structural changes to documentation content can cause merge conflicts that are hard to resolve. +## Building docs locally + +We provide a convenience script for building docs locally, using Docker; + +```bash +./build-locally.sh +``` + +For now, this will only work for CFEngine team members - you need to be able to clone the private (enterprise) repos with SSH. + +When the script finishes, it gives you instructions for how to start a webserver and see the resulting docs page. + ## Writing guidelines In order to make our documentation, blog posts, and website as consistent and easy to understand as possible, for both readers and writers, please follow the guidelines below. @@ -287,24 +299,6 @@ When the word is a function, mark it as such using `()`: **See also:** [`classify()`][classify] -Section titles of the form - - ### section title - -are included in that automatic linking. To exclude a section header -from that automatic linking, use the form - - ### section title, no linking ### - -which is otherwise equivalent for the markdown renderer. - -To use keywords in inline code _without_ creating an automatic link, use -triple backticks: - - The ```meta``` parameter to this function... - -With single backticks, this would link to the documentation of the `meta` attribute or promise type. - ### Custom macros The documentation generator will pre-process the markdown content diff --git a/build-locally.sh b/build-locally.sh new file mode 100755 index 0000000000..199ceba75e --- /dev/null +++ b/build-locally.sh @@ -0,0 +1,145 @@ +#!/usr/bin/env bash +# +# Build the CFEngine documentation locally in a Docker container. +# +# Self-contained: clones the sibling repos that the build expects +# (core, nova, enterprise, masterfiles, nt-docs) into ./tmp/ and runs +# the existing Docker-based pipeline against them, without requiring +# anything outside this directory. +# +# Override via env vars if needed: +# BRANCH branch name to build for (default: master) +# PACKAGE_JOB cf-remote or a buildcache job (default: cf-remote) +# PACKAGE_UPLOAD_DIRECTORY (default: n/a — unused with cf-remote) +# PACKAGE_BUILD (default: n/a — unused with cf-remote) +# LTS_VERSION (default: empty) +# DOCKER docker binary to use (default: docker) +# IMAGE_NAME tag for the build image (default: cfengine-docs-hugo) +# SKIP_PUBLISH=1 skip the _publish.sh step (just build) + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +TMP_DIR="$SCRIPT_DIR/tmp" +CACHE_DIR="$TMP_DIR/cache" # persistent clones with .git +WORK_DIR="$TMP_DIR/work" # clean working copies (.git stripped) — what we mount +DOC_WORK="$WORK_DIR/documentation" +mkdir -p "$CACHE_DIR" "$WORK_DIR" + +BRANCH="${BRANCH:-master}" +PACKAGE_JOB="${PACKAGE_JOB:-cf-remote}" +PACKAGE_UPLOAD_DIRECTORY="${PACKAGE_UPLOAD_DIRECTORY:-n/a}" +PACKAGE_BUILD="${PACKAGE_BUILD:-n/a}" +LTS_VERSION="${LTS_VERSION:-}" +DOCKER="${DOCKER:-docker}" +IMAGE_NAME="${IMAGE_NAME:-cfengine-docs-hugo}" + +# repo_name url default_branch +REPOS=( + "core git@github.com:cfengine/core.git master" + "nova git@github.com:cfengine/nova.git master" + "enterprise git@github.com:cfengine/enterprise.git master" + "masterfiles git@github.com:cfengine/masterfiles.git master" + "nt-docs git@github.com:northerntechhq/nt-docs.git main" +) + +# 1. Clone (or update) the sibling repos under tmp/cache/, then export a +# clean working copy (no .git) to tmp/work/. We mount the .git-free +# copy because the container does `chmod -R` over each repo, and on +# macOS Docker bind mounts can't chmod git pack files written by the +# host user. +echo "==> Preparing sibling repos under $TMP_DIR" +for entry in "${REPOS[@]}"; do + # shellcheck disable=SC2086 + set -- $entry + name="$1"; url="$2"; default_branch="$3" + cache="$CACHE_DIR/$name" + work="$WORK_DIR/$name" + + if [ -d "$cache/.git" ]; then + echo " - $name: fetching latest" + git -C "$cache" fetch --quiet --tags origin + else + echo " - $name: cloning $url" + git clone --quiet "$url" "$cache" + fi + + if git -C "$cache" rev-parse --verify --quiet "origin/$BRANCH" >/dev/null; then + git -C "$cache" checkout --quiet -B "$BRANCH" "origin/$BRANCH" + else + echo " branch '$BRANCH' not found in $name; using '$default_branch'" + git -C "$cache" checkout --quiet -B "$default_branch" "origin/$default_branch" + fi + + # Export a clean snapshot for the container. Using `git archive` so + # we get exactly what's tracked, without .git or untracked junk. + rm -rf "$work" + mkdir -p "$work" + git -C "$cache" archive --format=tar HEAD | tar -x -C "$work" +done + +# 1b. Sync the documentation source itself into tmp/work/documentation. +# The build mutates files in place (sed on config.toml, cfdoc_preprocess.py +# rewriting markdown, etc.), so we must NOT bind-mount the user's checkout +# directly. Use rsync with --delete to keep the copy in sync (including +# uncommitted/untracked changes) without dragging tmp/ or .git into it. +# cfdoc_log.markdown is a build artifact written into content/ by cfdoc_qa.py +# (it's gitignored). If a previous run left it behind, the link checker +# re-parses its log entries — which themselves contain literal +# [foo#foo][foo#foo] markdown — and reports hundreds of bogus "unresolved +# reference" errors. We must clear it from both sides: --exclude keeps the +# host's copy from being synced in, and the explicit rm removes any copy a +# previous in-container build wrote into the work tree (rsync --delete will +# NOT remove an --exclude'd path, so the exclude alone is not enough). +echo "==> Syncing documentation source to $DOC_WORK" +mkdir -p "$DOC_WORK" +rsync -a --delete \ + --exclude='/tmp/' \ + --exclude='/.git/' \ + --exclude='/content/cfdoc_log.markdown' \ + "$SCRIPT_DIR/" "$DOC_WORK/" +rm -f "$DOC_WORK/content/cfdoc_log.markdown" + +# 2. Build the docker image (only if it's not already built). +if ! "$DOCKER" image inspect "$IMAGE_NAME" >/dev/null 2>&1; then + echo "==> Building docker image $IMAGE_NAME" + "$DOCKER" build --tag "$IMAGE_NAME" "$SCRIPT_DIR/generator/build" +else + echo "==> Reusing docker image $IMAGE_NAME (delete it to rebuild)" +fi + +# 3. Run the build inside the container. +# main.sh expects /nt/{documentation,core,nova,enterprise,masterfiles,nt-docs}. +# We bind-mount this checkout as /nt/documentation and each tmp/ as +# its sibling, so nothing outside this directory is touched. +echo "==> Running documentation build in container" +RUN_FLAGS=( + --rm + -v "$DOC_WORK:/nt/documentation" +) +for entry in "${REPOS[@]}"; do + # shellcheck disable=SC2086 + set -- $entry + RUN_FLAGS+=(-v "$WORK_DIR/$1:/nt/$1") +done + +"$DOCKER" run "${RUN_FLAGS[@]}" "$IMAGE_NAME" \ + bash -x documentation/generator/build/main.sh \ + "$BRANCH" "$PACKAGE_JOB" "$PACKAGE_UPLOAD_DIRECTORY" \ + "$PACKAGE_BUILD" "$LTS_VERSION" + +# 4. Optionally package the result (mirrors the Jenkins pipeline). +if [ -z "${SKIP_PUBLISH:-}" ]; then + echo "==> Packaging output" + "$DOCKER" run "${RUN_FLAGS[@]}" "$IMAGE_NAME" \ + bash -x documentation/generator/_scripts/_publish.sh "$BRANCH" +fi + +echo "==> Done. Generated site is in: $DOC_WORK/generator/_site" +echo " Tarballs (if packaged) are in: $DOC_WORK/output/" +echo " Start a webserver:" +echo " python3 -m http.server --directory $DOC_WORK/generator/_site/" +echo " And then open in your browser:" +echo " http://127.0.0.1:8000/" diff --git a/cheatsheet.markdown b/cheatsheet.markdown index 4a6d99ebb6..e6b987a29c 100644 --- a/cheatsheet.markdown +++ b/cheatsheet.markdown @@ -278,11 +278,10 @@ This metadata won't be shown in the resulting HTML (it will be converted to the bundle agent hello_world { meta: - "tags" - slist => { "autorun" }; + "tags" slist => { "autorun" }; + vars: - "github_path" - string => "/tmp/github.com"; + "github_path" string => "/tmp/github.com"; } ``` @@ -302,7 +301,6 @@ If you want CFEngine syntax highlighting, use ```cf3 # CFEngine code block - bundle agent example() { } @@ -463,8 +461,9 @@ If you want to include a code block within a list, align it just as you would wi ```cf3 # CFEngine block - - bundle agent example() {} + bundle agent example() + { + } ``` 2. Second diff --git a/content/_index.markdown b/content/_index.markdown index 3abba0be76..19612ff916 100644 --- a/content/_index.markdown +++ b/content/_index.markdown @@ -23,16 +23,16 @@ aliases: