diff --git a/.deployment b/.deployment index 21227684f..2b834f52a 100644 --- a/.deployment +++ b/.deployment @@ -1,23 +1,34 @@ -; .deployment is actually an INI file and parsed by +; .deployment is actually an INI file and parsed by the following file ; https://raw.githubusercontent.com/projectkudu/kudu/master/Kudu.Core/Infrastructure/IniFile.cs ; Document of deployment with custom script ; https://github.com/projectkudu/kudu/wiki/Customizing-deployments#deploying-with-custom-script ; Document of configurable settings https://github.com/projectkudu/kudu/wiki/Configurable-settings -; Runtime settings cannot be overrided in .deployment e.g. WEBSITE_NODE_DEFAULT_VERSION +; Runtime settings cannot be overridden in .deployment e.g. WEBSITE_NODE_DEFAULT_VERSION ; More info https://github.com/projectkudu/kudu/wiki/Configurable-settings#runtime-settings -; Define default Node.js version in WEBSITE_NODE_DEFAULT_VERSION App Setting -; Find all Node.js versions from Kudu tool api/diagnostics/runtime +# Define default node version in WEBSITE_NODE_DEFAULT_VERSION APP Setting +# Find all Node.js versions from your AppService Kudu api/diagnostics/runtime +# More info https://codesanook-reactjs-server-side-rendering.scm.azurewebsites.net/api/diagnostics/runtime +; You can define a custom environment variable as +; CUSTOM_VARIABLE = my custom variable value +; and read in a deploy.ps1 script as +; $Env:CUSTOM_VARIABLE + +; https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_powershell_exe?view=powershell-5.1#examples [config] COMMAND = PowerShell -NoProfile -NoLogo -ExecutionPolicy Unrestricted -Command "& "$(Join-Path -Path $(Get-Location) -ChildPath deploy.ps1)" 2>&1 | Write-Output" + +; Set additional environment variables +; Timeout in seconds +; Set to one hour SCM_COMMAND_IDLE_TIMEOUT = 3600 -MSBUILD_PATH = D:\Program Files (x86)\MSBuild-15.9.21.664\MSBuild\MSBuild\15.0\Bin\MSBuild.exe -PROJECT_PATH = Orchard.proj +; Variables for MSBuild +MSBUILD_PATH = D:\Program Files (x86)\MSBuild-16.4\MSBuild\Current\Bin\MSBuild.exe SOLUTION_PATH = src/Orchard.sln -; You can define a custom environment variable as CUSTOM_VARIABLE = my custom variable value -; and use in a deploy.ps1 script as $Env:CUSTOM_VARIABLE. +; For Azure deployment, we use custom MS Build at root of the project. +PROJECT_PATH = Orchard.proj diff --git a/DeploymentUtility.psm1 b/DeploymentUtility.psm1 index 1cff59c4d..01dd06780 100644 --- a/DeploymentUtility.psm1 +++ b/DeploymentUtility.psm1 @@ -1,6 +1,22 @@ Set-StrictMode -Version Latest + +# Continue a build process even though there is a warning wrote to std err. +# We will check exit code in Invoke-ExternalCommand to design whether it fail or not $ErrorActionPreference = "Continue" +function Add-NpmToPathVariable { + $path = "$env:Appdata\npm" + $escapedPath = [Regex]::Escape($path) + + # Remove existing npm path safe to add npm path again + $paths = $env:Path -split ';' | Where-Object { + $_ -notmatch "^$escapedPath\\?$" + } + + # Update a path variable to this session + $env:Path = ($paths + $path) -join ";" # array + element item +} + function Invoke-ExternalCommand { param ( [Parameter(Mandatory = $true)] [scriptblock] $ScriptBlock @@ -8,11 +24,13 @@ function Invoke-ExternalCommand { # Displays an error message and continue executing if there is a standard error. # This is because there are some external command tools write warning message to standard error. - & $ScriptBlock 2>&1 + # Use Write-Output also fix "Window title cannot be longer than 1023 characters" issue + # https://github.com/projectkudu/kudu/issues/2635 + & $ScriptBlock 2>&1 | Write-Output # If last exit code is not 0, throw an exception to stop a script if ($LastExitCode) { - throw "Failed exitCode=$LastExitCode, command=$($ScriptBlock.ToString())" + throw "Failed with exit code = $LastExitCode and command = $($ScriptBlock.ToString())" } } @@ -29,5 +47,37 @@ function Write-EnviromentValue { "----------------- End of environment variables ---------------------------------" } +function Install-Yarn { + "Verify if yarn installed" + if (Get-Command -Name yarn -ErrorAction Ignore) { + "Updating yarn as a global tool to the latest version" + # https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/cmd#parameters + # issue https://github.com/projectkudu/kudu/issues/2635 + Invoke-ExternalCommand -ScriptBlock { npm update yarn -g } + } + else { + "Installing yarn as a global tool" + Invoke-ExternalCommand -ScriptBlock { npm install yarn -g } + Add-NpmToPathVariable + } +} + +function Install-KuduSync { + "Verify if kudusync installed" + if (Get-Command -Name kudusync -ErrorAction Ignore) { + "Updating kudusync as a global tool to the latest version" + # https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/cmd#parameters + # issue https://github.com/projectkudu/kudu/issues/2635 + Invoke-ExternalCommand -ScriptBlock { npm update kudusync -g } + } + else { + "Installing kudusync as a global tool" + Invoke-ExternalCommand -ScriptBlock { npm install kudusync -g } + Add-NpmToPathVariable + } +} + Export-ModuleMember -Function Invoke-ExternalCommand Export-ModuleMember -Function Write-EnviromentValue +Export-ModuleMember -Function Install-Yarn +Export-ModuleMember -Function Install-KuduSync diff --git a/deploy.ps1 b/deploy.ps1 index 24bc419e6..151861049 100644 --- a/deploy.ps1 +++ b/deploy.ps1 @@ -1,107 +1,119 @@ -#https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/set-strictmode?view=powershell-7 +# https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/set-strictmode?view=powershell-7 Set-StrictMode -Version Latest # https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_preference_variables?view=powershell-7#erroractionpreference -$ErrorActionPreference = "Stop" +$ErrorActionPreference = "Continue" # Just explicit set it -Import-Module -Name .\DeploymentUtility +Import-Module -Name ./DeploymentUtility -Force "Verify if Node.js installed" if (-not (Get-Command -Name node -ErrorAction Ignore)) { - throw "Missing node.js executable, please install node.js." + - "If already installed, make sure it can be reached from the current Environment." + throw ( + "Missing Node.js executable, please install Node.js." + + "If already installed, make sure it can be reached from the current environment." + ) } -# Setup -$ARTIFACTS = "$PSScriptRoot\..\artifacts" - +$ARTIFACTS = "$PSScriptRoot/../artifacts" +# Set deployment source folder if (-not $Env:DEPLOYMENT_SOURCE) { + 'Set $DEPLOYMENT_SOURCE variable from the current directory' $Env:DEPLOYMENT_SOURCE = $PSScriptRoot } if (-not $Env:DEPLOYMENT_TARGET) { - $Env:DEPLOYMENT_TARGET = "$ARTIFACTS\wwwroot" + 'Set $DEPLOYMENT_TARGET variable' + $Env:DEPLOYMENT_TARGET = "$ARTIFACTS/wwwroot" } if (-not $Env:NEXT_MANIFEST_PATH) { - $Env:NEXT_MANIFEST_PATH = "$ARTIFACTS\manifest" + 'Set $NEXT_MANIFEST_PATH variable' + $Env:NEXT_MANIFEST_PATH = "$ARTIFACTS/manifest" - if (-not $Env:PREVIOUS_MANIFEST_PATH) { - $Env:PREVIOUS_MANIFEST_PATH = "$ARTIFACTS\manifest" - } + if (-not $Env:PREVIOUS_MANIFEST_PATH) { + 'Set $PREVIOUS_MANIFEST_PATH variable' + $Env:PREVIOUS_MANIFEST_PATH = "$ARTIFACTS/manifest" + } } -if (-not $Env:KUDU_SYNC_CMD) { - "Installing Kudu Sync" - Invoke-ExternalCommand -ScriptBlock { & npm install kudusync -g --silent } - - # Locally just running "kuduSync" would also work - $Env:KUDU_SYNC_CMD = "$Env:AppData\npm\kuduSync.cmd" -} - -# Log Environment variables -$EnvironmentNameToWriteValue = @( +# Log environment variables +$environmentNameToWriteValue = @( "DEPLOYMENT_SOURCE" "DEPLOYMENT_TARGET" "NEXT_MANIFEST_PATH" "PREVIOUS_MANIFEST_PATH" - "KUDU_SYNC_CMD" "WEBSITE_NODE_DEFAULT_VERSION" + "WEBSITE_NPM_DEFAULT_VERSION" "SCM_REPOSITORY_PATH" - "Path" "SOLUTION_PATH" "PROJECT_PATH" "MSBUILD_PATH" + "Path" ) -Write-EnviromentValue -EnvironmentName $EnvironmentNameToWriteValue +Write-EnviromentValue -EnvironmentName $environmentNameToWriteValue -"Current node version: $(& node --version)" -"Current npm version: $(& npm --version)" -"Current MSBUILD version: $(& $Env:MSBUILD_PATH -version)" +################ Build Node.js project with yarn if there is yarn.lock file ################ +$nodeProjectsDir = Get-ChildItem -Path . -Recurse -Filter "yarn.lock" | + Select-Object -ExpandProperty DirectoryName -Unique | + Where-Object { $_ -NotMatch "node_modules" } -########################################################### -# Deployment -########################################################### +"Node projects directory:" +$nodeProjectsDir -"Handling .NET Web Application deployment." -"Restore NuGet packages" -"Current nuget version: $(nuget help | Select -First 1)" +Install-Yarn -Invoke-ExternalCommand -ScriptBlock { - & nuget restore "$Env:SOLUTION_PATH" -MSBuildPath "$(Split-Path -Path $Env:MSBUILD_PATH)" +$nodeProjectsDir | Foreach-Object { + $projectDir = $_ + Push-Location -Path $projectDir + + "Current Node project directory is $(Get-Location)" + "Installing npm packages with yarn" + Invoke-ExternalCommand -ScriptBlock { yarn install } + + "Building Node.js project with yarn" + Invoke-ExternalCommand -ScriptBlock { yarn build } + Pop-Location } +########################################################################################### + +# Build .NET project +"Restore NuGet packages" +# REF https://docs.microsoft.com/en-us/nuget/reference/cli-reference/cli-ref-restore#options +$msBuildDir = Split-Path -Path $Env:MSBUILD_PATH -Parent +Invoke-ExternalCommand -ScriptBlock { ./lib/nuget/nuget.exe restore "$Env:SOLUTION_PATH" -MSBuildPath "$msBuildDir" } + +"Build .NET project to the pre-compiled directory" +$preCompiledDir = "$Env:DEPLOYMENT_SOURCE/build/Precompiled" "Build .NET project to the temp directory" -$preCompiledDir = "$Env:DEPLOYMENT_SOURCE\build\Precompiled" - -"Building with MSBUILD to '$preCompiledDir'" +"Building the project with MSBuild to '$preCompiledDir'" Invoke-ExternalCommand -ScriptBlock { - # https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild-command-line-reference?view=vs-2019 - & "$Env:MSBUILD_PATH" ` - "$Env:PROJECT_PATH" ` - /t:Precompiled ` - /verbosity:minimal ` - /maxcpucount ` - /nologo ` - $Env:SCM_BUILD_ARGS - # Set SCM_BUILD_ARGS App Services Apps Settings to string you want to append to the msbuild command line. + cmd /c "$Env:MSBUILD_PATH" ` + "$Env:PROJECT_PATH" ` + /t:Precompiled ` + /p:PreCompiledDir=$preCompiledDir ` + /verbosity:minimal ` + /maxcpucount ` + /nologo ` + $Env:SCM_BUILD_ARGS + # Set SCM_BUILD_ARGS as App Service Configuration to any string you want to append to the MSBuild command line. } -"Kudu syncing" -Invoke-ExternalCommand -ScriptBlock { - & "$Env:KUDU_SYNC_CMD" ` - -v 50 ` - -f "$preCompiledDir" ` - -t "$Env:DEPLOYMENT_TARGET" ` - -n "$Env:NEXT_MANIFEST_PATH" ` - -p "$Env:PREVIOUS_MANIFEST_PATH" ` - -i ".git;.hg;.deployment;deploy.cmd;deploy.ps1;node_modules;" +Install-KuduSync + +"Syncing a build output to a deployment folder" +Invoke-ExternalCommand -ScriptBlock { + cmd /c kudusync ` + -f "$preCompiledDir" ` + -t "$Env:DEPLOYMENT_TARGET" ` + -n "$Env:NEXT_MANIFEST_PATH" ` + -p "$Env:PREVIOUS_MANIFEST_PATH" ` + -i ".git;.hg;.deployment;deploy.cmd;deploy.ps1;node_modules;" } if ($Env:POST_DEPLOYMENT_ACTION) { "Post deployment stub" - Invoke-ExternalCommand -ScriptBlock { & $Env:POST_DEPLOYMENT_ACTION } + Invoke-ExternalCommand -ScriptBlock { $Env:POST_DEPLOYMENT_ACTION } } "Deployment successfully" - diff --git a/lib/nuget/nuget.exe b/lib/nuget/nuget.exe index 9f8781de0..8f393dd3c 100644 Binary files a/lib/nuget/nuget.exe and b/lib/nuget/nuget.exe differ