-
Notifications
You must be signed in to change notification settings - Fork 0
/
build.fsx
187 lines (156 loc) · 6.59 KB
/
build.fsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#r "paket: groupref build //"
#load "./.fake/build.fsx/intellisense.fsx"
#if !FAKE
#r "netstandard"
#r "Facades/netstandard" // https://github.com/ionide/ionide-vscode-fsharp/issues/839#issuecomment-396296095
#endif
open System
open Fake.Core
open Fake.DotNet
open Fake.IO
#load @"paket-files/build/CompositionalIT/fshelpers/src/FsHelpers/ArmHelper/ArmHelper.fs"
open Cit.Helpers.Arm
open Cit.Helpers.Arm.Parameters
open Microsoft.Azure.Management.ResourceManager.Fluent.Core
let serverPath = Path.getFullName "./src/Server"
let clientPath = Path.getFullName "./src/Client"
let deployDir = Path.getFullName "./deploy"
let platformTool tool winTool =
let tool = if Environment.isUnix then tool else winTool
match Process.tryFindFileOnPath tool with
| Some t -> t
| _ ->
let errorMsg =
tool + " was not found in path. " +
"Please install it and make sure it's available from your path. " +
"See https://safe-stack.github.io/docs/quickstart/#install-pre-requisites for more info"
failwith errorMsg
let nodeTool = platformTool "node" "node.exe"
let npmTool = platformTool "npm" "npm.cmd"
let runTool cmd args workingDir =
let result =
Process.execSimple (fun info ->
{ info with
FileName = cmd
WorkingDirectory = workingDir
Arguments = args })
TimeSpan.MaxValue
if result <> 0 then failwithf "'%s %s' failed" cmd args
let runDotNet cmd workingDir =
let result =
DotNet.exec (DotNet.Options.withWorkingDirectory workingDir) cmd ""
if result.ExitCode <> 0 then failwithf "'dotnet %s' failed in %s" cmd workingDir
let openBrowser url =
let result =
//https://github.com/dotnet/corefx/issues/10361
Process.execSimple (fun info ->
{ info with
FileName = url
UseShellExecute = true })
TimeSpan.MaxValue
if result <> 0 then failwithf "opening browser failed"
Target.create "Clean" (fun _ ->
Shell.cleanDirs [deployDir]
)
Target.create "InstallClient" (fun _ ->
printfn "Node version:"
runTool nodeTool "--version" __SOURCE_DIRECTORY__
printfn "Npm version:"
runTool npmTool "--version" __SOURCE_DIRECTORY__
runTool npmTool "install" __SOURCE_DIRECTORY__
runDotNet "restore" clientPath
)
Target.create "RestoreServer" (fun _ ->
runDotNet "restore" serverPath
)
Target.create "Build" (fun _ ->
runDotNet "build" serverPath
runDotNet "fable webpack-cli -- --config src/Client/webpack.config.js -p" clientPath
)
Target.create "Run" (fun _ ->
let server = async {
runDotNet "watch run" serverPath
}
let client = async {
runDotNet "fable webpack-dev-server -- --config src/Client/webpack.config.js" clientPath
}
let browser = async {
do! Async.Sleep 5000
openBrowser "http://localhost:8080"
}
[ server; client; browser ]
|> Async.Parallel
|> Async.RunSynchronously
|> ignore
)
Target.create "Bundle" (fun _ ->
runDotNet (sprintf "publish \"%s\" -c release -o \"%s\"" serverPath deployDir) __SOURCE_DIRECTORY__
Shell.copyDir (Path.combine deployDir "public") (Path.combine clientPath "public") FileFilter.allFiles
)
type ArmOutput =
{ WebAppName : ParameterValue<string>
WebAppPassword : ParameterValue<string> }
let mutable deploymentOutputs : ArmOutput option = None
Target.create "ArmTemplate" (fun _ ->
let environment = Environment.environVarOrDefault "environment" (Guid.NewGuid().ToString().ToLower().Split '-' |> Array.head)
let armTemplate = @"arm-template.json"
let resourceGroupName = "safe-" + environment
let authCtx =
// You can safely replace these with your own subscription and client IDs hard-coded into this script.
let subscriptionId = try Environment.environVar "subscriptionId" |> Guid.Parse with _ -> failwith "Invalid Subscription ID. This should be your Azure Subscription ID."
let clientId = try Environment.environVar "clientId" |> Guid.Parse with _ -> failwith "Invalid Client ID. This should be the Client ID of a Native application registered in Azure with permission to create resources in your subscription."
Trace.tracefn "Deploying template '%s' to resource group '%s' in subscription '%O'..." armTemplate resourceGroupName subscriptionId
subscriptionId
|> authenticateDevice Trace.trace { ClientId = clientId; TenantId = None }
|> Async.RunSynchronously
let deployment =
let location = Environment.environVarOrDefault "location" Region.EuropeWest.Name
let pricingTier = Environment.environVarOrDefault "pricingTier" "F1"
{ DeploymentName = "SAFE-template-deploy"
ResourceGroup = New(resourceGroupName, Region.Create location)
ArmTemplate = IO.File.ReadAllText armTemplate
Parameters =
Simple
[ "environment", ArmString environment
"location", ArmString location
"pricingTier", ArmString pricingTier ]
DeploymentMode = Incremental }
deployment
|> deployWithProgress authCtx
|> Seq.iter(function
| DeploymentInProgress (state, operations) -> Trace.tracefn "State is %s, completed %d operations." state operations
| DeploymentError (statusCode, message) -> Trace.traceError <| sprintf "DEPLOYMENT ERROR: %s - '%s'" statusCode message
| DeploymentCompleted d -> deploymentOutputs <- d)
)
open Fake.IO.Globbing.Operators
open System.Net
// https://github.com/SAFE-Stack/SAFE-template/issues/120
// https://stackoverflow.com/a/6994391/3232646
type TimeoutWebClient() =
inherit WebClient()
override this.GetWebRequest uri =
let request = base.GetWebRequest uri
request.Timeout <- 30 * 60 * 1000
request
Target.create "AppService" (fun _ ->
let zipFile = "deploy.zip"
IO.File.Delete zipFile
Zip.zip deployDir zipFile !!(deployDir + @"\**\**")
let appName = deploymentOutputs.Value.WebAppName.value
let appPassword = deploymentOutputs.Value.WebAppPassword.value
let destinationUri = sprintf "https://%s.scm.azurewebsites.net/api/zipdeploy" appName
let client = new TimeoutWebClient(Credentials = NetworkCredential("$" + appName, appPassword))
Trace.tracefn "Uploading %s to %s" zipFile destinationUri
client.UploadData(destinationUri, IO.File.ReadAllBytes zipFile) |> ignore)
open Fake.Core.TargetOperators
"Clean"
==> "InstallClient"
==> "Build"
==> "Bundle"
==> "ArmTemplate"
==> "AppService"
"Clean"
==> "InstallClient"
==> "RestoreServer"
==> "Run"
Target.runOrDefault "Build"