diff --git a/.github/workflows/flake-bump.yaml b/.github/workflows/flake-bump.yaml new file mode 100644 index 0000000000..4e706be49e --- /dev/null +++ b/.github/workflows/flake-bump.yaml @@ -0,0 +1,56 @@ +name: Flake bump +on: + pull_request: + paths: + - 'flake.lock' + branches: + - gardenlinux + +jobs: + gitlint: + name: Check flake bump requirements + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v6 + with: + ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: 0 + - name: Set up Python 3.11 + uses: actions/setup-python@v6 + with: + python-version: "3.11" + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install --upgrade gitlint + - name: Lint git commit messages + run: | + gitlint --commits origin/$GITHUB_BASE_REF.. -C .gitlint_auto_approve + + gitmerge: + name: Merge flake bump + needs: gitlint # hard dependency on this check job + runs-on: ubuntu-latest + steps: + - name: Generate token + id: generate_token + uses: actions/create-github-app-token@v2 + with: + app-id: ${{ secrets.GH_AUTO_APPROVE_APP_ID }} + private-key: ${{ secrets.GH_AUTO_APPROVE_APP_PRIVATE_KEY }} + owner: daedalus-ca + repositories: test-auto-approve + - name: Merge Pull request + shell: bash + env: + GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }} + run: | + # GitHub CLI api + # https://cli.github.com/manual/gh_api + gh api \ + --method PUT \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2026-03-10" \ + /repos/${GITHUB_REPOSITORY}/pulls/${{ github.event.number }}/merge \ + -f 'merge_method=rebase' diff --git a/.gitlint_auto_approve b/.gitlint_auto_approve new file mode 100644 index 0000000000..d79e9b21f5 --- /dev/null +++ b/.gitlint_auto_approve @@ -0,0 +1,15 @@ +[general] +extra-path=ci/gitlint/rules_auto_approve +regex-style-search=true +ignore=body-is-missing,body-max-line-length + +# default 72 +[title-max-length] +line-length=72 + +# Empty bodies are fine +[body-min-length] +min-length=0 + +[UC-flake] +filepath=flake.lock diff --git a/ci/README.auto.approve.md b/ci/README.auto.approve.md new file mode 100644 index 0000000000..a38d3e6e7e --- /dev/null +++ b/ci/README.auto.approve.md @@ -0,0 +1,43 @@ +# Flake bump auto approve + +## Description + +We add a github workflow `Flake bump`. +First job of this workflow checks if a merge request contains only one commit which updates the `flake.lock` file. +If this condition is met the second job approve this merge request and automatically merge it. +The approval is done with a dedicated GitHubApp. + +## Install + +* Follow this guide: https://docs.github.com/en/apps/creating-github-apps/registering-a-github-app/registering-a-github-app +* Create a GitHub app `auto-approve-app` in your GH organization + * github.com/github-organization/ -> Settings -> Developer Settings -> GitHub Apps -> New GitHub App + * Add a name and Homepage URL + * Add Repository Permissions + * Actions: RO + * Contents: RW + * Metadata: RO + * Pull Requests: RW + * Workflows: RW + +* Install this app into your organization + * github.com/github-organization/ -> Settings -> Developer Settings -> GitHub Apps -> Select `auto-approve-app` -> Install App + * Only select repositories: + * repository-name + +* Find app_id + * github.com/github-organization/ -> Settings -> Developer Settings -> GitHub Apps -> Select `auto-approve-app` + * you find the app_id in the `General` section + +* Create app client secret + * github.com/github-organization/ -> Settings -> Developer Settings -> GitHub Apps -> Select `auto-approve-app` -> Client secrets + * The private key will be downloaded using your browser + * Save it in 1Password or vault + +* Create two organization secrets: + * GH_AUTO_APPROVE_APP_ID + * GH_AUTO_APPROVE_APP_PRIVATE_KEY + +* Add Github App `auto-approve-app` to your branch ruleset. + * github.com/github-organization/repository -> Settings -> Rules -> Rulesets -> rule name -> Bypass list -> Add bypass + * This allows the Github App `auto-approve-app` to merge the MRs even if other conditions of the ruleset are not met. diff --git a/ci/gitlint/rules_auto_approve/only-flake.py b/ci/gitlint/rules_auto_approve/only-flake.py new file mode 100644 index 0000000000..567323869f --- /dev/null +++ b/ci/gitlint/rules_auto_approve/only-flake.py @@ -0,0 +1,61 @@ +# Copyright © 2026 Cyberus Technology GmbH +# +# SPDX-License-Identifier: Apache-2.0 +# +from gitlint.options import ListOption, StrOption +from gitlint.rules import CommitRule, RuleViolation + +class SingleSpecificFile(CommitRule): + """Reject commits which modifies files other than those specified""" + id = "UC-flake" + name = "body-require-single-specific-file" + description = "Commit must change exactly one specific file" + target = None # Applies to entire commit + options_spec = [ + StrOption( + "filepath", + "flake.lock", + "The file path to check" + ) + ] + + def validate(self, commit): + changed_files = getattr(commit, "changed_files", None) + if changed_files is None: + # Newer gitlint commit objects expose the touched paths directly via + # `changed_files`. Older variants may only expose + # `changed_files_stats`, a mapping keyed by changed path, so we fall + # back to its keys when `changed_files` is unavailable. + changed_files_stats = getattr(commit, "changed_files_stats", {}) + changed_files = list(changed_files_stats.keys()) + + if len(changed_files) != 1: + return [RuleViolation("commit-changes-multiple-files-or-none", f"Commit changes {len(changed_files)} files, expected exactly 1: {', '.join(changed_files)}")] + + filepath = self.options["filepath"].value + if changed_files[0] != filepath: + return [RuleViolation("commit-wrong-file", f"Commit changes '{changed_files[0]}', expected only '{filepath}'")] + +#################### +# Usage of this rule +#################### +# +# .gitlint_auto_approve file +# [general] +# extra-path=ci/gitlint/rules_auto_approve +# regex-style-search=true +# ignore=body-is-missing,body-max-line-length + +# # default 72 +# [title-max-length] +# line-length=72 + +# # Empty bodies are fine +# [body-min-length] +# min-length=0 + +# [UC-flake] +# filepath=flake.lock + +## run with +# nix run nixpkgs#gitlint -- --commits origin/main.. -C .gitlint_auto_approve