How to deploy to multiple environments with webpack using msdeploy - deployment

I've got a .NET WebAPI solution, and a UI built in Angular2 RC4 (angular-cli webpack version). I'm confused about how to deploy these to different environments, especially configuration parameters - there seems to be a mismatch between the .NET way and the UI way of doing things, which I don't quite get.
Here's how I've got it currently in TeamCity. The WebAPI solution is built once only, and is configured at deploy time. The various configuration parameters the project needs (such as connection strings, endpoints etc.) are stored in web.config. When I deploy to my test environment using MSDeploy, I pass in setParam arguments to the MSDeploy command line which replaces the connection strings and endpoints in the web.config with those values. When I deploy to production, I use the same build but pass in different arguments to the setParam in the command line.
This approach makes sense to me because I know that the exact same build is going from one environment to the next, the only difference being the parameters I specifically told it to set for each environment. Super.
With Angular2 and webpack it looks like a different approach is needed. When I build my project (with ng build -prod) it minimizes and bundles my HTML and Javascript files into 3 or 4 files, along with gzipped versions of those files. This is great for reducing file size and increasing speed of my website, but there is no way to "inject" configuration parameters into these gzip files like there is with MSDeploy's setParam. Everywhere I've seen that mentions webpack is showing webpack.dev.config.js and webpack.prod.config.js. But doesn't that mean we need to build a different bundle for each environment? And actually with Angular2 the webpack bit is considered "a black box" and it's not possible to supply your own webpack.config file anyway.
The only workaround I can think of is to use TeamCity's "File Content Replacer" on the "main.1234abcd6946c6a08519.bundle.js" to replace my configuration parameters with the values for that environment, then gzip that file - overwriting the one created by webpack.
But this is horrible, so I'm looking for any better suggestions?

I don't have any experience with webpack or if this is better than your workaround but you can use the TextFile kind of setParam entry to alter any file in your project using Regex find/replace at deploy time.
https://technet.microsoft.com/en-us/library/dd569084(v=ws.10).aspx

I went with creating a separate package for each environment. I added a build step that replaces my API URL on localhost in src\app\environment.ts, with the appropriate URL for that environment, then it runs npm build -prod and then MSDeploy to create the package. I do this for all environments I want to target.
Here's the script:
REM =====CREATE TEST PACKAGE==================================================
REM backup the environment file
ren src\app\environment.ts environment.ts.bak
copy /Y src\app\environment.ts.bak src\app\environment.ts
REM replace localhost in environment file with the TEST environment URL
"%env.FART%" src\app\environment.ts http://localhost:12345 %TEST.api.url%
REM build using this environment
call npm run build-prod
REM restore backup environment file
del /Q src\app\environment.ts
ren src\app\environment.ts.bak environment.ts
REM create TEST package
"%env.MSDEPLOY%" ^
-verb:sync ^
-source:contentPath="%teamcity.build.workingDir%\dist" ^
-dest:package="%teamcity.build.checkoutDir%\Package_TEST.zip"
REM =====CREATE PROD PACKAGE==================================================
REM backup the environment file
ren src\app\environment.ts environment.ts.bak
copy /Y src\app\environment.ts.bak src\app\environment.ts
REM replace localhost in environment file with the PROD environment URL
"%env.FART%" src\app\environment.ts http://localhost:12345 %PROD.api.url%
REM build using this environment
call npm run build-prod
REM restore backup environment file
del /Q src\app\environment.ts
ren src\app\environment.ts.bak environment.ts
REM create PROD package
"%env.MSDEPLOY%" ^
-verb:sync ^
-source:contentPath="%teamcity.build.workingDir%\dist" ^
-dest:package="%teamcity.build.checkoutDir%\Package_PROD.zip"
By the way, %env.FART% is the location of fart.exe which is a great find/replace tool that I use to replace one string in a file with another.

Related

Compress folder to .WAR file using PowerShell

I have a folder on my D drive (D://MyFolder), which I want to compress into a .WAR file (D://MyFolder.war).
I am trying to automate a deployment process using PowerShell, so I am looking for a PowerShell (or MS command line) command to do this.
I've tried to google and scourge StackOverflow, but haven't been able to find anything yet. This is my first 'PowerShell Adventure', so I'm not entirely sure if/how I can do this?
Many thanks for your help.
What about simple (if you do not have JAVA_HOME which you can check with env | sls JAVA_HOME):
cd D:\MyFolder
& "<path_to_your_java>\bin\java.exe" -cvf my_folder.war *
java options:
-c create new archive
-v generate verbose output on standard output
-f specify archive file name

How to upload a lot of files at once using FileZilla (possibly using a file containing the list of files to publish)?

Is there a way, using FileZilla, to publish many files at once (currently I have to choose them one by one every time, because they can be in different directories and I can't publish the whole directory)?
The ideal solution I am looking for is to use a single .txt file where I can paste the list of paths I want to publish and then somehow tell FileZilla to use it and publish each file to the remote server.
FileZilla lets you export the list of the files you have published with File -> Export in XML format. I am looking for something like this but I need to do the opposite operation.
If someone has some insights on it, please share them with me. Thanks!
P.S.: currently, I also use NetBeans IDE and publish files with it by clicking with the right button of the mouse and selecting Upload. If there's a way to do the same with NetBeans, that would be great (I write PHP code).
Thanks for the attention.
FileZilla does not allow any kind of automation.
See How do I send a file with FileZilla from the command line?
But you can use any other command-line FTP client.
For example WinSCP FTP client has Uploading a list of files example that exactly covers your task:
You may use following batch file that calls WinSCP script:
#echo off
set SESSION=ftp://user:password#example.com/
set REMOTE_PATH=/home/user/
echo open %SESSION% >> script.tmp
rem Generate "put" command for each line in list file
for /F %%i in (list.txt) do echo put "%%i" "%REMOTE_PATH%" >> script.tmp
echo exit >> script.tmp
winscp.com /script=script.tmp
set RESULT=%ERRORLEVEL%
del script.tmp
rem Propagating WinSCP exit code
exit /b %RESULT%

Powershell Pre-Build script failing from msbuild

I have a Powershell script that executes as a pre-build call for a Xamarin mobile app. The script changes the package name to match the build type e.g. Debug, Release.
To enable different "flavours" of the app to be created, I have written a batch file to replace the config file of the app with one matching the requested build type.
When I build from within Visual Studio, the powershell script runs as I expect and changes what I expected. However when the batch file runs I get an error message appearing:
Here is the content of the batch file, this was my first attempt at writing a batch file to build a code project:
#ECHO OFF
set buildVer=%1
set path=XamarinTestApp\XamarinTestApp
set msBuildDir=%WINDIR%\Microsoft.NET\Framework\v4.0.30319
echo %buildVer%
IF "%buildVer%"=="Release" (
goto :releaseBuild)
IF "%buildVer%"=="Test" (
goto :testBuild)
IF "%buildVer%"=="Dev" (
goto :devBuild)
:releaseBuild
set buildType=Release
copy /-y %path%\app.Release.config %path%\app.Config
goto :builder
:testBuild
set buildType=Release
copy /-y %path%\app.Test.config %path%\app.Config
goto :builder
:devBuild
set buildType=Debug
copy /-y %path%\app.Debug.config %path%\app.Config
goto :builder
:builder
call %msBuildDir%\msbuild.exe
C:\Projects\%path%\XamarinTestApp.Droid\XamarinTestApp.Droid.csproj /property:Configuration=%buildType% /target:SignAndroidPackage /verbosity:diag
I'm looking for any advice on either the error message I am getting, or some advice on how to get configurable information into my app.
Thanks.
Do not use path as user-variable. It is predefined by the system to locate executables.
Change that name to mypath - almost anything other than path.
from the prompt, use the command
set
to see a partial list of the names of variables that are set by the system

Add registry key during vsix installation

Is there any way to dynamically add a registry key while installing from a vsix?
For example:
Say we have SomeExtension.vsix.
It should check for a AnExisting.dll under
C:\Program Files (x86)\Existing\AnExisting.dll
C:\Program Files (x86)\Existing2\AnExisting.dll
Say it finds under Existing folder
Then add
[HKEY_CURRENT_USER\Software]
"C:\Program Files (x86)\Existing"=""
I know of pkgdef, but it seems to be taking a constant value i.e. we cannot get it to dynamically change on the machine it is being installed.
Or is it possible to get an environment variable on the machine it is being installed say we set PRODUCT_HOME accordingly for the vsix to add the value to registry?
This is the easiest way we can do this, although I do not know what side effects it can have. The following is a batch file snippet:
rem generate a pkgdef with the appropriate value
echo [HKEY_CURRENT_USER\Software] > MyBindingPaths.pkgdef
echo "%PRODUCT_HOME%"="" >> MyBindingPaths.pkgdef
rem *** Copy to VS extensions folder, this is a known location to look for pkgdef files ***
copy MyBindingPaths.pkgdef "%DEVENVDIR%Extensions"
echo *** Installing our VSIX ***
"%DevEnvDir%\vsixinstaller" -q SomeExtension.vsix
Other better suggestions welcome.

How do I copy from numerous release directories to a single folder

Okay this is and isn't programming related I guess...
I've got a whole bunch of little useful console utilities scattered across a suite of projects that I wrote and I want to dump them all to a single directory to make using them simpler. The only issue is that I have them all compiled in both Debug and Release mode.
Given that I only want the release mode versions in my utilities directory, what switch would allow me to specify that I want all executables from my tree structure but only from within Release folders:
Example:
Projects\
Project1\
Bin\
Debug\
Project1.exe
Release\
Project1.exe
Project2\
etc etc...
To
Utilities\
Project1.exe
Project2.exe
Project3.exe
Project4.exe
...
etc etc...
I figured this would be a cinch with XCopy - but it doesn't seem to allow me to exclude the Debug directories - or rather - only include items in my Release directories.
Any ideas?
You can restrict it to only release executables with the following. However, I do not believe the other requirement of flattening is possible using xcopy alone. To do the restriction:
First create a file such as exclude.txt and put this inside:
\Debug\
Then use the following command:
xcopy /e /EXCLUDE:exclude.txt *.exe C:\target
You can, however, accomplish what you want using xxcopy (free for non-commercial use). Read technical bulletin #16 for an explanation of the flattening features.
If the claim in that technical bulletin is correct, then it confirms that flattening cannot be accomplished with xcopy alone.
The following command will do exactly what you want using xxcopy:
xxcopy /sgfo /X:*\Debug\* .\Projects\*.exe .\Utilities
I recommend reading the technical bulletin, however, as it gives more sophisticated options for the flattening. I chose one of the most basic above.
Sorry, I haven't tried it yet, but shouldn't you be using:
xcopy release*.exe d:\destination /s
I am currently on my Mac so, I cant really check to be for sure.
This might not help you with assembling them all in one place now, but going forward have you considered adding a post-build event to the projects in Visual Studio (I'm assuming you are using it based on the directory names)
xcopy /Y /I /E "$(TargetDir)\$(TargetFileName)" "c:\somedirectory\$(TargetFileName)"
Ok, this is probably not going to work for you since you seem to be on a windows machine.
Here goes anyway, for the logic.
# From the base directory
mkdir Utilities
find . -type f | grep -w Release > utils.txt
for f in $(<utils.txt); do cp $f Utilities/; done
You can combine the find and cp lines into one, I split them for readability.
To do this on a windows machine you'll need Cygwin or some such Unix Utilities handy.
Maybe there are tools in the Windows shell to do this...
This may help get you started:
C:\>for %i in (*) do dir "%~dpi\*.exe"
Used in the dir command as a modifier to i, ~dp uses the drive and path of everything found in (*). If I run the above in a folder that has several subfolders containing executables, I get a dir list of all of the executables in each folder.
You should be able to modify that to add '\bin\release\' following the ~dpi portion and change dir to xcopy. A little experimentation should make it pretty easy.
To use the for statement above in a batch file, change '%' to '%%' in both places.