bashvirtualenvgithub-actions

How to activate a virtualenv in a github action?


I am used to work with virtualenvs. However for some reason I am not able to activate an env in a github action job.

In order to debug I added this step:

      - name: Activate virtualenv
        run: |
          echo $PATH
          . .venv/bin/activate
          ls /home/runner/work/<APP>/<APP>/.venv/bin
          echo $PATH

On the action logs I can see

/opt/hostedtoolcache/Python/3.9.13/x64/bin:/opt/hostedtoolcache/Python/3.9.13/x64:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
[...]  # Cut here because a lot of lines are displayed. My executables are present including the one I'm trying to execute : pre-commit.
/home/runner/work/<APP>/<APP>/.venv/bin:/opt/hostedtoolcache/Python/3.9.13/x64/bin:/opt/hostedtoolcache/Python/3.9.13/x64:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

So it should work...

But the next steps which is

      - name: Linters
        run: pre-commit

Generates those error logs

Run pre-commit
  pre-commit
  shell: /usr/bin/bash -e {0}
  env:
    [...]  # private
/home/runner/work/_temp/8e893c8d-5032-4dbb-8a15-59be68cb0f5d.sh: line 1: pre-commit: command not found
Error: Process completed with exit code 127.

I have no issue if I transform the step above this way :

      - name: Linters
        run: .venv/bin/pre-commit

For some reason bash is not able to find my executable while the folder containing it is referenced in $PATH.


Solution

  • I'm sure you know that activation of a virtualenv is not magic — it just prepends …/.venv/bin/ to $PATH. Now the problematic thing in Github Action is that every run is executed by a different shell and hence every run has a default PATH as if the virtualenv was deactivated.

    I see 3 ways to overcome that. The 1st you already mentioned — just use .venv/bin/<command>.

    The 2nd is to activate the venv in every step:

    - name: Linters
      run: |
        . .venv/bin/activate
        pre-commit
    

    The 3rd is: activate it once and store $PATH in a file that Actions use to restore environment variables at every step. The file is described in the docs.

    So your entire workflow should looks like this:

    - name: Activate virtualenv
      run: |
        . .venv/bin/activate
        echo PATH=$PATH >> $GITHUB_ENV
    
    - name: Linters
      run: pre-commit