diff --git a/.github/actions/install-pkg/action.yml b/.github/actions/install-pkg/action.yml index af1ebfe7..5e8bd9e4 100644 --- a/.github/actions/install-pkg/action.yml +++ b/.github/actions/install-pkg/action.yml @@ -3,6 +3,7 @@ description: Install earthaccess Python package and testing dependencies inputs: python-version: + description: Version of Python to use required: true runs: @@ -16,7 +17,7 @@ runs: - name: Display full python version shell: bash id: full-python-version - run: echo "{version}=$(python -c "import sys; print('-'.join(str(v) for v in sys.version_info))")" >> $GITHUB_OUTPUT + run: echo "version=$(python -c "import sys; print('-'.join(str(v) for v in sys.version_info))")" >> $GITHUB_OUTPUT - name: Install package and test dependencies shell: bash diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index cb013525..fba60ccc 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -2,6 +2,7 @@ name: Integration Tests on: pull_request: + pull_request_target: push: branches: - main @@ -19,6 +20,25 @@ concurrency: jobs: integration-tests: + # + # This condition prevents DUPLICATE attempts to run integration tests for + # PRs coming from FORKS. + # + # When a PR originates from a fork, both a pull_request and a + # pull_request_target event are triggered. This means that without a + # condition, GitHub will attempt to run integration tests TWICE, once for + # each event. + # + # To prevent this, this condition ensures that integration tests are run + # in only ONE of the following cases: + # + # 1. The event is NOT a pull_request. This covers the case when the event + # is a pull_request_target (i.e., a PR from a fork), as well as all + # other cases listed in the "on" block at the top of this file. + # 2. The event IS a pull_request AND the base repo and head repo are the + # same (i.e., the PR is NOT from a fork). + # + if: github.event_name != 'pull_request' || github.event.pull_request.base.repo.full_name == github.event.pull_request.head.repo.full_name runs-on: ubuntu-latest strategy: matrix: @@ -26,13 +46,35 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@v4 + - name: Fetch user permission + id: permission + uses: actions-cool/check-user-permission@v2 + with: + require: write + username: ${{ github.triggering_actor }} + + - name: Check user permission + if: ${{ steps.permission.outputs.require-result == 'false' }} + # If the triggering actor does not have write permission (i.e., this is a + # PR from a fork), then we exit, otherwise most of the integration tests will + # fail because they require access to secrets. In this case, a maintainer + # will need to make sure the PR looks safe, and if so, manually re-run the + # failed pull_request_target jobs. + run: | + echo "User **${{ github.triggering_actor }}** does not have permission to run integration tests." >> $GITHUB_STEP_SUMMARY + echo "A maintainer must perform a security review and re-run this build, if the code is safe." >> $GITHUB_STEP_SUMMARY + echo "See [Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests](https://securitylab.github.com/resources/github-actions-preventing-pwn-requests)." >> $GITHUB_STEP_SUMMARY + exit 1 + + - name: Checkout source + uses: actions/checkout@v4 - - uses: ./.github/actions/install-pkg + - name: Install package with dependencies + uses: ./.github/actions/install-pkg with: python-version: ${{ matrix.python-version }} - - name: Test + - name: Run integration tests env: EARTHDATA_USERNAME: ${{ secrets.EDL_USERNAME }} EARTHDATA_PASSWORD: ${{ secrets.EDL_PASSWORD }} @@ -40,7 +82,7 @@ jobs: EARTHACCESS_TEST_PASSWORD: ${{ secrets.EDL_PASSWORD }} run: ./scripts/integration-test.sh - - name: Upload coverage + - name: Upload coverage report # Don't upload coverage when using the `act` tool to run the workflow locally if: ${{ !env.ACT }} uses: codecov/codecov-action@v4 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index af5fd1f6..1d6250d4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,7 +16,8 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@v4 + - name: Checkout sources + uses: actions/checkout@v4 - uses: ./.github/actions/install-pkg with: diff --git a/.gitignore b/.gitignore index 356afb4f..d0ee3ea9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ .ipynb_checkpoints .python-version .mypy_cache +.nox/ __pycache__ .pytest_cache htmlcov diff --git a/docs/contributing/development.md b/docs/contributing/development.md index 497b5391..1c4baa1a 100644 --- a/docs/contributing/development.md +++ b/docs/contributing/development.md @@ -33,19 +33,20 @@ environment for each run. ## Manual development environment setup -While `nox` is the fastest way to get started, you may soon find that you need a full -development environment, for example to test in a REPL. This development environment -also includes `nox`. +While `nox` is the fastest way to get started, you will likely need a full +development environment for making code contributions, for example to test in a +REPL, or to resolve references in your favorite IDE. This development +environment also includes `nox`. -Create and activate a virtual environment with `venv`, which comes by default with -Python, in the `.venv` directory: +Create and activate a virtual environment with `venv`, which comes by default +with Python, in the `.venv` directory: ```bash python -m venv .venv source .venv/bin/activate ``` -Install _earthaccess_ in editable mode with optional development dependencies: +Install `earthaccess` in editable mode with optional development dependencies: ```bash pip install --editable ".[dev,test,docs]" @@ -53,8 +54,8 @@ pip install --editable ".[dev,test,docs]" ??? note "For conda users" - For your convenience, there is a `environment.yml` file at the root of this - repository. You can create a dev environment quickly with: + For your convenience, there is an `environment.yml` file at the root of this + repository, allowing you to create a conda environment quickly, as follows: ```bash conda env create --file environment.yml @@ -62,6 +63,6 @@ pip install --editable ".[dev,test,docs]" ## Managing Dependencies -If you need to add a new dependency, edit `pyproject.toml` and insert the dependency in -the correct location (either in the `dependencies` array or -`[project.optional-dependencies]`. +If you need to add a new dependency, edit `pyproject.toml` and insert the +dependency in the correct location (either in the `dependencies` array or under +`[project.optional-dependencies]`). diff --git a/environment.yml b/environment.yml index a7a5dd01..e0eb49b3 100644 --- a/environment.yml +++ b/environment.yml @@ -9,3 +9,7 @@ dependencies: - pip - pip: - --editable .[dev,test,docs] +variables: + # Allow pip installs when conda environment is active + PIP_REQUIRE_VENV: 0 + PIP_REQUIRE_VIRTUALENV: 0 diff --git a/noxfile.py b/noxfile.py index cadc109d..257b0533 100644 --- a/noxfile.py +++ b/noxfile.py @@ -8,7 +8,7 @@ DIR = Path(__file__).parent.resolve() nox.needs_version = ">=2024.3.2" -nox.options.sessions = ["typecheck", "test_unit"] +nox.options.sessions = ["typecheck", "tests"] nox.options.default_venv_backend = "uv|virtualenv" @@ -20,7 +20,7 @@ def typecheck(session: nox.Session) -> None: @nox.session -def test_unit(session: nox.Session) -> None: +def tests(session: nox.Session) -> None: """Run the unit tests.""" session.install("--editable", ".[test]") session.run("pytest", "tests/unit", *session.posargs)