woozymasta/regdoc

By woozymasta

Updated 1 day ago

Build and publish container registry descriptions from project Markdown

Image
Integration & delivery
Developer tools
0

603

woozymasta/regdoc repository overview

regdoc

Git project: WoozyMasta/regdoc

License: MIT


regdoc

regdoc combines Markdown documentation from a project into one document, normalizes links and structure, and publishes the result to the container registry alongside the image.

It lets you reuse README files, changelogs, links, and metadata from the source repository and keep them available to users in Docker Hub, Quay, or Harbor.

Installation

Download a binary for your platform from the releases page, or install it with Go:

go install github.com/woozymasta/regdoc/cmd/regdoc@latest

Container images

ghcr.io/woozymasta/regdoc:latest
docker.io/woozymasta/regdoc:latest

Publish documentation

By default, regdoc finds README.md and CHANGELOG.md in the work directory, merges them, and publishes the result. The provider is determined from the image hostname.

Docker Hub uses a username with a password or personal access token:

REGDOC_USERNAME="example" REGDOC_TOKEN="$DOCKERHUB_TOKEN" \
  regdoc example/service

Publishing a Docker Hub description requires a PAT with Delete permission; image push permission alone is not sufficient.

For Quay, provide an OAuth token:

REGDOC_TOKEN="$QUAY_TOKEN" \
  regdoc quay.io/example/service

Harbor requires a username and password:

REGDOC_USERNAME="example" REGDOC_PASSWORD="$HARBOR_PASSWORD" \
  regdoc registry.example/team/service

Docker Hub and Harbor also use the Docker credential store and credential helpers when explicit credentials are absent. Select --provider explicitly when the registry hostname is ambiguous.

Do not pass secrets as command-line arguments. Use environment variables, --password-stdin, or --token-stdin.

Skipping stale publishes

The registry description is a single field per repository, shared across every tag. When parallel release lines (e.g. a 3.x and a 2.x branch) build independently, CI can publish out of version order and leave the description showing older docs than what was already there.

Add an explicit tag to IMAGE to guard against this:

regdoc quay.io/example/service:3.1.1

When IMAGE carries an explicit tag, regdoc lists the tags already published in the repository - using the same credentials already resolved for publishing, no extra permissions needed - finds the highest existing stable release, and skips publishing (a no-op, not an error) if tag being published is older. Equal versions still publish, so re-running the same tag's CI job is safe. A tag that isn't a valid stable SemVer release (:latest, :nightly, :sha-abcdef, prereleases) is treated the same as no tag at all: publish unconditionally. Without an explicit tag, behavior is unchanged from today.

--skip-tag-check bypasses the gate and publishes regardless of tag order.

--version-format selects how tags are compared: semver (the default, shown above), calver, numeric, lexical, pep440, debian, or rpm. --calver-format picks the calendar layout when --version-format=calver:

regdoc --version-format=calver --calver-format=ym-dot \
  quay.io/example/service:2026.07

A tag that does not match the configured format is treated the same as no tag at all: publish unconditionally.

Release version in the header

The generated header shows a Release line, when a version is known. --release-version sets it explicitly; without it, regdoc falls back to IMAGE's explicit tag (the same tag the stale-publish gate above reads), shown as-is with no validation:

regdoc --release-version=3.1.1 quay.io/example/service

When the source forge and project URL are known (see "Documents, links, and images" below), the release is linked to that version's tag page in the forge - not a Releases page, since a Release object is optional and a git tag is not. Without a known forge or without any version at all, the line is either plain text or omitted entirely.

Typical CI invocation

This example selects the provider explicitly, supplies project metadata, and uses a known corporate registry limit. Files are published in the listed order.

REGDOC_TOKEN="$QUAY_TOKEN" \
  regdoc \
  --provider=quay \
  --title="$CI_PROJECT_TITLE" \
  --source-url="$CI_PROJECT_URL" \
  --short-description="$CI_PROJECT_DESCRIPTION" \
  --doc-body-limit=65536 \
  --cut-heading-level=2 \
  --cut-retries=3 \
  quay.io/example/service \
  README.md docs/*.md CHANGELOG.md

docs/*.md is expanded by regdoc itself, including in PowerShell. Matches are added in lexical order.

Note

Supplying an explicit file list disables automatic selection of `README.md` and `CHANGELOG.md`.

CI examples

GitHub Actions runs the job in the image:

jobs:
  publish-documentation:
    runs-on: ubuntu-latest
    container: ghcr.io/woozymasta/regdoc:latest
    steps:
      - uses: actions/checkout@v6
      - env:
          REGDOC_TOKEN: ${{ secrets.QUAY_TOKEN }}
        run: regdoc quay.io/example/service README.md 'docs/*.md' CHANGELOG.md

GitLab CI requires an empty entrypoint so the runner can start its shell:

publish-documentation:
  image:
    name: ghcr.io/woozymasta/regdoc:latest
    entrypoint: [""]
  script:
    - regdoc quay.io/example/service README.md 'docs/*.md' CHANGELOG.md

Set REGDOC_TOKEN, REGDOC_USERNAME, and REGDOC_PASSWORD as protected CI variables when required by the target registry.

Local preview

--output disables publishing: no registry detection, credential lookup, or network requests occur.

Write Markdown to stdout:

regdoc --output - quay.io/example/service

Save HTML:

regdoc --format html --output description.html quay.io/example/service

HTML is useful for registries with limited Markdown support, such as legacy Quay UI versions that do not render tables.

Without explicit files, regdoc finds README.md and CHANGELOG.md under --root and adds them in that order. An explicit list disables autodiscovery:

regdoc quay.io/example/service README.md docs/*.md CHANGELOG.md

--link-base-url and --image-base-url turn relative file and image links into source repository links. A Markdown link needs a different route than a Markdown image on every supported forge, so the two are separate flags: set both or neither, setting only one is a configuration error.

When both are absent, regdoc determines them from CI metadata, trying providers in this order and stopping at the first one whose CI sentinel matches - an incomplete profile leaves relative links untouched rather than falling back to another provider or a default branch:

  • GitLab CI (GITLAB_CI=true): CI_PROJECT_URL and CI_COMMIT_SHA; links use -/blob/<sha>/, images use -/raw/<sha>/.
  • Bitbucket Pipelines (BITBUCKET_BUILD_NUMBER set): BITBUCKET_GIT_HTTP_ORIGIN and BITBUCKET_COMMIT; links use src/<sha>/, images use raw/<sha>/.
  • Forgejo Actions (FORGEJO_ACTIONS=true, Forgejo Runner v7.0.0+ only): FORGEJO_SERVER_URL, FORGEJO_REPOSITORY, FORGEJO_SHA, falling back per-field to the GITHUB_*-compatible aliases Forgejo also sets; links use src/commit/<sha>/, images use raw/commit/<sha>/. Older runners never set FORGEJO_ACTIONS and are picked up by the GitHub Actions profile below instead - there is no reliable way to tell them apart.
  • Gitea Actions (GITEA_ACTIONS=true): GITHUB_SERVER_URL, GITHUB_REPOSITORY, GITHUB_SHA (Gitea has no native variables of its own for these); same route shape as Forgejo.
  • GitHub Actions (GITHUB_ACTIONS=true): GITHUB_SERVER_URL, GITHUB_REPOSITORY, GITHUB_SHA; links use blob/<sha>/, images use raw/<sha>/.
  • Woodpecker CI (CI_FORGE_TYPE set): CI_REPO_URL and CI_COMMIT_SHA, with the route shape selected by the reported forge type (github, gitlab, gitea, forgejo, bitbucket, bitbucket_dc).

All discovered links are pinned to a full commit SHA, never a branch name. An unsupported forge, a proxy, or a third-party CI system with no forge-identifying variable (Drone, CircleCI, Jenkins, and similar) can opt in explicitly:

regdoc \
  --link-base-url="https://git.example/team/project/blob/0123456789abcdef/" \
  --image-base-url="https://git.example/team/project/raw/0123456789abcdef/" \
  quay.io/example/service

These bases include the forge route and revision. The source project URL shown in the header is configured separately with --source-url.

The same override also covers a deliberate choice to point documentation at a mutable ref instead of the pinned commit, e.g. always linking to a project's default branch:

regdoc \
  --link-base-url="$CI_PROJECT_URL/-/blob/$CI_DEFAULT_BRANCH/" \
  --image-base-url="$CI_PROJECT_URL/-/raw/$CI_DEFAULT_BRANCH/" \
  quay.io/example/service

The same CI data populates the generated header when --title, --source-name, and --source-url are not set:

  • GitLab CI: CI_PROJECT_TITLE, CI_PROJECT_PATH, CI_PROJECT_URL.
  • Bitbucket Pipelines: BITBUCKET_REPO_SLUG, BITBUCKET_REPO_FULL_NAME, and BITBUCKET_GIT_HTTP_ORIGIN.
  • Forgejo Actions, Gitea Actions, GitHub Actions: GITHUB_SERVER_URL and GITHUB_REPOSITORY (or the native FORGEJO_* variables when Forgejo sets them); the title is the final repository path component.
  • Woodpecker CI: CI_REPO_URL; the title is the final path component.

Explicit --title, --source-name, and --source-url always win over discovered metadata.

For private projects, local images can be embedded as base64 in the document:

regdoc --embed-images quay.io/example/service

Only files inside --root are embedded; external URLs remain unchanged. Data URIs increase description size, so account for selected registry limit.

Important

In addition to their size, not every registry can render base64 images in document links. Verify the result with the target registry.

Reference

The complete option list and default values are available in CLI.md and in the command itself:

regdoc --help
regdoc docs md -

regdoc

NAME

regdoc - Publish repository documentation to container registry descriptions.

SYNOPSIS

regdoc [OPTIONS]

Table of Contents

DESCRIPTION

regdoc collects repository Markdown and publishes it as the description of a Docker Hub, Quay or Harbor container registry.

OPTIONS

Output Options
OptionDescriptionDefaultEnvironmentRequired
--short-descriptionShort description, where supported by the provider$REGDOC_SHORT_DESCRIPTIONno
--fallbackBehavior when the payload is too large; choices: none, cutcut$REGDOC_FALLBACKno
-o, --outputWrite generated content without publishing; use - for stdout$REGDOC_OUTPUTno
--formatOutput format: md or html; choices: md, htmlmd$REGDOC_FORMATno
--doc-body-limitMaximum rendered document body size in bytes; zero uses the provider default0$REGDOC_DOC_BODY_LIMITno
--cut-heading-levelPrefer a heading from level 1 through this level as the cut boundary2$REGDOC_CUT_HEADING_LEVELno
--cut-retriesMaximum additional publish attempts after a payload-too-large response5$REGDOC_CUT_RETRIESno
--embed-imagesEmbed local images as base64 data URIs$REGDOC_EMBED_IMAGESno
Document Options
OptionDescriptionEnvironmentRequired
--titleProject title used in the generated header$REGDOC_TITLEno
--source-nameProject name shown in the generated header$REGDOC_SOURCE_NAMEno
--source-urlProject URL shown in the generated header$REGDOC_SOURCE_URLno
--release-versionRelease version shown in the generated header; defaults to IMAGE's explicit tag$REGDOC_RELEASE_VERSIONno
--licenseLicense file to identify in the header (default: auto-discover LICENSE in --root)$REGDOC_LICENSEno
--authorAuthor shown in the generated header$REGDOC_AUTHORno
--copyrightCopyright notice shown in the generated header$REGDOC_COPYRIGHTno
--link-base-urlBase URL prepended to relative Markdown link destinations; overrides CI URL discovery (requires --image-base-url)$REGDOC_LINK_BASE_URLno
--image-base-urlBase URL prepended to relative Markdown image destinations; overrides CI URL discovery (requires --link-base-url)$REGDOC_IMAGE_BASE_URLno
--keep-commentsKeep HTML comments instead of stripping them from the published Markdown$REGDOC_KEEP_COMMENTSno
Target Options
OptionDescriptionDefaultEnvironmentRequired
-p, --providerProvider: auto, dockerhub, quay or harbor; choices: auto, dockerhub, quay, harborauto$REGDOC_PROVIDERno
-r, --rootRoot directory for document discovery and relative link resolution.$REGDOC_ROOTno
--plain-httpUse plain HTTP for the target registry$REGDOC_PLAIN_HTTPno
--tls-skip-verifyDisable TLS certificate verification for the target registry$REGDOC_TLS_SKIP_VERIFYno
Authentication Options
OptionDescriptionEnvironmentRequired
--usernameRegistry username$REGDOC_USERNAMEno
--passwordRegistry password (prefer --password-stdin or REGDOC_PASSWORD: CLI arguments are visible to other processes)$REGDOC_PASSWORDno
--tokenAPI token (prefer --token-stdin or REGDOC_TOKEN: CLI arguments are visible to other processes)$REGDOC_TOKENno
--password-stdinRead the password from stdin$REGDOC_PASSWORD_STDINno
--token-stdinRead the token from stdin$REGDOC_TOKEN_STDINno
Runtime Options
OptionDescriptionDefaultEnvironmentRequired
--version-formatVersion format used to compare IMAGE's tag against existing tags; choices: semver, calver, numeric, lexical, pep440, debian, rpmsemver$REGDOC_VERSION_FORMATno
--calver-formatBuilt-in CalVer layout used when --version-format=calver; choices: ymd-dash, ymd-dot, ym-dot, ym-shortymd-dash$REGDOC_CALVER_FORMATno
--timeoutPer-request HTTP timeout30s$REGDOC_TIMEOUTno
--optionalTreat missing documents, credentials or repository as a successful no-op$REGDOC_OPTIONALno
--skip-tag-checkPublish even if IMAGE's tag is older than the highest already-published stable tag$REGDOC_SKIP_TAG_CHECKno
--debugPrint technical diagnostics to stderr$REGDOC_DEBUGno
-q, --quietSuppress informational output (errors are still printed)$REGDOC_QUIETno
Help Options
OptionDescriptionRequired
-h, --helpShow this help messageno
-v, --versionShow version informationno

COMMANDS

Help Commands

help

Show help

Usage: regdoc [OPTIONS] help

version

Show version information

Usage: regdoc [OPTIONS] version [version-OPTIONS]

Show version information
OptionDescriptionRequired
--shortPrint version number onlyno
--commitPrint commit SHA onlyno
--jsonPrint version information as JSONno
completion

Generate shell completion

Usage: regdoc [OPTIONS] completion [completion-OPTIONS]

Generate shell completion
OptionDescriptionRequired
--shellShell completion format; choices: bash, zsh, pwshno
Arguments
NameDescriptionRequired
outputOutput file pathno

ARGUMENTS

NameDescriptionRequired
IMAGEContainer repository referenceyes
MARKDOWNMarkdown files or glob patterns to publish, in orderno

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

0.3.0 - 2026-08-11

Changed
  • Replace go-containerregistry with ORAS for image-reference validation and Docker-compatible host credential lookup.
  • Replace goldmark-markdown with a maintained internal CommonMark renderer compatible with Goldmark 1.8.5.
Removed
  • Remove transitive Docker CLI, credential-helper library, and Logrus dependencies from the binary.

0.2.0 - 2026-07-27

Added
  • Skip publishing when IMAGE tag is older than the highest already-published tag, --skip-tag-check to bypass gate, --version-format/--calver-format to pick the comparison format.
  • --release-version show a Release line in the generated header, linked to that version's tag page when the source forge is known. Defaults to IMAGE's explicit tag.
  • Automatic source link/image URL discovery for Woodpecker CI.
Changed
  • Replace --base-url with --link-base-url/--image-base-url, since links and images need different routes on every forge.
  • CI-discovered link and image URLs are now pinned to a commit SHA instead of a branch.

0.1.0 - 2026-07-23

Added
  • First public release

Tag summary

Content type

Image

Digest

sha256:20e736b1e

Size

6 MB

Last updated

1 day ago

docker pull woozymasta/regdoc