あまりないケースかとは思うけど、自分には必要だった
自分はdotfilesの管理をAnsibleで行っていて、dotfilesのリポジトリの中にansibleディレクトリがありそれを実行するようにしている
基本ローカルで実行することを想定してたのでAnsibleのgitモジュールでdotfilesリポジトリをcloneして設定ファイルなどのシンボリックリンクなどを行っていた
ただ、この辺の処理に手を加えて試しにローカルで実行しようとするとエラーが出る
- name: Clone dotfiles repository ansible.builtin.git: repo: "{{ repo }}" dest: "{{ dotfiles_path }}" clone: true
この設定で実行すると
fatal: [localhost]: FAILED! => changed=false before: 81e3473d8b36204aeedb45d40cd78b2199ffbb5a msg: 'Local modifications exist in the destination: /path/to/dotfiles (force=no).'
ローカルで変更があると失敗するようになっている
エラーが出ないようにするにはforce: trueで変更を上からなくすことでエラーは出なくなる(changed扱い)
- name: Clone dotfiles repository ansible.builtin.git: repo: "{{ repo }}" dest: "{{ dotfiles_path }}" clone: true force: true
これでエラーは出ないようになるがそれまで作業していたデータが消えてしまう
tag管理でうまくやるとか、他のVMから実行するとか、回避方法はいくつかあると思うが今触ってる環境でとりあず実行したいけど差分は残しておきたい、差分を適用したplaybookを実行したいみたいなときに便利かと思って対応できる処理を書いてみた
- ansible/roles/deploy/tasks/main.yml
+- name: Check repository directory exists + ansible.builtin.stat: + path: "{{ dotfiles.dest }}" + register: dotfiles_dir + +- name: Check unstaged changes # noqa command-instead-of-module + ansible.builtin.command: + cmd: git diff --exit-code + chdir: "{{ dotfiles.dest }}" + register: repo_changed + ignore_errors: true + changed_when: repo_changed.rc != 0 + when: dotfiles_dir.stat.exists + +- name: Stash Changes # noqa command-instead-of-module + ansible.builtin.command: git stash + when: repo_changed is defined and repo_changed.rc is defined and repo_changed.rc != 0 + changed_when: true - name: Clone dotfiles repository ansible.builtin.git: repo: "{{ repo_prefix }}{{ dotfiles.src.repo }}" dest: "{{ dotfiles.dest }}" clone: true update: true force: true +- name: Pop stash changes # noqa command-instead-of-module + ansible.builtin.command: git stash pop + when: repo_changed is defined and repo_changed.rc is defined and repo_changed.rc != 0 + changed_when: true
要はcloneの前に変更があればstashして、clone後にpopするだけ
上書きの範囲がどの程度のものなのか深追いしていないからよくわかっていないが変更の情報が存在する.gitディレクトリは上書きしないようなのでこれで行けた
gitコマンド使っているがgitモジュールで同様の機能を実現はできなそうだったのでlint対象から除外している(# noqa command-instead-of-module)
これで冒頭書いていた不便がなくなったのでだいぶやりやすくなった