Microsoft MVP Logo

Update October 6, 2015: I've since updated my update & dev process for my OrchardCMS deployment which I've detailed here: Continous Delivery of OrchardCMS to Azure, Complete with Dev & Test Environments

Yesterday I pushed two blog posts and an article out on how I keep a local copy of my Orchard CMS development projects and then how I deploy these changes to their production hosts using Azure Web Sites and the git source control system:

Everything seemed great but this morning, this nagging thing I've been putting up with got the better of me and was determined to crack that nut (fueled by a full pot of coffee after setting a PR pace for a 3.5 mile run). After the posts yesterday, I thought I was leaving some unfinished business lying around, and I just couldn't let it sit.

Current Challenges

The issues are:

  • Having machine dynamically generated files in my production repository
  • Not having system generated files included in my repository

Both of these stem from the fact you just don't have the same level of control over your remote repository that you have locally. Referring back to my article, on the production side of things, when you create a git repository using the Azure portal, all the files in your current Azure Web Site are included in the repository. If you are starting with an existing site, that might mean you have log files, index files from search modules or in the case of Orchard CMS, other Orchard generated files.

That accounts for files you don't want, but what about files generated by your site that you DO want in source control? For example, Orchard is capable of operating in a multitenant capability, effectively hosting multiple sites on the same engine, but each site operating under it's own URL and having it's own database. In the codebase of the site, the engine creates a folder for each tenant with a settings.txt file that contains the database and other relevant data for the specific tenant. That file is something I wanted in source control as it isn't regenerated... think of it as Orchard's specific web.config.

Taking More Control Over Your Remote Repository

This isn't nearly as easy or obvious as I thought it was, but thankfully searching yielded this little gem. If you look for a post by JGCorba you'll see a sweet little process he outlines that makes it work just fine. I had to tweak it a bit for my liking because his is written like there is nothing in the website to start with, but for me there would be stuff in the site root. So, here's what I did:

WARNING: Make sure you have backups... this took a few times for me to get right and I won't be responsible if you blow stuff up!

Delete Existing Deployment Repositories

If you have an existing deployment repository, remove it by going into the Azure portal and deleting it from the dashboard of your Azure Web Site. If you don't have this step, then ignore it.

Create a New Repository

You are going to create it the same way, but you have a setup step to perform. When Azure creates the repository, it puts it within a repository folder under the site folder. When you push updates from your local copy of the cloned git repository, they go to this location and then are applied to the site (in wwwroot). However if you don't care about that staging and rather just want to push stuff into the wwwroot, you can change this.

Within the Azure portal, select your Web Site and click the Configure menu item. Scroll down to the app settings section and create key named SCM_REPOSITORY_PATH with the value wwwroot.

Now, create the repository from the Dashboard page.

Connect to and Modify the Repository

This is the point where the Azure portal assumes you have either an empty website you want to push to, or if you already have files in your Azure Web Site, you want all of those in your repository. Well neither of these are true. The latter is more of my situation, but I didn't want to include the Orchard generated log files, dynamically compiled files, etc.

So... to fix this I needed to get to the Azure Web Site and manually modify my repository. At first I thought this wasn't possible because you can't login to the server where your site resides, but I stumbled across Kudu! This is the underlying engine that hosts git in Azure and it accepts remote connections, sort of like SSH! Here's a little info on it from the guy behind it.

What I used is the KuduExec.NET client which you can get from GitHub: KuduExec.NET. Once you've built the project, you launch it from a command line. The only argument it wants is the deployment git repository which you can get from your Azure portal under the Deployments tab on your Azure Web Site. Look for the GIT URL... you want the whole thing, less the *.git filename on the end, so something like this:

KuduExec.exe https://[your deployment username]@[your Azure Web Site].scm.azurewebsites.net

KuduExec will then prompt you for your deployment credential password and then you'll get dropped in the root of your site, same as you would if you connected to your site via FTP! You can even see the contents of your site!

So now you need you have console access, so you are going to use the git command line (aka: bash) interface. Change directory under the site\wwwroot folder and reset the git repository Azure created (because it has all the stuff you don't want or files you do want). Now reinitialize your repository using:

git init

That might not have been necessary if you used a .gitignore file to exclude things. I forgot to do that before creating my repository so uploaded the following file (specific to Orchard CMS):

App_Data/CompilationSnapshots
App_Data/Logs
App_Data/Warmup
App_Data/Dependences App_Data/cache.dat App_Data/hrestart.txt App_Data/Sites/*

The last line excluded everything in the sites folder... not what I wanted. I want to keep just the settings.txt file in each tenant which is in a folder in that directory. I couldn't get the ignore working just right so in a moment, I'll forcefully add those into the repo.

Add Files to the Repository

Next up, I added all the files, followed by forcefully adding any files I wanted to keep:

git add .
git add "App_Data\Sites\Default\Settings.txt" -f
git add "App_Data\Sites\Tenant2\Settings.txt" -f
git add "App_Data\Sites\Tenant3\Settings.txt" -f

If you run a git status, you can see all the files that will get added. If any need to be removed, just use git rm --cached [path to file].

Last step is to commit your changes. Assuming this is the first time you've worked with git within your website, you need to establish yourself so you need to set the first two commands:

git config --global user.email "brickwall@andrewconnell.com"
git config --global user.name "Andrew Connell"
git commit -m "initial commit"

At this point, your repository has what you want it to have! Now you can clone the changes locally, make edits, and push them back.

One More Thing... When you Push Updates...

One thing I've seen in the forums is that when you do a push updates, sometimes the Azure repository doesn't switch back to the master branch, which you want it to do. This means you need to terminal back into your Azure Web Site using KuduExec, go to the wwwroot, and run git branch master to switch back to the master branch. The Kudu guys are aware of it and have tracked the issue (as well as fixed it), but the version of Kudu in your Azure Web Site might have this fix to just be warned.

The only hitch I've seen here is the fact that anytime I'm cloning, fetching, pulling or pushing to/from my azure deployment I had to use the git bash interface, not the handy GitExtensions. But all other work done locally worked just fine.

Comments powered by Disqus