diff --git a/README.md b/README.md index 6d2b5b7..41a23f2 100644 --- a/README.md +++ b/README.md @@ -167,6 +167,45 @@ 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. + +> **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. + +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 +214,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. diff --git a/action.yml b/action.yml index 81f92f7..0d390e4 100644 --- a/action.yml +++ b/action.yml @@ -1,32 +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" 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. @@ -50,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" @@ -119,6 +123,38 @@ 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 + + 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 + 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 + 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: @@ -137,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 diff --git a/update-flake-lock.sh b/update-flake-lock.sh index e33a199..512d875 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 + # Commit happening in next step + commitArg="suppress" +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-lock-file"} --commit-lockfile-summary "$COMMIT_MSG" else - nix flake update --commit-lock-file --commit-lockfile-summary "$COMMIT_MSG" + nix flake update ${commitArg:+"--commit-lock-file"} --commit-lockfile-summary "$COMMIT_MSG" fi