Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Porting SSH module to FAKE 5 #2652

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions Fake.sln
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Fake.DotNet.Xamarin", "src\
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Fake.Net.Http", "src\app\Fake.Net.Http\Fake.Net.Http.fsproj", "{D24CEE35-B6C0-4C92-AE18-E80F90B69974}"
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Fake.Net.SSH", "src\app\Fake.Net.SSH\Fake.Net.SSH.fsproj", "{5B2A7546-A441-45C9-8176-2872E2A30477}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{CCAC5CAB-03C8-4C11-ADBE-A0D05F6A4F18}"
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Fake.Core.UnitTests", "src\test\Fake.Core.UnitTests\Fake.Core.UnitTests.fsproj", "{31A5759B-B562-43C0-A845-14EFA4091543}"
Expand Down Expand Up @@ -633,6 +635,18 @@ Global
{D24CEE35-B6C0-4C92-AE18-E80F90B69974}.Release|x64.Build.0 = Release|Any CPU
{D24CEE35-B6C0-4C92-AE18-E80F90B69974}.Release|x86.ActiveCfg = Release|Any CPU
{D24CEE35-B6C0-4C92-AE18-E80F90B69974}.Release|x86.Build.0 = Release|Any CPU
{5B2A7546-A441-45C9-8176-2872E2A30477}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5B2A7546-A441-45C9-8176-2872E2A30477}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5B2A7546-A441-45C9-8176-2872E2A30477}.Debug|x64.ActiveCfg = Debug|Any CPU
{5B2A7546-A441-45C9-8176-2872E2A30477}.Debug|x64.Build.0 = Debug|Any CPU
{5B2A7546-A441-45C9-8176-2872E2A30477}.Debug|x86.ActiveCfg = Debug|Any CPU
{5B2A7546-A441-45C9-8176-2872E2A30477}.Debug|x86.Build.0 = Debug|Any CPU
{5B2A7546-A441-45C9-8176-2872E2A30477}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5B2A7546-A441-45C9-8176-2872E2A30477}.Release|Any CPU.Build.0 = Release|Any CPU
{5B2A7546-A441-45C9-8176-2872E2A30477}.Release|x64.ActiveCfg = Release|Any CPU
{5B2A7546-A441-45C9-8176-2872E2A30477}.Release|x64.Build.0 = Release|Any CPU
{5B2A7546-A441-45C9-8176-2872E2A30477}.Release|x86.ActiveCfg = Release|Any CPU
{5B2A7546-A441-45C9-8176-2872E2A30477}.Release|x86.Build.0 = Release|Any CPU
{31A5759B-B562-43C0-A845-14EFA4091543}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{31A5759B-B562-43C0-A845-14EFA4091543}.Debug|Any CPU.Build.0 = Debug|Any CPU
{31A5759B-B562-43C0-A845-14EFA4091543}.Debug|x64.ActiveCfg = Debug|Any CPU
Expand Down Expand Up @@ -1261,6 +1275,7 @@ Global
{4BCE4F9C-8FC2-4207-81F1-20CB07D852DC} = {7BFFAE76-DEE9-417A-A79B-6A6644C4553A}
{13C1F95D-2FAD-4890-BF94-0AE7CF9AB2FC} = {7BFFAE76-DEE9-417A-A79B-6A6644C4553A}
{D24CEE35-B6C0-4C92-AE18-E80F90B69974} = {7BFFAE76-DEE9-417A-A79B-6A6644C4553A}
{5B2A7546-A441-45C9-8176-2872E2A30477} = {7BFFAE76-DEE9-417A-A79B-6A6644C4553A}
{31A5759B-B562-43C0-A845-14EFA4091543} = {CCAC5CAB-03C8-4C11-ADBE-A0D05F6A4F18}
{D8850C67-0542-427A-ABCB-92174EA42C95} = {7BFFAE76-DEE9-417A-A79B-6A6644C4553A}
{8D72BED1-BC02-4B23-A631-4849BD0FD3E1} = {7BFFAE76-DEE9-417A-A79B-6A6644C4553A}
Expand Down
1 change: 1 addition & 0 deletions build.fsx
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,7 @@ let dotnetAssemblyInfos =
"Fake.JavaScript.Yarn", "Running Yarn commands"
"Fake.JavaScript.TypeScript", "Running TypeScript compiler"
"Fake.Net.Http", "HTTP Client"
"Fake.Net.SSH", "SSH operations"
"Fake.netcore", "Command line tool"
"Fake.Runtime", "Core runtime features"
"Fake.Sql.DacPac", "Sql Server Data Tools DacPac operations (Obsolete: Use Fake.Sql.SqlPackage instead)"
Expand Down
1 change: 1 addition & 0 deletions help/templates/template.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@
<a href="/apidocs/v5/index.html#Fake.Net" class="navbar-link">Net</a>
<div class="navbar-dropdown" class="navbar-item">
<a href="/net-http.html" class="navbar-item">Http</a>
<a href="/apidocs/v5/fake-net-ssh.html" class="navbar-item">SSH</a>
</div>
</div>
<div class="navbar-item has-dropdown is-hoverable">
Expand Down
19 changes: 19 additions & 0 deletions src/app/Fake.Net.SSH/AssemblyInfo.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Auto-Generated by FAKE; do not edit
namespace System
open System.Reflection

[<assembly: AssemblyTitleAttribute("FAKE - F# Make SSH operations")>]
[<assembly: AssemblyProductAttribute("FAKE - F# Make")>]
[<assembly: AssemblyVersionAttribute("5.21.1")>]
[<assembly: AssemblyInformationalVersionAttribute("5.21.1")>]
[<assembly: AssemblyFileVersionAttribute("5.21.1")>]
[<assembly: AssemblyMetadataAttribute("BuildDate","2022-01-31")>]
do ()

module internal AssemblyVersionInformation =
let [<Literal>] AssemblyTitle = "FAKE - F# Make SSH operations"
let [<Literal>] AssemblyProduct = "FAKE - F# Make"
let [<Literal>] AssemblyVersion = "5.21.1"
let [<Literal>] AssemblyInformationalVersion = "5.21.1"
let [<Literal>] AssemblyFileVersion = "5.21.1"
let [<Literal>] AssemblyMetadata_BuildDate = "2022-01-31"
23 changes: 23 additions & 0 deletions src/app/Fake.Net.SSH/Fake.Net.SSH.fsproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net472</TargetFrameworks>
<AssemblyName>Fake.Net.SSH</AssemblyName>
<OutputType>Library</OutputType>
</PropertyGroup>
<PropertyGroup>
<DefineConstants>$(DefineConstants)</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DefineConstants>$(DefineConstants);RELEASE</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Compile Include="AssemblyInfo.fs" />
<Compile Include="SSH.fs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Fake.Core.Environment\Fake.Core.Environment.fsproj" />
<ProjectReference Include="..\Fake.Core.Process\Fake.Core.Process.fsproj" />
<ProjectReference Include="..\Fake.Core.Trace\Fake.Core.Trace.fsproj" />
</ItemGroup>
<Import Project="..\..\..\.paket\Paket.Restore.targets" />
</Project>
63 changes: 63 additions & 0 deletions src/app/Fake.Net.SSH/SSH.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
namespace Fake.Net

open System
open Fake.Core

[<RequireQualifiedAccess>]
/// Contains a task which allows to perform SSH operations
module SSH =

/// The SSH parameter type.
type SSHParams =
{ /// Path of the scp.exe
ToolPath : string
/// Path of the private key file (optional)
PrivateKeyPath : string
/// remote User
RemoteUser : string
RemoteHost : string
RemotePort : string
}

/// The SSH default parameters
let SSHDefaults : SSHParams =
{ ToolPath = if Environment.isMono then "ssh" else "ssh.exe"
RemoteUser = "fake"
RemoteHost = "localhost"
RemotePort = "22"
PrivateKeyPath = null
}

let private getTarget sshParams =
match sshParams.RemotePort with
| "22" -> $"%s{sshParams.RemoteUser}@%s{sshParams.RemoteHost}"
| _ -> $"%s{sshParams.RemoteUser}@%s{sshParams.RemoteHost}:%s{sshParams.RemotePort}"

let private getPrivateKey privateKeyPath =
if String.IsNullOrEmpty privateKeyPath then "" else $"-i \"%s{privateKeyPath}\""

let buildArguments sshParams command =
let target = sshParams |> getTarget
let privateKey = sshParams.PrivateKeyPath |> getPrivateKey
$"%s{privateKey} %s{target} %s{Args.toWindowsCommandLine [command]}" |> String.trim

/// Performs a command via SSH.
/// ## Parameters
///
/// - `setParams` - Function used to manipulate the default SSHParams value.
/// - `command` - The target path. Can be something like user@host:directory/TargetFile or a local path.
///
/// ## Sample
///
/// SSH (fun p -> { p with ToolPath = "tools/ssh.exe" }) command
let SSH setParams command =
let (sshParams : SSHParams) = setParams SSHDefaults
let target = sshParams |> getTarget
let args = buildArguments sshParams command

Trace.tracefn $"%s{sshParams.ToolPath} %s{args}"

let result = CreateProcess.fromRawCommandLine sshParams.ToolPath args
|> CreateProcess.withTimeout(TimeSpan.MaxValue)
|> Proc.run
if result.ExitCode <> 0 then failwithf $"Error during SSH. Target: %s{target} Command: %s{command}"
4 changes: 4 additions & 0 deletions src/app/Fake.Net.SSH/paket.references
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
group netcore

FSharp.Core
NETStandard.Library
3 changes: 3 additions & 0 deletions src/legacy/FakeLib/FakeLib.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,9 @@
<Compile Include="..\..\app\Fake.Net.Http\Http.fs">
<Link>Fake.Net.Http/Http.fs</Link>
</Compile>
<Compile Include="..\..\app\Fake.Net.SSH\SSH.fs">
<Link>Fake.Net.SSH/SSH.fs</Link>
</Compile>
<Compile Include="..\..\app\Fake.Core.Xml\Xml.fs">
<Link>Fake.Core.Xml/Xml.fs</Link>
</Compile>
Expand Down
8 changes: 4 additions & 4 deletions src/legacy/FakeLib/SSHHelper.fs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
[<AutoOpen>]
[<System.Obsolete("This API is obsolete. There is no alternative in FAKE 5 yet. You can help by porting this module.")>]
[<System.Obsolete("Use the Fake.Net.SSH module instead.")>]
/// Conatins a task which allows to perform SSH operations
module Fake.SSHHelper

/// The SSH parameter type.
[<CLIMutable>]
[<System.Obsolete("This API is obsolete. There is no alternative in FAKE 5 yet. You can help by porting this module.")>]
[<System.Obsolete("Use the Fake.Net.SSH module instead.")>]
type SSHParams =
{ /// Path of the scp.exe
ToolPath : string
Expand All @@ -19,7 +19,7 @@ type SSHParams =


/// The SSH default parameters
[<System.Obsolete("This API is obsolete. There is no alternative in FAKE 5 yet. You can help by porting this module.")>]
[<System.Obsolete("Use the Fake.Net.SSH module instead.")>]
let SSHDefaults : SSHParams =
{ ToolPath = if isMono then "ssh" else "ssh.exe"
RemoteUser = "fake"
Expand All @@ -37,7 +37,7 @@ let SSHDefaults : SSHParams =
/// ## Sample
///
/// SSH (fun p -> { p with ToolPath = "tools/ssh.exe" }) command
[<System.Obsolete("This API is obsolete. There is no alternative in FAKE 5 yet. You can help by porting this module.")>]
[<System.Obsolete("Use the Fake.Net.SSH module instead.")>]
let SSH setParams command =
let (p : SSHParams) = setParams SSHDefaults
let target =
Expand Down
2 changes: 2 additions & 0 deletions src/test/Fake.Core.UnitTests/Fake.Core.UnitTests.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<ProjectReference Include="..\..\app\Fake.DotNet.Testing.VSTest\Fake.DotNet.Testing.VSTest.fsproj" />
<ProjectReference Include="..\..\app\Fake.IO.Zip\Fake.IO.Zip.fsproj" />
<ProjectReference Include="..\..\app\Fake.IO.FileSystem\Fake.IO.FileSystem.fsproj" />
<ProjectReference Include="..\..\app\Fake.Net.SSH\Fake.Net.SSH.fsproj" />
<ProjectReference Include="..\..\app\Fake.Testing.Fixie\Fake.Testing.Fixie.fsproj" />
<ProjectReference Include="..\..\app\Fake.Tools.GitVersion\Fake.Tools.GitVersion.fsproj" />
<ProjectReference Include="..\..\app\Fake.Tools.Git\Fake.Tools.Git.fsproj" />
Expand Down Expand Up @@ -76,6 +77,7 @@
<Compile Include="Fake.Core.Context.fs" />
<Compile Include="Fake.Core.FakeVar.fs" />
<Compile Include="Fake.Runtime.fs" />
<Compile Include="Fake.Net.SSH.fs" />
<Compile Include="Fake.Tools.GitVersion.fs" />
<Compile Include="Fake.Tools.Octo.fs" />
<Compile Include="Fake.Sql.SqlPackage.fs" />
Expand Down
44 changes: 44 additions & 0 deletions src/test/Fake.Core.UnitTests/Fake.Net.SSH.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
module Fake.Net.SSHTests

open Expecto
open Fake.Net

[<Tests>]
let tests =
testList "Fake.Net.SSH.Tests" [
testCase "Test all arguments are mapped correctly" <| fun _ ->
let args: SSH.SSHParams =
{ ToolPath = "ssh"
RemoteUser = "fake-user"
RemoteHost = "localhost"
RemotePort = "22"
PrivateKeyPath = "private-key-path" }
let sshCommand = "pwd"
let cmd = SSH.buildArguments args sshCommand

Expect.equal cmd "-i \"private-key-path\" fake-user@localhost pwd" "expected proper arguments formatting"

testCase "Test ssh target is mapped correctly when a custom port is used" <| fun _ ->
let args: SSH.SSHParams =
{ ToolPath = "ssh"
RemoteUser = "fake-user"
RemoteHost = "localhost"
RemotePort = "2222"
PrivateKeyPath = null }
let sshCommand = "pwd"
let cmd = SSH.buildArguments args sshCommand

Expect.equal cmd "fake-user@localhost:2222 pwd" "expected proper arguments formatting"

testCase "Test PrivateKeyPath is mapped correctly when it's empty" <| fun _ ->
let args: SSH.SSHParams =
{ ToolPath = "ssh"
RemoteUser = "fake-user"
RemoteHost = "localhost"
RemotePort = "22"
PrivateKeyPath = null }
let sshCommand = "pwd"
let cmd = SSH.buildArguments args sshCommand

Expect.equal cmd "fake-user@localhost pwd" "expected proper arguments formatting"
]