Skip to content

Commit

Permalink
v3.0.2 (#36)
Browse files Browse the repository at this point in the history
* Add Azure DevOps pipeline sample
* Add show debug step
* Add caching
* Add output for pdf path
* Various shellcheck fixes
  • Loading branch information
reijoh authored Mar 19, 2024
1 parent 81313a4 commit c66adce
Show file tree
Hide file tree
Showing 13 changed files with 911 additions and 220 deletions.
157 changes: 157 additions & 0 deletions .azuredevops/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
# Markdown to PDF converter

This is a Azure DevOps [pipeline](./markdown2pdf.yml) to publish a PDF artifact by converting Markdown files using a predefined template.

## Get started

To use the pipeline, several prerequisite steps are required:

1. If needed, [create a repo](https://learn.microsoft.com/en-us/azure/devops/repos/git/create-new-repo?view=azure-devops#create-a-repo-using-the-web-portal).

1. If needed, add [markdown](https://www.markdownguide.org/) documentation to the repo. It is recommended to keep the markdown files in a subfolder of a **"docs"** folder, for example **"docs/hld"**.

1. Add a **"document.order"** file in the markdown folder. It is recommended to only keep one order in each markdown folder.

1. Add markdown file names to **"document.order"**, one file name for each line.

Ensure that the file names are in the correct order. This is how they will appear in the PDF file.

Note that lines that start with the comment sign `#` will be ignored.

1. Add the [markdown2pdf.yml](./markdown2pdf.yml) to a repo folder with a name that represent what it converts, e.g. **".pipelines/docs.dns.design.yml"**.

1. Customize the variable values in the pipeline file and commit the changes.

1. Go to the Azure DevOps **Pipelines** page. Then choose the action to create a **New pipeline**.

1. Select **Azure Repos Git** as the location of the source code.

1. When the list of repositories appears, select the repository.

1. Select **Existing Azure Pipelines YAML file** and choose the YAML file, e.g. **"/.pipelines/docs.dns.design.yml"**.

1. Save the pipeline without running it.

1. Configure [branch policies](https://learn.microsoft.com/en-us/azure/devops/repos/git/branch-policies?view=azure-devops&tabs=browser#configure-branch-policies) for the default/main branch.

1. Add a [build validation branch policy](https://learn.microsoft.com/en-us/azure/devops/repos/git/branch-policies?view=azure-devops&tabs=browser#build-validation).

## Pipeline

The pipeline converts markdown to PDF using a [script](./../tools/convert.sh) and a [LaTeX template](./../tools/designdoc.tex).

### Template sections

The template has the following sections:

1. A **Title page** with a [cover logo](./../tools/designdoc-cover.png) and the document title and subtitle.

1. A **Version history page**. The content of this page is generated based on the following:

1. If a **HistoryFile** exist; use the content of that file.
1. Or, if **SkipGitCommitHistory** is set to `true` or a commit history don't exist; use the value of **MainAuthor** and **FirstChangeDescription**.
1. Or, use git commit history. Limit the number of items to the value of **GitLogLimit**.

1. A **Table of Content page**.

1. **Content pages** with the converted markdown files. This content is generated based on the following:

1. Merge the markdown files listed in the **"OrderFile"** to one markdown file.
1. Replace markdown links that have a relative path with a absolute path.
1. If a **ReplaceFile** exist; update the markdown file and replace each string that match the key from **ReplaceFile**, with the matching value.
1. Build metadata for the **"pandoc"** converter.
1. Convert the markdown using **"pandoc"** and save it as an artifact to the job.

1. **Page header** on all pages, except for the **Title page**:

- Left side: [logo](./../tools/designdoc-logo.png)
- Center: **Project** and **Author(s)**
- Right side: Current date.

1. **Page footer** on all pages, except for the **Title page**.

- Center: page number and total number of pages.

### Markdown tips

The markdown can include admonition blocks for text that need special attention.

The following blocks are supported: warning, important, note, caution, tip

Example:

```markdown
# A title

This is some regular text.

::: tip
This text is in a tip admonition block.
:::
```

### Issues

The following are known issues:

- Relative paths should start with `./` to ensure it can be replaced with absolute path before converting it to PDF.
- Markdown table columns can overlap in the PDF if the table is to wide, making text unreadable. To work around this:
- limit the text in the table. Typically it should be less than 80 characters wide.
- split the table up.
- use an ordered or unordered list.
- The template is designed for a standing A4 layout. It has no option to flip page orientation for one or several pages in a document.
- Titles are not automatically numbered. Titles can be manually numbered and maintained in the markdown document. To avoid having to manually update all titles, it is best to not use numbered titles if possible.

## Variables

- **FIRST_CHANGE_DESCRIPTION**: The first change description. This value will be used if a HistoryFile is not specified and a git commit comment is not available.

- **FOLDER**: The repository folder where the order file exist.

- **GIT_LOG_LIMIT**: Maximum entries to get from Git Log for version history.

- **HISTORY_FILE**: The name of the history file. This is a file with the version history content. The file must contain the following structure:

Version|Date|Author|Description

Example content for a history.txt file:

1|Oct 26, 2023|Jane Doe|Initial draft
2|Oct 28, 2023|John Doe|Added detailed design

- **MAIN_AUTHOR**: The main author of the PDF content. This value will be used if a HistoryFile is not specified and author can't be retrieved from git commits.

- **ORDER_FILE**: The name of the .order file. This is a text file with the name of each markdown file, one for each line, in the correct order.

Example content for a document.order file:

summary.md
details.md
faq.md

- **OUT_FILE**: The name of the output file. This file will be uploaded to the job artifacts.

- **PROJECT**: The project ID or name.

- **REPLACE_FILE**: The name of the replace file. This is a JSON file with key and value strings. Each key will be searched for in the markdown files and replaced with the value before conversion to PDF.

- **SKIP_GIT_COMMIT_HISTORY**: Skip using git commit history. When set to true, the change history will not be retrieved from the git commit log.

- **SUBTITLE**: The document subtitle.

- **TITLE**: The document title.

Example content for a replace.json file:

```json
{
"{data center name}": "WE1",
"{organization name}": "contoso"
}
```

- **WORKFLOW_VERSION**: The version of the markdown2pdf scripts to use. See <https://github.com/innofactororg/markdown2pdf/tags>.

## License

The code and documentation in this project are released under the [BSD 3-Clause License](./../LICENSE).
108 changes: 108 additions & 0 deletions .azuredevops/markdown2pdf.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
trigger: none
pr:
autoCancel: true
drafts: false

name: 📝 Convert Markdown

variables:
FIRST_CHANGE_DESCRIPTION: Initial draft
FOLDER: docs
GIT_LOG_LIMIT: 15
HISTORY_FILE:
MAIN_AUTHOR: Innofactor
ORDER_FILE: document.order
OUT_FILE: document.pdf
PROJECT:
REPLACE_FILE:
SKIP_GIT_COMMIT_HISTORY: false
SUBTITLE: Design Document
TITLE: DNS
WORKFLOW_VERSION: v3

pool:
vmImage: ubuntu-22.04

steps:
- checkout: self
displayName: Checkout
fetchDepth: 0

- task: Cache@2
displayName: Cache TeX Live
inputs:
key: 'texlive | "$(Agent.OS)"'
path: /opt/texlive

- task: Bash@3
displayName: Install tools
env:
SCRIPT: install-tools
VERSION: ${{ variables.WORKFLOW_VERSION }}
inputs:
targetType: inline
script: |
files=(
"${SCRIPT}.sh"
texlive.profile
texlive_packages.txt
requirements.txt
)
for file in "${files[@]}"; do
uri="https://github.com/innofactororg/markdown2pdf/raw/${VERSION}/tools/${file}"
HTTP_CODE=$(curl -sSL --remote-name --retry 4 \
--write-out "%{response_code}" \
--header 'Accept: application/vnd.github.raw' "${uri}"
)
if [ "${HTTP_CODE}" -lt 200 ] || [ "${HTTP_CODE}" -gt 299 ]; then
echo "##[error]Unable to get ${uri}! Response code: ${HTTP_CODE}"
exit 1
fi
done
chmod +x "${SCRIPT}.sh"
./"${SCRIPT}.sh"
- task: Bash@3
displayName: Build PDF
env:
AUTHOR: ${{ variables.MAIN_AUTHOR }}
DESCRIPTION: ${{ variables.FIRST_CHANGE_DESCRIPTION }}
SKIP_GIT_HISTORY: ${{ variables.SKIP_GIT_COMMIT_HISTORY }}
HISTORY: ${{ variables.HISTORY_FILE }}
LIMIT: ${{ variables.GIT_LOG_LIMIT }}
SCRIPT: convert
VERSION: ${{ variables.WORKFLOW_VERSION }}
inputs:
targetType: inline
script: |
files=(
"${SCRIPT}.sh"
designdoc.tex
designdoc-cover.png
designdoc-logo.png
)
for file in "${files[@]}"; do
uri="https://github.com/innofactororg/markdown2pdf/raw/${VERSION}/tools/${file}"
HTTP_CODE=$(curl -sSL --remote-name --retry 4 \
--write-out "%{response_code}" \
--header 'Accept: application/vnd.github.raw' "${uri}"
)
if [ "${HTTP_CODE}" -lt 200 ] || [ "${HTTP_CODE}" -gt 299 ]; then
echo "##[error]Unable to get ${uri}! Response code: ${HTTP_CODE}"
exit 1
fi
done
git config --global --add safe.directory '*'
chmod +x "${SCRIPT}.sh"
./"${SCRIPT}.sh" -a "${AUTHOR}" -d "${DESCRIPTION}" -f "${FOLDER}" \
-force "${SKIP_GIT_HISTORY}" -h "${HISTORY}" -l "${LIMIT}" \
-o "${ORDER_FILE}" -out "${OUT_FILE}" -p "${PROJECT}" \
-r "${REPLACE_FILE}" -s "${SUBTITLE}" -t "${TITLE}" \
--template "designdoc"
- task: PublishPipelineArtifact@1
displayName: Publish PDF
inputs:
targetPath: $(Build.SourcesDirectory)/${{ variables.OUT_FILE }}
artifact: ${{ variables.OUT_FILE }}
publishLocation: pipeline
17 changes: 9 additions & 8 deletions .devcontainer/setup.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#!/usr/bin/env sh
# shellcheck disable=SC2016
if [ -d "/var/run/docker.sock" ]; then
# Grant access to the docker socket
sudo chmod 666 /var/run/docker.sock
Expand All @@ -8,19 +9,19 @@ if ! [ -d ~/.ssh ]; then
if [ -d /tmp/.ssh-localhost ]; then
command mkdir -p -- ~/.ssh
sudo cp -R /tmp/.ssh-localhost/* ~/.ssh
sudo chown -R $(whoami):$(whoami) ~ || true ?>/dev/null
sudo chmod 400 ~/.ssh/*
sudo chown -R -- "$(whoami):$(whoami)" ~ || true -- ?>/dev/null
sudo chmod 400 -- ~/.ssh/*
fi
fi

apk add --no-cache git curl jq librsvg font-noto-cjk zsh bash starship
apk add --no-cache --repository=https://dl-cdn.alpinelinux.org/alpine/edge/community font-carlito font-fira-code-nerd shellcheck
apk add --no-cache bash font-noto-cjk starship zsh
apk add --no-cache --repository=https://dl-cdn.alpinelinux.org/alpine/edge/community font-fira-code-nerd shellcheck

pip install pre-commit
apk add --no-cache git curl jq librsvg
apk add --no-cache --repository=https://dl-cdn.alpinelinux.org/alpine/edge/community font-carlito

tlmgr update --self
tlmgr option -- autobackup -1
tlmgr install lastpage
#pip install --break-system-packages pre-commit
pip install pre-commit

if [ -f ~/.gitconfig ]; then
rm ~/.gitconfig
Expand Down
23 changes: 13 additions & 10 deletions .devcontainer/startup.sh
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
#!/usr/bin/env sh
if [ "${CODESPACES}" = "true" ]; then
# shellcheck disable=SC2016
if [ "${CODESPACES}" = 'true' ]; then
# Remove the default credential helper
sudo sed -i -E 's/helper =.*//' /etc/gitconfig

# Add one that just uses secrets available in the Codespace
git config --global credential.helper '!f() { sleep 1; echo "username=${GITHUB_USER}"; echo "password=${GH_TOKEN}"; }; f'
fi

if [ "$(git config --get safe.directory)" != "*" ]; then
git config --global --add safe.directory "*"
if [ "$(git config --get safe.directory)" != '*' ]; then
git config --global --add safe.directory '*'
fi
if [ "$(git config pull.rebase)" != "false" ]; then
if [ "$(git config pull.rebase)" != 'false' ]; then
git config --global pull.rebase false
fi
if [ "$(git config user.name)" = "" ]; then
echo "Warning: git user.name is not configured"
if [ "$(git config user.name)" = '' ]; then
echo 'Warning: git user.name is not configured'
fi
if [ "$(git config user.email)" = "" ]; then
echo "Warning: git user.email is not configured"
if [ "$(git config user.email)" = '' ]; then
echo 'Warning: git user.email is not configured'
fi

pre-commit install
pre-commit autoupdate
if type pre-commit > /dev/null 2>&1; then
pre-commit install
pre-commit autoupdate
fi
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@ jobs:
contents: write
steps:
- name: "Release"
uses: innofactororg/code-release@v1
uses: innofactororg/code-release@v2
with:
tag: ${{ github.event.inputs.tag }}
Loading

0 comments on commit c66adce

Please sign in to comment.