Skip to content

Commit 211a672

Browse files
authored
Merge branch 'main' into fix-issue-10385
2 parents b92beb5 + 26049ec commit 211a672

File tree

10 files changed

+291
-72
lines changed

10 files changed

+291
-72
lines changed

.github/workflows/nightly.yml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
name: nightly
22
on:
3+
workflow_dispatch:
34
schedule:
45
- cron: '0 0 * * *'
56

@@ -40,3 +41,44 @@ jobs:
4041
run: |
4142
dotnet nuget push drop/nuget/*.nupkg --api-key "${{ secrets.GITHUB_TOKEN }}" --skip-duplicate --source https://nuget.pkg.github.com/dotnet/index.json
4243
44+
test-nightly-package:
45+
if: github.repository == 'dotnet/docfx'
46+
runs-on: ubuntu-latest
47+
needs: [publish-github-packages]
48+
env:
49+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
50+
steps:
51+
52+
- name: Checkout
53+
uses: actions/checkout@v4
54+
55+
- name: Create NuGet.config
56+
shell: pwsh
57+
run: |
58+
@'
59+
<?xml version="1.0" encoding="utf-8"?>
60+
<configuration>
61+
<packageSources>
62+
<clear />
63+
<add key="github" value="https://nuget.pkg.github.com/dotnet/index.json" />
64+
</packageSources>
65+
<packageSourceCredentials>
66+
<github>
67+
<add key="Username" value="%USER%" />
68+
<add key="ClearTextPassword" value="%GITHUB_TOKEN%" />
69+
</github>
70+
</packageSourceCredentials>
71+
</configuration>
72+
'@ | Out-File NuGet.config -Encoding UTF8
73+
74+
- name: Install nightly build package
75+
run: |
76+
dotnet tool install docfx -g --prerelease
77+
78+
- name: Run docfx commands for test
79+
working-directory: samples/seed
80+
run: |
81+
docfx metadata
82+
docfx build
83+
docfx pdf
84+

Directory.Packages.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
<PackageVersion Include="FluentAssertions" Version="6.12.2" />
4444
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
4545
<PackageVersion Include="Verify.DiffPlex" Version="3.1.2" />
46-
<PackageVersion Include="Verify.Xunit" Version="28.3.1" />
46+
<PackageVersion Include="Verify.Xunit" Version="28.3.2" />
4747
<PackageVersion Include="xunit.runner.visualstudio" Version="2.8.2" />
4848
<PackageVersion Include="xunit" Version="2.9.2" />
4949
</ItemGroup>

docs/index.md

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ In this section we will build a simple documentation site on your local machine.
99
> Prerequisites
1010
> - Familiarity with the command line
1111
> - Install [.NET SDK](https://dotnet.microsoft.com/en-us/download) 8.0 or higher
12-
> - Install [Node.js](https://nodejs.org/) v20 or higher
12+
> - Install [Node.js](https://nodejs.org/) v20 or higher (Optional: It's required when using [Create PDF Files](https://filzrev.github.io/docfx/docs/pdf.html))
1313
1414
Make sure you have [.NET SDK](https://dotnet.microsoft.com/en-us/download) installed, then open a terminal and enter the following command to install the latest docfx:
1515

@@ -114,6 +114,53 @@ await Docfx.Docset.Build("docfx.json");
114114

115115
See [API References](api/Docfx.yml) for additional APIs.
116116

117+
## How to use prerelease version of docfx
118+
119+
Docfx publishes nightly builds to [GitHub Packages](https://github.com/dotnet/docfx/pkgs/nuget/docfx).
120+
If you want to use prerelease version, you can install package with following steps.
121+
122+
### Prerequisite
123+
124+
1. Install [GitHub CLI](https://github.com/cli/cli) command.
125+
2. Install PowerShell 7.x or later.
126+
127+
### Steps
128+
129+
1. Open PowerShell on working directory.
130+
131+
2. Login to GitHub with additional scope request
132+
133+
```pwsh
134+
gh auth login --scopes "read:packages" --host github.com
135+
```
136+
137+
3. Follow the instructions and complete the login steps.
138+
139+
4. Download docfx nuget package from GitHub Packages
140+
141+
```pwsh
142+
# Gets Access Token
143+
$token = gh auth token
144+
145+
# Gets the version of latest nightly build
146+
$version = gh api /orgs/dotnet/packages/nuget/docfx/versions --jq '.[0].name'
147+
148+
# Gets nupkg download URL.
149+
$downloadUrl = "https://nuget.pkg.github.com/dotnet/download/docfx/${version}/${version}.nupkg"
150+
151+
# Download nupkg to current directory.
152+
Write-Host ('Download nupkg from: {0}' -f $downloadUrl)
153+
Invoke-RestMethod -Method Get -Uri $downloadUrl -OutFile "docfx.${version}.nupkg" -Headers @{
154+
Authorization = "Bearer $token"
155+
}
156+
```
157+
158+
5. Install docfx as .NET Global Package from local source
159+
160+
```pwsh
161+
dotnet tool update docfx -g --prerelease --source ./
162+
```
163+
117164
## Next Steps
118165
119166
- [Write Articles](docs/markdown.md)

src/Docfx.App/PdfBuilder.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,6 @@ class Outline
4848
public string? pdfFooterTemplate { get; init; }
4949
}
5050

51-
static PdfBuilder()
52-
{
53-
PlaywrightHelper.EnsurePlaywrightNodeJsPath();
54-
}
55-
5651
public static Task Run(BuildJsonConfig config, string configDirectory, string? outputDirectory = null)
5752
{
5853
var outputFolder = Path.GetFullPath(Path.Combine(
@@ -70,6 +65,8 @@ public static async Task CreatePdf(string outputFolder)
7065
if (pdfTocs.Count == 0)
7166
return;
7267

68+
PlaywrightHelper.EnsurePlaywrightNodeJsPath();
69+
7370
Program.Main(["install", "chromium"]);
7471

7572
var builder = WebApplication.CreateBuilder();

src/Docfx.MarkdigEngine.Extensions/QuoteSectionNote/QuoteSectionNoteRender.cs

Lines changed: 109 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Collections.ObjectModel;
5+
using System.Diagnostics;
6+
using System.Text.RegularExpressions;
47
using System.Web;
58
using Markdig.Renderers;
69
using Markdig.Renderers.Html;
710

811
namespace Docfx.MarkdigEngine.Extensions;
912

10-
public class QuoteSectionNoteRender : HtmlObjectRenderer<QuoteSectionNoteBlock>
13+
public partial class QuoteSectionNoteRender : HtmlObjectRenderer<QuoteSectionNoteBlock>
1114
{
1215
private readonly MarkdownContext _context;
1316
private readonly Dictionary<string, string> _notes;
@@ -100,13 +103,14 @@ private static void WriteVideo(HtmlRenderer renderer, QuoteSectionNoteBlock obj)
100103

101104
public static string FixUpLink(string link)
102105
{
103-
if (!link.Contains("https"))
106+
if (link.StartsWith("http:"))
104107
{
105-
link = link.Replace("http", "https");
108+
link = "https:" + link.Substring("http:".Length);
106109
}
107110
if (Uri.TryCreate(link, UriKind.Absolute, out Uri videoLink))
108111
{
109112
var host = videoLink.Host;
113+
var path = videoLink.LocalPath;
110114
var query = videoLink.Query;
111115
if (query.Length > 1)
112116
{
@@ -125,16 +129,115 @@ public static string FixUpLink(string link)
125129
query += "&nocookie=true";
126130
}
127131
}
128-
else if (host.Equals("youtube.com", StringComparison.OrdinalIgnoreCase) || host.Equals("www.youtube.com", StringComparison.OrdinalIgnoreCase))
132+
else if (hostsYouTube.Contains(host, StringComparer.OrdinalIgnoreCase))
129133
{
130134
// case 2, YouTube video
131-
host = "www.youtube-nocookie.com";
135+
var idYouTube = GetYouTubeId(host, path, ref query);
136+
if (idYouTube != null)
137+
{
138+
host = "www.youtube-nocookie.com";
139+
path = "/embed/" + idYouTube;
140+
query = AddYouTubeRel(query);
141+
}
142+
else
143+
{
144+
//YouTube Playlist
145+
var listYouTube = GetYouTubeList(query);
146+
if (listYouTube != null)
147+
{
148+
host = "www.youtube-nocookie.com";
149+
path = "/embed/videoseries";
150+
query = "list=" + listYouTube;
151+
query = AddYouTubeRel(query);
152+
}
153+
}
154+
155+
//Keep this to preserve previous behavior
156+
if (host.Equals("youtube.com", StringComparison.OrdinalIgnoreCase) || host.Equals("www.youtube.com", StringComparison.OrdinalIgnoreCase))
157+
{
158+
host = "www.youtube-nocookie.com";
159+
}
132160
}
133161

134-
var builder = new UriBuilder(videoLink) { Host = host, Query = query };
162+
var builder = new UriBuilder(videoLink) { Host = host, Path = path, Query = query };
135163
link = builder.Uri.ToString();
136164
}
137165

138166
return link;
139167
}
168+
169+
/// <summary>
170+
/// Only related videos from the same channel
171+
/// https://developers.google.com/youtube/player_parameters
172+
/// </summary>
173+
private static string AddYouTubeRel(string query)
174+
{
175+
// Add rel=0 unless specified in the original link
176+
if (query.Split('&').Any(q => q.StartsWith("rel=")) == false)
177+
{
178+
if (query.Length == 0)
179+
return "rel=0";
180+
else
181+
return query + "&rel=0";
182+
}
183+
184+
return query;
185+
}
186+
187+
private static readonly ReadOnlyCollection<string> hostsYouTube = new string[] {
188+
"youtube.com",
189+
"www.youtube.com",
190+
"youtu.be",
191+
"www.youtube-nocookie.com",
192+
}.AsReadOnly();
193+
194+
private static string GetYouTubeId(string host, string path, ref string query)
195+
{
196+
if (host == "youtu.be")
197+
{
198+
return path.Substring(1);
199+
}
200+
201+
var match = ReYouTubeQueryVideo().Match(query);
202+
if (match.Success)
203+
{
204+
//Remove from query
205+
query = query.Replace(match.Groups[0].Value, "").Trim('&').Replace("&&", "&");
206+
return match.Groups[2].Value;
207+
}
208+
209+
match = ReYouTubePathId().Match(path);
210+
if (match.Success)
211+
{
212+
var id = match.Groups[1].Value;
213+
214+
if (id == "videoseries")
215+
return null;
216+
217+
return id;
218+
}
219+
220+
return null;
221+
}
222+
223+
[GeneratedRegex(@"(^|&)v=([^&]+)")]
224+
private static partial Regex ReYouTubeQueryVideo();
225+
226+
[GeneratedRegex(@"(^|&)list=([^&]+)")]
227+
private static partial Regex ReYouTubeQueryList();
228+
229+
[GeneratedRegex(@"/embed/([^/]+)$")]
230+
private static partial Regex ReYouTubePathId();
231+
232+
private static string GetYouTubeList(string query)
233+
{
234+
var match = ReYouTubeQueryList().Match(query);
235+
if (match.Success)
236+
{
237+
return match.Groups[2].Value;
238+
}
239+
240+
return null;
241+
}
242+
140243
}

src/docfx/docfx.csproj

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,9 @@
1111
<None Include="../../THIRD-PARTY-NOTICES.TXT" CopyToOutputDirectory="PreserveNewest" PackageCopyToOutput="true" />
1212
</ItemGroup>
1313

14-
<!-- Custom target to merge large docfx dependencies to TargetFramework independent folder.
15-
By default, these files are packed to `tools/$(TargetFramework)/any/*`.
16-
This target rewrite:
17-
- templates to the `/templates` directory.
18-
- .playwright to the `/tools/.playwright` directory.
14+
<!-- Custom target to merge docfx templates to TargetFramework independent folder.
15+
By default, docfx templates is packed to `tools/$(TargetFramework)/any/templates/*`.
16+
This target rewrite PackagePath and template files are placed at `templates/*` directory.
1917
-->
2018
<Target Name="RewriteDocfxTemplateFiles" AfterTargets="PackTool">
2119
<PropertyGroup>
@@ -27,16 +25,11 @@
2725
<TfmSpecificPackageFile Update="@(TfmSpecificPackageFile)"
2826
Condition="$([System.String]::new('%(TfmSpecificPackageFile.PackagePath)').StartsWith('tools/$(TargetFramework)/any/templates/'))"
2927
PackagePath="$([System.String]::new('%(TfmSpecificPackageFile.PackagePath)').Replace('tools/$(TargetFramework)/any/',''))"/>
30-
<TfmSpecificPackageFile Update="@(TfmSpecificPackageFile)"
31-
Condition="$([System.String]::new('%(TfmSpecificPackageFile.PackagePath)').StartsWith('tools/$(TargetFramework)/any/.playwright/'))"
32-
PackagePath="$([System.String]::new('%(TfmSpecificPackageFile.PackagePath)').Replace('$(TargetFramework)/any/',''))"/>
3328
</ItemGroup>
3429
<!-- If TargetFramework is not selected version. Remove template files from package. -->
3530
<ItemGroup Condition="'$(TargetFramework)' != '$(DocfxTemplateSourceTargetFramework)'">
3631
<TfmSpecificPackageFile Remove="@(TfmSpecificPackageFile)"
3732
Condition="$([System.String]::new('%(TfmSpecificPackageFile.PackagePath)').StartsWith('tools/$(TargetFramework)/any/templates/'))"/>
38-
<TfmSpecificPackageFile Remove="@(TfmSpecificPackageFile)"
39-
Condition="$([System.String]::new('%(TfmSpecificPackageFile.PackagePath)').StartsWith('tools/$(TargetFramework)/any/.playwright/'))"/>
4033
</ItemGroup>
4134
</Target>
4235

0 commit comments

Comments
 (0)