about summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
authorgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>2022-09-10 18:01:15 +0000
committerGitHub <noreply@github.com>2022-09-10 18:01:15 +0000
commitcf964b46ea18529f975f7593b1f971888f6a624d (patch)
tree43572bcdc92430ef9b680ad663d7d1c79b55c78c /nixos
parentdf949a94a186565285ee05b443d7d2fa541320e0 (diff)
parenteaba40695eeae3e9aeb4492e60d438c111b25f87 (diff)
downloadnixlib-cf964b46ea18529f975f7593b1f971888f6a624d.tar
nixlib-cf964b46ea18529f975f7593b1f971888f6a624d.tar.gz
nixlib-cf964b46ea18529f975f7593b1f971888f6a624d.tar.bz2
nixlib-cf964b46ea18529f975f7593b1f971888f6a624d.tar.lz
nixlib-cf964b46ea18529f975f7593b1f971888f6a624d.tar.xz
nixlib-cf964b46ea18529f975f7593b1f971888f6a624d.tar.zst
nixlib-cf964b46ea18529f975f7593b1f971888f6a624d.zip
Merge master into staging-next
Diffstat (limited to 'nixos')
-rw-r--r--nixos/doc/manual/default.nix3
-rw-r--r--nixos/doc/manual/development/option-declarations.section.md19
-rw-r--r--nixos/doc/manual/from_md/development/option-declarations.section.xml26
-rw-r--r--nixos/doc/manual/from_md/installation/installing.chapter.xml9
-rw-r--r--nixos/doc/manual/from_md/release-notes/rl-2211.section.xml19
-rw-r--r--nixos/doc/manual/installation/installing.chapter.md8
-rw-r--r--nixos/doc/manual/release-notes/rl-2211.section.md4
-rw-r--r--nixos/lib/make-options-doc/default.nix29
-rw-r--r--nixos/lib/make-options-doc/mergeJSON.py39
-rw-r--r--nixos/modules/misc/documentation.nix19
-rw-r--r--nixos/modules/programs/rust-motd.nix2
-rw-r--r--nixos/modules/services/continuous-integration/buildkite-agents.nix2
-rw-r--r--nixos/modules/services/desktops/espanso.nix2
-rw-r--r--nixos/modules/services/misc/gollum.nix10
-rw-r--r--nixos/modules/services/misc/sourcehut/default.nix2
-rw-r--r--nixos/modules/services/monitoring/prometheus/exporters/rtl_433.nix2
-rw-r--r--nixos/modules/services/monitoring/prometheus/exporters/v2ray.nix2
-rw-r--r--nixos/modules/services/networking/i2pd.nix6
-rw-r--r--nixos/modules/services/networking/keepalived/default.nix8
-rw-r--r--nixos/modules/services/networking/strongswan-swanctl/param-constructors.nix2
-rw-r--r--nixos/modules/services/networking/wpa_supplicant.nix8
-rw-r--r--nixos/modules/services/web-apps/dolibarr.nix42
-rw-r--r--nixos/modules/services/web-apps/writefreely.nix56
-rw-r--r--nixos/modules/system/boot/networkd.nix12
-rw-r--r--nixos/modules/virtualisation/qemu-vm.nix2
-rw-r--r--nixos/tests/all-tests.nix1
-rw-r--r--nixos/tests/gollum.nix14
27 files changed, 227 insertions, 121 deletions
diff --git a/nixos/doc/manual/default.nix b/nixos/doc/manual/default.nix
index 1cd769b6a544..d61bbaddf764 100644
--- a/nixos/doc/manual/default.nix
+++ b/nixos/doc/manual/default.nix
@@ -6,6 +6,7 @@
 , extraSources ? []
 , baseOptionsJSON ? null
 , warningsAreErrors ? true
+, allowDocBook ? true
 , prefix ? ../../..
 }:
 
@@ -28,7 +29,7 @@ let
   stripAnyPrefixes = lib.flip (lib.foldr lib.removePrefix) prefixesToStrip;
 
   optionsDoc = buildPackages.nixosOptionsDoc {
-    inherit options revision baseOptionsJSON warningsAreErrors;
+    inherit options revision baseOptionsJSON warningsAreErrors allowDocBook;
     transformOptions = opt: opt // {
       # Clean up declaration sites to not refer to the NixOS source tree.
       declarations = map stripAnyPrefixes opt.declarations;
diff --git a/nixos/doc/manual/development/option-declarations.section.md b/nixos/doc/manual/development/option-declarations.section.md
index 8bf73a66456b..7fdc77b964a1 100644
--- a/nixos/doc/manual/development/option-declarations.section.md
+++ b/nixos/doc/manual/development/option-declarations.section.md
@@ -44,26 +44,23 @@ The function `mkOption` accepts the following arguments.
 :   A textual representation of the default value to be rendered verbatim in
     the manual. Useful if the default value is a complex expression or depends
     on other values or packages.
-    Use `lib.literalExpression` for a Nix expression, `lib.literalDocBook` for
-    a plain English description in DocBook format.
+    Use `lib.literalExpression` for a Nix expression, `lib.literalMD` for
+    a plain English description in [Nixpkgs-flavored Markdown](
+    https://nixos.org/nixpkgs/manual/#sec-contributing-markup) format.
 
 `example`
 
 :   An example value that will be shown in the NixOS manual.
-    You can use `lib.literalExpression` and `lib.literalDocBook` in the same way
+    You can use `lib.literalExpression` and `lib.literalMD` in the same way
     as in `defaultText`.
 
 `description`
 
-:   A textual description of the option, in DocBook format, that will be
+:   A textual description of the option, in [Nixpkgs-flavored Markdown](
+    https://nixos.org/nixpkgs/manual/#sec-contributing-markup) format, that will be
     included in the NixOS manual. During the migration process from DocBook
-    to CommonMark the description may also be written in CommonMark, but has
-    to be wrapped in `lib.mdDoc` to differentiate it from DocBook. See
-    the nixpkgs manual for [the list of CommonMark extensions](
-    https://nixos.org/nixpkgs/manual/#sec-contributing-markup)
-    supported by NixOS documentation.
-
-    New documentation should preferably be written as CommonMark.
+    to CommonMark the description may also be written in DocBook, but this is
+    discouraged.
 
 ## Utility functions for common option patterns {#sec-option-declarations-util}
 
diff --git a/nixos/doc/manual/from_md/development/option-declarations.section.xml b/nixos/doc/manual/from_md/development/option-declarations.section.xml
index d7c7f7716bea..ba604d109ad2 100644
--- a/nixos/doc/manual/from_md/development/option-declarations.section.xml
+++ b/nixos/doc/manual/from_md/development/option-declarations.section.xml
@@ -69,8 +69,10 @@ options = {
           verbatim in the manual. Useful if the default value is a
           complex expression or depends on other values or packages. Use
           <literal>lib.literalExpression</literal> for a Nix expression,
-          <literal>lib.literalDocBook</literal> for a plain English
-          description in DocBook format.
+          <literal>lib.literalMD</literal> for a plain English
+          description in
+          <link xlink:href="https://nixos.org/nixpkgs/manual/#sec-contributing-markup">Nixpkgs-flavored
+          Markdown</link> format.
         </para>
       </listitem>
     </varlistentry>
@@ -82,7 +84,7 @@ options = {
         <para>
           An example value that will be shown in the NixOS manual. You
           can use <literal>lib.literalExpression</literal> and
-          <literal>lib.literalDocBook</literal> in the same way as in
+          <literal>lib.literalMD</literal> in the same way as in
           <literal>defaultText</literal>.
         </para>
       </listitem>
@@ -93,18 +95,12 @@ options = {
       </term>
       <listitem>
         <para>
-          A textual description of the option, in DocBook format, that
-          will be included in the NixOS manual. During the migration
-          process from DocBook to CommonMark the description may also be
-          written in CommonMark, but has to be wrapped in
-          <literal>lib.mdDoc</literal> to differentiate it from DocBook.
-          See the nixpkgs manual for
-          <link xlink:href="https://nixos.org/nixpkgs/manual/#sec-contributing-markup">the
-          list of CommonMark extensions</link> supported by NixOS
-          documentation.
-        </para>
-        <para>
-          New documentation should preferably be written as CommonMark.
+          A textual description of the option, in
+          <link xlink:href="https://nixos.org/nixpkgs/manual/#sec-contributing-markup">Nixpkgs-flavored
+          Markdown</link> format, that will be included in the NixOS
+          manual. During the migration process from DocBook to
+          CommonMark the description may also be written in DocBook, but
+          this is discouraged.
         </para>
       </listitem>
     </varlistentry>
diff --git a/nixos/doc/manual/from_md/installation/installing.chapter.xml b/nixos/doc/manual/from_md/installation/installing.chapter.xml
index 0112458674b5..e0ff368b800c 100644
--- a/nixos/doc/manual/from_md/installation/installing.chapter.xml
+++ b/nixos/doc/manual/from_md/installation/installing.chapter.xml
@@ -247,6 +247,15 @@ OK
         </listitem>
         <listitem>
           <para>
+            Set the root partition’s boot flag to on. This allows the
+            disk to be booted from.
+          </para>
+          <programlisting>
+# parted /dev/sda -- set 1 boot on
+</programlisting>
+        </listitem>
+        <listitem>
+          <para>
             Finally, add a <emphasis>swap</emphasis> partition. The size
             required will vary according to needs, here a 8GiB one is
             created.
diff --git a/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml b/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml
index 7d113462c793..8749ece51ec9 100644
--- a/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml
+++ b/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml
@@ -584,6 +584,25 @@
       </listitem>
       <listitem>
         <para>
+          Option descriptions, examples, and defaults writting in
+          DocBook are now deprecated. Using CommonMark is preferred and
+          will become the default in a future release.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          The
+          <literal>documentation.nixos.options.allowDocBook</literal>
+          option was added to ease the transition to CommonMark option
+          documentation. Setting this option to <literal>false</literal>
+          causes an error for every option included in the manual that
+          uses DocBook documentation; it defaults to
+          <literal>true</literal> to preserve the previous behavior and
+          will be removed once the transition to CommonMark is complete.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
           The udisks2 service, available at
           <literal>services.udisks2.enable</literal>, is now disabled by
           default. It will automatically be enabled through services and
diff --git a/nixos/doc/manual/installation/installing.chapter.md b/nixos/doc/manual/installation/installing.chapter.md
index 7254f9d18406..b1e58b14b783 100644
--- a/nixos/doc/manual/installation/installing.chapter.md
+++ b/nixos/doc/manual/installation/installing.chapter.md
@@ -183,7 +183,13 @@ update /etc/fstab.
     # parted /dev/sda -- mkpart primary 1MB -8GB
     ```
 
-3.  Finally, add a *swap* partition. The size required will vary
+3.  Set the root partition's boot flag to on. This allows the disk to be booted from.
+
+    ```ShellSession
+    # parted /dev/sda -- set 1 boot on
+    ```
+
+4.  Finally, add a *swap* partition. The size required will vary
     according to needs, here a 8GiB one is created.
 
     ```ShellSession
diff --git a/nixos/doc/manual/release-notes/rl-2211.section.md b/nixos/doc/manual/release-notes/rl-2211.section.md
index 83220c306612..84fa7081e91f 100644
--- a/nixos/doc/manual/release-notes/rl-2211.section.md
+++ b/nixos/doc/manual/release-notes/rl-2211.section.md
@@ -199,6 +199,10 @@ Use `configure.packages` instead.
 
 - memtest86+ was updated from 5.00-coreboot-002 to 6.00-beta2. It is now the upstream version from https://www.memtest.org/, as coreboot's fork is no longer available.
 
+- Option descriptions, examples, and defaults writting in DocBook are now deprecated. Using CommonMark is preferred and will become the default in a future release.
+
+- The `documentation.nixos.options.allowDocBook` option was added to ease the transition to CommonMark option documentation. Setting this option to `false` causes an error for every option included in the manual that uses DocBook documentation; it defaults to `true` to preserve the previous behavior and will be removed once the transition to CommonMark is complete.
+
 - The udisks2 service, available at `services.udisks2.enable`, is now disabled by default. It will automatically be enabled through services and desktop environments as needed.
   This also means that polkit will now actually be disabled by default. The default for `security.polkit.enable` was already flipped in the previous release, but udisks2 being enabled by default re-enabled it.
 
diff --git a/nixos/lib/make-options-doc/default.nix b/nixos/lib/make-options-doc/default.nix
index 3f98e2cf87b8..43dbff0e68dd 100644
--- a/nixos/lib/make-options-doc/default.nix
+++ b/nixos/lib/make-options-doc/default.nix
@@ -34,6 +34,10 @@
 # instead of printing warnings for eg options with missing descriptions (which may be lost
 # by nix build unless -L is given), emit errors instead and fail the build
 , warningsAreErrors ? true
+# allow docbook option docs if `true`. only markdown documentation is allowed when set to
+# `false`, and a different renderer may be used with different bugs and performance
+# characteristics but (hopefully) indistinguishable output.
+, allowDocBook ? true
 }:
 
 let
@@ -127,26 +131,23 @@ in rec {
       ];
       options = builtins.toFile "options.json"
         (builtins.unsafeDiscardStringContext (builtins.toJSON optionsNix));
+      # merge with an empty set if baseOptionsJSON is null to run markdown
+      # processing on the input options
+      baseJSON =
+        if baseOptionsJSON == null
+        then builtins.toFile "base.json" "{}"
+        else baseOptionsJSON;
     }
     ''
       # Export list of options in different format.
       dst=$out/share/doc/nixos
       mkdir -p $dst
 
-      ${
-        if baseOptionsJSON == null
-          then ''
-            # `cp $options $dst/options.json`, but with temporary
-            # markdown processing
-            python ${./mergeJSON.py} $options <(echo '{}') > $dst/options.json
-          ''
-          else ''
-            python ${./mergeJSON.py} \
-              ${lib.optionalString warningsAreErrors "--warnings-are-errors"} \
-              ${baseOptionsJSON} $options \
-              > $dst/options.json
-          ''
-      }
+      python ${./mergeJSON.py} \
+        ${lib.optionalString warningsAreErrors "--warnings-are-errors"} \
+        ${lib.optionalString (! allowDocBook) "--error-on-docbook"} \
+        $baseJSON $options \
+        > $dst/options.json
 
       brotli -9 < $dst/options.json > $dst/options.json.br
 
diff --git a/nixos/lib/make-options-doc/mergeJSON.py b/nixos/lib/make-options-doc/mergeJSON.py
index 1a1af11337e7..eae9ca031244 100644
--- a/nixos/lib/make-options-doc/mergeJSON.py
+++ b/nixos/lib/make-options-doc/mergeJSON.py
@@ -212,8 +212,17 @@ def convertMD(options: Dict[str, Any]) -> str:
 
     return options
 
-warningsAreErrors = sys.argv[1] == "--warnings-are-errors"
-optOffset = 1 if warningsAreErrors else 0
+warningsAreErrors = False
+errorOnDocbook = False
+optOffset = 0
+for arg in sys.argv[1:]:
+    if arg == "--warnings-are-errors":
+        optOffset += 1
+        warningsAreErrors = True
+    if arg == "--error-on-docbook":
+        optOffset += 1
+        errorOnDocbook = True
+
 options = pivot(json.load(open(sys.argv[1 + optOffset], 'r')))
 overrides = pivot(json.load(open(sys.argv[2 + optOffset], 'r')))
 
@@ -241,9 +250,33 @@ for (k, v) in overrides.items():
 
 severity = "error" if warningsAreErrors else "warning"
 
+def is_docbook(o, key):
+    val = o.get(key, {})
+    if not isinstance(val, dict):
+        return False
+    return val.get('_type', '') == 'literalDocBook'
+
 # check that every option has a description
 hasWarnings = False
+hasErrors = False
 for (k, v) in options.items():
+    if errorOnDocbook:
+        if isinstance(v.value.get('description', {}), str):
+            hasErrors = True
+            print(
+                f"\x1b[1;31merror: option {v.name} description uses DocBook\x1b[0m",
+                file=sys.stderr)
+        elif is_docbook(v.value, 'defaultText'):
+            hasErrors = True
+            print(
+                f"\x1b[1;31merror: option {v.name} default uses DocBook\x1b[0m",
+                file=sys.stderr)
+        elif is_docbook(v.value, 'example'):
+            hasErrors = True
+            print(
+                f"\x1b[1;31merror: option {v.name} example uses DocBook\x1b[0m",
+                file=sys.stderr)
+
     if v.value.get('description', None) is None:
         hasWarnings = True
         print(f"\x1b[1;31m{severity}: option {v.name} has no description\x1b[0m", file=sys.stderr)
@@ -254,6 +287,8 @@ for (k, v) in options.items():
             f"\x1b[1;31m{severity}: option {v.name} has no type. Please specify a valid type, see " +
             "https://nixos.org/manual/nixos/stable/index.html#sec-option-types\x1b[0m", file=sys.stderr)
 
+if hasErrors:
+    sys.exit(1)
 if hasWarnings and warningsAreErrors:
     print(
         "\x1b[1;31m" +
diff --git a/nixos/modules/misc/documentation.nix b/nixos/modules/misc/documentation.nix
index 5dcdc8f96c44..e85ad4efd008 100644
--- a/nixos/modules/misc/documentation.nix
+++ b/nixos/modules/misc/documentation.nix
@@ -99,7 +99,7 @@ let
               exit 1
             } >&2
         '';
-    inherit (cfg.nixos.options) warningsAreErrors;
+    inherit (cfg.nixos.options) warningsAreErrors allowDocBook;
   };
 
 
@@ -255,6 +255,23 @@ in
         '';
       };
 
+      nixos.options.allowDocBook = mkOption {
+        type = types.bool;
+        default = true;
+        description = lib.mdDoc ''
+          Whether to allow DocBook option docs. When set to `false` all option using
+          DocBook documentation will cause a manual build error; additionally a new
+          renderer may be used.
+
+          ::: {.note}
+          The `false` setting for this option is not yet fully supported. While it
+          should work fine and produce the same output as the previous toolchain
+          using DocBook it may not work in all circumstances. Whether markdown option
+          documentation is allowed is independent of this option.
+          :::
+        '';
+      };
+
       nixos.options.warningsAreErrors = mkOption {
         type = types.bool;
         default = true;
diff --git a/nixos/modules/programs/rust-motd.nix b/nixos/modules/programs/rust-motd.nix
index 671e701cd195..f89b5e038387 100644
--- a/nixos/modules/programs/rust-motd.nix
+++ b/nixos/modules/programs/rust-motd.nix
@@ -7,7 +7,7 @@ let
   format = pkgs.formats.toml { };
 in {
   options.programs.rust-motd = {
-    enable = mkEnableOption "rust-motd";
+    enable = mkEnableOption (lib.mdDoc "rust-motd");
     enableMotdInSSHD = mkOption {
       default = true;
       type = types.bool;
diff --git a/nixos/modules/services/continuous-integration/buildkite-agents.nix b/nixos/modules/services/continuous-integration/buildkite-agents.nix
index 3d29a641a195..7c8f77580ff6 100644
--- a/nixos/modules/services/continuous-integration/buildkite-agents.nix
+++ b/nixos/modules/services/continuous-integration/buildkite-agents.nix
@@ -9,7 +9,7 @@ let
     inherit name;
     value = mkOption {
       default = null;
-      inherit description;
+      description = lib.mdDoc description;
       type = types.nullOr types.lines;
     } // (if example == null then {} else { inherit example; });
   };
diff --git a/nixos/modules/services/desktops/espanso.nix b/nixos/modules/services/desktops/espanso.nix
index 4ef6724dda0a..cbc48034795e 100644
--- a/nixos/modules/services/desktops/espanso.nix
+++ b/nixos/modules/services/desktops/espanso.nix
@@ -6,7 +6,7 @@ in {
   meta = { maintainers = with lib.maintainers; [ numkem ]; };
 
   options = {
-    services.espanso = { enable = options.mkEnableOption "Espanso"; };
+    services.espanso = { enable = options.mkEnableOption (lib.mdDoc "Espanso"); };
   };
 
   config = mkIf cfg.enable {
diff --git a/nixos/modules/services/misc/gollum.nix b/nixos/modules/services/misc/gollum.nix
index a4bed2da8a2f..ca6f42736a10 100644
--- a/nixos/modules/services/misc/gollum.nix
+++ b/nixos/modules/services/misc/gollum.nix
@@ -87,6 +87,14 @@ in
       description = lib.mdDoc "Specifies the path of the repository directory. If it does not exist, Gollum will create it on startup.";
     };
 
+    package = mkOption {
+      type = types.package;
+      default = pkgs.gollum;
+      defaultText = literalExpression "pkgs.gollum";
+      description = lib.mdDoc ''
+        The package used in the service
+      '';
+    };
   };
 
   config = mkIf cfg.enable {
@@ -120,7 +128,7 @@ in
         Group = config.users.groups.gollum.name;
         WorkingDirectory = cfg.stateDir;
         ExecStart = ''
-          ${pkgs.gollum}/bin/gollum \
+          ${cfg.package}/bin/gollum \
             --port ${toString cfg.port} \
             --host ${cfg.address} \
             --config ${pkgs.writeText "gollum-config.rb" cfg.extraConfig} \
diff --git a/nixos/modules/services/misc/sourcehut/default.nix b/nixos/modules/services/misc/sourcehut/default.nix
index dd0e016a1da7..9177f3cd022e 100644
--- a/nixos/modules/services/misc/sourcehut/default.nix
+++ b/nixos/modules/services/misc/sourcehut/default.nix
@@ -101,7 +101,7 @@ let
     todosrht
   ]);
   mkOptionNullOrStr = description: mkOption {
-    inherit description;
+    description = lib.mdDoc description;
     type = with types; nullOr str;
     default = null;
   };
diff --git a/nixos/modules/services/monitoring/prometheus/exporters/rtl_433.nix b/nixos/modules/services/monitoring/prometheus/exporters/rtl_433.nix
index 42bf1788aea9..1f7235cb7830 100644
--- a/nixos/modules/services/monitoring/prometheus/exporters/rtl_433.nix
+++ b/nixos/modules/services/monitoring/prometheus/exporters/rtl_433.nix
@@ -16,7 +16,7 @@ in
           };
           "${field}" = lib.mkOption {
             type = int;
-            inherit description;
+            description = lib.mdDoc description;
           };
           location = lib.mkOption {
             type = str;
diff --git a/nixos/modules/services/monitoring/prometheus/exporters/v2ray.nix b/nixos/modules/services/monitoring/prometheus/exporters/v2ray.nix
index 185506cfc2b7..a019157c664b 100644
--- a/nixos/modules/services/monitoring/prometheus/exporters/v2ray.nix
+++ b/nixos/modules/services/monitoring/prometheus/exporters/v2ray.nix
@@ -11,7 +11,7 @@ in
     v2rayEndpoint = mkOption {
       type = types.str;
       default = "127.0.0.1:54321";
-      description = ''
+      description = lib.mdDoc ''
         v2ray grpc api endpoint
       '';
     };
diff --git a/nixos/modules/services/networking/i2pd.nix b/nixos/modules/services/networking/i2pd.nix
index 47f4a42aa5dd..b60cbe664b6f 100644
--- a/nixos/modules/services/networking/i2pd.nix
+++ b/nixos/modules/services/networking/i2pd.nix
@@ -396,12 +396,12 @@ in
       };
 
       precomputation.elgamal = mkEnableTrueOption "Precomputed ElGamal tables" // {
-        description = ''
+        description = lib.mdDoc ''
           Whenever to use precomputated tables for ElGamal.
-          <command>i2pd</command> defaults to <literal>false</literal>
+          {command}`i2pd` defaults to `false`
           to save 64M of memory (and looses some performance).
 
-          We default to <literal>true</literal> as that is what most
+          We default to `true` as that is what most
           users want anyway.
         '';
       };
diff --git a/nixos/modules/services/networking/keepalived/default.nix b/nixos/modules/services/networking/keepalived/default.nix
index 1ab25c879916..e9df08f00c37 100644
--- a/nixos/modules/services/networking/keepalived/default.nix
+++ b/nixos/modules/services/networking/keepalived/default.nix
@@ -268,11 +268,11 @@ in
         type = types.nullOr types.path;
         default = null;
         example = "/run/keys/keepalived.env";
-        description = ''
+        description = lib.mdDoc ''
           Environment variables from this file will be interpolated into the
-          final config file using envsubst with this syntax: <literal>$ENVIRONMENT</literal>
-          or <literal>''${VARIABLE}</literal>.
-          The file should contain lines formatted as <literal>SECRET_VAR=SECRET_VALUE</literal>.
+          final config file using envsubst with this syntax: `$ENVIRONMENT`
+          or `''${VARIABLE}`.
+          The file should contain lines formatted as `SECRET_VAR=SECRET_VALUE`.
           This is useful to avoid putting secrets into the nix store.
         '';
       };
diff --git a/nixos/modules/services/networking/strongswan-swanctl/param-constructors.nix b/nixos/modules/services/networking/strongswan-swanctl/param-constructors.nix
index 8245b25719e4..dc6d8f48e626 100644
--- a/nixos/modules/services/networking/strongswan-swanctl/param-constructors.nix
+++ b/nixos/modules/services/networking/strongswan-swanctl/param-constructors.nix
@@ -152,7 +152,7 @@ rec {
     option = mkOption {
       type = types.attrsOf (types.submodule {options = paramsToOptions params;});
       default = {};
-      inherit description;
+      description = lib.mdDoc description;
     };
     render = postfix: attrs:
       let postfixedAttrs = mapAttrs' (name: nameValuePair "${name}-${postfix}") attrs;
diff --git a/nixos/modules/services/networking/wpa_supplicant.nix b/nixos/modules/services/networking/wpa_supplicant.nix
index 6c58bcfbbf18..119575bdddb4 100644
--- a/nixos/modules/services/networking/wpa_supplicant.nix
+++ b/nixos/modules/services/networking/wpa_supplicant.nix
@@ -187,12 +187,12 @@ in {
       };
 
       allowAuxiliaryImperativeNetworks = mkEnableOption (lib.mdDoc "support for imperative & declarative networks") // {
-        description = ''
+        description = lib.mdDoc ''
           Whether to allow configuring networks "imperatively" (e.g. via
-          <literal>wpa_supplicant_gui</literal>) and declaratively via
-          <xref linkend="opt-networking.wireless.networks"/>.
+          `wpa_supplicant_gui`) and declaratively via
+          [](#opt-networking.wireless.networks).
 
-          Please note that this adds a custom patch to <literal>wpa_supplicant</literal>.
+          Please note that this adds a custom patch to `wpa_supplicant`.
         '';
       };
 
diff --git a/nixos/modules/services/web-apps/dolibarr.nix b/nixos/modules/services/web-apps/dolibarr.nix
index 2b2e2a6214dc..5335c439329c 100644
--- a/nixos/modules/services/web-apps/dolibarr.nix
+++ b/nixos/modules/services/web-apps/dolibarr.nix
@@ -48,12 +48,12 @@ in
 {
   # interface
   options.services.dolibarr = {
-    enable = mkEnableOption "dolibarr";
+    enable = mkEnableOption (lib.mdDoc "dolibarr");
 
     domain = mkOption {
       type = types.str;
       default = "localhost";
-      description = ''
+      description = lib.mdDoc ''
         Domain name of your server.
       '';
     };
@@ -61,35 +61,35 @@ in
     user = mkOption {
       type = types.str;
       default = "dolibarr";
-      description = ''
+      description = lib.mdDoc ''
         User account under which dolibarr runs.
 
-        <note><para>
-          If left as the default value this user will automatically be created
-          on system activation, otherwise you are responsible for
-          ensuring the user exists before the dolibarr application starts.
-        </para></note>
+        ::: {.note}
+        If left as the default value this user will automatically be created
+        on system activation, otherwise you are responsible for
+        ensuring the user exists before the dolibarr application starts.
+        :::
       '';
     };
 
     group = mkOption {
       type = types.str;
       default = "dolibarr";
-      description = ''
+      description = lib.mdDoc ''
         Group account under which dolibarr runs.
 
-        <note><para>
-          If left as the default value this group will automatically be created
-          on system activation, otherwise you are responsible for
-          ensuring the group exists before the dolibarr application starts.
-        </para></note>
+        ::: {.note}
+        If left as the default value this group will automatically be created
+        on system activation, otherwise you are responsible for
+        ensuring the group exists before the dolibarr application starts.
+        :::
       '';
     };
 
     stateDir = mkOption {
       type = types.str;
       default = "/var/lib/dolibarr";
-      description = ''
+      description = lib.mdDoc ''
         State and configuration directory dolibarr will use.
       '';
     };
@@ -98,33 +98,33 @@ in
       host = mkOption {
         type = types.str;
         default = "localhost";
-        description = "Database host address.";
+        description = lib.mdDoc "Database host address.";
       };
       port = mkOption {
         type = types.port;
         default = 3306;
-        description = "Database host port.";
+        description = lib.mdDoc "Database host port.";
       };
       name = mkOption {
         type = types.str;
         default = "dolibarr";
-        description = "Database name.";
+        description = lib.mdDoc "Database name.";
       };
       user = mkOption {
         type = types.str;
         default = "dolibarr";
-        description = "Database username.";
+        description = lib.mdDoc "Database username.";
       };
       passwordFile = mkOption {
         type = with types; nullOr path;
         default = null;
         example = "/run/keys/dolibarr-dbpassword";
-        description = "Database password file.";
+        description = lib.mdDoc "Database password file.";
       };
       createLocally = mkOption {
         type = types.bool;
         default = true;
-        description = "Create the database and database user locally.";
+        description = lib.mdDoc "Create the database and database user locally.";
       };
     };
 
diff --git a/nixos/modules/services/web-apps/writefreely.nix b/nixos/modules/services/web-apps/writefreely.nix
index c363760d5c2d..dec00b46f335 100644
--- a/nixos/modules/services/web-apps/writefreely.nix
+++ b/nixos/modules/services/web-apps/writefreely.nix
@@ -133,45 +133,45 @@ let
 in {
   options.services.writefreely = {
     enable =
-      lib.mkEnableOption "Writefreely, build a digital writing community";
+      lib.mkEnableOption (lib.mdDoc "Writefreely, build a digital writing community");
 
     package = lib.mkOption {
       type = lib.types.package;
       default = pkgs.writefreely;
       defaultText = lib.literalExpression "pkgs.writefreely";
-      description = "Writefreely package to use.";
+      description = lib.mdDoc "Writefreely package to use.";
     };
 
     stateDir = mkOption {
       type = types.path;
       default = "/var/lib/writefreely";
-      description = "The state directory where keys and data are stored.";
+      description = lib.mdDoc "The state directory where keys and data are stored.";
     };
 
     user = mkOption {
       type = types.str;
       default = "writefreely";
-      description = "User under which Writefreely is ran.";
+      description = lib.mdDoc "User under which Writefreely is ran.";
     };
 
     group = mkOption {
       type = types.str;
       default = "writefreely";
-      description = "Group under which Writefreely is ran.";
+      description = lib.mdDoc "Group under which Writefreely is ran.";
     };
 
     host = mkOption {
       type = types.str;
       default = "";
-      description = "The public host name to serve.";
+      description = lib.mdDoc "The public host name to serve.";
       example = "example.com";
     };
 
     settings = mkOption {
       default = { };
-      description = ''
-        Writefreely configuration (<filename>config.ini</filename>). Refer to
-        <link xlink:href="https://writefreely.org/docs/latest/admin/config" />
+      description = lib.mdDoc ''
+        Writefreely configuration ({file}`config.ini`). Refer to
+        <https://writefreely.org/docs/latest/admin/config>
         for details.
       '';
 
@@ -183,7 +183,7 @@ in {
             theme = mkOption {
               type = types.str;
               default = "write";
-              description = "The theme to apply.";
+              description = lib.mdDoc "The theme to apply.";
             };
           };
 
@@ -192,7 +192,7 @@ in {
               type = types.port;
               default = if cfg.nginx.enable then 18080 else 80;
               defaultText = "80";
-              description = "The port WriteFreely should listen on.";
+              description = lib.mdDoc "The port WriteFreely should listen on.";
             };
           };
         };
@@ -203,60 +203,60 @@ in {
       type = mkOption {
         type = types.enum [ "sqlite3" "mysql" ];
         default = "sqlite3";
-        description = "The database provider to use.";
+        description = lib.mdDoc "The database provider to use.";
       };
 
       name = mkOption {
         type = types.str;
         default = "writefreely";
-        description = "The name of the database to store data in.";
+        description = lib.mdDoc "The name of the database to store data in.";
       };
 
       user = mkOption {
         type = types.nullOr types.str;
         default = if cfg.database.type == "mysql" then "writefreely" else null;
         defaultText = "writefreely";
-        description = "The database user to connect as.";
+        description = lib.mdDoc "The database user to connect as.";
       };
 
       passwordFile = mkOption {
         type = types.nullOr types.path;
         default = null;
-        description = "The file to load the database password from.";
+        description = lib.mdDoc "The file to load the database password from.";
       };
 
       host = mkOption {
         type = types.str;
         default = "localhost";
-        description = "The database host to connect to.";
+        description = lib.mdDoc "The database host to connect to.";
       };
 
       port = mkOption {
         type = types.port;
         default = 3306;
-        description = "The port used when connecting to the database host.";
+        description = lib.mdDoc "The port used when connecting to the database host.";
       };
 
       tls = mkOption {
         type = types.bool;
         default = false;
         description =
-          "Whether or not TLS should be used for the database connection.";
+          lib.mdDoc "Whether or not TLS should be used for the database connection.";
       };
 
       migrate = mkOption {
         type = types.bool;
         default = true;
         description =
-          "Whether or not to automatically run migrations on startup.";
+          lib.mdDoc "Whether or not to automatically run migrations on startup.";
       };
 
       createLocally = mkOption {
         type = types.bool;
         default = false;
-        description = ''
-          When <option>services.writefreely.database.type</option> is set to
-          <code>"mysql"</code>, this option will enable the MySQL service locally.
+        description = lib.mdDoc ''
+          When {option}`services.writefreely.database.type` is set to
+          `"mysql"`, this option will enable the MySQL service locally.
         '';
       };
     };
@@ -264,15 +264,15 @@ in {
     admin = {
       name = mkOption {
         type = types.nullOr types.str;
-        description = "The name of the first admin user.";
+        description = lib.mdDoc "The name of the first admin user.";
         default = null;
       };
 
       initialPasswordFile = mkOption {
         type = types.path;
-        description = ''
+        description = lib.mdDoc ''
           Path to a file containing the initial password for the admin user.
-          If not provided, the default password will be set to <code>nixos</code>.
+          If not provided, the default password will be set to `nixos`.
         '';
         default = pkgs.writeText "default-admin-pass" "nixos";
         defaultText = "/nix/store/xxx-default-admin-pass";
@@ -284,13 +284,13 @@ in {
         type = types.bool;
         default = false;
         description =
-          "Whether or not to enable and configure nginx as a proxy for WriteFreely.";
+          lib.mdDoc "Whether or not to enable and configure nginx as a proxy for WriteFreely.";
       };
 
       forceSSL = mkOption {
         type = types.bool;
         default = false;
-        description = "Whether or not to force the use of SSL.";
+        description = lib.mdDoc "Whether or not to force the use of SSL.";
       };
     };
 
@@ -299,7 +299,7 @@ in {
         type = types.bool;
         default = false;
         description =
-          "Whether or not to automatically fetch and configure SSL certs.";
+          lib.mdDoc "Whether or not to automatically fetch and configure SSL certs.";
       };
     };
   };
diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix
index 25e30c9303bd..cb60117f0eb8 100644
--- a/nixos/modules/system/boot/networkd.nix
+++ b/nixos/modules/system/boot/networkd.nix
@@ -1257,11 +1257,10 @@ let
         default = {};
         example = { Route = "fd00::/64"; };
         type = types.addCheck (types.attrsOf unitOption) check.network.sectionIPv6RoutePrefix;
-        description = ''
+        description = lib.mdDoc ''
           Each attribute in this set specifies an option in the
-          <literal>[IPv6RoutePrefix]</literal> section of the unit.  See
-          <citerefentry><refentrytitle>systemd.network</refentrytitle>
-          <manvolnum>5</manvolnum></citerefentry> for details.
+          `[IPv6RoutePrefix]` section of the unit.  See
+          {manpage}`systemd.network(5)` for details.
         '';
       };
     };
@@ -1413,10 +1412,9 @@ let
       default = [];
       example = [ { ipv6RoutePrefixConfig = { Route = "fd00::/64"; LifetimeSec = 3600; }; } ];
       type = with types; listOf (submodule ipv6RoutePrefixOptions);
-      description = ''
+      description = lib.mdDoc ''
         A list of ipv6RoutePrefix sections to be added to the unit.  See
-        <citerefentry><refentrytitle>systemd.network</refentrytitle>
-        <manvolnum>5</manvolnum></citerefentry> for details.
+        {manpage}`systemd.network(5)` for details.
       '';
     };
 
diff --git a/nixos/modules/virtualisation/qemu-vm.nix b/nixos/modules/virtualisation/qemu-vm.nix
index 0207bfba82ad..edc6dfdc15ae 100644
--- a/nixos/modules/virtualisation/qemu-vm.nix
+++ b/nixos/modules/virtualisation/qemu-vm.nix
@@ -584,7 +584,7 @@ in
       example = literalExpression ''
         import pkgs.path { system = "x86_64-darwin"; }
       '';
-      description = ''
+      description = lib.mdDoc ''
         pkgs set to use for the host-specific packages of the vm runner.
         Changing this to e.g. a Darwin package set allows running NixOS VMs on Darwin.
       '';
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index 45f0575cd923..2464ec4d404b 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -189,6 +189,7 @@ in {
   gobgpd = handleTest ./gobgpd.nix {};
   gocd-agent = handleTest ./gocd-agent.nix {};
   gocd-server = handleTest ./gocd-server.nix {};
+  gollum = handleTest ./gollum.nix {};
   google-oslogin = handleTest ./google-oslogin {};
   gotify-server = handleTest ./gotify-server.nix {};
   grafana = handleTest ./grafana.nix {};
diff --git a/nixos/tests/gollum.nix b/nixos/tests/gollum.nix
new file mode 100644
index 000000000000..833db87f2f32
--- /dev/null
+++ b/nixos/tests/gollum.nix
@@ -0,0 +1,14 @@
+import ./make-test-python.nix ({ pkgs, ... }: {
+  name = "gollum";
+
+  nodes = {
+    webserver = { pkgs, lib, ... }: {
+      services.gollum.enable = true;
+    };
+  };
+
+  testScript = { nodes, ... }: ''
+    webserver.wait_for_unit("gollum")
+    webserver.wait_for_open_port(${toString nodes.webserver.config.services.gollum.port})
+  '';
+})