From bcc9682f0496c97e3a1377045ed148e3b1bf4002 Mon Sep 17 00:00:00 2001 From: Marco Spengler Date: Mon, 17 Jun 2024 07:33:56 +0200 Subject: [PATCH] ci: add workflow to automate n8n updates (N8N-13) --- .github/workflows/n8n-dependency-update.yaml | 241 +++++++++++++++++++ 1 file changed, 241 insertions(+) create mode 100644 .github/workflows/n8n-dependency-update.yaml diff --git a/.github/workflows/n8n-dependency-update.yaml b/.github/workflows/n8n-dependency-update.yaml new file mode 100644 index 00000000..363a69a5 --- /dev/null +++ b/.github/workflows/n8n-dependency-update.yaml @@ -0,0 +1,241 @@ +name: n8n Dependency Update + +on: + pull_request: + branches: + - main + types: + - opened + +env: + YQ_VERSION: v4.44.1 + +permissions: + contents: write + pull-requests: write + +jobs: + determine-versions: + name: Determine node, n8n and types Versions + runs-on: ubuntu-latest + if: contains(github.event.pull_request.title, 'bump n8n from') + + outputs: + target-node-version: ${{ steps.target-node-version.outputs.version }} + target-n8n-version: ${{ steps.target-n8n-version.outputs.version }} + target-n8n-nodes-base-version: ${{ steps.target-n8n-nodes-base-version.outputs.version }} + target-n8n-workflow-version: ${{ steps.target-n8n-workflow-version.outputs.version }} + target-types-node-version: ${{ steps.target-types-node-version.outputs.version }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Extract target n8n version + id: target-n8n-version + # yamllint disable-line rule:line-length + run: echo "version=$(jq --raw-output '.packages["node_modules/n8n"].version' package-lock.json)" >> "$GITHUB_OUTPUT" + + - name: Extract target n8n-nodes-base version + id: target-n8n-nodes-base-version + # yamllint disable-line rule:line-length + run: echo "version=$(jq --raw-output '.packages["node_modules/n8n"].dependencies["n8n-nodes-base"]' package-lock.json)" >> "$GITHUB_OUTPUT" + + - name: Extract target n8n-workflow version + id: target-n8n-workflow-version + # yamllint disable-line rule:line-length + run: echo "version=$(jq --raw-output '.packages["node_modules/n8n"].dependencies["n8n-workflow"]' package-lock.json)" >> "$GITHUB_OUTPUT" + + - name: Retrieve Node.js version from n8n Docker Image + id: target-node-version + run: | + node_version=$(echo $(docker run --rm --entrypoint node n8nio/n8n:1.44.2 --version)) + echo "version=${node_version#v}" >> "$GITHUB_OUTPUT" + + - name: Find closest matching version of @types/node + id: target-types-node-version + # yamllint disable-line rule:line-length + run: echo "version=$(npm show @types/node versions --json | jq -r 'map(select(. <= "${{ steps.target-node-version.outputs.version }}")) | map(split(".") | map(tonumber)) | max_by(.) | join(".")')" >> "$GITHUB_OUTPUT" + + update-common-dependencies: + name: Update Common Dependencies + runs-on: ubuntu-latest + if: contains(github.event.pull_request.title, 'bump n8n from') + needs: determine-versions + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Update node version in devcontainer.json + # yamllint disable rule:line-length + run: | + devcontainer_json='.devcontainer/devcontainer.json' + json_path='["features", "ghcr.io/devcontainers/features/node:1", "version"]' + target_node_version='${{ needs.determine-versions.outputs.target-node-version }}' + + if [ "$(jq -r --argjson path "${json_path}" 'getpath($path)' ${devcontainer_json})" != "${target_node_version}" ]; then + jq \ + --argjson path "${json_path}" \ + --arg version "${target_node_version}" \ + 'setpath($path; $version)' ${devcontainer_json} > ${devcontainer_json}.new + + mv ${devcontainer_json}.new ${devcontainer_json} + fi + # yamllint enable rule:line-length + + - name: Commit node version update in devcontainer.json + uses: stefanzweifel/git-auto-commit-action@v5 + with: + # yamllint disable-line rule:line-length + commit_message: 'chore: bump node version in devcontainer to ${{ needs.determine-versions.outputs.target-node-version }}' + skip_dirty_check: false + create_branch: false + + - name: Update @types/node + # yamllint disable rule:line-length + run: | + npm install @types/node@~${{ needs.determine-versions.outputs.target-types-node-version }} \ + --save-dev + # yamllint enable rule:line-length + + - name: Commit @types/node update + uses: stefanzweifel/git-auto-commit-action@v5 + with: + # yamllint disable-line rule:line-length + commit_message: 'chore: bump @types/node version to ${{ needs.determine-versions.outputs.target-types-node-version }}' + skip_dirty_check: false + create_branch: false + + - name: Update n8n-nodes-base in root + # yamllint disable rule:line-length + run: | + npm install n8n-nodes-base@${{ needs.determine-versions.outputs.target-n8n-nodes-base-version }} \ + --save-dev \ + --save-exact + # yamllint enable rule:line-length + + - name: Commit n8n-nodes-base update + uses: stefanzweifel/git-auto-commit-action@v5 + with: + # yamllint disable-line rule:line-length + commit_message: 'chore: bump n8n-nodes-base version to ${{ needs.determine-versions.outputs.target-n8n-nodes-base-version }}' + skip_dirty_check: false + create_branch: false + + - name: Update n8n-workflow in root + # yamllint disable rule:line-length + run: | + npm install n8n-workflow@${{ needs.determine-versions.outputs.target-n8n-workflow-version }} \ + --save-dev \ + --save-exact + # yamllint enable rule:line-length + + - name: Commit n8n-workflow update + uses: stefanzweifel/git-auto-commit-action@v5 + with: + # yamllint disable-line rule:line-length + commit_message: 'chore: bump n8n-workflow version to ${{ needs.determine-versions.outputs.target-n8n-workflow-version }}' + + update-n8n-versions-in-nodes: + name: Update n8n versions in nodes + runs-on: ubuntu-latest + if: contains(github.event.pull_request.title, 'bump n8n from') + needs: + - determine-versions + - update-common-dependencies + + strategy: + matrix: + node: + - test + max-parallel: 1 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Update n8n-nodes-base version + # yamllint disable rule:line-length + run: | + sed -i "s/\"n8n-nodes-base\": \".*\"/\"n8n-nodes-base\": \"${{ needs.determine-versions.outputs.target-n8n-nodes-base-version }}\"/g" nodes/${{matrix.node}}/package.json + # yamllint enable rule:line-length + + - name: Commit n8n version updates in node + uses: stefanzweifel/git-auto-commit-action@v5 + with: + # yamllint disable-line rule:line-length + commit_message: 'fix(${{matrix.node}}): bump n8n-nodes-base version to ${{ needs.determine-versions.outputs.target-n8n-nodes-base-version }}' + skip_dirty_check: false + create_branch: false + + - name: Update n8n-workflow version + # yamllint disable rule:line-length + run: | + sed -i "s/\"n8n-workflow\": \".*\"/\"n8n-workflow\": \"${{ needs.determine-versions.outputs.target-n8n-workflow-version }}\"/g" nodes/${{matrix.node}}/package.json + # yamllint enable rule:line-length + + - name: Commit n8n version updates in node + uses: stefanzweifel/git-auto-commit-action@v5 + with: + # yamllint disable-line rule:line-length + commit_message: 'fix(${{matrix.node}}): bump n8n-workflow version to ${{ needs.determine-versions.outputs.target-n8n-workflow-version }}' + skip_dirty_check: false + create_branch: false + + verify-workflow-node-version: + name: Verify matching version for GitHub Workflow Node.js + runs-on: ubuntu-latest + if: contains(github.event.pull_request.title, 'bump n8n from') + needs: determine-versions + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup YQ + uses: chrisdickinson/setup-yq@latest + with: + yq-version: ${{ env.YQ_VERSION }} + + - name: Check Node.js version + id: check_node_version + # yamllint disable rule:line-length + run: | + workflow_file_urls=() + + for workflow_file in ".github/workflows/"*.yaml; do + node_version=$(yq eval '.env.NODE_VERSION' "$workflow_file") + if [ "${node_version}" = "null" ] || [ "${node_version}" = "${{ needs.determine-versions.outputs.target-node-version }}" ] ; then + continue; + fi + + line_number=$(yq eval '.env.NODE_VERSION | line' "$workflow_file") + + url="[${workflow_file}](${{ github.server_url }}/${{ github.repository }}/blob/main/${workflow_file}#L${line_number})" + + workflow_file_urls+=("$url") + done + + if [ ${#workflow_file_urls[@]} -gt 0 ]; then + echo "workflow_file_urls=${workflow_file_urls[*]}" >> "$GITHUB_OUTPUT" + fi + # yamllint enable rule:line-length + + - name: Request changes on PR + if: steps.check_node_version.outputs.workflow_file_urls + # yamllint disable rule:line-length + run: | + # Split the output by spaces into an array + IFS=' ' read -r -a files_array <<< "${{ steps.check_node_version.outputs.workflow_file_urls }}" + + files_with_newlines=$(printf -- '- %s\n' "${files_array[@]}") + + body=$(printf "The following Workflows have a different NODE_VERSION:\n%s\n\nPlease update the Node.js version to **${{ needs.determine-versions.outputs.target-node-version }}**." "${files_with_newlines}") + + gh pr review ${{ github.event.pull_request.number }} \ + --request-changes \ + --body "${body}" + # yamllint enable rule:line-length + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}