惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Martin Fowler
Martin Fowler
Jina AI
Jina AI
J
Java Code Geeks
Microsoft Security Blog
Microsoft Security Blog
Recent Announcements
Recent Announcements
I
InfoQ
L
LangChain Blog
The Cloudflare Blog
IT之家
IT之家
博客园 - 叶小钗
Apple Machine Learning Research
Apple Machine Learning Research
B
Blog
A
About on SuperTechFans
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Last Week in AI
Last Week in AI
Blog — PlanetScale
Blog — PlanetScale
罗磊的独立博客
云风的 BLOG
云风的 BLOG
Microsoft Azure Blog
Microsoft Azure Blog
Engineering at Meta
Engineering at Meta
F
Fortinet All Blogs
博客园 - 聂微东
美团技术团队
博客园_首页

ashishb.net

A day in Luxembourg - the richest country in the world I was asked to install malware during a fake interview Book summary: Breakneck - China's quest to engineer the future by Dan Wang Book summary: How to Teach Your Baby to Read Book Summary: The Discontented Little Baby Book by Pamela Douglas Introducing Amazing Sandbox - run third-party tools and AI agents securely on your machine Why software outsourcing gets a bad reputation? Book summary: The Natural Baby Sleep Solution by Polly Moore A day in Antwerp, Belgium Journey of online influencers Two days in Brussels, Belgium Shortcuts - when we love them and when we don't A visit to Rakhigarhi Three days in overhyped Paris Empty Japan, crowded Tokyo The real lock-in in GitHub is not the code, but the stars 11-day Norwegian Breakaway East Caribbean cruise Sanskrit and Sri Lankan Air Force Use REST with Open API The Achilles heel of American capitalism Costa Rica in 4 days At a juice stall in Sri Lanka A short stay at Warsaw, Poland Best practices for using Python & uv inside Docker Two days in Vilnius, Lithuania How IntelliJ IDEs waste disk space Pregnancy Why there aren't many digital nomads from India Two days in Riga, Latvia To keep your machine secure, run third-party tools inside Docker
Common pitfalls of GitHub Actions
Ashish Bhatia · 2023-03-19 · via ashishb.net
Pointer.ioPythonHubPython WeeklyGitHub Repo stars

If you create GitHub Actions via GitHub’s UI by going to the URL of the form https://github.com/<username>/<reponame>/actions/new, it provides templates for setting up the build. However, the template is broken.

There are four problems with the default template

  1. No dependency caching - so package dependencies will be resolved and reinstalled every time
  2. No cancelation of stale executions - If you pushed a commit and before the tests finish, you decide to push another commit then the stale commits are not canceled. Rather they continue executing!
  3. No path filtering - So a change to README will trigger the execution of, for example, linters and tests!
  4. No timeouts - Rogue tests can run forever leading to resource exhaustion
  5. Bad security permissions - the default GITHUB_TOKEN gives too many permissions. With the recent attacks on Ultranalytics and tj-actions-changed-files, these attacks are no longer a theortical possibility. Few understand the security model though.

All these are fixable.

  1. Dependency caching is language-specific - see the directions in the actions/cache repository.

  2. Canceling stale executions is easy. Just add

    1
    2
    3
    
    concurrency:
      group: ${{ github.workflow }}-${{ github.ref }}
      cancel-in-progress: true
  3. Path filtering requires knowing the right dependencies but it is not hard. For example, for a job linting Python files, it will be **.py

  4. A reasonable job-level timeout makes sense. Look at the past execution and put a limit of 2X based on that. For example, if a job takes 5 minutes on average, timeout-minutes: 10 limits the job to 10 minutes.

Let’s consider a simple template that GitHub generates for building Python code and improving it.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# Template generated by GitHub
# This workflow will install Python dependencies, run tests and lint with a single version of Python
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python

name: Python application

on:
  push:
    branches: [ "master" ]
  pull_request:
    branches: [ "master" ]

permissions:
  contents: read

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3
    - name: Set up Python 3.10
      uses: actions/setup-python@v3
      with:
        python-version: "3.10"
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install flake8 pytest
        if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
    - name: Lint with flake8
      run: |
        # stop the build if there are Python syntax errors or undefined names
        flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
        # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
        flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
    - name: Test with pytest
      run: |
        pytest

My improvements are marked with # Improvement: comments

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
name: Python application

on:
  push:
    branches: [ "master", "main" ]
    # Improvement #1: Filter on files that should trigger this workflow
    paths:
      - 'requirements.txt'
      - '**.py'
      # Assume that this is the path of this file in the repo
      - '.github/workflows/python-app.yml'
  pull_request:
    branches: [ "master", "main" ]
    # Improvement #1: Filter on files that should trigger this workflow
    paths:
      - 'requirements.txt'
      - '**.py'
      # Assume that this is the path of this file in the repo
      - '.github/workflows/python-app.yml'

permissions:
  contents: read

# Improvement #2: Cancel existing executions when new commits are pushed onto the branch
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  # Improvement #3: Rename the job name, this makes it easier to run locally
  # with a tool like https://github.com/nektos/act
  buildPythonApp:

    runs-on: ubuntu-latest
    # Improvement #4: Add a timeout of 15 mins
    timeout-minutes: 15

    steps:
    - uses: actions/checkout@v3
    - name: Set up Python 3.10
      uses: actions/setup-python@v3
      with:
        python-version: "3.10"

    # Improvement #5: Cache Python dependencies using the hash of "requirements.txt" as the key
    # This step must be executed before "pip install"
    - uses: actions/cache@v3
      with:
        path: ~/.cache/pip
        key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
        restore-keys: |
          ${{ runner.os }}-pip-

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install flake8 pytest
        if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
    - name: Lint with flake8
      run: |
        # stop the build if there are Python syntax errors or undefined names
        flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
        # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
        flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
    - name: Test with pytest
      run: |
        pytest

Update

  1. This post was featured in Pointer, PythonHub, Python Weekly, and Research Computing. After getting a lot of positive feedback. I have open-sourced a project gabo to automate this. Feel free to try it out.
  2. If you like this post, you might also like how I use GitHub Actions to validate my dotfiles and how to do CI of mobile app.