diff --git a/.appveyor.yml b/.appveyor.yml index afb3780..1180781 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -22,5 +22,9 @@ branches: # Build Cache # #---------------------------------# cache: -- Source\packages -> Source\**\packages.config -- tools -> setup.cake \ No newline at end of file +- tools -> setup.cake + +#---------------------------------# +# Build Image # +#---------------------------------# +image: Visual Studio 2017 \ No newline at end of file diff --git a/.gitignore b/.gitignore index f1e3d20..4623fec 100644 --- a/.gitignore +++ b/.gitignore @@ -250,3 +250,6 @@ paket-files/ # JetBrains Rider .idea/ *.sln.iml + +BuildArtifacts +tools diff --git a/nuspec/nuget/Cake.DotEnv.Module.nuspec b/nuspec/nuget/Cake.DotEnv.Module.nuspec index 0627745..843fcfc 100644 --- a/nuspec/nuget/Cake.DotEnv.Module.nuspec +++ b/nuspec/nuget/Cake.DotEnv.Module.nuspec @@ -2,17 +2,24 @@ Cake.DotEnv.Module - 0.0.0 + 0.0.1 Jamie Phillips Jamie Phillips Cake Module for using the dotenv file for settings local environment variables. Cake Module for using the dotenv file for settings local environment variables. https://github.com/cake-contrib/Cake.DotEnv.Module/blob/master/LICENSE https://github.com/cake-contrib/Cake.DotEnv.Module/Cake.Netlify + https://cdn.jsdelivr.net/gh/cake-contrib/graphics/png/cake-contrib-medium.png false Copyright (c) Jamie Phillips 2017 - Present Cake, Script, Build, DotEnv, Module - + + + + + + + \ No newline at end of file diff --git a/setup.cake b/setup.cake index 51c1926..a9ea031 100644 --- a/setup.cake +++ b/setup.cake @@ -8,7 +8,9 @@ BuildParameters.SetParameters(context: Context, title: "Cake.DotEnv.Module", repositoryOwner: "cake-contrib", repositoryName: "Cake.DotEnv.Module", - appVeyorAccountName: "cakecontrib"); + appVeyorAccountName: "cakecontrib", + shouldRunDupFinder: false, + shouldRunInspectCode: false); BuildParameters.PrintParameters(Context); @@ -18,4 +20,4 @@ ToolSettings.SetToolSettings(context: Context, testCoverageFilter: "+[*]* -[xunit.*]* -[Cake.Core]* -[Cake.Testing]* -[*.Tests]* ", testCoverageExcludeByAttribute: "*.ExcludeFromCodeCoverage*", testCoverageExcludeByFile: "*/*Designer.cs;*/*.g.cs;*/*.g.i.cs"); -Build.Run(); +Build.RunDotNetCore(); diff --git a/src/Cake.DotEnv.Module.Tests/Cake.DotEnv.Module.Tests.csproj b/src/Cake.DotEnv.Module.Tests/Cake.DotEnv.Module.Tests.csproj index e78ecec..f27bb2e 100644 --- a/src/Cake.DotEnv.Module.Tests/Cake.DotEnv.Module.Tests.csproj +++ b/src/Cake.DotEnv.Module.Tests/Cake.DotEnv.Module.Tests.csproj @@ -1,13 +1,31 @@  - netstandard1.6 + netcoreapp2.0 + false + false - - - + + + + + + + + + + + + + + + + + + Always + \ No newline at end of file diff --git a/src/Cake.DotEnv.Module.Tests/Class1.cs b/src/Cake.DotEnv.Module.Tests/Class1.cs deleted file mode 100644 index ad688c3..0000000 --- a/src/Cake.DotEnv.Module.Tests/Class1.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System; - -namespace Cake.DotEnv.Module.Tests -{ - public class Class1 - { - } -} diff --git a/src/Cake.DotEnv.Module.Tests/DotEnvTests.cs b/src/Cake.DotEnv.Module.Tests/DotEnvTests.cs new file mode 100644 index 0000000..30b2df9 --- /dev/null +++ b/src/Cake.DotEnv.Module.Tests/DotEnvTests.cs @@ -0,0 +1,70 @@ +using System; +using System.Linq; + +using Xunit; + +namespace Cake.DotEnv.Module.Tests +{ + public class DotEnvTests : IDisposable + { + private readonly FakeCakeContext context; + + public DotEnvTests() + { + context = new FakeCakeContext(); + } + + public void Dispose() + { + context.DumpLogs(); + } + + [Fact] + public void ParseEnvString() + { + var data = @" +DOTENV_TEST_ENV1=Value 1 + +DOTENV_TEST_ENV2=Value 2 + DOTENV_TEST_ENV3 = Value 3 +#DOTENV_TEST_ENV4=Value 4"; + + CakeAliases.LoadEnvString(context.CakeContext, data); + + Assert.Equal("Value 1", Environment.GetEnvironmentVariable("DOTENV_TEST_ENV1")); + Assert.Equal("Value 2", Environment.GetEnvironmentVariable("DOTENV_TEST_ENV2")); + Assert.Equal("Value 3", Environment.GetEnvironmentVariable("DOTENV_TEST_ENV3")); + Assert.Null(Environment.GetEnvironmentVariable("DOTENV_TEST_ENV4")); + + var vars = Environment.GetEnvironmentVariables().Keys.OfType().Where(x => x.StartsWith("DOTENV_TEST_")).ToList(); + + Assert.Equal(3, vars.Count); + + // Delete test vars + foreach (var variable in vars) + { + Environment.SetEnvironmentVariable(variable, null); + } + } + + [Fact] + public void ParseEnvFile() + { + Assert.True(CakeAliases.LoadDotEnv(context.CakeContext, "Testdata\\testdata01.env")); + + Assert.Equal(".COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.PY;.PYW", Environment.GetEnvironmentVariable("DOTENV_TEST_PATHEXT")); + Assert.Equal("$P$G", Environment.GetEnvironmentVariable("DOTENV_TEST_PROMPT")); + Assert.Equal("-Xms256m -Xmx512m", Environment.GetEnvironmentVariable("DOTENV_TEST_JAVA_OPTS")); + + var vars = Environment.GetEnvironmentVariables().Keys.OfType().Where(x => x.StartsWith("DOTENV_TEST_")).ToList(); + + Assert.Equal(17, vars.Count); + + // Delete test vars + foreach (var variable in vars) + { + Environment.SetEnvironmentVariable(variable, null); + } + } + } +} diff --git a/src/Cake.DotEnv.Module.Tests/FakeCakeArguments.cs b/src/Cake.DotEnv.Module.Tests/FakeCakeArguments.cs new file mode 100644 index 0000000..1c33675 --- /dev/null +++ b/src/Cake.DotEnv.Module.Tests/FakeCakeArguments.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; + +using Cake.Core; + +namespace Cake.DotEnv.Module.Tests +{ + internal sealed class FakeCakeArguments : ICakeArguments + { + private readonly Dictionary _arguments; + + /// + /// Gets the arguments. + /// + /// The arguments. + public IReadOnlyDictionary Arguments => _arguments; + + /// + /// Initializes a new instance of the class. + /// + public FakeCakeArguments() + { + _arguments = new Dictionary(StringComparer.OrdinalIgnoreCase); + } + + /// + /// Initializes the argument list. + /// + /// The arguments. + public void SetArguments(IDictionary arguments) + { + if (arguments == null) + { + throw new ArgumentNullException(nameof(arguments)); + } + + _arguments.Clear(); + + foreach ((string key, string value) in arguments) + { + _arguments.Add(key, value); + } + } + + /// + /// Determines whether or not the specified argument exist. + /// + /// The argument name. + /// + /// true if the argument exist; otherwise false. + /// + public bool HasArgument(string name) + { + return _arguments.ContainsKey(name); + } + + /// + /// Gets an argument. + /// + /// The argument name. + /// The argument value. + public string GetArgument(string name) + { + return _arguments.ContainsKey(name) ? _arguments[name] : null; + } + } +} diff --git a/src/Cake.DotEnv.Module.Tests/FakeCakeContext.cs b/src/Cake.DotEnv.Module.Tests/FakeCakeContext.cs new file mode 100644 index 0000000..1b14a48 --- /dev/null +++ b/src/Cake.DotEnv.Module.Tests/FakeCakeContext.cs @@ -0,0 +1,55 @@ +using System; + +using Cake.Core; +using Cake.Core.IO; +using Cake.Core.Tooling; +using Cake.Testing; + +using Path = System.IO.Path; +using NSubstitute; + +namespace Cake.DotEnv.Module.Tests +{ + + public class FakeCakeContext + { + private readonly ICakeContext context; + private readonly FakeLog log; + private readonly DirectoryPath testsDir; + + public FakeCakeContext() + { + testsDir = new DirectoryPath(Path.GetFullPath(AppContext.BaseDirectory)); + + var environment = FakeEnvironment.CreateUnixEnvironment(false); + + var fileSystem = new FakeFileSystem(environment); + var globber = new Globber(fileSystem, environment); + log = new FakeLog(); + var args = new FakeCakeArguments(); + var registry = new WindowsRegistry(); + + var config = new FakeConfiguration(); + var tools = new ToolLocator(environment, new ToolRepository(environment), new ToolResolutionStrategy(fileSystem, environment, globber, config)); + var processRunner = new ProcessRunner(fileSystem, environment, log, tools, config); + var data = Substitute.For(); + context = new CakeContext(fileSystem, environment, globber, log, args, processRunner, registry, tools, data, config); + context.Environment.WorkingDirectory = testsDir; + } + + public DirectoryPath WorkingDirectory => testsDir; + + public ICakeContext CakeContext => context; + + public string GetLogs() + { + return string.Join(Environment.NewLine, log.Entries); + } + + public void DumpLogs() + { + foreach (var m in log.Entries) + Console.WriteLine(m); + } + } +} diff --git a/src/Cake.DotEnv.Module.Tests/Testdata/testdata01.env b/src/Cake.DotEnv.Module.Tests/Testdata/testdata01.env new file mode 100644 index 0000000..fe3ed8e --- /dev/null +++ b/src/Cake.DotEnv.Module.Tests/Testdata/testdata01.env @@ -0,0 +1,17 @@ +DOTENV_TEST_ALLUSERSPROFILE=C:\ProgramData +DOTENV_TEST_ANDROID_SDK_HOME=C:\Android +DOTENV_TEST_CommonProgramFiles=C:\Program Files\Common Files +DOTENV_TEST_CommonProgramFiles(x86)=C:\Program Files (x86)\Common Files +DOTENV_TEST_CommonProgramW6432=C:\Program Files\Common Files +DOTENV_TEST_JAVA_OPTS=-Xms256m -Xmx512m +DOTENV_TEST_OS=Windows_NT +DOTENV_TEST_PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.PY;.PYW +DOTENV_TEST_PROCESSOR_ARCHITECTURE=AMD64 +DOTENV_TEST_ProgramData=C:\ProgramData +DOTENV_TEST_ProgramFiles=C:\Program Files +DOTENV_TEST_ProgramFiles(x86)=C:\Program Files (x86) +DOTENV_TEST_ProgramW6432=C:\Program Files +DOTENV_TEST_PROMPT=$P$G +DOTENV_TEST_SystemDrive=C: +DOTENV_TEST_SystemRoot=C:\WINDOWS +DOTENV_TEST_windir=C:\WINDOWS diff --git a/src/Cake.DotEnv.Module/Cake.DotEnv.Module.csproj b/src/Cake.DotEnv.Module/Cake.DotEnv.Module.csproj index e4d67dd..ff0f0d3 100644 --- a/src/Cake.DotEnv.Module/Cake.DotEnv.Module.csproj +++ b/src/Cake.DotEnv.Module/Cake.DotEnv.Module.csproj @@ -1,11 +1,25 @@  - netstandard1.6 + net461;netstandard2.0 + Cake.DotEnv.Module + Cake.DotEnv.Module + false + true + anycpu + portable + + bin\$(Configuration)\$(TargetFramework)\Cake.DotEnv.Module.xml + + + + + + - + \ No newline at end of file diff --git a/src/Cake.DotEnv.Module/CakeAliases.cs b/src/Cake.DotEnv.Module/CakeAliases.cs new file mode 100644 index 0000000..58eee67 --- /dev/null +++ b/src/Cake.DotEnv.Module/CakeAliases.cs @@ -0,0 +1,120 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Text; + +using Cake.Core; +using Cake.Core.Annotations; +using Cake.Core.Diagnostics; +using Cake.Core.IO; + +namespace Cake.DotEnv.Module +{ + /// + /// Class CakeAliases. + /// + [CakeAliasCategory("Environment")] + [SuppressMessage("ReSharper", "UnusedMember.Global")] + public static class CakeAliases + { + /// + /// Loads the dot env. + /// + /// The context. + /// The dot env file. Is null, the filename ".env" is assumed. + /// The encoding or the default encoding if null + /// true if the dotenv file is found and processed, false otherwise. + /// context is null + [CakeMethodAlias] + [CakeAliasCategory("DotEnv")] + public static bool LoadDotEnv( + this ICakeContext context, + FilePath dotEnvFile = null, + Encoding encoding = null + ) + { + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + if (dotEnvFile == null) + { + dotEnvFile = new FilePath(".env"); + } + + var filename = dotEnvFile.FullPath; + if (!File.Exists(filename)) + { + context.Log.Error(".env file \"{0}\" not found", filename); + return false; + } + + var fileEncoding = encoding ?? Encoding.Default; + + var fileContent = File.ReadAllText(filename, fileEncoding); + + context.LoadEnvString(fileContent); + + return true; + } + + /// + /// Loads the env string. + /// + /// The context. + /// The env data. + /// context or envData is null/empty + [CakeMethodAlias] + [CakeAliasCategory("DotEnv")] + public static void LoadEnvString( + this ICakeContext context, + string envData + ) + { + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + if (string.IsNullOrWhiteSpace(envData)) + { + throw new ArgumentNullException(nameof(envData)); + } + + var fileContent = envData.SplitLines(); + + foreach (var fileContentLine in fileContent) + { + var line = fileContentLine.Trim(); + + // Skip empty or comment lines + if (string.IsNullOrWhiteSpace(line) || line.StartsWith("#")) + continue; + + // Find first equal char + var assignmentIndex = line.IndexOf('='); + + if (assignmentIndex == 0) + continue; + + var key = line.Substring(0, assignmentIndex).Trim(); + var value = line.Substring(assignmentIndex + 1, line.Length - (assignmentIndex + 1)).Trim(); + + if (key.Length == 0) + continue; + + if (value.Length > 0) + { + context.Log.Information(Verbosity.Diagnostic, "DotEnv: Setting environment variable \"{0}\" to \"{1}\"", key, value); + Environment.SetEnvironmentVariable(key, value); + } + else + { + context.Log.Information(Verbosity.Diagnostic, "DotEnv: Unsetting environment variable \"{0}\"", key); + Environment.SetEnvironmentVariable(key, null); + } + } + } + } +} diff --git a/src/Cake.DotEnv.Module/Class1.cs b/src/Cake.DotEnv.Module/Class1.cs deleted file mode 100644 index e839ceb..0000000 --- a/src/Cake.DotEnv.Module/Class1.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System; - -namespace Cake.DotEnv.Module -{ - public class Class1 - { - } -} diff --git a/src/SolutionInfo.cs b/src/SolutionInfo.cs new file mode 100644 index 0000000..0ba7245 --- /dev/null +++ b/src/SolutionInfo.cs @@ -0,0 +1,13 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by Cake. +// +//------------------------------------------------------------------------------ +using System.Reflection; + +[assembly: AssemblyCompany("Cake Contributions")] +[assembly: AssemblyProduct("Cake.DotEnv")] +[assembly: AssemblyVersion("0.1.0")] +[assembly: AssemblyFileVersion("0.1.0")] +[assembly: AssemblyInformationalVersion("0.1.0")] +[assembly: AssemblyCopyright("Copyright © Cake Contributions 2017 - Present")] \ No newline at end of file