Skip to content

Commit 92cedbf

Browse files
authored
Merge pull request #337 from apache/Feature/337-api-reference
generated API reference with DocFX #337
2 parents 353443f + a5cc53c commit 92cedbf

48 files changed

Lines changed: 1026 additions & 159 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.config/dotnet-tools.json‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"version": 1,
3+
"isRoot": true,
4+
"tools": {
5+
"docfx": {
6+
"version": "2.81.0",
7+
"commands": [
8+
"docfx"
9+
],
10+
"rollForward": false
11+
}
12+
}
13+
}

‎.github/workflows/build.yaml‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,14 @@ jobs:
5858
run: |
5959
dotnet test ./src/log4net.sln
6060
61+
# Recompiles both shipping projects through docfx with warnings as errors, so a broken doc
62+
# comment or cref fails the pull request rather than the release build. The script itself
63+
# is covered on all three runners by the Pester suite below; the real docfx run needs one.
64+
- name: API reference
65+
if: matrix.os == 'ubuntu-latest'
66+
shell: pwsh
67+
run: ./scripts/build-api-docs.ps1
68+
6169
# Pester 5.9 ships on all three runner images, so nothing is installed here.
6270
- name: Release script tests
6371
shell: pwsh

‎.gitignore‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,10 @@ _Pvt_Extensions
218218
# Maven target dir created during site build
219219
target
220220

221+
# Metadata generated by scripts/build-api-docs.ps1
222+
/src/site/docfx/log4net/
223+
/src/site/docfx/log4net.Ext.Mail/
224+
221225
# other files to ignore
222226
old-log4net.snk
223227
src/GeneratedAssemblyInfo.cs

‎AGENTS.md‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,15 +256,28 @@ The manual lives in `src/site/antora/modules/ROOT/pages/`. A new appender page n
256256
not one: the page itself, an `xref` line in `nav.adoc` (kept alphabetical), and the appender table
257257
in `manual/configuration/appenders.adoc`.
258258

259+
The API reference is DocFX output from the XML doc comments, built by `scripts/build-api-docs.ps1`
260+
into `target/site/api` and in CI with warnings as errors, so an unresolved `cref` or a missing
261+
public doc comment fails the PR. The configuration is in `src/site/docfx/`; the `log4net` and
262+
`log4net.Ext.Mail` folders generated there are ignored. `log4net` is documented as `net462`, since
263+
the `NET462_OR_GREATER` types exist only there. The Ext.Mail entry sets `ProduceReferenceAssembly`,
264+
without which Roslyn cannot match its project reference to log4net and warns.
265+
259266
## Release scripts
260267

268+
- **Before writing a helper function in a script, grep `scripts/` for its name and its idiom**
269+
(`Push-Location`, `Remove-Item`, `Get-Date`). A function two scripts need lives in
270+
`scripts/Common.psm1`, imported with `Import-Module $PSScriptRoot/Common.psm1 -Force`, not
271+
copied into the second script. A module takes its preferences from the global scope, so the
272+
module sets `$ErrorActionPreference` itself.
261273
- **Every file `build-release.ps1` writes gets LF on every platform.** `Set-Content` writes
262274
`[Environment]::NewLine`; use `-NoNewline` with the lines joined by `` `n ``. A CR is invisible in
263275
an editor, and `sha512sum` on macOS reads it as part of the file name.
264276
- **Each release ships the verifier built with it**, so never add backward compatibility to
265277
`verify-release.ps1` or `.sh`: a compatibility skip path is a hole, not a courtesy.
266278
- The scripts are tested with Pester through `scripts/FakeCommands.TestHelper.ps1`, which shadows
267-
`dotnet`, `git`, `gpg`, `zip` and `mvnw` with shims on a prepended `PATH`, because Pester `Mock`
279+
`dotnet`, `git`, `gpg`, `zip`, `mvnw` and `curl` with shims on a prepended `PATH` (`FAKE_FAIL` names a
280+
command, or a command and its first argument such as `dotnet docfx`), because Pester `Mock`
268281
intercepts only functions and cmdlets. CI runs the suite on macOS, Ubuntu and Windows, so keep
269282
the helper's `$IsWindows` branch working and put byte-level assertions where all three see them.
270283

‎antora-playbook.yaml‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ ui:
115115
<img src="{{{uiRootPath}}}/../_images/log4net.svg" alt="Apache log4net"/>
116116
</div>
117117
<div id="topbar-nav" class="navbar-menu">
118+
<div class="navbar-end">
119+
<a class="navbar-item" href="{{{siteRootPath}}}/api/index.html">API Reference</a>
120+
</div>
118121
<div class="navbar-end">
119122
<a class="navbar-item" href="https://github.com/apache/logging-log4net">GitHub</a>
120123
</div>

‎doc/BUILDING.md‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,19 @@ be pushed to the `asf-staging` branch of [https://github.com/apache/logging-log4
6767

6868
Once the site has been pushed to the `asf-staging` branch, it can be viewed at
6969
[http://logging.staged.apache.org/log4net](http://logging.staged.apache.org/log4net)
70+
71+
### API reference
72+
73+
The API reference under `target/site/api` is generated by [DocFX](https://dotnet.github.io/docfx/)
74+
from the XML documentation comments of `src/log4net` and `src/log4net.Ext.Mail`:
75+
76+
```
77+
./scripts/build-api-docs.ps1
78+
```
79+
80+
`scripts/build-release.ps1` runs it after the site, since it removes `target/` before `./mvnw site`.
81+
The script restores the docfx version pinned in `.config/dotnet-tools.json` and builds
82+
with warnings as errors, so an unresolved `cref` or an undocumented public member fails it, as it
83+
does in CI. The page titles name the `VersionPrefix` of `src/Directory.Build.props`, or the
84+
`-Version` given. The configuration lives in `src/site/docfx/docfx.json`. `log4net` is documented as
85+
`net462`, the larger of its two surfaces: the event log and ASP.NET types exist only there.

‎doc/RELEASING.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ release version 3.2.1:
2323
- people who suggested code that was implemented
2424
2. Build release artifacts with `scripts/build-release.ps1`
2525
- the scripts works on Linux and Windows
26+
- it also builds the API reference into `target/site/api`, restoring docfx from nuget.org first
2627
- Prerequisites
2728
- PowerShell
2829
- https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-windows
@@ -31,7 +32,7 @@ release version 3.2.1:
3132
3. Clone out the log4net doc repo (https://github.com/apache/logging-log4net-site)
3233
- check out the `asf-staging` branch
3334
- create a folder which includes the version, eg `log4net-3.2.1`
34-
4. Copy the contents of `target/site` from this repo into the folder created in (4)
35+
4. Copy the contents of `target/site` from this repo into the folder created in (3)
3536
5. Update the symlinks in the base of the docs repo, ie:
3637
- 3.2.x -> 3.2.1
3738
- 3.x -> 3.2.1

‎rat.excludesFile‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ rat.excludesFile
1111
**/*.txt
1212
**/*.sh
1313
**/*.ps1
14+
**/*.psm1
1415
**/*.xml
1516
**/*.props
1617
**/*.csproj

‎scripts/Common.psm1‎

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#Requires -Version 7.4
2+
3+
<#
4+
.SYNOPSIS
5+
Shared by the build scripts, which import it.
6+
#>
7+
8+
Set-StrictMode -Version Latest
9+
# A module takes its preferences from the global scope, not from the importing script, so
10+
# without this a failed delete below would be reported and ignored.
11+
$ErrorActionPreference = 'Stop'
12+
13+
# Paired, so a throw inside cannot leave the caller in the wrong directory.
14+
function Invoke-InDirectory
15+
{
16+
param
17+
(
18+
[Parameter(Mandatory=$true, HelpMessage='The directory to run in.')]
19+
[string]$Directory,
20+
[Parameter(Mandatory=$true, HelpMessage='What to run there.')]
21+
[scriptblock]$Action
22+
)
23+
24+
Push-Location $Directory
25+
try
26+
{
27+
& $Action
28+
}
29+
finally
30+
{
31+
Pop-Location
32+
}
33+
}
34+
35+
# Tested rather than silenced: -ErrorAction SilentlyContinue would also swallow a delete that
36+
# failed, leaving a stale artifact or page behind for whoever copies the directory.
37+
function Remove-Directory
38+
{
39+
param
40+
(
41+
[Parameter(Mandatory=$true, HelpMessage='The directory to remove if it exists.')]
42+
[string]$Directory
43+
)
44+
45+
if (Test-Path $Directory)
46+
{
47+
Remove-Item $Directory -Force -Recurse
48+
}
49+
}
50+
51+
# The Antora footer from antora-playbook.yaml, with the year computed as it is there, since
52+
# docfx has no year variable. Passed on the command line, so docfx.json never goes stale.
53+
function Get-ApiDocsFooter
54+
{
55+
@"
56+
Copyright &copy; 2007-$((Get-Date).Year) <a href="https://www.apache.org/">The Apache Software Foundation</a>.
57+
Licensed under the <a href="https://www.apache.org/licenses/LICENSE-2.0">Apache Software License, Version 2.0</a>.
58+
Please read our <a href="https://privacy.apache.org/policies/privacy-policy-public.html">privacy policy</a>.
59+
<br/>Apache, log4net, and the Apache logo are trademarks or registered trademarks of The Apache Software Foundation.
60+
Other names may be trademarks of their respective owners.
61+
"@ -replace "`r?`n", ' '
62+
}
63+
64+
Export-ModuleMember -Function Invoke-InDirectory, Remove-Directory, Get-ApiDocsFooter

‎scripts/FakeCommands.TestHelper.ps1‎

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,16 @@
1212
# The commit the fake "git rev-parse" reports, so a test can assert what was archived and recorded.
1313
$script:FakeCommitHash = 'a1b2c3d4e5f6071829a3b4c5d6e7f80912345678'
1414

15-
# Logs its call, fails when named in FAKE_FAIL, and otherwise writes the files the real command
16-
# would, where it is told to, so a wrong output path fails as it would for real. "git status" and
17-
# "git rev-parse" answer on stdout instead, FAKE_DIRTY faking an unclean tree.
15+
# Logs its call, fails when named in FAKE_FAIL (by command, or by command and first argument, as
16+
# in "dotnet docfx"), and otherwise writes the files the real command would, where it is told to,
17+
# so a wrong output path fails as it would for real. "git status" and "git rev-parse" answer on
18+
# stdout instead, FAKE_DIRTY faking an unclean tree and FAKE_NO_OUTPUT a docfx that wrote nothing.
19+
# "curl -o" writes a package with an assembly and its xml for every framework a script may look
20+
# for, and "dotnet docfx" its index.html at the -o base, or at target/site/api without one.
1821
$script:FakeCommand = @'
1922
param([string]$Name)
2023
Add-Content -Path $env:FAKE_LOG -Value "$Name $($args -join ' ')"
21-
if ($env:FAKE_FAIL -eq $Name) { exit 1 }
24+
if ($env:FAKE_FAIL -in $Name, "$Name $($args[0])") { exit 1 }
2225
if ($Name -eq 'git')
2326
{
2427
switch ($args[0])
@@ -31,29 +34,65 @@ $outputs = switch ($Name)
3134
{
3235
'dotnet'
3336
{
34-
$version = ($args -join ' ') -replace '.*PackageVersion=(\S+).*', '$1'
35-
$build = "$(Split-Path $PSScriptRoot)/build"
36-
"$build/artifacts/log4net.$version.nupkg", "$build/artifacts/log4net.Ext.Mail.$version.nupkg", "$build/Release/net462/log4net.dll"
37+
$root = Split-Path $PSScriptRoot
38+
switch ($args[0])
39+
{
40+
'tool' { }
41+
'docfx'
42+
{
43+
$base = $args.IndexOf('-o') -ge 0 ? $args[$args.IndexOf('-o') + 1] : "$root/target/site/api"
44+
if (!$env:FAKE_NO_OUTPUT) { "$base/index.html" }
45+
}
46+
default
47+
{
48+
$version = ($args -join ' ') -replace '.*PackageVersion=(\S+).*', '$1'
49+
"$root/build/artifacts/log4net.$version.nupkg", "$root/build/artifacts/log4net.Ext.Mail.$version.nupkg", "$root/build/Release/net462/log4net.dll"
50+
}
51+
}
3752
}
3853
'git' { if ($args[0] -eq 'archive') { $args[$args.IndexOf('--output') + 1] } }
3954
'zip' { $args[1] }
55+
'curl'
56+
{
57+
$package = New-Item -ItemType Directory -Path (Join-Path ([IO.Path]::GetTempPath()) ([guid]::NewGuid()))
58+
foreach ($lib in 'net462', 'netstandard2.0')
59+
{
60+
foreach ($file in 'log4net.dll', 'log4net.xml', 'log4net.Ext.Mail.dll', 'log4net.Ext.Mail.xml')
61+
{
62+
New-Item -ItemType File -Force -Path (Join-Path $package 'lib' $lib $file) | Out-Null
63+
}
64+
}
65+
Compress-Archive -Path (Join-Path $package 'lib') -DestinationPath $args[$args.IndexOf('-o') + 1] -Force
66+
Remove-Item $package -Recurse -Force
67+
}
4068
}
4169
$outputs | ForEach-Object { New-Item -ItemType File -Force -Path $_ | Out-Null }
4270
'@
4371

4472
function New-ScratchTree
4573
{
46-
param ([Parameter(Mandatory)][string]$Script)
74+
param ([Parameter(Mandatory, HelpMessage='The script under test, relative to scripts/.')][string]$Script)
4775

4876
$root = New-Item -ItemType Directory -Path (Join-Path ([System.IO.Path]::GetTempPath()) ([guid]::NewGuid()))
4977
$scripts = New-Item -ItemType Directory -Path (Join-Path $root 'scripts')
5078
$bin = New-Item -ItemType Directory -Path (Join-Path $root 'fakebin')
51-
Copy-Item (Join-Path $PSScriptRoot $Script) $scripts
79+
# The script keeps its place under scripts/, as the paths it derives from its own depend on it.
80+
$target = Join-Path $scripts $Script
81+
New-Item -ItemType Directory -Path (Split-Path $target) -Force | Out-Null
82+
Copy-Item (Join-Path $PSScriptRoot $Script) $target
5283
Copy-Item (Join-Path $PSScriptRoot 'verify-release.*') $scripts
84+
# build-release.ps1 calls it by path, and the build scripts import Common.psm1.
85+
Copy-Item (Join-Path $PSScriptRoot 'build-api-docs.ps1') $scripts
86+
Copy-Item (Join-Path $PSScriptRoot 'Common.psm1') $scripts
87+
# The version build-api-docs.ps1 names in its titles.
88+
Set-Content -Path (New-Item -ItemType File -Force -Path (Join-Path $root 'src' 'Directory.Build.props')) -Value '<Project><PropertyGroup><VersionPrefix>9.9.9</VersionPrefix></PropertyGroup></Project>'
89+
# The shared docfx sources the old-version script copies.
90+
Copy-Item (Join-Path $PSScriptRoot '..' 'src' 'site' 'docfx' 'logo.svg') (New-Item -ItemType Directory -Path (Join-Path $root 'src' 'site' 'docfx'))
91+
New-Item -ItemType Directory -Path (Join-Path $root 'src' 'site' 'docfx' 'template') | Out-Null
5392
'license' | Set-Content (Join-Path $root 'LICENSE')
5493
'notice' | Set-Content (Join-Path $root 'NOTICE')
5594
Set-Content -Path (Join-Path $bin 'fake.ps1') -Value $script:FakeCommand
56-
foreach ($name in 'dotnet', 'git', 'gpg', 'zip', 'mvnw')
95+
foreach ($name in 'dotnet', 'git', 'gpg', 'zip', 'mvnw', 'curl')
5796
{
5897
# mvnw is called by path from the root, the others through PATH.
5998
$directory = $name -eq 'mvnw' ? $root : $bin
@@ -74,7 +113,7 @@ function New-ScratchTree
74113
function Invoke-InScratchTree
75114
{
76115
param ([Parameter(Mandatory)][string]$Root, [Parameter(Mandatory)][string]$Script, [string]$Fail,
77-
[switch]$Dirty)
116+
[switch]$Dirty, [switch]$NoOutput, [string[]]$Arguments = @())
78117

79118
$log = Join-Path $Root 'calls.log'
80119
New-Item -ItemType File -Path $log -Force | Out-Null
@@ -86,14 +125,15 @@ function Invoke-InScratchTree
86125
$env:FAKE_FAIL = $Fail
87126
$env:FAKE_SHA = $script:FakeCommitHash
88127
$env:FAKE_DIRTY = $Dirty ? '1' : ''
128+
$env:FAKE_NO_OUTPUT = $NoOutput ? '1' : ''
89129
# NonInteractive makes the confirmation pause throw, standing in for a release manager who says no.
90-
$output = pwsh -NoProfile -NonInteractive -File (Join-Path $Root 'scripts' $Script) 2>&1
130+
$output = pwsh -NoProfile -NonInteractive -File (Join-Path $Root 'scripts' $Script) @Arguments 2>&1
91131
$exitCode = $LASTEXITCODE
92132
}
93133
finally
94134
{
95135
$env:PATH = $path
96-
Remove-Item Env:FAKE_LOG, Env:FAKE_FAIL, Env:FAKE_SHA, Env:FAKE_DIRTY -ErrorAction SilentlyContinue
136+
Remove-Item Env:FAKE_LOG, Env:FAKE_FAIL, Env:FAKE_SHA, Env:FAKE_DIRTY, Env:FAKE_NO_OUTPUT -ErrorAction SilentlyContinue
97137
}
98138
return [pscustomobject]@{
99139
ExitCode = $exitCode

0 commit comments

Comments
 (0)