diff --git a/.github/scripts/template.sh b/.github/scripts/template.sh index 927be6f1..e7c1fa4f 100644 --- a/.github/scripts/template.sh +++ b/.github/scripts/template.sh @@ -1,17 +1,27 @@ #!/bin/bash -NAME=${1:-"Pro Buddy Dev"} -EMAIL=${2:-"somedude@coolstartup.com"} +# .github/scripts/template.sh +# Perform automated templating. + +# 1: Optional TOML Formatting +# 2: Git Username +# 3: Git Email + +# CI only script. set -eo pipefail +OPTIONAL_TOML_LINTING=${1:-"1"} +NAME=${2:-"Pro Buddy Dev"} +EMAIL=${3:-"somedude@coolstartup.com"} + main() { git config --global user.name "${NAME}" git config --global user.email "${EMAIL}" - echo -e '\n\n\n\n\n\n\n\n\n' | cookiecutter template/ + echo -e "\n\n${OPTIONAL_TOML_LINTING}\n\n\n\n\n\n\n\n" | cookiecutter template/ } -main +main "$@" diff --git a/.github/scripts/test_precommit.sh b/.github/scripts/test_precommit.sh new file mode 100644 index 00000000..eea96f7b --- /dev/null +++ b/.github/scripts/test_precommit.sh @@ -0,0 +1,80 @@ +#!/bin/bash + +# .github/scripts/test_precommit.sh +# Performs tests on the pre-commit hooks. + +# 1: The name of a pre-commit test scenario. (See 'main' below.) +# TEMPLATED_NAME: The name of the rendered test project. + +# CI only script. + +set -eo pipefail + +test_commit_lint() { + util_git_reset + touch empty_file.txt + git stage empty_file.txt + git commit -m 'test - pre-commit: improperly formatted commit' || exit 0 + util_fail_test +} + +test_molecule_lint() { + util_git_reset + echo "" >> tasks/main.yml + git stage tasks/main.yml + git commit -m 'test(PRE-COMMIT): fail due to ansible-lint' > error.log 2>&1 || grep "empty-lines" error.log > /dev/null && exit 0 + util_fail_test +} + +test_toml_lint_1() { + util_git_reset + sed -i.bak 's/authors =/ authors = /g' pyproject.toml + git stage pyproject.toml + git commit -m 'test(PRE-COMMIT): fail due to tomll' || exit 0 + util_fail_test +} + +test_toml_lint_2() { + util_git_reset + sed -i.bak 's/>=3.9.0,<4.0/>=3.9.1,<4.0/g' pyproject.toml + git stage pyproject.toml + git commit -m 'test(PRE-COMMIT): upgrade python without issue' +} + +util_fail_test() { + echo "This commit should have failed." + exit 127 +} + +util_git_reset() { + git reset HEAD + git clean -fd + git checkout . +} + +main() { + + pushd "${TEMPLATED_NAME}" + case $1 in + commit-lint) + test_commit_lint + ;; + molecule-lint) + test_molecule_lint + ;; + toml-lint-1) + test_toml_lint_1 + ;; + toml-lint-2) + test_toml_lint_2 + ;; + *) + echo "Invalid test scenario." + exit 127 + ;; + esac + popd + +} + +main "$@" diff --git a/.github/workflows/self-test.yml b/.github/workflows/self-test.yml index a3ae31a8..2cdd88a7 100644 --- a/.github/workflows/self-test.yml +++ b/.github/workflows/self-test.yml @@ -2,9 +2,9 @@ name: ansible-workbench-self-test # Required Github Repository Secrets: -# REMOTE_TOKEN - Github Token With Access To This Repo -# REMOTE_ORIGIN - The git remote repository name (organization/repo) -# SLACK_WEBHOOK - The slack webhook for build notifications +# REMOTE_TOKEN - GitHub token with access to the test repository. +# REMOTE_ORIGIN - The git remote repository name (organization/repo). +# SLACK_WEBHOOK - The slack webhook for build notifications. on: push: @@ -16,7 +16,7 @@ env: ANSIBLE_WORKBENCH_BRANCH_NAME_BASE: "master" ANSIBLE_WORKBENCH_BRANCH_NAME_DEVELOPMENT: "dev" PROJECT_NAME: "ansible-workbench" - USERNAME: "niall-byrne" + USER_NAME: "niall-byrne" TEMPLATED_NAME: "flower-generator" VERBOSE_NOTIFICATIONS: 0 @@ -153,7 +153,7 @@ jobs: - name: Create Release -- Report Job Status on Success if: steps.branch_filter.outputs.match == 'TRUE' run: | - ./{{cookiecutter.project_slug}}/.github/scripts/notifications.sh "${NOTIFICATION}" ":white_check_mark: automated release has been created!\nhttps://github.com/${USERNAME}/${PROJECT_NAME}/releases" + ./{{cookiecutter.project_slug}}/.github/scripts/notifications.sh "${NOTIFICATION}" ":white_check_mark: automated release has been created!\nhttps://github.com/${USER_NAME}/${PROJECT_NAME}/releases" - name: Create Release -- Report Job Status on Failure if: failure() @@ -166,6 +166,7 @@ jobs: runs-on: ubuntu-latest env: ANSIBLE_WORKBENCH_SKIP_POETRY: 1 + ANSIBLE_WORKBENCH_SKIP_PRECOMMIT: 1 strategy: max-parallel: 4 matrix: @@ -227,6 +228,9 @@ jobs: needs: [_create_configuration] runs-on: ubuntu-latest + env: + ANSIBLE_WORKBENCH_SKIP_POETRY: 0 + ANSIBLE_WORKBENCH_SKIP_PRECOMMIT: 0 strategy: max-parallel: 4 matrix: @@ -291,12 +295,107 @@ jobs: run: | ./template/{{cookiecutter.project_slug}}/.github/scripts/notifications.sh "${NOTIFICATION}" ":x: molecule linting checks failed!" + precommit_test: + needs: [_create_configuration] + + runs-on: ubuntu-latest + env: + ANSIBLE_WORKBENCH_SKIP_POETRY: 0 + ANSIBLE_WORKBENCH_SKIP_PRECOMMIT: 0 + strategy: + matrix: + python-version: ${{ fromJson(needs._create_configuration.outputs.configuration)._GITHUB_CI_PYTHON_VERSIONS }} + cookiecutter-toml-selection: [1, 2] + + steps: + + - name: Pre-Commit Test -- Checkout Repository + uses: actions/checkout@v3 + with: + path: 'template' + + - name: Pre-Commit Test -- Setup Environment + run: | + source ./template/{{cookiecutter.project_slug}}/.github/scripts/setup.sh + env: + WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} + + - name: Pre-Commit Test -- Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: Pre-Commit Test -- Install Template Requirements + run: | + source ./template/.github/scripts/requirements.sh + + - name: Pre-Commit Test -- Install tomll + run: | + sudo apt-get install -y golang-github-pelletier-go-toml + + - name: Pre-Commit -- Initialize Cache Locations + run: | + mkdir -p ~/.cache/pypoetry/virtualenvs + source ./template/{{cookiecutter.project_slug}}/.github/scripts/ansible_cache.sh \ + "$(pwd)/ansible_cache" \ + ~/.cache + + - name: Pre-Commit -- Mount Ansible Cache + uses: actions/cache@v3 + with: + key: ansible-${{ hashFiles('./template/{{cookiecutter.project_slug}}/requirements.yml') }}-${{ env.CACHE_TTL }} + path: ansible_cache + + - name: Pre-Commit Test -- Mount Poetry Cache + uses: actions/cache@v3 + with: + key: poetry-${{ hashFiles('./template/{{cookiecutter.project_slug}}/pyproject.toml') }}-${{ runner.os }}-${{ env.CACHE_TTL }} + path: ~/.cache/pypoetry/virtualenvs + + - name: Pre-Commit Test -- Render Template + run: | + source ./template/.github/scripts/template.sh "${SELECTION_TOML}" "GitHub Action" "action@github.com" + env: + SELECTION_TOML: ${{ matrix.cookiecutter-toml-selection }} + + - name: Pre-Commit Test -- Test Commit Lint -- Expect Failure + run: | + source ./template/.github/scripts/test_precommit.sh "commit-lint" + + - name: Pre-Commit Test -- Test Molecule Lint -- Expect Failure + run: | + source ./template/.github/scripts/test_precommit.sh "molecule-lint" + + - name: Pre-Commit Test -- Test TOML Lint -- Expect Failure + if: matrix.cookiecutter-toml-selection == 1 + run: | + source ./template/.github/scripts/test_precommit.sh "toml-lint-1" + + - name: Pre-Commit Test -- Test TOML Lint -- Expect Success + if: matrix.cookiecutter-toml-selection == 1 + run: | + source ./template/.github/scripts/test_precommit.sh "toml-lint-2" + + - name: Pre-Commit Test -- Report Job Status on Success + if: env.VERBOSE_NOTIFICATIONS == '1' + run: | + ./template/{{cookiecutter.project_slug}}/.github/scripts/notifications.sh "${NOTIFICATION}" ":white_check_mark: pre-commit hook test has passed!" + + - name: Pre-Commit Test -- Report Job Status on Failure + if: failure() + run: | + ./template/{{cookiecutter.project_slug}}/.github/scripts/notifications.sh "${NOTIFICATION}" ":x: pre-commit hook test has failed!" + push_repository_test: - needs: [_create_configuration, _start_notification, documentation_test, molecule_lint_test, security_test, shellcheck_test, yaml_lint_test] + needs: [_create_configuration, _start_notification, documentation_test, molecule_lint_test, precommit_test, security_test, shellcheck_test, toml_lint_test, yaml_lint_test] runs-on: ubuntu-latest env: ANSIBLE_WORKBENCH_SKIP_POETRY: 1 + ANSIBLE_WORKBENCH_SKIP_PRECOMMIT: 1 + TEMPLATED_NAME_1: "flower-generator-with-toml" + TEMPLATED_NAME_2: "flower-generator-no-toml" + TEST_PUSH_TAG: "0.1.0" strategy: max-parallel: 4 matrix: @@ -326,7 +425,10 @@ jobs: - name: Push Test -- Render Template run: | - source ./template/.github/scripts/template.sh "GitHub Action" "action@github.com" + source ./template/.github/scripts/template.sh "1" "GitHub Action" "action@github.com" + mv "${TEMPLATED_NAME}" "${TEMPLATED_NAME_1}" + source ./template/.github/scripts/template.sh "2" "GitHub Action" "action@github.com" + mv "${TEMPLATED_NAME}" "${TEMPLATED_NAME_2}" - name: Push Test -- Clean Up Test Releases run: | @@ -335,30 +437,37 @@ jobs: GITHUB_TOKEN: ${{ secrets.REMOTE_TOKEN }} REMOTE_ORIGIN: ${{ secrets.REMOTE_ORIGIN }} - - name: Push Test -- Clean Up Tags for Git Push + - name: Push Test -- Clean Up Tags for Git Push (${{ env.TEMPLATED_NAME_1 }}) run: | - cd ${TEMPLATED_NAME} + cd ${TEMPLATED_NAME_1} git checkout "${ANSIBLE_WORKBENCH_BRANCH_NAME_BASE}" git tag --delete 0.0.0 # Don't Repush - git tag 0.1.0 - - name: Push Test -- Push To Test Repository (${{ env.ANSIBLE_WORKBENCH_BRANCH_NAME_BASE }}) + - name: Push Test -- Test Commit (${{ env.TEMPLATED_NAME_1 }}) + run: | + cd "${TEMPLATED_NAME_1}" + echo "test commit" > test_file.txt + git add test_file.txt + git commit -m 'feat(TEST_FILE): add test file' + git tag "${TEST_PUSH_TAG}" + + - name: Push Test -- Push To Test Repository (${{ env.ANSIBLE_WORKBENCH_BRANCH_NAME_BASE }}) (${{ env.TEMPLATED_NAME_1 }}) uses: ad-m/github-push-action@v0.6.0 with: github_token: ${{ secrets.REMOTE_TOKEN }} branch: ${{ env.ANSIBLE_WORKBENCH_BRANCH_NAME_BASE }} tags: false - directory: ${{ env.TEMPLATED_NAME }} + directory: ${{ env.TEMPLATED_NAME_1 }} repository: ${{ secrets.REMOTE_ORIGIN }} force: true - - name: Push Test -- Push To Test Repository (${{ env.ANSIBLE_WORKBENCH_BRANCH_NAME_DEVELOPMENT }}) + - name: Push Test -- Push To Test Repository (${{ env.ANSIBLE_WORKBENCH_BRANCH_NAME_DEVELOPMENT }}) (${{ env.TEMPLATED_NAME_2 }}) uses: ad-m/github-push-action@v0.6.0 with: github_token: ${{ secrets.REMOTE_TOKEN }} branch: ${{ env.ANSIBLE_WORKBENCH_BRANCH_NAME_DEVELOPMENT }} tags: false - directory: ${{ env.TEMPLATED_NAME }} + directory: ${{ env.TEMPLATED_NAME_2 }} repository: ${{ secrets.REMOTE_ORIGIN }} force: true @@ -368,7 +477,7 @@ jobs: github_token: ${{ secrets.REMOTE_TOKEN }} branch: ${{ env.ANSIBLE_WORKBENCH_BRANCH_NAME_BASE }} tags: true - directory: ${{ env.TEMPLATED_NAME }} + directory: ${{ env.TEMPLATED_NAME_1 }} repository: ${{ secrets.REMOTE_ORIGIN }} force: true @@ -430,6 +539,7 @@ jobs: runs-on: ubuntu-latest env: ANSIBLE_WORKBENCH_SKIP_POETRY: 1 + ANSIBLE_WORKBENCH_SKIP_PRECOMMIT: 1 strategy: max-parallel: 4 matrix: @@ -468,7 +578,9 @@ jobs: - name: Shellcheck -- Shellcheck Rendered Scripts run: | - shellcheck ${TEMPLATED_NAME}/.github/scripts/*.sh + cd "${TEMPLATED_NAME}" + shellcheck ./.github/scripts/*.sh + shellcheck -x ./.pre-commit/*.sh - name: Shellcheck -- Report Job Status on Success if: env.VERBOSE_NOTIFICATIONS == '1' @@ -480,16 +592,72 @@ jobs: run: | ./template/{{cookiecutter.project_slug}}/.github/scripts/notifications.sh "${NOTIFICATION}" ":x: shellcheck checks failed!" + toml_lint_test: + needs: [_create_configuration] + + runs-on: ubuntu-latest + env: + ANSIBLE_WORKBENCH_SKIP_POETRY: 1 + ANSIBLE_WORKBENCH_SKIP_PRECOMMIT: 1 + strategy: + max-parallel: 4 + matrix: + python-version: ${{ fromJson(needs._create_configuration.outputs.configuration)._GITHUB_CI_PYTHON_VERSIONS }} + + steps: + - name: Toml Lint Test -- Checkout Repository + uses: actions/checkout@v3 + with: + path: 'template' + + - name: Toml Lint Test -- Setup Environment + run: | + source ./template/{{cookiecutter.project_slug}}/.github/scripts/setup.sh + sudo apt-get install -y golang-github-pelletier-go-toml + env: + WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} + + - name: Toml Lint Test -- Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: Toml Lint Test -- Install Template Requirements + run: | + source ./template/.github/scripts/requirements.sh + + - name: Toml Lint Test -- Render Template + run: | + source ./template/.github/scripts/template.sh + + - name: Toml Lint Test -- Run Linter + run: | + cd "${TEMPLATED_NAME}" + find . -type f -name "*.toml" -exec tomll "{}" \; + git diff --exit-code + + - name: Toml Lint Test -- Report Job Status (Success) + if: env.VERBOSE_NOTIFICATIONS == '1' + run: | + ./template/{{cookiecutter.project_slug}}/.github/scripts/notifications.sh "${NOTIFICATION}" ":white_check_mark: toml linting was successful!" + + - name: Toml Lint Test -- Report Job Status (Failure) + if: failure() + run: | + ./template/{{cookiecutter.project_slug}}/.github/scripts/notifications.sh "${NOTIFICATION}" ":x: toml linting has failed!" + yaml_lint_test: needs: [_create_configuration] runs-on: ubuntu-latest env: ANSIBLE_WORKBENCH_SKIP_POETRY: 1 + ANSIBLE_WORKBENCH_SKIP_PRECOMMIT: 1 strategy: max-parallel: 4 matrix: python-version: ${{ fromJson(needs._create_configuration.outputs.configuration)._GITHUB_CI_PYTHON_VERSIONS }} + cookiecutter-toml-selection: [1, 2] steps: - name: Yaml Lint Test -- Checkout Repository @@ -514,7 +682,9 @@ jobs: - name: Yaml Lint Test -- Render Template run: | - source ./template/.github/scripts/template.sh + source ./template/.github/scripts/template.sh "${SELECTION_TOML}" + env: + SELECTION_TOML: ${{ matrix.cookiecutter-toml-selection }} - name: Yaml Lint Test -- Lint Template GitHub Workflows uses: ibiqlik/action-yamllint@v3 diff --git a/README.md b/README.md index 35b00f66..01f2e970 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,30 @@ Poetry is leveraged to manage the Python dependencies: | molecule | Ansible test framework | | yamllint | Lints yaml configuration files | +### Maintaining your pyproject.toml File + +The template also presents the option to create a pre-commit hook, and a GitHub workflow step to format the [pyproject.toml](./{{cookiecutter.project_slug}}/pyproject.toml) file: +- This is accomplished via the golang binary [tomll](https://github.com/pelletier/go-toml). +- This is the most robust TOML formatter I'm aware of right now. +- However, to use it, you'll need to install the binary on your locale system. + +If you'd like to install it and give it a try: +- You can download the latest binary [here](https://github.com/pelletier/go-toml/releases). +- Alternatively, your OS's package manager may support this tool. + - For example: [Ubuntu](https://manpages.ubuntu.com/manpages/jammy/man1/tomll.1.html) +- You can also compile the tool yourself fairly easily from [source](https://github.com/pelletier/go-toml). + - If you have go installed: `$ go install github.com/pelletier/go-toml/v2/cmd/tomll@latest` + +## Pre-Commit Git Hooks +The python library [pre-commit](https://pre-commit.com/) comes installed with a few useful initial hooks: + +### Default Pre-Commit Hooks: +| Hook Name | Description | +| ------------------ | ------------------------------------------------------------------------------------------------------------ | +| commit-lint | Runs [commitizen](https://commitizen-tools.github.io/commitizen/) on your commit message to validate it. | +| molecule-lint | Checks your profile for best Ansible practices and behaviour. | +| toml-lint | Optionally runs [tomll](https://github.com/pelletier/go-toml) on your TOML configuration file. | + ## Third Party Integrations Integrations with the following third party services are configured during templating: diff --git a/cookiecutter.json b/cookiecutter.json index 2c07113f..dca75b13 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -1,6 +1,7 @@ { "project_name": "Flower Generator", "project_slug": "{{ cookiecutter.project_name|slugify }}", + "optional_toml_linting": ["true", "false"], "github_handle": "niall-byrne", "galaxy_role_slug": "{{ cookiecutter.project_slug.replace('-', '_').replace('.', '_') }}", "galaxy_namespace_slug": "{{ cookiecutter.github_handle|slugify|replace('-', '_')|replace('.', '_') }}", diff --git a/hooks/post_gen_project.sh b/hooks/post_gen_project.sh index 4e9e10a7..52af4bd6 100644 --- a/hooks/post_gen_project.sh +++ b/hooks/post_gen_project.sh @@ -6,6 +6,7 @@ # ANSIBLE_WORKBENCH_BRANCH_NAME_BASE: Optional alternate base branch name. # ANSIBLE_WORKBENCH_BRANCH_NAME_DEVELOPMENT: Optional alternate development branch name. # ANSIBLE_WORKBENCH_SKIP_POETRY: Optionally set to 1 to skip installing dependencies. +# ANSIBLE_WORKBENCH_SKIP_PRECOMMIT: Optionally set to 1 to skip installing pre-commit hooks. # cookiecutter only script. @@ -34,6 +35,15 @@ initialize_poetry() { } +initialize_precommit() { + + if [[ "${ANSIBLE_WORKBENCH_SKIP_PRECOMMIT}" != "1" ]]; then + poetry run pre-commit install -t pre-commit -t commit-msg + poetry run molecule dependency + fi + +} + update_template_values() { if ! grep "${ANSIBLE_WORKBENCH_TEMPLATE_URL}" .cookiecutter/cookiecutter.json; then @@ -49,6 +59,7 @@ main() { update_template_values initialize_git initialize_poetry + initialize_precommit } diff --git a/scripts/test.sh b/scripts/test.sh index 3210b20d..359b9017 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -5,6 +5,8 @@ # Development only script. +OPTIONAL_TOML_LINTING=1 + set -eo pipefail main() { @@ -12,7 +14,7 @@ main() { rm -rf ../flower-generator pushd .. - echo -e "\n\n\n\n\n\n\n\n\n" | cookiecutter ansible-workbench + echo -e "\n\n${OPTIONAL_TOML_LINTING}\n\n\n\n\n\n\n\n" | cookiecutter ansible-workbench cd flower-generator echo -e "\nExit from this shell when finished testing ..." bash diff --git a/{{cookiecutter.project_slug}}/.github/workflows/push.yml b/{{cookiecutter.project_slug}}/.github/workflows/push.yml index e241c687..8c6f39b0 100644 --- a/{{cookiecutter.project_slug}}/.github/workflows/push.yml +++ b/{{cookiecutter.project_slug}}/.github/workflows/push.yml @@ -10,7 +10,7 @@ on: env: PROJECT_NAME: "{{ cookiecutter.project_slug }}" - USERNAME: "{{ cookiecutter.github_handle }}" + USER_NAME: "{{ cookiecutter.github_handle }}" VERBOSE_NOTIFICATIONS: 0 {% raw %} @@ -76,7 +76,7 @@ jobs: ./.github/scripts/notifications.sh "${NOTIFICATION}" ":x: error reporting job status!" create_release: - needs: [_create_python_versions, _start_notification, documentation_test, molecule_lint_test, molecule_test, security_test, yaml_lint_test] + needs: {% endraw %}[_create_python_versions, _start_notification, documentation_test, molecule_lint_test, molecule_test, security_test,{% if cookiecutter.optional_toml_linting == 'true' %} toml_lint_test,{% endif %} yaml_lint_test]{% raw %} runs-on: ubuntu-latest @@ -132,7 +132,7 @@ jobs: - name: Create Release -- Report Job Status (Success) if: steps.branch_filter.outputs.match == 'TRUE' run: | - ./.github/scripts/notifications.sh "${NOTIFICATION}" ":white_check_mark: automated release has been created:\nhttps://github.com/${USERNAME}/${PROJECT_NAME}/releases" + ./.github/scripts/notifications.sh "${NOTIFICATION}" ":white_check_mark: automated release has been created:\nhttps://github.com/${USER_NAME}/${PROJECT_NAME}/releases" - name: Create Release -- Report Job Status (Failure) if: failure() @@ -345,6 +345,40 @@ jobs: run: | ./.github/scripts/notifications.sh "${NOTIFICATION}" ":x: security checks failed!" + {%- endraw %}{% if cookiecutter.optional_toml_linting == 'true' %} + + toml_lint_test: + + runs-on: ubuntu-latest + + steps: + - name: Toml Lint Test -- Checkout Repository + uses: {{ cookiecutter._GITHUB_ACTION_CHECKOUT }} + + - name: Toml Lint Test -- Setup Environment + run: | + source ./.github/scripts/setup.sh + sudo apt-get install -y golang-github-pelletier-go-toml + env: + WEBHOOK_URL: {{ '${{' }} secrets.SLACK_WEBHOOK {{ '}}' }} + + - name: Toml Lint Test -- Run Linter + run: | + find . -type f -name "*.toml" -exec tomll "{}" \; + git diff --exit-code + + - name: Toml Lint Test -- Report Job Status (Success) + if: env.VERBOSE_NOTIFICATIONS == '1' + run: | + ./.github/scripts/notifications.sh "${NOTIFICATION}" ":white_check_mark: toml linting was successful!" + + - name: Toml Lint Test -- Report Job Status (Failure) + if: failure() + run: | + ./.github/scripts/notifications.sh "${NOTIFICATION}" ":x: toml linting has failed!" + + {%- endif %}{% raw %} + yaml_lint_test: runs-on: ubuntu-latest diff --git a/{{cookiecutter.project_slug}}/.github/workflows/release.yml b/{{cookiecutter.project_slug}}/.github/workflows/release.yml index c9f79a4b..500ef2af 100644 --- a/{{cookiecutter.project_slug}}/.github/workflows/release.yml +++ b/{{cookiecutter.project_slug}}/.github/workflows/release.yml @@ -18,7 +18,7 @@ on: env: PROJECT_NAME: "{{ cookiecutter.project_slug }}" PYTHON_VERSIONS: '{{ cookiecutter._GITHUB_CI_PYTHON_VERSIONS | tojson }}' - USERNAME: "{{ cookiecutter.github_handle }}" + USER_NAME: "{{ cookiecutter.github_handle }}" {% raw %} jobs: @@ -77,7 +77,7 @@ jobs: - name: Publish to Galaxy -- Trigger Ansible Galaxy Import run: | cd role - poetry run ansible-galaxy role import ${USERNAME} ${PROJECT_NAME} --token ${API_KEY} | tee import.log + poetry run ansible-galaxy role import ${USER_NAME} ${PROJECT_NAME} --token ${API_KEY} | tee import.log grep "0 errors" import.log env: API_KEY: ${{ secrets.GALAXY_API_KEY }} diff --git a/{{cookiecutter.project_slug}}/.pre-commit-config.yaml b/{{cookiecutter.project_slug}}/.pre-commit-config.yaml new file mode 100644 index 00000000..d08615a1 --- /dev/null +++ b/{{cookiecutter.project_slug}}/.pre-commit-config.yaml @@ -0,0 +1,29 @@ +--- +repos: + - repo: local + hooks: + - id: commit-lint + name: commit-lint + description: "Check whether the commit message follows committing rules." + entry: ./.pre-commit/commit-lint.sh + language: system + stages: [commit-msg] + - id: molecule-lint + name: molecule-lint + description: "Check the profile for Ansible best practices." + entry: ./.pre-commit/molecule-lint.sh + files: "^.+\\.(yaml|yml)$|^.ansible-lint$" + exclude: "^.github/.+$" + language: system + pass_filenames: false + stages: [commit] +{%- if cookiecutter.optional_toml_linting == 'true' %} + - id: toml-lint + name: toml-lint + description: "Lint the project's TOML files." + entry: ./.pre-commit/toml-lint.sh + files: "^.+\\.toml$" + language: system + stages: [commit] + pass_filenames: true +{%- endif %} diff --git a/{{cookiecutter.project_slug}}/.pre-commit/.poetry-compatible.sh b/{{cookiecutter.project_slug}}/.pre-commit/.poetry-compatible.sh new file mode 100644 index 00000000..9bd337b1 --- /dev/null +++ b/{{cookiecutter.project_slug}}/.pre-commit/.poetry-compatible.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +# scripts/pre-commit/.poetry-compatible.sh +# Enables running commands in or outside the Poetry virtual environment seamlessly. + +# @: An array of commands to run. + +# pre-commit script. + +set -eo pipefail + +run_command() { + + if [[ "${POETRY_ACTIVE}" == "1" ]]; then + "$@" + else + poetry run "$@" + fi + +} diff --git a/{{cookiecutter.project_slug}}/.pre-commit/commit-lint.sh b/{{cookiecutter.project_slug}}/.pre-commit/commit-lint.sh new file mode 100755 index 00000000..eb70da87 --- /dev/null +++ b/{{cookiecutter.project_slug}}/.pre-commit/commit-lint.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +# scripts/pre-commit/commit-lint.sh +# Runs commitizen on the passed commit message file. + +# 1: The path to the commit message file. + +# pre-commit script. + +set -eo pipefail + + +main () { + + # shellcheck source=./.pre-commit/.poetry-compatible.sh + source "$(dirname -- "${BASH_SOURCE[0]}")/.poetry-compatible.sh" + + run_command cz check --allow-abort --commit-msg-file "$1" + +} + +main "$@" diff --git a/{{cookiecutter.project_slug}}/.pre-commit/molecule-lint.sh b/{{cookiecutter.project_slug}}/.pre-commit/molecule-lint.sh new file mode 100755 index 00000000..abde8ec5 --- /dev/null +++ b/{{cookiecutter.project_slug}}/.pre-commit/molecule-lint.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# scripts/pre-commit/ansible-lint.sh +# Runs molecule to install/update the dependencies if needed, and then lints changes. + +# pre-commit script. + +set -eo pipefail + +main() { + + # shellcheck source=./.pre-commit/.poetry-compatible.sh + source "$(dirname -- "${BASH_SOURCE[0]}")/.poetry-compatible.sh" + + if ! git diff --exit-code HEAD -- requirements.yml; then + run_command molecule dependency + fi + + run_command molecule lint + +} + +main "$@" diff --git a/{{cookiecutter.project_slug}}/.pre-commit/toml-lint.sh b/{{cookiecutter.project_slug}}/.pre-commit/toml-lint.sh new file mode 100755 index 00000000..3eb28b4d --- /dev/null +++ b/{{cookiecutter.project_slug}}/.pre-commit/toml-lint.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# scripts/pre-commit/toml-lint.sh +# Runs tomll on the specified files and then runs diff to detect changes. + +# @: An array of toml files to lint. + +# pre-commit script. + +set -eo pipefail + +main () { + + for TOML_FILE in "$@"; do + + # shellcheck disable=SC2002 + diff "${TOML_FILE}" <(cat "${TOML_FILE}" | tomll) + + done + +} + +main "$@" diff --git a/{{cookiecutter.project_slug}}/molecule/default/molecule.yml b/{{cookiecutter.project_slug}}/molecule/default/molecule.yml index cd3b7f69..bf6bdf57 100644 --- a/{{cookiecutter.project_slug}}/molecule/default/molecule.yml +++ b/{{cookiecutter.project_slug}}/molecule/default/molecule.yml @@ -1,6 +1,9 @@ --- dependency: name: galaxy + options: + role-file: requirements.yml + requirements-file: requirements.yml driver: name: delegated platforms: diff --git a/{{cookiecutter.project_slug}}/molecule/docker1/molecule.yml b/{{cookiecutter.project_slug}}/molecule/docker1/molecule.yml index b5710a8e..aec43b91 100644 --- a/{{cookiecutter.project_slug}}/molecule/docker1/molecule.yml +++ b/{{cookiecutter.project_slug}}/molecule/docker1/molecule.yml @@ -1,6 +1,9 @@ --- dependency: name: galaxy + options: + role-file: requirements.yml + requirements-file: requirements.yml driver: name: docker platforms: diff --git a/{{cookiecutter.project_slug}}/molecule/hostmachine1/molecule.yml b/{{cookiecutter.project_slug}}/molecule/hostmachine1/molecule.yml index 5d013aad..709d32d7 100644 --- a/{{cookiecutter.project_slug}}/molecule/hostmachine1/molecule.yml +++ b/{{cookiecutter.project_slug}}/molecule/hostmachine1/molecule.yml @@ -1,6 +1,9 @@ --- dependency: name: galaxy + options: + role-file: requirements.yml + requirements-file: requirements.yml driver: name: delegated options: diff --git a/{{cookiecutter.project_slug}}/pyproject.toml b/{{cookiecutter.project_slug}}/pyproject.toml index 46f7a204..a4982846 100644 --- a/{{cookiecutter.project_slug}}/pyproject.toml +++ b/{{cookiecutter.project_slug}}/pyproject.toml @@ -1,20 +1,27 @@ -[tool.poetry] -name = "{{cookiecutter.project_slug}}" -version = "0.1.0" -description = "{{cookiecutter.description}}" -authors = ["{{cookiecutter.author}} <{{cookiecutter.email}}>"] -[tool.poetry.dependencies] -python = ">={{ cookiecutter._GITHUB_CI_PYTHON_VERSIONS | first }}.0,<4.0" +[build-system] + build-backend = "poetry.core.masonry.api" + requires = ["poetry-core>=1.0.0"] -[tool.poetry.dev-dependencies] -ansible = "^5.2.0" -ansible-compat = "<2.1.0" # https://github.com/ansible-community/ansible-compat/issues/114 -ansible-lint = "^5.3.2" -commitizen = "^2.20.4" -molecule = {extras = ["docker"], version = "^3.5.2"} -yamllint = "^1.26.3" +[tool] -[build-system] -requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" + [tool.poetry] + authors = ["{{cookiecutter.author}} <{{cookiecutter.email}}>"] + description = "{{cookiecutter.description}}" + name = "{{cookiecutter.project_slug}}" + version = "0.1.0" + + [tool.poetry.dependencies] + python = ">={{ cookiecutter._GITHUB_CI_PYTHON_VERSIONS | first }}.0,<4.0" + + [tool.poetry.dev-dependencies] + ansible = "^5.2.0" + ansible-compat = "<2.1.0" + ansible-lint = "^5.3.2" + commitizen = "^2.20.4" + pre-commit = "^3.1.0" + yamllint = "^1.26.3" + + [tool.poetry.dev-dependencies.molecule] + extras = ["docker"] + version = "^3.5.2"