name: Update on: # Runs everyday at noon schedule: - cron: "0 12 * * *" # Allow manual triggering workflow_dispatch: inputs: lock: type: boolean default: true description: Update flake.lock generate: type: boolean default: true description: Update generated files check_for_changes: type: boolean default: false description: Cancel if there are no changes to the `nixpkgs` input # Allow one concurrent update per branch concurrency: group: "update-${{ github.ref_name }}" cancel-in-progress: true # Allow pushing and creating PRs permissions: contents: write pull-requests: write jobs: update: name: Update the flake inputs and generate options runs-on: ubuntu-latest timeout-minutes: 40 if: github.event_name != 'schedule' || github.repository == 'nix-community/nixvim' env: repo: ${{ github.repository }} base_branch: ${{ github.ref_name }} pr_branch: update/${{ github.ref_name }} steps: - name: Checkout repository uses: actions/checkout@v4 with: ssh-key: ${{ secrets.CI_UPDATE_SSH_KEY }} - name: Install Nix uses: cachix/install-nix-action@v30 with: nix_path: nixpkgs=channel:nixos-unstable github_access_token: ${{ secrets.GITHUB_TOKEN }} - name: Configure git run: | git config user.name 'github-actions[bot]' git config user.email '41898282+github-actions[bot]@users.noreply.github.com' - name: Get info on the current PR id: open_pr_info env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | # Query for info about the already open update PR info=$( gh api graphql -F owner='{owner}' -F repo='{repo}' -F branch="$pr_branch" -f query=' query($owner:String!, $repo:String!, $branch:String!) { repository(owner: $owner, name: $repo) { pullRequests(first: 1, states: OPEN, headRefName: $branch) { nodes { number url } } } } ' | jq --raw-output ' .data.repository.pullRequests.nodes[] | to_entries[] | "\(.key)=\(.value)" ' ) if [[ -n "$info" ]]; then echo "PR info:" echo "$info" echo "$info" >> $GITHUB_OUTPUT else echo "No PR is currently open" fi - name: Update flake.lock id: flake_lock if: inputs.lock || github.event_name == 'schedule' run: | old=$(git show --no-patch --format=%h) nix flake update --commit-lock-file new=$(git show --no-patch --format=%h) if [ "$old" != "$new" ]; then echo "body<> "$GITHUB_OUTPUT" git show --no-patch --format=%b >> "$GITHUB_OUTPUT" echo "EOF" >> "$GITHUB_OUTPUT" fi - name: Check if nixpkgs input was changed id: changes if: github.event_name == 'schedule' || inputs.check_for_changes env: pr_num: ${{ steps.open_pr_info.outputs.number }} pr_url: ${{ steps.open_pr_info.outputs.url }} run: | getAttr() { nix eval --raw --impure \ --expr '{ ref }: builtins.getFlake ref' \ --argstr ref "$1" "$2" } getNixpkgsRev() { getAttr "$1" 'inputs.nixpkgs.rev' } if [[ -n "$pr_num" ]]; then old_branch=$pr_branch else old_branch=$base_branch fi old=$(getNixpkgsRev "github:$repo/$old_branch") new=$(getNixpkgsRev "$PWD") ( echo "old_rev=$old" echo "new_rev=$new" [[ "$old" = "$new" ]] && echo 'cancelled=1' ) >> $GITHUB_OUTPUT - name: Update generated files id: generate if: (!steps.changes.outputs.cancelled) && (inputs.generate || github.event_name == 'schedule') run: | old=$(git show --no-patch --format=%h) nix-build ./update-scripts -A generate ./result/bin/generate --commit new=$(git show --no-patch --format=%h) if [ "$old" != "$new" ]; then body=$(git show --no-patch --format=%b) echo "body<> "$GITHUB_OUTPUT" if [ -n "$body" ]; then # Multi-file changes are listed in the body echo "$body" >> "$GITHUB_OUTPUT" else # Single-file changes are only in the summary, # e.g. "generated: Updated none-ls.nix" git show --no-patch --format=%s | \ sed -e 's/^generated:/-/' >> "$GITHUB_OUTPUT" fi echo "EOF" >> "$GITHUB_OUTPUT" fi - name: Create Pull Request id: pr if: (!steps.changes.outputs.cancelled) uses: peter-evans/create-pull-request@v6 with: add-paths: "!**" pr_branch: update/${{ github.ref_name }} delete-branch: true title: | [${{ github.ref_name }}] Update flake.lock & generated files body: | ## Flake lockfile ``` ${{ steps.flake_lock.outputs.body || 'No changes' }} ``` ## Generate ${{ steps.generate.outputs.body || 'No changes' }} - name: Print summary if: steps.pr.outputs.pull-request-number env: pr_num: ${{ steps.pr.outputs.pull-request-number }} pr_url: ${{ steps.pr.outputs.pull-request-url }} pr_branch: ${{ steps.pr.outputs.pull-request-branch }} head: ${{ steps.pr.outputs.pull-request-head-sha }} operation: ${{ steps.pr.outputs.pull-request-operation }} run: | short=${head:0:6} # stdout echo "${short} pushed to ${pr_branch}" echo "#${pr_num} was ${operation}: ${pr_url}" ( # markdown summary echo "## ${{ github.ref_name }}" echo echo "\`${short}\` pushed to \`${pr_branch}\`" echo echo "[#${pr_num}](${pr_url}) was ${operation}." echo ) >> $GITHUB_STEP_SUMMARY - name: Print cancellation summary if: (!steps.pr.outputs.pull-request-number) env: pr_num: ${{ steps.open_pr_info.outputs.number }} pr_url: ${{ steps.open_pr_info.outputs.url }} changes: ${{ steps.flake_lock.outputs.body || 'No changes' }} cancelled: ${{ steps.changes.outputs.cancelled || '' }} rev: ${{ steps.changes.outputs.new_rev || '' }} run: | if [[ -n "$cancelled" ]]; then ( # stdout echo "nixpkgs rev has not changed ($rev)." echo 'You can re-run the workflow manually to update anyway.' ) >&2 ( # markdown summary echo '## Update cancelled' echo if [[ -n "$pr_num" ]]; then echo -n 'The `nixpkgs` input has not changed compared to the already open PR: ' echo "[#$pr_num]($pr_url) (\`nixpkgs.rev: ${rev:0:6}\`)." else echo -n 'The `nixpkgs` input has not changed compared to the base branch: ' echo "\`$base_branch\`" fi echo echo 'You can re-run the workflow manually to update anyway.' echo ) >> $GITHUB_STEP_SUMMARY else ( #stdout echo "No PR was opened" ) >&2 ( echo "## Not updated" echo ) >> $GITHUB_STEP_SUMMARY fi ( # markdown summary echo echo 'The following changes would have been made:' echo echo '```' echo "$changes" echo '```' echo ) >> $GITHUB_STEP_SUMMARY