jesseduffield/lazygit

6 workflows · maturity 50% · 5 patterns · GitHub ↗

Security 8.33/100

Practices

✓ Matrix✓ Permissions○ Security scan○ AI review✓ Cache○ Concurrency○ Reusable workflows

Detected patterns

Security dimensions

permissions
8.3
security scan
0
supply chain
0
secret handling
0
harden runner
0

Workflows (6)

check-required-label .github/workflows/check-required-label.yml
Triggers
pull_request
Runs on
ubuntu-latest
Jobs
check-required-label
Actions
mheap/github-action-required-labels
View raw YAML
name: Check Required Labels

on:
  pull_request:
    types: [opened, labeled, unlabeled, synchronize]

jobs:
  check-required-label:
    runs-on: ubuntu-latest
    steps:
      - uses: mheap/github-action-required-labels@v5
        with:
          mode: exactly
          count: 1
          labels: "ignore-for-release, feature, enhancement, bug, maintenance, docs, i18n, performance"
ci matrix .github/workflows/ci.yml
Triggers
push, pull_request
Runs on
${{matrix.os}}, ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest
Jobs
unit-tests, integration-tests, build, check-codebase, lint, upload-coverage, check-for-fixups
Matrix
git-version, include, include.cache_path, include.os, os→ 2.32.0, 2.38.2, 2.44.0, latest, ubuntu-latest, windows-latest, ~/.cache/go-build, ~\AppData\Local\go-build
Actions
golangci/golangci-lint-action
Commands
  • mkdir -p /tmp/code_coverage go test ./... -short -cover -args "-test.gocoverdir=/tmp/code_coverage"
  • sudo apt-get update && sudo apt-get install --no-install-recommends -y build-essential ca-certificates curl gettext libexpat1-dev libssl-dev libz-dev openssl && curl -sL "https://mirrors.edge.kernel.org/pub/software/scm/git/git-${{matrix.git-version}}.tar.xz" -o - | tar xJ -C "$HOME" && cd "$HOME/git-${{matrix.git-version}}" && ./configure && make -j
  • sudo make -C "$HOME/git-${{matrix.git-version}}" -j install
  • git --version
  • mkdir -p /tmp/code_coverage ./scripts/run_integration_tests.sh
  • GOOS=linux go build
  • GOOS=windows go build
  • GOOS=darwin go build
View raw YAML
name: Continuous Integration

env:
  GO_VERSION: 1.25

on:
  push:
    branches:
      - master
  pull_request:

jobs:
  unit-tests:
    strategy:
      fail-fast: false
      matrix:
        os:
          - ubuntu-latest
          - windows-latest
        include:
          - os: ubuntu-latest
            cache_path: ~/.cache/go-build
          - os: windows-latest
            cache_path: ~\AppData\Local\go-build
    name: ci - ${{matrix.os}}
    runs-on: ${{matrix.os}}
    env:
      GOFLAGS: -mod=vendor
    steps:
      - name: Checkout code
        uses: actions/checkout@v6
      - name: Setup Go
        uses: actions/setup-go@v6
        with:
          go-version: 1.25.x
      - name: Test code
        # we're passing -short so that we skip the integration tests, which will be run in parallel below
        run: |
          mkdir -p /tmp/code_coverage
          go test ./... -short -cover -args "-test.gocoverdir=/tmp/code_coverage"
      - name: Upload code coverage artifacts
        uses: actions/upload-artifact@v6
        with:
          name: coverage-unit-${{ matrix.os }}-${{ github.run_id }}
          path: /tmp/code_coverage

  integration-tests:
    strategy:
      fail-fast: false
      matrix:
        git-version:
          - 2.32.0 # oldest supported version
          - 2.38.2 # first version that supports the rebase.updateRefs config
          - 2.44.0
          - latest # We rely on github to have the latest version installed on their VMs
    runs-on: ubuntu-latest
    name: "Integration Tests - git ${{matrix.git-version}}"
    env:
      GOFLAGS: -mod=vendor
    steps:
      - name: Checkout code
        uses: actions/checkout@v6
      - name: Restore Git cache
        if: matrix.git-version != 'latest'
        id: cache-git-restore
        uses: actions/cache/restore@v4
        with:
          path: ~/git-${{matrix.git-version}}
          key: ${{runner.os}}-git-${{matrix.git-version}}
      - name: Build Git ${{matrix.git-version}}
        if: steps.cache-git-restore.outputs.cache-hit != 'true' && matrix.git-version != 'latest'
        run: >
          sudo apt-get update && sudo apt-get install --no-install-recommends -y build-essential ca-certificates curl gettext libexpat1-dev libssl-dev libz-dev openssl
          && curl -sL "https://mirrors.edge.kernel.org/pub/software/scm/git/git-${{matrix.git-version}}.tar.xz" -o - | tar xJ -C "$HOME"
          && cd "$HOME/git-${{matrix.git-version}}"
          && ./configure
          && make -j
      - name: Install Git ${{matrix.git-version}}
        if: matrix.git-version != 'latest'
        run: sudo make -C "$HOME/git-${{matrix.git-version}}" -j install
      - name: Save Git cache
        if: steps.cache-git-restore.outputs.cache-hit != 'true' && matrix.git-version != 'latest'
        uses: actions/cache/save@v4
        with:
          path: ~/git-${{matrix.git-version}}
          key: ${{runner.os}}-git-${{matrix.git-version}}
      - name: Setup Go
        uses: actions/setup-go@v6
        with:
          go-version: 1.25.x
      - name: Print git version
        run: git --version
      - name: Test code
        env:
          # See https://go.dev/blog/integration-test-coverage
          LAZYGIT_GOCOVERDIR: /tmp/code_coverage
        run: |
          mkdir -p /tmp/code_coverage
          ./scripts/run_integration_tests.sh
      - name: Upload code coverage artifacts
        uses: actions/upload-artifact@v6
        with:
          name: coverage-integration-${{ matrix.git-version }}-${{ github.run_id }}
          path: /tmp/code_coverage
  build:
    runs-on: ubuntu-latest
    env:
      GOFLAGS: -mod=vendor
      GOARCH: amd64
    steps:
      - name: Checkout code
        uses: actions/checkout@v6
      - name: Setup Go
        uses: actions/setup-go@v6
        with:
          go-version: 1.25.x
      - name: Build linux binary
        run: |
          GOOS=linux go build
      - name: Build windows binary
        run: |
          GOOS=windows go build
      - name: Build darwin binary
        run: |
          GOOS=darwin go build
      - name: Build integration test binary
        run: |
          GOOS=linux go build cmd/integration_test/main.go
      - name: Build integration test injector
        run: |
          GOOS=linux go build pkg/integration/clients/injector/main.go
  check-codebase:
    runs-on: ubuntu-latest
    env:
      GOFLAGS: -mod=vendor
      GOARCH: amd64
    steps:
      - name: Checkout code
        uses: actions/checkout@v6
      - name: Setup Go
        uses: actions/setup-go@v6
        with:
          go-version: 1.25.x
      - name: Check Vendor Directory
        # ensure our vendor directory matches up with our go modules
        run: |
          go mod vendor && git diff --exit-code || (echo "Unexpected change to vendor directory. Run 'go mod vendor' locally and commit the changes" && exit 1)
      - name: Check go.mod file
        # ensure our go.mod file is clean
        run: |
          go mod tidy && git diff --exit-code || (echo "go.mod file is not clean. Run 'go mod tidy' locally and commit the changes" && exit 1)
      - name: Check All Auto-Generated Files
        # ensure all our auto-generated files are up to date
        run: |
          go generate ./... && git diff --quiet || (git status -s; echo "Auto-generated files not up to date. Run 'go generate ./...' locally and commit the changes" && exit 1)
        shell: bash # needed so that we get "-o pipefail"
      - name: Check Filenames
        run: scripts/check_filenames.sh
  lint:
    runs-on: ubuntu-latest
    env:
      GOFLAGS: -mod=vendor
    steps:
      - name: Checkout code
        uses: actions/checkout@v6
      - name: Setup Go
        uses: actions/setup-go@v6
        with:
          go-version: 1.25.x
      - name: Lint
        uses: golangci/golangci-lint-action@v9
        with:
          # If you change this, make sure to also update scripts/golangci-lint-shim.sh
          version: v2.4.0
      - name: errors
        run: golangci-lint run
        if: ${{ failure() }}
  upload-coverage:
    # List all jobs that produce coverage files
    needs: [unit-tests, integration-tests]
    if: github.event.pull_request.head.repo.full_name == github.repository
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Setup Go
        uses: actions/setup-go@v6
        with:
          go-version: 1.25.x

      - name: Download all coverage artifacts
        uses: actions/download-artifact@v7
        with:
          path: /tmp/code_coverage

      - name: Combine coverage files
        run: |
          # Find all directories in /tmp/code_coverage and create a comma-separated list
          COVERAGE_DIRS=$(find /tmp/code_coverage -mindepth 1 -maxdepth 1 -type d -printf '/tmp/code_coverage/%f,' | sed 's/,$//')
          echo "Coverage directories: $COVERAGE_DIRS"
          # Run the combine command with the generated list
          go tool covdata textfmt -i=$COVERAGE_DIRS -o coverage.out
          echo "Combined coverage:"
          go tool cover -func coverage.out | tail -1 | awk '{print $3}'

      - name: Upload to Codacy
        run: |
          CODACY_PROJECT_TOKEN=${{ secrets.CODACY_PROJECT_TOKEN }} \
            bash <(curl -Ls https://coverage.codacy.com/get.sh) report \
            --force-coverage-parser go -r coverage.out

  check-for-fixups:
    runs-on: ubuntu-latest
    if: github.ref != 'refs/heads/master'
    steps:
      # See https://github.com/actions/checkout/issues/552#issuecomment-1167086216
      - name: "PR commits"
        run: echo "PR_FETCH_DEPTH=$(( ${{ github.event.pull_request.commits }} ))" >> "${GITHUB_ENV}"

      - name: "Checkout PR branch and all PR commits"
        uses: actions/checkout@v6
        with:
          repository: ${{ github.event.pull_request.head.repo.full_name }}
          ref: ${{ github.event.pull_request.head.ref }}
          fetch-depth: ${{ env.PR_FETCH_DEPTH }}

      - name: Check for fixups
        run: |
          ./scripts/check_for_fixups.sh ${{ github.event.pull_request.base.ref }}
close-issues perms .github/workflows/close-issues.yml
Triggers
issue_comment
Runs on
ubuntu-latest
Jobs
close_issue
View raw YAML
name: Close Issues

on:
  issue_comment:
    types: [created]

permissions:
  issues: write

jobs:
  close_issue:
    runs-on: ubuntu-latest
    if: ${{ github.event.issue.pull_request == null && startsWith(github.event.comment.body, '/close') }}
    steps:
      - uses: actions/github-script@v8
        with:
          script: |
            const trustedUsers = ['ChrisMcD1', 'jesseduffield', 'stefanhaller']
            const commenter = context.payload.comment.user.login

            console.log(`Commenter: ${commenter}`)

            if (!trustedUsers.includes(commenter)) {
              console.log(`User ${commenter} is not trusted. Ignoring.`)
              return
            }

            const issueNumber = context.payload.issue.number
            const owner = context.repo.owner
            const repo = context.repo.repo

            await github.rest.issues.update({
              owner,
              repo,
              issue_number: issueNumber,
              state: 'closed'
            })

            console.log(`Closed issue #${issueNumber} by request from ${commenter}.`)
codespell perms .github/workflows/codespell.yml
Triggers
push, pull_request
Runs on
ubuntu-latest
Jobs
codespell
Actions
codespell-project/codespell-problem-matcher, codespell-project/actions-codespell
View raw YAML
# Codespell configuration is within .codespellrc
---
name: Codespell

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

permissions:
  contents: read

jobs:
  codespell:
    name: Check for spelling errors
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Annotate locations with typos
        uses: codespell-project/codespell-problem-matcher@v1
      - name: Codespell
        uses: codespell-project/actions-codespell@v2
release .github/workflows/release.yml
Triggers
workflow_dispatch
Runs on
ubuntu-latest
Jobs
check-and-release
Actions
goreleaser/goreleaser-action
Commands
  • echo "Should only run in the stefanhaller/lazygit repository" exit 1
  • if (( $(date +%e) > 7 )); then echo "This is not the first Saturday of the month" exit 1 fi
  • latest_tag=$(git describe --tags $(git rev-list --tags --max-count=1) || echo "v0.0.0") if ! [[ $latest_tag =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then echo "Error: Tag format is invalid. Expected format: vX.X.X" exit 1 fi echo "Latest tag: $latest_tag" echo "latest_tag=$latest_tag" >> $GITHUB_ENV
  • if [ -z "$(git diff --name-only ${{ env.latest_tag }})" ]; then echo "No changes detected since last release" exit 1 fi
  • if diff -r -q docs docs-master > /dev/null && diff -r -q schema schema-master > /dev/null; then echo "Docs and schema are up to date." else echo "Docs or schema are out of date. Please run 'scripts/update_docs_for_release.sh' and make a PR." exit 1 fi
  • gh auth setup-git gh auth status echo "Checking for blocking issues and PRs..." # Check for blocking issues blocking_issues=$(gh issue list -l blocks-release --json number,title --jq '.[] | "- \(.title) (#\(.number))"') # Check for blocking PRs blocking_prs=$(gh pr list -l blocks-release --json number,title --jq '.[] | "- \(.title) (#\(.number)) (PR)"') # Combine the results blocking_items="$blocking_issues"$'\n'"$blocking_prs" # Remove empty lines blocking_items=$(echo "$blocking_items" | grep . || true) if [ -n "$blocking_items" ]; then echo "Blocking issues/PRs detected:" echo "$blocking_items" exit 1 fi
  • echo "Latest tag: ${{ env.latest_tag }}" IFS='.' read -r major minor patch <<< "${{ env.latest_tag }}" if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then if [[ "${{ inputs.version_bump }}" == "patch" ]]; then patch=$((patch + 1)) else minor=$((minor + 1)) patch=0 fi else # Default behavior for scheduled runs minor=$((minor + 1)) patch=0 fi new_tag="$major.$minor.$patch" if ! [[ $new_tag =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then echo "Error: New tag's format is invalid. Expected format: vX.X.X" exit 1 fi echo "New tag: $new_tag" echo "new_tag=$new_tag" >> $GITHUB_ENV
  • git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" git tag ${{ env.new_tag }} -a -m "Release ${{ env.new_tag }}" git push origin ${{ env.new_tag }}
View raw YAML
name: Release

on:
  # schedule:
  #   # Runs at 8:00 AM UTC on every Saturday
  #   # We'll check below if it's the first Saturday of the month, and fail if not
  #   - cron: '0 8 * * 6'

  # Allow manual triggering of the workflow
  workflow_dispatch:
    inputs:
      version_bump:
        description: 'Version bump type'
        type: choice
        required: true
        default: 'patch'
        options:
          - minor
          - patch
      ignore_blocks:
        description: 'Ignore blocking PRs/issues'
        type: boolean
        required: true
        default: false

defaults:
  run:
    shell: bash

jobs:
  check-and-release:
    runs-on: ubuntu-latest
    steps:
      - name: Check for correct repository
        if: ${{ github.event_name != 'workflow_dispatch' && github.repository != 'stefanhaller/lazygit' }}
        run: |
          echo "Should only run in the stefanhaller/lazygit repository"
          exit 1

      - name: Check for first Saturday of the month
        if: ${{ github.event_name != 'workflow_dispatch' }}
        run: |
          if (( $(date +%e) > 7 )); then
            echo "This is not the first Saturday of the month"
            exit 1
          fi

      - name: Checkout Code
        uses: actions/checkout@v6
        with:
          repository: jesseduffield/lazygit
          token: ${{ secrets.LAZYGIT_RELEASE_PAT }}
          fetch-depth: 0

      - name: Get Latest Tag
        run: |
          latest_tag=$(git describe --tags $(git rev-list --tags --max-count=1) || echo "v0.0.0")

          if ! [[ $latest_tag =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
            echo "Error: Tag format is invalid. Expected format: vX.X.X"
            exit 1
          fi

          echo "Latest tag: $latest_tag"
          echo "latest_tag=$latest_tag" >> $GITHUB_ENV

      - name: Check for changes since last release
        run: |
          if [ -z "$(git diff --name-only ${{ env.latest_tag }})" ]; then
            echo "No changes detected since last release"
            exit 1
          fi

      - name: Check that docs and schema are up to date
        run: |
          if diff -r -q docs docs-master > /dev/null && diff -r -q schema schema-master > /dev/null; then
            echo "Docs and schema are up to date."
          else
            echo "Docs or schema are out of date. Please run 'scripts/update_docs_for_release.sh' and make a PR."
            exit 1
          fi

      - name: Check for Blocking Issues/PRs
        if: ${{ !inputs.ignore_blocks }}
        id: check_blocks
        run: |
          gh auth setup-git
          gh auth status

          echo "Checking for blocking issues and PRs..."

          # Check for blocking issues
          blocking_issues=$(gh issue list -l blocks-release --json number,title --jq '.[] | "- \(.title) (#\(.number))"')

          # Check for blocking PRs
          blocking_prs=$(gh pr list -l blocks-release --json number,title --jq '.[] | "- \(.title) (#\(.number)) (PR)"')

          # Combine the results
          blocking_items="$blocking_issues"$'\n'"$blocking_prs"

          # Remove empty lines
          blocking_items=$(echo "$blocking_items" | grep . || true)

          if [ -n "$blocking_items" ]; then
            echo "Blocking issues/PRs detected:"
            echo "$blocking_items"
            exit 1
          fi
        env:
          GITHUB_TOKEN: ${{ secrets.LAZYGIT_RELEASE_PAT }}

      - name: Calculate next version
        run: |
          echo "Latest tag: ${{ env.latest_tag }}"
          IFS='.' read -r major minor patch <<< "${{ env.latest_tag }}"

          if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
            if [[ "${{ inputs.version_bump }}" == "patch" ]]; then
              patch=$((patch + 1))
            else
              minor=$((minor + 1))
              patch=0
            fi
          else
            # Default behavior for scheduled runs
            minor=$((minor + 1))
            patch=0
          fi

          new_tag="$major.$minor.$patch"

          if ! [[ $new_tag =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
            echo "Error: New tag's format is invalid. Expected format: vX.X.X"
            exit 1
          fi

          echo "New tag: $new_tag"
          echo "new_tag=$new_tag" >> $GITHUB_ENV

      - name: Create and Push Tag
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git tag ${{ env.new_tag }} -a -m "Release ${{ env.new_tag }}"
          git push origin ${{ env.new_tag }}
        env:
          GITHUB_TOKEN: ${{ secrets.LAZYGIT_RELEASE_PAT }}

      - name: Setup Go
        uses: actions/setup-go@v6
        with:
          go-version: 1.25.x

      - name: Run goreleaser
        uses: goreleaser/goreleaser-action@v6
        with:
          distribution: goreleaser
          version: v2
          args: release --clean
        env:
          GITHUB_TOKEN: ${{secrets.LAZYGIT_RELEASE_PAT}}
sponsors .github/workflows/sponsors.yml
Triggers
push
Runs on
ubuntu-latest
Jobs
deploy
Actions
JamesIves/github-sponsors-readme-action, peter-evans/create-pull-request
View raw YAML
# see https://github.com/JamesIves/github-sponsors-readme-action
name: Generate Sponsors README
on:
  push:
    branches:
      - master
jobs:
  deploy:
    runs-on: ubuntu-latest
    if: ${{ github.repository == 'jesseduffield/lazygit' }}
    steps:
      - name: Checkout 🛎️
        uses: actions/checkout@v6

      - name: Generate Sponsors 💖
        uses: JamesIves/github-sponsors-readme-action@v1.2.2
        with:
          token: ${{ secrets.SPONSORS_TOKEN }}
          file: "README.md"

      - name: Create Pull Request 🚀
        uses: peter-evans/create-pull-request@v8
        with:
          commit-message: "README.md: Update Sponsors"
          title: "README.md: Update Sponsors"
          author: "github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>"
          labels: "ignore-for-release"
          delete-branch: true
          token: ${{ secrets.SPONSORS_PR_TOKEN }}