diff --git a/.github/workflows/test-action.yml b/.github/workflows/test-action.yml index a4aa5f5..2bfc100 100644 --- a/.github/workflows/test-action.yml +++ b/.github/workflows/test-action.yml @@ -36,6 +36,8 @@ jobs: - '' pre-test-cmd: - '' + pull-request-change-detection: + - '' target: - '' target-python-version: @@ -68,8 +70,10 @@ jobs: testing-type: units - ansible-core-version: stable-2.13 collection-root: .internal/ansible/ansible_collections/internal/test - collection-src-directory: ./.tmp-action-checkout + # NOTE: A missing `collection-src-directory` input causes + # NOTE: fetching the repo from GitHub. origin-python-version: '3.9' + pull-request-change-detection: 'true' testing-type: integration - ansible-core-version: stable-2.13 collection-root: .internal/ansible/ansible_collections/internal/test @@ -111,6 +115,8 @@ jobs: git-checkout-ref: ${{ matrix.git-checkout-ref }} origin-python-version: ${{ matrix.origin-python-version }} pre-test-cmd: ${{ matrix.pre-test-cmd }} + pull-request-change-detection: >- + ${{ matrix.pull-request-change-detection || 'false' }} target: ${{ matrix.target }} target-python-version: ${{ matrix.target-python-version }} testing-type: ${{ matrix.testing-type }} diff --git a/README.md b/README.md index 4393d49..b11a4b6 100644 --- a/README.md +++ b/README.md @@ -104,6 +104,16 @@ version supported by the given `ansible-core-version` **(DEFAULT: `auto`)** Extra command to invoke before ansible-test **(OPTIONAL)** +### `pull-request-change-detection` + +Whether to use change detection for pull requests. If set to `true`, will +use change detection to determine changed files against the target branch, +and will not upload code coverage results. If the invocation is not from a +pull request, this option is ignored. Note that this requires +`collection-src-directory` to be empty or something ending with +`ansible_collections/{namespace}/{name}`. **(DEFAULT: `false`)** + + ### `python-version` **(DEPRECATED)** Use `origin-python-version` instead. diff --git a/action.yml b/action.yml index 306810b..86ae6cc 100644 --- a/action.yml +++ b/action.yml @@ -45,6 +45,15 @@ inputs: default: auto pre-test-cmd: description: Extra command to invoke before ansible-test + pull-request-change-detection: + description: >- + Whether to use change detection for pull requests. If set to `true`, will + use change detection to determine changed files against the target + branch, and will not upload code coverage results. If the invocation is + not from a pull request, this option is ignored. Note that this requires + `collection-src-directory` to be empty or something ending with + `ansible_collections/{namespace}/{name}`. + default: 'false' python-version: description: >- **(DEPRECATED)** Use `origin-python-version` instead. This is only kept @@ -191,6 +200,44 @@ runs: set +x shell: bash + - name: Log the next step action + run: echo ▷ Figuring out change detection and coverage + shell: bash + - name: Determine change detection and coverage + id: compute-change-detection-coverage + run: | + # Compute whether to use change detection and coverage + import os + import pathlib + import sys + + FILE_APPEND_MODE = 'a' + OUTPUTS_FILE_PATH = pathlib.Path(os.environ['GITHUB_OUTPUT']) + + def set_output(name, value): + with OUTPUTS_FILE_PATH.open(FILE_APPEND_MODE) as outputs_file: + outputs_file.writelines(f'{name}={value}{os.linesep}') + + # Input from GHA + pull_request_change_detection = '${{ + inputs.pull-request-change-detection + }}' + pull_request_branch = '${{ github.event.pull_request.base.ref || '' }}' + + # Compute coverage and change detection arguments + coverage_arg = '--coverage' + change_detection_arg = '' + if pull_request_branch and pull_request_change_detection == 'true': + coverage_arg = '' + change_detection_arg = ( + f'--changed --base-branch {pull_request_branch}' + ) + + # Set computed coverage-arg and change-detection-arg + set_output('coverage-arg', coverage_arg) + set_output('change-detection-arg', change_detection_arg) + shell: python + - name: Log the next step action if: >- !inputs.collection-src-directory @@ -205,6 +252,39 @@ runs: path: .tmp-ansible-collection-checkout persist-credentials: false ref: ${{ inputs.git-checkout-ref }} + fetch-depth: >- + ${{ + steps.compute-change-detection-coverage.outputs.change-detection-arg + && '0' || '1' + }} + + - name: Log the next step action + if: >- + !inputs.collection-src-directory + && steps.compute-change-detection-coverage.outputs.change-detection-arg + run: >- + echo ▷ Create branches for change detection + shell: bash + - name: Create branches for change detection + if: >- + !inputs.collection-src-directory + && steps.compute-change-detection-coverage.outputs.change-detection-arg + run: | + # Create a branch for the current HEAD, which happens to be a merge commit + git checkout -b __action_branch_name + + # Name the target branch + git branch ${{ + github.event.pull_request.base.ref + }} --track origin/${{ + github.event.pull_request.base.ref + }} + + # Show branch information + git branch -vv + shell: bash + working-directory: >- + .tmp-ansible-collection-checkout - name: Log the next step action run: >- @@ -224,8 +304,20 @@ runs: with OUTPUTS_FILE_PATH.open(FILE_APPEND_MODE) as outputs_file: outputs_file.writelines(f'{name}={value}{os.linesep}') + directory = "${{ + format( + '{0}/{1}', + ( + inputs.collection-src-directory + && inputs.collection-src-directory + || '.tmp-ansible-collection-checkout' + ), + inputs.collection-root + ) + }}" + COLLECTION_META_FILE = 'galaxy.yml' - with open(COLLECTION_META_FILE) as galaxy_yml: + with open(os.path.join(directory, COLLECTION_META_FILE)) as galaxy_yml: collection_meta = yaml.load(galaxy_yml) coll_name = collection_meta['name'] @@ -235,29 +327,35 @@ runs: set_output('namespace', coll_ns) set_output('fqcn', f'{coll_ns}.{coll_name}') - set_output('collection-namespace-path', f'ansible_collections/{coll_ns}') - set_output('checkout-path', f'ansible_collections/{coll_ns}/{coll_name}') + + wanted_path = f'ansible_collections{os.sep}{coll_ns}{os.sep}{coll_name}' + if directory.endswith(wanted_path): + set_output('copy-to-checkout-path', 'false') + set_output( + 'collection-namespace-path', + os.path.normpath(os.path.join(directory, '..'))) + set_output('checkout-path', directory) + else: + set_output('copy-to-checkout-path', 'true') + set_output( + 'collection-namespace-path', + os.path.join('ansible_collections', coll_ns)) + set_output( + 'checkout-path', + os.path.join('ansible_collections', coll_ns, coll_name)) shell: python - working-directory: >- - ${{ - format( - '{0}/{1}', - ( - inputs.collection-src-directory - && inputs.collection-src-directory - || '.tmp-ansible-collection-checkout' - ), - inputs.collection-root - ) - }} - name: Log the next step action + if: >- + ${{ fromJSON(steps.collection-metadata.outputs.copy-to-checkout-path) }} run: >- echo ▷ ${{ inputs.collection-src-directory && 'Copy' || 'Move' }} "'${{ steps.collection-metadata.outputs.fqcn }}'" collection to ${{ steps.collection-metadata.outputs.checkout-path }}... shell: bash - name: Move the collection to the proper path + if: >- + ${{ fromJSON(steps.collection-metadata.outputs.copy-to-checkout-path) }} run: >- set -x ; @@ -358,7 +456,8 @@ runs: ; ~/.local/bin/ansible-test ${{ inputs.testing-type }} -v --color - --coverage + ${{ steps.compute-change-detection-coverage.outputs.coverage-arg }} + ${{ steps.compute-change-detection-coverage.outputs.change-detection-arg }} ${{ inputs.testing-type == 'sanity' && '--junit' @@ -408,10 +507,12 @@ runs: working-directory: ${{ steps.collection-metadata.outputs.checkout-path }} - name: Log the next step action + if: steps.compute-change-detection-coverage.outputs.coverage-arg != '' run: >- echo ▷ Generating a coverage report... shell: bash - name: Generate coverage report + if: steps.compute-change-detection-coverage.outputs.coverage-arg != '' run: >- set -x ; @@ -425,6 +526,7 @@ runs: working-directory: ${{ steps.collection-metadata.outputs.checkout-path }} - name: Log the next step action + if: steps.compute-change-detection-coverage.outputs.coverage-arg != '' run: >- echo ▷ Sending the coverage data over to https://codecov.io/gh/${{ github.repository }}... @@ -432,6 +534,7 @@ runs: - name: >- Send the coverage data over to https://codecov.io/gh/${{ github.repository }} + if: steps.compute-change-detection-coverage.outputs.coverage-arg != '' uses: codecov/codecov-action@v3 with: files: >-