Skip to content

Commit

Permalink
Fix paths on Windows (#37)
Browse files Browse the repository at this point in the history
  • Loading branch information
joachimdalen authored Jan 10, 2023
1 parent b15260b commit 8abec83
Show file tree
Hide file tree
Showing 19 changed files with 182 additions and 129 deletions.
20 changes: 18 additions & 2 deletions .github/workflows/pr-validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,17 @@ env:
jobs:
build-cli:
name: Build CLI (${{ matrix.rid }})
runs-on: ubuntu-latest
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- rid: win-x64
os: windows-latest
- rid: linux-x64
os: ubuntu-latest
- rid: osx-x64
os: macos-latest
steps:
- uses: actions/checkout@v3
- name: Setup .NET Core
Expand All @@ -35,4 +38,17 @@ jobs:
run: dotnet test --configuration release src/BicepDocs.sln
- name: Build binary
run: dotnet publish --configuration release --self-contained true -p:PublishTrimmed=true -p:PublishSingleFile=true -p:TrimmerDefaultAction=copyused -p:SuppressTrimAnalysisWarnings=true -r ${{ matrix.rid }} ./src/BicepDocs.Cli/BicepDocs.Cli.csproj

- name: Test samples
if: matrix.rid != 'win-x64'
run: |
mv ./src/BicepDocs.Cli/bin/release/net6.0/${{ matrix.rid }}/publish/bicepdocs .
./bicepdocs generate filesystem \
--folderPath docs/formatters/examples/inputs \
--out ./docs/formatters/examples/generated-output/markdown \
--config docs/example-config.yml \
--formatter markdown
- name: Test samples (win)
if: matrix.rid == 'win-x64'
run: |
mv .\src\BicepDocs.Cli\bin\release\net6.0\${{ matrix.rid }}\publish\bicepdocs.exe .
.\bicepdocs.exe generate filesystem --folderPath docs\formatters\examples\inputs --out .\docs\formatters\examples\generated-output\markdown --config docs\example-config.yml --formatter markdown
9 changes: 5 additions & 4 deletions src/BicepDocs.Core.UnitTests/BicepFileTestBase.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.IO.Abstractions;
using Bicep.Core;
using Bicep.Core.Semantics;
using LandingZones.Tools.BicepDocs.Core.Extensions;
using Microsoft.Extensions.DependencyInjection;

namespace LandingZones.Tools.BicepDocs.Core.UnitTests;
Expand All @@ -27,11 +28,11 @@ protected async Task<SemanticModel> GetModelFromPath(string filePath)

protected async Task<SemanticModel> GetModel(string fileContent, string fileName = "deploy.bicep")
{
var vPath = Path.Join("/modules", fileName);
FileSystem.Directory.CreateDirectory("/modules");
var vPath = Path.Join("/modules", fileName).ToPlatformPath();
FileSystem.Directory.CreateDirectory("/modules".ToPlatformPath());
await FileSystem.File.WriteAllTextAsync(vPath, fileContent);
var compiler = ServiceProvider.GetRequiredService<BicepCompiler>();
var compilation = await compiler.CreateCompilation(new Uri(vPath));
var compilation = await compiler.CreateCompilation(PathResolver.FilePathToUri(vPath));
return compilation.GetEntrypointSemanticModel();
}
}
}
18 changes: 10 additions & 8 deletions src/BicepDocs.Core.UnitTests/Models/GenerationFileTests.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using LandingZones.Tools.BicepDocs.Core.Extensions;
using LandingZones.Tools.BicepDocs.Core.Models.Formatting;

namespace LandingZones.Tools.BicepDocs.Core.UnitTests.Models;
Expand All @@ -8,19 +9,20 @@ public class GenerationFileTests
[TestMethod]
public void GenerationFile_ValidPath_ReturnsFolder()
{
var ctx = new TextGenerationFile("/some/path/here/deploy.bicep", "");
Assert.AreEqual("/some/path/here", ctx.FolderPath);
var ctx = new TextGenerationFile("/some/path/here/deploy.bicep".ToPlatformPath(), "");
Assert.AreEqual("/some/path/here".ToPlatformPath(), ctx.FolderPath);
}

[TestMethod]
public void GenerationFile_VersionString_SetsProperties()
{
var ctx = new DemoGenFile("/some/path/here/deploy.bicep", "/some/path/here/version/deploy.bicep");
Assert.AreEqual("/some/path/here", ctx.FolderPath);
Assert.AreEqual("/some/path/here/deploy.bicep", ctx.FilePath);
var ctx = new DemoGenFile("/some/path/here/deploy.bicep".ToPlatformPath(), "/some/path/here/version/deploy.bicep"
.ToPlatformPath());
Assert.AreEqual("/some/path/here".ToPlatformPath(), ctx.FolderPath);
Assert.AreEqual("/some/path/here/deploy.bicep".ToPlatformPath(), ctx.FilePath);

Assert.AreEqual("/some/path/here/version", ctx.VersionFolderPath);
Assert.AreEqual("/some/path/here/version/deploy.bicep", ctx.VersionFilePath);
Assert.AreEqual("/some/path/here/version".ToPlatformPath(), ctx.VersionFolderPath);
Assert.AreEqual("/some/path/here/version/deploy.bicep".ToPlatformPath(), ctx.VersionFilePath);
}

class DemoGenFile : GenerationFile
Expand All @@ -29,4 +31,4 @@ public DemoGenFile(string filePath, string? versionFilePath = null) : base(fileP
{
}
}
}
}
44 changes: 22 additions & 22 deletions src/BicepDocs.Core.UnitTests/PathResolverTests.cs
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
using LandingZones.Tools.BicepDocs.Core.Extensions;

namespace LandingZones.Tools.BicepDocs.Core.UnitTests;

[TestClass]
public class PathResolverTests
{

[DataTestMethod]
[DataRow("./docs/somefolder","/root","/root/docs/somefolder")]
[DataRow("/root/docs/somefolder","/root","/root/docs/somefolder")]
[DataRow("../docs/somefolder","/root/mypath","/root/docs/somefolder")]
[DataRow("./docs/somefolder", "/root", "/root/docs/somefolder")]
[DataRow("/root/docs/somefolder", "/root", "/root/docs/somefolder")]
[DataRow("../docs/somefolder", "/root/mypath", "/root/docs/somefolder")]
public void ResolvePath_Input_Resolves(string input, string baseDirectory, string expected)
{
var resolved = PathResolver.ResolvePath(input, baseDirectory);

Assert.AreEqual(expected, resolved);
var resolved = PathResolver.ResolvePath(input.ToPlatformPath(), baseDirectory.ToPlatformPath());
Assert.AreEqual(Path.Combine(Path.GetPathRoot(resolved)!, expected.TrimStart('/').ToPlatformPath()), resolved);
}

[TestMethod]
public void PathResolver_ResolveModulePaths_Resolves()
{
var inputFolder = "/input/folder/modules";
var outputBaseFolder = "/output-folder/some-dir/docs";
var outputFolder = "/output-folder/some-dir/docs/vaults";
var inputFile = "/input/folder/modules/vaults/vault.bicep";
var relativeInputPath = "/vaults/vault.bicep";
var outputPath = "/output-folder/some-dir/docs/vaults/vault.md";
var inputFolder = "/input/folder/modules".ToPlatformPath();
var outputBaseFolder = "/output-folder/some-dir/docs".ToPlatformPath();
var outputFolder = "/output-folder/some-dir/docs/vaults".ToPlatformPath();
var inputFile = "/input/folder/modules/vaults/vault.bicep".ToPlatformPath();
var relativeInputPath = "/vaults/vault.bicep".ToPlatformPath();
var outputPath = "/output-folder/some-dir/docs/vaults/vault.md".ToPlatformPath();
var resolved = PathResolver.ResolveModulePaths(
bicepFilePath: inputFile,
baseInputFolder: inputFolder,
Expand All @@ -36,25 +36,25 @@ public void PathResolver_ResolveModulePaths_Resolves()
Assert.AreEqual(outputFolder, resolved.OutputFolder);
Assert.AreEqual(outputBaseFolder, resolved.OutputBaseFolder);
Assert.AreEqual(relativeInputPath, resolved.RelativeInputPath);
Assert.AreEqual("/modules/vaults/vault.bicep", resolved.VirtualPath);
Assert.AreEqual("/modules/vaults", resolved.VirtualFolder);
Assert.AreEqual("/modules/vaults/vault.bicep".ToPlatformPath(), resolved.VirtualPath);
Assert.AreEqual("/modules/vaults".ToPlatformPath(), resolved.VirtualFolder);
Assert.AreEqual(outputPath, resolved.OutputPath);
}

[TestMethod]
public void PathResolver_ResolveVersionPath_Resolves()
{
var inputFolder = "/input/folder/modules";
var outputBaseFolder = "/output-folder/some-dir/docs";
var inputFile = "/input/folder/modules/vaults/role-assignments/vault-rbac.bicep";
var inputFolder = "/input/folder/modules".ToPlatformPath();
var outputBaseFolder = "/output-folder/some-dir/docs".ToPlatformPath();
var inputFile = "/input/folder/modules/vaults/role-assignments/vault-rbac.bicep".ToPlatformPath();
var modulePaths = PathResolver.ResolveModulePaths(
bicepFilePath: inputFile,
baseInputFolder: inputFolder,
outputFolder: outputBaseFolder);

var filePaths = PathResolver.ResolveVersionPath(modulePaths, "2022-12-18");

Assert.AreEqual("/output-folder/some-dir/docs/vaults/versions/2022-12-18/role-assignments/vault-rbac.md", filePaths.OutputPath);
Assert.AreEqual("/output-folder/some-dir/docs/vaults/versions/2022-12-18/role-assignments", filePaths.OutputFolder);
Assert.AreEqual("/output-folder/some-dir/docs/vaults/versions/2022-12-18/role-assignments/vault-rbac.md".ToPlatformPath(), filePaths.OutputPath);
Assert.AreEqual("/output-folder/some-dir/docs/vaults/versions/2022-12-18/role-assignments".ToPlatformPath(), filePaths.OutputFolder);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@ param resourceGroupName string
Assert.IsNotNull(res);
Assert.AreEqual(1, res.AllResources.Length);
}
}
}
14 changes: 14 additions & 0 deletions src/BicepDocs.Core.UnitTests/TestExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using LandingZones.Tools.BicepDocs.Core.Extensions;

namespace LandingZones.Tools.BicepDocs.Core.UnitTests
{
public static class TestExtensions
{
public static string ToPlatformLineEndings(this string text)
{
return text.Contains("\r\n") ? text.Replace("\r\n", "\n") : text.Replace("\n", Environment.NewLine).Replace("\r", Environment.NewLine);
}

public static string WithPlatformRootPath(this string text) => Path.Combine(Path.GetPathRoot(Environment.CurrentDirectory)!, text.TrimStart('/').TrimStart('\\').ToPlatformPath());
}
}
7 changes: 6 additions & 1 deletion src/BicepDocs.Core/Extensions/StringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,16 @@ public static string Repeat(this string text, int count)
return string.Concat(Enumerable.Repeat(text, count));
}

public static string ToPlatformPath(this string path)
{
return path.Replace('\\', Path.DirectorySeparatorChar).Replace('/', Path.DirectorySeparatorChar);
}

public static string FirstCharToUpper(this string? input) =>
input switch
{
null => throw new ArgumentNullException(nameof(input)),
"" => throw new ArgumentException($"{nameof(input)} cannot be empty", nameof(input)),
_ => string.Concat(input[0].ToString().ToUpper(), input.AsSpan(1))
};
}
}
6 changes: 4 additions & 2 deletions src/BicepDocs.Core/Models/Formatting/GenerationFile.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
using LandingZones.Tools.BicepDocs.Core.Extensions;

namespace LandingZones.Tools.BicepDocs.Core.Models.Formatting;

public abstract class GenerationFile
{
protected GenerationFile(string filePath, string? versionFilePath = null)
{
FilePath = filePath;
FilePath = filePath.ToPlatformPath();
FolderPath = Path.GetDirectoryName(filePath) ?? throw new ArgumentException("Failed to resolve folder path");

if (!string.IsNullOrEmpty(versionFilePath))
Expand Down Expand Up @@ -35,4 +37,4 @@ protected GenerationFile(string filePath, string? versionFilePath = null)
/// Base folder of <see cref="VersionFilePath"/>
/// </summary>
public string? VersionFolderPath { get; }
}
}
18 changes: 13 additions & 5 deletions src/BicepDocs.Core/PathResolver.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
using LandingZones.Tools.BicepDocs.Core.Extensions;
using LandingZones.Tools.BicepDocs.Core.Models.Formatting;

namespace LandingZones.Tools.BicepDocs.Core;

public static class PathResolver
{
private const string VirtualBasePath = "/modules";
private const string VirtualBasePath = "modules";
private const string VersionsBasePath = "versions";

public static string ResolvePath(string path, string? baseDirectory = null)
Expand All @@ -22,7 +23,7 @@ public static ModuleVersionPaths ResolveVersionPath(ModulePaths modulePaths, str
{
var relativeOutput = Path.GetRelativePath(modulePaths.OutputBaseFolder, modulePaths.OutputFolder);
var root = relativeOutput.Split(Path.DirectorySeparatorChar);
var newPath = Path.Join(root.First(), VersionsBasePath, version,
var newPath = Path.Join(root.First(), Path.DirectorySeparatorChar.ToString(), VersionsBasePath, version,
string.Join(Path.DirectorySeparatorChar, root.Skip(1)));

return new ModuleVersionPaths(OutputFolder: Path.Join(modulePaths.OutputBaseFolder, newPath),
Expand All @@ -37,8 +38,8 @@ public static ModulePaths ResolveModulePaths(string bicepFilePath, string baseIn
var outputPathMd = Path.ChangeExtension(outputPath, "md");
return new ModulePaths(
RelativeInputPath: modulePath,
VirtualPath: Path.Join(VirtualBasePath, modulePath),
VirtualFolder: Path.Join(VirtualBasePath, Path.GetDirectoryName(modulePath)),
VirtualPath: Path.Join(Path.DirectorySeparatorChar.ToString(),VirtualBasePath, modulePath),
VirtualFolder: Path.Join(Path.DirectorySeparatorChar.ToString(),VirtualBasePath, Path.GetDirectoryName(modulePath)),
BaseFileName: Path.GetFileNameWithoutExtension(bicepFilePath),
InputFolder: baseInputFolder,
OutputBaseFolder: outputFolder,
Expand All @@ -49,4 +50,11 @@ public static ModulePaths ResolveModulePaths(string bicepFilePath, string baseIn
OutputPath: outputPathMd
);
}
}

public static Uri FilePathToUri(string path) => new UriBuilder
{
Scheme = "file",
Host = null,
Path = path.ToPlatformPath(),
}.Uri;
}
4 changes: 2 additions & 2 deletions src/BicepDocs.Core/Services/BicepFileService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ public async Task<SemanticModel> GetSemanticModelFromContent(string folder, stri
{
_fileSystem.Directory.CreateDirectory(folder);
await _fileSystem.File.WriteAllTextAsync(path, content);
var compilation = await _compiler.CreateCompilation(new Uri(path));
var compilation = await _compiler.CreateCompilation(PathResolver.FilePathToUri(path));
var sourceFile = compilation.GetEntrypointSemanticModel();
return sourceFile;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Collections.Immutable;
using System.IO.Abstractions;
using LandingZones.Tools.BicepDocs.Core.Abstractions;
using LandingZones.Tools.BicepDocs.Core.Extensions;
using LandingZones.Tools.BicepDocs.Core.Models.Formatting;
using Microsoft.Extensions.Logging.Abstractions;
using Moq;
Expand All @@ -23,7 +24,7 @@ public void Write_InvalidGenerationFileType_Throws()
var sut = new FileSystemDestination(new NullLogger<FileSystemDestination>(), _fileSystemMock.Object);
var files = new List<GenerationFile>()
{
new DummyGenFile("/somewhere/folder/deploy.md")
new DummyGenFile("/somewhere/folder/deploy.md".ToPlatformPath())
}.ToImmutableList();

Assert.ThrowsExceptionAsync<ArgumentException>(() => sut.Write(files));
Expand All @@ -32,15 +33,15 @@ public void Write_InvalidGenerationFileType_Throws()
[TestMethod]
public async Task Write_NoVersion_WritesSingleFile()
{
_fileSystemMock.Setup(x => x.Directory.Exists("/somewhere/folder")).Returns(true);
_fileSystemMock.Setup(x => x.Directory.Exists("/somewhere/folder".ToPlatformPath())).Returns(true);
_fileSystemMock
.Setup(x => x.File.WriteAllTextAsync("/somewhere/folder/deploy.md", It.IsAny<string>(),
.Setup(x => x.File.WriteAllTextAsync("/somewhere/folder/deploy.md".ToPlatformPath(), It.IsAny<string>(),
It.IsAny<CancellationToken>())).Returns(Task.CompletedTask);

var sut = new FileSystemDestination(new NullLogger<FileSystemDestination>(), _fileSystemMock.Object);
var files = new List<GenerationFile>()
{
new TextGenerationFile("/somewhere/folder/deploy.md", "hello-there")
new TextGenerationFile("/somewhere/folder/deploy.md".ToPlatformPath(), "hello-there")
}.ToImmutableList();

await sut.Write(files);
Expand All @@ -55,16 +56,16 @@ public async Task Write_WithVersion_WritesMultipleFiles()
{
_fileSystemMock.Setup(x => x.Directory.Exists(It.IsAny<string>())).Returns(true);
_fileSystemMock
.Setup(x => x.File.WriteAllTextAsync("/somewhere/folder/deploy.md", It.IsAny<string>(),
.Setup(x => x.File.WriteAllTextAsync("/somewhere/folder/deploy.md".ToPlatformPath(), It.IsAny<string>(),
It.IsAny<CancellationToken>())).Returns(Task.CompletedTask);
_fileSystemMock
.Setup(x => x.File.WriteAllTextAsync("/somewhere/v1/folder/deploy.md", It.IsAny<string>(),
.Setup(x => x.File.WriteAllTextAsync("/somewhere/v1/folder/deploy.md".ToPlatformPath(), It.IsAny<string>(),
It.IsAny<CancellationToken>())).Returns(Task.CompletedTask);

var sut = new FileSystemDestination(new NullLogger<FileSystemDestination>(), _fileSystemMock.Object);
var files = new List<GenerationFile>()
{
new TextGenerationFile("/somewhere/folder/deploy.md", "hello-there", "/somewhere/v1/folder/deploy.md")
new TextGenerationFile("/somewhere/folder/deploy.md".ToPlatformPath(), "hello-there", "/somewhere/v1/folder/deploy.md".ToPlatformPath())
}.ToImmutableList();

await sut.Write(files);
Expand All @@ -77,16 +78,16 @@ public async Task Write_WithVersion_WritesMultipleFiles()
[TestMethod]
public async Task Write_OutDirectoryDoesNotExist_CreatesDirectory()
{
_fileSystemMock.Setup(x => x.Directory.Exists("/somewhere/folder")).Returns(false);
_fileSystemMock.Setup(x => x.Directory.CreateDirectory("/somewhere/folder")).Returns((IDirectoryInfo)null!);
_fileSystemMock.Setup(x => x.Directory.Exists("/somewhere/folder".ToPlatformPath())).Returns(false);
_fileSystemMock.Setup(x => x.Directory.CreateDirectory("/somewhere/folder".ToPlatformPath())).Returns((IDirectoryInfo)null!);
_fileSystemMock
.Setup(x => x.File.WriteAllTextAsync("/somewhere/folder/deploy.md", It.IsAny<string>(),
.Setup(x => x.File.WriteAllTextAsync("/somewhere/folder/deploy.md".ToPlatformPath(), It.IsAny<string>(),
It.IsAny<CancellationToken>())).Returns(Task.CompletedTask);

var sut = new FileSystemDestination(new NullLogger<FileSystemDestination>(), _fileSystemMock.Object);
var files = new List<GenerationFile>()
{
new TextGenerationFile("/somewhere/folder/deploy.md", "hello-there")
new TextGenerationFile("/somewhere/folder/deploy.md".ToPlatformPath(), "hello-there")
}.ToImmutableList();

await sut.Write(files);
Expand All @@ -102,4 +103,4 @@ public DummyGenFile(string filePath, string? versionFilePath = null) : base(file
{
}
}
}
}
Loading

0 comments on commit 8abec83

Please sign in to comment.