From 6f9fc6eab12d4c74c0b4309d31e458947be4c134 Mon Sep 17 00:00:00 2001 From: Judson Lester Date: Wed, 12 Oct 2022 15:58:36 -0700 Subject: [PATCH 01/12] Use gh CLI to make (verified) commit --- action.yml | 33 +++++++++++++++++++++++++++++++++ update-flake-lock.sh | 10 ++++++++-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/action.yml b/action.yml index 81f92f7..1527412 100644 --- a/action.yml +++ b/action.yml @@ -9,6 +9,10 @@ inputs: description: 'GITHUB_TOKEN or a `repo` scoped Personal Access Token (PAT)' required: false default: ${{ github.token }} + commit-with-token: + description: 'Set to true to produce a verified commit with token' + required: false + default: false commit-msg: description: 'The message provided with the commit' required: false @@ -119,6 +123,35 @@ runs: TARGETS: ${{ inputs.inputs }} COMMIT_MSG: ${{ inputs.commit-msg }} PATH_TO_FLAKE_DIR: ${{ inputs.path-to-flake-dir }} + COMMIT_WITH_TOKEN: ${{ inputs.commit-with-token }} + + - name: Commit changes + if: ${{ inputs.commit-with-token == 'true' }} + env: + GITHUB_TOKEN: ${{ inputs.token }} + FILE_TO_COMMIT: flake.lock + DESTINATION_BRANCH: ${{ inputs.branch }} + shell: bash + run: | + set -x + export CONTENT=$( base64 -i $FILE_TO_COMMIT ) + export BASE=$DESTINATION_BRANCH + if gh api --method GET /repos/:owner/:repo/git/refs/heads/$DESTINATION_BRANCH; then + git fetch origin $DESTINATION_BRANCH + else + export BASE=$(gh repo view --json defaultBranchRef --template '{{ .defaultBranchRef.name }}' ${{github.repository}}) + gh api --method POST /repos/:owner/:repo/git/refs \ + --field ref=refs/heads/$DESTINATION_BRANCH \ + --field sha=$BASE_SHA + fi + export BASE_SHA=$( git rev-parse origin/$BASE ) + export SHA=$( git rev-parse origin/$BASE:$FILE_TO_COMMIT ) + gh api --method PUT /repos/:owner/:repo/contents/$FILE_TO_COMMIT \ + --field message="${{inputs.commit-msg}}" \ + --field content="$CONTENT" \ + --field encoding="base64" \ + --field branch="$DESTINATION_BRANCH" \ + --field sha="$SHA" - name: Save PR Body as file uses: DamianReeves/write-file-action@v1.1 with: diff --git a/update-flake-lock.sh b/update-flake-lock.sh index e33a199..bf90d73 100755 --- a/update-flake-lock.sh +++ b/update-flake-lock.sh @@ -5,12 +5,18 @@ if [[ -n "$PATH_TO_FLAKE_DIR" ]]; then cd "$PATH_TO_FLAKE_DIR" fi +commitArg="" + +if [[ "$COMMIT_WITH_TOKEN" != true ]]; then + commitArg="--commit-lock-file " +fi + if [[ -n "$TARGETS" ]]; then inputs=() for input in $TARGETS; do inputs+=("--update-input" "$input") done - nix flake lock "${inputs[@]}" --commit-lock-file --commit-lockfile-summary "$COMMIT_MSG" + nix flake lock "${inputs[@]}" $commitArg --commit-lockfile-summary "$COMMIT_MSG" else - nix flake update --commit-lock-file --commit-lockfile-summary "$COMMIT_MSG" + nix flake update $commitArg --commit-lockfile-summary "$COMMIT_MSG" fi From 1ee5a6cee54df82068385bdfb6dc0a1d311e4843 Mon Sep 17 00:00:00 2001 From: Judson Lester Date: Wed, 19 Oct 2022 12:47:05 -0700 Subject: [PATCH 02/12] Create the branch only if needed --- action.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/action.yml b/action.yml index 1527412..25f05ee 100644 --- a/action.yml +++ b/action.yml @@ -140,6 +140,7 @@ runs: git fetch origin $DESTINATION_BRANCH else export BASE=$(gh repo view --json defaultBranchRef --template '{{ .defaultBranchRef.name }}' ${{github.repository}}) + export BASE_SHA=$( git rev-parse origin/$BASE ) gh api --method POST /repos/:owner/:repo/git/refs \ --field ref=refs/heads/$DESTINATION_BRANCH \ --field sha=$BASE_SHA From 8e2a4ea6d8c9bd87b3c40107089ad171bcd6d08c Mon Sep 17 00:00:00 2001 From: Judson Lester Date: Fri, 28 Oct 2022 17:29:10 -0700 Subject: [PATCH 03/12] Document how to get compliant updates --- README.md | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6d2b5b7..a04ada9 100644 --- a/README.md +++ b/README.md @@ -167,6 +167,44 @@ jobs: token: ${{ secrets.GH_TOKEN_FOR_UPDATES }} ``` +### Authenticating via a Github App + +A Github App can both produce verified commits _and_ create pull requests that will trigger further Github Actions. + +Create a stub Github App in your organization. Disable webhooks, add Content write and Pull Request write permissions, and make it available only within your organization. Install the App in the Organization (possibly restricting only to relevant repos). Copy the App secret into an Actions secret, along with the App ID. + +Set up your workflow like this: + +```yaml +name: update-flake-lock +on: + workflow_dispatch: # allows manual triggering + schedule: + - cron: '0 0 * * 1,4' # Run twice a week + +jobs: + lockfile: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v2 + - name: Install Nix + uses: cachix/install-nix-action@v17 + - name: Get Updater Token + uses: tibdex/github-app-token@v1 + id: generate-token + with: + app_id: ${{ secrets.UPDATE_APP_ID}} + private_key: ${{secrets.UPDATE_APP_KEY}} + - name: Update flake.lock + uses: DeterminateSystems/update-flake-lock@vX + with: + token: ${{ steps.generate-token.outputs.token }} + commit-with-token: true + ``` + +``` + ## With GPG commit signing It's possible for the bot to produce GPG signed commits. Associating a GPG public key to a github user account is not required but it is necessary if you want the signed commits to appear as verified in Github. This can be a compliance requirement in some cases. @@ -175,7 +213,7 @@ You can follow [Github's guide on creating and/or adding a new GPG key to an use For the bot to produce signed commits, you will have to provide the GPG private keys to this action's input parameters. You can safely do that with [Github secrets as explained here](https://github.com/crazy-max/ghaction-import-gpg#prerequisites). -When using commit signing, the commit author name and email for the commits produced by this bot would correspond to the ones associated to the GPG Public Key. +When using commit signing, the commit author name and email for the commits produced by this bot would correspond to the ones associated to the GPG Public Key. If you want to sign using a subkey, you must specify the subkey fingerprint using the `gpg-fingerprint` input parameter. From caae4dc74add9d29b625390f70f61c54660290de Mon Sep 17 00:00:00 2001 From: Judson Lester Date: Fri, 4 Nov 2022 10:21:23 -0700 Subject: [PATCH 04/12] CI feedback --- action.yml | 4 ++-- update-flake-lock.sh | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/action.yml b/action.yml index 25f05ee..9ecc894 100644 --- a/action.yml +++ b/action.yml @@ -10,9 +10,9 @@ inputs: required: false default: ${{ github.token }} commit-with-token: - description: 'Set to true to produce a verified commit with token' + description: 'Set to "true" to produce a verified commit with token' required: false - default: false + default: '' commit-msg: description: 'The message provided with the commit' required: false diff --git a/update-flake-lock.sh b/update-flake-lock.sh index bf90d73..512d875 100755 --- a/update-flake-lock.sh +++ b/update-flake-lock.sh @@ -6,9 +6,9 @@ if [[ -n "$PATH_TO_FLAKE_DIR" ]]; then fi commitArg="" - -if [[ "$COMMIT_WITH_TOKEN" != true ]]; then - commitArg="--commit-lock-file " +if [[ "$COMMIT_WITH_TOKEN" != "true" ]]; then + # Commit happening in next step + commitArg="suppress" fi if [[ -n "$TARGETS" ]]; then @@ -16,7 +16,7 @@ if [[ -n "$TARGETS" ]]; then for input in $TARGETS; do inputs+=("--update-input" "$input") done - nix flake lock "${inputs[@]}" $commitArg --commit-lockfile-summary "$COMMIT_MSG" + nix flake lock "${inputs[@]}" ${commitArg:+"--commit-lock-file"} --commit-lockfile-summary "$COMMIT_MSG" else - nix flake update $commitArg --commit-lockfile-summary "$COMMIT_MSG" + nix flake update ${commitArg:+"--commit-lock-file"} --commit-lockfile-summary "$COMMIT_MSG" fi From 10aa0b3a9de6b7b92f12539bea94b63a222efc79 Mon Sep 17 00:00:00 2001 From: Judson Lester Date: Tue, 6 Jun 2023 14:52:45 -0700 Subject: [PATCH 05/12] Update README.md Co-authored-by: Cole Helbling --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a04ada9..e6ddc52 100644 --- a/README.md +++ b/README.md @@ -169,7 +169,9 @@ jobs: ### Authenticating via a Github App -A Github App can both produce verified commits _and_ create pull requests that will trigger further Github Actions. +A GitHub App can both produce verified commits _and_ create pull requests that will trigger further GitHub Actions. + +> **NOTE**: This will produce commits without a Nix-generated summary; i.e. the commit message will not tell you which inputs were updated from which old version to which new version. Create a stub Github App in your organization. Disable webhooks, add Content write and Pull Request write permissions, and make it available only within your organization. Install the App in the Organization (possibly restricting only to relevant repos). Copy the App secret into an Actions secret, along with the App ID. From d8c285288a6525de46e478a26d4ea3211635b391 Mon Sep 17 00:00:00 2001 From: Judson Lester Date: Tue, 6 Jun 2023 14:53:23 -0700 Subject: [PATCH 06/12] Update README.md Co-authored-by: Cole Helbling --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index e6ddc52..41a23f2 100644 --- a/README.md +++ b/README.md @@ -203,7 +203,6 @@ jobs: with: token: ${{ steps.generate-token.outputs.token }} commit-with-token: true - ``` ``` From e303679626fa692e3389a424ed7639472ae081e4 Mon Sep 17 00:00:00 2001 From: Judson Lester Date: Fri, 6 Jun 2025 10:04:17 -0700 Subject: [PATCH 07/12] fix: make commit-with-token default true --- action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yml b/action.yml index 9ecc894..9520dc5 100644 --- a/action.yml +++ b/action.yml @@ -11,7 +11,7 @@ inputs: default: ${{ github.token }} commit-with-token: description: 'Set to "true" to produce a verified commit with token' - required: false + required: true default: '' commit-msg: description: 'The message provided with the commit' From c00434d414d446c6ca8ab238aa73160b2f1d1393 Mon Sep 17 00:00:00 2001 From: Judson Lester Date: Fri, 6 Jun 2025 10:25:53 -0700 Subject: [PATCH 08/12] fix: set the _default_ to true (not required) --- action.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/action.yml b/action.yml index 9520dc5..4047967 100644 --- a/action.yml +++ b/action.yml @@ -11,8 +11,8 @@ inputs: default: ${{ github.token }} commit-with-token: description: 'Set to "true" to produce a verified commit with token' - required: true - default: '' + required: false + default: 'true' commit-msg: description: 'The message provided with the commit' required: false From a263995b5a6c5254eff8d0abc08b64c5d7fef53f Mon Sep 17 00:00:00 2001 From: Judson Lester Date: Fri, 28 Aug 2026 14:22:31 -0700 Subject: [PATCH 09/12] test: ci --- action.yml | 50 ++++++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/action.yml b/action.yml index 4047967..3e4554a 100644 --- a/action.yml +++ b/action.yml @@ -1,36 +1,36 @@ -name: 'Update flake.lock' -description: 'Update your flake.lock and send a PR' +name: "Update flake.lock" +description: "Update your flake.lock and send a PR" inputs: inputs: - description: 'A space-separated list of inputs to update. Leave empty to update all inputs.' + description: "A space-separated list of inputs to update. Leave empty to update all inputs." required: false - default: '' + default: "" token: - description: 'GITHUB_TOKEN or a `repo` scoped Personal Access Token (PAT)' + description: "GITHUB_TOKEN or a `repo` scoped Personal Access Token (PAT)" required: false default: ${{ github.token }} commit-with-token: description: 'Set to "true" to produce a verified commit with token' required: false - default: 'true' + default: "true" commit-msg: - description: 'The message provided with the commit' + description: "The message provided with the commit" required: false default: "flake.lock: Update" branch: - description: 'The branch of the PR to be created' + description: "The branch of the PR to be created" required: false default: "update_flake_lock_action" path-to-flake-dir: - description: 'The path of the directory containing `flake.nix` file within your repository. Useful when `flake.nix` cannot reside at the root of your repository.' + description: "The path of the directory containing `flake.nix` file within your repository. Useful when `flake.nix` cannot reside at the root of your repository." required: false - default: '' + default: "" pr-title: - description: 'The title of the PR to be created' + description: "The title of the PR to be created" required: false default: "flake.lock: Update" pr-body: - description: 'The body of the PR to be created' + description: "The body of the PR to be created" required: false default: | Automated changes by the [update-flake-lock](https://github.com/DeterminateSystems/update-flake-lock) GitHub Action. @@ -54,27 +54,27 @@ inputs: ``` pr-labels: - description: 'A comma or newline separated list of labels to set on the Pull Request to be created' + description: "A comma or newline separated list of labels to set on the Pull Request to be created" required: false - default: '' + default: "" sign-commits: - description: 'Set to true if the action should sign the commit with GPG' + description: "Set to true if the action should sign the commit with GPG" required: false - default: 'false' + default: "false" gpg-private-key: - description: 'GPG Private Key with which to sign the commits in the PR to be created' + description: "GPG Private Key with which to sign the commits in the PR to be created" required: false - default: '' + default: "" gpg-fingerprint: - description: 'Fingerprint of specific GPG subkey to use' + description: "Fingerprint of specific GPG subkey to use" required: false gpg-passphrase: - description: 'GPG Private Key Passphrase for the GPG Private Key with which to sign the commits in the PR to be created' + description: "GPG Private Key Passphrase for the GPG Private Key with which to sign the commits in the PR to be created" required: false - default: '' + default: "" outputs: pull-request-number: - description: 'The number of the opened pull request' + description: "The number of the opened pull request" value: ${{ steps.create-pr.outputs.pull-request-number }} runs: using: "composite" @@ -139,6 +139,8 @@ runs: if gh api --method GET /repos/:owner/:repo/git/refs/heads/$DESTINATION_BRANCH; then git fetch origin $DESTINATION_BRANCH else + git remote -v + git branch -a export BASE=$(gh repo view --json defaultBranchRef --template '{{ .defaultBranchRef.name }}' ${{github.repository}}) export BASE_SHA=$( git rev-parse origin/$BASE ) gh api --method POST /repos/:owner/:repo/git/refs \ @@ -171,8 +173,8 @@ runs: - name: Interpolate PR Body uses: pedrolamas/handlebars-action@v2.0.0 with: - files: 'pr_body.template' - output-filename: 'pr_body.txt' + files: "pr_body.template" + output-filename: "pr_body.txt" - name: Read pr_body.txt id: pr_body uses: andstor/file-reader-action@v1 From de039e421dc30d04028bbf2551947589bda77eb8 Mon Sep 17 00:00:00 2001 From: Judson Lester Date: Fri, 28 Aug 2026 14:39:13 -0700 Subject: [PATCH 10/12] test: ci --- action.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/action.yml b/action.yml index 3e4554a..4ddb1d2 100644 --- a/action.yml +++ b/action.yml @@ -140,6 +140,7 @@ runs: git fetch origin $DESTINATION_BRANCH else git remote -v + git fetch origin git branch -a export BASE=$(gh repo view --json defaultBranchRef --template '{{ .defaultBranchRef.name }}' ${{github.repository}}) export BASE_SHA=$( git rev-parse origin/$BASE ) From 93cbe87bdae19a4be0a8262f440c886823a61e70 Mon Sep 17 00:00:00 2001 From: Judson Lester Date: Fri, 28 Aug 2026 15:04:26 -0700 Subject: [PATCH 11/12] test: ci --- action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yml b/action.yml index 4ddb1d2..a84a8a9 100644 --- a/action.yml +++ b/action.yml @@ -134,13 +134,13 @@ runs: shell: bash run: | set -x + git fetch origin export CONTENT=$( base64 -i $FILE_TO_COMMIT ) export BASE=$DESTINATION_BRANCH if gh api --method GET /repos/:owner/:repo/git/refs/heads/$DESTINATION_BRANCH; then git fetch origin $DESTINATION_BRANCH else git remote -v - git fetch origin git branch -a export BASE=$(gh repo view --json defaultBranchRef --template '{{ .defaultBranchRef.name }}' ${{github.repository}}) export BASE_SHA=$( git rev-parse origin/$BASE ) From 70cf39b992b432029a28d165b14596273bda5cca Mon Sep 17 00:00:00 2001 From: Judson Lester Date: Fri, 28 Aug 2026 15:27:58 -0700 Subject: [PATCH 12/12] test: ci --- action.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/action.yml b/action.yml index a84a8a9..0d390e4 100644 --- a/action.yml +++ b/action.yml @@ -134,14 +134,13 @@ runs: shell: bash run: | set -x + git fetch origin export CONTENT=$( base64 -i $FILE_TO_COMMIT ) export BASE=$DESTINATION_BRANCH if gh api --method GET /repos/:owner/:repo/git/refs/heads/$DESTINATION_BRANCH; then git fetch origin $DESTINATION_BRANCH else - git remote -v - git branch -a export BASE=$(gh repo view --json defaultBranchRef --template '{{ .defaultBranchRef.name }}' ${{github.repository}}) export BASE_SHA=$( git rev-parse origin/$BASE ) gh api --method POST /repos/:owner/:repo/git/refs \