Tuesday, June 24, 2014

Git aliases for my Powershell friends

For my windows friends.

In retrospect, I realized that OSX gives you some niftly little shortcuts that I pretty much take for granted. A list of Git Aliases that comes with Dotfiles is something I took for granted. It sure would be nice to have had these a year ago. Here it is for all of my Powershell Friends:

just ctrl+h alias to new-alias and dump it somewhere in your powershell's $profile

alias g=git
alias gCa='git add $(gCl)'
alias gCe='git mergetool $(gCl)'
alias gCl='git status | sed -n "s/^.*both [a-z]*ed: *//p"'
alias gCo='git checkout --ours --'
alias gCt='git checkout --theirs --'
alias gR='git remote'
alias gRa='git remote add'
alias gRb=git-hub-browse
alias gRl='git remote --verbose'
alias gRm='git remote rename'
alias gRp='git remote prune'
alias gRs='git remote show'
alias gRu='git remote update'
alias gRx='git remote rm'
alias gS='git submodule'
alias gSI='git submodule update --init --recursive'
alias gSa='git submodule add'
alias gSf='git submodule foreach'
alias gSi='git submodule init'
alias gSl='git submodule status'
alias gSm=git-submodule-move
alias gSs='git submodule sync'
alias gSu='git submodule foreach git pull origin master'
alias gSx=git-submodule-remove
alias ga='git add -A'
alias gam='git amend --reset-author'
alias gb='git b'
alias gbL='git branch -av'
alias gbM='git branch -M'
alias gbS='git show-branch -a'
alias gbX='git branch -D'
alias gbb='git bisect bad'
alias gbc='git checkout -b'
alias gbd='git b -D -w'
alias gbg='git bisect good'
alias gbi='git rebase --interactive'
alias gbl='git branch -v'
alias gbm='git branch -m'
alias gbs='git show-branch'
alias gbx='git branch -d'
alias gc='git commit --verbose'
alias gcF='git commit --verbose --amend'
alias gcO='git checkout --patch'
alias gcP='git cherry-pick --no-commit'
alias gcR='git reset "HEAD^"'
alias gca='git commit --verbose --all'
alias gcf='git commit --amend --reuse-message HEAD'
alias gci='git ci'
alias gcim='git ci -m'
alias gcl=git-commit-lost
alias gcln='git clean'
alias gclndf='git clean -df'
alias gclndfx='git clean -dfx'
alias gcm='git ci -m'
alias gco='git co'
alias gcp='git cp'
alias gcr='git revert'
alias gcs='git show'
alias gd='git diff'
alias gdc='git diff --cached -w'
alias gdi='git status --porcelain --short --ignored | sed -n "s/^!! //p"'
alias gdk='git ls-files --killed'
alias gdm='git ls-files --modified'
alias gdu='git ls-files --other --exclude-standard'
alias gdx='git ls-files --deleted'
alias gf='git fetch'
alias gfc='git clone'
alias gfch='git fetch'
alias gfm='git pull'
alias gfr='git pull --rebase'
alias gg='git grep'
alias ggL='git grep --files-without-matches'
alias ggi='git grep --ignore-case'
alias ggl='git grep --files-with-matches'
alias ggrc='git rebase --continue'
alias ggv='git grep --invert-match'
alias ggw='git grep --word-regexp'
alias gi='vim .gitignore'
alias giA='git add --patch'
alias giD='git diff --no-ext-diff --cached --word-diff'
alias giR='git reset --patch'
alias giX='git rm -rf --cached'
alias gia='git add'
alias gid='git diff --no-ext-diff --cached'
alias gir='git reset'
alias git='noglob git'
alias giu='git add --update'
alias gix='git rm -r --cached'
alias gl='git l'
alias glb='git log --topo-order --pretty=format:${_git_log_brief_format}'
alias glc='git shortlog --summary --numbered'
alias gld='git log --topo-order --stat --patch --full-diff --pretty=format:${_git_log_medium_format}'
alias glg='git l'
alias glo='git log --topo-order --pretty=format:${_git_log_oneline_format}'
alias glog='git l'
alias gls='git log --topo-order --stat --pretty=format:${_git_log_medium_format}'
alias gm='git merge'
alias gmC='git merge --no-commit'
alias gmF='git merge --no-ff'
alias gma='git merge --abort'
alias gms='git merge --squash'
alias gmt='git mergetool'
alias gnb='git nb'
alias gp='git push'
alias gpA='git push --all && git push --tags'
alias gpa='git push --all'
alias gpc='git push --set-upstream origin "$(git-branch-current 2> /dev/null)"'
alias gpf='git push --force'
alias gpl='git pull'
alias gplr='git pull --rebase'
alias gpp='git pull origin "$(git-branch-current 2> /dev/null)" && git push origin "$(git-branch-current 2> /dev/null)"'
alias gps='git push'
alias gpsh='git push'
alias gpt='git push --tags'
alias gr='git rebase'
alias gra='git rebase --abort'
alias grad='git remote add'
alias grc='git rebase --continue'
alias gri='git rebase --interactive'
alias grr='git remote rm'
alias grs='git reset'
alias grsh='git reset --hard'
alias grv='git remote -v'
alias gs='git status'
alias gsL=git-stash-dropped
alias gsS='git stash save --patch --no-keep-index'
alias gsX=git-stash-clear-interactive
alias gsa='git stash apply'
alias gsd='git stash show --patch --stat'
alias gsh='git show'
alias gshow='git show'
alias gshw='git show'
alias gsl='git stash list'
alias gsm='git submodule'
alias gsmi='git submodule init'
alias gsmu='git submodule update'
alias gsp='git stash pop'
alias gsr=git-stash-recover
alias gss='git stash save --include-untracked'
alias gst='git stash'
alias gstsh='git stash'
alias gsw='git stash save --include-untracked --keep-index'
alias gsx='git stash drop'
alias gt='git t'
alias gunc='git uncommit'
alias guns='git unstage'
alias gwC='git clean -f'
alias gwD='git diff --no-ext-diff --word-diff'
alias gwR='git reset --hard'
alias gwS='git status --ignore-submodules=${_git_status_ignore_submodules}'
alias gwX='git rm -rf'
alias gwc='git clean -n'
alias gwd='git diff --no-ext-diff'
alias gwr='git reset --soft'
alias gws='git status --ignore-submodules=${_git_status_ignore_submodules} --short'
alias gwx='git rm -r'
    && print .bundle       >>! .gitignore \
    && print vendor/assets >>! .gitignore \
    && print vendor/bundle >>! .gitignore \
    && print vendor/cache  >>! .gitignore'
alias spb='git checkout -b `sp | tail -2 | grep ''#'' | sed ''s/^ //'' | sed ''s/[^A-Za-z0-9 ]//g'' | sed ''s/ /-/g'' | cut -d- -f1,2,3,4,5`'

Learning GIT

Step 1. Use it
Step 2. Use it

Other resources to supplement step 1 and 2:

http://gitimmersion.com/
http://git-scm.com/book/en/Getting-Started
http://www.git-tower.com/learn/

Monday, June 16, 2014

How to do conditional include_recipe (how to use guards with include_recipe)

Lets say you want to include a recipe based on some state of the server. Obviously this is a server you inherited from some team, and rebuilding it is just not an option because server provisioning takes 2 weeks (or two months).

include_recipe "foo::bar" do not_if { ::File.exists?("/etc/foo/bar") } end
/\ That simple does't work, although it'd be awesome if it did (seems like a consistency thing to me). Reason for that is include_recipe is a method and not a resource. Which means it's evaluated at the compilation phase, and not at execution (which makes sense from building the resource collection perspective)
So, if you do want a conditional include_recipe, you want to do something like this instead:
some_variable = {some logic to check for some state on a system} 
include_recide 'foo::bar' unless some_variable
Situation where this becomes super useful for example, is on windows, for chef runs which need to reboot a server and go on:
include_recipe 'cookbook::recipe' unless reboot_pending? 
Great link:

Toodles/

Thursday, June 12, 2014

mini post - Chef (Opscode) - Simplifying Unit Testing

Saw something cool today in regards to unit testing.

Chefspec runs the first portion of your Chef run, the complication phase, but not the execution phase.

Next, it tests the resulting objects against the set of objects you defined in your unit tests. If they match, you pass. The key here is that you have all of the recipe stuff accessible to you from inside your unit tests, so you can use it to simplify your life. (where applicable, last thing you want is a set of tests that never fails)

For example, in situations where I build a string and some of the attributes are from upstream cookbooks - DNS server, Bill Gates favorite color, population of Ukraine...

So, with an attribute driven cookbook, a traditional unit test looks something like this:

Attribute:
default['download_dir'] = '/var/windows/rocks'

Recipe:
directory node['download_dir'] do
  owner "root"
  group "root"
  mode 0755
  action :create
  recursive true
end
Unit test (traditional):
it 'create directory' do
    expect(chef_run).to create_directory('/var/windows/rocks')
      .with_owner('root')
      .with_group('root')
      .with_mode(0755)
end
Unit test (simplified):
it 'create directory' do
    expect(chef_run).to create_directory(chef_run.node['download_dir'])
      .with_owner('root')
      .with_group('root')
      .with_mode(0755)
end

Now if you modify the attribute your unit test will still pass. Whether you want it or not is a whole different story, but so far it's been working much better than placing an exact string in the unit test.




mini post - Chef (Opscode) best practices series - Unit testing and TDD

The argument of TDD is great and all, but I do not think it's directly applicable to Chef.

Here is the idea - Chef offers a lot of resources, and a lot of ways to skin the cat/dog/lizard/etc.. So you simply can't write unit tests first, because you don't actually know which resources you're going to use to skin said animal.

What you CAN do, is write integration tests first. Because you DO know the ultimate outcome of your cookbook. And you can write Stubs for your unit tests ahead of time, if that makes you feel good.

Lets say you want to write a WSUS cookbook. The goal of the cookbook is to install WSUS role on your server. So your TDD (test driven development) for installing WSUS server would look something like this:
/> knife kitchen create wsus (or knife cookbook create wsus)
Your unit test would look very generic:

it 'installs some prerequisite that came with windows' do
end 
it 'downloads some prereq that didnt come with windows' do
end 
it 'installs the downloaded prereq' do
end 
etc...
Your integration tests on the other hand, would look very specific - Because you know ahead of time what constitutes a functional WSUS server.

 describe package('wsus') do
   it { should be_installed }
 end 
describe service('wsus') do
  it { should be_enabled   }
  it { should be_running   }
end 
describe port(3859) do
  it { should be_listening }
end
etc... 
IMHO, that's the best you can do when it comes to TDD with Chef. If you start with unit tests you're forcing yourself down the path of constantly re-writing your tests... over and over and over...

Here is an image of DNA relication.