Categorygithub.com/abatilo/github-action-locks
modulepackage
2.1.0+incompatible
Repository: https://github.com/abatilo/github-action-locks.git
Documentation: pkg.go.dev

# README

github-action-locks

Main license

As of April 19, 2021, GitHub now natively supports this feature

Guarantee atomic execution of your GitHub Action workflows. Why would you want to do that, you might ask?

The reason I built this GitHub Action is specifically because Pulumi doesn't support locking remote state unless you use their SaaS offering. I deploy various bits of infrastructure using the Official Pulumi GitHub Actions and I want to be able to fearlessly merge code and watch as the updates are pushed one at a time.

Getting started

github-action-locks works by creating a record in a DynamoDB table. We rely on Conditional Writes in order to guarantee that we can't write or create the same lock record twice.

Additionally, this action works by utilizing the post-entrypoint functionality of GitHub Actions. That is to say that as long as you start this action early in your workflow, the lock will get cleaned up at the end of the job execution once all of the "post" Actions are invoked.

DynamoDB table

Here is a minimal Terraform example of what a DynamoDB table should look like for usage with this Action:

resource "aws_dynamodb_table" "github-action-locks-table" {
  name           = "github-action-locks"
  billing_mode   = "PAY_PER_REQUEST"
  hash_key       = "LockID"
  attribute {
    name = "LockID"
    type = "S"
  }
}

IAM Permissions

Here is the minimum IAM Policy required for github-action-locks to work:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:GetItem",
                "dynamodb:PutItem",
                "dynamodb:DeleteItem"
            ],
            "Resource": "arn:aws:dynamodb:*:*:table/github-action-locks"
        }
    ]
}

Required Environment Variables

Since we're connecting to AWS, you must set the required AWS variables for creating a session as needed by the Go AWS SDK which are AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_REGION. These variables will be used to create the DynamoDB client which create the locks.

Additional Configuration

There are 4 input variables that you can use to control the behavior of this action:

InputDescriptionDefault
timeoutHow long to wait to acquire a lock, in minutes30
tableDynamoDB table to write the lock ingithub-action-locks
keyName of the column where we write locksLockID
nameName of the lockfoobar

See action.yml for more information.

Example workflow

This workflow uses the workflow name as the identifier for the lock. You can use any value you want here to synchronize Actions within the same repo, workflows with multiple parallel jobs, or even Actions across repositories.

name: Main
on: [push, pull_request]

env:
  AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
  AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
  AWS_REGION: ${{ secrets.AWS_REGION }}
jobs:
  test:
    strategy:
      fail-fast: false
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@master
    - name: Create lock
      uses: abatilo/github-action-locks@v1
      with:
        timeout: "30"
        table: "github-action-locks"
        key: "LockID"
        name: "${{ github.workflow }}" # Use the workflow name, in this case "Main" as the lock identifier
    - run: |
        echo "Do something that takes a long time here"
        sleep 5

# Constants

DefaultLockKeyName is the default name of the column where we write locks.
DefaultLockName is the default name for the lock to create.
DefaultLockTable is the default name of the DynamoDB table to write the lock in.
DefaultLockTimeout is the default time, in minutes, for how long to wait to acquire a lock before giving up.
LockKeyNameVar is the key for the setting to control the name of the column where we write locks.
LockNameVar is the key for the setting to control the name of the lock.
LockTableVar is the key for the setting to control the DynamoDB table to write the lock in.
LockTimeoutVar is the key for the setting to control how long to wait to acquire a lock, in minutes.