Skip to content

Commit 07dc924

Browse files
committed
Docs: provide option to skip analysis in doc-check
Some projects may not want to run the `--analyze` option on the DocC generation until they are ready. Provide an workflow input option to skip the analyze. While at it, update the `check-docs.sh` script to accept arugments instead of relying on environment variables being set. This allows more easily run the script at-desk. Fixes #2181
1 parent c8aaa3d commit 07dc924

9 files changed

Lines changed: 329 additions & 10 deletions

File tree

.github/workflows/pull_request.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,26 @@ jobs:
9696
with:
9797
api_breakage_check_enabled: false
9898
license_header_check_project_name: "Swift.org"
99+
100+
soundness-docs:
101+
name: "Soundness - Docs (override_target_name: ${{ matrix.override_target_name }} ; post command: ${{ matrix.post_command }})"
102+
strategy:
103+
fail-fast: false
104+
matrix:
105+
override_target_name: ["theDocs", ""]
106+
post_command: ["cat .spi.yml", 'rm -rfv .spi.yml']
107+
uses: ./.github/workflows/soundness.yml
108+
with:
109+
concurrency_group_suffix: "${{ matrix.override_target_name }}-${{ matrix.post_command }}"
110+
linux_pre_build_command: "cd tests/TestPackage && ${{ matrix.post_command }}"
111+
docs_check_enabled: true
112+
docs_check_targets: ${{ matrix.override_target_name}}
113+
docs_check_macos_enabled: false
114+
api_breakage_check_enabled: false
115+
unacceptable_language_check_enabled: false
116+
license_header_check_enabled: false
117+
broken_symlink_check_enabled: false
118+
format_check_enabled: false
119+
shell_check_enabled: false
120+
yamllint_check_enabled: false
121+
python_lint_check_enabled: false

.github/workflows/scripts/check-docs.sh

Lines changed: 74 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,73 @@ log() { printf -- "** %s\n" "$*" >&2; }
1717
error() { printf -- "** ERROR: %s\n" "$*" >&2; }
1818
fatal() { error "$@"; exit 1; }
1919

20-
if [ ! -f .spi.yml ]; then
21-
log "No '.spi.yml' found, no documentation targets to check."
22-
exit 0
20+
usage() {
21+
cat <<EOF
22+
Usage: $(basename "$0") [options]
23+
24+
Options:
25+
--no-analyze Do not pass --analyze to 'swift package plugin generate-documentation'.
26+
--doc-targets target [target2 ...] The documentation targets to build.
27+
--additional-docc-arguments [arg ...] Extra arguments forwarded to 'swift package plugin generate-documentation'.
28+
-h, --help Show this help message.
29+
EOF
30+
}
31+
32+
is_known_option() {
33+
case "$1" in
34+
--no-analyze|--additional-docc-arguments|--doc-targets|-h|--help)
35+
return 0
36+
;;
37+
*)
38+
return 1
39+
;;
40+
esac
41+
}
42+
43+
analyze_flag="--analyze"
44+
additional_docc_arguments=""
45+
docs_targets=""
46+
while [[ $# -gt 0 ]]; do
47+
case "$1" in
48+
--no-analyze)
49+
analyze_flag=""
50+
shift
51+
;;
52+
--doc-targets)
53+
shift
54+
collected=()
55+
while [[ $# -gt 0 ]] && ! is_known_option "$1"; do
56+
collected+=("$1")
57+
shift
58+
done
59+
docs_targets="${collected[*]}"
60+
;;
61+
--additional-docc-arguments)
62+
shift
63+
collected=()
64+
while [[ $# -gt 0 ]] && ! is_known_option "$1"; do
65+
collected+=("$1")
66+
shift
67+
done
68+
additional_docc_arguments="${collected[*]}"
69+
;;
70+
-h|--help)
71+
usage
72+
exit 0
73+
;;
74+
*)
75+
error "Unknown argument: $1"
76+
usage >&2
77+
exit 2
78+
;;
79+
esac
80+
done
81+
82+
if [ -z "${docs_targets}" ] ; then
83+
if [ ! -f .spi.yml ]; then
84+
log "No '.spi.yml' found, no documentation targets to check."
85+
exit 0
86+
fi
2387
fi
2488

2589
if ! command -v yq &> /dev/null; then
@@ -29,6 +93,10 @@ if ! command -v yq &> /dev/null; then
2993
esac
3094
fi
3195

96+
if [ -z "${docs_targets}" ] ; then
97+
docs_targets=$(yq ".builder.configs[] | select(.documentation_targets[] != \"\") | .documentation_targets[]" .spi.yml)
98+
fi
99+
32100
package_files=$(find . -maxdepth 1 -name 'Package*.swift')
33101
if [ -z "$package_files" ]; then
34102
fatal "Package.swift not found. Please ensure you are running this script from the root of a Swift package."
@@ -53,10 +121,10 @@ EOF
53121
fi
54122

55123
log "Checking documentation targets..."
56-
for target in $(yq -r '.builder.configs[].documentation_targets[]' .spi.yml); do
124+
for target in ${docs_targets}; do
57125
log "Checking target $target..."
58-
# shellcheck disable=SC2086 # We explicitly want to explode "$ADDITIONAL_DOCC_ARGUMENTS" into multiple arguments.
59-
swift package plugin generate-documentation --target "$target" --warnings-as-errors --analyze $ADDITIONAL_DOCC_ARGUMENTS
126+
# shellcheck disable=SC2086 # We explicitly want to explode "$analyze_flag" an "$additional_docc_arguments"d into multiple arguments.
127+
swift package plugin generate-documentation --target "$target" --warnings-as-errors $analyze_flag $additional_docc_arguments
60128
done
61129

62130
log "✅ Found no documentation issues."

.github/workflows/soundness.yml

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,14 @@ on:
3131
type: string
3232
description: "Additional arguments that should be passed to docc"
3333
default: ""
34+
docs_check_targets:
35+
type: string
36+
description: "List of targets to check for documentation. Defaults to empty string."
37+
default: ""
38+
docs_check_analyze:
39+
type: boolean
40+
description: "Boolean to pass --analyze to the docs check. Defaults to true."
41+
default: true
3442
docs_check_macos_enabled:
3543
type: boolean
3644
description: "Boolean to enable the macOS docs check job. Defaults to false."
@@ -51,6 +59,14 @@ on:
5159
type: string
5260
description: "Additional arguments that should be passed to docc for the macOS docs check job."
5361
default: ""
62+
docs_check_macos_targets:
63+
type: string
64+
description: "List of targets to check for documentation. Defaults to empty string."
65+
default: ""
66+
docs_check_macos_analyze:
67+
type: boolean
68+
description: "Boolean to pass --analyze to the macOS docs check. Defaults to true."
69+
default: true
5470
unacceptable_language_check_enabled:
5571
type: boolean
5672
description: "Boolean to enable the acceptable language check job. Defaults to true."
@@ -99,13 +115,17 @@ on:
99115
type: string
100116
description: "Linux command to execute before building the Swift package"
101117
default: ""
118+
concurrency_group_suffix:
119+
type: string
120+
description: "Optional suffix appended to the concurrency group. Use this when calling soundness.yml from a matrix so that matrix entries don't cancel each other."
121+
default: ""
102122

103123
permissions:
104124
contents: read
105125

106126
## We are cancelling previously triggered workflow runs
107127
concurrency:
108-
group: ${{ github.workflow }}-${{ github.ref }}-soundness
128+
group: ${{ github.workflow }}-${{ github.ref }}-soundness-${{ inputs.concurrency_group_suffix }}
109129
cancel-in-progress: true
110130

111131
jobs:
@@ -187,8 +207,19 @@ jobs:
187207
- name: Run documentation check
188208
env:
189209
ADDITIONAL_DOCC_ARGUMENTS: ${{ inputs.docs_check_additional_arguments }}
210+
DOCC_ANALYZE: ${{ inputs.docs_check_analyze }}
211+
DOCS_TARGETS: ${{ inputs.docs_check_targets}}
190212
SCRIPT_ROOT: ${{ steps.script_path.outputs.root }}
191-
run: ${SCRIPT_ROOT}/.github/workflows/scripts/check-docs.sh
213+
run: |
214+
analyze_arg=""
215+
doc_target_arg=""
216+
if [[ "${DOCS_TARGETS}" != "" ]] ; then
217+
doc_target_arg="--doc-targets ${DOCS_TARGETS}"
218+
fi
219+
if [[ "${DOCC_ANALYZE}" != "true" ]]; then
220+
analyze_arg="--no-analyze"
221+
fi
222+
"${SCRIPT_ROOT}/.github/workflows/scripts/check-docs.sh" ${analyze_arg} ${doc_target_arg} --additional-docc-arguments ${ADDITIONAL_DOCC_ARGUMENTS}
192223
193224
docs-check-macos:
194225
name: Documentation check (macOS)
@@ -226,8 +257,19 @@ jobs:
226257
- name: Run documentation check
227258
env:
228259
ADDITIONAL_DOCC_ARGUMENTS: ${{ inputs.docs_check_macos_additional_arguments }}
260+
DOCC_ANALYZE: ${{ inputs.docs_check_macos_analyze }}
261+
DOCS_TARGETS: ${{ inputs.docs_check_macos_targets}}
229262
SCRIPT_ROOT: ${{ steps.script_path.outputs.root }}
230-
run: ${SCRIPT_ROOT}/.github/workflows/scripts/check-docs.sh
263+
run: |
264+
analyze_arg=""
265+
doc_target_arg=""
266+
if [[ "${DOCS_TARGETS}" != "" ]] ; then
267+
doc_target_arg="--doc-targets ${DOCS_TARGETS}"
268+
fi
269+
if [[ "${DOCC_ANALYZE}" != "true" ]]; then
270+
analyze_arg="--no-analyze"
271+
fi
272+
"${SCRIPT_ROOT}/.github/workflows/scripts/check-docs.sh" ${analyze_arg} ${doc_target_arg} --additional-docc-arguments ${ADDITIONAL_DOCC_ARGUMENTS}
231273
232274
unacceptable-language-check:
233275
name: Unacceptable language check

docs/pr-dependency-workflow.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,5 @@ permissions:
2929
3030
jobs:
3131
check_dependencies:
32-
uses: swiftlang/github-workflows/.github/workflows/github_actions_dependencies.yml.yml@<to-be-updated>
32+
uses: swiftlang/github-workflows/.github/workflows/github_actions_dependencies.yml@<to-be-updated>
3333
```

docs/soundness-docs-check.md

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
# Documentation Check
2+
3+
The Soundness workflow can verify that your Swift package's [DocC](https://www.swift.org/documentation/docc/) documentation builds without warnings. Two jobs are available:
4+
5+
- **`docs-check`** — runs on Linux. Enabled by default.
6+
- **`docs-check-macos`** — runs on a self-hosted macOS runner. Opt-in.
7+
8+
Running both lets you catch documentation issues that only surface on one toolchain.
9+
10+
Documentation warnings (and, by default, DocC analyzer findings) cause the job to fail.
11+
12+
## Requirements
13+
14+
### For both jobs
15+
16+
1. **A `Package.swift`** (or any `Package*.swift`) at the repository root.
17+
18+
2. **At least one documentation target**, supplied via either:
19+
- the `docs_check_targets` / `docs_check_macos_targets` input, **or**
20+
- a `documentation_targets` entry in a `.spi.yml` file at the repository root.
21+
22+
If neither is provided, the job exits successfully without checking anything.
23+
24+
The `.spi.yml` file is also where you can declare per-target DocC parameters via `custom_documentation_parameters`. Read the [official documentation](https://swiftpackageindex.com/SwiftPackageIndex/SPIManifest/1.12.0/documentation/spimanifest/commonusecases) for the full schema. For example:
25+
26+
```yaml
27+
version: 1
28+
builder:
29+
configs:
30+
- documentation_targets: [MyLibrary, MyOtherLibrary]
31+
custom_documentation_parameters:
32+
- --include-extended-types
33+
```
34+
35+
Target names must match real SwiftPM target names declared in `Package.swift`.
36+
37+
You do not need to add `swift-docc-plugin` to your package — CI provides it for you.
38+
39+
### Additional requirement for the macOS job
40+
41+
A self-hosted runner must be registered with the label set `[self-hosted, macos, <version>, <arch>]` matching the values you pass to `docs_check_macos_version` and `docs_check_macos_arch`, with the requested Xcode version installed.
42+
43+
## Enabling the check
44+
45+
Add (or extend) a workflow file under `.github/workflows/` in your repository:
46+
47+
```yaml
48+
name: Pull request
49+
50+
on:
51+
pull_request:
52+
branches: [main]
53+
54+
jobs:
55+
soundness:
56+
name: Soundness
57+
uses: swiftlang/github-workflows/.github/workflows/soundness.yml@<to-be-updated>>
58+
with:
59+
docs_check_enabled: true
60+
```
61+
62+
This enables the Linux documentation check along with the other soundness checks. The macOS variant remains off unless you opt in.
63+
64+
## Configuration
65+
66+
### Linux job (`docs-check`)
67+
68+
| Input | Type | Default | Description |
69+
|---|---|---|---|
70+
| `docs_check_enabled` | boolean | `true` | Enable or disable the job. |
71+
| `docs_check_container_image` | string | `swift:6.2-noble` | Docker image used to run the check. |
72+
| `docs_check_targets` | string | `""` | Space-separated list of documentation targets to check. When empty, targets are read from `.spi.yml` (if present). |
73+
| `docs_check_additional_arguments` | string | `""` | Extra arguments to pass to DocC. |
74+
| `docs_check_analyze` | boolean | `true` | Set to `false` to skip DocC's analyzer pass. |
75+
| `linux_pre_build_command` | string | `""` | Shell command to run before the check (e.g., installing system dependencies). |
76+
77+
### macOS job (`docs-check-macos`)
78+
79+
| Input | Type | Default | Description |
80+
|---|---|---|---|
81+
| `docs_check_macos_enabled` | boolean | `false` | Enable or disable the job. |
82+
| `docs_check_macos_version` | string | `tahoe` | macOS version label of the runner to target. |
83+
| `docs_check_macos_arch` | string | `ARM64` | Architecture label of the runner to target. |
84+
| `docs_check_macos_xcode_version` | string | `26.0` | Xcode version to use. |
85+
| `docs_check_macos_targets` | string | `""` | Space-separated list of documentation targets to check. When empty, targets are read from `.spi.yml` (if present). |
86+
| `docs_check_macos_additional_arguments` | string | `""` | Extra arguments to pass to DocC. |
87+
| `docs_check_macos_analyze` | boolean | `true` | Set to `false` to skip DocC's analyzer pass. |
88+
89+
The macOS job requires a self-hosted runner registered with the label set `[self-hosted, macos, <version>, <arch>]`.
90+
91+
## Common scenarios
92+
93+
### Enable the macOS check
94+
95+
```yaml
96+
jobs:
97+
soundness:
98+
uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main
99+
with:
100+
docs_check_macos_enabled: true
101+
docs_check_macos_version: "tahoe"
102+
docs_check_macos_arch: "ARM64"
103+
docs_check_macos_xcode_version: "26.0"
104+
```
105+
106+
### Check only specific targets
107+
108+
By default the check documents every target listed in `.spi.yml`. To override that list without editing `.spi.yml`, provide the target names explicitly:
109+
110+
```yaml
111+
jobs:
112+
soundness:
113+
uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main
114+
with:
115+
docs_check_targets: "MyLibrary MyOtherLibrary"
116+
```
117+
118+
### Pin a different Swift toolchain or pass extra DocC flags
119+
120+
```yaml
121+
jobs:
122+
soundness:
123+
uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main
124+
with:
125+
docs_check_container_image: "swift:nightly-noble"
126+
docs_check_additional_arguments: "--include-extended-types"
127+
linux_pre_build_command: "apt-get update && apt-get install -y libxml2-dev"
128+
```
129+
130+
### Skip the DocC analyzer
131+
132+
```yaml
133+
jobs:
134+
soundness:
135+
uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main
136+
with:
137+
docs_check_analyze: false
138+
```
139+
140+
### Disable the check
141+
142+
If you want to skip the documentation check entirely (regardless of whether your package has documentation targets), turn it off:
143+
144+
```yaml
145+
jobs:
146+
soundness:
147+
uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main
148+
with:
149+
docs_check_enabled: false
150+
```
151+
152+
If you simply have no documentation targets to check, you can leave the job enabled — it will exit successfully without doing anything.
153+
154+
## Troubleshooting
155+
156+
| Symptom | Likely cause |
157+
|---|---|
158+
| Job logs `No '.spi.yml' found, no documentation targets to check.` and exits successfully. | Neither `docs_check_targets` nor a `.spi.yml` was provided. Add one of them if you expected the check to run. |
159+
| `Package.swift not found.` | The check expects a SwiftPM package at the repo root. |
160+
| Warnings cause the job to fail. | Intentional. Resolve the DocC warnings, or pass DocC flags via `.spi.yml`'s `custom_documentation_parameters` to suppress them. |
161+
| macOS job stays queued. | No self-hosted runner matches the requested labels. Verify the `version` and `arch` inputs against your runner inventory. |
162+
| macOS job cannot find Xcode. | The requested Xcode version is not installed on the runner. |

tests/TestPackage/.spi.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
version: 1
2+
builder:
3+
configs:
4+
- documentation_targets:
5+
- theDocs

0 commit comments

Comments
 (0)