Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Привет! Меня зовут Андрей Гладилин, я работаю в Swordfish Security над составлением технической документации для ИТ-решений. Завершая предыдущую статью, мы обсудили преимущества и недостатки DocOps-подхода к разработке технической документации и немного поговорили о прикладной реализации этой парадигмы — Doc-as-code.
Позволю себе напомнить, что основная идея DocOps заключается в том, что создание технической документации осуществляется в тесном контакте с разработкой программного продукта и во многом «отзеркаливает» этапы последней — рабочие процессы максимально синхронизируются и объединяются в общую систему, широко применяется автоматизация рутинных операций и упрощается совместная работа, что позволяет повысить общую эффективность процесса.
Теперь перейдем к практической реализации DocOps-решения, которое мы начали обсуждать в первой части статьи. Что же, начнем!
Перед техническими писателями, помимо прочего, почти всегда стоит задача разработки и публикации эксплуатационной документации для продукта — руководства пользователя, администратора и т. д. Если говорить о форматах публикации, как правило, необходим онлайн справочный портал, а также зачастую документы в формате для печати, например PDF. Кроме этого, предположим, что наши клиенты одновременно пользуются несколькими версиями продукта, — потребуется версионирование документации.
Собственно, исходя из перечисленных требований, предлагаю приступить к созданию инструментальной среды разработки технической документации. Очевидно, что реальные требования конкретного проекта могут быть гораздо шире: часто нужны документы в формате docx, иногда оформленные в соответствии с требованиями ГОСТов или конкретных заказчиков, но это определенно выходит за рамки нашей сегодняшней беседы. Текущая задача — «завести» систему, которая будет «закрывать» базовые потребности, в части разработки и публикации эксплуатационной документации, а дальше можно наращивать функционал по мере необходимости.
Выбор инструментов
Для решения поставленной задачи предлагаю следующий базовый набор инструментов:
Система контроля версий (Version Control System, VCS) для хранения исходных файлов (в нашем случае в формате MarkDown).
Сервис выполнения CI/CD-конвейеров (пайплайнов) для автоматизации процессов сборки и публикации.
Static Site Generator для конвертации MarkDown‑файлов в статические HTML‑страницы и создания онлайн‑версии документации с поддержкой поиска, версионирования и других базовых функций.
Плагины для генерации документации в PDF‑формате.
Выбирая что-то конкретное, стоит помнить, что поставленная задача может быть решена с использованием широкого спектра инструментов, — одних только генераторов статики несколько сотен. Разумно остановить выбор на достаточно популярных решениях, позволяющих в полной мере реализовать необходимый функционал.
Система контроля версий
Предлагаю сфокусироваться на Git и на популярных сервисах для работы с этой системой — GitHub и GitLab. Кроме основных функций системы контроля версий, они предлагают возможность запуска CI/CD-конвейеров, что позволит нам автоматизировать, а значит упростить и ускорить процесс публикации. В части решения аналогичных задач мне приходилось работать с обоими сервисами и я не заметил существенных преимуществ одного над другим — есть некоторые особенности, но они не имеют решающего значения. Логично сделать выбор в пользу того, который используется в вашей компании при разработке программных продуктов.
Если говорить о бесплатных тарифах, стоит, пожалуй, упомянуть, что запуск пайплайнов в GitLab возможен только после указания данных платежной карты, с чем могут возникнуть проблемы, однако никто не мешает использовать on-premise установку GitLab Community Edition, где такое ограничение отсутствует. Нежелание/невозможность размещать информацию на сторонних серверах также может стать весомым аргументом в пользу такого решения.
Расскажу об использовании обоих сервисов, а выбирать вам. Чтобы ограничить объем статьи, будем исходить из того, что на GitHub документация будет храниться в публичном репозитории, а на GitLab — в приватном. Очевидно, что эти два случая не перекрывают все поле возможных вариантов и никто не может помешать вам при реализации конкретного проекта выбрать любой из двух оставшихся.
Static Site Generator
Повторюсь, выбор подобных инструментов огромен, и очевидно, что широкая распространенность решения является залогом того, что в случае возникновения проблем вы не окажетесь один на один с нерешаемой задачей. Исходя из вышесказанного, предлагаю использовать MkDocs. Его популярность во многом обусловлена современной и активно поддерживаемой разработчиками и комьюнити темой MkDocs Material, которая «из коробки» предлагает неплохой функционал, а при наличии сколько-нибудь умелых рук может быть доведена до отличного состояния. В пользу выбора этого решения говорит также большое количество плагинов, с некоторыми из которых мы познакомимся.
Плагины для генерации PDF
Переходя к инструментам для генерации PDF, замечу, что мне удалось попробовать два решения: одно простое и обладающее минимальными настройками, а второе более сложное в части настройки, но открывающее достаточно широкие возможности для кастомизации генерируемых документов. Увы, расплачиваться за эти возможности придется уверенными знаниями HTML/CSS, а также значительными временными затратами.
Другие инструменты и компоненты
Для комфортной работы пригодится интегрированная среда разработки (Integrated Development Environment, IDE) — рекомендую VS Code. Можно выбрать любую другую или даже просто текстовый редактор, но в случае с VS Code удобно использовать интеграцию с Git, встроенный терминал и большой выбор расширений. Кроме этого, встроенные среды разработки GitHub и GitLab обладают аналогичными интерфейсами и функциями и, привыкнув однажды, не придется переучиваться.
Выбор ОС не принципиален — все «заводится» и работает и на Windows, и на Linux, и на MacOS, но в разных системах вы можете столкнуться с различными решаемыми трудностями — об известных мне буду по возможности предупреждать. Самым беспроблемным выбором является Linux, например Ubuntu, — при ее использовании бубен придется доставать реже. Кроме этого, наша цель — переложить сборку и публикацию на плечи CI/CD-конвейера сервиса системы контроля версий, а локально будет происходить лишь работа с исходными MarkDown-файлами, ну и графическими материалами, конечно.
Если планируется размещение документации в приватном репозитории, необходимо сгенерировать SSH-ключи (об этом ниже).
Кроме этого, на локальной машине должны быть установлены Python и PIP, а также Git.
Безусловно, желательны базовые навыки работы со всем перечисленным, однако в известной мере их можно приобрести и в ходе работы.
Установка и настройка
Создание репозитория
Создадим репозиторий для документации на выбранном сервисе.
GitHub
GitLab
Установка и локальный запуск MkDocs Material
Запустим VS Code и откроем встроенный терминал (Ctrl+Shift+`).
Выполнив следующие команды, убедимся, что Python и PIP установлены.
python --version pip --version
Если видим, например:
Python 3.9.6
иpip 23.1.2 from…
, все отлично.Установим MkDocs с темой Material.
pip install mkdocs mkdocs-material
Создадим папку для нашего проекта и перейдем в нее.
cd ~ mkdir -p habr/docopsgh cd habr/docopsgh
Создадим новый проект.
mkdocs new .
В проектной директории появятся следующие файлы и папки:
. ├── docs // Папка с исходными файлами │ └── index.md // Главная страница └── mkdocs.yml // Конфигурационный файл
Открыв директорию проекта в VS Code (Cmd+O), добавим в конфигурационный файл mkdocs.yml следующий раздел:
theme: name: material
Примечание: В конце статьи приведены ссылки на открытый репозиторий GitHub и конфигурационные файлы для GitLab. Это поможет сэкономить время и избежать элементарных ошибок при настройке.
Запустим MkDocs локально из терминала VS Code (Ctrl+Shift+`) следующей командой:
mkdocs serve
Откроем в браузере URL http://127.0.0.1:8000/.
На этом локальная установка завершена и можно определиться со структурой будущего справочного портала.
Структура
Для примера создадим несколько страниц и объединим их в простую структуру. Предположим, что необходимо опубликовать два документа (Руководство по установке и Руководство администратора), каждый с парой статей. Я сознательно утрирую ситуацию, чтобы просто продемонстрировать, как работает механизм.
Можно расположить документы в различных директориях или просто в папке docs. Пойдем первым путем, чтобы второй гарантировано не вызвал затруднений. Пути и названия создаваемых файлов указаны в скобках.
Руководство по установке (
ig/index.md
).Создание репозитория.
Создание репозитория в GitHub (
ig/repo_creation_gh.md
).Создание репозитория в GitLab (
ig/repo_creation_gl.md
).
Установка MkDocs (
ig/mkdocs_installation.md
).
Руководство администратора (
ag/index.md
).Настройки (
ag/setup.md
).Настройка публикации (
ag/pub_setup.md
).
Примечание: Если локальный сервер MkDocs все еще запущен, его необходимо предварительно остановить — команда (Ctrl+C) в терминале.
Создадим директории для документов в папке docs.
cd docs mkdir ig ag
В каждой директории создадим файлы в соответствии с обозначенной структурой.
Примечание: Для работы с папками и файлами удобно использовать проводник VS Code.
. ├── docs // Корневая директория с документами │ ├── ag // Директория Руководства администратора │ │ ├── index.md // Главная страница Руководства администратора │ │ ├── pub_setup.md // Настройка публикации │ │ └── setup.md // Настройки │ ├── ig // Директория Руководства по установке │ │ ├── index.md // Главная страница Руководства по установке │ │ ├── mkdocs_installation.md // Установка MkDocs │ │ ├── repo_creation_gh.md // Создание репозитория на GitHub │ │ └── repo_creation_gl.md // Создание репозитория на GitLab │ └── index.md // Главная страница портала └── mkdocs.yml // Конфигурационный файл
В конфигурационном файле mkdocs.yml создадим раздел
nav
, который интерпретирует созданную файловую структуру в разделы справочного портала.site_name: Документация для Наш продукт nav: - Руководство по установке: - ig/index.md - Создание репозитория: - ig/repo_creation_gh.md - ig/repo_creation_gl.md - ig/mkdocs_installation.md - Руководство администратора: - ag/index.md - ag/setup.md - ag/pub_setup.md
Перенесем верхний уровень заголовков в горизонтальное меню и выполним еще пару полезных настроек, добавив в раздел
theme
секциюfeatures
со следующими параметрами:theme: name: material ... features: - navigation.instant # ускорение загрузки (SPA) - navigation.tracking # динамический URL страницы - navigation.tabs # перенос названий документов в горизонтальное меню - navigation.tabs.sticky # горизонтальное меню не скрывается при прокрутке - navigation.indexes # главные страницы разделов не отображаются в меню - navigation.top # вкл. кнопку возврата наверх
В каждом файле укажем соответствующий ему заголовок первого уровня.
Примечание: В VS Code рекомендую активировать функцию автосохранения (File › AutoSave).
Запустим MkDocs-сервер локально, выполнив в терминале (Ctrl+Shift+`) уже знакомую команду
mkdocs serve
. Открыв в браузере URL http://127.0.0.1:8000/, увидим, что заданная структура соответствующим образом реализована.Примечание: Отметим, что при изменении исходных MarkDown-файлов автоматически изменяется и содержимое нашего портала — это позволяет отслеживать изменения в режиме реального времени, например при редактировании. Однако при изменении конфигурационного файла почти всегда требуется перезапуск сервера уже хорошо известной нам командой
mkdocs serve
.
Дополнительные настройки
Выполним еще несколько полезных настроек в файле mkdocs.yml.
Изменим название портала.
site_name: Документация для Наш продукт
Изменим логотип и favicon:
Создадим директорию docs/assets.
Скопируем в нее файлы логотипа и favicon.
Добавим в раздел
theme
следующие параметры:
theme: logo: assets/logo.png favicon: assets/logo_fav.png
Изменим язык интерфейса, добавив параметр
language
в разделtheme
.theme: ... language: ru
Активируем поиск на русском и английском языках, создав раздел
plugins
со следующим параметром:plugins: - search: lang: - en - ru
Активируем переключатель режимов просмотра (день/ночь), добавив в раздел
theme
следующие строки:theme: name: material ... palette: - scheme: default toggle: icon: material/brightness-7 name: Ночь - scheme: slate toggle: icon: material/brightness-4 name: День
Запустим сервер MkDocs локально и посмотрим, как изменился наш портал.
На этом пока остановимся, однако разработчики MkDocs Material предлагают много интересных функциональностей и широкие возможности для кастомизации. Понимая, что требования у всех разные, с легким сердцем отправляю вас на отличный сайт с документацией, где, без сомнения, можно найти много интересного.
Мы установили MkDocs Material локально, создали структуру нашего портала и выполнили ряд предварительных настроек. Настало время перенести файлы в репозиторий системы контроля версий и настроить автоматическую сборку и публикацию.
Настройка сборки и публикации
Примечание: Прежде чем продолжить, убедитесь, что на вашей машине установлен Git.
git --version
Примечание: После установки Git вероятно потребуется перезапустить VS Code.
GitHub
Примечание: В примере будем использовать публичный репозиторий на GitHub. Чтобы не делать настройки самостоятельно, можете просто клонировать его и использовать в качестве шаблона вашего проекта.
Примечание: Все команды Git, которые мы выполняем в интерфейсе VS Code, безусловно могут быть выполнены и через CLI.
В VS Code перейдите на вкладку Source Control (Ctrl+Shift+G) и нажмите на кнопку Initialize Repository.
На вкладке Source Control нажмите … › Remote › Add remote…, а затем выберите Add remote from GitHub.
После успешной авторизации в браузере и возвращения в VS Code выберите ранее созданный репозиторий и назначьте ему имя.
В поле Message вкладки Source Control введите комментарий, например
init
, и нажмите на кнопку Commit.Примечание: Если попытка выгрузки коммита закончилась неудачно, выполните в терминале две следующие команды, указав в кавычках свои данные, и опубликуйте коммит вновь.
git config --global user.email "you@mail.ru" git config --global user.name "Your Name"
На вкладке Source Control нажмите на появившуюся кнопку Publish Branch.
Примечание: В некоторых ОС на этом этапе можно столкнуться с затруднениями, но их легко преодолеть, следуя рекомендациям разработчиков VS Code и GitHub, а также многоуважаемого сетевого комьюнити.
Открыв в браузере соответствующий репозиторий, убеждаемся, что файлы успешно загружены.
В GitHub переходим на вкладку Actions и нажимаем на кнопку Configure на карточке Simple workflow.
Переименуем файл в main.yml, вставим следующие строки и нажмем на кнопку Commit changes….
name: ci on: push: branches: - main permissions: contents: write jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: python-version: 3.x - run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV - uses: actions/cache@v3 with: key: mkdocs-material-${{ env.cache_id }} path: .cache restore-keys: | mkdocs-material- - run: pip install mkdocs-material - run: mkdocs gh-deploy --force
В открывшемся окне просто нажимаем на кнопку Commit changes.
Переходим на вкладку Actions и убеждаемся, что пайплайн отработал без ошибок.
Переходим на вкладку Settings.
Выбираем пункт меню Pages.
Выбираем ветку для публикации (в нашем случае
gh-pages
).Нажимаем на кнопку Save.
Спустя минуту нужно перезагрузить страницу (Cmd+R) и нажать на кнопку Visit site, появившуюся в ее верхней части.
Теперь после размещения в репозитории каждого нового коммита будет автоматически запускаться сборка и публикация справочного портала на GitHub Pages.
На мой взгляд, описанный подход вполне подойдет для небольших Open Source проектов и не только.
GitLab
Немного усложним задачу и предположим, что в силу тех или иных причин необходимо разместить документацию в приватном репозитории GitLab и опубликовать ее оттуда.
Выполним настройку SSH-ключей:
Генерируем пару RSA-ключей в терминале (все параметры по умолчанию).
ssh-keygen -t rsa -b 2048
Копируем публичный ключ в буфер обмена:
Ubuntu
sudo apt install xclipx clip -sel clip < ~/.ssh/id_rsa.pub
MacOS
cat ~/.ssh/id_rsa.pub | pbcopy
В GitLab нажмем на иконку профиля в правом верхнем углу и выберем пункт Edit Profile.
Слева в меню выберем пункт SSH Keys, вставим публичный ключ из буфера обмена в поле SSH Fingerprints, установим срок действия ключа и нажмем на кнопку Add Key.
Перейдем в репозиторий и скопируем его SSH-адрес, нажав кнопку Clone.
В VS Code перейдем на вкладку Source Control (Ctrl+Shift+G) и нажмем на кнопку Initialize Repository.
В правой части вкладки Source Control нажмем … › Remote > Add remote… и вставим скопированный адрес репозитория.
В поле Message вкладки Source Control введем комментарий, например
init
, и нажмем на кнопку Commit.Примечание: Если попытка выгрузки коммита закончилась неудачно, выполните в терминале две следующие команды, указав в кавычках свои данные, и опубликуйте коммит вновь.
git config --global user.email "you@mail.ru" git config --global user.name "Your Name"
На вкладке Source Control нажмем появившуюся кнопку Publish Branch.
Вернемся в GitLab и убедимся, что все файлы успешно выгружены.
В меню GitLab выберем CI/CD › Editor и нажмем на кнопку Configure Pipeline.
В открывшемся окне заменим все строки следующими и нажмем на кнопку Commit changes внизу.
image: python:latest pages: stage: deploy tags: - linux script: - pip install mkdocs-material - mkdocs build --site-dir public artifacts: paths: - public rules: - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
Спустя пару минут, перейдя на страницу Settings › Pages, можно обнаружить ссылку на наш портал, опубликованный с помощью сервиса GitLab Pages.
Примечание: Я исхожу из того, что вы работаете в корпоративном аккаунте GitLab и среда выполнения задач (runner) уже настроена для вашей группы, в противном случае обратитесь к DevOps-специалисту, который выполнит необходимые настройки.
Теперь при размещении каждого нового коммита будет происходить автоматическая сборка и публикация справочного портала.
Таким образом, задача-минимум по публикации онлайн документов выполнена. При необходимости вы можете настроить домен и сертификат для GitLab Pages и размещать документацию публично, но разумнее использовать для этого отдельный сервер, а GitLab Pages оставить для ревью и тестирования документации. При необходимости доступ к GitLab Pages может быть ограничен только для членов проекта (Settings › General › Visibility).
Версионирование
Предположим, что клиенты используют разные версии вашего продукта и необходимо обеспечить поддержку каждой из них.
Примечание: Есть одно ограничение — следует исходить из того, что если мы переходим к работе с новой версией документации, изменения в старую уже не вносим. Технически это возможно, но затруднительно и нетехнологично. Такой подход вполне соответствует реальному положению дел — в предыдущие версии продукта функциональные изменения, как правило, тоже не вносятся.
Чтобы отличать одну версию от другой, предлагаю в каждый наш md-файл сразу после заголовка добавить строку «Это первая версия».
Примечание: Напоминаю, что сейчас пайплайны настроены таким образом, что портал собирается и публикуется каждый раз после размещения нового коммита.
В VS Code переходим на вкладку Source Control (Ctrl+Shift+G).
В поле Message вводим комментарий для коммита (в нашем случае —
1st version
).Нажимаем на кнопку Commit (Cmd+Enter).
Нажимаем на кнопку Sync Changes.
Реализовать версионирование нам поможет утилита Mike. В конфигурационный файл mkdocs.yml добавляем раздел
extra
со следующими параметрами:extra: version: provider: mike
Вносим изменения в пайплайны:
GitHub
Меняем содержимое файла docops/.github/workflows/main.yml следующим образом и размещаем коммит.
name: ci on: push: branches: - main permissions: contents: write jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: python-version: 3.x - run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV - uses: actions/cache@v3 with: key: mkdocs-material-${{ env.cache_id }} path: .cache restore-keys: | mkdocs-material- - run: pip install mkdocs-material - run: git config --global user.name = "Your Name" - run: git config --global user.email = "your@mail" - run: git fetch - run: pip install mike - run: mike deploy --push --update-aliases -b gh-pages 1.0 latest
Примечание: Здесь, как и ранее, важно указать свое имя и адрес электронной почты в параметрах
git config --global user.name = "Your Name"
иgit config --global user.email = "your@mail"
, а также каждый раз при изменении версии документации менять ее номер в последней строке. Например, сейчас указано- run: mike deploy --push --update-aliases -b gh-pages 1.0 latest
, где1.0
— это номер версии. Если вы хотите опубликовать документацию версии 2.0, необходимо это значение заменить на2.0
, т. е. строка будет выглядеть следующим образом:- run: mike deploy --push --update-aliases -b gh-pages 2.0 latest
. Подчеркну, что это необходимо делать только при изменении версии. Если вы публикуете изменения в рамках одной версии, просто размещайте коммиты и они будут автоматически собираться с текущей версией.Чтобы открывалась последняя версия документации, на GitHub в корне ветки
gh-pages
создадим файл index.html со следующим содержимым:<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Redirecting</title> <noscript> <meta http-equiv="refresh" content="1; url=latest/" /> </noscript> <script> window.location.replace("latest/" + window.location.hash); </script> </head> <body> Redirecting to <a href="latest/">latest/</a>... </body> </html>
Это можно сделать как в интерфейсе GitHub, так и в VS Code — в любом случае важно не забыть разместить коммит. Теперь при переходе по ссылке на GitHub Pages будет происходить редирект на последнюю версию документации (https://docopshabr.github.io/docopshabr/latest/), а рядом с названием портала появится переключатель версий.
Представим ситуацию, когда у нас несколько версий документации, и пользователь приходит на старую по ссылке, например из поисковой системы. Неплохо бы уведомить его об этом и предложить ссылку на актуальную версию.
Создадим в корневой директории проекта папку overrides, а в ней файл main.html.
. ├── docs │ ├── ag │ │ ├── index.md │ │ ├── pub_setup.md │ │ └── setup.md │ ├── assets │ │ ├── logo.png │ │ └── logo_fav.png │ ├── ig │ │ ├── index.md │ │ ├── mkdocs_installation.md │ │ ├── repo_creation_gh.md │ │ └── repo_creation_gl.md │ └── index.md ├── mkdocs.yml └── overrides └── main.html
Вставим в main.html следующий блок:
{% extends "base.html" %} {% block outdated %} Самая актуальная версия документации <a href="{{ '../' ~ base_url }}"> <strong>здесь</strong>. </a> {% endblock %}
В раздел
theme
файла mkdocs.yml добавим параметрcustom_dir: overrides
:theme: name: material custom_dir: overrides language: ru
В файле .github/workflows/main.yml изменим номер версии, например на 2.0, см. примечание выше.
Примечание: В нашем примере, чтобы отличать версии, в каждый md-файл можно добавить строку «Это вторая версия».
Размещаем коммит, ждем пока отработает пайплайн и переходим на GitLab Pages.
Примечание: Если после обновления версии что-то работает неправильно, с большой долей вероятности нужно просто очистить кэш браузера.
Видим, что открылась новая версия. Переключив версии, можно убедиться, что старая также сохранилась. Кроме этого, вверху страниц старой версии появилось соответствующее предупреждение.
GitLab
Примечание: Для реализации версионирования в GitLab выберем несколько другой подход. Номер версии будем не указывать в конфигурационном файле, а передавать с помощью механизма тегирования. Кроме этого, сам пайплайн выстроим немного по-другому.
Заменяем содержимое файла .gitlab-ci.yml:
stages: - deploy pages: stage: deploy variables: PAGES_BRANCH: gl-pages PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip" HTTPS_REMOTE: https://gitlab-ci-token:$CICDTOKEN@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git image: ubuntu tags: - linux before_script: - mkdir public - apt update && apt install -y git - apt -y install python3-pip - pip install mkdocs-material - pip install mike script: - git config user.name $GITLAB_USER_NAME - git config user.email $GITLAB_USER_EMAIL - git fetch origin $PAGES_BRANCH && git checkout -b $PAGES_BRANCH origin/$PAGES_BRANCH || git checkout $PAGES_BRANCH || echo "Pages branch not deployed yet." - git checkout $CI_COMMIT_SHA - mike deploy --rebase --prefix public -r $HTTPS_REMOTE -p -b $PAGES_BRANCH -u $CI_COMMIT_TAG latest - mike set-default --rebase --prefix public -r $HTTPS_REMOTE -p -b $PAGES_BRANCH latest - git checkout $PAGES_BRANCH -- public/ artifacts: paths: - public/ only: - tags
Для запуска пайплайна создаем токен (Settings › Access Tokens) с указанными на рисунке правами.
Скопировав созданный токен в буфер обмена, переходим на страницу Settings › CI/CD › Variables и добавляем переменную
CICDTOKEN
со значением сгенерированного токена, установим флаги, как на рисунке.Создадим в корневой директории проекта папку overrides, а в ней файл main.html:
. ├── docs │ ├── ag │ │ ├── index.md │ │ ├── pub_setup.md │ │ └── setup.md │ ├── assets │ │ ├── logo.png │ │ └── logo_fav.png │ ├── ig │ │ ├── index.md │ │ ├── mkdocs_installation.md │ │ ├── repo_creation_gh.md │ │ └── repo_creation_gl.md │ └── index.md ├── mkdocs.yml └── overrides └── main.html
Вставим в main.html следующий блок:
{% extends "base.html" %} {% block outdated %} Самая актуальная версия документации <a href="{{ '../' ~ base_url }}"> <strong>здесь</strong>. </a> {% endblock %}
В раздел
theme
файла mkdocs.yml добавим параметрcustom_dir: overrides
:theme: ... custom_dir: overrides
Опубликуем коммит и, перейдя на страницу Repository › Tags, создадим новый тег, имя которого соответствует публикуемой версии, например — 1.0.
Примечание: За работой пайплайна можно проследить на странице CI/CD › Pipelines.
Чтобы убедиться, что настроенный механизм работает нормально, добавим в каждый md-файл строки «Это вторая версия» и, разместив коммит, создадим тег 2.0, чтобы опубликовать вторую версию документа.
Настройка генерации PDF
Итак, онлайн документация опубликована, самое время подумать о PDF. Расскажу о двух плагинах. Один попроще, но с ограниченными возможностями кастомизации генерируемого документа, второй, напротив, предлагает достаточно широкие возможности настройки, но требует уверенных знаний HTML/CSS и ощутимых временных затрат.
Коль скоро речь зашла о плагинах для MkDocs, хочется отметить, что их написано множество. Возможно, вы найдете что-нибудь интересное для себя.
Традиционно предлагаю рассмотреть два варианта реализации на разных сервисах: более простой вариант в GitHub, а посложнее — в GitLab.
Плагин mkdocs-print-site-plugin
Устанавливаем плагин локально.
pip install mkdocs-print-site-plugin
В раздел
plugins
конфигурационного файла mkdocs.yml добавляем параметр- print-site
.plugins: - search: ... - print-site
Примечание: Разработчики обращают внимание, что параметр
- print-site
должен быть в списке плагинов последним.Запускаем MkDocs локально.
Открываем в браузере URL http://127.0.0.1:8000/print_page/, нажимаем Ctrl+P и выбираем формат документа Save as PDF.
В файл .github/workflows/main.yml добавляем строку
- run: pip install mkdocs-print-site-plugin
.В файл mkdocs.yml можно добавить ряд настроек для плагина, см. комментарии в коде ниже.
plugins: - search: lang: - en - ru - print-site: add_to_navigation: true # Пункт "Распечатать PDF" в меню, см. след. парам. print_page_title: 'Распечатать PDF' # Название пункта, см. пред. парам. add_print_site_banner: false # Выключает ненужный:) баннер на странице печати add_table_of_contents: true # Включает отображение содержания toc_title: 'Содержание' # Название раздела с содержанием toc_depth: 6 # Количество уровней заголовков в содержании add_full_urls: false # Отображение адресов ссылок, например: ссылка (https://site) enumerate_headings: false # Отключает нумерацию заголовков enumerate_figures: true # Включает нумерацию рисунков add_cover_page: true # Включает отображение титульной страницы cover_page_template: "" # Путь к шаблону титульной страницы path_to_pdf: "" # Путь к сгенерированному PDF-документу include_css: true # Включает переопределение дефолтных CSS с целью кастомизации enabled: true # Включает плагин exclude: # Исключает страницы из PDF - index.md
Если отдельный пункт в горизонтальном меню не нужен, можно добавить соответствующую иконку на каждую страницу, просто включив следующий блок в созданный ранее файл overrides/main.html.
{% block content %} {% if page.url_to_print_page %} <a href="{{ page.url_to_print_page }}" title="Print Site" class="md-content__button md-icon"> {% include ".icons/material/printer.svg" %} </a> {% endif %} {{ super() }} {% endblock content %}
В целом, если этот плагин показался вам интересным и его функциональности достаточно для решения ваших задач, можете посмотреть документацию данного проекта, там есть исчерпывающая информация.
Вот такое простое и вместе с тем достаточно эффективное решение. Надеюсь, что оно найдет своих приверженцев.
Если по тем или иным причинам предложенной функциональности недостаточно, можно использовать другой плагин, обладающий более широкими возможностями кастомизации публикуемого документа.
Плагин mkdocs-with-pdf
Рассмотрим второй более сложный, но вместе с тем более функциональный вариант. Сразу предложу ознакомиться с примером — документацией для MkDocs Material, подготовленной с помощью этого решения. Очевидно, что уровень здесь совершенно другой. Если необходимы более широкие возможности кастомизации, этот вариант явно предпочтительнее.
В раздел
plugins
файла mkdocs.yml добавляем параметр- with-pdf
:plugins: - search: ... - with-pdf
В раздел
before_script
файла .gitlab-ci.yml в строку- apt -y install python3-pip
добавляем установку еще нескольких компонентов:
before_script:
- mkdir public
- apt update && apt install -y git
- apt -y install python3-pip python3-cffi python3-brotli libpango-1.0-0 libharfbuzz0b libpangoft2-1.0-0
- pip install mkdocs-material
- pip install mike
- pip install mkdocs-with-pdf
Размещаем коммит и добавляем/заменяем тег, чтобы опубликовать документацию.
В браузере откроем наш портал и добавим к адресу /pdf/document.pdf, чтобы получилось:
https://yourgroup.pages.yourdomain.com/docs/docopshabr/2.1/pdf/document.pdf.
У этого плагина гораздо больше настроек, см. комментарии ниже:
plugins: - search: lang: - en - ru - with-pdf: author: Автор Документа # Автор документа copyright: ©2023 Your company # Копирайт # cover: false # Отключает отображение обложки (С1 — титульный лист) # back_cover: true # Включает отображение обложки (С4 — задняя часть). На ней может отображаться QR-code со ссылкой на вашу документацию, см. ниже cover_title: Документация для Наш продукт # Заголовок на обложке С1 cover_subtitle: Руководство по установке • Руководство администратора # Подзаголовок на обложке С1 cover_logo: docs/assets/logo_fav.png # Логотип на обложку custom_template_path: templates # Директория с кастомизированными СSS toc_title: Содержание # Название раздела с содержанием # heading_shift: false # Отключает вложенность заголовков. Просто раскомментируйте этот параметр и посмотрите, как изменится содержание #toc_level: 3 # Уровни заголовков в содержании. К сожалению, максимальное значение — 3 ordered_chapter_level: 3 # Максимальный уровень нумеруемых заголовков. К сожалению, максимальное значение — 3 #excludes_children: # Исключает отдельные документы из генерируемого PDF # - 'release-notes/:upgrading' # см. секцию nav в этом файле # - 'release-notes/:changelog' # см. секцию nav в этом файле #exclude_pages: # Исключает отдельные папки из PDF # - 'ig/' # см. секцию nav в этом файле # - 'ag/contribute/' # см. секцию nav в этом файле #convert_iframe: # Конвертирует тег iframe в картинку со ссылкой # - src: IFRAME SRC # # img: POSTER IMAGE URL # # text: ALTERNATE TEXT # # - src: ... # two_columns_level: 3 # Bключает двухколоночную верстку, начиная с третьего уровня заголовков #render_js: true # Включает рендер результатов JS (требуется Headless Chrome) #headless_chrome_path: headless-chromium # путь к Headless Chrome output_path: ../site/Doc.pdf # Директория, в которую сохраняется PDF. В данном случае, чтобы просмотреть документ достаточно будет добавить к адресу в браузере Docs.pdf # enabled_if_env: PDF_EXPORT # Отключение генерации PDF, например при разработке (чтобы включить, комментируем эту строку) debug_html: true # Создает html-файл со всеми разделами. Незаменим при создании/редактировании стилей. Для вывода в файл, а не в терминал используем команду mkdocs build > pdf_print.html # verbose: true # Подробное логирование процесса генерации
Примечание: Для генерации QR-кода на задней обложке необходимо установить специальный плагин
- pip install qrcode
, а также добавить соответствующую строку (- pip install qrcode
) в разделbefore_script
файла .gitlab-ci.yml.Опубликуем изменения и, добавив Doc.pdf в адресной строке, посмотрим, как теперь выглядит наш документ:
https://yourgroup.pages.yourdomain.ru/docs/docopshabr/2.1/Doc.pdf
Настройка внешнего вида документа
Первое, что бросается в глаза при просмотре сгенерированного PDF, — это несоответствие шрифтов. Это проблема, особенно если в компании есть брендбуки и стайлгайды, регламентирующие использование элементов оформления.
Решить ее локально достаточно просто — установить необходимые гарнитуры на машину, на которой генерируется PDF, и прописать их в templates/styles.scss, о котором мы подробнее поговорим позже.
Но поскольку мы стремимся к полной автоматизации публикации, необходимо указать шрифты в пайплайне GitLab, чтобы при каждом тегировании собиралась и онлайн-версия документации, и генерировался новый PDF-документ с нужным оформлением.
Предположим, что для заголовков и основного текста мы хотим использовать гарнитуру Roboto, а для блоков кода — JetBrains Mono (выбор абсолютно случаен — нам просто нужен пример).
В рамках решения этой задачи мы также коснемся оформления других элементов генерируемого PDF, что позволит получить общее впечатление о механизме, который в дальнейшем каждый сможет использовать в своих целях.
Вспомним, что среди параметров плагина есть debug_html: true
. Если это не так, раскомментируем его.
Запустим сборку документации локально, выполнив команду mkdocs build
. Объем информации, отображаемой в терминале, увеличится: дело в том, что в него выводится файл html со всеми страницами, подготовленными для генерации PDF. Так работать неудобно, поэтому добавим к команде имя файла, в который будет сохраняться html — mkdocs build > pdf_print.html
. После ее выполнения в корне проекта появится подготовленный для генерации файл pdf_print.html.
Примечание: В некоторых ОС при попытке запустить локальную сборку с помощью команды mkdocs build
могут возникать ошибки, связанные с отсутствием отдельных библиотек. Пожалуйста, следуйте инструкциям по установке, а также по поиску и устранению неисправностей, на сайте разработчика WeasyPrint (именно он используется для конвертации HTML в PDF).
Открыв pdf_print.html в VS Code, заметим, что он включает интегрированные CSS и непосредственно html-разметку будущего документа. Нас, очевидно, больше интересует первая часть, поскольку, меняя стили отдельных элементов, мы сможем изменить общий вид генерируемого PDF.
Примечание: К большому сожалению, говорить о полной совместимости форматов не приходится, но многие стили WeasyPrint интерпретирует достаточно точно и при определенных трудозатратах можно добиться достойного результата.
Остается вопрос, каким образом мы можем менять стили. Все достаточно просто — необходимо в корне проекта создать файл templates/styles.scss и, прописывая стили в нем, мы будем переопределять их в промежуточном файле pdf_print.html, из которого, в свою очередь, и будет сгенерирован PDF-документ.
Чтобы проиллюстрировать сказанное, попробуем изменить формат листа генерируемого документа. Предположим, что вместо дефолтного А4 с книжной (портретной) ориентацией и полями 25-10-25-10 мм нам нужен формат А5 с альбомной ориентацией и полями 10 мм со всех сторон.
Добавим в файл templates/styles.scss следующие строки:
@page {
size: a5 landscape;
margin: 10mm;
}
Действуя аналогичным образом, можно переопределить все используемые в PDF-документе элементы, но я столкнулся с парой особенностей.
Если после изменения стиля вы не наблюдаете соответствующих изменений в сгенерированном PDF-документе, не стоит избегать использования модификатора !important
для того или иного свойства — зачастую это помогает.
Мне также приходилось сталкиваться с тем, что переносы страниц находились не в тех местах, в которых хотелось бы. Здесь следует использовать конструкции такого вида:
@media print {
section + section ul {
break-before: auto !important;
break-inside: auto !important;
}
section + section ol {
break-before: auto !important;
break-inside: auto !important; }
section + section pre {
break-before: avoid !important;
break-inside: auto !important; }
code {break-inside: auto !important;}
pre + span {break-inside: avoid !important;}
span + code {break-inside: avoid !important;}
p {break-inside: avoid !important; }
p + table {
break-before: avoid !important;
break-inside: auto !important;}
ul {break-inside: auto !important;}
h2 + table {break-inside: auto !important;}
table {break-inside: auto !important;}
p + div.highlight {
break-before: auto !important;
break-inside: avoid !important;}
div.highlight {
break-before: avoid !important;
break-inside: auto !important;}
section p + figure {
break-before: auto !important;
break-inside: avoid !important;
break-after: auto !important;
}
section h4 + div.highlight {
break-before: avoid !important;
break-inside: avoid !important;}
article * + div.highlight, article * + div.tabbed-set, section + section * + div.highlight, section + section * + div.tabbed-set {
page-break-before: avoid !important;
break-inside: auto !important;
}
}
Если необходимо принудительно поставить перенос в определенном месте, находим этот фрагмент в соответствующем md-файле и просто вставляем html-тег:
<div style="break-after: always"></div>
В общем случае этого приема следует избегать, но иногда без него не обойтись.
Если возьметесь за настройку дизайна генерируемого документа, перед вами длинный путь «увлекательных» экспериментов, но ситуация не безнадежна — вас ждет приличный результат.
Вернемся к проблеме со шрифтами. Чтобы добиться предсказуемости в отношении их использования, необходимо «скормить» их runner-у.
Скачаем архивы с нужными гарнитурами, например с Google Fonts, и разархивируем их в созданную в корне нашего проекта папку fonts.
.
├── docs
├── fonts
│ ├── JetBrainsMono-BoldItalic.ttf
│ ├── JetBrainsMono-Bold.ttf
│ ├── JetBrainsMono-ExtraBoldItalic.ttf
…
В раздел before_script
файла .gitlab-ci.yml добавим следующие строки:
before_script:
...
- mkdir -p /usr/share/fonts/truetype/google-fonts
- find /builds/your/repository/path/fonts/ -name "*.ttf" -exec install -m644 {} /usr/share/fonts/truetype/google-fonts/ \; || return 1
Примечание: Не забудьте заменить фрагмент your/repository/path на адрес реального репозитория.
И, безусловно, необходимо прописать стили для соответствующих элементов в файле templates/styles.scss, например, так:
* {
font-family: Roboto !important;
color: #666 !important;
font-size: 12pt !important;
line-height: 1.1 !important;
margin-left: 0 !important;
padding-left: 0 !important;
}
code {
font-family: 'JetBrains Mono' !important;
font-size: 10pt !important;
line-height: 1.1 !important;
}
Публикуем обновления и убеждаемся, что документ сгенерирован с использованием нужных шрифтов.
Очевидно, что это лишь небольшая часть пути, который придется пройти для определения стилей всего PDF-документа, но, познакомившись с принципом работы, остальное уже вопрос времени.
Примечание: Важно заметить, что при генерации PDF соответствующие шрифты внедряются в документ, и это гарантирует его неизменный вид на различных ОС.
Workflow/Gitflow
Пришло время поговорить об организации рабочего процесса в целом и о стратегии ветвления в частности. Обычно в ходе спринта проектная команда реализует несколько функциональностей, и задача технического писателя — отразить эту информацию в пользовательской документации.
Организация совместной работы
В рамках организации совместной работы развернутая нами система документирования может предложить интересную функциональность. Выполним еще пару настроек, чтобы познакомиться с ней.
Добавим в файл mkdocs.yml следующие строки:
GitHub
repo_name: DocOpsHabr Docs repo_url: https://github.dev/docopshabr/docopshabr edit_uri: blob/main/docs/
GitLab
repo_name: DocOpsHabr Docs repo_url: https://gitlab.yourdomain.com/-/ide/project/yourgroup/docs/docopshabr/ edit_uri: edit/main/-/docs/
Примечание: Не забудьте в параметре
repo_url
указать адрес реального репозитория.
В раздел
theme: features
этого же файла добавим параметрcontent.action.edit
:theme: ... features: ... - content.action.edit # вкл. редактирование страницы
В результате описанных действий на каждой странице появится иконка, при нажатии на которую будет происходить переход к редактированию соответствующего md-файла в удаленном репозитории.
Примечание: GitLab сразу открывает файлы для редактирования во встроенной веб-IDE. Чтобы добиться этого же в GitHub, необходимо несколько изменить параметры repo_url
и edit_uri
, в противном случае файлы придется редактировать файлы просто в интерфейсе GitHub.
repo_name: DocOpsHabr Docs
# repo_url: https://github.com/docopshabr/docopshabr
repo_url: https://github.dev/docopshabr/docopshabr
# edit_uri: edit/main/docs/
edit_uri: blob/main/docs/
Пользоваться настроенной функциональностью достаточно просто:
Открываем страницу, на которой хотим внести правку.
Нажимаем на иконку редактирования (см. выше).
Авторизуемся в GitHub.
Вносим изменения непосредственно в веб-IDE, которая, имеет уже привычный нам интерфейс и функционал VS Code.
Переходим на вкладку Source Control (Ctrl+Shift+G).
Комментируем и размещаем коммит.
Даем название создаваемой ветке и соглашаемся с предложением создать Fork.
Переходим на вкладку GitHub и нажимаем на иконку Create Pull Request.
При необходимости изменяем параметры PR и нажимаем на кнопку Create.
В открывшемся окне оставляем комментарий и нажимаем кнопку Comment справа внизу — Pull Request (PR) создан.
Далее владелец репозитория или другой пользователь, наделенный соответствующими правами, сможет просмотреть предлагаемый PR, при необходимости обсудить и изменить его, а затем принять и впоследствии опубликовать.
Кто может использовать этот механизм? Любой, кто хочет принять участие в разработке и улучшении документации, — а это и сотрудники компании (SME, QA, CS и т. д.), и, если модель распространения вашего продукта это допускает, обычные пользователи.
Можно, например, включать описанную функциональность только на тестовой версии документации на этапе разработки, ревью и тестирования и отключать перед окончательной публикацией. В непубличном репозитории можно ограничить доступ к тестовой версии только для участников рабочей группы (в GitLab, например, есть все необходимые для этого инструменты).
Теперь, имея общее представление о работе механизма, можно адаптировать его к конкретным особенностям вашей компании/проектной команды: сформировать процессы, распределить роли и определить критерии оценки.
Кроме этого, можно использовать весь богатый инструментарий, предлагаемый нам современными сервисами для работы с системами контроля версий. Мы получаем возможность не только организовать совместную работу специалистов, но и успешно пользоваться функциями управления проектом, трекинга задач, сбора обратной связи и т. д., — все это к нашим услугам.
GitFlow
Пару слов о стратегиях ветвления. До сих пор мы обходились одной веткой main, в которую последовательно добавляли коммиты (описания функциональностей), — это самый простой и достаточно распространенный gitflow.
Теперь представим ситуацию: мы добавили в ветку main описание нескольких функциональностей, разместили соответствующую версию документации на GitLab Pages, завершили ревью/тестирование, и ждем окончания релиза, чтобы все это благополучно опубликовать.
Но по тем или иным причинам оказывается, что описание одной описанной функциональности нужно опубликовать незамедлительно, не дожидаясь окончания спринта и/или выпуска релиза. Учитывая, что при этом могут быть затронуты несколько файлов, а также возможны изменения в графических материалах, ситуация не очень хорошая. Если в вашей практике это будет происходить регулярно, стоит задуматься о более сложной стратегии ветвления: выделять для описания каждой функциональности отдельную ветку и называть ее, скажем, по номеру задачи в трекинг-системе. При этом каждый раз «ветвиться» лучше от ветки main, а собирать тестовую версию документации в отдельной ветке testing. При таком gitflow можно ревьюировать и публиковать описания функциональностей в любой последовательности, независимо друг от друга.
Так у нас сохраняется текущая опубликованная версия документации и описание всех функциональностей, из которых мы в любой момент можем собрать релиз, а также мы не будем лишены возможности при необходимости оперативно публиковать HotFix-ы прямо в ветку main (с последующим дублированием в ветку testing, конечно). Проще представить этот gitflow на диаграмме — одна иллюстрация может стоить тысячи слов.
У такого подхода есть свои недостатки: усложненная стратегия — верный путь к мерж-конфликтам, особенно при совместной работе нескольких специалистов.
Выбор стратегии ветвления целиком зависит от особенностей ваших рабочих процессов. Со своей стороны скажу, что с некоторыми продуктами удается работать в рамках упрощенной стратегии, а для некоторых требуется более сложная.
Вместо заключения
Целью данной статьи является не всестороннее изучение функциональности используемых инструментов, а, скорее, легкое знакомство с предлагаемой концепцией, которая реализована с их использованием. У читателя появляется возможность оценить, насколько данное решение применимо в его компании, и при положительном решении он сможет использовать созданную в ходе наших рассуждений инструментальную среду в качестве базы при построении собственной системы документирования.
Система хорошо масштабируется — в соответствии с возникающими потребностями можно добавлять инструменты, начиная линтерами и спел-чекерами и заканчивая плагинами для публикации документации на нескольких языках.
В ходе дальнейшего анализа и, возможно, опытной эксплуатации системы, рекомендую оценить ее с точки зрения следующих аспектов, которые, очевидно, можно отнести к сильным сторонам:
повышение технологичности — увеличение скорости разработки и упрощение сопровождения технической документации;
повышение эффективности взаимодействия команды;
широкие возможности автоматизации — максимальное устранение рутинных операций;
упрощение организации и контроля командной работы;
глубокая интеграция с процессами продуктовой разработки;
эффективное использование ресурсов.
Полезные ссылки
Упражнения делались в публичном репозитории GitHub.
Конфигурационные файлы для GitLab можете скачать здесь (не забудьте внести изменения для вашего репозитория).
Документация MkDocs.
Документация MkDocs Material.
Плагин mkdocs-print-site-plugin
Плагин mkdocs-with-pdf