diff --git a/.coderabbit.yaml b/.coderabbit.yaml index 068d3d0dba..6c3bf6334c 100644 --- a/.coderabbit.yaml +++ b/.coderabbit.yaml @@ -3,15 +3,14 @@ # Based on conventions from https://linux-system-roles.github.io/contribute.html # This file is managed from https://github.com/linux-system-roles/.github, # any manual edits will be overwritten. - +--- chat: art: false + allow_non_org_members: false reviews: - # Skip reviews for PRs with [citest_skip] in the title auto_review: - ignore_title_keywords: - - "[citest_skip]" + enabled: false # to conserve resources, reviews are done manually # Disable fun features poem: false @@ -200,13 +199,14 @@ reviews: - NEVER use `ansible.builtin.include_role` directly - NEVER use `ansible.builtin.import_role` directly - NEVER use `roles:` keyword - - ALWAYS use the centrally managed wrapper: + - ALMOST ALWAYS use the centrally managed wrapper: ```yaml - name: Run role ansible.builtin.include_tasks: tasks/run_role_with_clear_facts.yml vars: postgresql_: ``` + The only exception to this rule is in tests_invalid_inputs.yml where we need to use the include_role directly to test the invalid inputs. **Test quality requirements:** - Tests should verify both success and failure scenarios diff --git a/.github/workflows/ansible-lint.yml b/.github/workflows/ansible-lint.yml index 0d8dc9fb33..ebd55ca997 100644 --- a/.github/workflows/ansible-lint.yml +++ b/.github/workflows/ansible-lint.yml @@ -1,23 +1,12 @@ --- name: Ansible Lint on: # yamllint disable-line rule:truthy - pull_request: - types: - - opened - - synchronize - - labeled - issue_comment: - types: - - created - merge_group: - branches: - - main - types: - - checks_requested - push: - branches: - - main - workflow_dispatch: + workflow_call: + inputs: + requested: + description: Run this workflow for an authorized /citest command + required: true + type: boolean env: LSR_ROLE2COLL_NAMESPACE: fedora LSR_ROLE2COLL_NAME: linux_system_roles @@ -28,40 +17,7 @@ permissions: statuses: write jobs: ansible_lint: - if: | - ( - github.event_name == 'issue_comment' - && github.event.issue.pull_request - && (contains(github.event.comment.body, '[citest_all]') - || contains(github.event.comment.body, '[citest_ansible-lint]')) - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.comment.author_association) - || github.event.comment.user.login == 'systemroller') - ) || ( - github.event_name == 'pull_request' - && github.event.action == 'opened' - && (contains(github.event.pull_request.labels.*.name, 'citest_all') - || contains(github.event.pull_request.labels.*.name, 'citest_ansible-lint')) - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.pull_request.author_association) - || github.event.pull_request.user.login == 'systemroller') - ) || ( - github.event_name == 'pull_request' - && github.event.action == 'synchronize' - && (contains(github.event.pull_request.labels.*.name, 'citest_all') - || contains(github.event.pull_request.labels.*.name, 'citest_ansible-lint')) - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.pull_request.author_association) - || github.event.sender.login == 'systemroller') - ) || ( - github.event_name == 'pull_request' - && github.event.action == 'labeled' - && (github.event.label.name == 'citest_all' - || github.event.label.name == 'citest_ansible-lint') - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.pull_request.author_association) - || github.event.sender.login == 'systemroller') - ) + if: inputs.requested || github.event_name != 'issue_comment' runs-on: ubuntu-latest strategy: fail-fast: false @@ -95,7 +51,7 @@ jobs: status: pending context: ${{ steps.head_sha_context.outputs.context }} description: Test started - targetUrl: "" + targetUrl: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/job/${{ job.check_run_id }} - name: Update pip, git run: | @@ -138,4 +94,4 @@ jobs: status: ${{ job.status }} context: ${{ steps.head_sha_context.outputs.context }} description: Test finished - targetUrl: "" + targetUrl: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/job/${{ job.check_run_id }} diff --git a/.github/workflows/ansible-managed-var-comment.yml b/.github/workflows/ansible-managed-var-comment.yml index c4e2f0456d..7b2836a6ad 100644 --- a/.github/workflows/ansible-managed-var-comment.yml +++ b/.github/workflows/ansible-managed-var-comment.yml @@ -1,23 +1,12 @@ --- name: Check for ansible_managed variable use in comments on: # yamllint disable-line rule:truthy - pull_request: - types: - - opened - - synchronize - - labeled - issue_comment: - types: - - created - merge_group: - branches: - - main - types: - - checks_requested - push: - branches: - - main - workflow_dispatch: + workflow_call: + inputs: + requested: + description: Run this workflow for an authorized /citest command + required: true + type: boolean permissions: contents: read pull-requests: read @@ -25,40 +14,7 @@ permissions: statuses: write jobs: ansible_managed_var_comment: - if: | - ( - github.event_name == 'issue_comment' - && github.event.issue.pull_request - && (contains(github.event.comment.body, '[citest_all]') - || contains(github.event.comment.body, '[citest_ansible-managed-var-comment]')) - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.comment.author_association) - || github.event.comment.user.login == 'systemroller') - ) || ( - github.event_name == 'pull_request' - && github.event.action == 'opened' - && (contains(github.event.pull_request.labels.*.name, 'citest_all') - || contains(github.event.pull_request.labels.*.name, 'citest_ansible-managed-var-comment')) - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.pull_request.author_association) - || github.event.pull_request.user.login == 'systemroller') - ) || ( - github.event_name == 'pull_request' - && github.event.action == 'synchronize' - && (contains(github.event.pull_request.labels.*.name, 'citest_all') - || contains(github.event.pull_request.labels.*.name, 'citest_ansible-managed-var-comment')) - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.pull_request.author_association) - || github.event.sender.login == 'systemroller') - ) || ( - github.event_name == 'pull_request' - && github.event.action == 'labeled' - && (github.event.label.name == 'citest_all' - || github.event.label.name == 'citest_ansible-managed-var-comment') - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.pull_request.author_association) - || github.event.sender.login == 'systemroller') - ) + if: inputs.requested || github.event_name != 'issue_comment' runs-on: ubuntu-latest steps: - name: Get PR head SHA and context @@ -83,7 +39,7 @@ jobs: status: pending context: ${{ steps.head_sha_context.outputs.context }} description: Test started - targetUrl: "" + targetUrl: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/job/${{ job.check_run_id }} - name: Update pip, git run: | @@ -116,4 +72,4 @@ jobs: status: ${{ job.status }} context: ${{ steps.head_sha_context.outputs.context }} description: Test finished - targetUrl: "" + targetUrl: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/job/${{ job.check_run_id }} diff --git a/.github/workflows/ansible-test.yml b/.github/workflows/ansible-test.yml index cefb144310..75a45d499f 100644 --- a/.github/workflows/ansible-test.yml +++ b/.github/workflows/ansible-test.yml @@ -1,23 +1,12 @@ --- name: Ansible Test on: # yamllint disable-line rule:truthy - pull_request: - types: - - opened - - synchronize - - labeled - issue_comment: - types: - - created - merge_group: - branches: - - main - types: - - checks_requested - push: - branches: - - main - workflow_dispatch: + workflow_call: + inputs: + requested: + description: Run this workflow for an authorized /citest command + required: true + type: boolean env: LSR_ROLE2COLL_NAMESPACE: fedora LSR_ROLE2COLL_NAME: linux_system_roles @@ -28,40 +17,7 @@ permissions: statuses: write jobs: ansible_test: - if: | - ( - github.event_name == 'issue_comment' - && github.event.issue.pull_request - && (contains(github.event.comment.body, '[citest_all]') - || contains(github.event.comment.body, '[citest_ansible-test]')) - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.comment.author_association) - || github.event.comment.user.login == 'systemroller') - ) || ( - github.event_name == 'pull_request' - && github.event.action == 'opened' - && (contains(github.event.pull_request.labels.*.name, 'citest_all') - || contains(github.event.pull_request.labels.*.name, 'citest_ansible-test')) - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.pull_request.author_association) - || github.event.pull_request.user.login == 'systemroller') - ) || ( - github.event_name == 'pull_request' - && github.event.action == 'synchronize' - && (contains(github.event.pull_request.labels.*.name, 'citest_all') - || contains(github.event.pull_request.labels.*.name, 'citest_ansible-test')) - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.pull_request.author_association) - || github.event.sender.login == 'systemroller') - ) || ( - github.event_name == 'pull_request' - && github.event.action == 'labeled' - && (github.event.label.name == 'citest_all' - || github.event.label.name == 'citest_ansible-test') - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.pull_request.author_association) - || github.event.sender.login == 'systemroller') - ) + if: inputs.requested || github.event_name != 'issue_comment' runs-on: ubuntu-latest strategy: fail-fast: false # get all results, not just the first failure @@ -97,7 +53,7 @@ jobs: status: pending context: ${{ steps.head_sha_context.outputs.context }} description: Test started - targetUrl: "" + targetUrl: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/job/${{ job.check_run_id }} - name: Update pip, git run: | @@ -139,4 +95,4 @@ jobs: status: ${{ job.status }} context: ${{ steps.head_sha_context.outputs.context }} description: Test finished - targetUrl: "" + targetUrl: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/job/${{ job.check_run_id }} diff --git a/.github/workflows/citest-instructions.yml b/.github/workflows/citest-instructions.yml new file mode 100644 index 0000000000..daa12665b0 --- /dev/null +++ b/.github/workflows/citest-instructions.yml @@ -0,0 +1,81 @@ +--- +# This workflow must never check out or execute pull request code. It uses +# pull_request_target only so fork pull requests can receive this fixed comment. +name: Show CI test instructions +on: # yamllint disable-line rule:truthy + pull_request_target: + types: + - opened + +permissions: + contents: read + pull-requests: write + +jobs: + instructions: + permissions: + contents: read + pull-requests: write + runs-on: ubuntu-latest + steps: + - name: Post CI test instructions + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.pull_request.number }} + REPO: ${{ github.repository }} + run: | + gh api --method POST "repos/${REPO}/issues/${PR_NUMBER}/comments" \ + --raw-field body="$(sed 's/^ //' <<'EOF' + CI tests do not run automatically on pull requests. A role repository + maintainer can start them by posting a `/citest` slash command in a + pull request comment. + + See [GitHub CI testing using /citest](https://github.com/linux-system-roles/postgresql/blob/main/contributing.md#github-ci-testing-using-citest) + for details. + + Run every available CI workflow: + + ```text + /citest all + ``` + + Run the linting and other lightweight checks: + + ```text + /citest linters + ``` + + Run the integration tests (QEMU/container and Testing Farm): + + ```text + /citest integration + ``` + + Run one or more selected workflows by separating their names with spaces: + + ```text + /citest ansible-lint + /citest ansible-lint markdownlint + ``` + + | Command | Check name | Description | + | --- | --- | --- | + | `/citest all` | All checks listed below | Run every CI test available for this role | + | `/citest linters` | Lint and lightweight checks | Run ansible-lint, ansible-test, ansible-managed-var-comment, codespell, markdownlint, pr-title-lint, test_converting_readme, and codeql, python-unit-test, and shellcheck when those workflows exist | + | `/citest integration` | QEMU/container and Testing Farm checks | Run qemu-kvm-integration-tests and tft | + | `/citest ansible-lint` | `Ansible Lint / ansible_lint (, , ) (pull_request)` | Lint Ansible content after converting the role to collection format | + | `/citest ansible-managed-var-comment` | `Check for ansible_managed variable use in comments / ansible_managed_var_comment (pull_request)` | Fail if `ansible_managed` is used in comments | + | `/citest ansible-test` | `Ansible Test / ansible_test (, ) (pull_request)` | Run ansible-test sanity tests | + | `/citest codespell` | `Codespell / Check for spelling errors (pull_request)` | Check for spelling errors | + | `/citest markdownlint` | `Markdown Lint / markdownlint (pull_request)` | Lint Markdown files | + | `/citest pr-title-lint` | `PR Title Lint / commit-checks` | Check that the pull request title follows the required format | + | `/citest qemu-kvm-integration-tests` | `Test / scenario (, ) (pull_request)` | Run role integration tests in QEMU VMs and containers | + | `/citest test_converting_readme` | `Test converting README.md to README.html / test_converting_readme (pull_request)` | Convert README.md to HTML | + | `/citest tft` | `\|ansible-` | Run integration tests in Testing Farm | + | `/citest woke` | `Woke / Detect non-inclusive language (pull_request)` | Detect non-inclusive language | + + Post another `/citest` comment at any time to run another selection. + + + EOF + )" diff --git a/.github/workflows/citest.yml b/.github/workflows/citest.yml new file mode 100644 index 0000000000..f48775b5bf --- /dev/null +++ b/.github/workflows/citest.yml @@ -0,0 +1,212 @@ +--- +name: Run CI tests +on: # yamllint disable-line rule:truthy + issue_comment: + types: + - created + +permissions: + actions: read + contents: read + pull-requests: read + statuses: write + +jobs: + parse: + if: | + github.event_name == 'issue_comment' + && github.event.issue.pull_request + && (github.event.comment.body == '/citest' + || startsWith(github.event.comment.body, '/citest ')) + && (contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), + github.event.comment.author_association) + || github.event.comment.user.login == 'systemroller') + runs-on: ubuntu-latest + outputs: + selected: ${{ steps.command.outputs.selected }} + steps: + - name: Parse and authorize command + id: command + env: + COMMENT_BODY: ${{ github.event.comment.body }} + COMMENTER: ${{ github.event.comment.user.login }} + GH_TOKEN: ${{ github.token }} + REPO: ${{ github.repository }} + run: | + set -euo pipefail + if [ "$COMMENTER" != systemroller ]; then + permission=$(gh api \ + "repos/${REPO}/collaborators/${COMMENTER}/permission" \ + --jq '.permission') + case "$permission" in + admin|maintain|write) ;; + *) + echo "@${COMMENTER} does not have permission to run CI tests" >&2 + exit 1 + ;; + esac + fi + + command_line=${COMMENT_BODY%%$'\n'*} + command_line=${command_line%$'\r'} + read -r -a words <<<"$command_line" + if [ "${words[0]-}" != /citest ] || [ -z "${words[1]-}" ]; then + echo 'Usage: /citest all | /citest linters | /citest integration | /citest WORKFLOW [WORKFLOW ...]' >&2 + exit 1 + fi + + known=( + ansible-lint + ansible-managed-var-comment + ansible-test + codespell + markdownlint + pr-title-lint + qemu-kvm-integration-tests + test_converting_readme + tft + woke + ) + + linters=( + ansible-lint + ansible-managed-var-comment + ansible-test + codespell + markdownlint + pr-title-lint + test_converting_readme + ) + + integration=( + qemu-kvm-integration-tests + tft + ) + + requested=("${words[@]:1}") + selected=() + unknown=() + select_all=false + select_linters=false + select_integration=false + for request in "${requested[@]}"; do + if [ "$request" = all ]; then + select_all=true + continue + fi + if [ "$request" = linters ]; then + select_linters=true + continue + fi + if [ "$request" = integration ]; then + select_integration=true + continue + fi + found=false + for workflow in "${known[@]}"; do + if [ "$request" = "$workflow" ]; then + found=true + selected+=("$workflow") + break + fi + done + if [ "$found" = false ]; then + unknown+=("$request") + fi + done + + if [ -n "${unknown[*]-}" ]; then + printf 'Unknown workflow: %s\n' "${unknown[@]}" >&2 + printf 'Known workflows: %s all linters integration\n' "${known[*]}" >&2 + exit 1 + fi + if [ "$select_all" = true ]; then + selected=("${known[@]}") + else + if [ "$select_linters" = true ]; then + selected+=("${linters[@]}") + fi + if [ "$select_integration" = true ]; then + selected+=("${integration[@]}") + fi + fi + + selected_json=$(printf '%s\n' "${selected[@]}" \ + | jq -Rsc 'split("\n") | map(select(length > 0)) | unique') + echo "selected=$selected_json" >> "$GITHUB_OUTPUT" + echo "Selected workflows: $selected_json" + + ansible_lint: + needs: parse + if: contains(fromJSON(needs.parse.outputs.selected), 'ansible-lint') + uses: ./.github/workflows/ansible-lint.yml + with: + requested: true + + ansible_managed_var_comment: + needs: parse + if: contains(fromJSON(needs.parse.outputs.selected), 'ansible-managed-var-comment') + uses: ./.github/workflows/ansible-managed-var-comment.yml + with: + requested: true + + ansible_test: + needs: parse + if: contains(fromJSON(needs.parse.outputs.selected), 'ansible-test') + uses: ./.github/workflows/ansible-test.yml + with: + requested: true + + codespell: + needs: parse + if: contains(fromJSON(needs.parse.outputs.selected), 'codespell') + uses: ./.github/workflows/codespell.yml + with: + requested: true + + markdownlint: + needs: parse + if: contains(fromJSON(needs.parse.outputs.selected), 'markdownlint') + uses: ./.github/workflows/markdownlint.yml + with: + requested: true + + pr_title_lint: + needs: parse + if: contains(fromJSON(needs.parse.outputs.selected), 'pr-title-lint') + uses: ./.github/workflows/pr-title-lint.yml + with: + requested: true + pr_title: ${{ github.event.issue.title }} + + qemu_kvm_integration_tests: + needs: parse + if: contains(fromJSON(needs.parse.outputs.selected), 'qemu-kvm-integration-tests') + uses: ./.github/workflows/qemu-kvm-integration-tests.yml + with: + requested: true + + test_converting_readme: + needs: parse + if: contains(fromJSON(needs.parse.outputs.selected), 'test_converting_readme') + uses: ./.github/workflows/test_converting_readme.yml + with: + requested: true + + tft: + needs: parse + if: contains(fromJSON(needs.parse.outputs.selected), 'tft') + uses: ./.github/workflows/tft.yml + with: + requested: true + secrets: + SR_LSR_DOMAIN: ${{ secrets.SR_LSR_DOMAIN }} + SR_LSR_SSH_KEY: ${{ secrets.SR_LSR_SSH_KEY }} + TF_API_KEY_RH: ${{ secrets.TF_API_KEY_RH }} + + woke: + needs: parse + if: contains(fromJSON(needs.parse.outputs.selected), 'woke') + uses: ./.github/workflows/woke.yml + with: + requested: true diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index af9b81f9d0..a0e1bdc9a6 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -2,14 +2,12 @@ --- name: Codespell on: # yamllint disable-line rule:truthy - pull_request: - types: - - opened - - synchronize - - labeled - issue_comment: - types: - - created + workflow_call: + inputs: + requested: + description: Run this workflow for an authorized /citest command + required: true + type: boolean permissions: contents: read pull-requests: read @@ -17,40 +15,7 @@ permissions: statuses: write jobs: codespell: - if: | - ( - github.event_name == 'issue_comment' - && github.event.issue.pull_request - && (contains(github.event.comment.body, '[citest_all]') - || contains(github.event.comment.body, '[citest_codespell]')) - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.comment.author_association) - || github.event.comment.user.login == 'systemroller') - ) || ( - github.event_name == 'pull_request' - && github.event.action == 'opened' - && (contains(github.event.pull_request.labels.*.name, 'citest_all') - || contains(github.event.pull_request.labels.*.name, 'citest_codespell')) - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.pull_request.author_association) - || github.event.pull_request.user.login == 'systemroller') - ) || ( - github.event_name == 'pull_request' - && github.event.action == 'synchronize' - && (contains(github.event.pull_request.labels.*.name, 'citest_all') - || contains(github.event.pull_request.labels.*.name, 'citest_codespell')) - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.pull_request.author_association) - || github.event.sender.login == 'systemroller') - ) || ( - github.event_name == 'pull_request' - && github.event.action == 'labeled' - && (github.event.label.name == 'citest_all' - || github.event.label.name == 'citest_codespell') - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.pull_request.author_association) - || github.event.sender.login == 'systemroller') - ) + if: inputs.requested || github.event_name != 'issue_comment' name: Check for spelling errors runs-on: ubuntu-latest steps: @@ -76,7 +41,7 @@ jobs: status: pending context: ${{ steps.head_sha_context.outputs.context }} description: Test started - targetUrl: "" + targetUrl: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/job/${{ job.check_run_id }} - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 @@ -95,4 +60,4 @@ jobs: status: ${{ job.status }} context: ${{ steps.head_sha_context.outputs.context }} description: Test finished - targetUrl: "" + targetUrl: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/job/${{ job.check_run_id }} diff --git a/.github/workflows/markdownlint.yml b/.github/workflows/markdownlint.yml index d5d63ebc15..d0b47ada62 100644 --- a/.github/workflows/markdownlint.yml +++ b/.github/workflows/markdownlint.yml @@ -2,23 +2,12 @@ # yamllint disable rule:line-length name: Markdown Lint on: # yamllint disable-line rule:truthy - pull_request: - types: - - opened - - synchronize - - labeled - issue_comment: - types: - - created - merge_group: - branches: - - main - types: - - checks_requested - push: - branches: - - main - workflow_dispatch: + workflow_call: + inputs: + requested: + description: Run this workflow for an authorized /citest command + required: true + type: boolean permissions: contents: read pull-requests: read @@ -26,40 +15,7 @@ permissions: statuses: write jobs: markdownlint: - if: | - ( - github.event_name == 'issue_comment' - && github.event.issue.pull_request - && (contains(github.event.comment.body, '[citest_all]') - || contains(github.event.comment.body, '[citest_markdownlint]')) - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.comment.author_association) - || github.event.comment.user.login == 'systemroller') - ) || ( - github.event_name == 'pull_request' - && github.event.action == 'opened' - && (contains(github.event.pull_request.labels.*.name, 'citest_all') - || contains(github.event.pull_request.labels.*.name, 'citest_markdownlint')) - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.pull_request.author_association) - || github.event.pull_request.user.login == 'systemroller') - ) || ( - github.event_name == 'pull_request' - && github.event.action == 'synchronize' - && (contains(github.event.pull_request.labels.*.name, 'citest_all') - || contains(github.event.pull_request.labels.*.name, 'citest_markdownlint')) - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.pull_request.author_association) - || github.event.sender.login == 'systemroller') - ) || ( - github.event_name == 'pull_request' - && github.event.action == 'labeled' - && (github.event.label.name == 'citest_all' - || github.event.label.name == 'citest_markdownlint') - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.pull_request.author_association) - || github.event.sender.login == 'systemroller') - ) + if: inputs.requested || github.event_name != 'issue_comment' runs-on: ubuntu-latest steps: - name: Get PR head SHA and context @@ -84,7 +40,7 @@ jobs: status: pending context: ${{ steps.head_sha_context.outputs.context }} description: Test started - targetUrl: "" + targetUrl: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/job/${{ job.check_run_id }} - name: Update pip, git run: | @@ -116,4 +72,4 @@ jobs: status: ${{ job.status }} context: ${{ steps.head_sha_context.outputs.context }} description: Test finished - targetUrl: "" + targetUrl: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/job/${{ job.check_run_id }} diff --git a/.github/workflows/pr-title-lint.yml b/.github/workflows/pr-title-lint.yml index e82f7f35ec..2bea365765 100644 --- a/.github/workflows/pr-title-lint.yml +++ b/.github/workflows/pr-title-lint.yml @@ -1,51 +1,22 @@ --- name: PR Title Lint on: # yamllint disable-line rule:truthy - pull_request: - types: - - opened - - synchronize - - labeled - - reopened - - edited - merge_group: - branches: - - main - types: - - checks_requested + workflow_call: + inputs: + requested: + description: Run this workflow for an authorized /citest command + required: true + type: boolean + pr_title: + description: Pull request title to validate + required: true + type: string permissions: contents: read pull-requests: read jobs: commit-checks: - if: | - ( - github.event_name == 'pull_request' - && github.event.action == 'opened' - && (contains(github.event.pull_request.labels.*.name, 'citest_all') - || contains(github.event.pull_request.labels.*.name, 'citest_pr-title-lint')) - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.pull_request.author_association) - || github.event.pull_request.user.login == 'systemroller') - ) || ( - github.event_name == 'pull_request' - && (github.event.action == 'synchronize' - || github.event.action == 'reopened' - || github.event.action == 'edited') - && (contains(github.event.pull_request.labels.*.name, 'citest_all') - || contains(github.event.pull_request.labels.*.name, 'citest_pr-title-lint')) - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.pull_request.author_association) - || github.event.sender.login == 'systemroller') - ) || ( - github.event_name == 'pull_request' - && github.event.action == 'labeled' - && (github.event.label.name == 'citest_all' - || github.event.label.name == 'citest_pr-title-lint') - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.pull_request.author_association) - || github.event.sender.login == 'systemroller') - ) + if: inputs.requested || github.event_name != 'issue_comment' runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 @@ -58,6 +29,6 @@ jobs: - name: Run pr_title_lint.py on PR title env: - PR_TITLE: ${{ github.event.pull_request.title }} + PR_TITLE: ${{ inputs.pr_title || github.event.pull_request.title }} # Echo from env variable to avoid bash errors with extra characters run: python3 pr_title_lint.py "${PR_TITLE}" diff --git a/.github/workflows/qemu-kvm-integration-tests.yml b/.github/workflows/qemu-kvm-integration-tests.yml index b663e97911..75e3628ece 100644 --- a/.github/workflows/qemu-kvm-integration-tests.yml +++ b/.github/workflows/qemu-kvm-integration-tests.yml @@ -1,23 +1,12 @@ --- name: Test on: # yamllint disable-line rule:truthy - pull_request: - types: - - opened - - synchronize - - labeled - issue_comment: - types: - - created - merge_group: - branches: - - main - types: - - checks_requested - push: - branches: - - main - workflow_dispatch: + workflow_call: + inputs: + requested: + description: Run this workflow for an authorized /citest command + required: true + type: boolean permissions: contents: read @@ -26,40 +15,7 @@ permissions: statuses: write jobs: scenario: - if: | - ( - github.event_name == 'issue_comment' - && github.event.issue.pull_request - && (contains(github.event.comment.body, '[citest_all]') - || contains(github.event.comment.body, '[citest_qemu-kvm-integration-tests]')) - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.comment.author_association) - || github.event.comment.user.login == 'systemroller') - ) || ( - github.event_name == 'pull_request' - && github.event.action == 'opened' - && (contains(github.event.pull_request.labels.*.name, 'citest_all') - || contains(github.event.pull_request.labels.*.name, 'citest_qemu-kvm-integration-tests')) - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.pull_request.author_association) - || github.event.pull_request.user.login == 'systemroller') - ) || ( - github.event_name == 'pull_request' - && github.event.action == 'synchronize' - && (contains(github.event.pull_request.labels.*.name, 'citest_all') - || contains(github.event.pull_request.labels.*.name, 'citest_qemu-kvm-integration-tests')) - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.pull_request.author_association) - || github.event.sender.login == 'systemroller') - ) || ( - github.event_name == 'pull_request' - && github.event.action == 'labeled' - && (github.event.label.name == 'citest_all' - || github.event.label.name == 'citest_qemu-kvm-integration-tests') - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.pull_request.author_association) - || github.event.sender.login == 'systemroller') - ) + if: inputs.requested || github.event_name != 'issue_comment' runs-on: ubuntu-latest strategy: @@ -112,7 +68,7 @@ jobs: status: pending context: ${{ steps.head_sha_context.outputs.context }} description: Test started - targetUrl: "" + targetUrl: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/job/${{ job.check_run_id }} - name: Checkout repo uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 @@ -310,7 +266,7 @@ jobs: status: ${{ job.status }} context: ${{ steps.head_sha_context.outputs.context }} description: Test finished - targetUrl: "" + targetUrl: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/job/${{ job.check_run_id }} - name: Set commit status as success with a description that platform is skipped if: ${{ success() && github.event_name == 'issue_comment' && steps.check_platform.outputs.supported == '' }} @@ -320,4 +276,4 @@ jobs: status: success context: ${{ steps.head_sha_context.outputs.context }} description: The role does not support this platform. Skipping. - targetUrl: "" + targetUrl: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/job/${{ job.check_run_id }} diff --git a/.github/workflows/test_converting_readme.yml b/.github/workflows/test_converting_readme.yml index 1174b7dacc..ef184f3155 100644 --- a/.github/workflows/test_converting_readme.yml +++ b/.github/workflows/test_converting_readme.yml @@ -2,22 +2,12 @@ # yamllint disable rule:line-length name: Test converting README.md to README.html on: # yamllint disable-line rule:truthy - pull_request: - types: - - opened - - synchronize - - labeled - issue_comment: - types: - - created - merge_group: - branches: - - main - types: - - checks_requested - push: - branches: - - main + workflow_call: + inputs: + requested: + description: Run this workflow for an authorized /citest command + required: true + type: boolean permissions: contents: read pull-requests: read @@ -25,44 +15,11 @@ permissions: statuses: write jobs: test_converting_readme: - if: | - ( - github.event_name == 'issue_comment' - && github.event.issue.pull_request - && (contains(github.event.comment.body, '[citest_all]') - || contains(github.event.comment.body, '[citest_test_converting_readme]')) - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.comment.author_association) - || github.event.comment.user.login == 'systemroller') - ) || ( - github.event_name == 'pull_request' - && github.event.action == 'opened' - && (contains(github.event.pull_request.labels.*.name, 'citest_all') - || contains(github.event.pull_request.labels.*.name, 'citest_test_converting_readme')) - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.pull_request.author_association) - || github.event.pull_request.user.login == 'systemroller') - ) || ( - github.event_name == 'pull_request' - && github.event.action == 'synchronize' - && (contains(github.event.pull_request.labels.*.name, 'citest_all') - || contains(github.event.pull_request.labels.*.name, 'citest_test_converting_readme')) - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.pull_request.author_association) - || github.event.sender.login == 'systemroller') - ) || ( - github.event_name == 'pull_request' - && github.event.action == 'labeled' - && (github.event.label.name == 'citest_all' - || github.event.label.name == 'citest_test_converting_readme') - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.pull_request.author_association) - || github.event.sender.login == 'systemroller') - ) + if: inputs.requested || github.event_name != 'issue_comment' runs-on: ubuntu-latest permissions: pull-requests: read - contents: write + contents: read statuses: write steps: - name: Get PR head SHA and context @@ -87,7 +44,7 @@ jobs: status: pending context: ${{ steps.head_sha_context.outputs.context }} description: Test started - targetUrl: "" + targetUrl: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/job/${{ job.check_run_id }} - name: Update pip, git run: | @@ -126,4 +83,4 @@ jobs: status: ${{ job.status }} context: ${{ steps.head_sha_context.outputs.context }} description: Test finished - targetUrl: "" + targetUrl: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/job/${{ job.check_run_id }} diff --git a/.github/workflows/tft.yml b/.github/workflows/tft.yml index e04a7523d9..dc0900dad2 100644 --- a/.github/workflows/tft.yml +++ b/.github/workflows/tft.yml @@ -1,14 +1,19 @@ --- name: Run integration tests in Testing Farm on: - pull_request: - types: - - opened - - synchronize - - labeled - issue_comment: - types: - - created + workflow_call: + inputs: + requested: + description: Run this workflow for an authorized /citest command + required: true + type: boolean + secrets: + SR_LSR_DOMAIN: + required: true + SR_LSR_SSH_KEY: + required: true + TF_API_KEY_RH: + required: true permissions: contents: read pull-requests: read @@ -24,44 +29,7 @@ jobs: cancel-in-progress: true # Let's schedule tests only on user request. NOT automatically. # Only repository owner or member can schedule tests - if: | - ( - github.event_name == 'issue_comment' - && github.event.issue.pull_request - && (contains(github.event.comment.body, '[citest_all]') - || contains(github.event.comment.body, '[citest]') - || contains(github.event.comment.body, '[citest_tft]')) - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.comment.author_association) - || github.event.comment.user.login == 'systemroller') - ) || ( - github.event_name == 'pull_request' - && github.event.action == 'opened' - && (contains(github.event.pull_request.labels.*.name, 'citest_all') - || contains(github.event.pull_request.labels.*.name, 'citest') - || contains(github.event.pull_request.labels.*.name, 'citest_tft')) - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.pull_request.author_association) - || github.event.pull_request.user.login == 'systemroller') - ) || ( - github.event_name == 'pull_request' - && github.event.action == 'synchronize' - && (contains(github.event.pull_request.labels.*.name, 'citest_all') - || contains(github.event.pull_request.labels.*.name, 'citest') - || contains(github.event.pull_request.labels.*.name, 'citest_tft')) - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.pull_request.author_association) - || github.event.sender.login == 'systemroller') - ) || ( - github.event_name == 'pull_request' - && github.event.action == 'labeled' - && (github.event.label.name == 'citest_all' - || github.event.label.name == 'citest' - || github.event.label.name == 'citest_tft') - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.pull_request.author_association) - || github.event.sender.login == 'systemroller') - ) + if: inputs.requested || github.event_name != 'issue_comment' runs-on: ubuntu-latest outputs: supported_platforms: ${{ steps.supported_platforms.outputs.supported_platforms }} @@ -181,7 +149,7 @@ jobs: status: pending context: ${{ steps.head_sha_context.outputs.context }} description: Test started - targetUrl: "" + targetUrl: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/job/${{ job.check_run_id }} - name: Set variables with DATETIME and artifact location id: set_vars @@ -204,7 +172,7 @@ jobs: status: success context: ${{ steps.head_sha_context.outputs.context }} description: The role does not support this platform. Skipping. - targetUrl: "" + targetUrl: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/job/${{ job.check_run_id }} - name: Run test in testing farm uses: sclorg/testing-farm-as-github-action@230555baceb860aa468d216f1822974836b965d1 # v4.3.1 diff --git a/.github/workflows/woke.yml b/.github/workflows/woke.yml index 60aee57793..e6978dfa13 100644 --- a/.github/workflows/woke.yml +++ b/.github/workflows/woke.yml @@ -2,14 +2,12 @@ # yamllint disable rule:line-length name: Woke on: # yamllint disable-line rule:truthy - pull_request: - types: - - opened - - synchronize - - labeled - issue_comment: - types: - - created + workflow_call: + inputs: + requested: + description: Run this workflow for an authorized /citest command + required: true + type: boolean permissions: contents: read pull-requests: read @@ -17,40 +15,7 @@ permissions: statuses: write jobs: woke: - if: | - ( - github.event_name == 'issue_comment' - && github.event.issue.pull_request - && (contains(github.event.comment.body, '[citest_all]') - || contains(github.event.comment.body, '[citest_woke]')) - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.comment.author_association) - || github.event.comment.user.login == 'systemroller') - ) || ( - github.event_name == 'pull_request' - && github.event.action == 'opened' - && (contains(github.event.pull_request.labels.*.name, 'citest_all') - || contains(github.event.pull_request.labels.*.name, 'citest_woke')) - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.pull_request.author_association) - || github.event.pull_request.user.login == 'systemroller') - ) || ( - github.event_name == 'pull_request' - && github.event.action == 'synchronize' - && (contains(github.event.pull_request.labels.*.name, 'citest_all') - || contains(github.event.pull_request.labels.*.name, 'citest_woke')) - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.pull_request.author_association) - || github.event.sender.login == 'systemroller') - ) || ( - github.event_name == 'pull_request' - && github.event.action == 'labeled' - && (github.event.label.name == 'citest_all' - || github.event.label.name == 'citest_woke') - && (contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), - github.event.pull_request.author_association) - || github.event.sender.login == 'systemroller') - ) + if: inputs.requested || github.event_name != 'issue_comment' name: Detect non-inclusive language runs-on: ubuntu-latest steps: @@ -76,7 +41,7 @@ jobs: status: pending context: ${{ steps.head_sha_context.outputs.context }} description: Test started - targetUrl: "" + targetUrl: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/job/${{ job.check_run_id }} - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 @@ -100,4 +65,4 @@ jobs: status: ${{ job.status }} context: ${{ steps.head_sha_context.outputs.context }} description: Test finished - targetUrl: "" + targetUrl: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/job/${{ job.check_run_id }} diff --git a/README.md b/README.md index 293c1d2384..bb9a404dce 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # PostgreSQL system role -[![ansible-lint.yml](https://github.com/linux-system-roles/postgresql/actions/workflows/ansible-lint.yml/badge.svg)](https://github.com/linux-system-roles/postgresql/actions/workflows/ansible-lint.yml) [![ansible-test.yml](https://github.com/linux-system-roles/postgresql/actions/workflows/ansible-test.yml/badge.svg)](https://github.com/linux-system-roles/postgresql/actions/workflows/ansible-test.yml) [![codespell.yml](https://github.com/linux-system-roles/postgresql/actions/workflows/codespell.yml/badge.svg)](https://github.com/linux-system-roles/postgresql/actions/workflows/codespell.yml) [![markdownlint.yml](https://github.com/linux-system-roles/postgresql/actions/workflows/markdownlint.yml/badge.svg)](https://github.com/linux-system-roles/postgresql/actions/workflows/markdownlint.yml) [![qemu-kvm-integration-tests.yml](https://github.com/linux-system-roles/postgresql/actions/workflows/qemu-kvm-integration-tests.yml/badge.svg)](https://github.com/linux-system-roles/postgresql/actions/workflows/qemu-kvm-integration-tests.yml) [![tft.yml](https://github.com/linux-system-roles/postgresql/actions/workflows/tft.yml/badge.svg)](https://github.com/linux-system-roles/postgresql/actions/workflows/tft.yml) [![tft_citest_bad.yml](https://github.com/linux-system-roles/postgresql/actions/workflows/tft_citest_bad.yml/badge.svg)](https://github.com/linux-system-roles/postgresql/actions/workflows/tft_citest_bad.yml) [![woke.yml](https://github.com/linux-system-roles/postgresql/actions/workflows/woke.yml/badge.svg)](https://github.com/linux-system-roles/postgresql/actions/workflows/woke.yml) +[![citest.yml](https://github.com/linux-system-roles/postgresql/actions/workflows/citest.yml/badge.svg)](https://github.com/linux-system-roles/postgresql/actions/workflows/citest.yml) The PostgreSQL system role installs, configures, and starts the PostgreSQL server. diff --git a/contributing.md b/contributing.md index 31f7c7bcf7..f168b1c1ae 100644 --- a/contributing.md +++ b/contributing.md @@ -20,6 +20,59 @@ are likely to be suitable for new contributors! **Code** is managed on [Github](https://github.com/linux-system-roles/postgresql), using [Pull Requests](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests). +## GitHub CI testing using /citest + +GitHub CI tests do not run automatically on pull requests. A role repository +maintainer must start them by posting a `/citest` slash command as a pull +request comment. + +Run every available CI workflow: + +```text +/citest all +``` + +Run the linting and other lightweight checks: + +```text +/citest linters +``` + +Run the integration tests (QEMU/container and Testing Farm): + +```text +/citest integration +``` + +Run one or more selected workflows by separating their names with spaces: + +```text +/citest ansible-lint +/citest ansible-lint markdownlint +``` + +Post another `/citest` comment at any time to run another selection. + +The table below lists each command, the check name shown in the pull request +checks list, and what the test does. Matrix jobs produce one check per +combination; those rows show the check name pattern. + +| Command | Check name | Description | +| --- | --- | --- | +| `/citest all` | All checks listed below | Run every CI test available for this role | +| `/citest linters` | Lint and lightweight checks | Run ansible-lint, ansible-test, ansible-managed-var-comment, codespell, markdownlint, pr-title-lint, test_converting_readme, and codeql, python-unit-test, and shellcheck when those workflows exist | +| `/citest integration` | QEMU/container and Testing Farm checks | Run qemu-kvm-integration-tests and tft | +| `/citest ansible-lint` | `Ansible Lint / ansible_lint (, , ) (pull_request)` | Lint Ansible content after converting the role to collection format | +| `/citest ansible-managed-var-comment` | `Check for ansible_managed variable use in comments / ansible_managed_var_comment (pull_request)` | Fail if `ansible_managed` is used in comments | +| `/citest ansible-test` | `Ansible Test / ansible_test (, ) (pull_request)` | Run ansible-test sanity tests | +| `/citest codespell` | `Codespell / Check for spelling errors (pull_request)` | Check for spelling errors | +| `/citest markdownlint` | `Markdown Lint / markdownlint (pull_request)` | Lint Markdown files | +| `/citest pr-title-lint` | `PR Title Lint / commit-checks` | Check that the pull request title follows the required format | +| `/citest qemu-kvm-integration-tests` | `Test / scenario (, ) (pull_request)` | Run role integration tests in QEMU VMs and containers | +| `/citest test_converting_readme` | `Test converting README.md to README.html / test_converting_readme (pull_request)` | Convert README.md to HTML | +| `/citest tft` | `\|ansible-` | Run integration tests in Testing Farm | +| `/citest woke` | `Woke / Detect non-inclusive language (pull_request)` | Detect non-inclusive language | + ## AI Coding Assistants The `.coderabbit.yaml` configuration file in the repository root contains coding