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:
- Blog Post: Upgrading Orchard CMS from 1.6 to 1.7.1
- Blog Post: HowTo Setup: Orchard CMS Source Enlistment for Local Dev and Automated Git Publishing to Azure
- Article: HowTo Setup: Orchard CMS Source Enlistment for Local Dev and Automated Git Publishing to Azure
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.
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
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
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 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:
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 "firstname.lastname@example.org" 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.