docs(ci): Deploy Previews (#1988)
* docs(ci): Support deploy previews for documentation Each PR that contributes to docs will generate a unique (to that PR) URL to preview the PR live for review. * docs(ci): Split workflow To support previews from non-collaborators PR contributions, we cannot rely on secrets access from workflows triggered by the `pull_request` event. To do so securely, according to official advice from Github, we must run the third-party contribution in the restricted `pull_request` context, and then use a 2nd workflow to deploy the build (which requires secrets access). * docs(ci): Rename doc workflows + add commit status Better naming convention for documentation workflows. Split workflow only indicated status on PR of the 1st stage (building the preview to deploy), not the deployment progress/result. This needs to be managed more directly until the action better supports split-workflow scenario. * docs(ci): Add concurrency limit to preview deploy workflow This would be more ideal on the 2nd phase workflow (`workflow_run`), however keeping it simple for now. Limits the concurrency of the initial pull request workflow for documentation contributions that have PRs with multiple event triggers in a small time span (before the workflow triggered would complete). The main benefit is to avoid redundant deploys if the initial workflow has been triggered again to build the PR once more. It only will work against concurrent workflows for that PR in the 1st stage, if an existing `workflow_run` (2nd stage) is active for that PR it will not be cancelled. * docs(ci): Add sponsor branding for deploy preview service A requirement from Netlify for the [sponsored OSS organization plan](https://www.netlify.com/legal/open-source-policy). * docs(ci): Use a shared build script Production and Deploy Preview builds are now maintained via the same shell command, so version updates of docker image is in one place. Additionally deletes unnecessary build output which upstream provides no support to exclude. * docs: Add a custom 404 page This is used by the preview deploys on Netlify. Production deploys on Github Pages require a top-level 404 page manually deployed (since all are deployed to a version subpath). This 404 page was custom built and optimized by me. This is the final minified output, separate source to build is available if needed. --- Likewise the `favicon.ico` is a fallback for browsers that implicitly check the domain root for this file if the SVG isn't supported/preferred. Browsers check for this file without it being present in the HTML head meta elements. On Github Pages the `favicon.ico` isn't likely to be picked up by even top-level as typical deployment has the project name as a subpath. The docs however reference a PNG favicon which should be widely supported. The `favicon.ico` was generated by RealFaviconGenerator online tool with SVG source input. It contains 16px, 32px and 48px sizes. Quality is better than the `favicon.io` generator. * chore: Optimized logo SVG source cleaned up and optimized with SVGO 2.3. Minified versions (`.min.svg` extension) remove unnecessary data and white-space to reduce size further for production use. This extension better differentiates by filename that it's different from the `src` version.
119
.github/workflows/docs-preview-deploy.yml
vendored
Normal file
|
@ -0,0 +1,119 @@
|
|||
name: 'Documentation (run)'
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ['Documentation (PR)']
|
||||
types:
|
||||
- completed
|
||||
|
||||
# Note: If limiting concurrency is required for this workflow:
|
||||
# 1. Add an additional job prior to `preview` to get the PR number make it an output.
|
||||
# 2. Assign that new job as a `needs` dependency for the `preview` job.
|
||||
# It is still required for `preview` job to download the artifact so that it can access the preview build files.
|
||||
|
||||
# This workflow runs off the primary branch and has access to secrets as expected.
|
||||
jobs:
|
||||
preview:
|
||||
name: 'Deploy Preview'
|
||||
runs-on: ubuntu-20.04
|
||||
if: ${{ github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' }}
|
||||
steps:
|
||||
|
||||
# ======================== #
|
||||
# Restore workflow context #
|
||||
# ======================== #
|
||||
|
||||
# The official Github Action for downloading artifacts does not support multi-workflow
|
||||
- name: 'Download build artifact'
|
||||
uses: dawidd6/action-download-artifact@v2
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
workflow: docs-preview-prepare.yml
|
||||
name: preview-build
|
||||
|
||||
- name: 'Extract build artifact'
|
||||
run: tar -xf artifact.tar.zst
|
||||
|
||||
- name: 'Restore preserved ENV'
|
||||
run: cat pr.env >> "${GITHUB_ENV}"
|
||||
|
||||
# ==================== #
|
||||
# Deploy preview build #
|
||||
# ==================== #
|
||||
|
||||
# Manage workflow deployment status. `enable-commit-status` from `nwtgck/actions-netlify` would handle this,
|
||||
# but presently does not work correctly via split workflow. It is useful in a split workflow as the 1st stage
|
||||
# no longer indicates if the entire workflow/deployment was successful.
|
||||
- name: 'Commit Status: Set Workflow Status as Pending'
|
||||
uses: myrotvorets/set-commit-status-action@1.0.2
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
status: pending
|
||||
# Should match `env.PR_HEADSHA` when triggered by `pull_request` event workflow,
|
||||
# Avoids failure of ENV being unavailable if job fails early:
|
||||
sha: ${{ github.event.workflow_run.head_sha }}
|
||||
context: 'Deploy Preview (pull_request => workflow_run)'
|
||||
|
||||
- name: 'Send preview build to Netlify'
|
||||
uses: nwtgck/actions-netlify@v1.2
|
||||
id: preview
|
||||
timeout-minutes: 1
|
||||
env:
|
||||
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
|
||||
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# Fail the job early if credentials are missing / invalid:
|
||||
fails-without-credentials: true
|
||||
# Sets/creates the Netlify deploy URL prefix.
|
||||
# Uses the PR number for uniqueness:
|
||||
alias: ${{ env.NETLIFY_SITE_PREFIX }}
|
||||
# Only publish the contents of the build output:
|
||||
publish-dir: ${{ env.BUILD_DIR }}
|
||||
# Custom message for the deploy log on Netlify:
|
||||
deploy-message: '${{ env.PR_TITLE }} (PR #${{ env.PR_NUMBER }} @ commit: ${{ env.PR_HEADSHA }})'
|
||||
|
||||
# Note: Split workflow incorrectly references latest primary branch commit for deployment.
|
||||
# Assign to non-default Deployment Environment for better management:
|
||||
github-deployment-environment: documentation-previews
|
||||
github-deployment-description: 'Preview deploy for documentation PRs'
|
||||
|
||||
# Note - PR context used by this action is incorrect. These features are broken with split workflow:
|
||||
# https://github.com/nwtgck/actions-netlify/issues/545
|
||||
# Disable unwanted action defaults:
|
||||
# Disable adding deploy comment on pre-merge commit (Github creates this for PR diff):
|
||||
enable-commit-comment: false
|
||||
# Disable adding a "Netlify - Netlify deployment" check status:
|
||||
enable-commit-status: false
|
||||
# Disable. We provide a custom PR comment in the next action:
|
||||
enable-pull-request-comment: false
|
||||
|
||||
# If a `netlify.toml` config is ever needed, enable this:
|
||||
# netlify-config-path: ./docs/netlify.toml
|
||||
# If ever switching from Github Pages, enable this conditionally (false by default):
|
||||
# production-deploy: false
|
||||
|
||||
- name: 'Comment on PR: Add/Update deployment status'
|
||||
uses: marocchino/sticky-pull-request-comment@v2
|
||||
with:
|
||||
number: ${{ env.PR_NUMBER }}
|
||||
header: preview-comment
|
||||
message: |
|
||||
[Documentation preview for this PR](${{ steps.preview.outputs.deploy-url }}) is ready! :tada:
|
||||
|
||||
Built with commit: ${{ env.PR_HEADSHA }}
|
||||
|
||||
- name: 'Commit Status: Update deployment status'
|
||||
uses: myrotvorets/set-commit-status-action@1.0.2
|
||||
# Always run this step regardless of job failing early:
|
||||
if: ${{ always() }}
|
||||
env:
|
||||
DEPLOY_SUCCESS: Successfully deployed preview.
|
||||
DEPLOY_FAILURE: Failed to deploy preview.
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
status: ${{ job.status == 'success' && 'success' || 'failure' }}
|
||||
sha: ${{ github.event.workflow_run.head_sha }}
|
||||
context: 'Deploy Preview (pull_request => workflow_run)'
|
||||
description: ${{ job.status == 'success' && env.DEPLOY_SUCCESS || env.DEPLOY_FAILURE }}
|
70
.github/workflows/docs-preview-prepare.yml
vendored
Normal file
|
@ -0,0 +1,70 @@
|
|||
name: 'Documentation (PR)'
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'docs/**'
|
||||
|
||||
# If the workflow for a PR is triggered multiple times, previous existing runs will be canceled.
|
||||
# eg: Applying multiple suggestions from a review directly via the Github UI.
|
||||
# Instances of the 2nd phase of this workflow (via `workflow_run`) presently lack concurrency limits due to added complexity.
|
||||
concurrency:
|
||||
group: deploypreview-pullrequest-${{ github.event.pull_request.number }}
|
||||
cancel-in-progress: true
|
||||
|
||||
# `pull_request` workflow is unreliable alone: Non-collaborator contributions lack access to secrets for security reasons.
|
||||
# A separate workflow (docs-preview-deploy.yml) handles the deploy after the potentially untrusted code is first run in this workflow.
|
||||
# See: https://securitylab.github.com/research/github-actions-preventing-pwn-requests/
|
||||
jobs:
|
||||
prepare-preview:
|
||||
name: 'Build Preview'
|
||||
runs-on: ubuntu-20.04
|
||||
env:
|
||||
BUILD_DIR: docs/site
|
||||
NETLIFY_SITE_PREFIX: pullrequest-${{ github.event.pull_request.number }}
|
||||
NETLIFY_SITE_NAME: dms-doc-previews
|
||||
steps:
|
||||
- uses: actions/checkout@v2.3.4
|
||||
|
||||
- name: 'Build with mkdocs-material via Docker'
|
||||
working-directory: docs
|
||||
env:
|
||||
PREVIEW_URL: 'https://${NETLIFY_SITE_PREFIX}--${NETLIFY_SITE_NAME}.netlify.app/'
|
||||
NETLIFY_BRANDING: '<img alt="Deploys by Netlify" src="https://www.netlify.com/img/global/badges/netlify-color-accent.svg" style="float: right;">'
|
||||
run: |
|
||||
# Adjust mkdocs.yml for preview build
|
||||
sed -i "s|^site_url:.*|site_url: '${PREVIEW_URL}'|" mkdocs.yml
|
||||
|
||||
# Insert sponsor branding into page content (Provider OSS plan requirement):
|
||||
# Upstream does not provide a nicer maintainable way to do this..
|
||||
# Prepends HTML to copyright text and then aligns to the right side.
|
||||
sed -i "s|^copyright: '|copyright: '${NETLIFY_BRANDING}|" mkdocs.yml
|
||||
# Need to override a CSS media query for parent element to always be full width:
|
||||
echo '.md-footer-copyright { width: 100%; }' >> content/assets/css/customizations.css
|
||||
|
||||
../.github/workflows/scripts/docs/build-docs.sh
|
||||
|
||||
# ============================== #
|
||||
# Volley over to secure workflow #
|
||||
# ============================== #
|
||||
|
||||
# Minimize risk of upload failure by bundling files to a single compressed archive (tar + zstd).
|
||||
# Bundles build dir and env file into a compressed archive, nested file paths will be preserved.
|
||||
- name: 'Prepare artifact for transfer'
|
||||
run: |
|
||||
# Save ENV for transfer
|
||||
echo "PR_HEADSHA=${{ github.event.pull_request.head.sha }}" >> pr.env
|
||||
echo "PR_NUMBER=${{ github.event.pull_request.number }}" >> pr.env
|
||||
echo "PR_TITLE=${{ github.event.pull_request.title }}" >> pr.env
|
||||
echo "NETLIFY_SITE_PREFIX=${{ env.NETLIFY_SITE_PREFIX }}" >> pr.env
|
||||
echo "BUILD_DIR=${{ env.BUILD_DIR }}" >> pr.env
|
||||
|
||||
tar --zstd -cf artifact.tar.zst pr.env ${{ env.BUILD_DIR }}
|
||||
|
||||
- name: 'Upload artifact for workflow transfer'
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: preview-build
|
||||
path: artifact.tar.zst
|
||||
retention-days: 1
|
||||
|
|
@ -40,8 +40,7 @@ jobs:
|
|||
|
||||
- name: 'Build with mkdocs-material via Docker'
|
||||
working-directory: docs
|
||||
# --user is required for build output file ownership to match the CI user instead of the containers internal user
|
||||
run: docker run --rm --user "$(id -u):$(id -g)" -v "${PWD}:/docs" squidfunk/mkdocs-material:7.1.4 build --strict
|
||||
run: '../.github/workflows/scripts/docs/build-docs.sh'
|
||||
|
||||
- name: 'If a tagged version, fix canonical links and remove `404.html`'
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
|
@ -51,8 +50,8 @@ jobs:
|
|||
# (Note the edge 404.html isn't useful either as it's not copied to the `gh-pages` branch root)
|
||||
rm 404.html
|
||||
|
||||
# Replace '${DOCS_VERSION}' (defaults to 'edge') in the 'canonical' link element of HTML files,
|
||||
# with the tagged docs version:
|
||||
# Replace the tagged '${DOCS_VERSION}' in the 'canonical' link element of HTML files,
|
||||
# to point to the 'edge' version of docs as the authoritative source:
|
||||
find . -type f -name "*.html" -exec \
|
||||
sed -i "s|^\(.*<link rel=\"canonical\".*\)${DOCS_VERSION}|\1edge|" \
|
||||
{} +
|
22
.github/workflows/pr-docs.yml
vendored
|
@ -1,22 +0,0 @@
|
|||
name: 'Documentation'
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/pr-docs.yml'
|
||||
- 'docs/**'
|
||||
|
||||
# Jobs will run shell commands from this subdirectory:
|
||||
defaults:
|
||||
run:
|
||||
working-directory: docs
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: 'Verify Build'
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2.3.4
|
||||
|
||||
- name: 'Build with mkdocs-material via Docker'
|
||||
run: docker run --rm -v ${PWD}:/docs squidfunk/mkdocs-material:7.1.4 build --strict
|
16
.github/workflows/scripts/docs/build-docs.sh
vendored
Executable file
|
@ -0,0 +1,16 @@
|
|||
#!/bin/bash
|
||||
|
||||
# `--user` is required for build output file ownership to match the CI user,
|
||||
# instead of the internal root user of the container.
|
||||
docker run \
|
||||
--rm \
|
||||
--user "$(id -u):$(id -g)" \
|
||||
-v "${PWD}:/docs" \
|
||||
squidfunk/mkdocs-material:7.1.4 build --strict
|
||||
|
||||
# Remove unnecessary build artifacts: https://github.com/squidfunk/mkdocs-material/issues/2519
|
||||
cd site || exit
|
||||
find . -type f -name '*.min.js.map' -delete -o -name '*.min.css.map' -delete
|
||||
rm sitemap.xml.gz
|
||||
rm assets/images/favicon.png
|
||||
rm -r assets/javascripts/lunr
|
|
@ -3,7 +3,8 @@
|
|||
# CI ENV `GITHUB_REF` from Github Actions CI provides the tag or branch that triggered the build
|
||||
# See `github.ref`: https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context
|
||||
# https://docs.github.com/en/actions/reference/environment-variables
|
||||
function _update-versions-json {
|
||||
function _update_versions_json
|
||||
{
|
||||
# Extract the version tag, truncate `<PATCH>` version and any suffix beyond it.
|
||||
local MAJOR_MINOR
|
||||
MAJOR_MINOR=$(grep -oE 'v[0-9]+\.[0-9]+' <<< "${GITHUB_REF}")
|
||||
|
|
BIN
docs/content/assets/logo/.src/dmo-logo-white.png
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
docs/content/assets/logo/.src/dmo-logo-white.svg
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
docs/content/assets/logo/.src/dmo-logo.png
Normal file
After Width: | Height: | Size: 52 KiB |
BIN
docs/content/assets/logo/.src/dmo-logo.svg
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
docs/content/assets/logo/dmo-logo-white.min.svg
Normal file
After Width: | Height: | Size: 677 B |
Before Width: | Height: | Size: 1.9 KiB |
BIN
docs/content/assets/logo/dmo-logo.min.svg
Normal file
After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 5.6 KiB |
|
@ -20,13 +20,14 @@ docs_dir: 'content/'
|
|||
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Choosing_between_www_and_non-www_URLs#using_%3Clink_relcanonical%3E
|
||||
# Also required for `sitemap.xml` generation at build time; which bots use to assist them crawling and indexing a website,
|
||||
# the `mkdocs-material` 'Instant Navigation' feature utilizes the sitemap data to work.
|
||||
site_url: 'https://docker-mailserver.github.io/docker-mailserver/edge'
|
||||
site_url: 'https://docker-mailserver.github.io/docker-mailserver/edge/'
|
||||
|
||||
# Anything related to the `mkdocs-material` theme config goes here:
|
||||
theme:
|
||||
name: 'material'
|
||||
custom_dir: 'overrides/'
|
||||
favicon: assets/logo/favicon-32x32.png
|
||||
logo: assets/logo/dmo-logo-white.svg
|
||||
logo: assets/logo/dmo-logo-white.min.svg
|
||||
icon:
|
||||
repo: fontawesome/brands/github
|
||||
features:
|
||||
|
@ -36,7 +37,7 @@ theme:
|
|||
- navigation.instant
|
||||
palette:
|
||||
# Light mode
|
||||
- media: "(prefers-color-scheme: light)"
|
||||
- media: '(prefers-color-scheme: light)'
|
||||
scheme: default
|
||||
primary: indigo
|
||||
accent: indigo
|
||||
|
@ -44,7 +45,7 @@ theme:
|
|||
icon: material/weather-night
|
||||
name: Switch to dark mode
|
||||
# Dark mode
|
||||
- media: "(prefers-color-scheme: dark)"
|
||||
- media: '(prefers-color-scheme: dark)'
|
||||
scheme: slate
|
||||
primary: indigo
|
||||
accent: blue
|
||||
|
|
1
docs/overrides/404.html
Normal file
BIN
docs/overrides/assets/img/bg-water.webp
Normal file
After Width: | Height: | Size: 91 KiB |
BIN
docs/overrides/favicon.ico
Normal file
After Width: | Height: | Size: 15 KiB |