diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..16f9cdb --- /dev/null +++ b/.rspec @@ -0,0 +1,2 @@ +--color +--format documentation diff --git a/.travis.yml b/.travis.yml index 6b10af5..f398abf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,12 +5,30 @@ python: "2.7" before_install: - sudo apt-get update -qq - sudo apt-get remove --purge zsh + - sudo apt-get install ruby rubygems + - sudo useradd mtester -m -d /home/mtester -s /bin/bash + - sudo chgrp ```id -gn``` /home/mtester + - sudo chmod g+s /home/mtester + - sudo rm -rf /home/mtester/.zfunctions + - sudo rm -f /home/mtester/.zshrc + - umask 002 + - gem install serverspec install: - pip install ansible - "{ echo '[defaults]'; echo 'roles_path = ../'; } >> ansible.cfg" script: - - ansible-playbook -i ./tests/inventory ./tests/test_install.yml --syntax-check - - ansible-playbook -i ./tests/inventory ./tests/test_zshrc.yml --connection=local --sudo - - ansible-playbook -i ./tests/inventory ./tests/test_prompt.yml --connection=local --sudo + # Check machine pre-test state. + - rspec tests/spec/before_test_spec.rb + + # Check syntax + - ansible-playbook -i tests/inventory ./tests/playbooks/install.yml --syntax-check --list-tasks + + # Check install + - ansible-playbook -i ./tests/inventory tests/playbooks/install.yml --connection=local --sudo + - rspec tests/spec/install_spec.rb + + # Check configuration + - ansible-playbook -i ./tests/inventory tests/playbooks/configure.yml --connection=local --sudo + - rspec tests/spec/configure_spec.rb diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..0a61937 --- /dev/null +++ b/Gemfile @@ -0,0 +1,3 @@ +source 'https://rubygems.org' + +gem 'serverspec' diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..2492f94 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,41 @@ +GEM + remote: https://rubygems.org/ + specs: + diff-lcs (1.2.5) + multi_json (1.11.1) + net-scp (1.2.1) + net-ssh (>= 2.6.5) + net-ssh (2.9.2) + rspec (3.3.0) + rspec-core (~> 3.3.0) + rspec-expectations (~> 3.3.0) + rspec-mocks (~> 3.3.0) + rspec-core (3.3.1) + rspec-support (~> 3.3.0) + rspec-expectations (3.3.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.3.0) + rspec-its (1.2.0) + rspec-core (>= 3.0.0) + rspec-expectations (>= 3.0.0) + rspec-mocks (3.3.1) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.3.0) + rspec-support (3.3.0) + serverspec (2.19.0) + multi_json + rspec (~> 3.0) + rspec-its + specinfra (~> 2.35) + specinfra (2.36.6) + net-scp + net-ssh + +PLATFORMS + ruby + +DEPENDENCIES + serverspec + +BUNDLED WITH + 1.10.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..686981e --- /dev/null +++ b/README.md @@ -0,0 +1,81 @@ +# Ansible Role: ZSH + +[![Build Status](https://travis-ci.org/loliee/ansible-zsh.svg?branch=master)](https://travis-ci.org/loliee/ansible-zsh) + +Install and set up [ZSH](http://www.zsh.org/). +This role can also configure `~./zshrc` file and download and set up `prompt`. + +## Requirements + +- RedHat family +- Debian family +- OSX (Configuration part) + +## Role Variables + +### `__users__` + +Unset by default, dictionary should defined like this: + +```yaml +__users__: + [username]: + [option]: [value] +``` +**Options** + +| Option | Type | Comments | +|---------------------------|----------|---------------------------------------------------------------| +| zsh_default_shell | bool | Configure as default shell. Create `.zshrc`and `.zfunctions`. | +| zsh_prompt_install | bool | Install prompt ?, default value is `No` | +| zsh_prompt_name | string | Prompt name to load in `.zshrc`. | +| zsh_prompt_download_url | string | Prompt download url, e.g [pure](https://github.com/sindresorhus/pure) | +| zsh_prompt_additional_url | string | Prompt additional download url to put in `.zfunctions`. | +| zsh_zfunctions_directory | string | Directory of files to upload on remote `.zfunctions`. | +| zsh_zshrc_content | text | Lines to append in `~/.zshrc`. | + + +### Defaults + +Check [defaults/main.yml](defaults/main.yml) for default values. + + +| Variable | Type | Comments | +|-----------------------------------|----------|-----------------------------------------------------| +| zsh_default_prompt_name | string | Default prompt_name, `mlpure`. | +| zsh_default_prompt_download_url | string | Prompt download url, [mlpure](https://github.com/loliee/mlpure) | +| zsh_default_prompt_additional_url | text | `mlpure` async lib. |Ó + + +## Example Playbook + +The following playbook will ensure zsh is present for root user and will setup pure as prompt. This playbook will also append an alias in zshrc file. + +```yaml +# ./test/playbooks/configuration.yml +- hosts: localhost + remote_user: root + vars: + __users__: + root: + zsh_prompt_install: Yes + zsh_prompt_name: pure + zsh_prompt_download_url: https://raw.githubusercontent.com/sindresorhus/pure/master/pure.zsh + zsh_prompt_additional_url: https://raw.githubusercontent.com/sindresorhus/pure/master/async.zsh + zfunctions_directory: ./files/zfunctions + zshrc_content: | + alias ls='ls -lah' + + # Run + roles: + - zsh +``` + +## Run Tests + +Require [serverspec](http://serverspec.org/). +Check [.travis.yml](.travis.yml) for details. + +## Licence + +MIT © [Maxime Loliée](https://github.com/loliee.com/) diff --git a/README.rst b/README.rst deleted file mode 100644 index 80a63d8..0000000 --- a/README.rst +++ /dev/null @@ -1,86 +0,0 @@ -Ansible Role: ZSH -################# - -.. image:: https://travis-ci.org/loliee/ansible-zsh.svg?branch=master - :target: https://travis-ci.org/loliee/ansible-zsh - - -Install and set up `ZSH `_. -This role can also configure `~./zshrc` file and configure nice prompt (check `mlpure `_ for a nice, fast and customizable one !) - -Requirements -============ - -- RedHat family -- Debian family - -Role Variables -============== - -`zsh_users_config` ------------------- - -Unset by default, dictionary should defined like this: - -.. code:: yaml - - zsh_users_config: - [username]: - [option]: [value] - -**Options** - -+---------------------+----------+-----------------------------------------------+ -| parameter | type | comments | -+=====================+==========+===============================================+ -| default_shell | bool | Configure as default shell | -+---------------------+----------+-----------------------------------------------+ -| prompt_install | bool | Install prompt in ~/zfunctions/ ? | -+---------------------+----------+-----------------------------------------------+ -| prompt_name | string | Prompt name | -+---------------------+----------+-----------------------------------------------+ -| prompt_download_url | string | Prompt download url | -+---------------------+----------+-----------------------------------------------+ -| file_zshrc | text | Lines to append in ~/.zshrc | -+---------------------+----------+-----------------------------------------------+ - - -Example Playbook -================ - -The following playbook will ensure zsh is present for root user and will setup pure as prompt. This playbook will also append an alias in zshrc file. - - -.. code:: yaml - - # ./test/test_prompt.yml - - - hosts: localhost - remote_user: root - vars: - zsh_users_config: - root: - prompt_install: Yes - prompt_name: pure - prompt_download_url: > - https://raw.githubusercontent.com/sindresorhus/pure/master/pure.zsh - file_zshrc: | - alias ls='ls -lah' - - # Run - roles: - - zsh - -Run test, make sure ansible-zsh role is in your role path - -.. code:: bash - - sudo ansible-playbook -i ./tests/inventory ./tests/test_prompt.yml --connection=local - - -Check `.travis.yml <.travis.yml>`_ for detail - -Licence -======= - -MIT © `Maxime Loliée `_ diff --git a/defaults/main.yml b/defaults/main.yml new file mode 100644 index 0000000..b3232a9 --- /dev/null +++ b/defaults/main.yml @@ -0,0 +1,5 @@ +--- + +zsh_default_prompt_name: mlpure +zsh_default_prompt_download_url: https://raw.githubusercontent.com/loliee/mlpure/master/pure.zsh +zsh_default_prompt_additional_url: https://raw.githubusercontent.com/loliee/mlpure/master/async.zsh diff --git a/tasks/Config.yml b/tasks/Config.yml deleted file mode 100644 index 7a03442..0000000 --- a/tasks/Config.yml +++ /dev/null @@ -1,53 +0,0 @@ ---- -# Setup zshrc and prompt - -- name: Set as default shell - user: name={{ item.key }} shell=/bin/zsh - with_dict: zsh_users_config | default({}) - when: > - (ansible_os_family == 'RedHat' or ansible_os_family == 'Debian') and - (item.value.has_key('default_shell') and item.value.default_shell) - -- name: Generate ~.zshrc. - template: - mode=0644 - src=zshrc.j2 - owner={{ item.key }} - dest=~{{ item.key }}/.zshrc - with_dict: zsh_users_config | default({}) - when: > - (item.value.has_key('prompt_install') and item.value.prompt_install) or - (item.value.has_key('file_zshrc') and item.value.file_zshrc) - -- name: Check for .zsfunctions directory. - always_run: Yes - file: - state=directory - mode=0755 - owner={{ item.key }} - dest=~{{ item.key }}/.zfunctions - with_dict: zsh_users_config | default({}) - when: > - item.value.has_key('prompt_install') and item.value.prompt_install - -- fail: msg='Check user "{{ item.key }}" config dict ! "prompt_name" and "prompt_download_url" must set up if prompt_install is True.' - always_run: Yes - with_dict: zsh_users_config | default({}) - when: > - item.value.has_key('prompt_install') and item.value.prompt_install and - ( - (not item.value.has_key('prompt_name') and item.value.has_key('prompt_download_url')) or - (item.value.has_key('prompt_name') and not item.value.has_key('prompt_download_url')) - ) - -- name: Download zsh prompt file. - get_url: - mode=0744 - owner={{ item.key }} - url={{ item.value.prompt_download_url }} - dest=~{{ item.key }}/.zfunctions/prompt_{{ item.value.prompt_name }}_setup - - with_dict: zsh_users_config | default({}) - when: > - item.value.has_key('prompt_name') and - item.value.has_key('prompt_download_url') diff --git a/tasks/configure.yml b/tasks/configure.yml new file mode 100644 index 0000000..44133ed --- /dev/null +++ b/tasks/configure.yml @@ -0,0 +1,70 @@ +--- +# Setup zshrc and prompt + +- name: Set as default shell + user: name={{ item.key }} shell=/bin/zsh + with_dict: __users__ | default({}) + when: > + (ansible_os_family == 'RedHat' or ansible_os_family == 'Debian') and + (item.value.has_key('zsh_default_shell') and item.value.zsh_default_shell) + +- name: Generate ~.zshrc. + template: + mode=0644 + src=zshrc.j2 + owner={{ item.key }} + dest=~{{ item.key }}/.zshrc + with_dict: __users__ | default({}) + when: (item.value.has_key('zsh_default_shell') and item.value.zsh_default_shell) + +- name: Check for .zfunctions directory. + file: + state=directory + mode=0755 + owner={{ item.key }} + dest=~{{ item.key }}/.zfunctions + with_dict: __users__ | default({}) + when: (item.value.has_key('zsh_default_shell') and item.value.zsh_default_shell) + +- name: Upload zfunctions files + copy: + src=./{{ item.value.zsh_zfunctions_directory }}/ + dest=~{{ item.key }}/.zfunctions/ + owner={{ item.key }} + directory_mode=yes + force=yes + mode=0755 + with_dict: __users__ | default({}) + when: > + item.value.has_key('zsh_zfunctions_directory') + +- name: Download zsh prompt file. + get_url: + mode=0744 + owner={{ item.key }} + url={{ item.value.zsh_prompt_download_url | default(zsh_default_prompt_download_url) }} + dest=~{{ item.key }}/.zfunctions/prompt_{{ item.value.zsh_prompt_name | default(zsh_default_prompt_name) }}_setup + with_dict: __users__ | default({}) + when: item.value.has_key('zsh_prompt_install') and item.value.zsh_prompt_install + +- name: Download zsh prompt additional file. + get_url: + mode=0744 + owner={{ item.key }} + url={{ item.value.zsh_prompt_additional_url }} + dest=~{{ item.key }}/.zfunctions/{{ zsh_prompt_additional_url | basename | replace('.zsh', '') }} + with_dict: __users__ | default({}) + when: > + item.value.has_key('zsh_prompt_install') and item.value.zsh_prompt_install and + item.value.has_key('zsh_prompt_additional_url') and item.value.zsh_prompt_additional_url + +- name: Download zsh additional file if install default prompt. + get_url: + mode=0744 + owner={{ item.key }} + url={{ zsh_default_prompt_additional_url }} + dest=~{{ item.key }}/.zfunctions/{{ zsh_default_prompt_additional_url | basename | replace('.zsh', '') }} + with_dict: __users__ | default({}) + when: > + item.value.has_key('zsh_prompt_install') and item.value.zsh_prompt_install and not + item.value.has_key('zsh_prompt_name') diff --git a/tasks/main.yml b/tasks/main.yml index 3b536b8..a45d710 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -1,10 +1,10 @@ --- # Install and zsh package, set up zshrc. -- include: RedHat.yml - when: ansible_os_family == 'RedHat' - tags: - - packages +#- include: RedHat.yml +# when: ansible_os_family == 'RedHat' +# tags: +# - packages - include: Debian.yml when: ansible_os_family == 'Debian' @@ -17,6 +17,6 @@ tags: - test -- include: Config.yml +- include: configure.yml tags: - config diff --git a/templates/zshrc.j2 b/templates/zshrc.j2 index ca32df2..fb370a2 100644 --- a/templates/zshrc.j2 +++ b/templates/zshrc.j2 @@ -1,22 +1,21 @@ -# File managed by ansible, should not be modified. +# {{ ansible_managed }} -{% for username, options in zsh_users_config.iteritems() %} - {% if username == item.key %} +fpath=("$HOME/.zfunctions" $fpath) - {%- if options.has_key('prompt_install') and options.prompt_install %} +{%- for username, options in __users__.iteritems() %} + {%- if username == item.key %} + {# Install prompt #} + {%- if options.has_key('zsh_prompt_install') and options.zsh_prompt_install %} -fpath=( "$HOME/.zfunctions" $fpath ) autoload -U promptinit && promptinit -prompt {{ options.prompt_name }} +prompt {{ options.zsh_prompt_name | default(zsh_default_prompt_name) }} {%- endif %} + {# Add custom lines #} + {%- if options.has_key('zsh_zshrc_content') and options.zsh_zshrc_content %} - {%- if options.has_key('file_zshrc') and options.file_zshrc %} - -# Customs -{{ options.file_zshrc }} +{{ options.zsh_zshrc_content }} {%- endif %} - {% endif %} {% endfor %} diff --git a/tests/files/zfunctions/test.zsh b/tests/files/zfunctions/test.zsh new file mode 100644 index 0000000..1100654 --- /dev/null +++ b/tests/files/zfunctions/test.zsh @@ -0,0 +1 @@ +# Tests functions diff --git a/tests/playbooks/configure.yml b/tests/playbooks/configure.yml new file mode 100644 index 0000000..ef841a5 --- /dev/null +++ b/tests/playbooks/configure.yml @@ -0,0 +1,17 @@ +--- +# Test playbook: configure zsh. + +- hosts: localhost + remote_user: root + vars: + __users__: + mtester: + zsh_default_shell: Yes + zsh_prompt_install: Yes + zsh_zshrc_content: | + alias ll='ls -la' + + + # Run + roles: + - ansible-zsh diff --git a/tests/playbooks/install.yml b/tests/playbooks/install.yml new file mode 100644 index 0000000..8e9a9bd --- /dev/null +++ b/tests/playbooks/install.yml @@ -0,0 +1,7 @@ +--- +# Test playbook: package install + +- hosts: localhost + remote_user: root + roles: + - ansible-zsh diff --git a/tests/spec/before_test_spec.rb b/tests/spec/before_test_spec.rb new file mode 100644 index 0000000..3163f11 --- /dev/null +++ b/tests/spec/before_test_spec.rb @@ -0,0 +1,38 @@ +require 'serverspec' + +set :backend, :exec + +describe package('zsh') do + it { should_not be_installed } +end + +describe file('/home/mtester/.zfunctions/') do + it { should_not be_directory } +end + +describe file('/home/mtester/.zfunctions/prompt_mlpure_setup') do + it { should_not be_file } +end + +describe file('/home/mtester/.zfunctions/async') do + it { should_not be_file } +end + +describe file('/home/mtester/.zfunctions/prompt_mlpure_setup') do + it { should_not be_file } +end + +describe file('/home/mtester/.zshrc') do + its(:content) { should_not contain /# Ansible managed:/ } + its(:content) { should_not contain /autoload -U promptinit && promptinit/ } + its(:content) { should_not contain /prompt mlpure/ } + its(:content) { should_not contain /alias ll='ls -la'/ } +end + +describe user('mtester') do + it { should have_home_directory '/home/mtester' } +end + +describe user('mtester') do + it { should have_login_shell '/bin/bash' } +end diff --git a/tests/spec/configure_spec.rb b/tests/spec/configure_spec.rb new file mode 100644 index 0000000..cdad975 --- /dev/null +++ b/tests/spec/configure_spec.rb @@ -0,0 +1,26 @@ +require 'serverspec' + +set :backend, :exec + +describe file('/home/mtester/.zfunctions/') do + it { should be_directory } +end + +describe file('/home/mtester/.zfunctions/async') do + it { should be_file } +end + +describe file('/home/mtester/.zfunctions/prompt_mlpure_setup') do + it { should be_file } +end + +describe file('/home/mtester/.zshrc') do + its(:content) { should contain /# Ansible managed:/ } + its(:content) { should contain /autoload -U promptinit && promptinit/ } + its(:content) { should contain /prompt mlpure/ } + its(:content) { should contain /alias ll='ls -la'/ } +end + +describe user('mtester') do + it { should have_login_shell '/bin/zsh' } +end diff --git a/tests/spec/install_spec.rb b/tests/spec/install_spec.rb new file mode 100644 index 0000000..1fb5438 --- /dev/null +++ b/tests/spec/install_spec.rb @@ -0,0 +1,7 @@ +require 'serverspec' + +set :backend, :exec + +describe package('zsh') do + it { should be_installed } +end diff --git a/tests/test_install.yml b/tests/test_install.yml deleted file mode 100644 index 82965d6..0000000 --- a/tests/test_install.yml +++ /dev/null @@ -1,20 +0,0 @@ ---- -# Test playbook: package install - -- hosts: localhost - remote_user: root - roles: - - ansible-zsh - - tasks: - - name: Get zsh version - command: 'zsh --version' - ignore_errors: yes - register: zsh_version - - - name: Check zsh version - fail: msg="zsh install failed" - when: zsh_version.stdout.find('zsh 5') == -1 and zsh_version.stderr == '' - - - name: Display "zsh --version" results - debug: var=zsh_version.stdout diff --git a/tests/test_prompt.yml b/tests/test_prompt.yml deleted file mode 100644 index 30d1ada..0000000 --- a/tests/test_prompt.yml +++ /dev/null @@ -1,33 +0,0 @@ ---- -# Test playbook: Prompt install - -- hosts: localhost - remote_user: root - vars: - zsh_users_config: - root: - prompt_install: Yes - prompt_name: pure - prompt_download_url: > - https://raw.githubusercontent.com/sindresorhus/pure/master/pure.zsh - file_zshrc: | - alias ls='ls -lah' - # Run - roles: - - ansible-zsh - - # Test Result - tasks: - - name: Check if zfunctions was successfully created, just ls ... - shell: ls ~{{ item.key }}/.zfunctions - with_dict: zsh_users_config - register: ls_result - failed_when: ls_result.rc != 0 - always_run: True - - - name: Check if zsh_file_zshrc was correctly appended. - shell: 'grep "prompt {{ item.value.prompt_name }}" ~{{ item.key }}/.zshrc' - with_dict: zsh_users_config - register: grep_result - failed_when: grep_result.rc != 0 - always_run: True diff --git a/tests/test_zshrc.yml b/tests/test_zshrc.yml deleted file mode 100644 index 000f369..0000000 --- a/tests/test_zshrc.yml +++ /dev/null @@ -1,35 +0,0 @@ ---- -# Test playbook: Configuration ~/.zshrc - -- hosts: localhost - remote_user: root - vars: - zsh_users_config: - root: - file_zshrc: | - alias ll='ls -lah' - - roles: - - ansible-zsh - - tasks: - - name: Check if zshrc was successfully created, just ls ... - shell: ls ~{{ item.key }}/.zshrc - with_dict: zsh_users_config - register: ls_result - failed_when: ls_result.rc != 0 - always_run: True - - - name: Check if lines was correctly appended in .zshrc. - shell: grep "alias ll='ls -lah'" ~{{ item.key }}/.zshrc - with_dict: zsh_users_config - register: grep_result - failed_when: grep_result.rc != 0 - always_run: True - - - name: Check if no prompt config added in zshrc. - shell: 'grep "autoload -U promptinit && promptinit" ~{{ item.key }}/.zshrc' - with_dict: zsh_users_config - register: grep_result - failed_when: grep_result.rc == 0 - always_run: True