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

推荐订阅源

月光博客
月光博客
人人都是产品经理
人人都是产品经理
博客园 - 聂微东
WordPress大学
WordPress大学
S
SegmentFault 最新的问题
博客园 - Franky
V
V2EX
Y
Y Combinator Blog
Google DeepMind News
Google DeepMind News
J
Java Code Geeks
T
The Blog of Author Tim Ferriss
罗磊的独立博客
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Jina AI
Jina AI
博客园 - 叶小钗
F
Fortinet All Blogs
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
A
About on SuperTechFans
M
MIT News - Artificial intelligence
云风的 BLOG
云风的 BLOG
Last Week in AI
Last Week in AI
D
Docker
博客园 - 【当耐特】
阮一峰的网络日志
阮一峰的网络日志

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.