Ansible Migrate GIT repos

Summary

I recently had to figure out how to automate a migration of a dev git repo to a qa git repo. For security reasons, the repositories had to be kept separate, using one repo with branches for environments was immediately ruled out. The challenge then is to maintain 2 seperate git repositories, build an automated sequence that would allow for content from one repo to be migrated into the other.

The Solution

Cool… I will automate this with Ansible. I began by looking into the Ansible git module, the module does half of what I am trying to acheive, it allows for the automation of clone/checkout of specific branches of a git repo.

I broke the solution down into a number of smaller steps, first of all I will use the git module to check out the source branch. Secondly the git module will be used to checkout the destination repo and create a new branch with a meaningful title and a timestamp appended to the end. This ensures that imported data doesn’t break anything on the destination repo and allows maintainers to review and decide if they want to merge the code into other branches. Lastly I will sync the files from src to destination on the local copy located on the Ansible server, the changes will be added, committed and pushed to the new branch on the destination repo.

- name: migrate repo to dest
  hosts: localhost
  connection: local
  tasks:
  - name: get repo name from URL
    set_fact:
      repo_name:  "{{ src_repo | regex_replace('.+\\/(.+)\\.git', '\\1') }}"
  - debug:
      var: repo_name
  - name: set branch name
    set_fact:
      branch_name: "dev_repo_import_{{ ansible_date_time.iso8601_basic_short }}"
  - name: generate timestamp
    debug:
      var: branch_name
  - name: get a copy of the source repo
    git:
      repo: "{{ src_repo }}"
      dest: "/tmp/{{ repo_name }}"
      clone: yes
      version: "{{ src_branch }}"
  - name: checkout dest repo
    git:
      repo: "{{ dest_repo }}"
      dest: "/tmp/dest_{{ repo_name }}"
      clone: yes
  - name: switch to new branch
    shell: "git --git-dir=/tmp/dest_{{ repo_name }}/.git checkout -b {{ branch_name }}"
  - name: check if env_vars,yml exists
    stat:
     path: "/tmp/{{ repo_name }}/vars/env_vars.yml"
    register: env_vars_file
  - name: update environment variable to QA
    replace:
      path: "/tmp/{{ repo_name }}/vars/env_vars.yml"
      regexp: '^environment: DEV$'
      replace: 'environment: QA'
    when: env_vars_file.stat.exists
  - name: copy files from source to dest
    synchronize:
      src: "/tmp/{{ repo_name }}/"
      dest: "/tmp/dest_{{ repo_name }}"
      rsync_opts:
        - "--exclude=.git*"
  - name: add files to local repo
    shell: "cd /tmp/dest_{{ repo_name }} && git add ."
  - name: commit new files
    shell: "git --git-dir=/tmp/dest_{{ repo_name }}/.git commit -m 'importing from MSE repo'"
  - name: push changes
    shell: "git --git-dir=/tmp/dest_{{ repo_name }}/.git push -u origin {{ branch_name }}"
  - name: clean up source repo in /tmp/src
    file:
      path: "/tmp/{{ repo_name }}"
      state: absent
  - name: clean up dest repo in //tmp/dest
    file:
      path: "/tmp/dest_{{ repo_name }}"
      state: absent

I had to use the shell module to complete the add, push, commit as the current version of the git module simply doesn’t provide these features.

In my example my repository contains a vars/env_vars.yml file, I use this within my different environments to set conditionals such as if environment == “DEV” then URL = http://dev.example.com. Using these types of variables can make it a bit easier when managing playbooks in multiple enviornments.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s