Оркестрация сборки

Обзор

Сборочный слой умышленно дублирован:

  • GNU Make — основной вход, применяется CI и Docker

  • build.py — эквивалент на Python 3.11+ для систем без make

Обе точки входа обслуживают общий конвейер:

  • Генерация — HTML / PDF / DOCX

  • Контроль качества — Vale, htmltest, Shellcheck

  • Упаковка — ZIP-архив каждого билда

  • Контейнеризация — полная воспроизводимость через docker build

Используйте либо Makefile, либо build.py — не смешивайте их в одном прогоне.

Режимы сборки

Локальный — собирается только текущая ветка HEAD или ветка, заданная через BUILD_REF.

make build-all
make build-all BUILD_REF=my-feature

Теги — мультиверсионная сборка по всем Git-тегам.

make build-all BUILD_SCOPE=tags

Переменные Make: BUILD_SCOPE = local или tags; BUILD_REF по умолчанию HEAD.

Артефакты и размещение

PDF

  • build/pdf/<locale>/<version>/adaptadocx-<locale>.pdf

  • копируется в site/<locale>/<version>/_downloads/adaptadocx-<locale>.pdf

DOCX

  • build/docx/<locale>/<version>/adaptadocx-<locale>.docx

  • копируется в site/<locale>/<version>/_downloads/adaptadocx-<locale>.docx

Цели Make

Target Назначение

make build-site

HTML + PDF + DOCX (все локали)

make build-html

только HTML

make build-pdf

только PDF

make build-docx

только DOCX

make test

Vale • htmltest • Shellcheck

make clean

удалить build/

make release

ZIP + QA-проверка

make build-all

псевдоним → build-site

Точки входа Python

Команда Назначение

python3 build.py build-site

HTML + PDF + DOCX

python3 build.py build-html

Только HTML

python3 build.py build-pdf

Только PDF

python3 build.py build-docx

Только DOCX

python3 build.py test

Запуск тестов (Vale, htmltest при наличии сайта, Shellcheck)

python3 build.py clean

Удалить build/

Параметры и значения по умолчанию:

  • --scope local|tags (по умолчанию local) local собирает только текущий ref; tags собирает все Git-теги.

  • --ref <git-ref> (по умолчанию HEAD) Используется только при --scope local.

  • Переменные окружения дублируют флаги: BUILD_SCOPE, BUILD_REF.

Примеры:

# Все теги (мультиверсионная сборка)
python3 build.py --scope tags build-all

# Локальная сборка для конкретной ветки
python3 build.py --scope local --ref my-feature build-site

Основные цели Make (сокращённо)

build-site: build-html build-pdf build-docx
	@echo "[site] full build done"

build-html:
	@echo "[html] start"; \
	for l in $(LOCALES); do \
		echo "  • $${l}"; \
		pb="antora-playbook-$${l}.yml"; \
		if [ "$(BUILD_SCOPE)" = "tags" ]; then \
			npx antora "$$pb"; \
		else \
			bak="$$pb.bak"; \
			cp "$$pb" "$$bak"; \
			tr -d '\r' < "$$pb" > "$$pb.unix" && mv "$$pb.unix" "$$pb"; \
			sed -i "s/tags: '\*'/tags: ~/" "$$pb"; \
			sed -i "s/branches: ~$$/branches: $(BUILD_REF)/" "$$pb"; \
			npx antora "$$pb"; \
			mv "$$bak" "$$pb"; \
		fi; \
	done
	@echo "[html] done"

build-pdf: build-html
	@mkdir -p "$(PDF_DIR)"; \
	for l in $(LOCALES); do \
		echo "[pdf] $$l"; \
		for version_dir in $(SITE_DIR)/$$l/*/; do \
			if [ -d "$$version_dir" ]; then \
				version=$$(basename "$$version_dir"); \
				if [ "$(BUILD_SCOPE)" != "tags" ] && [ "$$version" != "$(BUILD_REF)" ] && [ "$$version" != "current" ] && [ "$$version" != "main" ]; then continue; fi; \
				export_file=""; \
				for candidate in "$(ASM_DIR)/$$l/$$version/_exports/index.adoc" "$(ASM_DIR)/$$l/_exports/index.adoc" "$(ASM_DIR)/_exports/$$l/$$version/index.adoc" "$(ASM_DIR)/_exports/$$l/index.adoc"; do \
					if [ -f "$$candidate" ]; then export_file="$$candidate"; base=$$(dirname "$$(dirname "$$candidate")")); break; fi; \
				done; \
				[ -z "$$export_file" ] && continue; \
				img_src="$$base/_images"; img_dst="$$(dirname "$$export_file")/$$l/$$version/_images"; \
				[ -d "$$img_src" ] && mkdir -p "$$img_dst" && cp -r "$$img_src"/* "$$img_dst"/ || true; \
				outdir="$(PDF_DIR)/$$l/$$version"; outfile="$$outdir/adaptadocx-$$l.pdf"; \
				mkdir -p "$$outdir"; \
				toc=$$( [ "$$l" = ru ] && echo '-a toc-title=Содержание' || echo '-a toc-title=Contents' ); \
				asciidoctor-pdf $(ASCIIDOCTOR_PDF_OPTS) $$toc -a revnumber=$$version -o "$$outfile" "$$export_file"; \
				mkdir -p "$(SITE_DIR)/$$l/$$version/_downloads"; \
				cp "$$outfile" "$(SITE_DIR)/$$l/$$version/_downloads/adaptadocx-$$l.pdf"; \
			fi; \
		done; \
	done
	@echo "[pdf] done"

build-docx: build-html
	@mkdir -p "$(DOCX_DIR)"; \
	for l in $(LOCALES); do \
		echo "[docx] $$l"; \
		for version_dir in $(SITE_DIR)/$$l/*/; do \
			if [ -d "$$version_dir" ]; then \
				version=$$(basename "$$version_dir"); \
				if [ "$(BUILD_SCOPE)" != "tags" ] && [ "$$version" != "$(BUILD_REF)" ] && [ "$$version" != "current" ] && [ "$$version" != "main" ]; then continue; fi; \
				base="$(ASM_DIR)/$$l/$$version"; \
				img_src="$$base/_images"; img_dst="$$base/_exports/$$l/$$version/_images"; \
				[ -d "$$img_src" ] && mkdir -p "$$img_dst" && cp -r "$$img_src"/* "$$img_dst"/ || true; \
				outdir="$(DOCX_DIR)/$$l/$$version"; outfile="$$outdir/adaptadocx-$$l.docx"; outfile_abs="$(CURDIR)/$$outfile"; \
				mkdir -p "$$outdir"; \
				tmp_meta="$(CURDIR)/$(DOCX_DIR)/meta-$$l-$$version.yml"; \
				sed "s/{page-version}/$$version/g" $(CURDIR)/config/meta-$$l.yml > "$$tmp_meta"; \
				( cd "$$base/_exports" && asciidoctor -b docbook5 -r $(CURDIR)/extensions/collapsible_tree_processor.rb -a allow-uri-read -a revdate! -a revnumber! -a docdate! -a docdatetime! -o - index.adoc | pandoc --from=docbook --to=docx --reference-doc=$(PANDOC_REF) --metadata-file="$$tmp_meta" $(SVG_FILTER) --lua-filter=$(LUA_COVER) -o "$$outfile_abs" ); \
				rm -f "$$tmp_meta"; \
				mkdir -p "$(SITE_DIR)/$$l/$$version/_downloads"; \
				cp "$$outfile" "$(SITE_DIR)/$$l/$$version/_downloads/adaptadocx-$$l.docx"; \
			fi; \
		done; \
	done
	@echo "[docx] done"

Цели контроля качества

test:
	@if [ -d "$(SITE_DIR)" ]; then \
		htmltest -c .htmltest.yml "$(SITE_DIR)"; \
	else \
		echo "[test] Skipping htmltest - no site built"; \
	fi
	@vale --config=.vale.ini docs/
	@find scripts -name '*.sh' -print0 | xargs -0 -I{} bash -c 'tr -d "\r" < "{}" | shellcheck -'
	@echo '[test] OK'

Служебные цели

clean:
	-rm -rf build
	@echo '[clean] build/ removed'

release: build-site test
	@cd build && zip -rq ../"$(RELEASE_FILE)" .
	@echo "[release] $(RELEASE_FILE) created"

Где RELEASE_FILE := adaptadocx-docs-$(VERSION).zip.

Работа в контейнере

Образ Docker инкапсулирует весь тулчейн; типовые запуски:

# Сборка образа
docker build -t adaptadocx:latest .

# Полная сборка
docker run --rm -v "$(pwd)":/work adaptadocx:latest make build-site

# Только QA-проверки
docker run --rm -v "$(pwd)":/work adaptadocx:latest make test

# Интерактивная отладка
docker run -it --rm -v "$(pwd)":/work adaptadocx:latest bash

Конфигурационные переменные

Variable

Назначение

Default

LOCALES

Поддерживаемые языки

ru en

VERSION

Версия из Git/package.json

автоопределение

BUILD_SCOPE

Режим сборки (local или tags)

local

BUILD_REF

Ветка для локального режима

HEAD

SITE_DIR

Каталог HTML-сайта

build/site

ASM_DIR

Каталог сборки Antora

build/asm

PDF_DIR

Каталог PDF-файлов

build/pdf

DOCX_DIR

Каталог DOCX-файлов

build/docx

PANDOC_REF

Референсный DOCX

docx/reference.docx

LUA_COVER

Lua-фильтр обложки

docx/coverpage.lua

SVG_FILTER

Lua-фильтр SVG→PNG

docx/svg2png.lua

RELEASE_FILE

Имя архива релиза

adaptadocx-docs-$(VERSION).zip

Определение версии

VERSION := $(shell git describe --tags --abbrev=0 2>/dev/null \
             || node -p "require('./package.json').version")

Отладка

  • Unknown target — запускать make из корня репозитория

  • Stale artefacts — make clean перед новой сборкой

  • CI mismatch — версии инструментов в Docker должны совпадать с локальными

См. также: CI/CD процессы