├── .ansible-lint ├── .editorconfig ├── .gitattributes ├── .github └── workflows │ └── pipeline.yml ├── .gitignore ├── .markdownlint.json ├── .pre-commit-config.yaml ├── .yamllint ├── CHANGELOG.md ├── LICENSE ├── Makefile ├── README.md ├── defaults └── main.yml ├── meta └── main.yml ├── tasks ├── install │ ├── debian.yml │ ├── install.yml │ ├── redhat.yml │ ├── with_git.yml │ └── with_installer.yml ├── main.yml └── shell │ ├── bash.yml │ ├── shell.yml │ └── zsh.yml ├── tests ├── debian-bullseye │ └── Dockerfile ├── debian-buster │ └── Dockerfile ├── fedora-37 │ └── Dockerfile ├── inventory ├── run-tests ├── run-tests-with-git ├── run-tests-with-installer ├── test.yml ├── ubuntu-bionic │ └── Dockerfile ├── ubuntu-focal │ └── Dockerfile └── ubuntu-jammy │ └── Dockerfile └── vars ├── main.yml └── os ├── Debian.yml ├── Pengwin.yml ├── RedHat.yml └── Ubuntu.yml /.ansible-lint: -------------------------------------------------------------------------------- 1 | --- 2 | exclude_paths: 3 | - .ansible-lint 4 | - .github/ 5 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig: https://editorconfig.org 2 | root = true 3 | 4 | # Unix-style newlines with a newline ending every file 5 | [*] 6 | end_of_line = lf 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | charset = utf-8 10 | 11 | # Shell scripts without extension 12 | [{tests/run-*,tests/update}] 13 | indent_style = space 14 | indent_size = 4 15 | 16 | # Shell scripts 17 | [{*.sh}] 18 | indent_style = space 19 | indent_size = 4 20 | 21 | # Markdown files 22 | [*.md] 23 | indent_style = space 24 | indent_size = 2 25 | 26 | # YAML files 27 | [{*.yml,*.yaml}] 28 | indent_style = space 29 | indent_size = 2 30 | 31 | # YAML files without extension 32 | [{.ansible-lint,.yamllint}] 33 | indent_style = space 34 | indent_size = 2 35 | 36 | # JSON files 37 | [{*.json}] 38 | indent_style = space 39 | indent_size = 2 40 | 41 | # Dockerfile 42 | [{Dockerfile,Dockerfile.template}] 43 | indent_style = space 44 | indent_size = 2 45 | 46 | # Makefile 47 | [Makefile] 48 | indent_style = tab 49 | indent_size = 2 50 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Autodetect text files 2 | * text=auto 3 | 4 | *.yml text eol=lf 5 | *.yaml text eol=lf 6 | *.md text eol=lf 7 | -------------------------------------------------------------------------------- /.github/workflows/pipeline.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Test and release 3 | 4 | # This workflow is triggered on pushes to the repository. 5 | on: 6 | pull_request: 7 | branches: 8 | - "**" 9 | push: 10 | branches: 11 | - master 12 | tags: 13 | - v.* 14 | release: 15 | types: [published] 16 | 17 | jobs: 18 | lint: 19 | name: Lint with pre-commit 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: actions/checkout@v3 23 | 24 | - uses: actions/setup-node@v3 25 | with: 26 | node-version: "18" 27 | 28 | - uses: actions/setup-python@v3 29 | with: 30 | python-version: "3.11" 31 | 32 | - uses: actions/setup-go@v3 33 | with: 34 | go-version: "1.19" 35 | 36 | - name: Install dependencies 37 | run: | 38 | pip3 install pre-commit 39 | go install mvdan.cc/sh/v3/cmd/shfmt@latest 40 | sudo apt-get install -y shellcheck 41 | python --version 42 | shfmt -version 43 | shellcheck --version 44 | pre-commit --version 45 | 46 | - name: Cache pre-commit dependencies 47 | uses: actions/cache@v3 48 | with: 49 | path: ~/.cache/pre-commit/ 50 | # yamllint disable-line rule:line-length 51 | key: ${{ runner.os }}-pre-commit-${{ hashFiles('**/.pre-commit-config.yaml') }} 52 | restore-keys: | 53 | ${{ runner.os }}-pre-commit- 54 | 55 | - name: Run pre-commit 56 | run: pre-commit run -a 57 | 58 | ubuntu: 59 | runs-on: ubuntu-latest 60 | strategy: 61 | matrix: 62 | distrib: [ubuntu] 63 | release: [focal, jammy, bionic] 64 | 65 | name: Test on ${{ matrix.distrib }}:${{ matrix.release }} 66 | env: 67 | DISTRIB: ${{ matrix.distrib }} 68 | RELEASE: ${{ matrix.release }} 69 | steps: 70 | - uses: actions/checkout@v3 71 | 72 | - name: Run tests on ${{ matrix.distrib }}:${{ matrix.release }} 73 | run: ./tests/run-tests ${DISTRIB}-${RELEASE} 74 | 75 | debian: 76 | runs-on: ubuntu-latest 77 | strategy: 78 | matrix: 79 | distrib: [debian] 80 | release: [bullseye, buster] 81 | 82 | name: Test on ${{ matrix.distrib }}:${{ matrix.release }} 83 | env: 84 | DISTRIB: ${{ matrix.distrib }} 85 | RELEASE: ${{ matrix.release }} 86 | steps: 87 | - uses: actions/checkout@v3 88 | 89 | - name: Run tests on ${{ matrix.distrib }}:${{ matrix.release }} 90 | run: ./tests/run-tests ${DISTRIB}-${RELEASE} 91 | 92 | fedora: 93 | runs-on: ubuntu-latest 94 | strategy: 95 | matrix: 96 | distrib: [fedora] 97 | release: [37] 98 | 99 | name: Test on ${{ matrix.distrib }}:${{ matrix.release }} 100 | env: 101 | DISTRIB: ${{ matrix.distrib }} 102 | RELEASE: ${{ matrix.release }} 103 | steps: 104 | - uses: actions/checkout@v3 105 | 106 | - name: Run tests on ${{ matrix.distrib }}:${{ matrix.release }} 107 | run: ./tests/run-tests ${DISTRIB}-${RELEASE} 108 | 109 | release: 110 | name: Publish tagged releases to Ansible Galaxy 111 | needs: 112 | - lint 113 | - ubuntu 114 | - debian 115 | - fedora 116 | runs-on: ubuntu-latest 117 | if: startsWith(github.ref, 'refs/tags/v') 118 | steps: 119 | - name: galaxy 120 | uses: robertdebock/galaxy-action@1.2.0 121 | with: 122 | galaxy_api_key: ${{ secrets.GALAXY_API_KEY }} 123 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.retry 2 | ansible.cfg 3 | 4 | # VSCode 5 | .vscode/* 6 | -------------------------------------------------------------------------------- /.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "default": true, 3 | "heading-style": { 4 | "style": "atx" 5 | }, 6 | "line-length": { 7 | "code_blocks": false, 8 | "tables": false 9 | }, 10 | "no-duplicate-heading": { 11 | "siblings_only": true 12 | }, 13 | "code-block-style": { 14 | "style": "fenced" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | repos: 3 | - repo: https://github.com/pre-commit/pre-commit-hooks.git 4 | rev: v4.4.0 5 | hooks: 6 | - id: check-executables-have-shebangs 7 | - id: check-byte-order-marker 8 | - id: check-case-conflict 9 | - id: check-merge-conflict 10 | - id: trailing-whitespace 11 | args: ["--markdown-linebreak-ext=md"] 12 | - id: end-of-file-fixer 13 | - id: mixed-line-ending 14 | args: ["--fix=lf"] 15 | - id: check-yaml 16 | - id: pretty-format-json 17 | args: ["--autofix", "--indent=2", "--no-sort-keys"] 18 | 19 | - repo: https://github.com/adrienverge/yamllint.git 20 | rev: v1.29.0 21 | hooks: 22 | - id: yamllint 23 | 24 | - repo: https://github.com/ansible/ansible-lint.git 25 | rev: v6.13.1 26 | hooks: 27 | - id: ansible-lint 28 | files: \.(yaml|yml)$ 29 | exclude: .github/workflows/pipeline.yml 30 | 31 | - repo: https://github.com/syntaqx/git-hooks 32 | rev: v0.0.17 33 | hooks: 34 | - id: shellcheck 35 | files: (tests/run-.*|tests/update)$ 36 | 37 | - repo: https://github.com/scop/pre-commit-shfmt 38 | rev: v3.6.0-1 39 | hooks: 40 | - id: shfmt 41 | files: (tests/run-.*|tests/update)$ 42 | 43 | - repo: https://github.com/igorshubovych/markdownlint-cli.git 44 | rev: v0.33.0 45 | hooks: 46 | - id: markdownlint 47 | -------------------------------------------------------------------------------- /.yamllint: -------------------------------------------------------------------------------- 1 | # -*- mode: yaml -*- 2 | # vim:ts=2:sw=2:ai:si:syntax=yaml 3 | # 4 | # yamllint configuration directives 5 | # Project Homepage: https://github.com/adrienverge/yamllint 6 | # 7 | # Overriding rules in files: 8 | # http://yamllint.readthedocs.io/en/latest/disable_with_comments.html 9 | --- 10 | extends: default 11 | 12 | # Rules documentation: http://yamllint.readthedocs.io/en/latest/rules.html 13 | rules: 14 | 15 | document-start: 16 | present: true 17 | 18 | indentation: 19 | # Requiring 2 space indentation 20 | spaces: 2 21 | # Requiring consistent indentation within a file, either indented or not 22 | indent-sequences: true 23 | # Lint indentation in multi-line strings 24 | check-multi-line-strings: false 25 | 26 | line-length: 27 | max: 80 28 | level: warning 29 | allow-non-breakable-inline-mappings: true 30 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [2.0.2] - 2023-02-17 4 | 5 | Fix Ansible Galaxy API key for automated role publishing. 6 | 7 | [2.0.2]: https://github.com/markosamuli/ansible-linuxbrew/releases/tag/v2.0.2 8 | 9 | ## [2.0.1] - 2023-02-17 10 | 11 | Run GitHub Actions workflow when new release is published. 12 | 13 | [2.0.1]: https://github.com/markosamuli/ansible-linuxbrew/releases/tag/v2.0.1 14 | 15 | ## [2.0.0] - 2023-02-17 16 | 17 | Support for RedHat-based systems and latest Ansible versions. 18 | 19 | [2.0.0]: https://github.com/markosamuli/ansible-linuxbrew/releases/tag/v2.0.0 20 | 21 | ### Ansible compatibility 22 | 23 | - Require Ansible 2.9.22 24 | - Support Ansible 7.2.0 25 | - Use fully qualified collection names (FQCN) with builtin modules 26 | 27 | ### Fixes 28 | 29 | - Use `become_user` instead of `become` when installing with Git by [@Hunsu] in [#6] 30 | - Remove installer script checksum that causes issues [#10] 31 | 32 | [@hunsu]: https://github.com/Hunsu 33 | [#6]: https://github.com/markosamuli/ansible-linuxbrew/pull/6 34 | [#10]: https://github.com/markosamuli/ansible-linuxbrew/issues/10 35 | 36 | ### Python compatibility 37 | 38 | - Use Python 3 on all test Docker images 39 | - Drop support for EOL Python 2.7 40 | 41 | ### OS compatibility 42 | 43 | - Add support for Ubuntu 20.04 LTS and 22.04 LTS 44 | - Add support for Debian 11 45 | - Add support for Fedora 37 and RedHat based-systems by [@aarey] in [#9] 46 | - Drop support for Debian 11 47 | - Drop support for Ubuntu 16.04 LTS 48 | 49 | [@aarey]: https://github.com/aairey 50 | [#9]: https://github.com/markosamuli/ansible-linuxbrew/pull/9 51 | 52 | ### Testing 53 | 54 | - Run tests with supported Docker images on GitHub Actions 55 | 56 | ## [1.2.2] - 2020-09-06 57 | 58 | ### Fixed 59 | 60 | - Update `install.sh` checksum 61 | - Create missing `var/homebrew/linked` directory 62 | - Update `linuxbrew-core` repository URL 63 | 64 | ## [1.2.1] - 2020-09-05 65 | 66 | ### Fixed 67 | 68 | - Migrate to the new `install.sh` script 69 | 70 | ## [1.2.0] - 2019-10-25 71 | 72 | ### Changes 73 | 74 | - Add `linuxbrew_init_shell` variable to allow shell file modification to be 75 | disabled. Fixes [#1] 76 | 77 | ## [1.1.1] - 2019-07-20 78 | 79 | ### Fixes 80 | 81 | - Updated `install.sh` checksum for the 2019-07-18 updated version. 82 | 83 | ## [1.1.0] - 2019-07-14 84 | 85 | ### Changes 86 | 87 | - Use Ansible tasks to clone the Homebrew Git repositories, create directories 88 | and set permissions where possible instead of using the official installer 89 | bash script. 90 | 91 | ### Fixes 92 | 93 | - Install installation dependencies. 94 | - Update both `.bashrc` and `.zshrc` shell scripts. 95 | 96 | ## [1.0.0] - 2019-01-13 97 | 98 | Initial release using the official Homebrew installer. 99 | 100 | [1.2.2]: https://github.com/markosamuli/ansible-linuxbrew/releases/tag/v1.2.2 101 | [1.2.1]: https://github.com/markosamuli/ansible-linuxbrew/releases/tag/v1.2.1 102 | [1.2.0]: https://github.com/markosamuli/ansible-linuxbrew/releases/tag/v1.2.0 103 | [1.1.1]: https://github.com/markosamuli/ansible-linuxbrew/releases/tag/v1.1.1 104 | [1.1.0]: https://github.com/markosamuli/ansible-linuxbrew/releases/tag/v1.1.0 105 | [1.0.0]: https://github.com/markosamuli/ansible-linuxbrew/releases/tag/v1.0.0 106 | [#1]: https://github.com/markosamuli/ansible-linuxbrew/issues/1 107 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2009-present, Homebrew contributors 4 | Copyright (c) 2017-present, Marko Samuli Kirves 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | .DEFAULT_GOAL := help 3 | 4 | # Use VERBOSE=1 make to get verbose output 5 | ifndef VERBOSE 6 | .SILENT: 7 | endif 8 | 9 | .PHONY: help 10 | help: ## print this help 11 | @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort -d | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' 12 | @echo "" 13 | $(MAKE) list-images 14 | 15 | PRE_COMMIT_HOOKS = .git/hooks/pre-commit 16 | 17 | TEST_IMAGES = $(shell ls tests/*/Dockerfile | xargs dirname | xargs basename) 18 | 19 | .PHONY: setup 20 | setup: $(PRE_COMMIT_HOOKS) 21 | 22 | .PHONY: test 23 | test: ## run tests with all available Docker images 24 | ./tests/run-tests 25 | 26 | .PHONY: list-images 27 | list-images: ## list available test images 28 | @echo "Available test images:" 29 | @for i in $(TEST_IMAGES); do echo "$$i" | awk '{printf "\033[36m%-30s\033[0m run tests with %s\n", $$1, $$1}'; done 30 | 31 | .PHONY: $(TEST_IMAGES) 32 | $(TEST_IMAGES): 33 | ./tests/run-tests $@ 34 | 35 | .PHONY: lint 36 | lint: $(PRE_COMMIT_HOOKS) 37 | pre-commit run -a 38 | 39 | $(PRE_COMMIT_HOOKS): 40 | pre-commit install 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ansible-linuxbrew 2 | 3 | [![Test and release](https://github.com/markosamuli/ansible-linuxbrew/actions/workflows/pipeline.yml/badge.svg?branch=master)](https://github.com/markosamuli/ansible-linuxbrew/actions/workflows/pipeline.yml) 4 | [![Ansible Quality Score](https://img.shields.io/ansible/quality/42044.svg)](https://galaxy.ansible.com/markosamuli/linuxbrew) 5 | [![Ansible Role](https://img.shields.io/ansible/role/42044.svg)](https://galaxy.ansible.com/markosamuli/linuxbrew) 6 | [![GitHub release](https://img.shields.io/github/release/markosamuli/ansible-linuxbrew.svg)](https://github.com/markosamuli/ansible-linuxbrew/releases) 7 | [![License](https://img.shields.io/github/license/markosamuli/ansible-linuxbrew.svg)](https://github.com/markosamuli/ansible-linuxbrew/blob/master/LICENSE) 8 | 9 | Ansible role to install [Homebrew](https://brew.sh/) on Linux. 10 | 11 | ## Compatibility 12 | 13 | Run tests with a supported Docker image, for example with `bionic`: 14 | 15 | ```bash 16 | make bionic 17 | ``` 18 | 19 | | Release | Docker image | Ansible | 20 | | ---------------- | ------------------------------------ | ---------------- | 21 | | Debian 10 | [`debian-buster`][debian-buster] | `<2.12,>=2.9.22` | 22 | | Debian 11 | [`debian-bullseye`][debian-bullseye] | `>=2.9.22` | 23 | | Fedora 37 | [`fedora-37`][fedora-37] | `>=2.9.22` | 24 | | Ubuntu 18.04 LTS | [`ubuntu-bionic`][ubuntu-bionic] | `<2.12,>=2.9.22` | 25 | | Ubuntu 20.04 LTS | [`ubuntu-focal`][ubuntu-focal] | `>=2.9.22` | 26 | | Ubuntu 22.04 LTS | [`ubuntu-jammy`][ubuntu-jammy] | `>=2.9.22` | 27 | 28 | If you want to add a new distribution or release version, please create a 29 | Docker image for it under the `tests/` directory and make sure the existing 30 | tests work. 31 | 32 | I'm developing this role currently in a black box using the Docker images 33 | included in the repository and not running it on live environments. 34 | 35 | [ubuntu-bionic]: tests/ubuntu-bionic/Dockerfile 36 | [ubuntu-focal]: tests/ubuntu-focal/Dockerfile 37 | [ubuntu-jammy]: tests/ubuntu-jammy/Dockerfile 38 | [debian-buster]: tests/debian-buster/Dockerfile 39 | [debian-bullseye]: tests/debian-bullseye/Dockerfile 40 | [fedora-37]: tests/fedora-37/Dockerfile 41 | 42 | ## Configuration 43 | 44 | By default, the role uses Ansible to clone the Homebrew Git repository and 45 | create all relevant directories. 46 | 47 | To use the official [Homebrew installer][homebrew-installer] script instead, 48 | you need to enable this in the Ansible configuration: 49 | 50 | ```yaml 51 | linuxbrew_use_installer: true 52 | ``` 53 | 54 | The installer seems to be faster than the default Ansible installation method. 55 | 56 | ## Role Variables 57 | 58 | Set `linuxbrew_init_shell` to `false` if you're for example managing your shell 59 | init files using your own `.dotfiles` repository. 60 | 61 | ```yaml 62 | # Configure shell rc files 63 | linuxbrew_init_shell: true 64 | ``` 65 | 66 | ## Coding style 67 | 68 | Install pre-commit hooks and validate coding style: 69 | 70 | ```bash 71 | make lint 72 | ``` 73 | 74 | ## Run tests 75 | 76 | Run tests in Ubuntu and Debian using Docker: 77 | 78 | ```bash 79 | make test 80 | ``` 81 | 82 | ## License 83 | 84 | - [BSD License](LICENSE) 85 | 86 | ## Contributing 87 | 88 | I'm not actively using or maintaining this role, but welcome bug fixes and 89 | support for missing operating systems. 90 | 91 | ## Contributions 92 | 93 | The installation is based on the official [Homebrew installer][homebrew-installer] 94 | script. 95 | 96 | [homebrew-installer]: https://github.com/Homebrew/install 97 | 98 | ## Author information 99 | 100 | - [@markosamuli](https://github.com/markosamuli) 101 | -------------------------------------------------------------------------------- /defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Path to user home directory 3 | linuxbrew_home: "{{ ansible_env.HOME }}" 4 | 5 | # Installation under user home directory 6 | linuxbrew_prefix_user: "{{ linuxbrew_home }}/.linuxbrew" 7 | 8 | # Install using the installer script 9 | linuxbrew_use_installer: false 10 | 11 | # Configure shell rc files 12 | linuxbrew_init_shell: true 13 | -------------------------------------------------------------------------------- /meta/main.yml: -------------------------------------------------------------------------------- 1 | # -*- mode: yaml -*- 2 | # vim:ts=2:sw=2:ai:si:syntax=yaml 3 | --- 4 | galaxy_info: 5 | role_name: linuxbrew 6 | namespace: markosamuli 7 | author: Marko Samuli Kirves 8 | description: Install Homebrew on Linux 9 | license: BSD 10 | min_ansible_version: 2.9.22 11 | github_branch: master 12 | platforms: 13 | - name: Ubuntu 14 | versions: 15 | - bionic 16 | - focal 17 | - jammy 18 | - name: Debian 19 | versions: 20 | - buster 21 | - bullseye 22 | - name: Fedora 23 | versions: 24 | - "37" 25 | galaxy_tags: 26 | - linuxbrew 27 | - homebrew 28 | - packaging 29 | - system 30 | dependencies: [] 31 | -------------------------------------------------------------------------------- /tasks/install/debian.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install dependencies with APT 3 | ansible.builtin.apt: 4 | name: "{{ linuxbrew_install_dependencies }}" 5 | when: linuxbrew_install_dependencies is defined 6 | become: true 7 | -------------------------------------------------------------------------------- /tasks/install/install.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install dependencies on Debian based systems 3 | ansible.builtin.include_tasks: debian.yml 4 | when: "ansible_os_family == 'Debian' or ansible_distribution == 'Pengwin'" 5 | 6 | - name: Install dependencies on RedHat based systems 7 | ansible.builtin.include_tasks: redhat.yml 8 | when: "ansible_os_family == 'RedHat'" 9 | 10 | - name: Install with Git 11 | ansible.builtin.include_tasks: with_git.yml 12 | when: not linuxbrew_use_installer 13 | 14 | - name: Install using the installer script 15 | ansible.builtin.include_tasks: with_installer.yml 16 | when: linuxbrew_use_installer 17 | -------------------------------------------------------------------------------- /tasks/install/redhat.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install dependencies with yum 3 | ansible.builtin.yum: 4 | name: "{{ linuxbrew_install_dependencies }}" 5 | state: present 6 | when: linuxbrew_install_dependencies is defined 7 | become: true 8 | -------------------------------------------------------------------------------- /tasks/install/with_git.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Get current user 3 | ansible.builtin.command: whoami 4 | register: linuxbrew_whoami 5 | changed_when: false 6 | become: false 7 | 8 | - name: Set Linuxbrew user 9 | ansible.builtin.set_fact: 10 | linuxbrew_user: "{{ linuxbrew_whoami.stdout }}" 11 | when: linuxbrew_user is undefined 12 | 13 | - name: Get group for user {{ linuxbrew_user }} 14 | ansible.builtin.command: id -g 15 | register: linuxbrew_user_group 16 | become_user: "{{ linuxbrew_user }}" 17 | changed_when: false 18 | 19 | - name: Set Linuxbrew group 20 | ansible.builtin.set_fact: 21 | linuxbrew_group: "{{ linuxbrew_user_group.stdout }}" 22 | when: linuxbrew_group is undefined 23 | 24 | - name: Create Linuxbrew directory 25 | ansible.builtin.file: 26 | path: "{{ linuxbrew_prefix_shared }}" 27 | state: directory 28 | owner: "{{ linuxbrew_user }}" 29 | group: "{{ linuxbrew_group }}" 30 | mode: "0755" 31 | become: true 32 | 33 | - name: Create Linuxbrew directories 34 | ansible.builtin.file: 35 | path: "{{ linuxbrew_prefix_shared }}/{{ item }}" 36 | state: directory 37 | owner: "{{ linuxbrew_user }}" 38 | group: "{{ linuxbrew_group }}" 39 | mode: "0755" 40 | with_items: 41 | - bin 42 | - etc 43 | - include 44 | - lib 45 | - sbin 46 | - share 47 | - var 48 | - var/homebrew/linked 49 | - opt 50 | - share/zsh 51 | - share/zsh/site-functions 52 | - Cellar 53 | - Caskroom 54 | - Homebrew 55 | - Frameworks 56 | 57 | - name: Set path to Homebrew repository 58 | ansible.builtin.set_fact: 59 | linuxbrew_repository: "{{ linuxbrew_prefix_shared }}/Homebrew" 60 | 61 | - name: Clone Homebrew repository 62 | ansible.builtin.git: 63 | repo: "{{ linuxbrew_brew_repo }}" 64 | dest: "{{ linuxbrew_repository }}" 65 | version: "{{ linuxbrew_brew_version }}" 66 | 67 | - name: Clone Homebrew Core Tap repository 68 | ansible.builtin.git: 69 | repo: "{{ linuxbrew_core_tap_repo }}" 70 | dest: "{{ linuxbrew_repository }}/Library/Taps/homebrew/homebrew-core" 71 | version: "{{ linuxbrew_core_tap_version }}" 72 | 73 | - name: Update permissions 74 | ansible.builtin.file: 75 | path: "{{ item }}" 76 | owner: "{{ linuxbrew_user }}" 77 | group: "{{ linuxbrew_group }}" 78 | mode: "0755" 79 | with_items: 80 | - "{{ linuxbrew_repository }}" 81 | - "{{ linuxbrew_repository }}/Library/Taps/homebrew/homebrew-core" 82 | 83 | - name: Create symlink to brew binary 84 | ansible.builtin.file: 85 | dest: "{{ linuxbrew_prefix_shared }}/bin/brew" 86 | src: "{{ linuxbrew_repository }}/bin/brew" 87 | state: "link" 88 | when: linuxbrew_prefix_shared != linuxbrew_repository 89 | 90 | - name: Path to portable-ruby vendor directory 91 | ansible.builtin.set_fact: 92 | # yamllint disable-line rule:line-length 93 | linuxbrew_ruby_current: "{{ linuxbrew_repository }}/vendor/portable-ruby/current" 94 | 95 | - name: Path to portable-ruby binary 96 | ansible.builtin.set_fact: 97 | linuxbrew_ruby_path: "{{ linuxbrew_ruby_current }}/bin/ruby" 98 | 99 | - name: Update Homebrew to install portable Ruby 100 | # yamllint disable-line rule:line-length 101 | ansible.builtin.command: "{{ linuxbrew_prefix_shared }}/bin/brew update --force" 102 | args: 103 | creates: "{{ linuxbrew_ruby_path }}" 104 | -------------------------------------------------------------------------------- /tasks/install/with_installer.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Temporary directory 3 | ansible.builtin.file: 4 | path: "{{ linuxbrew_install_tmp }}" 5 | state: directory 6 | mode: 0700 7 | become: false 8 | 9 | - name: Download Homebrew install script 10 | ansible.builtin.get_url: 11 | url: "{{ linuxbrew_install_url }}" 12 | dest: "{{ linuxbrew_install_tmp }}/install.sh" 13 | checksum: "{{ linuxbrew_install_checksum | default(omit) }}" 14 | mode: 0700 15 | become: false 16 | 17 | - name: Install Homebrew with the installer 18 | ansible.builtin.command: sh -c "{{ linuxbrew_install_tmp }}/install.sh" 19 | register: install_result 20 | changed_when: "install_result.rc == 0" 21 | become: false 22 | 23 | - name: Remove temporary directory 24 | ansible.builtin.file: 25 | path: "{{ linuxbrew_install_tmp }}" 26 | state: absent 27 | become: false 28 | -------------------------------------------------------------------------------- /tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # tasks file for markosamuli.linuxbrew 3 | 4 | - name: Load variables for the target system 5 | ansible.builtin.include_vars: "{{ item }}" 6 | with_first_found: 7 | - "os/{{ ansible_distribution }}.yml" 8 | - "os/{{ ansible_os_family }}.yml" 9 | 10 | - name: Check if Linuxbrew is already installed in {{ linuxbrew_prefix_shared }} 11 | ansible.builtin.stat: 12 | path: "{{ linuxbrew_prefix_shared }}/bin/brew" 13 | register: linuxbrew_shared_st 14 | become: true 15 | 16 | - name: Check if Linuxbrew is already installed in {{ linuxbrew_prefix_user }} 17 | ansible.builtin.stat: 18 | path: "{{ linuxbrew_prefix_user }}/bin/brew" 19 | register: linuxbrew_user_st 20 | become: false 21 | 22 | - name: Install Linuxbrew 23 | ansible.builtin.include_tasks: install/install.yml 24 | when: not linuxbrew_shared_st.stat.exists 25 | and not linuxbrew_user_st.stat.exists 26 | 27 | - name: Configure Linuxbrew in shell 28 | ansible.builtin.include_tasks: shell/shell.yml 29 | when: linuxbrew_init_shell|bool 30 | -------------------------------------------------------------------------------- /tasks/shell/bash.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Find .bash_profile and .profile files 3 | block: 4 | - name: Set path to .bash_profile 5 | ansible.builtin.set_fact: 6 | linuxbrew_bash_profile_path: "{{ linuxbrew_home }}/.bash_profile" 7 | when: linuxbrew_bash_profile_path is undefined 8 | 9 | - name: Check whether .bash_profile exists 10 | ansible.builtin.stat: 11 | path: "{{ linuxbrew_bash_profile_path }}" 12 | register: linuxbrew_bash_profile_st 13 | 14 | - name: Set path to .profile 15 | ansible.builtin.set_fact: 16 | linuxbrew_profile_path: "{{ linuxbrew_home }}/.profile" 17 | when: linuxbrew_profile_path is undefined 18 | 19 | - name: Check whether .profile exists 20 | ansible.builtin.stat: 21 | path: "{{ linuxbrew_profile_path }}" 22 | register: linuxbrew_profile_st 23 | 24 | - name: Configure .bash_profile (if it exists) 25 | when: linuxbrew_bash_profile_st.stat.exists 26 | block: 27 | - name: Resolve .bash_profile symlink 28 | ansible.builtin.set_fact: 29 | # yamllint disable-line rule:line-length 30 | linuxbrew_bash_profile_path: "{{ linuxbrew_bash_profile_st.stat.lnk_source }}" 31 | when: 32 | - linuxbrew_bash_profile_st.stat.exists 33 | - linuxbrew_bash_profile_st.stat.islnk 34 | 35 | - name: Check whether Homebrew is loaded in .bash_profile 36 | ansible.builtin.command: >- 37 | grep -Fq 'brew shellenv' {{ linuxbrew_bash_profile_path }} 38 | register: check_bash_profile 39 | ignore_errors: true 40 | changed_when: false 41 | failed_when: false 42 | when: linuxbrew_bash_profile_st.stat.exists 43 | 44 | - name: Load Homebrew in .bash_profile 45 | ansible.builtin.blockinfile: 46 | dest: "{{ linuxbrew_bash_profile_path }}" 47 | marker: "# {mark} ANSIBLE MANAGED BLOCK: linuxbrew" 48 | block: | 49 | eval $({{ linuxbrew_prefix }}/bin/brew shellenv) 50 | when: 51 | - linuxbrew_bash_profile_st.stat.exists 52 | - check_bash_profile.rc != 0 53 | 54 | - name: Create new .bash_profile 55 | ansible.builtin.blockinfile: 56 | dest: "{{ linuxbrew_bash_profile_path }}" 57 | create: true 58 | mode: "0644" 59 | marker: "# {mark} ANSIBLE MANAGED BLOCK: linuxbrew" 60 | block: | 61 | eval $({{ linuxbrew_prefix }}/bin/brew shellenv) 62 | when: not linuxbrew_bash_profile_st.stat.exists 63 | 64 | - name: Configure .profile (if it exists) 65 | when: not linuxbrew_bash_profile_st.stat.exists 66 | block: 67 | - name: Resolve .profile symlink 68 | ansible.builtin.set_fact: 69 | linuxbrew_profile_path: "{{ linuxbrew_profile_st.stat.lnk_source }}" 70 | when: 71 | - linuxbrew_profile_st.stat.exists 72 | - linuxbrew_profile_st.stat.islnk 73 | 74 | - name: Check whether Homebrew is loaded in .profile 75 | ansible.builtin.command: >- 76 | grep -Fq 'brew shellenv' {{ linuxbrew_profile_path }} 77 | register: check_profile 78 | ignore_errors: true 79 | changed_when: false 80 | failed_when: false 81 | when: linuxbrew_profile_st.stat.exists 82 | 83 | - name: Load Homebrew in .profile 84 | ansible.builtin.blockinfile: 85 | dest: "{{ linuxbrew_profile_path }}" 86 | marker: "# {mark} ANSIBLE MANAGED BLOCK: linuxbrew" 87 | block: | 88 | eval $({{ linuxbrew_prefix }}/bin/brew shellenv) 89 | when: 90 | - linuxbrew_profile_st.stat.exists 91 | - check_profile.rc != 0 92 | 93 | - name: Create new .profile 94 | ansible.builtin.blockinfile: 95 | dest: "{{ linuxbrew_profile_path }}" 96 | create: true 97 | mode: "0644" 98 | marker: "# {mark} ANSIBLE MANAGED BLOCK: linuxbrew" 99 | block: | 100 | eval $({{ linuxbrew_prefix }}/bin/brew shellenv) 101 | when: not linuxbrew_profile_st.stat.exists 102 | 103 | - name: Configure .bashrc (if it exists) 104 | block: 105 | - name: Set path to .bashrc 106 | ansible.builtin.set_fact: 107 | linuxbrew_bashrc_path: "{{ linuxbrew_home }}/.bashrc" 108 | when: linuxbrew_bashrc_path is undefined 109 | 110 | - name: Check whether .bashrc file exists 111 | ansible.builtin.stat: 112 | path: "{{ linuxbrew_bashrc_path }}" 113 | register: linuxbrew_bashrc_st 114 | 115 | - name: Resolve .bashrc symlink 116 | ansible.builtin.set_fact: 117 | linuxbrew_bashrc_path: "{{ linuxbrew_bashrc_st.stat.lnk_source }}" 118 | when: 119 | - linuxbrew_bashrc_st.stat.exists 120 | - linuxbrew_bashrc_st.stat.islnk 121 | 122 | - name: Check whether Homebrew is loaded in .bashrc 123 | ansible.builtin.command: >- 124 | grep -EFq 'brew shellenv' {{ linuxbrew_bashrc_path }} 125 | register: check_bashrc_linuxbrew 126 | ignore_errors: true 127 | changed_when: false 128 | failed_when: false 129 | when: linuxbrew_bashrc_st.stat.exists 130 | 131 | - name: Load Homebrew in .bashrc 132 | ansible.builtin.blockinfile: 133 | dest: "{{ linuxbrew_bashrc_path }}" 134 | marker: "# {mark} ANSIBLE MANAGED BLOCK: linuxbrew" 135 | block: | 136 | eval $({{ linuxbrew_prefix }}/bin/brew shellenv) 137 | when: 138 | - linuxbrew_bashrc_st.stat.exists 139 | - check_bashrc_linuxbrew.rc != 0 140 | -------------------------------------------------------------------------------- /tasks/shell/shell.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Set path to Linuxbrew prefix 3 | ansible.builtin.set_fact: 4 | linuxbrew_prefix: "{{ item }}" 5 | with_first_found: 6 | - "{{ linuxbrew_prefix_shared }}" 7 | - "{{ linuxbrew_prefix_user }}" 8 | become: true 9 | 10 | - name: Load Linuxbrew in bash 11 | ansible.builtin.include_tasks: bash.yml 12 | when: linuxbrew_prefix is defined 13 | 14 | - name: Load Linuxbrew in zsh 15 | ansible.builtin.include_tasks: zsh.yml 16 | when: linuxbrew_prefix is defined 17 | -------------------------------------------------------------------------------- /tasks/shell/zsh.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Configure .zprofile 3 | block: 4 | - name: Set path to .zprofile 5 | ansible.builtin.set_fact: 6 | linuxbrew_zprofile_path: "{{ linuxbrew_home }}/.zprofile" 7 | when: linuxbrew_zprofile_path is undefined 8 | 9 | - name: Check whether .zprofile exists 10 | ansible.builtin.stat: 11 | path: "{{ linuxbrew_zprofile_path }}" 12 | register: linuxbrew_zprofile_st 13 | 14 | - name: Resolve .zprofile symlink 15 | ansible.builtin.set_fact: 16 | linuxbrew_zprofile_path: "{{ linuxbrew_zprofile_st.stat.lnk_source }}" 17 | when: 18 | - linuxbrew_zprofile_st.stat.exists 19 | - linuxbrew_zprofile_st.stat.islnk 20 | 21 | - name: Check whether pyenv is loaded in .zprofile 22 | ansible.builtin.command: >- 23 | grep -Fq 'brew shellenv' {{ linuxbrew_zprofile_path }} 24 | register: check_zprofile 25 | ignore_errors: true 26 | changed_when: false 27 | failed_when: false 28 | when: linuxbrew_zprofile_st.stat.exists 29 | 30 | - name: Configure .zprofile and create if missing 31 | when: not linuxbrew_zprofile_st.stat.exists or check_zprofile.rc != 0 32 | block: 33 | - name: Load Homebrew in .zprofile 34 | ansible.builtin.blockinfile: 35 | dest: "{{ linuxbrew_zprofile_path }}" 36 | create: true 37 | mode: "0644" 38 | marker: "# {mark} ANSIBLE MANAGED BLOCK: linuxbrew" 39 | block: | 40 | eval $({{ linuxbrew_prefix }}/bin/brew shellenv) 41 | 42 | - name: Configure .zshrc (if it exists) 43 | block: 44 | - name: Set path to .zshrc 45 | ansible.builtin.set_fact: 46 | linuxbrew_zshrc_path: "{{ linuxbrew_home }}/.zshrc" 47 | when: linuxbrew_zshrc_path is undefined 48 | 49 | - name: Check whether .zshrc exists 50 | ansible.builtin.stat: 51 | path: "{{ linuxbrew_zshrc_path }}" 52 | register: linuxbrew_zshrc_st 53 | 54 | - name: Resolve .zshrc symlink 55 | ansible.builtin.set_fact: 56 | linuxbrew_zshrc_path: "{{ linuxbrew_zshrc_st.stat.lnk_source }}" 57 | when: 58 | - linuxbrew_zshrc_st.stat.exists 59 | - linuxbrew_zshrc_st.stat.islnk 60 | 61 | - name: Check whether pyenv is loaded in .zshrc 62 | ansible.builtin.command: >- 63 | grep -Fq 'brew shellenv' {{ linuxbrew_zshrc_path }} 64 | register: check_zshrc_linuxbrew 65 | ignore_errors: true 66 | changed_when: false 67 | failed_when: false 68 | when: linuxbrew_zshrc_st.stat.exists 69 | 70 | - name: Load Homebrew in .zshrc 71 | ansible.builtin.blockinfile: 72 | dest: "{{ linuxbrew_zshrc_path }}" 73 | marker: "# {mark} ANSIBLE MANAGED BLOCK: linuxbrew" 74 | block: | 75 | eval $({{ linuxbrew_prefix }}/bin/brew shellenv) 76 | when: 77 | - linuxbrew_zshrc_st.stat.exists 78 | - check_zshrc_linuxbrew.rc != 0 79 | -------------------------------------------------------------------------------- /tests/debian-bullseye/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:bullseye 2 | 3 | RUN apt-get update && apt-get install -y \ 4 | ca-certificates \ 5 | && rm -rf /var/lib/apt/lists/* 6 | 7 | # Use HTTPS 8 | RUN sed -i "s~http://~https://~g" /etc/apt/sources.list 9 | 10 | RUN apt-get update && apt-get upgrade -y \ 11 | && rm -rf /var/lib/apt/lists/* 12 | 13 | RUN apt-get update && apt-get install -y \ 14 | zsh \ 15 | sudo \ 16 | python3-minimal \ 17 | python3-pip \ 18 | && rm -rf /var/lib/apt/lists/* 19 | 20 | ARG user=test 21 | ARG repository=markosamuli.linuxbrew 22 | 23 | # Create test user 24 | RUN useradd -m ${user} -s /bin/bash \ 25 | && echo "${user}:${user}" | chpasswd \ 26 | && adduser ${user} sudo \ 27 | && echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers 28 | RUN touch /home/${user}/.zshrc \ 29 | && chown -R ${user}:${user} /home/${user} 30 | 31 | # Create directory for code 32 | RUN mkdir -p /home/${user}/${repository} ; \ 33 | chown -R ${user}:${user} /home/${user}/${repository} 34 | VOLUME ["/home/${user}/${repository}"] 35 | 36 | # Make sure we have the latest packages 37 | RUN apt-get update 38 | 39 | USER ${user} 40 | 41 | ARG ansible_version=">=2.9.22" 42 | ENV ANSIBLE_VERSION="${ansible_version}" 43 | RUN python3 -m pip install ansible${ANSIBLE_VERSION} 44 | 45 | CMD exec /bin/bash -c "trap : TERM INT; sleep infinity & wait" 46 | -------------------------------------------------------------------------------- /tests/debian-buster/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:buster 2 | 3 | RUN apt-get update && apt-get install -y \ 4 | ca-certificates \ 5 | && rm -rf /var/lib/apt/lists/* 6 | 7 | # Use HTTPS 8 | RUN sed -i "s~http://~https://~g" /etc/apt/sources.list 9 | 10 | RUN apt-get update && apt-get upgrade -y \ 11 | && rm -rf /var/lib/apt/lists/* 12 | 13 | # Python 3.7.3 14 | RUN apt-get update && apt-get install -y \ 15 | zsh \ 16 | sudo \ 17 | python3-minimal \ 18 | python3-pip \ 19 | && rm -rf /var/lib/apt/lists/* 20 | 21 | ARG user=test 22 | ARG repository=markosamuli.linuxbrew 23 | 24 | # Create test user 25 | RUN useradd -m ${user} -s /bin/bash \ 26 | && echo "${user}:${user}" | chpasswd \ 27 | && adduser ${user} sudo \ 28 | && echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers 29 | RUN touch /home/${user}/.zshrc \ 30 | && chown -R ${user}:${user} /home/${user} 31 | 32 | # Create directory for code 33 | RUN mkdir -p /home/${user}/${repository} ; \ 34 | chown -R ${user}:${user} /home/${user}/${repository} 35 | VOLUME ["/home/${user}/${repository}"] 36 | 37 | # Make sure we have the latest packages 38 | RUN apt-get update 39 | 40 | USER ${user} 41 | 42 | # Ansible will require Python 3.8 or newer on the controller starting with 43 | # Ansible 2.12 44 | ARG ansible_version=">=2.9.22" 45 | ENV ANSIBLE_VERSION="<2.12,${ansible_version}" 46 | RUN python3 -m pip install ansible${ANSIBLE_VERSION} 47 | 48 | CMD exec /bin/bash -c "trap : TERM INT; sleep infinity & wait" 49 | -------------------------------------------------------------------------------- /tests/fedora-37/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM fedora:37 2 | 3 | RUN dnf -y update && dnf clean all 4 | 5 | # Python 3.11 6 | RUN dnf -y install \ 7 | zsh \ 8 | sudo \ 9 | python3 \ 10 | python3-pip \ 11 | && dnf clean all 12 | 13 | ARG user=test 14 | ARG repository=markosamuli.linuxbrew 15 | 16 | # Create test user 17 | RUN useradd -m -s /bin/bash ${user} \ 18 | && echo "${user}:${user}" | chpasswd \ 19 | && usermod -aG wheel ${user} \ 20 | && echo '%wheel ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers 21 | RUN touch /home/${user}/.zshrc \ 22 | && chown -R ${user}:${user} /home/${user} 23 | 24 | # Create directory for code 25 | RUN mkdir -p /home/${user}/${repository} ; \ 26 | chown -R ${user}:${user} /home/${user}/${repository} 27 | VOLUME ["/home/${user}/${repository}"] 28 | 29 | USER ${user} 30 | 31 | ARG ansible_version=">=2.9.22" 32 | ENV ANSIBLE_VERSION="${ansible_version}" 33 | RUN python3 -m pip install ansible${ANSIBLE_VERSION} 34 | 35 | CMD exec /bin/bash -c "trap : TERM INT; sleep infinity & wait" 36 | -------------------------------------------------------------------------------- /tests/inventory: -------------------------------------------------------------------------------- 1 | localhost ansible_python_interpreter=auto 2 | -------------------------------------------------------------------------------- /tests/run-tests: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 4 | PROJECT_ROOT=$(dirname "${DIR}") 5 | 6 | REPO_NAME="$(basename "${PROJECT_ROOT}")" 7 | ROLE_NAME="markosamuli.${REPO_NAME/ansible-/}" 8 | TEST_HOME=/home/test 9 | 10 | docker_run_opts=() 11 | 12 | # Ansible version to install on the Docker images 13 | # Use PIP version specifiers: 14 | # https://peps.python.org/pep-0440/#version-specifiers 15 | ANSIBLE_VERSION=">=2.9.22" 16 | 17 | # Colour list copied from: 18 | # https://stackoverflow.com/questions/5947742/how-to-change-the-output-color-of-echo-in-linux 19 | 20 | # Reset 21 | Color_Off='\033[0m' # Text Reset 22 | 23 | # Bold 24 | BPurple='\033[1;35m' # Purple 25 | 26 | image_msg() { 27 | local image=$1 28 | shift 29 | echo -e "${BPurple}[${image}] $*${Color_Off}" 30 | } 31 | 32 | # Detect Windows Subsystem for Linux 33 | detect_wsl() { 34 | if [ ! -e /proc/version ]; then 35 | is_wsl=0 36 | return 37 | fi 38 | if grep -q Microsoft /proc/version; then 39 | echo "*** Windows Subsystem for Linux detected" 40 | is_wsl=1 41 | else 42 | is_wsl=0 43 | fi 44 | } 45 | 46 | # Stop all containers 47 | finish() { 48 | local containers="" 49 | containers=$(docker ps -q --filter=name="${REPO_NAME}") 50 | if [ -n "${containers}" ]; then 51 | echo "*** Stop and remove all test containers" 52 | # shellcheck disable=SC2086 53 | docker stop ${containers} 54 | fi 55 | } 56 | 57 | # Stop container 58 | stop() { 59 | local image=$1 60 | local container_name=${REPO_NAME}-${image}-tests 61 | echo "" 62 | image_msg "${image}" "Stop and remove containers" 63 | echo "" 64 | docker stop "${container_name}" 65 | sleep 1 66 | } 67 | 68 | # Build image 69 | build() { 70 | local image=$1 71 | local image_name=${REPO_NAME}-${image} 72 | echo "" 73 | image_msg "${image}" "Build image from tests/${image}/Dockerfile" 74 | echo "" 75 | docker build \ 76 | --build-arg "ansible_version=${ANSIBLE_VERSION}" \ 77 | --build-arg "repository=${ROLE_NAME}" \ 78 | -t "${image_name}" \ 79 | "./tests/${image}" 80 | } 81 | 82 | # Start container in the background 83 | start() { 84 | local image=$1 85 | local image_name=${REPO_NAME}-${image} 86 | local container_name=${REPO_NAME}-${image}-tests 87 | echo "" 88 | image_msg "${image}" "Start container ${container_name}" 89 | echo "" 90 | docker run --rm -d \ 91 | "${docker_run_opts[@]}" \ 92 | -v "${MOUNT_ROOT}:${TEST_HOME}/${ROLE_NAME}" \ 93 | -e "TEST_IMAGE=${image}" \ 94 | --name "${container_name}" \ 95 | "$image_name" 96 | } 97 | 98 | run_tests_with_git() { 99 | local image=$1 100 | local container_name=${REPO_NAME}-${image}-tests 101 | echo "" 102 | image_msg "${image}" "Run tests installing with Ansible from Git" 103 | echo "" 104 | docker exec \ 105 | "${docker_run_opts[@]}" \ 106 | --user test \ 107 | "${container_name}" \ 108 | "${TEST_HOME}/${ROLE_NAME}/tests/run-tests-with-git" 109 | } 110 | 111 | run_tests_with_installer() { 112 | local image=$1 113 | local container_name=${REPO_NAME}-${image}-tests 114 | echo "" 115 | image_msg "${image}" "Run tests installing with the Homebrew installer" 116 | echo "" 117 | docker exec \ 118 | "${docker_run_opts[@]}" \ 119 | --user test \ 120 | "${container_name}" \ 121 | "${TEST_HOME}/${ROLE_NAME}/tests/run-tests-with-installer" 122 | } 123 | 124 | trap finish EXIT 125 | 126 | if [ -z "$CI" ]; then 127 | docker_run_opts+=("-it") 128 | fi 129 | 130 | detect_wsl 131 | 132 | cd "${DIR}" || { 133 | echo "${DIR} not found" 134 | exit 1 135 | } 136 | 137 | images=("$@") 138 | if [ ${#images[@]} -eq 0 ]; then 139 | images=(*/Dockerfile) 140 | images=("${images[@]/\/Dockerfile/}") 141 | fi 142 | 143 | cd "${PROJECT_ROOT}" || { 144 | echo "${PROJECT_ROOT} not found" 145 | exit 1 146 | } 147 | 148 | if [ "${is_wsl}" == "1" ]; then 149 | MOUNT_ROOT="$(pwd -P | sed 's~/mnt/c/~c:/~')" 150 | else 151 | MOUNT_ROOT="$(pwd -P)" 152 | fi 153 | 154 | set -e 155 | 156 | for i in "${images[@]}"; do 157 | build "$i" 158 | done 159 | 160 | for i in "${images[@]}"; do 161 | start "$i" 162 | run_tests_with_git "$i" 163 | stop "$i" 164 | done 165 | 166 | for i in "${images[@]}"; do 167 | start "$i" 168 | run_tests_with_installer "$i" 169 | stop "$i" 170 | done 171 | -------------------------------------------------------------------------------- /tests/run-tests-with-git: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 4 | PROJECT_ROOT=$(dirname "$DIR") 5 | 6 | if [ -d "${HOME}/.local/bin" ]; then 7 | export PATH="${HOME}/.local/bin:${PATH}" 8 | fi 9 | 10 | command -v ansible-playbook >/dev/null || { 11 | echo "ansible-playbook: command not found" 12 | exit 127 13 | } 14 | 15 | set -e 16 | 17 | # Variables to pass to ansible-playbook 18 | ansible_vars=( 19 | "'linuxbrew_use_installer':false" 20 | ) 21 | extra_vars=$(printf ",%s" "${ansible_vars[@]}") 22 | extra_vars="{${extra_vars:1}}" 23 | 24 | # Paths in which Ansible will search for Roles 25 | ANSIBLE_ROLES_PATH=$(dirname "$PROJECT_ROOT") 26 | export ANSIBLE_ROLES_PATH 27 | 28 | cd "$PROJECT_ROOT" 29 | 30 | echo "*** Check syntax" 31 | 32 | ansible-playbook tests/test.yml -i tests/inventory --syntax-check 33 | 34 | echo "*** Run Ansible playbook" 35 | 36 | ansible-playbook tests/test.yml -i tests/inventory --connection=local \ 37 | -v \ 38 | -e "${extra_vars}" 39 | run_status=$? 40 | if [[ ${run_status} -eq 0 ]]; then 41 | echo 'Run: pass' 42 | else 43 | echo 'Run: fail' 44 | exit 1 45 | fi 46 | 47 | echo "*** Idempotence test" 48 | 49 | ansible-playbook tests/test.yml -i tests/inventory --connection=local \ 50 | -e "${extra_vars}" | 51 | grep -q 'changed=0.*failed=0' 52 | idempotence_status=$? 53 | if [[ $idempotence_status -eq 0 ]]; then 54 | echo 'Idempotence test: pass' 55 | else 56 | echo 'Idempotence test: fail' 57 | exit 1 58 | fi 59 | 60 | echo "*** Ansible playbooks completed on image ${TEST_IMAGE}" 61 | 62 | echo "*** Verify installed Homebrew version in bash" 63 | bash -i -c 'command -v brew && brew --version' 64 | 65 | echo "*** Tests completed on image ${TEST_IMAGE}" 66 | -------------------------------------------------------------------------------- /tests/run-tests-with-installer: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 4 | PROJECT_ROOT=$(dirname "$DIR") 5 | 6 | if [ -d "${HOME}/.local/bin" ]; then 7 | export PATH="${HOME}/.local/bin:${PATH}" 8 | fi 9 | 10 | command -v ansible-playbook >/dev/null || { 11 | echo "ansible-playbook: command not found" 12 | exit 127 13 | } 14 | 15 | set -e 16 | 17 | # Variables to pass to ansible-playbook 18 | ansible_vars=( 19 | "'linuxbrew_use_installer':true" 20 | ) 21 | extra_vars=$(printf ",%s" "${ansible_vars[@]}") 22 | extra_vars="{${extra_vars:1}}" 23 | 24 | # Paths in which Ansible will search for Roles 25 | ANSIBLE_ROLES_PATH=$(dirname "$PROJECT_ROOT") 26 | export ANSIBLE_ROLES_PATH 27 | 28 | cd "$PROJECT_ROOT" 29 | 30 | echo "*** Check syntax" 31 | 32 | ansible-playbook tests/test.yml -i tests/inventory --syntax-check 33 | 34 | echo "*** Run Ansible playbook" 35 | 36 | ansible-playbook tests/test.yml -i tests/inventory --connection=local \ 37 | -v \ 38 | -e "${extra_vars}" 39 | run_status=$? 40 | if [[ ${run_status} -eq 0 ]]; then 41 | echo 'Run: pass' 42 | else 43 | echo 'Run: fail' 44 | exit 1 45 | fi 46 | 47 | echo "*** Idempotence test" 48 | 49 | ansible-playbook tests/test.yml -i tests/inventory --connection=local \ 50 | -e "${extra_vars}" | 51 | grep -q 'changed=0.*failed=0' 52 | idempotence_status=$? 53 | if [[ $idempotence_status -eq 0 ]]; then 54 | echo 'Idempotence test: pass' 55 | else 56 | echo 'Idempotence test: fail' 57 | exit 1 58 | fi 59 | 60 | echo "*** Ansible playbooks completed on image ${TEST_IMAGE}" 61 | 62 | echo "*** Verify installed Homebrew version in bash" 63 | bash -i -c 'command -v brew && brew --version' 64 | 65 | echo "*** Tests completed on image ${TEST_IMAGE}" 66 | -------------------------------------------------------------------------------- /tests/test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | remote_user: root 4 | name: Install Homebrew on Linux 5 | roles: 6 | - markosamuli.linuxbrew 7 | -------------------------------------------------------------------------------- /tests/ubuntu-bionic/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:bionic 2 | 3 | RUN apt-get update && apt-get install -y \ 4 | ca-certificates \ 5 | && rm -rf /var/lib/apt/lists/* 6 | 7 | # Use a maintained UK-based mirror with HTTPS support 8 | ARG ubuntu_archive=https://mirror.pulsant.com/sites/ubuntu-archive/ 9 | RUN sed -i "s~http://archive.ubuntu.com/ubuntu/~${ubuntu_archive}~g" /etc/apt/sources.list 10 | 11 | RUN apt-get update && apt-get upgrade -y \ 12 | && rm -rf /var/lib/apt/lists/* 13 | 14 | # Python 3.6.9 15 | RUN apt-get update && apt-get install -y \ 16 | zsh \ 17 | sudo \ 18 | python3-minimal \ 19 | python3-pip \ 20 | && rm -rf /var/lib/apt/lists/* 21 | 22 | # Fixed in Python 3.7 23 | # https://github.com/pypa/pip/issues/10219 24 | ENV LANG C.UTF-8 25 | ENV LC_ALL C.UTF-8 26 | 27 | ARG user=test 28 | ARG repository=markosamuli.linuxbrew 29 | 30 | # Create test user 31 | RUN useradd -m ${user} -s /bin/bash \ 32 | && echo "${user}:${user}" | chpasswd \ 33 | && adduser ${user} sudo \ 34 | && echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers 35 | RUN touch /home/${user}/.zshrc \ 36 | && chown -R ${user}:${user} /home/${user} 37 | 38 | # Create directory for code 39 | RUN mkdir -p /home/${user}/${repository} ; \ 40 | chown -R ${user}:${user} /home/${user}/${repository} 41 | VOLUME ["/home/${user}/${repository}"] 42 | 43 | # Make sure we have the latest packages 44 | RUN apt-get update 45 | 46 | USER ${user} 47 | 48 | # Upgrade pip to fix installation issues 49 | RUN python3 -m pip install --upgrade pip 50 | 51 | # Ansible will require Python 3.8 or newer on the controller starting 52 | # with Ansible 2.12. 53 | ARG ansible_version=">=2.9.22" 54 | ENV ANSIBLE_VERSION="<2.12,${ansible_version}" 55 | RUN python3 -m pip install ansible${ANSIBLE_VERSION} 56 | 57 | CMD exec /bin/bash -c "trap : TERM INT; sleep infinity & wait" 58 | -------------------------------------------------------------------------------- /tests/ubuntu-focal/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:focal 2 | 3 | RUN apt-get update && apt-get install -y \ 4 | ca-certificates \ 5 | && rm -rf /var/lib/apt/lists/* 6 | 7 | # Use a maintained UK-based mirror with HTTPS support 8 | ARG ubuntu_archive=https://mirror.pulsant.com/sites/ubuntu-archive/ 9 | RUN sed -i "s~http://archive.ubuntu.com/ubuntu/~${ubuntu_archive}~g" /etc/apt/sources.list 10 | 11 | RUN apt-get update && apt-get upgrade -y \ 12 | && rm -rf /var/lib/apt/lists/* 13 | 14 | RUN apt-get update && apt-get install -y \ 15 | zsh \ 16 | sudo \ 17 | python3-minimal \ 18 | python3-pip \ 19 | && rm -rf /var/lib/apt/lists/* 20 | 21 | ARG user=test 22 | ARG repository=markosamuli.linuxbrew 23 | 24 | # Create test user 25 | RUN useradd -m ${user} -s /bin/bash \ 26 | && echo "${user}:${user}" | chpasswd \ 27 | && adduser ${user} sudo \ 28 | && echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers 29 | RUN touch /home/${user}/.zshrc \ 30 | && chown -R ${user}:${user} /home/${user} 31 | 32 | # Create directory for code 33 | RUN mkdir -p /home/${user}/${repository} ; \ 34 | chown -R ${user}:${user} /home/${user}/${repository} 35 | VOLUME ["/home/${user}/${repository}"] 36 | 37 | # Make sure we have the latest packages 38 | RUN apt-get update 39 | 40 | USER test 41 | 42 | ARG ansible_version=">=2.9.22" 43 | ENV ANSIBLE_VERSION="${ansible_version}" 44 | RUN python3 -m pip install ansible${ANSIBLE_VERSION} 45 | 46 | CMD exec /bin/bash -c "trap : TERM INT; sleep infinity & wait" 47 | -------------------------------------------------------------------------------- /tests/ubuntu-jammy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:jammy 2 | 3 | RUN apt-get update && apt-get install -y \ 4 | ca-certificates \ 5 | && rm -rf /var/lib/apt/lists/* 6 | 7 | # Use a maintained UK-based mirror with HTTPS support 8 | ARG ubuntu_archive=https://mirror.pulsant.com/sites/ubuntu-archive/ 9 | RUN sed -i "s~http://archive.ubuntu.com/ubuntu/~${ubuntu_archive}~g" /etc/apt/sources.list 10 | 11 | RUN apt-get update && apt-get upgrade -y \ 12 | && rm -rf /var/lib/apt/lists/* 13 | 14 | RUN apt-get update && apt-get install -y \ 15 | zsh \ 16 | sudo \ 17 | python3-minimal \ 18 | python3-pip \ 19 | && rm -rf /var/lib/apt/lists/* 20 | 21 | ARG user=test 22 | ARG repository=markosamuli.linuxbrew 23 | 24 | # Create test user 25 | RUN useradd -m ${user} -s /bin/bash \ 26 | && echo "${user}:${user}" | chpasswd \ 27 | && adduser ${user} sudo \ 28 | && echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers 29 | RUN touch /home/${user}/.zshrc \ 30 | && chown -R ${user}:${user} /home/${user} 31 | 32 | # Create directory for code 33 | RUN mkdir -p /home/${user}/${repository} ; \ 34 | chown -R ${user}:${user} /home/${user}/${repository} 35 | VOLUME ["/home/${user}/${repository}"] 36 | 37 | # Make sure we have the latest packages 38 | RUN apt-get update 39 | 40 | USER ${user} 41 | 42 | ARG ansible_version=">=2.9.22" 43 | ENV ANSIBLE_VERSION="${ansible_version}" 44 | RUN python3 -m pip install ansible${ANSIBLE_VERSION} 45 | 46 | CMD exec /bin/bash -c "trap : TERM INT; sleep infinity & wait" 47 | -------------------------------------------------------------------------------- /vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # vars file for markosamuli.linuxbrew 3 | 4 | # Shared directory to install Linuxbrew in 5 | linuxbrew_prefix_shared: "/home/linuxbrew/.linuxbrew" 6 | 7 | # Brew Git repository 8 | linuxbrew_brew_repo: https://github.com/Homebrew/brew 9 | linuxbrew_brew_version: master 10 | linuxbrew_core_tap_repo: https://github.com/Homebrew/linuxbrew-core 11 | linuxbrew_core_tap_version: master 12 | 13 | # Linuxbrew installer script 14 | linuxbrew_install_tmp: "/tmp/linuxbrew" 15 | linuxbrew_install_url: "https://raw.githubusercontent.com/Homebrew/install/master/install.sh" 16 | -------------------------------------------------------------------------------- /vars/os/Debian.yml: -------------------------------------------------------------------------------- 1 | --- 2 | linuxbrew_install_dependencies: 3 | - git 4 | - curl 5 | - build-essential 6 | - locales 7 | 8 | # ps is not installed on the buster Docker image 9 | # https://github.com/Homebrew/brew/blob/master/Library/Homebrew/cmd/shellenv.sh 10 | - procps 11 | -------------------------------------------------------------------------------- /vars/os/Pengwin.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | linuxbrew_install_dependencies: 4 | - git 5 | - curl 6 | - build-essential 7 | - locales 8 | -------------------------------------------------------------------------------- /vars/os/RedHat.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # RedHat dependencies from: 3 | # https://github.com/markosamuli/ansible-linuxbrew/pull/9 4 | linuxbrew_install_dependencies: 5 | - "@Development Tools" 6 | - git 7 | - curl 8 | - procps-ng 9 | - file 10 | - libxcrypt-compat 11 | -------------------------------------------------------------------------------- /vars/os/Ubuntu.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | linuxbrew_install_dependencies: 4 | - git 5 | - curl 6 | - build-essential 7 | - locales 8 | - language-pack-en 9 | --------------------------------------------------------------------------------