0

I have read and tested different things but didn't found a solution. Maybe I have to live with the boilerplate, but I am not yet done trying it.

I have the follow github actions workflow:

---
name: Code Quality Checks

on:
  push:
    branches: [main, development]
  pull_request:
    branches: [main, development]

jobs: 
  test:
    runs-on: ubuntu-latest
    needs: setup
    steps:
      - name: get repo
        uses: actions/checkout@v2
      - name: Set up Python 3.7
        uses: actions/setup-python@v1
        with:
          python-version: 3.7
      - name: Install poetry
        uses: snok/install-poetry@v1.0.0
        with:
          virtualenvs-create: true
          virtualenvs-in-project: true
      - name: Load cached venv
        id: cached-poetry-dependencies
        uses: actions/cache@v2
        with:
          path: .venv
          key: venv-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }}
      - name: Install dependencies
        run: poetry install
        if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true'
      - name: Unit & Coverage test with pytest
        run: poetry run pytest

  check:
    runs-on: ubuntu-latest
    needs: setup
    steps:
      - name: get repo
        uses: actions/checkout@v2
      - name: Set up Python 3.7
        uses: actions/setup-python@v1
        with:
          python-version: 3.7
      - name: Install poetry
        uses: snok/install-poetry@v1.0.0
        with:
          virtualenvs-create: true
          virtualenvs-in-project: true
      - name: Load cached venv
        id: cached-poetry-dependencies
        uses: actions/cache@v2
        with:
          path: .venv
          key: venv-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }}
      - name: Install dependencies
        run: poetry install
        if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true'
      - name: Check style with flake8
        run: poetry run flake8 boxsup_pytorch/ tests/

As you might see there is a lot of boilerplate in both jobs. I tested 'composition' which has issues with the cached variables. I also tinkert around with upload and download artifacts, but since the setup-python action uses python binary outside my cwd I was thinking uploading the complete runner is not a good idea.

Any working solutions for my scenario?

My previous Ideas was mostly based on In a github actions workflow, is there a way to have multiple jobs reuse the same setup?

MaKaNu
  • 762
  • 8
  • 25
  • And by the way I somehow corrupted the cached installation. – MaKaNu May 06 '22 at 14:04
  • 1
    You could use reusable workflows as Gui recommends, or you could stick the first five actions into a [composite action](https://docs.github.com/en/actions/creating-actions/creating-a-composite-action) that can be used like a single action. – Benjamin W. May 06 '22 at 15:34
  • Maybe this wasn't clear enough I tried already composition. Got an error: `Mapping values are not allowed in this context.` couldn't really find a solution an tried a different approach. I completely roled back to version which worked. This is my composition repo: https://github.com/MaKaNu/poetry-setup-composite-action/blob/main/action.yml – MaKaNu May 06 '22 at 15:39
  • 1
    Ah, I see, should have read more closely. I think you can get around this problem by adding an input to the composite action, like `cache-key`, then in the composite action use `key: ${{ inputs.cache-key }}`, and where you call your composite action, you'd use in the `with` object something like `cache-key: venv-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }}`, thus moving the disallowed call out of the composite context. – Benjamin W. May 06 '22 at 16:06
  • Benjamin W suggestion is great and worth trying. You could even add the poetry command arguments as an input to the action to to execute the command inside the action at the last step as well :) – GuiFalourd May 06 '22 at 16:15
  • So the only issue I see and there I do not see any workaround for is the `action/checkout` before the composition call, because the `hashFile` uses the poetry.lock file which is inside the repo and only available after checkout. correct? – MaKaNu May 06 '22 at 16:21
  • 1
    From the Blogpost: "Cannot use if: conditionals". Since my workflow includes an if condition compositions seems not an Option or am I wrong? – MaKaNu May 06 '22 at 16:27
  • Benjamin W. your trick worked and combined with @GuiFalourd idea of also putting the poetry command inside the inputs was great. I only cannot follow the restriction with if conditions. Moving the key outside of the composition (Maybe it could worked somehow else inside) is also better in the case I have a broken cache. – MaKaNu May 06 '22 at 17:09
  • 1
    I still think you could achieve what you want with a reusable workflow, which would allow you to use `if: conditionals`. But the most important is for it to work, so if you achieve a result that satisfies you using a composite actions, perfect! (that may be even better if you want to share it later) – GuiFalourd May 06 '22 at 17:29
  • yes I think so as well. In my first test runs the `if: conditionals` worked inside of a composite action. Maybe composites got an update since the blog post. And while writing this comment I looked into it and found: https://github.blog/changelog/2021-11-09-github-actions-conditional-execution-of-steps-in-actions/. Funny that this announcement is older than the other blog post. – MaKaNu May 06 '22 at 18:00
  • @Benjamin W. would you like to provide an answer? Since your idea finally worked for my problem and is also my favorite solution for my workflow (I started with composites because it seems the best way to share a workflow over many projects) I would like to credit you. – MaKaNu May 08 '22 at 19:03
  • Sure, I can write up something! – Benjamin W. May 08 '22 at 19:46

2 Answers2

1

What you are looking for is the concept of reusable workflow on Github Actions.

Reusing workflows avoids duplication. This makes workflows easier to maintain and allows you to create new workflows more quickly by building on the work of others, just as you do with actions. Workflow reuse also promotes best practice by helping you to use workflows that are well designed, have already been tested, and have been proved to be effective.

Just be aware of the limitations:

  • Reusable workflows can't call other reusable workflows.
  • Reusable workflows stored within a private repository can only be used by workflows within the same repository.
  • Any environment variables set in an env context defined at the workflow level in the caller workflow are not propagated to the called workflow.
  • The strategy property is not supported in any job that calls a reusable workflow.

Here is the documentation step by step to create a reusable workflow.

EDIT: And if you wonder what's the differences between composite actions and reusable workflows, I recommend reading this Github blog post

GuiFalourd
  • 15,523
  • 8
  • 44
  • 71
  • Isn't that the same as my attempt on 'composition' just inside a repo? Since my composition try also failed I didn't try reusable workflow. I was also a bit worried about: "Reusable workflows can't call other reusable workflows." Because isn't `actions/checkout@v2` and the others also some kind of reusable workflow? – MaKaNu May 06 '22 at 15:35
  • 1
    @MaKaNu There are subtle differences between reusable workflows and composite actions. `actions/checkout` isn't a workflow, it's an action, so you can definitely call it from a reusable workflow. This article talks about the differences: https://chris48s.github.io/blogmarks/github/2021/11/06/composite-actions-reusable-workflows.html – Benjamin W. May 06 '22 at 16:08
  • You can actually check the differences between composite actions and reusable workflows [in this blog post](https://github.blog/2022-02-10-using-reusable-workflows-github-actions/#:~:text=Composite%20actions,-Cannot%20call%20another&text=They%20allow%20you%20to%20specify,workflow%20like%20composite%20actions%20do.). – GuiFalourd May 06 '22 at 16:16
1

You could use a composite action that takes the cache key as an input; something like this (with updated action versions as of today):

name: Install Python and Poetry

inputs:
  python-version:
    description: Python version
    required: false
    default: 3.7
  cache-key:
    description: Key to use for cache action
    required: true

runs:
  using: composite
  steps:
    - name: Set up Python
      uses: actions/setup-python@v3.1.2
      with:
        python-version: ${{ inputs.python-version }}
    - name: Install poetry
      uses: snok/install-poetry@v1.3.1
      with:
        virtualenvs-in-project: true
    - name: Load cached venv
      id: cache
      uses: actions/cache@v3.0.2
      with:
        path: .venv
        key: ${{ inputs.cache-key }}
    - name: Install dependencies
      if: '! steps.cache.outputs.cache-hit'
      shell: bash
      run: poetry install

which replaces the steps 2-5 in your jobs. It also lets you specify the Python version, but defaults to 3.7 when that is omitted.

The workflow would then look something like this:

name: Code Quality Checks

on:
  push:
    branches:
      - main
      - development
  pull_request:
    branches:
      - main
      - development

jobs:
  test:
    runs-on: ubuntu-20.04
    needs: setup
    steps:
      - name: Get repo
        uses: actions/checkout@v3.0.2
      - name: Install Python and Poetry
        uses: ./.github/actions/poetry
        with:
          cache-key: env-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }}
      - name: Unit & coverage test with pytest
        run: poetry run pytest

  check:
    runs-on: ubuntu-20.04
    needs: setup
    steps:
      - name: Get repo
        uses: actions/checkout@v3.0.2
      - name: Install Python and Poetry
        uses: ./.github/actions/poetry
        with:
          cache-key: env-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }}
      - name: Check style with flake8
        run: poetry run flake8 boxsup_pytorch/ tests/

This assumes that the action.yml above lives in .github/actions/poetry, i.e., the .github directory would look like this:

.github
├── actions
│   └── poetry
│       └── action.yml
└── workflows
    └── checks.yml
Benjamin W.
  • 46,058
  • 19
  • 106
  • 116