Skip to content

Commit c645070

Browse files
committed
Add a git_repo role
This role accepts a single complex data structure to clone a git repository with multiple remotes and branches. (cherry picked from commit 2fae914)
1 parent b06a0ae commit c645070

File tree

5 files changed

+163
-0
lines changed

5 files changed

+163
-0
lines changed

roles/git_repo/README.md

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
This role clones a set of git repositories, handling multiple remotes and managing different branches for each remote. It also provides basic support for bundle installs for Ruby projects, and pip installs within a virtual environment for Python projects. The role aims to present a single, simple interface in Ansible variables for managing a collection of locally cloned git repositories.
2+
3+
Role Variables
4+
--------------
5+
6+
The main data structure for the role is the list of `git_repositories`. Each repository in the list requires the following attributes:
7+
8+
- `name`: The local name of the repository.
9+
- `dir`: The parent directory to clone the repository from.
10+
- `remotes`: List of repository remotes, each with `name`, `url`, and `branches`.
11+
12+
Repositories may also have the following optional attributes:
13+
14+
- `install_gems`: Boolean to indicate if Ruby gems should be installed. This assumes the cloned repository provides a Gemfile.
15+
- `python_packages`: A list of python packages to install in a venv within the repository.
16+
17+
Each remote requires the following attributes:
18+
19+
- `name`: Name of the remote.
20+
- `url`: URL of the remote.
21+
- `branches`: A list of branches in the remote repository that will be created in the local clone.
22+
23+
Examples
24+
--------
25+
26+
Basic example of the `git_repositories` variable, configuring two repositories, each with a single remote and a single branch:
27+
28+
```yaml
29+
git_repositories:
30+
- name: 'foreman'
31+
dir: '/home/vagrant'
32+
remotes:
33+
- name: 'origin'
34+
url: 'git@github.com/my_github_user/foreman.git'
35+
branches:
36+
- 'develop'
37+
- name: 'katello'
38+
dir: '/home/vagrant'
39+
remotes:
40+
- name: 'origin'
41+
url: 'git@github.com/my_github_user/katello.git'
42+
branches:
43+
- 'master'
44+
```
45+
46+
Example configuring a repository with multiple remotes and branches and installing gems from the project's Gemfile. The checkout will be of the first branch on the first remote when performing the bundle install:
47+
48+
```yaml
49+
git_repositories:
50+
- name: 'foreman'
51+
dir: '/home/vagrant'
52+
remotes:
53+
- name: 'upstream'
54+
url: 'git@github.com/theforeman/foreman.git'
55+
branches:
56+
- 'develop'
57+
- name: 'myfork'
58+
url: 'git@github.com/my_github_user/foreman.git'
59+
branches:
60+
- 'exciting-new-feature'
61+
- 'fix-annoying-bug'
62+
install_gems: true
63+
```
64+
65+
Installing Python Packages in a Virtual Environment:
66+
67+
```yaml
68+
git_repositories:
69+
- name: 'rpm-packaging'
70+
dir: '/home/vagrant'
71+
remotes:
72+
- name: 'downstream'
73+
url: 'git@gitlab.example.com/systems_management/rpm-packaging.git'
74+
branches:
75+
- 'STREAM'
76+
- 'VERSION-1'
77+
- 'VERSION-2'
78+
- 'VERSION-3'
79+
python_packages:
80+
- 'ansible'
81+
- 'obal'
82+
- 'tito'
83+
```

roles/git_repo/tasks/branch.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
- name: "Configure repository branch"
3+
block:
4+
- name: "Create local branch"
5+
ansible.builtin.command:
6+
cmd: "git branch -f {{ branch }} {{ remote.name }}/{{ branch }}"
7+
chdir: "{{ git_repo_repository.dir }}/{{ git_repo_repository.name }}"

roles/git_repo/tasks/clone.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
- name: "Clone repository"
3+
ansible.builtin.git:
4+
repo: "{{ remote.url }}"
5+
remote: "{{ remote.name }}"
6+
version: "{{ (remote.branches[0]) if (remote.branches is defined) else 'HEAD' }}"
7+
dest: "{{ git_repo_repository.dir }}/{{ git_repo_repository.name }}"
8+
accept_newhostkey: yes
9+
10+
- name: "Configure additional branches for initial remote"
11+
ansible.builtin.include_tasks: branch.yml
12+
when: (remote.branches is defined) and (remote.branches | length > 1)
13+
loop: "{{ remote.branches[1:] }}"
14+
loop_control:
15+
loop_var: branch

roles/git_repo/tasks/main.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
- name: "Configure git repository"
3+
ansible.builtin.include_tasks: "{{ 'clone.yml' if ansible_loop.first else 'remote.yml' }}"
4+
loop: "{{ git_repo_repository.remotes }}"
5+
loop_control:
6+
loop_var: remote
7+
extended: yes
8+
label: "{{ remote.name }}"
9+
10+
- name: "Local bundle config"
11+
when: git_repo_repository.install_gems is defined and git_repo_repository.install_gems
12+
block:
13+
- name: "Create .bundle/gems"
14+
ansible.builtin.file:
15+
path: "{{ git_repo_repository.dir }}/{{ git_repo_repository.name }}/.bundle/gems"
16+
state: directory
17+
- name: "Configure bundler to use .bundle/gems"
18+
ansible.builtin.command:
19+
cmd: "bundle config --local path .bundle/gems"
20+
chdir: "{{ git_repo_repository.dir }}/{{ git_repo_repository.name }}"
21+
- name: "Install Gems"
22+
community.general.bundler:
23+
state: present
24+
chdir: "{{ git_repo_repository.dir }}/{{ git_repo_repository.name }}"
25+
26+
- name: "Create venv and install python packages"
27+
ansible.builtin.pip:
28+
name: "{{ git_repo_repository.python_packages }}"
29+
virtualenv: "{{ git_repo_repository.dir }}/{{ git_repo_repository.name }}/env"
30+
virtualenv_command: "python3 -m venv"
31+
virtualenv_site_packages: yes
32+
when: (git_repo_repository.python_packages is defined) and (git_repo_repository.python_packages | length >= 1)

roles/git_repo/tasks/remote.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
- name: "Configure additional remote for repository"
3+
block:
4+
- name: "Configure remote url"
5+
community.general.git_config:
6+
scope: local
7+
repo: "{{ git_repo_repository.dir }}/{{ git_repo_repository.name }}"
8+
name: "remote.{{ remote.name }}.url"
9+
value: "{{ remote.url }}"
10+
- name: "Configure remote fetch"
11+
community.general.git_config:
12+
scope: local
13+
repo: "{{ git_repo_repository.dir }}/{{ git_repo_repository.name }}"
14+
name: "remote.{{ remote.name }}.fetch"
15+
value: '+refs/heads/*:refs/remotes/{{ remote.name }}/*'
16+
- name: "Fetch remote"
17+
ansible.builtin.command:
18+
cmd: "git fetch {{ remote.name }}"
19+
chdir: "{{ git_repo_repository.dir }}/{{ git_repo_repository.name }}"
20+
21+
- name: "Configure branches for additional remote"
22+
ansible.builtin.include_tasks: branch.yml
23+
when: remote.branches is defined
24+
loop: "{{ remote.branches }}"
25+
loop_control:
26+
loop_var: branch

0 commit comments

Comments
 (0)