diff --git a/src/app/Fake.Deploy.Lib/Fake.Deploy.Lib.fsproj b/src/app/Fake.Deploy.Lib/Fake.Deploy.Lib.fsproj
index 83e4d366192..90917ea7460 100644
--- a/src/app/Fake.Deploy.Lib/Fake.Deploy.Lib.fsproj
+++ b/src/app/Fake.Deploy.Lib/Fake.Deploy.Lib.fsproj
@@ -49,6 +49,7 @@
+
diff --git a/src/app/Fake.Deploy.Lib/FakeDeployAgentHelper.fs b/src/app/Fake.Deploy.Lib/FakeDeployAgentHelper.fs
index d889b04a989..f1aa042d9c9 100644
--- a/src/app/Fake.Deploy.Lib/FakeDeployAgentHelper.fs
+++ b/src/app/Fake.Deploy.Lib/FakeDeployAgentHelper.fs
@@ -93,7 +93,7 @@ let uploadData (action: Action) (url: Url) (body: byte[]) =
let uploadFile (action: Action) (url: Url) (file: FilePath) (args: string[]) =
let req = webRequest url action
- req.Headers.Add(scriptArgumentsHeaderName, String.Join (";", args))
+ req.Headers.Add(scriptArgumentsHeaderName, args |> toHeaderValue)
req.AllowWriteStreamBuffering <- false
use fileStream = File.OpenRead file
req.ContentLength <- fileStream.Length
diff --git a/src/app/Fake.Deploy.Lib/HttpHeaderHelper.fs b/src/app/Fake.Deploy.Lib/HttpHeaderHelper.fs
new file mode 100644
index 00000000000..6fb10280934
--- /dev/null
+++ b/src/app/Fake.Deploy.Lib/HttpHeaderHelper.fs
@@ -0,0 +1,34 @@
+[]
+module Fake.HttpHeaderHelper
+open System
+open System.Text.RegularExpressions
+
+let toHeaderValue (values:string []) : string =
+ values
+ |> Array.map (fun x ->
+ x.Replace("\"", "%22")
+ |> sprintf "\"%s\""
+ )
+ |> fun strs -> System.String.Join(",", strs
+ )
+
+let private regex = Regex("(\"[^\"]*\")(?:,(\"[^\"]*\"))*", RegexOptions.Compiled)
+let fromHeaderValue (value:string) : string [] =
+ let matches = regex.Matches(value)
+ //back compat: existing agents not expecting quoted params will continue to function.
+ if matches.Count = 0 then [|value|]
+ else
+ matches |> Seq.cast
+ |> Seq.collect (fun (m:Match) -> m.Groups |> Seq.cast)
+ |> Seq.skip 1
+ |> Seq.collect (fun (g:Group) ->
+ g.Captures |> Seq.cast |> Seq.map (fun (c:Capture) -> c.Value)
+ |> Seq.map (fun (x:string) ->
+ x.Substring(1, x.Length - 2)
+ |> fun y -> y.Replace("%22", "\"")
+ )
+ )
+ |> Array.ofSeq
+
+
+
\ No newline at end of file
diff --git a/src/app/Fake.Deploy/DeploymentAgent.fs b/src/app/Fake.Deploy/DeploymentAgent.fs
index 725836960ee..549afac0baf 100644
--- a/src/app/Fake.Deploy/DeploymentAgent.fs
+++ b/src/app/Fake.Deploy/DeploymentAgent.fs
@@ -19,9 +19,10 @@ let getBodyFromNancyRequest (ctx : Nancy.Request) =
let getScriptArgumentsFromNancyRequest (ctx : Nancy.Request) =
ctx.Headers
- |> Seq.choose (fun pair -> if pair.Key = FakeDeployAgentHelper.scriptArgumentsHeaderName then Some pair.Value else None)
- |> Seq.concat
- |> Seq.toArray
+ |> Seq.choose (fun pair -> if pair.Key = FakeDeployAgentHelper.scriptArgumentsHeaderName then Some <| pair.Value else None)
+ |> Seq.head
+ |> Seq.head
+ |> fromHeaderValue
let runDeployment workDir (ctx : Nancy.Request) =
let packageBytes = getBodyFromNancyRequest ctx
diff --git a/src/deploy.web/Fake.Deploy.Web/Modules/Api.Agent.fs b/src/deploy.web/Fake.Deploy.Web/Modules/Api.Agent.fs
index 3814a039e67..060483e8600 100644
--- a/src/deploy.web/Fake.Deploy.Web/Modules/Api.Agent.fs
+++ b/src/deploy.web/Fake.Deploy.Web/Modules/Api.Agent.fs
@@ -16,7 +16,7 @@ open Fake.Deploy.Web.Module.NancyOp
type AgentResponse<'t> =
{ case : string
- values : 't [] }
+ fields : 't [] }
type ApiAgent(dataProvider : IDataProvider, agentProxy : AgentProxy) as http =
inherit FakeModule("/api/v1/agent")
diff --git a/src/deploy.web/Fake.Deploy.Web/Modules/Api.Package.fs b/src/deploy.web/Fake.Deploy.Web/Modules/Api.Package.fs
index 2f3a710fdc6..319c96b9b91 100644
--- a/src/deploy.web/Fake.Deploy.Web/Modules/Api.Package.fs
+++ b/src/deploy.web/Fake.Deploy.Web/Modules/Api.Package.fs
@@ -22,17 +22,6 @@ type ApiPackage (dataProvider : IDataProvider) as http =
let packageTemp = Path.Combine(appdata.FullName, "Package_Temp")
- let deploy packageFileName agent =
- let toStr (msgs:seq) =
- msgs |> Seq.map(fun msg -> sprintf "%s: %s" (msg.Timestamp.ToString("yyyy-MM-dd HH:mm:ss")) msg.Message )
-
- let url = Uri(agent.Address, "/fake/")
- let response = postDeploymentPackage url.AbsoluteUri packageFileName [||]
- match response with
- | Failure x -> { Agent = agent.Name; Messages = toStr x.Messages; Success = not <| x.IsError; Error = x.Exception.ToString() }
- | Success x -> { Agent = agent.Name; Messages = toStr x.Messages; Success = not <| x.IsError; Error = "" }
- | _ -> { Agent = agent.Name; Messages = []; Success = false; Error = "Unexpected response from agent" }
-
do
http.post "/rollback" (fun p ->
let body = http.Bind()
@@ -58,6 +47,12 @@ type ApiPackage (dataProvider : IDataProvider) as http =
let agentId = http.Request.Form ?> "agentId"
let agent = dataProvider.GetAgents [agentId] |> Seq.head
let url = agent.Address.AbsoluteUri + "fake/"
+ let env =
+ [agent.EnvironmentId]
+ |>dataProvider.GetEnvironments
+ |> Seq.head
+ |> fun x -> x.Name
+ |> sprintf "env=%s"
Directory.CreateDirectory(packageTemp) |> ignore
let files =
http.Request.Files
@@ -69,9 +64,9 @@ type ApiPackage (dataProvider : IDataProvider) as http =
let code, message =
files
|> Seq.map(fun file ->
- match postDeploymentPackage url file [||] with
+ match postDeploymentPackage url file [|env|] with
| Failure(err) ->
- file, Some err, HttpStatusCode.InternalServerError, None
+ file, Some err, HttpStatusCode.InternalServerError, Some(err)
| Success a ->
if File.Exists(file) then File.Delete(file)
file, None, HttpStatusCode.Created, Some a
diff --git a/src/deploy.web/Fake.Deploy.Web/Scripts/app/Home.Agent.js b/src/deploy.web/Fake.Deploy.Web/Scripts/app/Home.Agent.js
index daf1cd2cd2e..58f1236c20c 100644
--- a/src/deploy.web/Fake.Deploy.Web/Scripts/app/Home.Agent.js
+++ b/src/deploy.web/Fake.Deploy.Web/Scripts/app/Home.Agent.js
@@ -21,6 +21,18 @@ function AgentViewModel() {
self.recentMessages = ko.observableArray();
+ self.updateMessagesFrom = function(data) {
+ self.recentMessages([]);
+ if (data != null) {
+ var response = data.xhr().response;
+ var messages = [];
+ if (response) messages = $.parseJSON(response);
+ $.each(messages, function (i, msg) {
+ self.recentMessages.push(msg);
+ });
+ }
+ };
+
self.getAgentDetails = function () {
$.ajax({
type: 'GET',
@@ -46,7 +58,8 @@ function AgentViewModel() {
contentType: 'application/json'
}).done(function (data) {
self.deployments([]);
- $.each(data.values, function (i, d) {
+
+ $.each(data.fields || [], function (i, d) {
$.each(d, function (i2, dep) {
var deployment = ko.mapping.fromJS(dep);
self.deployments.push(deployment);
@@ -97,13 +110,7 @@ function AgentViewModel() {
$('#filePlaceHolder').modal('hide');
$('#selectPackageBtn').removeClass('hide');
toastr.info('Package deployed');
- self.recentMessages([]);
- if (data != null && data.result !== undefined) {
- $.each(data.result, function (i, msg) {
- self.recentMessages.push(msg);
- });
- }
-
+ self.updateMessagesFrom(data);
self.refreshDeploymentsForAgent();
},
fail: function (e, data) {
@@ -111,12 +118,7 @@ function AgentViewModel() {
$('#selectPackageBtn').removeClass('hide');
$('#filePlaceHolder').modal('hide');
toastr.error('Package deployment failed');
- self.recentMessages([]);
- if (data != null && data.result !== undefined) {
- $.each(data.result, function (i, msg) {
- self.recentMessages.push(msg);
- });
- }
+ self.updateMessagesFrom(data);
}
});
diff --git a/src/test/Test.Fake.Deploy/Http/HttpHeaderParsingSpecs.cs b/src/test/Test.Fake.Deploy/Http/HttpHeaderParsingSpecs.cs
new file mode 100644
index 00000000000..0d239e72663
--- /dev/null
+++ b/src/test/Test.Fake.Deploy/Http/HttpHeaderParsingSpecs.cs
@@ -0,0 +1,44 @@
+using Fake;
+using Machine.Specifications;
+
+namespace Test.Fake.Deploy.Http
+{
+ public class when_parsing_values_without_commas
+ {
+ private static string[] _results;
+
+ private Because of = () => _results = HttpHeaderHelper.fromHeaderValue("\"param%22one\",\"second\"");
+
+ private It should_parse_params_with_quotes = () =>
+ _results[0].ShouldEqual("param\"one");
+ private It should_parse_params_without_quotes = () =>
+ _results[1].ShouldEqual("second");
+ }
+
+
+ public class when_parsing_values_with_commas
+ {
+ private static string[] _results;
+
+ private Because of = () => _results = HttpHeaderHelper.fromHeaderValue("\"param,%22one\",\"second\",\"another, %22 parameter\"");
+
+ private It should_parse_params_with_comma_and_quotes = () =>
+ _results[0].ShouldEqual("param,\"one");
+ private It should_parse_params_without_quotes = () =>
+ _results[1].ShouldEqual("second");
+ private It should_parse_third_param = () =>
+ _results[2].ShouldEqual("another, \" parameter");
+ }
+
+ public class when_parsing_unquoted_params
+ {
+ private static string[] _results;
+
+ private Because of = () => _results = HttpHeaderHelper.fromHeaderValue("simple command");
+
+ private It should_parse_exact_value = () =>
+ _results[0].ShouldEqual("simple command");
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/test/Test.Fake.Deploy/Test.Fake.Deploy.csproj b/src/test/Test.Fake.Deploy/Test.Fake.Deploy.csproj
index 660e99520df..86728dc3270 100644
--- a/src/test/Test.Fake.Deploy/Test.Fake.Deploy.csproj
+++ b/src/test/Test.Fake.Deploy/Test.Fake.Deploy.csproj
@@ -62,6 +62,7 @@
Extensions.cs
+