Work in progress
Some checks failed
site.yaml / Work in progress (push) Failing after 0s
Build Antora container image for Fedora Docs / build (x86_64, latest, buildroot) (push) Successful in 2m5s
Build buildroot container image for Fedora Docs / build (x86_64, latest, buildroot) (push) Successful in 2m13s
Build Antora container image for Fedora Docs / merge (x86_64, latest, buildroot) (push) Successful in 35s
Build buildroot container image for Fedora Docs / merge (x86_64, latest, buildroot) (push) Successful in 41s

Signed-off-by: Hristo Marinov <hricky@fedoraproject.org>
This commit is contained in:
Hristo Marinov 2026-08-10 08:54:10 +03:00
commit 7ad7e30802
No known key found for this signature in database
28 changed files with 2546 additions and 0 deletions

View file

@ -0,0 +1,100 @@
# SPDX-FileCopyrightText: Fedora Docs maintainers
# SPDX-License-Identifier: MIT
ARG BASEIMAGE_REPO=overridden
ARG BASEIMAGE_TAG=overridden
ARG CHUNKAH_REPO=overridden
ARG CHUNKAH_TAG=overridden
ARG CHUNKAH_TMP_OCIARCHIVE=overridden
FROM ${BASEIMAGE_REPO}:${BASEIMAGE_TAG} AS buildroot
ARG NODEJS_VERSION=overridden
ENV NODEJS_VERSION=${NODEJS_VERSION}
# Install the required packages and modify the defaults
RUN --mount=type=cache,rw,target=/cache \
--mount=type=cache,dst=/var/cache/dnf \
--mount=type=cache,dst=/var/cache/libdnf5 \
<<EORUN
set -euo pipefail
set -x
export FORCE_COLUMNS=134
rm --force /etc/yum.repos.d/fedora-cisco-openh264.repo
dnf upgrade --assumeyes --refresh --no-allow-downgrade \
--allowerasing
dnf --refresh install --assumeyes --allowerasing \
--no-allow-downgrade --no-docs --setopt=tsflags=nodocs \
--setopt=install_weak_deps=False --best \
--exclude container-selinux \
nodejs${NODEJS_VERSION} \
fuse-overlayfs \
git-core \
tar \
jq \
podman \
buildah
# Copy and modify the defaults to provide reference if runtime changes needed.
# Changes here are required for running with fuse-overlay storage inside container.
sed \
--expression 's|^#mount_program|mount_program|g' \
--expression '/additionalimage.*/a "/var/lib/shared",' \
--expression 's|^mountopt[[:space:]]*=.*$|mountopt = "nodev,fsync=0"|g' \
/usr/share/containers/storage.conf \
> /etc/containers/storage.conf
mkdir --parents \
/var/lib/shared/overlay-images \
/var/lib/shared/overlay-layers \
/var/lib/shared/vfs-images \
/var/lib/shared/vfs-layers
touch \
/var/lib/shared/overlay-images/images.lock \
/var/lib/shared/overlay-layers/layers.lock \
/var/lib/shared/vfs-images/images.lock \
/var/lib/shared/vfs-layers/layers.lock
dnf clean all
rm --recursive --force /tmp/* /var/lib/dnf/* /var/cache/dnf/* /var/log/*
EORUN
# Rechunk
# - Use more layers (128)
FROM ${CHUNKAH_REPO}:${CHUNKAH_TAG} AS chunkah
ARG CHUNKAH_TMP_OCIARCHIVE=overridden
RUN --mount=from=buildroot,src=/,target=/chunkah,ro \
--mount=type=bind,target=/run/src,rw \
chunkah build \
--verbose \
--skip-special-files \
--max-layers 128 \
--output oci:${CHUNKAH_TMP_OCIARCHIVE}
# Create the final image from the rechunked oci-archive
# Redeclare ARG for this stage
ARG CHUNKAH_TMP_OCIARCHIVE=overridden
ARG IMAGE_TITLE=overridden
ARG IMAGE_DESCRIPTION=overridden
ARG IMAGE_SOURCE=overridden
ARG IMAGE_LICENSES=overridden
ARG QUAY_EXPIRES_AFTER=overridden
FROM oci:${CHUNKAH_TMP_OCIARCHIVE}
ARG IMAGE_TITLE=overridden
ARG IMAGE_DESCRIPTION=overridden
ARG IMAGE_SOURCE=overridden
ARG IMAGE_LICENSES=overridden
ARG QUAY_EXPIRES_AFTER=overridden
LABEL org.opencontainers.image.title="${IMAGE_TITLE}"
LABEL org.opencontainers.image.description="${IMAGE_DESCRIPTION}"
LABEL org.opencontainers.image.source="${IMAGE_SOURCE}"
LABEL org.opencontainers.image.licenses="${IMAGE_LICENSES}"
LABEL quay.expires-after="${QUAY_EXPIRES_AFTER}"

View file

@ -0,0 +1,191 @@
# SPDX-FileCopyrightText: Fedora Docs maintainers
# SPDX-License-Identifier: MIT
name: "Build Antora container image for Fedora Docs"
env:
CONTAINERFILE: "Containerfile"
REGISTRY: "quay.io/fedora-docs"
IMAGE: "antora"
BASEIMAGE_REPO: "quay.io/fedora/fedora-minimal"
BASEIMAGE_TAG: "44"
RUNNERIMAGE_REPO: "quay.io/fedora-docs/buildroot"
RUNNERIMAGE_TAG: "latest"
CHUNKAH_REPO: "quay.io/coreos/chunkah"
CHUNKAH_TAG: "dev"
CHUNKAH_TMP_OCIARCHIVE: "/tmp/chunkah"
NODEJS_VERSION: "24"
IMAGE_TITLE: "Fedora Docs Antora"
IMAGE_DESCRIPTION: "Antora container image for the Fedora Docs build and preview tools"
IMAGE_SOURCE: "https://forge.fedoraproject.org/docs/docs-fp-o"
IMAGE_LICENSES: "MIT"
QUAY_EXPIRES_AFTER: "4w"
on:
pull_request:
branches:
- "main"
push:
branches:
- "main"
schedule:
- cron: "0 7 * * *"
workflow_dispatch:
permissions: read-all
# Prevent multiple workflow runs from racing to ensure that pushes are made
# sequentialy for the main branch. Also cancel in progress workflow runs.
concurrency:
group: ${{ forgejo.workflow }}-${{ forgejo.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: "${{ matrix.runner }}"
container:
# image: quay.io/containers/aio:latest
image: ${{ env.RUNNERIMAGE_REPO }}:${{ env.RUNNERIMAGE_TAG }}
strategy:
fail-fast: false
matrix:
# arch: ['x86_64', 'aarch64']
arch: ['x86_64']
# release: ['rawhide', '44', '43']
release: ['latest']
include:
- arch: x86_64
runner: buildroot
# - arch: aarch64
# runner: TBD
steps:
- name: "Checkout repo"
uses: https://github.com/actions/checkout@v7
- name: "Determine Antora version"
id: antora-version
run: |
set -xeuo pipefail
readonly ANTORA_VERSION=$(curl --silent \
"https://gitlab.com/api/v4/projects/4180516/repository/tags?order_by=updated&sort=desc&per_page=1" \
| jq --raw-output '.[].name[1:]')
echo "version=${ANTORA_VERSION}" >> "${FORGEJO_OUTPUT}"
- name: "Build container image"
uses: https://github.com/redhat-actions/buildah-build@v3
with:
context: "build-antora-container"
image: ${{ env.IMAGE }}
tags: ${{ matrix.release }}-${{ matrix.arch }}
containerfiles: ${{ env.CONTAINERFILE }}
oci: true
build-args: |
BASEIMAGE_REPO=${{ env.BASEIMAGE_REPO }}
BASEIMAGE_TAG=${{ env.BASEIMAGE_TAG }}
CHUNKAH_REPO=${{ env.CHUNKAH_REPO }}
CHUNKAH_TAG=${{ env.CHUNKAH_TAG }}
CHUNKAH_TMP_OCIARCHIVE=${{ env.CHUNKAH_TMP_OCIARCHIVE }}
NODEJS_VERSION=${{ env.NODEJS_VERSION }}
ANTORA_VERSION=${{ steps.antora-version.outputs.version }}
IMAGE_TITLE=${{ env.IMAGE_TITLE }}
IMAGE_DESCRIPTION=${{ env.IMAGE_DESCRIPTION }}
IMAGE_SOURCE=${{ env.IMAGE_SOURCE }}
IMAGE_LICENSES=${{ env.IMAGE_LICENSES }}
QUAY_EXPIRES_AFTER=${{ env.QUAY_EXPIRES_AFTER }}
extra-args: |
--no-cache
--skip-unused-stages=false
--volume /tmp:/tmp
- name: "Login to Container Registry"
uses: https://github.com/redhat-actions/podman-login@v2
# if: (forgejo.event_name == 'push' || forgejo.event_name == 'schedule' || forgejo.event_name == 'workflow_dispatch') && forgejo.ref == 'refs/heads/main'
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.BOT_USERNAME }}
password: ${{ secrets.BOT_SECRET }}
auth_file_path: /tmp/auth.json
- name: "Push to Container Registry"
uses: https://github.com/redhat-actions/push-to-registry@v3
id: "push"
# if: (forgejo.event_name == 'push' || forgejo.event_name == 'schedule' || forgejo.event_name == 'workflow_dispatch') && forgejo.ref == 'refs/heads/main'
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.BOT_USERNAME }}
password: ${{ secrets.BOT_SECRET }}
image: ${{ env.IMAGE }}
tags: ${{ matrix.release }}-${{ matrix.arch }}
extra-args: |
--compression-format=zstd
--compression-level=22
merge:
runs-on: "${{ matrix.runner }}"
container:
image: ${{ env.RUNNERIMAGE_REPO }}:${{ env.RUNNERIMAGE_TAG }}
needs:
- "build"
strategy:
fail-fast: false
matrix:
# arch: ['x86_64', 'aarch64']
arch: ['x86_64']
# release: ['rawhide', '44', '43']
release: ['latest']
include:
- arch: x86_64
runner: buildroot
# - arch: aarch64
# runner: TBD
steps:
- name: "Create multi-arch manifest"
# if: (forgejo.event_name == 'push' || forgejo.event_name == 'schedule' || forgejo.event_name == 'workflow_dispatch') && forgejo.ref == 'refs/heads/main'
shell: bash
run: |
set -xeuo pipefail
buildah manifest create \
"${REGISTRY}/${IMAGE}:${RELEASE}" \
"${REGISTRY}/${IMAGE}:${RELEASE}-x86_64"
# "${REGISTRY}/${IMAGE}:${RELEASE}-aarch64"
env:
RELEASE: ${{ matrix.release }}
- name: "Push to Container Registry"
# uses: https://github.com/redhat-actions/push-to-registry@v3
uses: https://github.com/redhat-actions/push-to-registry@v2
id: "push"
# if: (forgejo.event_name == 'push' || forgejo.event_name == 'schedule' || forgejo.event_name == 'workflow_dispatch') && forgejo.ref == 'refs/heads/main'
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.BOT_USERNAME }}
password: ${{ secrets.BOT_SECRET }}
image: ${{ env.IMAGE }}
tags: ${{ matrix.release }}
- name: "Login to Container Registry"
uses: https://github.com/redhat-actions/podman-login@v2
# if: (forgejo.event_name == 'push' || forgejo.event_name == 'schedule' || forgejo.event_name == 'workflow_dispatch') && forgejo.ref == 'refs/heads/main'
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.BOT_USERNAME }}
password: ${{ secrets.BOT_SECRET }}
auth_file_path: /tmp/auth.json
- name: "Setup cosign"
uses: https://github.com/sigstore/cosign-installer@v3.10.0
# if: (forgejo.event_name == 'push' || forgejo.event_name == 'schedule' || forgejo.event_name == 'workflow_dispatch') && forgejo.ref == 'refs/heads/main'
- name: "Sign container image"
# if: (forgejo.event_name == 'push' || forgejo.event_name == 'schedule' || forgejo.event_name == 'workflow_dispatch') && forgejo.ref == 'refs/heads/main'
run: |
cosign sign --yes --recursive --key env://COSIGN_PRIVATE_KEY ${{ env.REGISTRY }}/${{ env.IMAGE }}@${{ steps.push.outputs.digest }}
env:
COSIGN_EXPERIMENTAL: false
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
COSIGN_PASSWORD: ""

View file

@ -0,0 +1,265 @@
# SPDX-FileCopyrightText: Fedora Docs maintainers
# SPDX-License-Identifier: MIT
name: "Build buildroot container image for Fedora Docs"
env:
CONTAINERFILE: "Containerfile.buildroot"
REGISTRY: "quay.io/fedora-docs"
IMAGE: "buildroot"
BASEIMAGE_REPO: "quay.io/fedora/fedora-minimal"
BASEIMAGE_TAG: "44"
CHUNKAH_REPO: "quay.io/coreos/chunkah"
CHUNKAH_TAG: "dev"
CHUNKAH_TMP_OCIARCHIVE: "/tmp/chunkah"
NODEJS_VERSION: "24"
IMAGE_TITLE: "Fedora Docs Buildroot"
IMAGE_DESCRIPTION: "Buildroot container image for the Fedora Docs CI"
IMAGE_SOURCE: "https://forge.fedoraproject.org/docs/docs-fp-o"
IMAGE_LICENSES: "MIT"
QUAY_EXPIRES_AFTER: "4w"
on:
pull_request:
branches:
- "main"
push:
branches:
- "main"
schedule:
- cron: "0 7 * * *"
workflow_dispatch:
permissions: read-all
# Prevent multiple workflow runs from racing to ensure that pushes are made
# sequentialy for the main branch. Also cancel in progress workflow runs.
concurrency:
group: ${{ forgejo.workflow }}-${{ forgejo.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: "${{ matrix.runner }}"
container:
# image: quay.io/containers/aio:latest
image: ${{ env.BASEIMAGE_REPO }}:${{ env.BASEIMAGE_TAG }}
strategy:
fail-fast: false
matrix:
# arch: ['x86_64', 'aarch64']
arch: ['x86_64']
# release: ['rawhide', '44', '43']
release: ['latest']
include:
- arch: x86_64
runner: buildroot
# - arch: aarch64
# runner: TBD
steps:
- name: "Install packages"
run: |
set -xeuo pipefail
export FORCE_COLUMNS=134
mkdir --parents /root/.docker
rm --force /etc/yum.repos.d/fedora-cisco-openh264.repo
dnf --refresh install --assumeyes --allowerasing \
--no-allow-downgrade --no-docs --setopt=tsflags=nodocs \
--setopt=install_weak_deps=False --best \
--exclude container-selinux \
nodejs${{ env.NODEJS_VERSION }} \
fuse-overlayfs \
git-core \
tar \
jq \
podman \
buildah
dnf clean all
rm --recursive --force /var/lib/dnf /var/cache /var/log
- name: "Modify the defaults"
# Copy and modify the defaults to provide reference if runtime changes needed.
# Changes here are required for running with fuse-overlay storage inside container.
run: |
set -xeuo pipefail
export FORCE_COLUMNS=134
sed \
--expression 's|^#mount_program|mount_program|g' \
--expression '/additionalimage.*/a "/var/lib/shared",' \
--expression 's|^mountopt[[:space:]]*=.*$|mountopt = "nodev,fsync=0"|g' \
/usr/share/containers/storage.conf \
> /etc/containers/storage.conf
mkdir --parents \
/var/lib/shared/overlay-images \
/var/lib/shared/overlay-layers \
/var/lib/shared/vfs-images \
/var/lib/shared/vfs-layers
touch \
/var/lib/shared/overlay-images/images.lock \
/var/lib/shared/overlay-layers/layers.lock \
/var/lib/shared/vfs-images/images.lock \
/var/lib/shared/vfs-layers/layers.lock
- name: "Checkout repo"
uses: https://github.com/actions/checkout@v7
- name: "Build container image"
uses: https://github.com/redhat-actions/buildah-build@v3
with:
context: ".forgejo"
image: ${{ env.IMAGE }}
tags: ${{ matrix.release }}-${{ matrix.arch }}
containerfiles: ${{ env.CONTAINERFILE }}
oci: true
build-args: |
BASEIMAGE_REPO=${{ env.BASEIMAGE_REPO }}
BASEIMAGE_TAG=${{ env.BASEIMAGE_TAG }}
CHUNKAH_REPO=${{ env.CHUNKAH_REPO }}
CHUNKAH_TAG=${{ env.CHUNKAH_TAG }}
CHUNKAH_TMP_OCIARCHIVE=${{ env.CHUNKAH_TMP_OCIARCHIVE }}
NODEJS_VERSION=${{ env.NODEJS_VERSION }}
ANTORA_VERSION=${{ steps.antora-version.outputs.version }}
IMAGE_TITLE=${{ env.IMAGE_TITLE }}
IMAGE_DESCRIPTION=${{ env.IMAGE_DESCRIPTION }}
IMAGE_SOURCE=${{ env.IMAGE_SOURCE }}
IMAGE_LICENSES=${{ env.IMAGE_LICENSES }}
QUAY_EXPIRES_AFTER=${{ env.QUAY_EXPIRES_AFTER }}
extra-args: |
--no-cache
--skip-unused-stages=false
--volume /tmp:/tmp
- name: "Login to Container Registry"
uses: https://github.com/redhat-actions/podman-login@v2
# if: (forgejo.event_name == 'push' || forgejo.event_name == 'schedule' || forgejo.event_name == 'workflow_dispatch') && forgejo.ref == 'refs/heads/main'
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.BOT_USERNAME }}
password: ${{ secrets.BOT_SECRET }}
auth_file_path: /tmp/auth.json
- name: "Push to Container Registry"
uses: https://github.com/redhat-actions/push-to-registry@v3
id: "push"
# if: (forgejo.event_name == 'push' || forgejo.event_name == 'schedule' || forgejo.event_name == 'workflow_dispatch') && forgejo.ref == 'refs/heads/main'
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.BOT_USERNAME }}
password: ${{ secrets.BOT_SECRET }}
image: ${{ env.IMAGE }}
tags: ${{ matrix.release }}-${{ matrix.arch }}
extra-args: |
--compression-format=zstd
--compression-level=22
merge:
runs-on: "${{ matrix.runner }}"
container:
image: ${{ env.BASEIMAGE_REPO }}:${{ env.BASEIMAGE_TAG }}
needs:
- "build"
strategy:
fail-fast: false
matrix:
# arch: ['x86_64', 'aarch64']
arch: ['x86_64']
# release: ['rawhide', '44', '43']
release: ['latest']
include:
- arch: x86_64
runner: buildroot
# - arch: aarch64
# runner: TBD
steps:
- name: "Install packages"
run: |
set -xeuo pipefail
export FORCE_COLUMNS=134
mkdir --parents /root/.docker
rm --force /etc/yum.repos.d/fedora-cisco-openh264.repo
dnf --refresh install --assumeyes --allowerasing \
--no-allow-downgrade --no-docs --setopt=tsflags=nodocs \
--setopt=install_weak_deps=False --best \
--exclude container-selinux \
nodejs${{ env.NODEJS_VERSION }} \
fuse-overlayfs \
git-core \
tar \
jq \
podman \
buildah
dnf clean all
rm --recursive --force /var/lib/dnf /var/cache /var/log
- name: "Modify the defaults"
# Copy and modify the defaults to provide reference if runtime changes needed.
# Changes here are required for running with fuse-overlay storage inside container.
run: |
set -xeuo pipefail
export FORCE_COLUMNS=134
sed \
--expression 's|^#mount_program|mount_program|g' \
--expression '/additionalimage.*/a "/var/lib/shared",' \
--expression 's|^mountopt[[:space:]]*=.*$|mountopt = "nodev,fsync=0"|g' \
/usr/share/containers/storage.conf \
> /etc/containers/storage.conf
mkdir --parents \
/var/lib/shared/overlay-images \
/var/lib/shared/overlay-layers \
/var/lib/shared/vfs-images \
/var/lib/shared/vfs-layers
touch \
/var/lib/shared/overlay-images/images.lock \
/var/lib/shared/overlay-layers/layers.lock \
/var/lib/shared/vfs-images/images.lock \
/var/lib/shared/vfs-layers/layers.lock
- name: "Create multi-arch manifest"
# if: (forgejo.event_name == 'push' || forgejo.event_name == 'schedule' || forgejo.event_name == 'workflow_dispatch') && forgejo.ref == 'refs/heads/main'
shell: bash
run: |
set -xeuo pipefail
buildah manifest create \
"${REGISTRY}/${IMAGE}:${RELEASE}" \
"${REGISTRY}/${IMAGE}:${RELEASE}-x86_64"
# "${REGISTRY}/${IMAGE}:${RELEASE}-aarch64"
env:
RELEASE: ${{ matrix.release }}
- name: "Push to Container Registry"
# uses: https://github.com/redhat-actions/push-to-registry@v3
uses: https://github.com/redhat-actions/push-to-registry@v2
id: "push"
# if: (forgejo.event_name == 'push' || forgejo.event_name == 'schedule' || forgejo.event_name == 'workflow_dispatch') && forgejo.ref == 'refs/heads/main'
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.BOT_USERNAME }}
password: ${{ secrets.BOT_SECRET }}
image: ${{ env.IMAGE }}
tags: ${{ matrix.release }}
- name: "Login to Container Registry"
uses: https://github.com/redhat-actions/podman-login@v2
# if: (forgejo.event_name == 'push' || forgejo.event_name == 'schedule' || forgejo.event_name == 'workflow_dispatch') && forgejo.ref == 'refs/heads/main'
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.BOT_USERNAME }}
password: ${{ secrets.BOT_SECRET }}
auth_file_path: /tmp/auth.json
- name: "Setup cosign"
uses: https://github.com/sigstore/cosign-installer@v3.10.0
# if: (forgejo.event_name == 'push' || forgejo.event_name == 'schedule' || forgejo.event_name == 'workflow_dispatch') && forgejo.ref == 'refs/heads/main'
- name: "Sign container image"
# if: (forgejo.event_name == 'push' || forgejo.event_name == 'schedule' || forgejo.event_name == 'workflow_dispatch') && forgejo.ref == 'refs/heads/main'
run: |
cosign sign --yes --recursive --key env://COSIGN_PRIVATE_KEY ${{ env.REGISTRY }}/${{ env.IMAGE }}@${{ steps.push.outputs.digest }}
env:
COSIGN_EXPERIMENTAL: false
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
COSIGN_PASSWORD: ""

View file

@ -0,0 +1,133 @@
# SPDX-FileCopyrightText: Fedora Docs maintainers
# SPDX-License-Identifier: MIT
name: "Build container image for testing the Fedora Council Docs"
env:
CONTAINERFILE: "Containerfile"
REGISTRY: "quay.io/fedora-docs"
IMAGE: "council-docs-test"
TAGS: "latest"
BASEIMAGE_REPO: "quay.io/fedora/fedora-minimal"
BASEIMAGE_TAG: "44"
RUNNERIMAGE_REPO: "quay.io/fedora-docs/buildroot"
RUNNERIMAGE_TAG: "latest"
CHUNKAH_REPO: "quay.io/coreos/chunkah"
CHUNKAH_TAG: "dev"
CHUNKAH_TMP_OCIARCHIVE: "/tmp/chunkah"
PLAYBOOK_PATH: "site-council-docs-new.yaml"
NODEJS_VERSION: "24"
IMAGE_TITLE: "Fedora Docs"
IMAGE_DESCRIPTION: "Container image for testing the Fedora Council Docs"
IMAGE_SOURCE: "https://forge.fedoraproject.org/docs/docs-fp-o"
IMAGE_LICENSES: "MIT"
QUAY_EXPIRES_AFTER: "4w"
on:
pull_request:
branches:
- "main"
push:
branches:
- "main"
schedule:
- cron: "50 * * * *"
workflow_dispatch:
permissions: "read-all"
# Prevent multiple workflow runs from racing to ensure that pushes are made
# sequentialy for the main branch. Also cancel in progress workflow runs.
concurrency:
group: ${{ forgejo.workflow }}-${{ forgejo.ref }}
cancel-in-progress: true
jobs:
build:
# runs-on: "${{ matrix.runner }}"
runs-on: "buildroot"
container:
# image: quay.io/containers/aio:latest
image: ${{ env.RUNNERIMAGE_REPO }}:${{ env.RUNNERIMAGE_TAG }}
steps:
- name: "Checkout repo"
uses: https://github.com/actions/checkout@v7
- name: "Determine Antora version"
id: antora-version
run: |
set -xeuo pipefail
readonly ANTORA_VERSION=$(curl --silent \
"https://gitlab.com/api/v4/projects/4180516/repository/tags?order_by=updated&sort=desc&per_page=1" \
| jq --raw-output '.[].name[1:]')
echo "version=${ANTORA_VERSION}" >> "${FORGEJO_OUTPUT}"
- name: "Build container image"
uses: https://github.com/redhat-actions/buildah-build@v3
with:
context: "build-site-container"
image: ${{ env.IMAGE }}
tags: ${{ env.TAGS }}
containerfiles: ${{ env.CONTAINERFILE }}
context: ./docs
oci: true
build-args: |
BASEIMAGE_REPO=${{ env.BASEIMAGE_REPO }}
BASEIMAGE_TAG=${{ env.BASEIMAGE_TAG }}
CHUNKAH_REPO=${{ env.CHUNKAH_REPO }}
CHUNKAH_TAG=${{ env.CHUNKAH_TAG }}
CHUNKAH_TMP_OCIARCHIVE=${{ env.CHUNKAH_TMP_OCIARCHIVE }}
NODEJS_VERSION=${{ env.NODEJS_VERSION }}
ANTORA_VERSION=${{ steps.antora-version.outputs.version }}
PLAYBOOK_PATH=${{ env.PLAYBOOK_PATH }}
IMAGE_TITLE=${{ env.IMAGE_TITLE }}
IMAGE_DESCRIPTION=${{ env.IMAGE_DESCRIPTION }}
IMAGE_SOURCE=${{ env.IMAGE_SOURCE }}
IMAGE_LICENSES=${{ env.IMAGE_LICENSES }}
QUAY_EXPIRES_AFTER=${{ env.QUAY_EXPIRES_AFTER }}
extra-args: |
--no-cache
--skip-unused-stages=false
--volume /tmp:/tmp
- name: "Login to Container Registry"
uses: https://github.com/redhat-actions/podman-login@v2
# if: (forgejo.event_name == 'push' || forgejo.event_name == 'schedule' || forgejo.event_name == 'workflow_dispatch') && forgejo.ref == 'refs/heads/main'
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.BOT_USERNAME }}
password: ${{ secrets.BOT_SECRET }}
auth_file_path: /tmp/auth.json
- name: "Push to Container Registry"
uses: https://github.com/redhat-actions/push-to-registry@v3
id: "push"
# if: (forgejo.event_name == 'push' || forgejo.event_name == 'schedule' || forgejo.event_name == 'workflow_dispatch') && forgejo.ref == 'refs/heads/main'
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.BOT_USERNAME }}
password: ${{ secrets.BOT_SECRET }}
image: ${{ env.IMAGE }}
tags: ${{ env.TAGS }}
extra-args: |
--compression-format=zstd
--compression-level=22
- name: "Setup cosign"
uses: https://github.com/sigstore/cosign-installer@v3.10.0
# if: (forgejo.event_name == 'push' || forgejo.event_name == 'schedule' || forgejo.event_name == 'workflow_dispatch') && forgejo.ref == 'refs/heads/main'
- name: "Sign container image"
# if: (forgejo.event_name == 'push' || forgejo.event_name == 'schedule' || forgejo.event_name == 'workflow_dispatch') && forgejo.ref == 'refs/heads/main'
run: |
cosign sign --yes --recursive --key env://COSIGN_PRIVATE_KEY ${{ env.REGISTRY }}/${{ env.IMAGE }}@${{ steps.push.outputs.digest }}
env:
COSIGN_EXPERIMENTAL: false
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
COSIGN_PASSWORD: ""

6
.gitignore vendored Normal file
View file

@ -0,0 +1,6 @@
build
public
cache
build-scripts/output
node_modules

74
README.md Normal file
View file

@ -0,0 +1,74 @@
# Fedora Docs Build Repository
> [!WARNING]
> This is an experimental repository for testing.<br />
> Expect force pushes and rebases.
This is the build repository for the Fedora Documentation Website. Fedora Docs are built using [Antora](https://antora.org/). The repository CI builds the following container images:
- **quay.io/fedora-docs/buildroot:latest**<br />
The image is built daily and is used in the Fedora Forge runner to build the other images.
- **quay.io/fedora-docs/antora:latest**<br />
The image is built daily. It contains the Antora application and is used in the `docsbuilder.sh` script.
- **quay.io/fedora-docs/council-docs-test:latest**<br />
The image is built hourly. It contains the generated English Fedora Docs site and can be previewed by following the instructions in the [Previewing the site](#previewing-the-site) section.
## Prerequisites
- [**Podman**](https://podman.io/) (for container operations)
- [**`just`**](https://just.systems/) (command runner)
## Verifying the images
The images are signed using Cosign and can be verified by running the following command:
```text
just verify quay.io/fedora-docs/antora:latest
```
To verify another image, replace `quay.io/fedora-docs/antora:latest` in the above command with any other image in the [Fedora Docs](https://quay.io/organization/fedora-docs) organization.
## Testing changes locally
### Building the site
The following command builds the English documentation container image using the specified playbook file (defaults to `site.yml`).
```text
just build ./site-council-docs-test.yaml
```
> [!NOTE]
> Rebuilding all the languages locally may take hours and result in a large container image.
> [!NOTE]
> The container build process uses multiple build stages, which can leave behind dangling images on your system. To clean these up, run:
> ```text
> just cleanup
> ```
> The above command removes unused images and build cache, then displays the first 21 images on your system.
### Previewing the site
The following command runs the built container image and exposes the documentation site at http://localhost:8080 for local testing.
```text
just preview
```
## Documentation content
Documentation content is stored in multiple repositories listed in the `site.yml` file.
## Project Plan
See the Project Board at the [Documentation Team](https://forge.fedoraproject.org/docs/-/projects).
## Reporting issues
Please report general issues and submit pull requests for publishing fixes here.
## Contributing
Want to contribute? [Learn about contributing to the Fedora Docs](https://docs.fedoraproject.org/en-US/fedora-docs/).

20
_l10n/first_time_make_pot.sh Executable file
View file

@ -0,0 +1,20 @@
#!/bin/bash
dir="modules" # no trailing slash
for file in $( find -L $dir -name "*.adoc" ); do
basename=`basename -s .adoc $file`
dirname=`dirname $file`
path=`echo ${dirname#$dir/}`
mkdir -p pot/$path
if [ "$dirname" = "$dir" ]; then
potname=$basename.pot
else
potname=$path/$basename.pot
fi
echo po4a-gettextize -f asciidoc -m $file -p pot/$potname --master-charset "UTF-8" -o debug split_attributelist
PERLLIB=~/Repositories/po4a/po4a/lib po4a-gettextize -f asciidoc -m $file -p pot/$potname --master-charset "UTF-8" -o debug split_attributelist
done
#echo po4a-gettextize -f yaml -o keys=Name -m ../_topic_map.yml -p pot/_topic_map.yml.pot --master-charset "UTF-8"
#PERLLIB=~/Repositories/po4a/po4a/lib po4a-gettextize -f yaml -o keys=Name -m ../_topic_map.yml -p pot/_topic_map.yml.pot --master-charset "UTF-8"

24
_l10n/use_pot.sh Executable file
View file

@ -0,0 +1,24 @@
#!/bin/bash
lang=$1
dir="modules" # no trailing slash
for file in $( find -L $dir -name "*.adoc" ); do
basename=`basename -s .adoc $file`
dirname=`dirname $file`
path=`echo ${dirname#$dir/}`
if [ "$dirname" = "$dir" ]; then
potname=$basename
else
potname=$path/$basename
fi
if [ -e po/$potname.$lang.po ]; then
echo po4a-translate -f asciidoc -m $file -p po/$potname.$lang.po --master-charset "UTF-8" --localized-charset "UTF-8" -l $file -o debug split_attributelist -k 0
PERLLIB=~/Repositories/po4a/po4a/lib po4a-translate -f asciidoc -m $file -p po/$potname.$lang.po --master-charset "UTF-8" --localized-charset "UTF-8" -l $file -o debug split_attributelist -k 0
fi
done
#if [ -e po/_topic_map.yml.$lang.po ]; then
# echo po4a-translate -f yaml -o keys=Name -m ../_topic_map.yml -p po/_topic_map.yml.$lang.po --master-charset "UTF-8" --localized-charset "UTF-8" -l ../_topic_map.yml -k 0
# PERLLIB=../../po4a/lib po4a-translate -f yaml -o keys=Name -m ../_topic_map.yml -p po/_topic_map.yml.$lang.po --master-charset "UTF-8" --localized-charset "UTF-8" -l ../_topic_map.yml -k 0
#fi

12
_l10n/zanata.xml Normal file
View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<config xmlns="http://zanata.org/namespace/config/">
<url>https://fedora.zanata.org/</url>
<project>fedora-docs-system-adminstration-guide</project>
<project-version>master</project-version>
<project-type>gettext</project-type>
<src-dir>pot/</src-dir>
<trans-dir>./po/</trans-dir>
<rules>
<rule>{path}/{filename}.{locale}.po</rule>
</rules>
</config>

View file

@ -0,0 +1,93 @@
# SPDX-FileCopyrightText: Fedora Docs maintainers
# SPDX-License-Identifier: MIT
ARG BASEIMAGE_REPO=overridden
ARG BASEIMAGE_TAG=overridden
ARG CHUNKAH_REPO=overridden
ARG CHUNKAH_TAG=overridden
ARG CHUNKAH_TMP_OCIARCHIVE=overridden
FROM ${BASEIMAGE_REPO}:${BASEIMAGE_TAG} AS antora
ARG NODEJS_VERSION=overridden
ENV NODEJS_VERSION=${NODEJS_VERSION}
ARG ANTORA_VERSION=overridden
ENV ANTORA_VERSION=${ANTORA_VERSION}
# Install the required packages
RUN --mount=type=cache,rw,target=/cache \
--mount=type=cache,dst=/var/cache/dnf \
--mount=type=cache,dst=/var/cache/libdnf5 \
<<EORUN
set -euo pipefail
set -x
export FORCE_COLUMNS=134
rm --force /etc/yum.repos.d/fedora-cisco-openh264.repo
dnf upgrade --assumeyes --refresh --no-allow-downgrade \
--allowerasing
dnf --refresh install --assumeyes --allowerasing \
--no-allow-downgrade --no-docs --setopt=tsflags=nodocs \
--setopt=install_weak_deps=False --best \
--exclude container-selinux \
nodejs${NODEJS_VERSION}-npm
dnf clean all
rm --recursive --force /tmp/* /var/lib/dnf/* /var/cache/dnf/* /var/log/*
npm install \
--global \
@antora/cli@${ANTORA_VERSION} \
@antora/site-generator@${ANTORA_VERSION} \
@antora/lunr-extension \
cheerio \
@asciidoctor/tabs
npm cache clean --force
EORUN
# Rechunk
# - Use more layers (128)
FROM ${CHUNKAH_REPO}:${CHUNKAH_TAG} AS chunkah
ARG CHUNKAH_TMP_OCIARCHIVE=overridden
RUN --mount=from=antora,src=/,target=/chunkah,ro \
--mount=type=bind,target=/run/src,rw \
chunkah build \
--verbose \
--skip-special-files \
--max-layers 128 \
--output oci:${CHUNKAH_TMP_OCIARCHIVE}
# Create the final image from the rechunked oci-archive
# Redeclare ARG for this stage
ARG CHUNKAH_TMP_OCIARCHIVE=overridden
ARG IMAGE_TITLE=overridden
ARG IMAGE_DESCRIPTION=overridden
ARG IMAGE_SOURCE=overridden
ARG IMAGE_LICENSES=overridden
ARG QUAY_EXPIRES_AFTER=overridden
FROM oci:${CHUNKAH_TMP_OCIARCHIVE}
ARG IMAGE_TITLE=overridden
ARG IMAGE_DESCRIPTION=overridden
ARG IMAGE_SOURCE=overridden
ARG IMAGE_LICENSES=overridden
ARG QUAY_EXPIRES_AFTER=overridden
LABEL org.opencontainers.image.title="${IMAGE_TITLE}"
LABEL org.opencontainers.image.description="${IMAGE_DESCRIPTION}"
LABEL org.opencontainers.image.source="${IMAGE_SOURCE}"
LABEL org.opencontainers.image.licenses="${IMAGE_LICENSES}"
LABEL quay.expires-after="${QUAY_EXPIRES_AFTER}"
ENV NODE_PATH=/usr/local/lib/node_modules
WORKDIR /antora
ENTRYPOINT ["antora", "--stacktrace"]

15
build-scripts/Dockerfile Normal file
View file

@ -0,0 +1,15 @@
FROM registry.fedoraproject.org/fedora-minimal:42
RUN microdnf -y install --setopt=install_weak_deps=False \
nodejs-npm git python3-yaml && \
microdnf clean all
RUN npm i -g @antora/cli@3.1 @antora/site-generator@3.1 @antora/lunr-extension@1.0.0-alpha.8 cheerio @asciidoctor/tabs
ENV NODE_PATH=/usr/local/lib/node_modules
ADD rebuild-site.py /antora/rebuild-site.py
WORKDIR /antora
CMD /antora/rebuild-site.py

7
build-scripts/README.md Normal file
View file

@ -0,0 +1,7 @@
# Building the docs
This script is used in OpenShift to rebuild the whole site for Fedora Docs.
## Local testing
See [README.md](../README.md).

611
build-scripts/rebuild-site.py Executable file
View file

@ -0,0 +1,611 @@
#! /usr/bin/env python3
# The script requires the following environment variables to be set:
#
# Variable Values Effect
# -----------------|-----------------------------------------------------------
# BUILD_ENV prod Build the production version of the site
# using the "prod" branch. DEFAULT
#
# stg Build the staging version of the site
# using the "stg" branch.
# -----------------|-----------------------------------------------------------
# BUILD_LANGS english Build the "en-US" version only. DEFAULT
#
# translated Build only the translated versions.
#
# all Build the "en-US" and the translated versions.
# -----------------|-----------------------------------------------------------
# PLAYBOOK_PATH <path> Path to the Antora playbook file to use
# for building the documentation.
# DEFAULT: site.yml
import tempfile
import yaml
import os
import errno
import subprocess
import copy
import datetime
import time
import shutil
import sys
import glob
import re
def get_config():
config = {}
config["docs_repo_url"] = os.getenv(
"DOCS_REPO_URL",
"https://forge.fedoraproject.org/docs/docs-fp-o.git")
config["docs_repo_branch"] = os.getenv(
"BUILD_ENV",
"prod")
config["playbook_path"] = os.getenv(
"PLAYBOOK_PATH",
None)
config["build_langs"] = os.getenv(
"BUILD_LANGS",
"english")
config["translated_sources_repo_url"] = os.getenv(
"TRANSLATED_SOURCES_REPO_URL",
"https://forge.fedoraproject.org/docs/translated-sources.git"
)
config["translated_adockeywords_repo_url"] = os.getenv(
"TRANSLATED_ADOCKEYWORDS_REPO_URL",
"https://pagure.io/fedora-docs-l10n/asciidoc-keywords.git")
os.environ['CI'] = "true"
return config
def log(msg):
print(msg, flush=True)
def retry_cmd(cmd, retry=3):
""" Run command and retry x time on failure """
while retry > 0:
s = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if s.returncode > 0:
log(s.returncode)
log(s.stdout)
retry -= 1
log(f"{' '.join(cmd)} failed. {retry} tries remaining...")
time.sleep(5)
if retry <= 0:
raise Exception(s.stdout)
else:
break
def get_languages(config):
languages_dict = {}
with tempfile.TemporaryDirectory() as workdir:
translated_sources_repo = os.path.join(workdir, "translated_sources_repo")
subprocess.run(["git", "clone", "--depth=1", config["translated_sources_repo_url"], translated_sources_repo])
languages = []
filename_blacklist = [".git"]
for filename in os.listdir(translated_sources_repo):
filepath = os.path.join(translated_sources_repo, filename)
if os.path.isdir(filepath) and filename not in filename_blacklist:
languages.append(filename)
languages.sort()
for lang in languages:
languages_dict[lang] = []
lang_dir = os.path.join(translated_sources_repo, lang)
for component in os.listdir(lang_dir):
version_dir = os.path.join(lang_dir, component)
for version in os.listdir(version_dir):
start_path = "{lang}/{component}/{version}".format(
lang=lang, component=component, version=version)
# This is a workaround for cases when a component doesn't have
# the ROOT module that should contain the antora.yml.
# Without the ROOT module the translation scripts won't
# pick up the antora.yml causing the docs build to fail.
# So we're only including directories with the antora.yml file.
if "antora.yml" in os.listdir(os.path.join(version_dir, version)):
languages_dict[lang].append(start_path)
return languages_dict
def generate_lang_switch_ui(languages):
template_start = """
<div class="page-languages">
<button class="languages-menu-toggle" title="Show other languages of the site">
{{{env.ANTORA_LANGUAGE}}}
</button>
<div class="languages-menu">
"""
template_end = """
</div>
</div>
"""
template_list = []
template_list.append(template_start)
for language in languages:
link = '<a class="language" href="{{{{siteRootPath}}}}/../{language}{{{{page.url}}}}">{language}</a>'.format(
language=language)
template_list.append(link)
template_list.append(template_end)
return "\n".join(template_list)
def get_metadata_from_branch(branch, repodir):
cmd = f"""
for file in $(git ls-tree -r --name-only origin/{branch}|grep -E "adoc$"); do
git log -1 --format="'$file':%n refs: %S%n hash: %h%n date: %as" origin/{branch} -- $file;
done"""
s = subprocess.run(cmd, shell=True, cwd=repodir, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
return yaml.safe_load(s.stdout)
def prefetch_sources(original_sources, site_yml, config):
if not os.path.isdir(original_sources):
os.mkdir(original_sources)
default_branch = site_yml["content"].get("branches", ["main"])
if type(default_branch) is str:
default_branch = [default_branch]
metadata = {}
for repo_data in site_yml["content"]["sources"]:
gitdir = tempfile.TemporaryDirectory(dir=original_sources)
dirname = gitdir.name
gitdir.cleanup()
log(f"Fetching {repo_data['url']}...")
retry_cmd(["git", "clone", repo_data['url'], dirname])
if re.search(r"://forge.fedoraproject.org", repo_data['url']):
weburl = repo_data['url'].strip('.git')
repo_data['edit_url'] = f"{weburl}/src/branch/{{refname}}/{{path}}"
repo_data['url'] = dirname
branches = repo_data.get("branches", default_branch)
if type(branches) is str:
branches = [branches]
for branch in branches:
y = get_metadata_from_branch(branch, repo_data['url'])
if dirname in metadata:
metadata[dirname][branch] = y
else:
metadata[dirname] = { branch: y }
if metadata:
with open("/tmp/metadata.yml", "w") as f:
yaml.dump(metadata, f)
return site_yml
def prepare_translated_sources(translated_sources, site_yml, languages, config):
with tempfile.TemporaryDirectory() as workdir:
# Location of the translated-sources repo
# (This repo only holds content that has some translations done,
# so it might be incomplete.)
translated_sources_original = os.path.join(workdir, "translated_sources_original")
# Location of the English sources in the same structure
# as translated-sources, so:
# COMPONENT/VERSION/antora.yml
# COMPONENT/VERSION/modules/MODULE1
# COMPONENT/VERSION/modules/MODULE2
# COMPONENT/VERSION/modules/...
en_sources = os.path.join(workdir, "en_sources")
# Clone the original translated-sources
subprocess.run(["git", "clone", "--depth=1", config["translated_sources_repo_url"], translated_sources_original])
# Get a list of the original English repos
repos = []
default_branch = site_yml["content"].get("branches", ["main"])
if type(default_branch) is str:
default_branch = [default_branch]
for repo_data in site_yml["content"]["sources"]:
branches = repo_data.get("branches", default_branch)
if type(branches) is str:
branches = [branches]
start_path = repo_data.get("start_path", "")
for branch in branches:
repo = {}
repo["url"] = repo_data["url"]
repo["branch"] = branch
repo["start_path"] = start_path
repos.append(repo)
# Clome the original English sources and put them into the
# desired structure in en_sources (described above)
components = {}
for repo in repos:
with tempfile.TemporaryDirectory() as tmp_repo_root:
log("")
log("Cloning {url} {branch}".format(url=repo["url"], branch=repo["branch"]))
retry_cmd(["git", "clone", "--branch", repo["branch"], "--depth=1", repo["url"], tmp_repo_root])
repo_dir = os.path.join(tmp_repo_root, repo["start_path"])
antora_yml_file = os.path.join(repo_dir, "antora.yml")
with open(antora_yml_file, "r") as file:
antora_yml = yaml.safe_load(file)
component = antora_yml["name"]
version = antora_yml["version"]
# if component version is null (~), fallback to "main"
if not version:
version = "main"
# Saving components and all their versions
if component not in components:
components[component] = set()
components[component].add(version)
for module in os.listdir(os.path.join(repo_dir, "modules")):
# Now this is looping over modules accross all components,
# so component, module, and version variables are available
try:
os.makedirs(os.path.join(en_sources, component, version, "modules"))
except OSError as e:
if e.errno != errno.EEXIST:
raise
original_module_dir = os.path.join(repo_dir, "modules", module)
module_dir = os.path.join(en_sources, component, version, "modules", module)
subprocess.run(["cp", "-a", original_module_dir, module_dir])
if module == "ROOT" or "nav" in antora_yml:
# if this is the main antora.yml file
subprocess.run(["cp", "-a", antora_yml_file, os.path.join(en_sources, component, version, "antora.yml")])
log("----- copying antora.yml for {component} {module} {version}".format(
component=component, module=module, version=version))
else:
log("----- skipping antora.yml for {component} {module} {version}".format(
component=component, module=module, version=version))
# Set up the language structure in translated_sources
for language in languages:
lang_dir = os.path.join(translated_sources, language)
try:
os.makedirs(lang_dir)
except OSError as e:
if e.errno != errno.EEXIST:
raise
# Copy the English sources in the translated_sources
for language in languages:
lang_dir = os.path.join(translated_sources, language)
for component in components:
en_component_dir = os.path.join(en_sources, component)
subprocess.run(["cp", "-a", en_component_dir, lang_dir])
# And finally copy the original translated sources
# into translated_sources
for language in languages:
src = os.path.join(translated_sources_original, language)
subprocess.run(["cp", "-a", src, translated_sources + "/"])
return components
def prepare_localized_admonitions(languages, config):
""" Asciidoc use keywords for admonitions and others items """
keywords = {}
with tempfile.TemporaryDirectory() as workdir:
translated_keywords_repo = os.path.join(workdir, "asciidoc-keywords")
subprocess.run(["git", "clone", "--depth=1", config["translated_adockeywords_repo_url"], translated_keywords_repo])
languages = []
log(translated_keywords_repo + "/langs/*/asciidoc-attributes.yml")
for filename in glob.glob(translated_keywords_repo + "/langs/*/asciidoc-attributes.yml"):
languages.append(filename.rsplit("/")[::-1][1])
for lang in languages:
file = translated_keywords_repo + "/langs/" + lang + "/asciidoc-attributes.yml"
with open(file, 'r') as stream:
try:
keywords[lang] = yaml.safe_load(stream)
except yaml.YAMLError as exc:
print(exc)
return keywords
def init_git_repo(path):
try:
os.makedirs(path)
except OSError as e:
if e.errno != errno.EEXIST:
raise
subprocess.run(["git", "init"], cwd=path)
subprocess.run(["git", "config", "user.name", "Your Name"], cwd=path)
subprocess.run(["git", "config", "user.email", "you@example.com"], cwd=path)
subprocess.run(["git", "commit", "--allow-empty", "-m", "init"], cwd=path)
def get_version_from_file(index_file):
latest = None
if os.path.isfile(index_file):
with open(index_file, 'r') as f:
for l in f:
m = re.search(r'data-version="(f\d+)"', l)
if m:
latest = m[1]
break
return latest
def gen_redirect(lang, results_dir):
htaccess = os.path.join(results_dir, ".htaccess")
latest = get_version_from_file(f"{results_dir}/fedora/latest/index.html")
if latest:
htaccess_content = f"""
ErrorDocument 404 /{lang}/404.html
Redirect 302 /{lang}/fedora/{latest} /{lang}/fedora/latest
"""
with open(htaccess, "w") as file:
file.write(htaccess_content)
def main():
config = get_config()
with tempfile.TemporaryDirectory() as workdir:
#####--------------------------------------#####
##### Preparation #####
#####--------------------------------------#####
# Location of the docs-fp-o repo
# docs_repo = os.path.join(workdir, "docs_repo")
docs_repo = "/antora"
# Location of the translated sources used for the build
# (That's the translated-sources repo with the missing files added
# from the English sources.)
translated_sources = os.path.join(workdir, "translated_sources")
init_git_repo(translated_sources)
log("")
log("===== Getting the site definition (site.yml) =====")
# Use local playbook if PLAYBOOK_PATH is set, otherwise clone
if config.get("playbook_path"):
# Load from provided playbook path
log(f"Loading playbook from: {config['playbook_path']}")
with open(config["playbook_path"], "r") as file:
original_site_yml = yaml.safe_load(file)
else:
# Clone and load from repo
subprocess.run(["git", "clone", "--branch", config["docs_repo_branch"], "--depth=1", config["docs_repo_url"], docs_repo])
with open(os.path.join(docs_repo, "site.yml"), "r") as file:
original_site_yml = yaml.safe_load(file)
log("")
log("===== Getting a list of languages =====")
languages = get_languages(config)
log(" Languages: {}".format(" ".join(languages)))
log("")
log("===== Generating the language switch UI =====")
lang_switch_ui = generate_lang_switch_ui(["en-US"] + list(languages.keys()))
ui_dir = os.path.join(docs_repo, "supplemental-ui", "partials")
try:
os.makedirs(ui_dir)
except OSError as e:
if e.errno != errno.EEXIST:
raise
ui_file = os.path.join(ui_dir, "page-languages.hbs")
with open(ui_file, "w") as file:
file.write(lang_switch_ui)
# Timestamp to be included in the footer of the docs
timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S UTC')
antora_env = copy.deepcopy(os.environ)
antora_env["ANTORA_DATE"] = timestamp
#####--------------------------------------#####
##### English site build #####
#####--------------------------------------#####
if config["build_langs"] == "english" or config["build_langs"] == "all":
log("")
log("===== Prefetching all components =====")
original_sources = os.path.join(workdir, "orginal_sources")
site_local = prefetch_sources(original_sources, original_site_yml, config)
log(original_site_yml["content"]["sources"][0]['url'])
log(site_local["content"]["sources"][0]['url'])
filename = os.path.join(docs_repo, "site-local.yml")
with open(filename, "w") as file:
file.write(yaml.dump(site_local))
log("")
log("===== Building the en-US site =====")
antora_env["ANTORA_LANGUAGE"] = "en-US"
# result = subprocess.run(["antora", "--html-url-extension-style=indexify", os.path.join(docs_repo, "site.yml")], env=antora_env)
result = subprocess.run(["antora", "--extension=lunr", filename], env=antora_env)
if result.returncode != 0:
log("ERROR building the en-US site")
sys.exit(1)
log("")
log("===== Copying the en-US site =====")
source_dir = os.path.join(docs_repo, "public")
target_dir_copying = "/antora/output/en-US.building"
target_dir_copied = "/antora/output/en-US.building/en-US"
target_dir_final = "/antora/output/en-US"
# Generate htaccess for redirect
gen_redirect("en-US", os.path.join(source_dir, "en-US"))
shutil.rmtree(target_dir_copying, ignore_errors=True)
subprocess.run(["cp", "-a", source_dir, target_dir_copying])
shutil.rmtree(target_dir_final, ignore_errors=True)
shutil.move(target_dir_copied, target_dir_final)
shutil.rmtree(target_dir_copying, ignore_errors=True)
log("")
log("===== Copying the index.html =====")
source_index_html = os.path.join(docs_repo, "static", "index.html")
target_index_html = "/antora/output/index.html"
shutil.copy(source_index_html, target_index_html)
#####--------------------------------------#####
##### Translated site build #####
#####--------------------------------------#####
if config["build_langs"] == "translated" or config["build_langs"] == "all":
log("")
log("===== Preparing the translated sources =====")
components = prepare_translated_sources(translated_sources, original_site_yml, languages, config)
log("")
log("===== Preparing the translated ascidoc keywords =====")
keywords = prepare_localized_admonitions(languages, config)
log("")
log("===== Generating site.lang.yml files =====")
for lang in languages:
lang_site_yml = copy.deepcopy(original_site_yml)
lang_site_yml["output"]["dir"] = "./public/{lang}".format(lang=lang)
lang_site_yml["content"] = {}
# Branches are set to HEAD because the script uses a locally-generated
# content on top of the original translated-sources repo
lang_site_yml["content"]["branches"] = "HEAD"
# disable the "Edit this Page"
lang_site_yml["content"]["edit_url"] = False
lang_site_yml["content"]["sources"] = []
for component, versions in components.items():
for version in versions:
source = {}
source["url"] = translated_sources
source["start_path"] = "{lang}/{component}/{version}".format(
lang=lang, component=component, version=version)
lang_site_yml["content"]["sources"].append(source)
if lang in keywords:
if "attributes" in lang_site_yml["asciidoc"]:
lang_site_yml["asciidoc"]["attributes"].append(keywords[lang])
else:
lang_site_yml["asciidoc"]["attributes"] = keywords[lang]
# disable page-last-update extension
if "antora" in lang_site_yml and "extensions" in lang_site_yml["antora"]:
for ext in lang_site_yml["antora"]["extensions"]:
if 'id' in ext and ext['id'] == "page-last-update":
ext['enabled'] = False
# don't pull ui-bundle (use cache)
lang_site_yml["runtime"]["fetch"] = False
filename = os.path.join(docs_repo, "site-{lang}.yml".format(lang=lang))
with open(filename, "w") as file:
file.write(yaml.dump(lang_site_yml))
log(" {lang} done".format(lang=lang))
# Building all the translated sites
lastlang = list(languages)[-1]
for lang in languages:
log("")
log("===== Building the {lang} site =====".format(lang=lang))
filename = "site-{lang}.yml".format(lang=lang)
antora_env["ANTORA_LANGUAGE"] = lang
result = subprocess.run(["antora", "--extension=lunr", os.path.join(docs_repo, filename)], env=antora_env)
if result.returncode != 0:
log("ERROR building the {lang} site".format(lang=lang))
sys.exit(1)
# Copying the translated site
log("")
log(f"=== Copying the {lang} site ===")
results_dir = os.path.join(docs_repo, "public", lang)
publish_dir = f"/antora/output/{lang}"
copying_dir = f"/antora/output/{lang}.tmp"
lastlang_dir = f"/antora/output/{lastlang}"
# I have:
# docs_repo/public/xx <- results_dir (local partition)
# /antora/output/xx.tmp <- copying_dir (mounted partition)
# /antora/output/xx <- publish_dir (mounted partition)
#
# I need to:
# 1/ copy from local to mounted
# 2/ remove old in mounted
# 3/ move new within mounted
# 4/ remove the copying dir
# Generate htaccess for redirect
gen_redirect(lang, results_dir)
# Make sure copying_dir doesn't exist
shutil.rmtree(copying_dir, ignore_errors=True)
# Copy results from local partition to a mounted partition
log(f"Copying from {results_dir} to {copying_dir}")
subprocess.run(["cp", "-a", results_dir, copying_dir])
# Swap the old tree for the new one for each language
log(f"Moving language to the final place: {copying_dir} to {publish_dir}")
shutil.rmtree(publish_dir, ignore_errors=True)
subprocess.run(["mv", copying_dir, publish_dir])
# Recreate hardlinks as we go, in case the rsync job
# start while we are still building
if (lang != lastlang):
log(f"hardlinking files: {publish_dir} - {lastlang_dir}")
subprocess.run(["hardlink", "-cv", publish_dir, lastlang_dir])
# Remove local build
shutil.rmtree(results_dir, ignore_errors=True)
# End Building all the translated sites
# https://pagure.io/fedora-infrastructure/issue/8964
log("Consolidate files with hardlink...")
subprocess.run(["hardlink", "-cv", "/antora/output/"])
log("DONE!")
if __name__ == "__main__":
main()

View file

@ -0,0 +1,157 @@
# SPDX-FileCopyrightText: Fedora Docs maintainers
# SPDX-License-Identifier: MIT
ARG BASEIMAGE_REPO=overridden
ARG BASEIMAGE_TAG=overridden
ARG CHUNKAH_REPO=overridden
ARG CHUNKAH_TAG=overridden
ARG CHUNKAH_TMP_OCIARCHIVE=overridden
FROM ${BASEIMAGE_REPO}:${BASEIMAGE_TAG} AS builder
ARG PLAYBOOK_PATH=${PLAYBOOK_PATH}
ENV PLAYBOOK_PATH=${PLAYBOOK_PATH}
ARG NODEJS_VERSION=${NODEJS_VERSION}
ENV NODEJS_VERSION=${NODEJS_VERSION}
ARG ANTORA_VERSION=${ANTORA_VERSION}
ENV ANTORA_VERSION=${ANTORA_VERSION}
# Install required packages
RUN --mount=type=cache,rw,target=/cache \
--mount=type=cache,dst=/var/cache/dnf \
--mount=type=cache,dst=/var/cache/libdnf5 \
<<EORUN
set -euo pipefail
set -x
export FORCE_COLUMNS=134
rm --force /etc/yum.repos.d/fedora-cisco-openh264.repo
dnf upgrade --assumeyes --refresh --no-allow-downgrade \
--allowerasing
dnf --refresh install --assumeyes --allowerasing \
--no-allow-downgrade --no-docs --setopt=tsflags=nodocs \
--setopt=install_weak_deps=False --best \
--exclude container-selinux \
nodejs${NODEJS_VERSION}-npm \
git-core \
python3-pyyaml
dnf clean all
# rm --recursive --force /tmp/* /var/lib/dnf/* /var/cache/dnf/* /var/log/*
rm --recursive --force /var/lib/dnf/* /var/cache/dnf/* /var/log/*
npm install \
--global \
@antora/cli@${ANTORA_VERSION} \
@antora/site-generator@${ANTORA_VERSION} \
@antora/lunr-extension \
cheerio \
@asciidoctor/tabs
npm cache clean --force
mkdir --parents /antora/output
EORUN
ENV NODE_PATH=/usr/local/lib/node_modules
COPY build-scripts/rebuild-site.py /antora/rebuild-site.py
COPY ${PLAYBOOK_PATH} /antora/${PLAYBOOK_PATH}
COPY lib /antora/lib
COPY static /antora/static
COPY supplemental-ui /aantora/supplemental-ui
WORKDIR /antora
# ENTRYPOINT ["antora", "--stacktrace"]
# CMD /antora/rebuild-site.py
RUN /antora/rebuild-site.py
FROM ${BASEIMAGE_REPO}:${BASEIMAGE_TAG} AS docs
# Install required packages
RUN --mount=type=cache,rw,target=/cache \
--mount=type=cache,dst=/var/cache/dnf \
--mount=type=cache,dst=/var/cache/libdnf5 \
<<EORUN
set -euo pipefail
set -x
export FORCE_COLUMNS=134
rm --force /etc/yum.repos.d/fedora-cisco-openh264.repo
dnf upgrade --assumeyes --refresh --no-allow-downgrade \
--allowerasing
dnf --refresh install --assumeyes --allowerasing \
--no-allow-downgrade --no-docs --setopt=tsflags=nodocs \
--setopt=install_weak_deps=False --best \
--exclude container-selinux \
nginx
dnf clean all
# rm --recursive --force /tmp/* /var/lib/dnf/* /var/cache/dnf/* /var/log/*
rm --recursive --force /var/lib/dnf/* /var/cache/dnf/* /var/log/*
# Create log directories and symlink to stdout/stderr
mkdir --parents /var/log/nginx
ln --symbolic /dev/stdout /var/log/nginx/access.log
ln --symbolic /dev/stderr /var/log/nginx/error.log
EORUN
# Copy the nginx configuration
COPY build-site-container/nginx.conf /etc/nginx/nginx.conf
# Copy the built site from builder stage to nginx document root
COPY --from=builder /antora/output/en-US /usr/share/nginx/html
COPY build-site-container/run.sh /usr/bin/
# Rechunk
# - Use more layers (128)
FROM ${CHUNKAH_REPO}:${CHUNKAH_TAG} AS chunkah
ARG CHUNKAH_TMP_OCIARCHIVE=overridden
RUN --mount=from=docs,src=/,target=/chunkah,ro \
--mount=type=bind,target=/run/src,rw \
chunkah build \
--verbose \
--skip-special-files \
--max-layers 128 \
--output oci:${CHUNKAH_TMP_OCIARCHIVE}
# Create the final image from the rechunked oci-archive
# Redeclare ARG for this stage
ARG CHUNKAH_TMP_OCIARCHIVE=overridden
ARG IMAGE_TITLE=overridden
ARG IMAGE_DESCRIPTION=overridden
ARG IMAGE_SOURCE=overridden
ARG IMAGE_LICENSES=overridden
ARG QUAY_EXPIRES_AFTER=overridden
FROM oci:${CHUNKAH_TMP_OCIARCHIVE}
ARG IMAGE_TITLE=overridden
ARG IMAGE_DESCRIPTION=overridden
ARG IMAGE_SOURCE=overridden
ARG IMAGE_LICENSES=overridden
ARG QUAY_EXPIRES_AFTER=overridden
LABEL org.opencontainers.image.title="${IMAGE_TITLE}"
LABEL org.opencontainers.image.description="${IMAGE_DESCRIPTION}"
LABEL org.opencontainers.image.source="${IMAGE_SOURCE}"
LABEL org.opencontainers.image.licenses="${IMAGE_LICENSES}"
LABEL quay.expires-after="${QUAY_EXPIRES_AFTER}"
EXPOSE 80
STOPSIGNAL SIGQUIT
ENTRYPOINT ["run.sh"]

View file

@ -0,0 +1,39 @@
daemon off;
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 4096;
server {
listen 80 default_server;
listen [::]:80 default_server;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
}

14
build-site-container/run.sh Executable file
View file

@ -0,0 +1,14 @@
#! /usr/bin/env bash
set -euo pipefail
# set -x
main() {
echo -e "\nThe Fedora Docs site preview is available at http://localhost:8080\n"
echo -e "To exit the preview, press Ctrl+C.\n"
exec nginx
}
main "${@}"

4
docs-fp-o.pub Normal file
View file

@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEk8TxLQwNLG42J26YHlA+plNMOKli
lEP2oy2V6WkfX0Km63gA9ftvyl4eHX/G6mxjjA2dwUj+3Oc7LwMgozMmMA==
-----END PUBLIC KEY-----

166
justfile Normal file
View file

@ -0,0 +1,166 @@
baseiamge_repo := "quay.io/fedora/fedora-minimal"
baseiamge_tag := "44"
target_repo := "quay.io/fedora-docs/council-docs-test"
target_tag := "latest"
target_image := target_repo + ":" + target_tag
chunkah_repo := "quay.io/coreos/chunkah"
chunkah_tag := "dev"
chunkah_tmp_ociarchive := "/tmp/chunkah"
containerfile := "./build-site-container/Containerfile"
nodejs_version := "24"
org_opencontainers_image_title := "Fedora Docs"
org_opencontainers_image_description := "Container image for testing the Fedora Council Docs"
org_opencontainers_image_source := "https://forge.fedoraproject.org/docs/docs-fp-o"
org_opencontainers_image_licenses := "MIT"
quay_expires_after := "4w"
all:
@echo "Please read README.md"
# Verify container image
verify image:
#! /usr/bin/env bash
set -euo pipefail
# set -x
export FORCE_COLUMNS=134
function main() {
local -r cosign_image="ghcr.io/sigstore/cosign/cosign:latest"
# local -r cosign_image="ghcr.io/sigstore/cosign/cosign:latest-dev"
# local -r cosign_image="ghcr.io/sigstore/cosign/cosign:unstable"
# local -r cosign_image="ghcr.io/sigstore/cosign/cosign:unstable-dev"
# local -r cosign_image="ghcr.io/sigstore/cosign/cosign:v3.0.2"
local -r key="https://forge.stg.fedoraproject.org/playground/docs-fp-o-ci-test/raw/branch/main/docs-fp-o.pub"
function cosign() {
podman container run \
--pull newer \
--rm \
--interactive \
--tty \
--name cosign \
${cosign_image} \
"${@}"
}
# Verify Cosign in container image
# See https://docs.sigstore.dev/cosign/system_config/installation/#verify-cosign-in-container-image
echo -e "\n Verifying Cosign in ${cosign_image} container image... \n"
cosign verify ${cosign_image} \
--certificate-identity keyless@projectsigstore.iam.gserviceaccount.com \
--certificate-oidc-issuer https://accounts.google.com
if ! [[ {{image}} =~ ^localhost/.* ]]; then
echo -e "\nVerifying {{image}}..."
cosign verify --key ${key} {{image}}
echo -e "\n"
fi
}
main "${@}"
# Build container image
build playbook="":
#! /bin/env bash
set -euo pipefail
# set -x
export FORCE_COLUMNS=134
function main() {
# Determine latest Antora version
local -r ANTORA_VERSION=$(curl --silent \
"https://gitlab.com/api/v4/projects/4180516/repository/tags?order_by=updated&sort=desc&per_page=1" |\
jq --raw-output '.[].name[1:]')
# Conditional PLAYBOOK_PATH environment variable
local playbook_env=""
if [[ -n "{{playbook}}" ]]; then
playbook_env="--env PLAYBOOK_PATH={{playbook}}"
fi
# Cleanup
function cleanup() {
rm --recursive --force {{chunkah_tmp_ociarchive}}
}
trap 'cleanup' EXIT
podman image build \
--pull=newer \
--no-cache \
--cap-add sys_admin \
--security-opt label=type:unconfined_t \
${playbook_env} \
--env NODEJS_VERSION="{{nodejs_version}}" \
--env ANTORA_VERSION="${ANTORA_VERSION}" \
--build-arg BASEIMAGE_REPO="{{baseiamge_repo}}" \
--build-arg BASEIMAGE_TAG="{{baseiamge_tag}}" \
--build-arg CHUNKAH_REPO="{{chunkah_repo}}" \
--build-arg CHUNKAH_TAG="{{chunkah_tag}}" \
--build-arg CHUNKAH_TAG="{{chunkah_tag}}" \
--build-arg CHUNKAH_TMP_OCIARCHIVE="{{chunkah_tmp_ociarchive}}" \
--build-arg IMAGE_TITLE="{{org_opencontainers_image_title}}" \
--build-arg IMAGE_DESCRIPTION="{{org_opencontainers_image_description}}" \
--build-arg IMAGE_SOURCE="{{org_opencontainers_image_source}}" \
--build-arg IMAGE_LICENSES="{{org_opencontainers_image_licenses}}" \
--build-arg QUAY_EXPIRES_AFTER="{{quay_expires_after}}" \
--skip-unused-stages=false \
--volume ${PWD}:/run/src \
--volume /tmp:/tmp \
--tag "{{target_image}}" \
--file "{{containerfile}}" \
.
just list
}
main "${@}"
# Preview site
preview:
#! /usr/bin/env bash
set -euo pipefail
# set -x
export FORCE_COLUMNS=134
function main() {
podman container run \
--pull=newer \
--rm \
--interactive \
--tty \
--name fedora-docs \
--publish 8080:80 \
{{target_image}}
}
main "${@}"
# List first 21 images in local storage
list:
#! /usr/bin/env bash
set -euo pipefail
# set -x
export FORCE_COLUMNS=134
function main() {
podman images --all | \
head --lines=21 || \
[[ ${PIPESTATUS[0]} -eq 141 ]] && \
true || false
}
main "${@}"
# Prune unused images and list first 21 images
cleanup:
#! /usr/bin/env bash
set -euo pipefail
# set -x
export FORCE_COLUMNS=134
function main() {
podman image prune --external --force
podman image prune --build-cache --force
just list
}
main "${@}"

View file

@ -0,0 +1,39 @@
const DEFAULT_PACKAGE_URL_FORMAT = 'https://apps.fedoraproject.org/packages/%s'
/**
* Adds an AsciiDoc inline macro named package that provides a shorthand syntax for linking to the
* page on Fedora apps for the specified Fedora package.
*
* This macro produces links that use the base URL https://apps.fedoraproject.org/packages by
* default. That URL can be overridden by defining the document attribute named
* uri-package-url-format. The %s token in the value of that attribute gets replaced by the name of
* the package.
*
* Example:
*
* package:asciidoctor[]
*
* @author Dan Allen <dan.j.allen@gmail.com>
*/
const PackageInlineMacro = (() => {
const superclass = Opal.module(null, 'Asciidoctor').Extensions.InlineMacroProcessor
const scope = Opal.klass(Opal.module(null, 'Antora'), superclass, 'PackageInlineMacro', function () {})
Opal.defn(scope, '$initialize', function initialize (name, config) {
Opal.send(this, Opal.find_super_dispatcher(this, 'initialize', initialize), [name, config])
})
Opal.defn(scope, '$process', function (parent, target, attrs) {
const format = parent.getDocument().getAttribute('url-package-url-format', DEFAULT_PACKAGE_URL_FORMAT)
const url = format.replace('%s', target)
const content = target
const attributes = Opal.hash2(['window'], { window: '_blank' })
return this.createInline(parent, 'anchor', content, { type: 'link', target: url, attributes })
})
return scope
})()
module.exports.register = (registry) => {
registry.inlineMacro(PackageInlineMacro.$new('package', Opal.hash()))
}

View file

@ -0,0 +1,38 @@
module.exports.register = function () {
this.on('contentClassified', async ({ contentCatalog }) => {
const logger = this.require('@antora/logger').get('page-last-update')
const yaml = this.require('js-yaml')
const path = this.require('path')
const fs = this.require('fs')
const pages = contentCatalog.findBy({ family: 'page' })
const pageRx = new RegExp('modules/[^/]+/pages/(?:.+/)*[^.].*\.adoc$')
if (fs.existsSync("/tmp/metadata.yml")) {
let data = fs.readFileSync("/tmp/metadata.yml", "utf-8")
let y = yaml.loadAll(data)
for (const page of pages) {
if (page.src.origin.type == "git" && pageRx.test(page.src.path)) {
const relpath = path.join(page.src.origin.startPath, page.src.path)
const abspath = page.src.origin.gitdir.replace(/\/\.git$/, "")
// logger.warn(abspath)
const contents = page.contents.toString('utf-8')
const branch = page.src.origin.branch
if (abspath in y[0] && branch in y[0][abspath] && relpath in y[0][abspath][branch]) {
let last_update = y[0][abspath][branch][relpath]["date"].toISOString().split('T')[0]
logger.warn({name: relpath, rev: branch, update: last_update})
// Inject attribute in page content
const patchedContents = ":page-last-updated: " + last_update + "\n" + contents
page.contents = Buffer.from(patchedContents)
}
}
}
} else {
logger.warn("no git metadata found, skipping...")
}
this.updateVariables({ contentCatalog })
})
}

View file

@ -0,0 +1,47 @@
'use strict'
const createPage = (category, pages, asciidocConfig) => {
const attributes = {
...asciidocConfig.attributes,
'page-layout': 'category',
'page-category': category,
'page-category-pages': pages,
'page-breadcrumb': category
}
return {
title: `Category ${category}`,
asciidoc: {
attributes
},
src: {
component: 'quick-docs',
version: 'master',
module: 'ROOT',
family: 'page',
relative: `categories/${category}.adoc`,
stem: category,
mediaType: 'text/asciidoc'
}
}
}
function generate (pages, asciidocConfig) {
const pagesPerCategory = pages
.filter((page) => page.asciidoc && page.asciidoc.attributes && page.asciidoc.attributes.category)
.reduce((acc, page) => {
// category must be a single value
const category = page.asciidoc.attributes.category.split(',')[0].trim().toLowerCase()
let pages
if (category in acc) {
pages = acc[category]
} else {
pages = []
acc[category] = pages
}
pages.push(page)
return acc
}, {})
return Object.entries(pagesPerCategory).map(([category, associatedPages]) => createPage(category, associatedPages, asciidocConfig))
}
module.exports = generate

View file

@ -0,0 +1,49 @@
'use strict'
const createPage = (tag, pages, asciidocConfig) => {
const attributes = {
...asciidocConfig.attributes,
'page-layout': 'category',
'page-tag': tag,
'page-tag-pages': pages,
'page-breadcrumb': tag,
}
return {
title: `Tag ${tag}`,
asciidoc: {
attributes
},
src: {
component: 'quick-docs',
version: 'master',
module: 'ROOT',
family: 'page',
relative: `tags/${tag}.adoc`,
stem: tag,
mediaType: 'text/asciidoc'
}
}
}
function generate (pages, asciidocConfig) {
const pagesPerTag = pages
.filter((page) => page.asciidoc && page.asciidoc.attributes && page.asciidoc.attributes.tags)
.reduce((acc, page) => {
const tagsAttribute = page.asciidoc.attributes.tags
const tags = tagsAttribute.trim().split(',').map((value) => value.trim().toLowerCase()).filter((value) => value !== '')
for (const tag of tags) {
let pages
if (tag in acc) {
pages = acc[tag]
} else {
pages = []
acc[tag] = pages
}
pages.push(page)
}
return acc
}, {})
return Object.entries(pagesPerTag).map(([tag, associatedPages]) => createPage(tag, associatedPages, asciidocConfig))
}
module.exports = generate

View file

@ -0,0 +1,28 @@
'use strict'
const name = "qd-extension"
const setExcerpt = require('./set-excerpt')
const generateCategoryPage = require('./generate-category-page')
const generateTagPage = require('./generate-tag-page')
function register({ config: { componentName = 'quick-docs', ...unknownOptions } }) {
if (Object.keys(unknownOptions).length) {
const keys = Object.keys(unknownOptions)
throw new Error(`Unrecognized option${keys.length > 1 ? 's' : ''} specified for ${packageName}: ${keys.join(', ')}`)
}
this.on('navigationBuilt', async ({ contentCatalog, siteAsciiDocConfig }) => {
const pages = contentCatalog.getPages((page) => page.src.component === componentName)
setExcerpt(pages)
const categoryPages = generateCategoryPage(pages, siteAsciiDocConfig)
for (const categoryPage of categoryPages) {
contentCatalog.addFile(categoryPage)
}
const tagPages = generateTagPage(pages, siteAsciiDocConfig)
for (const tagPage of tagPages) {
contentCatalog.addFile(tagPage)
}
})
}
module.exports = { register }

View file

@ -0,0 +1,34 @@
'use strict'
const cheerio = require('cheerio')
const generateExcerpt = (page) => {
const $ = cheerio.load(page.contents.toString())
// removes tables, images and source block
$('table').remove()
$('img').remove()
$('pre').remove()
$('iframe').remove()
let text = $.text()
text = text.trim()
.replace(/\n/g, ' ')
.replace(/\s{2,}/g, ' ')
let words = text.split(' ')
let excerpt
if (words.length > 30) {
words = words.slice(0, 30)
excerpt = words.join(' ') + '…'
} else {
excerpt = words.join(' ')
}
return excerpt
}
// remind: could be an Asciidoctor Postprocessor extension
function setExcerpt(pages) {
pages
.filter((page) => page.src.basename !== 'index.adoc' && page.asciidoc && page.asciidoc.attributes && !page.asciidoc.attributes['description'])
.forEach((page) => page.asciidoc.attributes['description'] = generateExcerpt(page))
}
module.exports = setExcerpt

185
site-council-docs-test.yaml Normal file
View file

@ -0,0 +1,185 @@
site:
title: Fedora Docs
url: https://docs.fedoraproject.org/en-US/
start_page: docs::index.adoc
keys:
howtos: |
{
"gitlab": { "title": "How to edit this page", "link": "fedora-docs::contributing-docs/tools-gitlab-howto.adoc" }
}
content:
branches: main
sources:
- url: https://forge.fedoraproject.org/docs/site-frontpage.git
start_path: homepage
- url: https://forge.fedoraproject.org/docs/site-frontpage.git
start_path: engineering
- url: https://forge.fedoraproject.org/docs/site-frontpage.git
start_path: mindshare
- url: https://forge.fedoraproject.org/docs/site-frontpage.git
start_path: spins-labs
- url: https://forge.fedoraproject.org/docs/site-frontpage.git
start_path: tools
- url: https://forge.fedoraproject.org/docs/site-frontpage.git
start_path: arm-sbc
- url: https://forge.fedoraproject.org/docs/release-docs-home.git
branches:
- main
- f44
- f43
- f42
- f41
- f40
- f39
- f38
- f37
- f36
- f35
- f34
- f33
- f32
- f31
- f30
- f29
- f28
- f27
- f26
- url: https://forge.fedoraproject.org/docs/release-notes.git
branches:
- main
- f44
- f43
- f42
- f41
- f40
- f39
- f38
- f37
- f36
- f35
- f34
- f33
- f32
- f31
- f30
- f29
- f28
- f27
- f26
- url: https://forge.fedoraproject.org/docs/quick-docs.git
- url: https://forge.fedoraproject.org/commops/docs.git
- url: https://forge.fedoraproject.org/mentored-projects/docs.git
- url: https://gitlab.com/fedora/websites-apps/documentation.git
# - url: https://forge.fedoraproject.org/council/docs.git
- url: https://forge.stg.fedoraproject.org/playground/council-docs-test.git
start_path: council
# - url: https://forge.fedoraproject.org/council/docs.git
- url: https://forge.stg.fedoraproject.org/playground/council-docs-test.git
start_path: project
- url: https://forge.fedoraproject.org/packaging/maintainer-docs.git
- url: https://forge.fedoraproject.org/atomic-desktops/docs.git
- url: https://forge.fedoraproject.org/docs/team-docs.git
- url: https://forge.fedoraproject.org/flatpak/docs.git
- url: https://forge.fedoraproject.org/dei/docs.git
- url: https://forge.fedoraproject.org/packaging/guidelines.git
start_path: guidelines
- url: https://forge.fedoraproject.org/mindshare/docs.git
- url: https://forge.fedoraproject.org/fesco/docs
start_path: fesco
branches: main
- url: https://github.com/fedora-iot/iot-docs.git
start_path: user-docs
- url: https://github.com/fedora-iot/iot-docs.git
start_path: wg-docs
- url: https://forge.fedoraproject.org/apps/badges-docs.git
- url: https://github.com/containers/docs.git
- url: https://forge.fedoraproject.org/neuro/docs.git
- url: https://forge.fedoraproject.org/ci/docs.git
- url: https://github.com/fedora-java/howto.git
branches: master
- url: https://forge.fedoraproject.org/magazine/fedora-magazine.git
branches: main
- url: https://github.com/coreos/fedora-coreos-docs.git
- url: https://forge.fedoraproject.org/cle/rawhide-gating-docs
branches: master
- url: https://forge.fedoraproject.org/cle/docs
branches: master
- url: https://forge.fedoraproject.org/quality/docs.git
branches: master
- url: https://forge.fedoraproject.org/operations/docs.git
- url: https://forge.fedoraproject.org/operations/docs.git
start_path: releases
- url: https://forge.fedoraproject.org/join/docs.git
- url: https://forge.fedoraproject.org/docs/localization-stats.git
branches: master
- url: https://forge.fedoraproject.org/localization/docs.git
- url: https://github.com/fedora-eln/eln-docs.git
branches: master
- url: https://forge.fedoraproject.org/i3/i3-docs.git
- url: https://forge.fedoraproject.org/docs/accounts-docs.git
- url: https://forge.fedoraproject.org/games/documentation.git
- url: https://forge.fedoraproject.org/server/user-documentation.git
- url: https://forge.fedoraproject.org/server/wg-documentation.git
- url: https://forge.fedoraproject.org/epel/docs.git
- url: https://forge.fedoraproject.org/infra/docs.git
- url: https://forge.fedoraproject.org/workstation/wg-docs.git
branches: master
- url: https://forge.fedoraproject.org/workstation/user-docs.git
branches: master
- url: https://forge.fedoraproject.org/marketing/docs.git
- url: https://forge.fedoraproject.org/security/defensive-coding-guide.git
branches: master
- url: https://gitlab.com/fedora/legal/fedora-legal-docs.git
- url: https://gitlab.com/fedora/sigs/robotics/fedora-docs.git
- url: https://forge.fedoraproject.org/commops/community-docs.git
- url: https://forge.fedoraproject.org/asahi/docs-site.git
- url: https://forge.fedoraproject.org/reproduciblebuilds/docs-site.git
- url: https://forge.fedoraproject.org/dei/fedora-accessibility.git
start_path: docs
- url: https://forge.fedoraproject.org/atomic/docs.git
- url: https://forge.fedoraproject.org/design/docs.git
- url: https://github.com/fedora-minimal/documentation-minimal.git
start_path: minimal-docs
- url: https://forge.fedoraproject.org/cloud/docs-site.git
branches: master
- url: https://forge.fedoraproject.org/ai-ml/docs.git
- url: https://forge.fedoraproject.org/forge/documentation.git
- url: https://forge.fedoraproject.org/kde/user-docs.git
- url: https://forge.fedoraproject.org/docs/beginners-guide.git
- url: https://forge.fedoraproject.org/security/docs.git
- url: https://forge.fedoraproject.org/discussion/self-moderation-guidelines-and-rules
- url: https://forge.fedoraproject.org/fdwg/docs.git
ui:
bundle:
url: https://gitlab.com/fedora/docs/docs-website/ui-bundle/-/jobs/artifacts/HEAD/raw/build/ui-bundle.zip?job=bundle-stable
snapshot: true
default_layout: with_menu
supplemental_files: ./supplemental-ui
output:
clean: true
dir: ./public/en-US
runtime:
fetch: true
cache_dir: ./cache
log:
format: pretty
level: fatal
asciidoc:
extensions:
- ./lib/extensions/package-inline-macro.js
- '@asciidoctor/tabs'
antora:
extensions:
- id: page-last-update
require: ./lib/extensions/page-last-update.js
enabled: true
- id: lunr
require: '@antora/lunr-extension'
index_latest_only: true
enabled: false
- id: qd
require: ./lib/extensions/qd-extension
enabled: true
urls:
latest_version_segment: latest
html_extension_style: indexify

183
site.yml Normal file
View file

@ -0,0 +1,183 @@
site:
title: Fedora Docs
url: https://docs.fedoraproject.org/en-US/
start_page: docs::index.adoc
keys:
howtos: |
{
"gitlab": { "title": "How to edit this page", "link": "fedora-docs::contributing-docs/tools-gitlab-howto.adoc" }
}
content:
branches: main
sources:
- url: https://forge.fedoraproject.org/docs/site-frontpage.git
start_path: homepage
- url: https://forge.fedoraproject.org/docs/site-frontpage.git
start_path: engineering
- url: https://forge.fedoraproject.org/docs/site-frontpage.git
start_path: mindshare
- url: https://forge.fedoraproject.org/docs/site-frontpage.git
start_path: spins-labs
- url: https://forge.fedoraproject.org/docs/site-frontpage.git
start_path: tools
- url: https://forge.fedoraproject.org/docs/site-frontpage.git
start_path: arm-sbc
- url: https://forge.fedoraproject.org/docs/release-docs-home.git
branches:
- main
- f44
- f43
- f42
- f41
- f40
- f39
- f38
- f37
- f36
- f35
- f34
- f33
- f32
- f31
- f30
- f29
- f28
- f27
- f26
- url: https://forge.fedoraproject.org/docs/release-notes.git
branches:
- main
- f44
- f43
- f42
- f41
- f40
- f39
- f38
- f37
- f36
- f35
- f34
- f33
- f32
- f31
- f30
- f29
- f28
- f27
- f26
- url: https://forge.fedoraproject.org/docs/quick-docs.git
- url: https://forge.fedoraproject.org/commops/docs.git
- url: https://forge.fedoraproject.org/mentored-projects/docs.git
- url: https://gitlab.com/fedora/websites-apps/documentation.git
- url: https://forge.fedoraproject.org/council/docs.git
start_path: council
- url: https://forge.fedoraproject.org/council/docs.git
start_path: project
- url: https://forge.fedoraproject.org/packaging/maintainer-docs.git
- url: https://forge.fedoraproject.org/atomic-desktops/docs.git
- url: https://forge.fedoraproject.org/docs/team-docs.git
- url: https://forge.fedoraproject.org/flatpak/docs.git
- url: https://forge.fedoraproject.org/dei/docs.git
- url: https://forge.fedoraproject.org/packaging/guidelines.git
start_path: guidelines
- url: https://forge.fedoraproject.org/mindshare/docs.git
- url: https://forge.fedoraproject.org/fesco/docs
start_path: fesco
branches: main
- url: https://github.com/fedora-iot/iot-docs.git
start_path: user-docs
- url: https://github.com/fedora-iot/iot-docs.git
start_path: wg-docs
- url: https://forge.fedoraproject.org/apps/badges-docs.git
- url: https://github.com/containers/docs.git
- url: https://forge.fedoraproject.org/neuro/docs.git
- url: https://forge.fedoraproject.org/ci/docs.git
- url: https://github.com/fedora-java/howto.git
branches: master
- url: https://forge.fedoraproject.org/magazine/fedora-magazine.git
branches: main
- url: https://github.com/coreos/fedora-coreos-docs.git
- url: https://forge.fedoraproject.org/cle/rawhide-gating-docs
branches: master
- url: https://forge.fedoraproject.org/cle/docs
branches: master
- url: https://forge.fedoraproject.org/quality/docs.git
branches: master
- url: https://forge.fedoraproject.org/operations/docs.git
- url: https://forge.fedoraproject.org/operations/docs.git
start_path: releases
- url: https://forge.fedoraproject.org/join/docs.git
- url: https://forge.fedoraproject.org/docs/localization-stats.git
branches: master
- url: https://forge.fedoraproject.org/localization/docs.git
- url: https://github.com/fedora-eln/eln-docs.git
branches: master
- url: https://forge.fedoraproject.org/i3/i3-docs.git
- url: https://forge.fedoraproject.org/docs/accounts-docs.git
- url: https://forge.fedoraproject.org/games/documentation.git
- url: https://forge.fedoraproject.org/server/user-documentation.git
- url: https://forge.fedoraproject.org/server/wg-documentation.git
- url: https://forge.fedoraproject.org/epel/docs.git
- url: https://forge.fedoraproject.org/infra/docs.git
- url: https://forge.fedoraproject.org/workstation/wg-docs.git
branches: master
- url: https://forge.fedoraproject.org/workstation/user-docs.git
branches: master
- url: https://forge.fedoraproject.org/marketing/docs.git
- url: https://forge.fedoraproject.org/security/defensive-coding-guide.git
branches: master
- url: https://gitlab.com/fedora/legal/fedora-legal-docs.git
- url: https://gitlab.com/fedora/sigs/robotics/fedora-docs.git
- url: https://forge.fedoraproject.org/commops/community-docs.git
- url: https://forge.fedoraproject.org/asahi/docs-site.git
- url: https://forge.fedoraproject.org/reproduciblebuilds/docs-site.git
- url: https://forge.fedoraproject.org/dei/fedora-accessibility.git
start_path: docs
- url: https://forge.fedoraproject.org/atomic/docs.git
- url: https://forge.fedoraproject.org/design/docs.git
- url: https://github.com/fedora-minimal/documentation-minimal.git
start_path: minimal-docs
- url: https://forge.fedoraproject.org/cloud/docs-site.git
branches: master
- url: https://forge.fedoraproject.org/ai-ml/docs.git
- url: https://forge.fedoraproject.org/forge/documentation.git
- url: https://forge.fedoraproject.org/kde/user-docs.git
- url: https://forge.fedoraproject.org/docs/beginners-guide.git
- url: https://forge.fedoraproject.org/security/docs.git
- url: https://forge.fedoraproject.org/discussion/self-moderation-guidelines-and-rules
- url: https://forge.fedoraproject.org/fdwg/docs.git
ui:
bundle:
url: https://gitlab.com/fedora/docs/docs-website/ui-bundle/-/jobs/artifacts/HEAD/raw/build/ui-bundle.zip?job=bundle-stable
snapshot: true
default_layout: with_menu
supplemental_files: ./supplemental-ui
output:
clean: true
dir: ./public/en-US
runtime:
fetch: true
cache_dir: ./cache
log:
format: pretty
level: fatal
asciidoc:
extensions:
- ./lib/extensions/package-inline-macro.js
- '@asciidoctor/tabs'
antora:
extensions:
- id: page-last-update
require: ./lib/extensions/page-last-update.js
enabled: true
- id: lunr
require: '@antora/lunr-extension'
index_latest_only: true
enabled: false
- id: qd
require: ./lib/extensions/qd-extension
enabled: true
urls:
latest_version_segment: latest
html_extension_style: indexify

11
static/index.html Normal file
View file

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<!-- HTML meta refresh URL redirection -->
<meta http-equiv="refresh"
content="0; url=./en-US/">
</head>
<body>
<a href="./en-US/">Continue to the English site.</a></p>
</body>
</html>

View file

@ -0,0 +1 @@
<!-- Add any HTML code to show at the top of each page — like a banner to a survey, some announcement, etc. Leave this file empty to not show anything-->