From 78fc950300a9a50ad4dba858cb58d281c61f5f7a Mon Sep 17 00:00:00 2001 From: Brian Golden Date: Wed, 21 Jul 2021 14:03:42 -0700 Subject: [PATCH 1/6] docs: fix links from GitHub Actions badges (#20) --- .markdownlint.json | 8 ++++++++ README.md | 10 ++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 .markdownlint.json diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 0000000..5519a3c --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,8 @@ +{ + "line-length": { + "line_length": 104, + "code_blocks": false + }, + "no-duplicate-header": false, + "ul-start-left": false +} \ No newline at end of file diff --git a/README.md b/README.md index aa293df..5196769 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,10 @@ Install your dotfiles, no matter what platform you're on. ## Build Status -| Branch | | -|:-------------|:----------------------------| -| **develop** | ![Build status][ci-develop] | -| **main** | ![Build status][ci-main] | +| Branch | | +|:-------------|:--------------------------------------------------| +| **develop** | [![Build status][ci-develop]][ci-develop-history] | +| **main** | [![Build status][ci-main]][ci-main-history] | ## Overview @@ -59,3 +59,5 @@ cnct -c ~/.dotfiles/cnct.json [create-pat]: https://docs.github.com/en/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token [ci-develop]: https://github.com/bgold09/cnct-net/actions/workflows/actions-main.yml/badge.svg?branch=develop [ci-main]: https://github.com/bgold09/cnct-net/actions/workflows/actions-main.yml/badge.svg?branch=main +[ci-develop-history]: https://github.com/bgold09/cnct-net/actions?query=event%3Apush+branch%3Adevelop +[ci-main-history]: https://github.com/bgold09/cnct-net/actions?query=event%3Apush+branch%3Amain From 6ba13665836913c8227b7bd11fba3221c8fdeea1 Mon Sep 17 00:00:00 2001 From: Brian Golden Date: Wed, 11 Aug 2021 11:16:24 -0700 Subject: [PATCH 2/6] docs: fix install command in README (#21) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5196769..64a35d7 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ $c = Get-Credential -UserName "" dotnet nuget add source --name github-bgold09 "https://nuget.pkg.github.com/bgold09/index.json" ` --username $c.UserName --password $c.GetNetworkCredential().Password -dotnet tool install --global cnct --source github-bgold09 +dotnet tool install --global cnct ``` ## Configuration file From 6303d7c90da55488e9e38a9d519d3b70011ae6e2 Mon Sep 17 00:00:00 2001 From: Brian Golden Date: Sat, 20 Nov 2021 15:31:38 -0800 Subject: [PATCH 3/6] fix: symlink creation on linux (#24) --- Cnct/Cnct.Core/NativeMethods.cs | 6 ++++-- Cnct/Cnct.Core/Tasks/LinkTask.cs | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Cnct/Cnct.Core/NativeMethods.cs b/Cnct/Cnct.Core/NativeMethods.cs index 9b4abf7..56a38f2 100644 --- a/Cnct/Cnct.Core/NativeMethods.cs +++ b/Cnct/Cnct.Core/NativeMethods.cs @@ -1,4 +1,6 @@ -using System.Runtime.InteropServices; +using System; +using System.Reflection; +using System.Runtime.InteropServices; using Cnct.Core.Tasks; namespace Cnct.Core @@ -11,7 +13,7 @@ public static extern bool CreateSymbolicLink( string targetFileName, LinkType flags); - [DllImport("libc.so.6", EntryPoint = "symlink", CharSet = CharSet.Unicode)] + [DllImport("libc", EntryPoint = "symlink", CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true)] public static extern int CreateLinuxSymlink(string targetPath, string linkPath); } } diff --git a/Cnct/Cnct.Core/Tasks/LinkTask.cs b/Cnct/Cnct.Core/Tasks/LinkTask.cs index ca739f1..2ca528e 100644 --- a/Cnct/Cnct.Core/Tasks/LinkTask.cs +++ b/Cnct/Cnct.Core/Tasks/LinkTask.cs @@ -70,7 +70,8 @@ private void CreateLink(string linkPath, string targetPath, LinkType linkType) case PlatformType.Linux: if (NativeMethods.CreateLinuxSymlink(targetPath, linkPath) != 0) { - this.Logger.LogError($"Failed to create link."); + var errno = Marshal.GetLastWin32Error(); + this.Logger.LogError($"Failed to create link (errno: {errno})."); } break; From 3ecac5838a9483da3ee71d19c3d95812d429fc7f Mon Sep 17 00:00:00 2001 From: Brian Golden Date: Mon, 20 Dec 2021 07:05:50 -0800 Subject: [PATCH 4/6] feat: add JSON schema for vNext (#25) --- Cnct/Cnct.Core/schemas/cnctConfig.vnext.json | 158 +++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 Cnct/Cnct.Core/schemas/cnctConfig.vnext.json diff --git a/Cnct/Cnct.Core/schemas/cnctConfig.vnext.json b/Cnct/Cnct.Core/schemas/cnctConfig.vnext.json new file mode 100644 index 0000000..d26b736 --- /dev/null +++ b/Cnct/Cnct.Core/schemas/cnctConfig.vnext.json @@ -0,0 +1,158 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "id": "https://raw.githubusercontent.com/bgold09/cnct-net/develop/schema/cnctConfig.vnext.json", + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "type": "string" + }, + "actions": { + "description": "The actions to execute.", + "type": "array", + "minItems": 1, + "items": { + "oneOf": [ + { + "$ref": "#/definitions/ShellAction" + }, + { + "$ref": "#/definitions/LinkAction" + } + ] + } + } + }, + "definitions": { + "ActionBase": { + "type": "object", + "required": [ + "actionType" + ], + "properties": { + "os": { + "description": "The operating system for which to execute the action.", + "type": "string", + "enum": [ + "windows", + "linux", + "osx" + ] + }, + "actionType": { + "description": "The type of the action.", + "type": "string" + }, + "description": { + "description": "A description for the action.", + "type": "string" + } + } + }, + "DestinationLinks": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + }, + "PlatformLinks": { + "type": "object", + "properties": { + "windows": { + "description": "Symlinks to create in a Windows environment.", + "$ref": "#/definitions/DestinationLinks" + }, + "linux": { + "description": "Symlinks to create in a Linux environment.", + "$ref": "#/definitions/DestinationLinks" + }, + "osx": { + "description": "Symlinks to create in an OSX environment.", + "$ref": "#/definitions/DestinationLinks" + } + } + }, + "ShellAction": { + "description": "An action that invokes a command or script in a shell.", + "allOf": [ + { + "$ref": "#/definitions/ActionBase" + }, + { + "type": "object", + "required": [ + "command" + ], + "properties": { + "actionType": { + "enum": [ + "shell" + ] + }, + "command": { + "description": "The command to invoke.", + "type": "string" + }, + "shell": { + "description": "The type of shell to use when invoking the command.", + "enum": [ + "sh", + "powershell" + ] + }, + "silent": { + "description": "If true, do not direct output from the shell to the console.", + "type": "boolean" + } + } + } + ] + }, + "LinkAction": { + "allOf":[ + { + "$ref": "#/definitions/ActionBase" + }, + { + "type": "object", + "required": [ + "links" + ], + "properties": { + "actionType": { + "enum": [ + "link" + ] + }, + "links": { + "description": "The target and destination for symlinks to create.", + "type": "object", + "minItems": 1, + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/DestinationLinks" + }, + { + "$ref": "#/definitions/PlatformLinks" + } + ] + } + } + } + } + ] + } + } +} \ No newline at end of file From 55e513619223d7432be1236b407d95725ee3cb71 Mon Sep 17 00:00:00 2001 From: Brian Golden Date: Mon, 20 Dec 2021 08:04:09 -0800 Subject: [PATCH 5/6] feat: create UNIX-specific symlinks (#26) * Allow specifying `unix` in link tasks, to create links on a UNIX system (Linux or OSX). * Resolves #23 --- .../LinkTaskSpecificationTests.cs | 89 ++++++++++++++++++- Cnct/Cnct.Core.Tests/PlatformTests.cs | 14 +++ .../Configuration/LinkTaskSpecification.cs | 35 ++++---- Cnct/Cnct.Core/Configuration/Platform.cs | 14 +++ .../Configuration/SymlinkSpecification.cs | 3 + .../schemas => schema}/cnctConfig.vnext.json | 4 + 6 files changed, 142 insertions(+), 17 deletions(-) rename {Cnct/Cnct.Core/schemas => schema}/cnctConfig.vnext.json (96%) diff --git a/Cnct/Cnct.Core.Tests/LinkTaskSpecificationTests.cs b/Cnct/Cnct.Core.Tests/LinkTaskSpecificationTests.cs index 0900692..f3e12b6 100644 --- a/Cnct/Cnct.Core.Tests/LinkTaskSpecificationTests.cs +++ b/Cnct/Cnct.Core.Tests/LinkTaskSpecificationTests.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; using System.Linq; using Cnct.Core.Configuration; @@ -84,5 +85,91 @@ public void ExplicitLinkPath() Assert.Single(links); Assert.Equal(explicitLinkPath, links.Single()); } + + /// + /// If Windows-specific links are specified, they should only be created in a Windows enviromment. + /// + [Fact] + public void CreateWindowsLinks() + { + TestPlatformLinks(PlatformType.Windows, new SymlinkSpecification + { + Windows = Array.Empty(), + }); + } + + /// + /// If Linux-specific links are specified, they should only be created in a Linux environment. + /// + [Fact] + public void CreateLinuxLinks() + { + TestPlatformLinks(PlatformType.Linux, new SymlinkSpecification + { + Linux = Array.Empty(), + }); + } + + /// + /// If OSX-specific links are specified, they should only be created in an OSX environment. + /// + [Fact] + public void CreateOsxLinks() + { + TestPlatformLinks(PlatformType.OSX, new SymlinkSpecification + { + Osx = Array.Empty(), + }); + } + + /// + /// If UNIX-specific links are specified, they should only be created in UNIX environments (Linux and OSX). + /// + /// The platform that should create links. + [Fact] + public void CreateUnixLinks() + { + TestPlatformLinks( + Platform.CurrentPlatformIsUnix, + new SymlinkSpecification + { + Unix = Array.Empty(), + }); + } + + private static void TestPlatformLinks(bool predicate, SymlinkSpecification symlinkSpec) + { + string configRootDirectory = "test"; + string target = "file.ext"; + string expectedFullTargetPath = $"{configRootDirectory}{Path.DirectorySeparatorChar}{target}"; + var linkSpec = new LinkTaskSpecification() + { + Links = new Dictionary() + { + [target] = symlinkSpec, + }, + }; + + var actualLinks = linkSpec.GetLinkConfigurations(configRootDirectory); + + if (predicate) + { + Assert.Equal(1, actualLinks.Count); + Assert.Contains(expectedFullTargetPath, actualLinks); + + IEnumerable links = actualLinks[expectedFullTargetPath]; + Assert.Single(links); + Assert.Equal($"{Platform.Home}{Path.DirectorySeparatorChar}.{target}", links.Single()); + } + else + { + Assert.Empty(actualLinks); + } + } + + private static void TestPlatformLinks(PlatformType allowedPlatform, SymlinkSpecification symlinkSpec) + { + TestPlatformLinks(allowedPlatform == Platform.CurrentPlatform, symlinkSpec); + } } } diff --git a/Cnct/Cnct.Core.Tests/PlatformTests.cs b/Cnct/Cnct.Core.Tests/PlatformTests.cs index cbba2d6..e75fe0a 100644 --- a/Cnct/Cnct.Core.Tests/PlatformTests.cs +++ b/Cnct/Cnct.Core.Tests/PlatformTests.cs @@ -32,5 +32,19 @@ public void IdentifyCurrentPlatform() Assert.Equal(expectedPlatformType, actualPlatformType); } + + [Fact] + public void IsUnixPlatform() + { + bool isUnix = Platform.CurrentPlatformIsUnix; + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + Assert.True(isUnix); + } + else + { + Assert.False(isUnix); + } + } } } diff --git a/Cnct/Cnct.Core/Configuration/LinkTaskSpecification.cs b/Cnct/Cnct.Core/Configuration/LinkTaskSpecification.cs index 38d8065..17cf89f 100644 --- a/Cnct/Cnct.Core/Configuration/LinkTaskSpecification.cs +++ b/Cnct/Cnct.Core/Configuration/LinkTaskSpecification.cs @@ -41,21 +41,21 @@ public IDictionary> GetLinkConfigurations(string con break; case SymlinkSpecification spec: - string[] destinationPaths = null; - switch (Platform.CurrentPlatform) + string[] platformLinkPaths = Platform.CurrentPlatform switch { - case PlatformType.Windows: - destinationPaths = GetPlatformLinkPaths(target, spec.Windows); - break; - case PlatformType.Linux: - destinationPaths = GetPlatformLinkPaths(target, spec.Linux); - break; - case PlatformType.OSX: - destinationPaths = GetPlatformLinkPaths(target, spec.Osx); - break; + PlatformType.Windows => spec.Windows, + PlatformType.Linux => spec.Linux, + PlatformType.OSX => spec.Osx, + _ => throw new NotImplementedException(), + }; + + string[] destinationPaths; + if (TryGetPlatformLinkPaths(target, platformLinkPaths, out destinationPaths)) + { + linkConfigs.Add(target, destinationPaths); } - if (destinationPaths != null) + if (Platform.CurrentPlatformIsUnix && TryGetPlatformLinkPaths(target, spec.Unix, out destinationPaths)) { linkConfigs.Add(target, destinationPaths); } @@ -73,19 +73,22 @@ public async Task ExecuteAsync(ILogger logger, string confgiDirectoryRoot) await linkTask.ExecuteAsync(); } - private static string[] GetPlatformLinkPaths(string target, string[] platformLinkPaths) + private static bool TryGetPlatformLinkPaths(string target, string[] platformLinkPaths, out string[] destinationLinks) { if (platformLinkPaths == null) { - return null; + destinationLinks = null; + return false; } else if (platformLinkPaths.Length == 0) { - return new[] { GetDotFileLinkPath(target) }; + destinationLinks = new[] { GetDotFileLinkPath(target) }; + return true; } else { - return platformLinkPaths.Select(p => p.NormalizePath()).ToArray(); + destinationLinks = platformLinkPaths.Select(p => p.NormalizePath()).ToArray(); + return true; } } diff --git a/Cnct/Cnct.Core/Configuration/Platform.cs b/Cnct/Cnct.Core/Configuration/Platform.cs index 85f3241..186d74a 100644 --- a/Cnct/Cnct.Core/Configuration/Platform.cs +++ b/Cnct/Cnct.Core/Configuration/Platform.cs @@ -26,6 +26,20 @@ public static string Home public static PlatformType CurrentPlatform => CurrentPlatformLazy.Value; + public static bool CurrentPlatformIsUnix { get; } = IsUnix(); + + private static bool IsUnix() + { + switch (CurrentPlatform) + { + case PlatformType.Linux: + case PlatformType.OSX: + return true; + default: + return false; + } + } + private static PlatformType GetCurrentPlatformType() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) diff --git a/Cnct/Cnct.Core/Configuration/SymlinkSpecification.cs b/Cnct/Cnct.Core/Configuration/SymlinkSpecification.cs index 21b578d..14fee39 100644 --- a/Cnct/Cnct.Core/Configuration/SymlinkSpecification.cs +++ b/Cnct/Cnct.Core/Configuration/SymlinkSpecification.cs @@ -12,5 +12,8 @@ public class SymlinkSpecification [JsonConverter(typeof(LinkCollectionConverter))] public string[] Linux { get; set; } + + [JsonConverter(typeof(LinkCollectionConverter))] + public string[] Unix { get; set; } } } diff --git a/Cnct/Cnct.Core/schemas/cnctConfig.vnext.json b/schema/cnctConfig.vnext.json similarity index 96% rename from Cnct/Cnct.Core/schemas/cnctConfig.vnext.json rename to schema/cnctConfig.vnext.json index d26b736..e0dda93 100644 --- a/Cnct/Cnct.Core/schemas/cnctConfig.vnext.json +++ b/schema/cnctConfig.vnext.json @@ -80,6 +80,10 @@ "osx": { "description": "Symlinks to create in an OSX environment.", "$ref": "#/definitions/DestinationLinks" + }, + "unix": { + "description": "Symlinks to create in a UNIX environment.", + "$ref": "#/definitions/DestinationLinks" } } }, From 77abd94e10b318aec5a99277517626e015114dad Mon Sep 17 00:00:00 2001 From: Brian Golden Date: Mon, 20 Dec 2021 08:32:04 -0800 Subject: [PATCH 6/6] feat: update to .NET 6 runtime and update packages (#27) --- .github/workflows/actions-main.yml | 2 +- Cnct/Cnct.Core.Tests/Cnct.Core.Tests.csproj | 4 +-- Cnct/Cnct.Core/Cnct.Core.csproj | 10 +++--- Cnct/Cnct.NetCore/Cnct.NetCore.csproj | 6 ++-- azure-pipelines.yml | 36 --------------------- 5 files changed, 11 insertions(+), 47 deletions(-) delete mode 100644 azure-pipelines.yml diff --git a/.github/workflows/actions-main.yml b/.github/workflows/actions-main.yml index 9b057e4..fba7c9f 100644 --- a/.github/workflows/actions-main.yml +++ b/.github/workflows/actions-main.yml @@ -28,7 +28,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v1 with: - dotnet-version: 3.1.x + dotnet-version: 6.0.x source-url: https://nuget.pkg.github.com/${{github.repository_owner}}/index.json env: NUGET_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}} diff --git a/Cnct/Cnct.Core.Tests/Cnct.Core.Tests.csproj b/Cnct/Cnct.Core.Tests/Cnct.Core.Tests.csproj index 3964901..b7a4e06 100644 --- a/Cnct/Cnct.Core.Tests/Cnct.Core.Tests.csproj +++ b/Cnct/Cnct.Core.Tests/Cnct.Core.Tests.csproj @@ -1,14 +1,14 @@ - netcoreapp3.1 + net6.0 false - + all runtime; build; native; contentfiles; analyzers diff --git a/Cnct/Cnct.Core/Cnct.Core.csproj b/Cnct/Cnct.Core/Cnct.Core.csproj index 9f09612..b67ac59 100644 --- a/Cnct/Cnct.Core/Cnct.Core.csproj +++ b/Cnct/Cnct.Core/Cnct.Core.csproj @@ -2,25 +2,25 @@ Library - netcoreapp3.1 + net6.0 Cnct.Core Cnct.Core 8.0 - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + all runtime; build; native; contentfiles; analyzers - + diff --git a/Cnct/Cnct.NetCore/Cnct.NetCore.csproj b/Cnct/Cnct.NetCore/Cnct.NetCore.csproj index 4492f23..288e6b5 100644 --- a/Cnct/Cnct.NetCore/Cnct.NetCore.csproj +++ b/Cnct/Cnct.NetCore/Cnct.NetCore.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp3.1 + net6.0 true cnct @@ -20,7 +20,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -28,7 +28,7 @@ all runtime; build; native; contentfiles; analyzers - + diff --git a/azure-pipelines.yml b/azure-pipelines.yml deleted file mode 100644 index 0e9909f..0000000 --- a/azure-pipelines.yml +++ /dev/null @@ -1,36 +0,0 @@ -trigger: -- master -- develop -- release/* - -pr: -- master -- develop -- release/* - -pool: - vmImage: windows-2019 - -steps: -- task: DotNetCoreCLI@2 - displayName: Restore - inputs: - command: restore - projects: '**/*.csproj' - -- task: DotNetCoreCLI@2 - displayName: Build - inputs: - command: build - projects: './Cnct/Cnct.sln' - arguments: '--no-incremental --configuration Release /WarnAsError' - -- task: DotNetCoreCLI@2 - displayName: Test - inputs: - command: test - projects: '**/*Tests/*.csproj' - arguments: '--configuration Release' - -- task: PublishBuildArtifacts@1 -