Octopus Deploy has fantastic native support for substituting configuration variables in .NET applications, using the “substitute variables in files” feature, and the ability to run XML config transforms. Combining these two approaches using the “One transform + Variable replacement” approach is my favoured approach to configuring ASP.NET applications.
But what about web applications that are front-end focussed such as Single Page Apps, or those which have no .NET back end code to configure? A web app I was working on recently contained a ‘global variable’ JavaScript file (variables.js), containing a single variable which acted as a pointer to an API endpoint.
servicesUrl = "http://services.test.endpoint.url.com/"
When the app is deployed out across CI, QA and Production environments, I wanted this variable to be substituted by Octopus for a variable. So I duly configured my web deployment step to perform an additional substitution in the variables.js file, and replaced the line above to include the Octopus variable syntax. So far, so good. However, I also wanted to be able to run the app locally without having to constantly change the variables.js file. So here was my next iteration:
servicesUrl = "http://#{WebsiteName.DataServices}/" if (~servicesUrl.indexOf("#{")) servicesUrl = "http://services.test.endpoint.url/";
Unfortunately, I then hit upon an issue in Octostache (the variable substitution engine in Octopus) whereby you can’t use the ‘#’ symbol in files unless it does actually relate to a variable you want to be substituted. You can’t even include a hash in a comment without Octostache throwing an error like:
Octostache returned the following error: `Parsing failure: unexpected '#'; expected end of input (Line n, Column n); recently consumed: xxxxxxxxxx
So, in the end I had to use a bit of JavaScript string encoding in order to parse for the ‘un-substituted’ variable placeholder, and fallback to a default URL. Here’s what worked for me – noting that “%23%7B” is the encoded version of “#{“…
// During Octopus deployment, variable values in this file using Octopus hash-syntax will be replaced servicesUrl = "http://#{WebsiteName.DataServices}/" // For local development, the string above won't be replaced. The following block provides a default fallback URL // In a file being ran through Octopus variable substitution, you have to avoid using the 'hash' symbol anywhere // (other than a "real" Octopus variable, of course). Otherwise Octopus throws a wobbly. if (~encodeURIComponent(servicesUrl).indexOf("%23%7B")) servicesUrl = "http://services.test.endpoint.url";