Archive

Archive for the ‘Git’ Category

DeployTo – a simple PowerShell web deployment script

February 10, 2012 1 comment

We’re constantly working to standardize how builds get pushed out to our development, UAT, and production servers. The typical ‘order of operations’ includes:

  1. compile the build
  2. backup the existing deployment
  3. copy the new deployment
  4. celebrate

Pretty simple, but with a few moving parts (git push, TeamCity pulls in, compiles, runs deployment procedures, IIS (hopefully) doesn’t explode).

One step to standardize this has been to add these steps into our psake scripts, but that got tiring (and dangerous when we found a flaw).  When in doubt, refactor!

First, get the codez!

DeployTo.ps1 and an example settings.xml file.

Creating a simple deployment tool – DeployTo

The PowerShell file, DeployTo.ps1, should be located in your project, your PATH, or wherever your CI server can find it–I tend to include it in a folder we have that synchronizes to ALL of our build servers automatically via Live Mesh. You could include it with your project to ensure dependencies are always met (for public projects).

DeployTo has one expectation, that a settings.xml file (or file passed in the Settings argument) will contain a breakdown of your deployment paths.

Example:

<site>
    <name>development</name>
    <path>\\server\webs\path</path>
</site>

With names and paths in hand, DeployTo sets about to match the passed in deployment location to what exists in the file. If one is found, it proceeds with the backup and deployment process.

Calling DeployTo is as simple as:

deployto development

Now, looping through our settings.xml file looking for ‘deployment’:

foreach ($site in $xml.settings.site) {
    if ($site.name.ToLower() -eq $deploy.ToLower()) {
        writeMessage ("Found deployment plan for {0} -> {1}." -f $site.name, $site.path)
	if ($SkipBackup -eq $false) {
	    backup($site)
	}
	deploy($site)
	$success = $true
	break;
    }
}

The output also lets us know what’s happening (and is helpful for diagnosing issues in your CI’s build logs).

Deploying to DEVELOPMENT
Reading settings file at settings.xml.
Testing release path at .\release.
Found deployment plan for development -> \\server\site.
Making backup of 255 file(s) at \\server\site to \\server\site-2012-02-10-105321.
Backup succeeded.
Removing existing files at \\server\site.
Copying new release to \\server\site.
Deployment succeeded.
SUCCESS!

Backing up – A safety net when things go awry.

Your builds NEVER go bad, right? Deployments work 100% of the time? Right? Sure. 😉 No matter how many staging sites you test on, things can go back on a deployment. That’s why we have BACKUPS. I could get fancy and .7z/.gzip up the files and such, but a simple directory copy serves exactly what I need.

The backup function itself is quite simple–take a list directory of files, copy it into a new directory with the directory name + current date/time.

function backup($site) {
try {
    $currentDate = (Get-Date).ToString("yyyy-MM-dd-HHmmss");
    $backupPath = $site.path + "-" + $currentDate;

    $originalCount = (gci -recurse $site.path).count

    writeMessage ("Making backup of {0} file(s) at {1} to {2}." -f $originalCount, $site.path, $backupPath)
    
    # do the actual file copy, but ignore the thumbs.db file. It's such a horrid little file.
    cp -recurse -exclude thumbs.db $site.path $backupPath

    $backupCount = (gci -recurse $backupPath).count	

    if ($originalCount -ne $backupCount) {
      writeError ("Backup failed; attempted to copy {0} file(s) and only copied {1} file(s)." -f $originalCount, $backupCount)
    }
    else {
      writeSuccess ("Backup succeeded.")
    }
}
catch
{
    writeError ("Could not complete backup. EXCEPTION: {1}" -f $_)
}
}

Deploying — copying files, plain and simple

Someday, I may have the need to be fancy. Since IIS automatically boots itself when a new web.config is added, I don’t have any ‘logic’ to my deployment scripts. We also, for now, keep our database deployments separate from our web view deployments. For now, deploying is copying files; however, who wants to do that by hand? Not me.

function deploy($site) {
try {
    writeMessage ("Removing existing files at {0}." -f $site.path)

    # force, because thumbs.db is annoying
    rm -force -recurse $site.path

    writeMessage ("Copying new release to {0}." -f $site.path)

    cp -recurse -exclude thumbs.db  $releaseDirectory $site.path
    $originalCount = (gci -recurse $releaseDirectory).count
    $siteCount = (gci -recurse $site.path).count
    
    if ($originalCount -ne $siteCount)
    {
      writeError ( "Deployment failed; attempted to copy {0} file(s) and only copied {1} file(s)." -f $originalCount, $siteCount)
    }
    else {
      writeSuccess ("Deployment succeeded.")
    }
}
catch {
    writeError ("Could not deploy. EXCEPTION: {1}" -f $_)
}
}

That’s it.

Once thing you’ll notice in both scripts is I am doing a bit of monitoring and testing.

  • Do paths exist before we begin the process?
  • Do the backed up/copied/original file counts match?
  • Did anything else go awry so we can throw a general error?

It’s a work in progress, but has met our needs quite well over the past several months with psake and TeamCity.

Advertisements

Creating Local Git Repositories – Yeah, it’s that simple!

November 9, 2009 Comments off

We’re in the process of evaluating several source control systems here at the office.  It’s a JOYOUS experience and I mean that… sorta.  Currently, we have a montage of files dumped into two SourceSafe repos.

At this point, most of you are either laughing, crying, or have closed your web browser so you don’t get caught reading something with the word ‘SourceSafe’ in it.  That’s cool, I get that.

As part of my demonstrations (for the various toolings we’re looking at), I wanted to show how simple it was to create a local GIT repository.

Since I’m discussing ‘local’, I’m taking a lot of things out of the picture.

  • Authentication/authorization is handled by Windows file permissions/Active Directory.  If you can touch the repo and read it, then knock yourself out.
  • Everything is handled through shares, no HTTP or that goodness.  Users are used to hitting a mapped drive for SourceSafe repos, we’re just emulating that.

So what do we need to do to create a Git repository? Three easy steps (commands).

1. Create your directory with the .git extention.

mkdir example.git

2. Change into that new directory.

cd example.git

3. Initialize the repository using Git.

git init —bare

Our new Git repository is now initialized. You can even see that PowerShell picks up on the new repository and has changed my prompt accordingly.

Local Git Repository - example.git

Now that we have example.git as our ‘remote’ repository, we’re ready to make a local clone.

git clone H:\example.git example

Now we have an empty clone (and it’s kind enough to tell us).

Empty clone.

All of our Git goodness is packed into the standard .git directory.

Git clone contents.

To test things out, let’s create a quick file, add it to our repo, and then commit it in.

First, let’s create/append an example file in our clone.

Create/append an example file to Git

(note: this is called ‘so lazy, I don’t even want to open NotePad’)

Now, we can add and verify that our newly added ‘example.text’ file shows up:

Git - add file and verify

Finally, commit…

git commit -a -m “this is our first commit”

First commit

… and push!

git push origin master

Push to origin repo.

The last step is to ensure that our new ‘remote’ repository can be reproduced.  Here’s a quick single line to clone our repository into another new folder, list out the contents, and verify the log has the commit we made in the first repo.

Finished Second Clone to Verify

It’s amazing how quick and easy it is to setup local Git repositories.  From here, we can look at the file system/Windows for authentication/authorization and focus on our migration AWAY from Visual SourceSafe. 🙂

Tags: ,