Skip to content

Commit ad2bf01

Browse files
Caleb BroseCaleb Brose
authored andcommitted
Initial work
1 parent a78087f commit ad2bf01

File tree

4 files changed

+295
-88
lines changed

4 files changed

+295
-88
lines changed

SAMPLE-action.ps1

Lines changed: 0 additions & 48 deletions
This file was deleted.

SAMPLE-action.yml

Lines changed: 0 additions & 40 deletions
This file was deleted.

action.ps1

Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
#!/usr/bin/env pwsh
2+
3+
[cmdletbinding()]
4+
param()
5+
6+
if (-not (Get-Module -ListAvailable GitHubActions)) {
7+
Install-Module GitHubActions -Force
8+
}
9+
10+
Import-Module GitHubActions
11+
12+
## Pull in some inputs
13+
$repositoryUrl = Get-ActionInput repositoryUrl -Required
14+
$defaultBranch = Get-ActionInput defaultBranch
15+
$rootDocsFolder = Get-ActionInput root
16+
$convertRootReadmeToHomePage = Get-ActionInput convertRootReadmeToHomePage
17+
$useHeaderForWikiName = Get-ActionInput useHeaderForWikiName
18+
19+
$wikiRepoName = ($repositoryUrl -split "/")[-1] + ".wiki"
20+
$wikiRepoUrl = "$repositoryUrl.wiki.git"
21+
22+
if (-not $defaultBranch) {
23+
$defaultBranch = git branch --show-current
24+
}
25+
26+
if (-not $rootDocsFolder)
27+
{
28+
$rootDocsFolder = "."
29+
$rootDocsFolderDirs = @()
30+
}
31+
else
32+
{
33+
$rootDocsFolderDirs = $rootDocsFolder -split "/"
34+
}
35+
36+
$filenameToWikiNameMap = @{}
37+
$wikiNameToFileNameMap = @{}
38+
39+
Function ProcessSourceDirectory()
40+
{
41+
[cmdletbinding()]
42+
param([string[]]$directories=@())
43+
44+
foreach ($file in Get-ChildItem "*.md")
45+
{
46+
ProcessSourceFile $file $directories
47+
}
48+
49+
foreach ($dir in Get-ChildItem -Directory)
50+
{
51+
Push-Location $dir.Name
52+
53+
ProcessSourceDirectory ($directories + @($dir.Name))
54+
55+
Pop-Location
56+
}
57+
}
58+
59+
Function ProcessSourceFile()
60+
{
61+
[cmdletbinding()]
62+
param($file, [string[]]$directories)
63+
64+
Write-Verbose "Processing file $($file.FullName)"
65+
66+
$outputFileName = ($directories + $file.Name) -join "__"
67+
68+
$content = Get-Content -Path $file.FullName
69+
$content = UpdateFileLinks $file.Name $directories $content
70+
71+
$override = GetOutputFileNameFromFile $content
72+
73+
if ($convertRootReadmeToHomePage -and ($directories.Count -eq 0) -and ($file.Name -eq "readme.md"))
74+
{
75+
$outputFileName = "Home.md"
76+
}
77+
elseif ($override)
78+
{
79+
Write-Verbose "Using overridden file name $($override.FileName)"
80+
81+
if ($wikiNameToFileNameMap[$override.FileName])
82+
{
83+
throw "Overridden file name $($override.FileName) is already in use by $($wikiNameToFileNameMap[$override.FileName])"
84+
}
85+
$wikiNameToFileNameMap[$override.FileName] = $outputFileName
86+
87+
$filenameToWikiNameMap[$outputFileName] = $override.FileName
88+
$outputFileName = $override.FileName
89+
90+
$content = $override.NewContent
91+
}
92+
93+
$outputPath = $wikiRepoPath + "/" + $outputFileName
94+
95+
$content | Set-Content -Path $outputPath
96+
}
97+
98+
Function GetOutputFileNameFromFile()
99+
{
100+
[cmdletbinding()]
101+
param($content)
102+
103+
if ($useHeaderForWikiName)
104+
{
105+
$firstLine = $content | Select-Object -First 1
106+
$headerMatch = [regex]::match($firstLine, "^#\s+(.*)$")
107+
if ($headerMatch.Success)
108+
{
109+
$filename = $headerMatch.Groups[1].Value
110+
$filename = $filename -replace " ", "-"
111+
$filename = $filename -replace "[^A-Za-z0-9\s.(){}_!?-]", ""
112+
113+
return @{
114+
FileName = "$filename.md";
115+
NewContent = $content[1..$content.Count];
116+
}
117+
}
118+
}
119+
}
120+
121+
Function UpdateFileLinks()
122+
{
123+
[cmdletbinding()]
124+
param($filename, [string[]]$directories, $content)
125+
126+
$evaluator = {
127+
[cmdletbinding()]
128+
param($match)
129+
130+
$text = $match.Groups[1].Value
131+
$link = $match.Groups[2].Value
132+
133+
if ($link -like "http*")
134+
{
135+
# Absolute link, no change
136+
Write-Verbose "Link $link is already absolute, nothing to do"
137+
return "[$text]($link)"
138+
}
139+
140+
$upDirs = 0
141+
$path = @()
142+
143+
$link -split "/" | % {
144+
if ($_ -eq "..")
145+
{
146+
$upDirs += 1
147+
}
148+
else
149+
{
150+
$path += @($_)
151+
}
152+
}
153+
154+
if (($upDirs -le $directories.Count) -and ($link -like "*.md"))
155+
{
156+
# Link to another doc which should now point to a wiki file
157+
158+
$relativeWikiPath = @($directories | Select-Object -First ($directories.Count - $upDirs)) + @($path)
159+
$wikiFileName = ($relativeWikiPath -join "__") -replace ".md$", ""
160+
161+
Write-Verbose "Link $link updated to $wikiFileName"
162+
return "[$text]($wikiFileName)"
163+
}
164+
165+
# Outside the root directory or not a doc, convert to absolute Url
166+
$extraUpDirs = $upDirs - $directories.Count
167+
168+
if ($extraUpDirs -gt $rootDocsFolderDirs.Count)
169+
{
170+
throw "Relative link $link in $filename does not exist"
171+
}
172+
173+
$relativePathFromRoot = ($rootDocsFolderDirs | Select-Object -First ($rootDocsFolderDirs.Count - $extraUpDirs)) -join "/"
174+
if ($relativePathFromRoot) { $relativePathFromRoot += "/" }
175+
176+
$absoluteLink = $repositoryUrl + "/blob/$defaultBranch/" + $relativePathFromRoot + ($path -join "/")
177+
178+
if ($link -like "*.md")
179+
{
180+
Write-Verbose "Link $link is outside the docs root, updating to absolute link $absoluteLink"
181+
}
182+
else
183+
{
184+
Write-Verbose "Link $link is not a doc, updating to absolute link $absoluteLink"
185+
}
186+
187+
return "[$text]($absoluteLink)"
188+
}
189+
190+
# TODO - handle nested brackets
191+
# Matches `[text](link)`
192+
$linkRegex = [regex]"\[([^\]]+)\]\(([^\)]+)\)"
193+
194+
$content | % { $linkRegex.Replace($_, $evaluator) }
195+
}
196+
197+
Function ProcessWikiDirectory()
198+
{
199+
[cmdletbinding()]
200+
param([string[]]$directories=@())
201+
202+
foreach ($file in Get-ChildItem "*.md")
203+
{
204+
ProcessWikiFile $file $directories
205+
}
206+
207+
foreach ($dir in Get-ChildItem -Directory)
208+
{
209+
Push-Location $dir.Name
210+
211+
ProcessWikiDirectory ($directories + @($dir.Name))
212+
213+
Pop-Location
214+
}
215+
}
216+
217+
Function ProcessWikiFile()
218+
{
219+
[cmdletbinding()]
220+
param($file, [string[]]$directories)
221+
222+
Write-Verbose "Processing file $($file.Name)"
223+
224+
$content = Get-Content $file
225+
$filenameToWikiNameMap.Keys | % {
226+
$originalLink = $_ -replace ".md$", ""
227+
$newLink = $filenameToWikiNameMap[$_] -replace ".md$", ""
228+
229+
$content = $content -replace $originalLink, $newLink
230+
}
231+
232+
Set-Content -Path $file.FullName -Value $content -Force
233+
}
234+
235+
Push-Location ..
236+
Write-Information "Cloning wiki repo..."
237+
git clone $wikiRepoUrl
238+
$wikiRepoPath = $pwd.Path + "/" + $wikiRepoName
239+
cd $wikiRepoName
240+
git rm -rf * | Out-Null
241+
Pop-Location
242+
243+
Push-Location $rootDocsFolder
244+
Write-Information "Processing source directory..."
245+
ProcessSourceDirectory
246+
Pop-Location
247+
248+
Push-Location ..\$wikiRepoName
249+
Write-Information "Post-processing wiki files..."
250+
ProcessWikiDirectory
251+
252+
Write-Information "Pushing wiki"
253+
git add .
254+
git commit -am "Sync Files"
255+
git push
256+
Pop-Location

action.yml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
name: github-docs-to-wiki
2+
author: cmbrose
3+
description: Converts markdown content in a repository into a wiki.
4+
5+
inputs:
6+
7+
repositoryUrl:
8+
description: The url of the repository being operated on
9+
required: true
10+
11+
defaultBranch:
12+
description: The default branch name (master, main, etc)
13+
required: false
14+
default: The value returned by `git branch --show-current`
15+
16+
rootDocsFolder:
17+
description: A directory within the repository where the docs are located
18+
required: false
19+
default: The repository's root
20+
21+
convertRootReadmeToHomePage:
22+
description: If true, renames the README.md file to Home.md in the wiki (the wiki homepage)
23+
required: false
24+
default: false
25+
26+
useHeaderForWikiName:
27+
description: If true, names wiki pages according to the top header of the source file (using `#`)
28+
required: false
29+
default: false
30+
31+
outputs:
32+
33+
branding:
34+
color: purple
35+
icon: terminal
36+
37+
runs:
38+
using: node12
39+
main: _init/index.js

0 commit comments

Comments
 (0)