From 4563f0f0fff3626c715b568949a3a4ec6ed81598 Mon Sep 17 00:00:00 2001 From: Matteo Marsala Date: Tue, 25 Aug 2026 20:14:14 +0200 Subject: [PATCH 01/19] feat: try to improve build time --- .github/workflows/deploy-production.yml | 62 +++++++++++++++++++++++-- .github/workflows/deploy-staging.yml | 62 +++++++++++++++++++++++-- .github/workflows/preview.yml | 53 +++++++++++++++++++-- 3 files changed, 165 insertions(+), 12 deletions(-) diff --git a/.github/workflows/deploy-production.yml b/.github/workflows/deploy-production.yml index 88625b6fa1..335a5437ec 100644 --- a/.github/workflows/deploy-production.yml +++ b/.github/workflows/deploy-production.yml @@ -21,8 +21,29 @@ jobs: render-datasheets: name: Render Datasheets runs-on: ubuntu-latest + timeout-minutes: 30 steps: + # Checkout stalls intermittently on this repo (~9 GB): on 2026-08-25, 4 of + # 8 checkouts hung with no progress at all. Bound the attempt and retry + # once, instead of letting a stalled transfer run into the 6h default. - uses: actions/checkout@v4 + id: checkout + continue-on-error: true + timeout-minutes: 15 + with: + fetch-depth: 1 + + # A checkout killed by the timeout leaves a partial clone behind (and + # sometimes a stale index.lock): wiping the workspace makes the second + # attempt genuinely independent of the first. + - name: Reset workspace before checkout retry + if: steps.checkout.outcome == 'failure' + run: | + shopt -s dotglob + rm -rf "${GITHUB_WORKSPACE:?}"/* + + - uses: actions/checkout@v4 + if: steps.checkout.outcome == 'failure' with: fetch-depth: 1 @@ -36,17 +57,44 @@ jobs: needs: render-datasheets runs-on: ubuntu-latest environment: production + timeout-minutes: 150 env: REPO_ACCESS_TOKEN: ${{ secrets.REPO_ACCESS_TOKEN }} APP_ENV: prod steps: + # fetch-depth: 0 is required by gatsby-transformer-gitinfo, which runs + # `git log -n 1 -- ` on every content file to populate + # gitLogLatestDate (the "last updated" date shown on tutorial pages). + # filter: blob:none still fetches every commit and every tree - so that + # git log keeps resolving locally - while skipping historical blob + # contents, which are the bulk of this repo's ~11 GB of git history. + # Do NOT swap this for fetch-depth: 1: it would blank out gitLogLatestDate. + # Checkout stalls intermittently on this repo (~9 GB): on 2026-08-25, 4 of + # 8 checkouts hung with no progress at all. Bound the attempt and retry + # once, instead of letting a stalled transfer run into the 6h default. - uses: actions/checkout@v4 + id: checkout + continue-on-error: true + timeout-minutes: 20 with: fetch-depth: "0" + filter: blob:none - - name: Cleanup runner disk - uses: ./.github/actions/cleanup-disk # Cleanup machine before starting the build + # A checkout killed by the timeout leaves a partial clone behind (and + # sometimes a stale index.lock): wiping the workspace makes the second + # attempt genuinely independent of the first. + - name: Reset workspace before checkout retry + if: steps.checkout.outcome == 'failure' + run: | + shopt -s dotglob + rm -rf "${GITHUB_WORKSPACE:?}"/* + + - uses: actions/checkout@v4 + if: steps.checkout.outcome == 'failure' + with: + fetch-depth: "0" + filter: blob:none - uses: actions/setup-node@v4 with: @@ -120,10 +168,15 @@ jobs: - name: Compress Large Images run: | sudo apt-get update && sudo apt-get install -y jpegoptim optipng + # -exec ... \; spawns one process per file, sequentially on a single + # core. xargs -P "$(nproc)" does the same work across every available + # core: the files are independent, so the result is identical. echo "Compressing large JPGs..." - find content -type f \( -name "*.jpg" -o -name "*.jpeg" \) -size +2M -print -exec jpegoptim --strip-all {} \; + find content -type f \( -name "*.jpg" -o -name "*.jpeg" \) -size +2M -print0 | + xargs -0 -r -P "$(nproc)" -n 1 jpegoptim --strip-all echo "Compressing large PNGs..." - find content -type f -name "*.png" -size +2M -print -exec optipng -o2 {} \; + find content -type f -name "*.png" -size +2M -print0 | + xargs -0 -r -P "$(nproc)" -n 1 optipng -o2 - name: Gatsby main cache uses: actions/cache@v4 @@ -162,6 +215,7 @@ jobs: needs: build runs-on: ubuntu-latest environment: production + timeout-minutes: 10 steps: - name: Purge Cloudflare Cache shell: bash diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml index 190f405b1d..74937cdfa8 100644 --- a/.github/workflows/deploy-staging.yml +++ b/.github/workflows/deploy-staging.yml @@ -21,8 +21,29 @@ jobs: render-datasheets: name: Render Datasheets runs-on: ubuntu-latest + timeout-minutes: 30 steps: + # Checkout stalls intermittently on this repo (~9 GB): on 2026-08-25, 4 of + # 8 checkouts hung with no progress at all. Bound the attempt and retry + # once, instead of letting a stalled transfer run into the 6h default. - uses: actions/checkout@v4 + id: checkout + continue-on-error: true + timeout-minutes: 15 + with: + fetch-depth: 1 + + # A checkout killed by the timeout leaves a partial clone behind (and + # sometimes a stale index.lock): wiping the workspace makes the second + # attempt genuinely independent of the first. + - name: Reset workspace before checkout retry + if: steps.checkout.outcome == 'failure' + run: | + shopt -s dotglob + rm -rf "${GITHUB_WORKSPACE:?}"/* + + - uses: actions/checkout@v4 + if: steps.checkout.outcome == 'failure' with: fetch-depth: 1 @@ -36,17 +57,44 @@ jobs: needs: render-datasheets runs-on: ubuntu-latest environment: staging + timeout-minutes: 150 env: REPO_ACCESS_TOKEN: ${{ secrets.REPO_ACCESS_TOKEN }} APP_ENV: staging steps: + # fetch-depth: 0 is required by gatsby-transformer-gitinfo, which runs + # `git log -n 1 -- ` on every content file to populate + # gitLogLatestDate (the "last updated" date shown on tutorial pages). + # filter: blob:none still fetches every commit and every tree - so that + # git log keeps resolving locally - while skipping historical blob + # contents, which are the bulk of this repo's ~11 GB of git history. + # Do NOT swap this for fetch-depth: 1: it would blank out gitLogLatestDate. + # Checkout stalls intermittently on this repo (~9 GB): on 2026-08-25, 4 of + # 8 checkouts hung with no progress at all. Bound the attempt and retry + # once, instead of letting a stalled transfer run into the 6h default. - uses: actions/checkout@v4 + id: checkout + continue-on-error: true + timeout-minutes: 20 with: fetch-depth: "0" + filter: blob:none - - name: Cleanup runner disk - uses: ./.github/actions/cleanup-disk # Cleanup machine before starting the build + # A checkout killed by the timeout leaves a partial clone behind (and + # sometimes a stale index.lock): wiping the workspace makes the second + # attempt genuinely independent of the first. + - name: Reset workspace before checkout retry + if: steps.checkout.outcome == 'failure' + run: | + shopt -s dotglob + rm -rf "${GITHUB_WORKSPACE:?}"/* + + - uses: actions/checkout@v4 + if: steps.checkout.outcome == 'failure' + with: + fetch-depth: "0" + filter: blob:none - uses: actions/setup-node@v4 with: @@ -120,10 +168,15 @@ jobs: - name: Compress Large Images run: | sudo apt-get update && sudo apt-get install -y jpegoptim optipng + # -exec ... \; spawns one process per file, sequentially on a single + # core. xargs -P "$(nproc)" does the same work across every available + # core: the files are independent, so the result is identical. echo "Compressing large JPGs..." - find content -type f \( -name "*.jpg" -o -name "*.jpeg" \) -size +2M -print -exec jpegoptim --strip-all {} \; + find content -type f \( -name "*.jpg" -o -name "*.jpeg" \) -size +2M -print0 | + xargs -0 -r -P "$(nproc)" -n 1 jpegoptim --strip-all echo "Compressing large PNGs..." - find content -type f -name "*.png" -size +2M -print -exec optipng -o2 {} \; + find content -type f -name "*.png" -size +2M -print0 | + xargs -0 -r -P "$(nproc)" -n 1 optipng -o2 - name: Gatsby main cache uses: actions/cache@v4 @@ -162,6 +215,7 @@ jobs: needs: build runs-on: ubuntu-latest environment: staging + timeout-minutes: 10 steps: - name: Purge Cloudflare Cache shell: bash diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 87b5e7fa6f..cf5476ff0d 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -18,8 +18,29 @@ jobs: name: Render Datasheets if: ${{ contains(github.event.pull_request.labels.*.name, 'preview') || github.ref_name == 'main' }} runs-on: ubuntu-latest + timeout-minutes: 30 steps: + # Checkout stalls intermittently on this repo (~9 GB): on 2026-08-25, 4 of + # 8 checkouts hung with no progress at all. Bound the attempt and retry + # once, instead of letting a stalled transfer run into the 6h default. - uses: actions/checkout@v4 + id: checkout + continue-on-error: true + timeout-minutes: 15 + with: + fetch-depth: 1 + + # A checkout killed by the timeout leaves a partial clone behind (and + # sometimes a stale index.lock): wiping the workspace makes the second + # attempt genuinely independent of the first. + - name: Reset workspace before checkout retry + if: steps.checkout.outcome == 'failure' + run: | + shopt -s dotglob + rm -rf "${GITHUB_WORKSPACE:?}"/* + + - uses: actions/checkout@v4 + if: steps.checkout.outcome == 'failure' with: fetch-depth: 1 @@ -32,6 +53,7 @@ jobs: if: ${{ contains(github.event.pull_request.labels.*.name, 'preview') || github.ref_name == 'main' }} runs-on: ubuntu-latest needs: render-datasheets + timeout-minutes: 150 concurrency: group: netlify cancel-in-progress: false @@ -61,12 +83,30 @@ jobs: ## Preview Deployment Waiting for deployment to complete... + # Checkout stalls intermittently on this repo (~9 GB): on 2026-08-25, 4 of + # 8 checkouts hung with no progress at all. Bound the attempt and retry + # once, instead of letting a stalled transfer run into the 6h default. + - uses: actions/checkout@v4 + id: checkout + continue-on-error: true + timeout-minutes: 15 + with: + fetch-depth: 1 + + # A checkout killed by the timeout leaves a partial clone behind (and + # sometimes a stale index.lock): wiping the workspace makes the second + # attempt genuinely independent of the first. + - name: Reset workspace before checkout retry + if: steps.checkout.outcome == 'failure' + run: | + shopt -s dotglob + rm -rf "${GITHUB_WORKSPACE:?}"/* + - uses: actions/checkout@v4 + if: steps.checkout.outcome == 'failure' with: fetch-depth: 1 - - name: Cleanup runner disk - uses: ./.github/actions/cleanup-disk - uses: actions/setup-node@v4 with: node-version: 18 @@ -123,10 +163,15 @@ jobs: - name: Compress Large Images run: | sudo apt-get update && sudo apt-get install -y jpegoptim optipng + # -exec ... \; spawns one process per file, sequentially on a single + # core. xargs -P "$(nproc)" does the same work across every available + # core: the files are independent, so the result is identical. echo "Compressing large JPGs..." - find content -type f \( -name "*.jpg" -o -name "*.jpeg" \) -size +2M -print -exec jpegoptim --strip-all {} \; + find content -type f \( -name "*.jpg" -o -name "*.jpeg" \) -size +2M -print0 | + xargs -0 -r -P "$(nproc)" -n 1 jpegoptim --strip-all echo "Compressing large PNGs..." - find content -type f -name "*.png" -size +2M -print -exec optipng -o2 {} \; + find content -type f -name "*.png" -size +2M -print0 | + xargs -0 -r -P "$(nproc)" -n 1 optipng -o2 - name: Gatsby main cache uses: actions/cache@v4 From 9107bd88f4d624f8907a49cc33257846d5a5f18e Mon Sep 17 00:00:00 2001 From: Matteo Marsala Date: Thu, 27 Aug 2026 14:14:31 +0200 Subject: [PATCH 02/19] 2.2.9-alpha.1 --- .github/workflows/deploy-production.yml | 33 +++++++++++---- .github/workflows/deploy-staging.yml | 33 +++++++++++---- .github/workflows/preview.yml | 55 ++++++++++++++++++++----- package-lock.json | 8 ++-- package.json | 2 +- 5 files changed, 100 insertions(+), 31 deletions(-) diff --git a/.github/workflows/deploy-production.yml b/.github/workflows/deploy-production.yml index 335a5437ec..b52c5bcf7c 100644 --- a/.github/workflows/deploy-production.yml +++ b/.github/workflows/deploy-production.yml @@ -165,18 +165,35 @@ jobs: # echo "No oversized files found. New check passed." # fi + # Key on the paths and sizes of the files the step compresses, so it changes as soon as any of them does + - name: Compressed images key + id: images-key + run: echo "hash=$(find content -type f \( -name '*.jpg' -o -name '*.jpeg' -o -name '*.png' \) -size +2M -printf '%p %s\n' | sort | sha256sum | cut -c1-40)" >> "$GITHUB_OUTPUT" + + - name: Compressed images cache + uses: actions/cache@v4 + with: + path: /tmp/compressed-images.tar + key: ${{ runner.os }}-compressed-images-${{ steps.images-key.outputs.hash }} + - name: Compress Large Images run: | + # jpegoptim and optipng are deterministic, so a hit means the same bytes without spending ~9 min again + if [ -f /tmp/compressed-images.tar ]; then + echo "Restoring images compressed by an earlier run..." + tar xf /tmp/compressed-images.tar + exit 0 + fi sudo apt-get update && sudo apt-get install -y jpegoptim optipng - # -exec ... \; spawns one process per file, sequentially on a single - # core. xargs -P "$(nproc)" does the same work across every available - # core: the files are independent, so the result is identical. + # -exec ... \; spawns one process per file on a single core: xargs -P "$(nproc)" spreads the same work over every core + find content -type f \( -name "*.jpg" -o -name "*.jpeg" \) -size +2M -print0 > /tmp/big-jpg.lst + find content -type f -name "*.png" -size +2M -print0 > /tmp/big-png.lst echo "Compressing large JPGs..." - find content -type f \( -name "*.jpg" -o -name "*.jpeg" \) -size +2M -print0 | - xargs -0 -r -P "$(nproc)" -n 1 jpegoptim --strip-all + xargs -0 -r -P "$(nproc)" -n 1 jpegoptim --strip-all < /tmp/big-jpg.lst echo "Compressing large PNGs..." - find content -type f -name "*.png" -size +2M -print0 | - xargs -0 -r -P "$(nproc)" -n 1 optipng -o2 + xargs -0 -r -P "$(nproc)" -n 1 optipng -o2 < /tmp/big-png.lst + # The list is captured before compressing: some files drop under 2M and find would no longer report them + cat /tmp/big-jpg.lst /tmp/big-png.lst | tar --null -cf /tmp/compressed-images.tar -T - - name: Gatsby main cache uses: actions/cache@v4 @@ -196,7 +213,7 @@ jobs: restore-keys: | ${{ runner.os }}-public-gatsby-main - - run: npm install + - run: npm install --prefer-offline --no-audit --fund=false - name: Build run: npm run build diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml index 74937cdfa8..5be6da8f6b 100644 --- a/.github/workflows/deploy-staging.yml +++ b/.github/workflows/deploy-staging.yml @@ -165,18 +165,35 @@ jobs: # echo "No oversized files found. New check passed." # fi + # Key on the paths and sizes of the files the step compresses, so it changes as soon as any of them does + - name: Compressed images key + id: images-key + run: echo "hash=$(find content -type f \( -name '*.jpg' -o -name '*.jpeg' -o -name '*.png' \) -size +2M -printf '%p %s\n' | sort | sha256sum | cut -c1-40)" >> "$GITHUB_OUTPUT" + + - name: Compressed images cache + uses: actions/cache@v4 + with: + path: /tmp/compressed-images.tar + key: ${{ runner.os }}-compressed-images-${{ steps.images-key.outputs.hash }} + - name: Compress Large Images run: | + # jpegoptim and optipng are deterministic, so a hit means the same bytes without spending ~9 min again + if [ -f /tmp/compressed-images.tar ]; then + echo "Restoring images compressed by an earlier run..." + tar xf /tmp/compressed-images.tar + exit 0 + fi sudo apt-get update && sudo apt-get install -y jpegoptim optipng - # -exec ... \; spawns one process per file, sequentially on a single - # core. xargs -P "$(nproc)" does the same work across every available - # core: the files are independent, so the result is identical. + # -exec ... \; spawns one process per file on a single core: xargs -P "$(nproc)" spreads the same work over every core + find content -type f \( -name "*.jpg" -o -name "*.jpeg" \) -size +2M -print0 > /tmp/big-jpg.lst + find content -type f -name "*.png" -size +2M -print0 > /tmp/big-png.lst echo "Compressing large JPGs..." - find content -type f \( -name "*.jpg" -o -name "*.jpeg" \) -size +2M -print0 | - xargs -0 -r -P "$(nproc)" -n 1 jpegoptim --strip-all + xargs -0 -r -P "$(nproc)" -n 1 jpegoptim --strip-all < /tmp/big-jpg.lst echo "Compressing large PNGs..." - find content -type f -name "*.png" -size +2M -print0 | - xargs -0 -r -P "$(nproc)" -n 1 optipng -o2 + xargs -0 -r -P "$(nproc)" -n 1 optipng -o2 < /tmp/big-png.lst + # The list is captured before compressing: some files drop under 2M and find would no longer report them + cat /tmp/big-jpg.lst /tmp/big-png.lst | tar --null -cf /tmp/compressed-images.tar -T - - name: Gatsby main cache uses: actions/cache@v4 @@ -196,7 +213,7 @@ jobs: restore-keys: | ${{ runner.os }}-public-gatsby-main - - run: npm install + - run: npm install --prefer-offline --no-audit --fund=false - name: Build run: npm run build diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index cf5476ff0d..3ddb74ef68 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -160,21 +160,38 @@ jobs: # echo "No oversized files found. New check passed." # fi + # Key on the paths and sizes of the files the step compresses, so it changes as soon as any of them does + - name: Compressed images key + id: images-key + run: echo "hash=$(find content -type f \( -name '*.jpg' -o -name '*.jpeg' -o -name '*.png' \) -size +2M -printf '%p %s\n' | sort | sha256sum | cut -c1-40)" >> "$GITHUB_OUTPUT" + + - name: Compressed images cache + uses: actions/cache@v4 + with: + path: /tmp/compressed-images.tar + key: ${{ runner.os }}-compressed-images-${{ steps.images-key.outputs.hash }} + - name: Compress Large Images run: | + # jpegoptim and optipng are deterministic, so a hit means the same bytes without spending ~9 min again + if [ -f /tmp/compressed-images.tar ]; then + echo "Restoring images compressed by an earlier run..." + tar xf /tmp/compressed-images.tar + exit 0 + fi sudo apt-get update && sudo apt-get install -y jpegoptim optipng - # -exec ... \; spawns one process per file, sequentially on a single - # core. xargs -P "$(nproc)" does the same work across every available - # core: the files are independent, so the result is identical. + # -exec ... \; spawns one process per file on a single core: xargs -P "$(nproc)" spreads the same work over every core + find content -type f \( -name "*.jpg" -o -name "*.jpeg" \) -size +2M -print0 > /tmp/big-jpg.lst + find content -type f -name "*.png" -size +2M -print0 > /tmp/big-png.lst echo "Compressing large JPGs..." - find content -type f \( -name "*.jpg" -o -name "*.jpeg" \) -size +2M -print0 | - xargs -0 -r -P "$(nproc)" -n 1 jpegoptim --strip-all + xargs -0 -r -P "$(nproc)" -n 1 jpegoptim --strip-all < /tmp/big-jpg.lst echo "Compressing large PNGs..." - find content -type f -name "*.png" -size +2M -print0 | - xargs -0 -r -P "$(nproc)" -n 1 optipng -o2 + xargs -0 -r -P "$(nproc)" -n 1 optipng -o2 < /tmp/big-png.lst + # The list is captured before compressing: some files drop under 2M and find would no longer report them + cat /tmp/big-jpg.lst /tmp/big-png.lst | tar --null -cf /tmp/compressed-images.tar -T - - name: Gatsby main cache - uses: actions/cache@v4 + uses: actions/cache/restore@v4 id: gatsby-cache-folder with: path: .cache @@ -183,7 +200,7 @@ jobs: ${{ runner.os }}-cache-gatsby-main - name: Gatsby Public Folder - uses: actions/cache@v4 + uses: actions/cache/restore@v4 id: gatsby-public-folder with: path: public/ @@ -191,8 +208,26 @@ jobs: restore-keys: | ${{ runner.os }}-public-gatsby-main - - run: npm install + - run: npm install --prefer-offline --no-audit --fund=false - run: GATSBY_HF_CDN_URL="" npm run build + env: + # Gatsby defaults to physical cores, which is half the vCPUs of a runner + GATSBY_CPU_COUNT: logical_cores + + # A PR's ~4 GB public/ entry is unreadable by other PRs and evicts main's, the one they all restore from: only main writes + - name: Save Gatsby main cache + if: github.ref_name == 'main' + uses: actions/cache/save@v4 + with: + path: .cache + key: ${{ runner.os }}-cache-gatsby-main-${{ github.run_id }} + + - name: Save Gatsby Public Folder + if: github.ref_name == 'main' + uses: actions/cache/save@v4 + with: + path: public/ + key: ${{ runner.os }}-public-gatsby-main-${{ github.run_id }} - name: Install Netlify run: npm install netlify-cli@17.23.2 -g diff --git a/package-lock.json b/package-lock.json index aebbf45da1..251057e16d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "hasInstallScript": true, "license": "ISC", "dependencies": { - "@arduino/docs-arduino-cc": "^2.2.81", + "@arduino/docs-arduino-cc": "^2.2.9-alpha.1", "gatsby": "^5.11.0", "gatsby-background-image": "^1.6.0", "gatsby-image": "^3.11.0", @@ -315,9 +315,9 @@ } }, "node_modules/@arduino/docs-arduino-cc": { - "version": "2.2.81", - "resolved": "https://npm.pkg.github.com/download/@arduino/docs-arduino-cc/2.2.81/1300e5fda82cbd34ea78198c5984571d1d76e2b5", - "integrity": "sha512-wr3OvvGfzqR/xxGPZfxzHG2xDzrAXwh1D69h/W1alnIKOmG2ujs8orb3EntfKIOJmKfxixZqepBqYt0hckOaYQ==", + "version": "2.2.9-alpha.1", + "resolved": "https://npm.pkg.github.com/download/@arduino/docs-arduino-cc/2.2.9-alpha.1/6dd15e6d8c8d4e518b6578c54ca62ba3ecc08062", + "integrity": "sha512-YdSjMsrSme/a2a/k0RUGOHktoCtQ9rAc7xKQkqunUHcasLvEcK1I2AxjI4CQZi2g8JBRH5TVPNb1vJ3zo/Wm3w==", "dependencies": { "@algolia/autocomplete-core": "^1.10.0", "@algolia/autocomplete-plugin-recent-searches": "^1.17.0", diff --git a/package.json b/package.json index d51b841f84..87a60e4d3d 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ }, "homepage": "https://github.com/arduino/docs-content#readme", "dependencies": { - "@arduino/docs-arduino-cc": "^2.2.81", + "@arduino/docs-arduino-cc": "^2.2.9-alpha.1", "gatsby": "^5.11.0", "gatsby-background-image": "^1.6.0", "gatsby-image": "^3.11.0", From e888f5397c8ea81c2c0fca07acea11c052641633 Mon Sep 17 00:00:00 2001 From: Matteo Marsala Date: Thu, 27 Aug 2026 16:14:47 +0200 Subject: [PATCH 03/19] 2.2.9-alpha.1 --- .github/workflows/deploy-production.yml | 9 +++++---- .github/workflows/deploy-staging.yml | 9 +++++---- .github/workflows/preview.yml | 9 +++++---- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/.github/workflows/deploy-production.yml b/.github/workflows/deploy-production.yml index b52c5bcf7c..0f522d9874 100644 --- a/.github/workflows/deploy-production.yml +++ b/.github/workflows/deploy-production.yml @@ -29,7 +29,7 @@ jobs: - uses: actions/checkout@v4 id: checkout continue-on-error: true - timeout-minutes: 15 + timeout-minutes: 5 with: fetch-depth: 1 @@ -76,7 +76,7 @@ jobs: - uses: actions/checkout@v4 id: checkout continue-on-error: true - timeout-minutes: 20 + timeout-minutes: 5 with: fetch-depth: "0" filter: blob:none @@ -188,10 +188,11 @@ jobs: # -exec ... \; spawns one process per file on a single core: xargs -P "$(nproc)" spreads the same work over every core find content -type f \( -name "*.jpg" -o -name "*.jpeg" \) -size +2M -print0 > /tmp/big-jpg.lst find content -type f -name "*.png" -size +2M -print0 > /tmp/big-png.lst + # find -exec ignored the exit status of each command, xargs reports 123 if any file fails: a few .png are really JPEGs echo "Compressing large JPGs..." - xargs -0 -r -P "$(nproc)" -n 1 jpegoptim --strip-all < /tmp/big-jpg.lst + xargs -0 -r -P "$(nproc)" -n 1 jpegoptim --strip-all < /tmp/big-jpg.lst || echo "Some JPGs could not be optimized, continuing" echo "Compressing large PNGs..." - xargs -0 -r -P "$(nproc)" -n 1 optipng -o2 < /tmp/big-png.lst + xargs -0 -r -P "$(nproc)" -n 1 optipng -o2 < /tmp/big-png.lst || echo "Some PNGs could not be optimized, continuing" # The list is captured before compressing: some files drop under 2M and find would no longer report them cat /tmp/big-jpg.lst /tmp/big-png.lst | tar --null -cf /tmp/compressed-images.tar -T - diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml index 5be6da8f6b..62170c5099 100644 --- a/.github/workflows/deploy-staging.yml +++ b/.github/workflows/deploy-staging.yml @@ -29,7 +29,7 @@ jobs: - uses: actions/checkout@v4 id: checkout continue-on-error: true - timeout-minutes: 15 + timeout-minutes: 5 with: fetch-depth: 1 @@ -76,7 +76,7 @@ jobs: - uses: actions/checkout@v4 id: checkout continue-on-error: true - timeout-minutes: 20 + timeout-minutes: 5 with: fetch-depth: "0" filter: blob:none @@ -188,10 +188,11 @@ jobs: # -exec ... \; spawns one process per file on a single core: xargs -P "$(nproc)" spreads the same work over every core find content -type f \( -name "*.jpg" -o -name "*.jpeg" \) -size +2M -print0 > /tmp/big-jpg.lst find content -type f -name "*.png" -size +2M -print0 > /tmp/big-png.lst + # find -exec ignored the exit status of each command, xargs reports 123 if any file fails: a few .png are really JPEGs echo "Compressing large JPGs..." - xargs -0 -r -P "$(nproc)" -n 1 jpegoptim --strip-all < /tmp/big-jpg.lst + xargs -0 -r -P "$(nproc)" -n 1 jpegoptim --strip-all < /tmp/big-jpg.lst || echo "Some JPGs could not be optimized, continuing" echo "Compressing large PNGs..." - xargs -0 -r -P "$(nproc)" -n 1 optipng -o2 < /tmp/big-png.lst + xargs -0 -r -P "$(nproc)" -n 1 optipng -o2 < /tmp/big-png.lst || echo "Some PNGs could not be optimized, continuing" # The list is captured before compressing: some files drop under 2M and find would no longer report them cat /tmp/big-jpg.lst /tmp/big-png.lst | tar --null -cf /tmp/compressed-images.tar -T - diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 3ddb74ef68..886b25e93d 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -26,7 +26,7 @@ jobs: - uses: actions/checkout@v4 id: checkout continue-on-error: true - timeout-minutes: 15 + timeout-minutes: 5 with: fetch-depth: 1 @@ -89,7 +89,7 @@ jobs: - uses: actions/checkout@v4 id: checkout continue-on-error: true - timeout-minutes: 15 + timeout-minutes: 5 with: fetch-depth: 1 @@ -183,10 +183,11 @@ jobs: # -exec ... \; spawns one process per file on a single core: xargs -P "$(nproc)" spreads the same work over every core find content -type f \( -name "*.jpg" -o -name "*.jpeg" \) -size +2M -print0 > /tmp/big-jpg.lst find content -type f -name "*.png" -size +2M -print0 > /tmp/big-png.lst + # find -exec ignored the exit status of each command, xargs reports 123 if any file fails: a few .png are really JPEGs echo "Compressing large JPGs..." - xargs -0 -r -P "$(nproc)" -n 1 jpegoptim --strip-all < /tmp/big-jpg.lst + xargs -0 -r -P "$(nproc)" -n 1 jpegoptim --strip-all < /tmp/big-jpg.lst || echo "Some JPGs could not be optimized, continuing" echo "Compressing large PNGs..." - xargs -0 -r -P "$(nproc)" -n 1 optipng -o2 < /tmp/big-png.lst + xargs -0 -r -P "$(nproc)" -n 1 optipng -o2 < /tmp/big-png.lst || echo "Some PNGs could not be optimized, continuing" # The list is captured before compressing: some files drop under 2M and find would no longer report them cat /tmp/big-jpg.lst /tmp/big-png.lst | tar --null -cf /tmp/compressed-images.tar -T - From ea0c0e45a6661adeae14dd0884188850e4fe7af7 Mon Sep 17 00:00:00 2001 From: Matteo Marsala Date: Fri, 28 Aug 2026 09:28:54 +0200 Subject: [PATCH 04/19] 2.2.9-alpha.2 --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 251057e16d..2dc09059e9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "hasInstallScript": true, "license": "ISC", "dependencies": { - "@arduino/docs-arduino-cc": "^2.2.9-alpha.1", + "@arduino/docs-arduino-cc": "^2.2.9-alpha.2", "gatsby": "^5.11.0", "gatsby-background-image": "^1.6.0", "gatsby-image": "^3.11.0", @@ -315,9 +315,9 @@ } }, "node_modules/@arduino/docs-arduino-cc": { - "version": "2.2.9-alpha.1", - "resolved": "https://npm.pkg.github.com/download/@arduino/docs-arduino-cc/2.2.9-alpha.1/6dd15e6d8c8d4e518b6578c54ca62ba3ecc08062", - "integrity": "sha512-YdSjMsrSme/a2a/k0RUGOHktoCtQ9rAc7xKQkqunUHcasLvEcK1I2AxjI4CQZi2g8JBRH5TVPNb1vJ3zo/Wm3w==", + "version": "2.2.9-alpha.2", + "resolved": "https://npm.pkg.github.com/download/@arduino/docs-arduino-cc/2.2.9-alpha.2/19f482f564ab94f3e2a83cc1e4c6397311407c47", + "integrity": "sha512-qx3PpwK5z55S+5HY3Shr/lRTRjHoem5wdUMOKps5M8OdWyfmf6jBFvqZ+uSWT6dGUmC5oin1KqctxKnwni7gTQ==", "dependencies": { "@algolia/autocomplete-core": "^1.10.0", "@algolia/autocomplete-plugin-recent-searches": "^1.17.0", diff --git a/package.json b/package.json index 87a60e4d3d..2c9eb2cc98 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ }, "homepage": "https://github.com/arduino/docs-content#readme", "dependencies": { - "@arduino/docs-arduino-cc": "^2.2.9-alpha.1", + "@arduino/docs-arduino-cc": "^2.2.9-alpha.2", "gatsby": "^5.11.0", "gatsby-background-image": "^1.6.0", "gatsby-image": "^3.11.0", From 38a9d2713e7925b535301791162ac11572d42f26 Mon Sep 17 00:00:00 2001 From: Matteo Marsala Date: Fri, 28 Aug 2026 10:38:06 +0200 Subject: [PATCH 05/19] improve build --- .github/workflows/deploy-production.yml | 17 +++++++++++++++-- .github/workflows/deploy-staging.yml | 4 ++-- .github/workflows/preview.yml | 15 --------------- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/.github/workflows/deploy-production.yml b/.github/workflows/deploy-production.yml index 0f522d9874..efffa7ab82 100644 --- a/.github/workflows/deploy-production.yml +++ b/.github/workflows/deploy-production.yml @@ -197,7 +197,7 @@ jobs: cat /tmp/big-jpg.lst /tmp/big-png.lst | tar --null -cf /tmp/compressed-images.tar -T - - name: Gatsby main cache - uses: actions/cache@v4 + uses: actions/cache/restore@v4 id: gatsby-cache-folder with: path: .cache @@ -206,7 +206,7 @@ jobs: ${{ runner.os }}-cache-gatsby-main - name: Gatsby Public Folder cache - uses: actions/cache@v4 + uses: actions/cache/restore@v4 id: gatsby-public-folder with: path: public/ @@ -219,6 +219,19 @@ jobs: - name: Build run: npm run build + # A warm public/ is worth 38 minutes of sharp, and costs ~4 GB of quota: main writes it, every other branch only reads + - name: Save Gatsby main cache + uses: actions/cache/save@v4 + with: + path: .cache + key: ${{ runner.os }}-cache-gatsby-main-${{ github.run_id }} + + - name: Save Gatsby Public Folder cache + uses: actions/cache/save@v4 + with: + path: public/ + key: ${{ runner.os }}-public-gatsby-main-${{ github.run_id }} + - name: Clean up node_modules # Just to save space run: rm -rf node_modules diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml index 62170c5099..6119d8e4b6 100644 --- a/.github/workflows/deploy-staging.yml +++ b/.github/workflows/deploy-staging.yml @@ -197,7 +197,7 @@ jobs: cat /tmp/big-jpg.lst /tmp/big-png.lst | tar --null -cf /tmp/compressed-images.tar -T - - name: Gatsby main cache - uses: actions/cache@v4 + uses: actions/cache/restore@v4 id: gatsby-cache-folder with: path: .cache @@ -206,7 +206,7 @@ jobs: ${{ runner.os }}-cache-gatsby-main - name: Gatsby Public Folder cache - uses: actions/cache@v4 + uses: actions/cache/restore@v4 id: gatsby-public-folder with: path: public/ diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 886b25e93d..397154a88b 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -215,21 +215,6 @@ jobs: # Gatsby defaults to physical cores, which is half the vCPUs of a runner GATSBY_CPU_COUNT: logical_cores - # A PR's ~4 GB public/ entry is unreadable by other PRs and evicts main's, the one they all restore from: only main writes - - name: Save Gatsby main cache - if: github.ref_name == 'main' - uses: actions/cache/save@v4 - with: - path: .cache - key: ${{ runner.os }}-cache-gatsby-main-${{ github.run_id }} - - - name: Save Gatsby Public Folder - if: github.ref_name == 'main' - uses: actions/cache/save@v4 - with: - path: public/ - key: ${{ runner.os }}-public-gatsby-main-${{ github.run_id }} - - name: Install Netlify run: npm install netlify-cli@17.23.2 -g From 9ec61bdf6562e0c5ea57c67c8916e3aa760f373a Mon Sep 17 00:00:00 2001 From: Matteo Marsala Date: Fri, 28 Aug 2026 12:23:24 +0200 Subject: [PATCH 06/19] improve build --- .github/workflows/deploy-production.yml | 9 +++++++++ .github/workflows/deploy-staging.yml | 9 +++++++++ .github/workflows/preview.yml | 9 +++++++++ 3 files changed, 27 insertions(+) diff --git a/.github/workflows/deploy-production.yml b/.github/workflows/deploy-production.yml index efffa7ab82..fcc13e5cc1 100644 --- a/.github/workflows/deploy-production.yml +++ b/.github/workflows/deploy-production.yml @@ -63,6 +63,15 @@ jobs: APP_ENV: prod steps: + # A full-history checkout plus node_modules and a restored public/ do not fit beside the preinstalled toolchains: a + # checkout on a full disk dies with "unable to write new index file". The local action cannot be used before checkout. + - name: Free up disk space + run: | + df -h / + sudo rm -rf /opt/hostedtoolcache /usr/share/dotnet /usr/local/lib/android /usr/share/swift /usr/local/julia* \ + /opt/pipx /usr/lib/mono /opt/google/chrome /opt/microsoft /usr/local/lib/node_modules /usr/local/share/powershell + df -h / + # fetch-depth: 0 is required by gatsby-transformer-gitinfo, which runs # `git log -n 1 -- ` on every content file to populate # gitLogLatestDate (the "last updated" date shown on tutorial pages). diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml index 6119d8e4b6..d01891fc50 100644 --- a/.github/workflows/deploy-staging.yml +++ b/.github/workflows/deploy-staging.yml @@ -63,6 +63,15 @@ jobs: APP_ENV: staging steps: + # A full-history checkout plus node_modules and a restored public/ do not fit beside the preinstalled toolchains: a + # checkout on a full disk dies with "unable to write new index file". The local action cannot be used before checkout. + - name: Free up disk space + run: | + df -h / + sudo rm -rf /opt/hostedtoolcache /usr/share/dotnet /usr/local/lib/android /usr/share/swift /usr/local/julia* \ + /opt/pipx /usr/lib/mono /opt/google/chrome /opt/microsoft /usr/local/lib/node_modules /usr/local/share/powershell + df -h / + # fetch-depth: 0 is required by gatsby-transformer-gitinfo, which runs # `git log -n 1 -- ` on every content file to populate # gitLogLatestDate (the "last updated" date shown on tutorial pages). diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 397154a88b..956cac59aa 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -63,6 +63,15 @@ jobs: BRANCH_NAME: ${{ github.ref_name }} steps: + # A full-history checkout plus node_modules and a restored public/ do not fit beside the preinstalled toolchains: a + # checkout on a full disk dies with "unable to write new index file". The local action cannot be used before checkout. + - name: Free up disk space + run: | + df -h / + sudo rm -rf /opt/hostedtoolcache /usr/share/dotnet /usr/local/lib/android /usr/share/swift /usr/local/julia* \ + /opt/pipx /usr/lib/mono /opt/google/chrome /opt/microsoft /usr/local/lib/node_modules /usr/local/share/powershell + df -h / + - name: Find PR Preview Comment if: github.event_name == 'pull_request' From eff748c9bd0008cf53ab502c2c2cfeff79679eaa Mon Sep 17 00:00:00 2001 From: Matteo Marsala Date: Mon, 31 Aug 2026 08:29:30 +0200 Subject: [PATCH 07/19] ci: retry checkout three times, drop the disk cleanup --- .github/workflows/deploy-production.yml | 40 +++++++++++++++++++------ .github/workflows/deploy-staging.yml | 40 +++++++++++++++++++------ .github/workflows/preview.yml | 39 ++++++++++++++++++------ 3 files changed, 92 insertions(+), 27 deletions(-) diff --git a/.github/workflows/deploy-production.yml b/.github/workflows/deploy-production.yml index fcc13e5cc1..c532befd64 100644 --- a/.github/workflows/deploy-production.yml +++ b/.github/workflows/deploy-production.yml @@ -43,7 +43,22 @@ jobs: rm -rf "${GITHUB_WORKSPACE:?}"/* - uses: actions/checkout@v4 + id: checkout-retry if: steps.checkout.outcome == 'failure' + continue-on-error: true + timeout-minutes: 5 + with: + fetch-depth: 1 + + # Attempt 2 has failed outright before, not only stalled: one more wipe and one last try + - name: Reset workspace before last checkout attempt + if: steps.checkout.outcome == 'failure' && steps.checkout-retry.outcome == 'failure' + run: | + shopt -s dotglob + rm -rf "${GITHUB_WORKSPACE:?}"/* + + - uses: actions/checkout@v4 + if: steps.checkout.outcome == 'failure' && steps.checkout-retry.outcome == 'failure' with: fetch-depth: 1 @@ -63,15 +78,6 @@ jobs: APP_ENV: prod steps: - # A full-history checkout plus node_modules and a restored public/ do not fit beside the preinstalled toolchains: a - # checkout on a full disk dies with "unable to write new index file". The local action cannot be used before checkout. - - name: Free up disk space - run: | - df -h / - sudo rm -rf /opt/hostedtoolcache /usr/share/dotnet /usr/local/lib/android /usr/share/swift /usr/local/julia* \ - /opt/pipx /usr/lib/mono /opt/google/chrome /opt/microsoft /usr/local/lib/node_modules /usr/local/share/powershell - df -h / - # fetch-depth: 0 is required by gatsby-transformer-gitinfo, which runs # `git log -n 1 -- ` on every content file to populate # gitLogLatestDate (the "last updated" date shown on tutorial pages). @@ -100,7 +106,23 @@ jobs: rm -rf "${GITHUB_WORKSPACE:?}"/* - uses: actions/checkout@v4 + id: checkout-retry if: steps.checkout.outcome == 'failure' + continue-on-error: true + timeout-minutes: 5 + with: + fetch-depth: "0" + filter: blob:none + + # Attempt 2 has failed outright before, not only stalled: one more wipe and one last try + - name: Reset workspace before last checkout attempt + if: steps.checkout.outcome == 'failure' && steps.checkout-retry.outcome == 'failure' + run: | + shopt -s dotglob + rm -rf "${GITHUB_WORKSPACE:?}"/* + + - uses: actions/checkout@v4 + if: steps.checkout.outcome == 'failure' && steps.checkout-retry.outcome == 'failure' with: fetch-depth: "0" filter: blob:none diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml index d01891fc50..be19df3c28 100644 --- a/.github/workflows/deploy-staging.yml +++ b/.github/workflows/deploy-staging.yml @@ -43,7 +43,22 @@ jobs: rm -rf "${GITHUB_WORKSPACE:?}"/* - uses: actions/checkout@v4 + id: checkout-retry if: steps.checkout.outcome == 'failure' + continue-on-error: true + timeout-minutes: 5 + with: + fetch-depth: 1 + + # Attempt 2 has failed outright before, not only stalled: one more wipe and one last try + - name: Reset workspace before last checkout attempt + if: steps.checkout.outcome == 'failure' && steps.checkout-retry.outcome == 'failure' + run: | + shopt -s dotglob + rm -rf "${GITHUB_WORKSPACE:?}"/* + + - uses: actions/checkout@v4 + if: steps.checkout.outcome == 'failure' && steps.checkout-retry.outcome == 'failure' with: fetch-depth: 1 @@ -63,15 +78,6 @@ jobs: APP_ENV: staging steps: - # A full-history checkout plus node_modules and a restored public/ do not fit beside the preinstalled toolchains: a - # checkout on a full disk dies with "unable to write new index file". The local action cannot be used before checkout. - - name: Free up disk space - run: | - df -h / - sudo rm -rf /opt/hostedtoolcache /usr/share/dotnet /usr/local/lib/android /usr/share/swift /usr/local/julia* \ - /opt/pipx /usr/lib/mono /opt/google/chrome /opt/microsoft /usr/local/lib/node_modules /usr/local/share/powershell - df -h / - # fetch-depth: 0 is required by gatsby-transformer-gitinfo, which runs # `git log -n 1 -- ` on every content file to populate # gitLogLatestDate (the "last updated" date shown on tutorial pages). @@ -100,7 +106,23 @@ jobs: rm -rf "${GITHUB_WORKSPACE:?}"/* - uses: actions/checkout@v4 + id: checkout-retry if: steps.checkout.outcome == 'failure' + continue-on-error: true + timeout-minutes: 5 + with: + fetch-depth: "0" + filter: blob:none + + # Attempt 2 has failed outright before, not only stalled: one more wipe and one last try + - name: Reset workspace before last checkout attempt + if: steps.checkout.outcome == 'failure' && steps.checkout-retry.outcome == 'failure' + run: | + shopt -s dotglob + rm -rf "${GITHUB_WORKSPACE:?}"/* + + - uses: actions/checkout@v4 + if: steps.checkout.outcome == 'failure' && steps.checkout-retry.outcome == 'failure' with: fetch-depth: "0" filter: blob:none diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 956cac59aa..037a7a6422 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -40,7 +40,22 @@ jobs: rm -rf "${GITHUB_WORKSPACE:?}"/* - uses: actions/checkout@v4 + id: checkout-retry if: steps.checkout.outcome == 'failure' + continue-on-error: true + timeout-minutes: 5 + with: + fetch-depth: 1 + + # Attempt 2 has failed outright before, not only stalled: one more wipe and one last try + - name: Reset workspace before last checkout attempt + if: steps.checkout.outcome == 'failure' && steps.checkout-retry.outcome == 'failure' + run: | + shopt -s dotglob + rm -rf "${GITHUB_WORKSPACE:?}"/* + + - uses: actions/checkout@v4 + if: steps.checkout.outcome == 'failure' && steps.checkout-retry.outcome == 'failure' with: fetch-depth: 1 @@ -63,15 +78,6 @@ jobs: BRANCH_NAME: ${{ github.ref_name }} steps: - # A full-history checkout plus node_modules and a restored public/ do not fit beside the preinstalled toolchains: a - # checkout on a full disk dies with "unable to write new index file". The local action cannot be used before checkout. - - name: Free up disk space - run: | - df -h / - sudo rm -rf /opt/hostedtoolcache /usr/share/dotnet /usr/local/lib/android /usr/share/swift /usr/local/julia* \ - /opt/pipx /usr/lib/mono /opt/google/chrome /opt/microsoft /usr/local/lib/node_modules /usr/local/share/powershell - df -h / - - name: Find PR Preview Comment if: github.event_name == 'pull_request' @@ -112,7 +118,22 @@ jobs: rm -rf "${GITHUB_WORKSPACE:?}"/* - uses: actions/checkout@v4 + id: checkout-retry if: steps.checkout.outcome == 'failure' + continue-on-error: true + timeout-minutes: 5 + with: + fetch-depth: 1 + + # Attempt 2 has failed outright before, not only stalled: one more wipe and one last try + - name: Reset workspace before last checkout attempt + if: steps.checkout.outcome == 'failure' && steps.checkout-retry.outcome == 'failure' + run: | + shopt -s dotglob + rm -rf "${GITHUB_WORKSPACE:?}"/* + + - uses: actions/checkout@v4 + if: steps.checkout.outcome == 'failure' && steps.checkout-retry.outcome == 'failure' with: fetch-depth: 1 From 4fe9c4caff0ba1da3229438de1bba52131183184 Mon Sep 17 00:00:00 2001 From: Matteo Marsala Date: Mon, 31 Aug 2026 09:12:01 +0200 Subject: [PATCH 08/19] ci: give Gatsby every vCPU on staging --- .github/workflows/deploy-staging.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml index be19df3c28..f05980a790 100644 --- a/.github/workflows/deploy-staging.yml +++ b/.github/workflows/deploy-staging.yml @@ -247,8 +247,17 @@ jobs: - run: npm install --prefer-offline --no-audit --fund=false + # nproc and free tell us whether logical_cores actually doubled the workers, and how much headroom they have + - name: Runner capacity + run: | + echo "vCPU: $(nproc)" + free -g + - name: Build run: npm run build + env: + # Gatsby defaults to physical cores, which is half the vCPUs of a runner + GATSBY_CPU_COUNT: logical_cores - name: Clean up node_modules # Just to save space run: rm -rf node_modules From 89bad45e58d6cb73291f2b7b365542412cf15ba4 Mon Sep 17 00:00:00 2001 From: Matteo Marsala Date: Mon, 31 Aug 2026 09:59:55 +0200 Subject: [PATCH 09/19] ci: give Gatsby every vCPU in production too --- .github/workflows/deploy-production.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/deploy-production.yml b/.github/workflows/deploy-production.yml index c532befd64..50529ac34d 100644 --- a/.github/workflows/deploy-production.yml +++ b/.github/workflows/deploy-production.yml @@ -249,6 +249,9 @@ jobs: - name: Build run: npm run build + env: + # Gatsby defaults to physical cores, which is half the vCPUs of a runner + GATSBY_CPU_COUNT: logical_cores # A warm public/ is worth 38 minutes of sharp, and costs ~4 GB of quota: main writes it, every other branch only reads - name: Save Gatsby main cache From 51d27999e3d2b2cbf1121674dda7eb44735898d0 Mon Sep 17 00:00:00 2001 From: Matteo Marsala Date: Mon, 31 Aug 2026 10:25:19 +0200 Subject: [PATCH 10/19] Clean up old branches monthly (#3004) --- .github/workflows/stale-branch-cleanup.yml | 270 +++++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100644 .github/workflows/stale-branch-cleanup.yml diff --git a/.github/workflows/stale-branch-cleanup.yml b/.github/workflows/stale-branch-cleanup.yml new file mode 100644 index 0000000000..f77f504df2 --- /dev/null +++ b/.github/workflows/stale-branch-cleanup.yml @@ -0,0 +1,270 @@ +name: Stale Branch Cleanup + +on: + schedule: + # Runs at 03:00 UTC every Monday + - cron: '0 3 * * 1' + workflow_dispatch: + inputs: + dry_run: + description: 'Only report what would happen, without commenting, closing or deleting.' + required: false + default: true + type: boolean + days_threshold: + description: 'Treat a branch as stale when it has had no commits and no pushes for this many days.' + required: false + default: '365' + type: string + +permissions: + contents: write + pull-requests: write + issues: write + +jobs: + cleanup: + name: Remind on stale pull requests, delete abandoned branches + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Process stale branches + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO: ${{ github.repository }} + DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} + # For scheduled runs the inputs are empty, so fall back to defaults. + DRY_RUN: ${{ github.event.inputs.dry_run || 'false' }} + DAYS_THRESHOLD: ${{ github.event.inputs.days_threshold || '365' }} + # A stale pull request gets this many reminders, one per run, before it is closed. + MAX_REMINDERS: '3' + REMINDER_INTERVAL_DAYS: '7' + # Branches and pull requests carrying this label are never touched. + EXEMPT_LABEL: 'keep-open' + run: | + set -euo pipefail + + THRESHOLD_SECONDS=$(( DAYS_THRESHOLD * 24 * 60 * 60 )) + # Half a day of slack so a weekly cron is never skipped for firing a few minutes early. + REMINDER_SECONDS=$(( REMINDER_INTERVAL_DAYS * 24 * 60 * 60 - 43200 )) + NOW=$(date +%s) + + REMINDER_MARKER='' + CLOSED_MARKER='' + + echo "Repository: $REPO" + echo "Default branch: $DEFAULT_BRANCH" + echo "Stale after: $DAYS_THRESHOLD days with no commits and no pushes" + echo "Reminders: $MAX_REMINDERS, one every $REMINDER_INTERVAL_DAYS days" + echo "Dry run: $DRY_RUN" + echo "----------------------------------------" + + # Open pull requests whose head branch lives in this repository. Pull requests from + # forks are out of scope: their branch is not ours to delete. + gh pr list --repo "$REPO" --state open --limit 500 \ + --json number,headRefName,author,isCrossRepository,labels,createdAt \ + --jq '.[] | select(.isCrossRepository == false) + | [.headRefName, .number, .author.login, .createdAt[0:10], + ([.labels[].name] | join(","))] | @tsv' > /tmp/open_prs.tsv + + # Deleting the base branch of an open pull request closes it, so those are protected + # too, even when the base branch itself is old. Fork pull requests count here. + gh pr list --repo "$REPO" --state open --limit 500 \ + --json baseRefName --jq '.[].baseRefName' | sort -u > /tmp/base_branches.txt + + # A branch can carry old commits and still be new: it may have been cut from an old + # commit, or had old history force-pushed onto it yesterday. The tip commit date on + # its own would call that stale, so pair it with the repository activity log, which + # records when each ref was really created or pushed to. If this call fails the job + # fails with it, on purpose: better a red run than deleting branches unguarded. + ACTIVITY_QUERY='per_page=100' + if [ "$DAYS_THRESHOLD" -le 365 ]; then + ACTIVITY_QUERY="$ACTIVITY_QUERY&time_period=year" + fi + gh api "repos/$REPO/activity?$ACTIVITY_QUERY" --paginate \ + --jq '.[] | select(.activity_type == "push" or .activity_type == "force_push" + or .activity_type == "branch_creation") + | select(.ref | startswith("refs/heads/")) + | [(.timestamp | fromdateiso8601), (.ref | sub("^refs/heads/"; ""))] | @tsv' \ + | awk -F'\t' '$1 > seen[$2] { seen[$2] = $1 } + END { for (b in seen) print seen[b] "\t" b }' > /tmp/branch_activity.tsv + + echo "Open pull requests from this repository: $(wc -l < /tmp/open_prs.tsv)" + echo "Branches used as a base by an open pull request: $(wc -l < /tmp/base_branches.txt)" + echo "Branches created or pushed to within the activity window: $(wc -l < /tmp/branch_activity.tsv)" + echo "----------------------------------------" + + PROTECTED_REGEX="^(${DEFAULT_BRANCH}|main|master|develop|staging|production|gh-pages)$" + + reminded=0 + closed=0 + deleted=0 + waiting=0 + skipped=0 + + while IFS=$'\t' read -r commit_ts branch_ref; do + branch="${branch_ref#origin/}" + + # Skip the HEAD pointer entry and empty lines. + if [ -z "$branch" ] || [ "$branch" = "HEAD" ]; then + continue + fi + + if echo "$branch" | grep -Eq "$PROTECTED_REGEX"; then + skipped=$((skipped + 1)) + continue + fi + + if [ $(( NOW - commit_ts )) -lt "$THRESHOLD_SECONDS" ]; then + skipped=$((skipped + 1)) + continue + fi + + # Old commits are not enough on their own: the ref must also have been left alone. + activity_ts=$(awk -F'\t' -v b="$branch" '$2 == b { print $1; exit }' /tmp/branch_activity.tsv) + if [ -n "$activity_ts" ] && [ $(( NOW - activity_ts )) -lt "$THRESHOLD_SECONDS" ]; then + echo "SKIP (old commits, but created or pushed on $(date -u -d "@$activity_ts" '+%Y-%m-%d')): $branch" + skipped=$((skipped + 1)) + continue + fi + + if grep -qxF "$branch" /tmp/base_branches.txt; then + echo "SKIP (base branch of an open pull request): $branch" + skipped=$((skipped + 1)) + continue + fi + + last_commit_date=$(date -u -d "@$commit_ts" '+%Y-%m-%d') + stale_days=$(( (NOW - commit_ts) / 86400 )) + + pr_row=$(awk -F'\t' -v b="$branch" '$1 == b { print; exit }' /tmp/open_prs.tsv) + + # No open pull request: nothing to discuss, the branch just goes. + if [ -z "$pr_row" ]; then + if [ "$DRY_RUN" = "true" ]; then + echo "WOULD DELETE branch (no open pull request): $branch (last commit: $last_commit_date)" + else + echo "DELETING branch (no open pull request): $branch (last commit: $last_commit_date)" + if ! git push origin --delete "$branch"; then + echo " WARNING: could not delete $branch, leaving it in place" + continue + fi + fi + deleted=$((deleted + 1)) + continue + fi + + IFS=$'\t' read -r _ pr_number pr_author pr_created pr_labels <<< "$pr_row" + + if echo ",$pr_labels," | grep -qF ",$EXEMPT_LABEL,"; then + echo "SKIP (labelled $EXEMPT_LABEL): PR #$pr_number <- $branch" + skipped=$((skipped + 1)) + continue + fi + + # Count the reminders we already posted. Only those newer than the last commit + # count, so pushing to the branch restarts the cycle from scratch. + reminder_count=0 + last_reminder_ts=0 + while read -r created_at; do + if [ -z "$created_at" ]; then + continue + fi + reminder_ts=$(date -u -d "$created_at" +%s) + if [ "$reminder_ts" -gt "$commit_ts" ]; then + reminder_count=$((reminder_count + 1)) + if [ "$reminder_ts" -gt "$last_reminder_ts" ]; then + last_reminder_ts=$reminder_ts + fi + fi + done < <(gh api --paginate "repos/$REPO/issues/$pr_number/comments" \ + --jq ".[] | select(.body | contains(\"$REMINDER_MARKER\")) | .created_at" \ + < /dev/null || true) + + # Nothing is due yet if the previous reminder is younger than the interval. + if [ "$reminder_count" -gt 0 ] && \ + [ $(( NOW - last_reminder_ts )) -lt "$REMINDER_SECONDS" ]; then + echo "WAIT (reminder $reminder_count/$MAX_REMINDERS sent $(date -u -d "@$last_reminder_ts" '+%Y-%m-%d')): PR #$pr_number <- $branch" + waiting=$((waiting + 1)) + continue + fi + + if [ "$reminder_count" -lt "$MAX_REMINDERS" ]; then + next=$((reminder_count + 1)) + deletion_date=$(date -u -d "+$(( (MAX_REMINDERS - next + 1) * REMINDER_INTERVAL_DAYS )) days" '+%Y-%m-%d') + + body=$(cat <> "$GITHUB_STEP_SUMMARY" + + echo "Reminders sent: $reminded | Pull requests closed: $closed | Branches deleted: $deleted | Waiting: $waiting | Untouched: $skipped" From 7d2b74f2996e37bfde0250f698d8ad8be40f4733 Mon Sep 17 00:00:00 2001 From: Matteo Marsala Date: Tue, 1 Sep 2026 09:14:13 +0200 Subject: [PATCH 11/19] improve note --- .../styles/common-style.css | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/scripts/datasheet-rendering/styles/common-style.css b/scripts/datasheet-rendering/styles/common-style.css index 84e8db2eca..67d059cf71 100644 --- a/scripts/datasheet-rendering/styles/common-style.css +++ b/scripts/datasheet-rendering/styles/common-style.css @@ -296,4 +296,20 @@ h1::after, h2::after, h3::after, h4::after { display: block; height: 300px; margin-bottom: -300px; -} \ No newline at end of file +} + +/* Notes written as plain markdown blockquotes, so a datasheet needs no inline HTML for them */ +blockquote { + background-color: rgba(0, 170, 228, 0.2); + border-left: 6px solid rgba(0, 120, 180, 1); + margin: 20px 0; + padding: 15px; +} + +blockquote > :first-child { + margin-block-start: 0; +} + +blockquote > :last-child { + margin-block-end: 0; +} From 8e8f2fec59f23e6a8bf4506e5978e278f050ba82 Mon Sep 17 00:00:00 2001 From: Matteo Marsala Date: Tue, 1 Sep 2026 09:17:18 +0200 Subject: [PATCH 12/19] improve note --- .../hardware/02.uno/boards/uno-q/datasheet/it-datasheet.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/content/hardware/02.uno/boards/uno-q/datasheet/it-datasheet.md b/content/hardware/02.uno/boards/uno-q/datasheet/it-datasheet.md index 28708c68c7..750299f2b4 100644 --- a/content/hardware/02.uno/boards/uno-q/datasheet/it-datasheet.md +++ b/content/hardware/02.uno/boards/uno-q/datasheet/it-datasheet.md @@ -997,9 +997,7 @@ Le guide d’utilisation des dispositifs pour réseaux locaux doit inclure des i (i) les dispositifs fonctionnant dans la bande 5 150-5 250 MHz sont réservés uniquement pour une utilisation à l’intérieur afin de réduire les risques de brouillage préjudiciable aux systèmes de satellites mobiles utilisant les mêmes canaux ; -
- Note: For 5GHz and/or when co-located with 5 GHz transmitters, the following statements should be provided in the user information. -
+> **Note:** For 5GHz and/or when co-located with 5 GHz transmitters, the following statements should be provided in the user information. **Radiation Exposure Statement** From e4e66e4089aab62b25768de5695e1db1fdd1b9b2 Mon Sep 17 00:00:00 2001 From: Matteo Marsala Date: Tue, 1 Sep 2026 09:33:19 +0200 Subject: [PATCH 13/19] Update notes --- .../02.uno/boards/uno-q/datasheet/it-datasheet.md | 1 + scripts/datasheet-rendering/package-lock.json | 8 ++++---- scripts/datasheet-rendering/package.json | 2 +- scripts/datasheet-rendering/styles/common-style.css | 11 +++++++++++ 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/content/hardware/02.uno/boards/uno-q/datasheet/it-datasheet.md b/content/hardware/02.uno/boards/uno-q/datasheet/it-datasheet.md index 750299f2b4..72c164819f 100644 --- a/content/hardware/02.uno/boards/uno-q/datasheet/it-datasheet.md +++ b/content/hardware/02.uno/boards/uno-q/datasheet/it-datasheet.md @@ -997,6 +997,7 @@ Le guide d’utilisation des dispositifs pour réseaux locaux doit inclure des i (i) les dispositifs fonctionnant dans la bande 5 150-5 250 MHz sont réservés uniquement pour une utilisation à l’intérieur afin de réduire les risques de brouillage préjudiciable aux systèmes de satellites mobiles utilisant les mêmes canaux ; +> [!NOTE] > **Note:** For 5GHz and/or when co-located with 5 GHz transmitters, the following statements should be provided in the user information. **Radiation Exposure Statement** diff --git a/scripts/datasheet-rendering/package-lock.json b/scripts/datasheet-rendering/package-lock.json index 0da7511b4f..16947aeeb4 100644 --- a/scripts/datasheet-rendering/package-lock.json +++ b/scripts/datasheet-rendering/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "datasheet-renderer": "git+https://github.com/arduino/datasheet-renderer.git#e36fd5549e1a351c0d85843109817653c8dce15b" + "datasheet-renderer": "git+https://github.com/arduino/datasheet-renderer.git#97e240e01be744e5e34ea13613f0c69c48100cd9" } }, "node_modules/@babel/code-frame": { @@ -443,9 +443,9 @@ } }, "node_modules/datasheet-renderer": { - "version": "1.0.6", - "resolved": "git+ssh://git@github.com/arduino/datasheet-renderer.git#e36fd5549e1a351c0d85843109817653c8dce15b", - "integrity": "sha512-7SLMplDVUb/KfP46U9CiPMShRQ/gkKWfknLJ8h4DANOV2T3jBQfVLq/4JMGTxnRB1zVk2o1iyEHT/lLaLnMzVQ==", + "version": "1.0.7", + "resolved": "git+ssh://git@github.com/arduino/datasheet-renderer.git#97e240e01be744e5e34ea13613f0c69c48100cd9", + "integrity": "sha512-mvjfLs19L6LHM/+Ll6JbO+QChfbj3IRv1rq0ObgaEGC5rdghwhuFwAfNDjWF+tyqIhZHp8mChZo6GXgZNsGbpQ==", "license": "ISC", "dependencies": { "express": "^4.18.2", diff --git a/scripts/datasheet-rendering/package.json b/scripts/datasheet-rendering/package.json index 2df449b7ce..94a448fd06 100644 --- a/scripts/datasheet-rendering/package.json +++ b/scripts/datasheet-rendering/package.json @@ -10,6 +10,6 @@ "author": "Sebastian Romero", "license": "ISC", "dependencies": { - "datasheet-renderer": "git+https://github.com/arduino/datasheet-renderer.git#e36fd5549e1a351c0d85843109817653c8dce15b" + "datasheet-renderer": "git+https://github.com/arduino/datasheet-renderer.git#97e240e01be744e5e34ea13613f0c69c48100cd9" } } diff --git a/scripts/datasheet-rendering/styles/common-style.css b/scripts/datasheet-rendering/styles/common-style.css index 67d059cf71..7acdb35d24 100644 --- a/scripts/datasheet-rendering/styles/common-style.css +++ b/scripts/datasheet-rendering/styles/common-style.css @@ -313,3 +313,14 @@ blockquote > :first-child { blockquote > :last-child { margin-block-end: 0; } + +/* Severities from a [!WARNING] or [!CAUTION] marker, same colours the inline HTML notes used */ +blockquote.warning { + background-color: #FFFFE0; + border-left-color: #FFD700; +} + +blockquote.caution { + background-color: #FFCCCC; + border-left-color: #FF0000; +} From 3913ee6b1b2950ff634752f7fa53089ccfb63f1f Mon Sep 17 00:00:00 2001 From: Matteo Marsala Date: Tue, 1 Sep 2026 10:29:14 +0200 Subject: [PATCH 14/19] bump actions --- .github/actions/cloudflare-upload/action.yml | 78 ------------------- .../actions/generate-datasheets/action.yml | 6 +- .github/actions/image-size-check/action.yml | 4 +- .github/actions/sync-s3/action.yml | 2 +- .github/workflows/deploy-production.yml | 26 +++---- .github/workflows/deploy-staging.yml | 22 +++--- .github/workflows/docs-auto-bump.yml | 6 +- .github/workflows/image-size-check.yml | 2 +- .github/workflows/preview.yml | 30 +++---- .github/workflows/render-datasheets.yaml | 4 +- .github/workflows/stale-branch-cleanup.yml | 2 +- .github/workflows/sync-private-mirror.yml | 2 +- .github/workflows/sync-pull-request.yml | 2 +- .github/workflows/workflow-validate.yaml | 4 +- 14 files changed, 57 insertions(+), 133 deletions(-) delete mode 100644 .github/actions/cloudflare-upload/action.yml diff --git a/.github/actions/cloudflare-upload/action.yml b/.github/actions/cloudflare-upload/action.yml deleted file mode 100644 index ceac755bb3..0000000000 --- a/.github/actions/cloudflare-upload/action.yml +++ /dev/null @@ -1,78 +0,0 @@ -name: "Upload an app to Cloudflare Pages" -description: "Manually deploy an app to cloudflare pages" -inputs: - upload-dir: - description: "The name of the app to build and export" - required: true - - project-name: - description: "The name of the project to upload to" - required: true - - cloudflare-account: - description: "The Cloudflare account ID" - required: true - - cloudflare-api-token: - description: "The Cloudflare API token" - required: true - -runs: - using: composite - steps: - - name: Find PR Preview Comment - if: github.event_name == 'pull_request' - uses: peter-evans/find-comment@v1 - id: deploy-preview-comment - with: - issue-number: ${{ github.event.pull_request.number }} - comment-author: "github-actions[bot]" - body-includes: ${{ inputs.project-name }} - - - name: Update Comment if exists - if: github.event_name == 'pull_request' && steps.deploy-preview-comment.outputs.comment-id != 0 - uses: peter-evans/create-or-update-comment@v1.4.5 - with: - comment-id: ${{ steps.deploy-preview-comment.outputs.comment-id }} - edit-mode: replace - body: | - ### ${{ inputs.project-name }} - Waiting for deployment to complete... - - - id: branch-name - uses: tj-actions/branch-names@v5 - - - id: format-branch - shell: bash - run: format=$(echo ${{ steps.branch-name.outputs.current_branch }} | tr / -) && echo "::set-output name=branch::$(echo "${format:0:28}")" - - - name: deploy-cloudflare - uses: cloudflare/pages-action@v1 - id: deploy-cloudflare - with: - apiToken: ${{ inputs.cloudflare-api-token }} - accountId: ${{ inputs.cloudflare-account }} - projectName: ${{ inputs.project-name }} - directory: ${{ inputs.upload-dir }} - branch: ${{ steps.format-branch.outputs.branch }} - - - name: Create PR Preview Comment - if: github.event_name == 'pull_request' && steps.deploy-preview-comment.outputs.comment-id == 0 - uses: peter-evans/create-or-update-comment@v1.4.5 - with: - issue-number: ${{ github.event.pull_request.number }} - body: | - ### ${{ inputs.project-name }} - 🚀 Preview this PR: ${{ steps.deploy-cloudflare.outputs.url }} - 📍 Commit SHA: ${{ github.sha }} - - - name: Update PR Preview Comment - if: github.event_name == 'pull_request' && steps.deploy-preview-comment.outputs.comment-id != 0 - uses: peter-evans/create-or-update-comment@v1.4.5 - with: - comment-id: ${{ steps.deploy-preview-comment.outputs.comment-id }} - edit-mode: replace - body: | - ### ${{ inputs.project-name }} - 🚀 Preview this PR: ${{ steps.deploy-cloudflare.outputs.url }} - 📍 Commit SHA: ${{ github.sha }} diff --git a/.github/actions/generate-datasheets/action.yml b/.github/actions/generate-datasheets/action.yml index 908c4f6d10..2ad69223af 100644 --- a/.github/actions/generate-datasheets/action.yml +++ b/.github/actions/generate-datasheets/action.yml @@ -12,13 +12,13 @@ inputs: runs: using: composite steps: - - uses: actions/cache@v4 + - uses: actions/cache@v5 id: cache with: path: ${{ inputs.datasheets-path }} key: ${{ runner.os }}-datasheets-${{ hashFiles('**/*datasheet.md') }} - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v5 if: steps.cache.outputs.cache-hit != 'true' with: node-version: 18 @@ -36,7 +36,7 @@ runs: shell: bash - name: Export artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: ${{ inputs.artifact-name }} path: ${{ inputs.datasheets-path }} diff --git a/.github/actions/image-size-check/action.yml b/.github/actions/image-size-check/action.yml index cba3fd7795..dd6d7f039a 100644 --- a/.github/actions/image-size-check/action.yml +++ b/.github/actions/image-size-check/action.yml @@ -5,7 +5,9 @@ runs: steps: - name: Get changed files id: changed-files - uses: tj-actions/changed-files@v44 + # Pinned to a commit SHA rather than a tag: this action had all of its tags + # rewritten to point at malicious code in the March 2025 compromise (CVE-2025-30066). + uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96 # v47.0.6 with: separator: '\n' files_ignore_pattern: | diff --git a/.github/actions/sync-s3/action.yml b/.github/actions/sync-s3/action.yml index 7f2a7524ac..4493a7a60a 100644 --- a/.github/actions/sync-s3/action.yml +++ b/.github/actions/sync-s3/action.yml @@ -11,7 +11,7 @@ runs: using: composite steps: - name: Configure AWS credentials from Staging account - uses: aws-actions/configure-aws-credentials@v4 + uses: aws-actions/configure-aws-credentials@v6 with: role-to-assume: ${{ inputs.role-to-assume }} aws-region: us-east-1 diff --git a/.github/workflows/deploy-production.yml b/.github/workflows/deploy-production.yml index 50529ac34d..2d7a6ade82 100644 --- a/.github/workflows/deploy-production.yml +++ b/.github/workflows/deploy-production.yml @@ -26,7 +26,7 @@ jobs: # Checkout stalls intermittently on this repo (~9 GB): on 2026-08-25, 4 of # 8 checkouts hung with no progress at all. Bound the attempt and retry # once, instead of letting a stalled transfer run into the 6h default. - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 id: checkout continue-on-error: true timeout-minutes: 5 @@ -42,7 +42,7 @@ jobs: shopt -s dotglob rm -rf "${GITHUB_WORKSPACE:?}"/* - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 id: checkout-retry if: steps.checkout.outcome == 'failure' continue-on-error: true @@ -57,7 +57,7 @@ jobs: shopt -s dotglob rm -rf "${GITHUB_WORKSPACE:?}"/* - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 if: steps.checkout.outcome == 'failure' && steps.checkout-retry.outcome == 'failure' with: fetch-depth: 1 @@ -88,7 +88,7 @@ jobs: # Checkout stalls intermittently on this repo (~9 GB): on 2026-08-25, 4 of # 8 checkouts hung with no progress at all. Bound the attempt and retry # once, instead of letting a stalled transfer run into the 6h default. - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 id: checkout continue-on-error: true timeout-minutes: 5 @@ -105,7 +105,7 @@ jobs: shopt -s dotglob rm -rf "${GITHUB_WORKSPACE:?}"/* - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 id: checkout-retry if: steps.checkout.outcome == 'failure' continue-on-error: true @@ -121,20 +121,20 @@ jobs: shopt -s dotglob rm -rf "${GITHUB_WORKSPACE:?}"/* - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 if: steps.checkout.outcome == 'failure' && steps.checkout-retry.outcome == 'failure' with: fetch-depth: "0" filter: blob:none - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v5 with: node-version: 18 cache: "npm" cache-dependency-path: "package-lock.json" - name: Retrieve Datasheets - uses: actions/download-artifact@v4 # Retrieve the datasheets generated in the previous job + uses: actions/download-artifact@v8 # Retrieve the datasheets generated in the previous job with: name: datasheets path: static/resources/datasheets @@ -202,7 +202,7 @@ jobs: run: echo "hash=$(find content -type f \( -name '*.jpg' -o -name '*.jpeg' -o -name '*.png' \) -size +2M -printf '%p %s\n' | sort | sha256sum | cut -c1-40)" >> "$GITHUB_OUTPUT" - name: Compressed images cache - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: /tmp/compressed-images.tar key: ${{ runner.os }}-compressed-images-${{ steps.images-key.outputs.hash }} @@ -228,7 +228,7 @@ jobs: cat /tmp/big-jpg.lst /tmp/big-png.lst | tar --null -cf /tmp/compressed-images.tar -T - - name: Gatsby main cache - uses: actions/cache/restore@v4 + uses: actions/cache/restore@v5 id: gatsby-cache-folder with: path: .cache @@ -237,7 +237,7 @@ jobs: ${{ runner.os }}-cache-gatsby-main - name: Gatsby Public Folder cache - uses: actions/cache/restore@v4 + uses: actions/cache/restore@v5 id: gatsby-public-folder with: path: public/ @@ -255,13 +255,13 @@ jobs: # A warm public/ is worth 38 minutes of sharp, and costs ~4 GB of quota: main writes it, every other branch only reads - name: Save Gatsby main cache - uses: actions/cache/save@v4 + uses: actions/cache/save@v5 with: path: .cache key: ${{ runner.os }}-cache-gatsby-main-${{ github.run_id }} - name: Save Gatsby Public Folder cache - uses: actions/cache/save@v4 + uses: actions/cache/save@v5 with: path: public/ key: ${{ runner.os }}-public-gatsby-main-${{ github.run_id }} diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml index f05980a790..63bce9d8ee 100644 --- a/.github/workflows/deploy-staging.yml +++ b/.github/workflows/deploy-staging.yml @@ -26,7 +26,7 @@ jobs: # Checkout stalls intermittently on this repo (~9 GB): on 2026-08-25, 4 of # 8 checkouts hung with no progress at all. Bound the attempt and retry # once, instead of letting a stalled transfer run into the 6h default. - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 id: checkout continue-on-error: true timeout-minutes: 5 @@ -42,7 +42,7 @@ jobs: shopt -s dotglob rm -rf "${GITHUB_WORKSPACE:?}"/* - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 id: checkout-retry if: steps.checkout.outcome == 'failure' continue-on-error: true @@ -57,7 +57,7 @@ jobs: shopt -s dotglob rm -rf "${GITHUB_WORKSPACE:?}"/* - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 if: steps.checkout.outcome == 'failure' && steps.checkout-retry.outcome == 'failure' with: fetch-depth: 1 @@ -88,7 +88,7 @@ jobs: # Checkout stalls intermittently on this repo (~9 GB): on 2026-08-25, 4 of # 8 checkouts hung with no progress at all. Bound the attempt and retry # once, instead of letting a stalled transfer run into the 6h default. - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 id: checkout continue-on-error: true timeout-minutes: 5 @@ -105,7 +105,7 @@ jobs: shopt -s dotglob rm -rf "${GITHUB_WORKSPACE:?}"/* - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 id: checkout-retry if: steps.checkout.outcome == 'failure' continue-on-error: true @@ -121,20 +121,20 @@ jobs: shopt -s dotglob rm -rf "${GITHUB_WORKSPACE:?}"/* - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 if: steps.checkout.outcome == 'failure' && steps.checkout-retry.outcome == 'failure' with: fetch-depth: "0" filter: blob:none - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v5 with: node-version: 18 cache: "npm" cache-dependency-path: "package-lock.json" - name: Retrieve Datasheets - uses: actions/download-artifact@v4 # Retrieve the datasheets generated in the previous job + uses: actions/download-artifact@v8 # Retrieve the datasheets generated in the previous job with: name: datasheets path: static/resources/datasheets @@ -202,7 +202,7 @@ jobs: run: echo "hash=$(find content -type f \( -name '*.jpg' -o -name '*.jpeg' -o -name '*.png' \) -size +2M -printf '%p %s\n' | sort | sha256sum | cut -c1-40)" >> "$GITHUB_OUTPUT" - name: Compressed images cache - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: /tmp/compressed-images.tar key: ${{ runner.os }}-compressed-images-${{ steps.images-key.outputs.hash }} @@ -228,7 +228,7 @@ jobs: cat /tmp/big-jpg.lst /tmp/big-png.lst | tar --null -cf /tmp/compressed-images.tar -T - - name: Gatsby main cache - uses: actions/cache/restore@v4 + uses: actions/cache/restore@v5 id: gatsby-cache-folder with: path: .cache @@ -237,7 +237,7 @@ jobs: ${{ runner.os }}-cache-gatsby-main - name: Gatsby Public Folder cache - uses: actions/cache/restore@v4 + uses: actions/cache/restore@v5 id: gatsby-public-folder with: path: public/ diff --git a/.github/workflows/docs-auto-bump.yml b/.github/workflows/docs-auto-bump.yml index d2c222c639..009f7f5184 100644 --- a/.github/workflows/docs-auto-bump.yml +++ b/.github/workflows/docs-auto-bump.yml @@ -15,10 +15,10 @@ jobs: REPO_ACCESS_TOKEN: ${{ secrets.REPO_ACCESS_TOKEN }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v5 with: node-version: 20 cache: 'npm' @@ -54,7 +54,7 @@ jobs: run: npm install --ignore-scripts - name: Create Pull Request - uses: peter-evans/create-pull-request@v6 + uses: peter-evans/create-pull-request@v8 with: token: ${{ secrets.BUMP_DOCS_TOKEN }} commit-message: 'Bump @arduino/docs.arduino.cc to v${{ steps.get_version.outputs.version }}' diff --git a/.github/workflows/image-size-check.yml b/.github/workflows/image-size-check.yml index e58ea09d8e..473c60c324 100644 --- a/.github/workflows/image-size-check.yml +++ b/.github/workflows/image-size-check.yml @@ -13,7 +13,7 @@ jobs: # every historical version of the PDFs and ZIPs: those blobs are ~10GB of the # 10.4GB pack and they filled the runner disk, so the checkout never completed. - name: Checkout Repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 0 filter: blob:none diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 037a7a6422..165d1ad7b1 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -23,7 +23,7 @@ jobs: # Checkout stalls intermittently on this repo (~9 GB): on 2026-08-25, 4 of # 8 checkouts hung with no progress at all. Bound the attempt and retry # once, instead of letting a stalled transfer run into the 6h default. - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 id: checkout continue-on-error: true timeout-minutes: 5 @@ -39,7 +39,7 @@ jobs: shopt -s dotglob rm -rf "${GITHUB_WORKSPACE:?}"/* - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 id: checkout-retry if: steps.checkout.outcome == 'failure' continue-on-error: true @@ -54,7 +54,7 @@ jobs: shopt -s dotglob rm -rf "${GITHUB_WORKSPACE:?}"/* - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 if: steps.checkout.outcome == 'failure' && steps.checkout-retry.outcome == 'failure' with: fetch-depth: 1 @@ -81,7 +81,7 @@ jobs: - name: Find PR Preview Comment if: github.event_name == 'pull_request' - uses: peter-evans/find-comment@v1 + uses: peter-evans/find-comment@v4 id: deploy-preview-comment with: issue-number: ${{ github.event.pull_request.number }} @@ -90,7 +90,7 @@ jobs: - name: Update Comment if exists if: github.event_name == 'pull_request' && steps.deploy-preview-comment.outputs.comment-id != 0 - uses: peter-evans/create-or-update-comment@v1.4.5 + uses: peter-evans/create-or-update-comment@v5 with: comment-id: ${{ steps.deploy-preview-comment.outputs.comment-id }} edit-mode: replace @@ -101,7 +101,7 @@ jobs: # Checkout stalls intermittently on this repo (~9 GB): on 2026-08-25, 4 of # 8 checkouts hung with no progress at all. Bound the attempt and retry # once, instead of letting a stalled transfer run into the 6h default. - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 id: checkout continue-on-error: true timeout-minutes: 5 @@ -117,7 +117,7 @@ jobs: shopt -s dotglob rm -rf "${GITHUB_WORKSPACE:?}"/* - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 id: checkout-retry if: steps.checkout.outcome == 'failure' continue-on-error: true @@ -132,19 +132,19 @@ jobs: shopt -s dotglob rm -rf "${GITHUB_WORKSPACE:?}"/* - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 if: steps.checkout.outcome == 'failure' && steps.checkout-retry.outcome == 'failure' with: fetch-depth: 1 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v5 with: node-version: 18 cache: "npm" cache-dependency-path: "**/package-lock.json" - name: Retrieve Datasheets - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: datasheets path: static/resources/datasheets @@ -196,7 +196,7 @@ jobs: run: echo "hash=$(find content -type f \( -name '*.jpg' -o -name '*.jpeg' -o -name '*.png' \) -size +2M -printf '%p %s\n' | sort | sha256sum | cut -c1-40)" >> "$GITHUB_OUTPUT" - name: Compressed images cache - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: /tmp/compressed-images.tar key: ${{ runner.os }}-compressed-images-${{ steps.images-key.outputs.hash }} @@ -222,7 +222,7 @@ jobs: cat /tmp/big-jpg.lst /tmp/big-png.lst | tar --null -cf /tmp/compressed-images.tar -T - - name: Gatsby main cache - uses: actions/cache/restore@v4 + uses: actions/cache/restore@v5 id: gatsby-cache-folder with: path: .cache @@ -231,7 +231,7 @@ jobs: ${{ runner.os }}-cache-gatsby-main - name: Gatsby Public Folder - uses: actions/cache/restore@v4 + uses: actions/cache/restore@v5 id: gatsby-public-folder with: path: public/ @@ -278,7 +278,7 @@ jobs: - name: Create PR Preview Comment if: github.event_name == 'pull_request' && steps.deploy-preview-comment.outputs.comment-id == 0 - uses: peter-evans/create-or-update-comment@v1.4.5 + uses: peter-evans/create-or-update-comment@v5 with: issue-number: ${{ github.event.pull_request.number }} body: | @@ -288,7 +288,7 @@ jobs: - name: Update PR Preview Comment if: github.event_name == 'pull_request' && steps.deploy-preview-comment.outputs.comment-id != 0 - uses: peter-evans/create-or-update-comment@v1.4.5 + uses: peter-evans/create-or-update-comment@v5 with: comment-id: ${{ steps.deploy-preview-comment.outputs.comment-id }} edit-mode: replace diff --git a/.github/workflows/render-datasheets.yaml b/.github/workflows/render-datasheets.yaml index 2a26f81258..a4f9dabc2d 100644 --- a/.github/workflows/render-datasheets.yaml +++ b/.github/workflows/render-datasheets.yaml @@ -10,8 +10,8 @@ jobs: REPO_ACCESS_TOKEN: ${{ secrets.REPO_ACCESS_TOKEN }} steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@v5 + - uses: actions/setup-node@v5 with: node-version: 18 cache: "npm" diff --git a/.github/workflows/stale-branch-cleanup.yml b/.github/workflows/stale-branch-cleanup.yml index f77f504df2..61f73b7a5a 100644 --- a/.github/workflows/stale-branch-cleanup.yml +++ b/.github/workflows/stale-branch-cleanup.yml @@ -28,7 +28,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 0 diff --git a/.github/workflows/sync-private-mirror.yml b/.github/workflows/sync-private-mirror.yml index db17e618a2..a8c1715232 100644 --- a/.github/workflows/sync-private-mirror.yml +++ b/.github/workflows/sync-private-mirror.yml @@ -8,7 +8,7 @@ jobs: if: "github.repository == 'arduino/docs-content'" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v5 with: fetch-depth: "0" ref: "main" diff --git a/.github/workflows/sync-pull-request.yml b/.github/workflows/sync-pull-request.yml index 8fa8e66f6d..8efd48b012 100644 --- a/.github/workflows/sync-pull-request.yml +++ b/.github/workflows/sync-pull-request.yml @@ -7,7 +7,7 @@ jobs: if: "github.repository == 'arduino/docs-content-private'" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v5 with: fetch-depth: "0" diff --git a/.github/workflows/workflow-validate.yaml b/.github/workflows/workflow-validate.yaml index e72ff090f5..6f78d49ddb 100644 --- a/.github/workflows/workflow-validate.yaml +++ b/.github/workflows/workflow-validate.yaml @@ -14,7 +14,7 @@ jobs: name: Spell Check runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Run spell check run: | pip install codespell==2.3.0 @@ -30,7 +30,7 @@ jobs: node_version: [14] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Run linter run: | From bc4ac19aa2340217579dcd64f87f0958ea755194 Mon Sep 17 00:00:00 2001 From: Matteo Marsala Date: Tue, 1 Sep 2026 11:18:07 +0200 Subject: [PATCH 15/19] feat: bump node --- .github/actions/generate-datasheets/action.yml | 2 +- .github/workflows/deploy-production.yml | 14 +++++++------- .github/workflows/deploy-staging.yml | 10 +++++----- .github/workflows/docs-auto-bump.yml | 2 +- .github/workflows/preview.yml | 10 +++++----- .github/workflows/render-datasheets.yaml | 2 +- package.json | 4 ++-- 7 files changed, 22 insertions(+), 22 deletions(-) diff --git a/.github/actions/generate-datasheets/action.yml b/.github/actions/generate-datasheets/action.yml index 2ad69223af..60627bea9c 100644 --- a/.github/actions/generate-datasheets/action.yml +++ b/.github/actions/generate-datasheets/action.yml @@ -21,7 +21,7 @@ runs: - uses: actions/setup-node@v5 if: steps.cache.outputs.cache-hit != 'true' with: - node-version: 18 + node-version: 22 cache: "npm" cache-dependency-path: "package-lock.json" diff --git a/.github/workflows/deploy-production.yml b/.github/workflows/deploy-production.yml index 2d7a6ade82..d43decacbf 100644 --- a/.github/workflows/deploy-production.yml +++ b/.github/workflows/deploy-production.yml @@ -129,7 +129,7 @@ jobs: - uses: actions/setup-node@v5 with: - node-version: 18 + node-version: 22 cache: "npm" cache-dependency-path: "package-lock.json" @@ -232,18 +232,18 @@ jobs: id: gatsby-cache-folder with: path: .cache - key: ${{ runner.os }}-cache-gatsby-${{ github.ref_name }} + key: ${{ runner.os }}-cache-gatsby-node22-${{ github.ref_name }} restore-keys: | - ${{ runner.os }}-cache-gatsby-main + ${{ runner.os }}-cache-gatsby-node22-main - name: Gatsby Public Folder cache uses: actions/cache/restore@v5 id: gatsby-public-folder with: path: public/ - key: ${{ runner.os }}-public-gatsby-${{ github.ref_name }} + key: ${{ runner.os }}-public-gatsby-node22-${{ github.ref_name }} restore-keys: | - ${{ runner.os }}-public-gatsby-main + ${{ runner.os }}-public-gatsby-node22-main - run: npm install --prefer-offline --no-audit --fund=false @@ -258,13 +258,13 @@ jobs: uses: actions/cache/save@v5 with: path: .cache - key: ${{ runner.os }}-cache-gatsby-main-${{ github.run_id }} + key: ${{ runner.os }}-cache-gatsby-node22-main-${{ github.run_id }} - name: Save Gatsby Public Folder cache uses: actions/cache/save@v5 with: path: public/ - key: ${{ runner.os }}-public-gatsby-main-${{ github.run_id }} + key: ${{ runner.os }}-public-gatsby-node22-main-${{ github.run_id }} - name: Clean up node_modules # Just to save space run: rm -rf node_modules diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml index 63bce9d8ee..35dceb6340 100644 --- a/.github/workflows/deploy-staging.yml +++ b/.github/workflows/deploy-staging.yml @@ -129,7 +129,7 @@ jobs: - uses: actions/setup-node@v5 with: - node-version: 18 + node-version: 22 cache: "npm" cache-dependency-path: "package-lock.json" @@ -232,18 +232,18 @@ jobs: id: gatsby-cache-folder with: path: .cache - key: ${{ runner.os }}-cache-gatsby-${{ github.ref_name }} + key: ${{ runner.os }}-cache-gatsby-node22-${{ github.ref_name }} restore-keys: | - ${{ runner.os }}-cache-gatsby-main + ${{ runner.os }}-cache-gatsby-node22-main - name: Gatsby Public Folder cache uses: actions/cache/restore@v5 id: gatsby-public-folder with: path: public/ - key: ${{ runner.os }}-public-gatsby-${{ github.ref_name }} + key: ${{ runner.os }}-public-gatsby-node22-${{ github.ref_name }} restore-keys: | - ${{ runner.os }}-public-gatsby-main + ${{ runner.os }}-public-gatsby-node22-main - run: npm install --prefer-offline --no-audit --fund=false diff --git a/.github/workflows/docs-auto-bump.yml b/.github/workflows/docs-auto-bump.yml index 009f7f5184..5f54a859ed 100644 --- a/.github/workflows/docs-auto-bump.yml +++ b/.github/workflows/docs-auto-bump.yml @@ -20,7 +20,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v5 with: - node-version: 20 + node-version: 22 cache: 'npm' - name: Configure Git diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 165d1ad7b1..483fd69274 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -139,7 +139,7 @@ jobs: - uses: actions/setup-node@v5 with: - node-version: 18 + node-version: 22 cache: "npm" cache-dependency-path: "**/package-lock.json" @@ -226,18 +226,18 @@ jobs: id: gatsby-cache-folder with: path: .cache - key: ${{ runner.os }}-cache-gatsby-${{ github.ref_name }} + key: ${{ runner.os }}-cache-gatsby-node22-${{ github.ref_name }} restore-keys: | - ${{ runner.os }}-cache-gatsby-main + ${{ runner.os }}-cache-gatsby-node22-main - name: Gatsby Public Folder uses: actions/cache/restore@v5 id: gatsby-public-folder with: path: public/ - key: ${{ runner.os }}-public-gatsby-${{ github.ref_name }} + key: ${{ runner.os }}-public-gatsby-node22-${{ github.ref_name }} restore-keys: | - ${{ runner.os }}-public-gatsby-main + ${{ runner.os }}-public-gatsby-node22-main - run: npm install --prefer-offline --no-audit --fund=false - run: GATSBY_HF_CDN_URL="" npm run build diff --git a/.github/workflows/render-datasheets.yaml b/.github/workflows/render-datasheets.yaml index a4f9dabc2d..76951a6d20 100644 --- a/.github/workflows/render-datasheets.yaml +++ b/.github/workflows/render-datasheets.yaml @@ -13,7 +13,7 @@ jobs: - uses: actions/checkout@v5 - uses: actions/setup-node@v5 with: - node-version: 18 + node-version: 22 cache: "npm" cache-dependency-path: "**/package-lock.json" diff --git a/package.json b/package.json index 2c9eb2cc98..a1ff448be1 100644 --- a/package.json +++ b/package.json @@ -42,8 +42,8 @@ "npm": "^10.4.0" }, "volta": { - "node": "18.16.1", - "npm": "9.8.0" + "node": "22.22.3", + "npm": "10.9.8" }, "devDependencies": { "fast-glob": "^3.3.3", From 749fa9048293a18cd1b1d6ecf874f38d4bddb714 Mon Sep 17 00:00:00 2001 From: Matteo Marsala Date: Tue, 1 Sep 2026 12:49:56 +0200 Subject: [PATCH 16/19] 2.2.9 --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2dc09059e9..9df9536bb3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "hasInstallScript": true, "license": "ISC", "dependencies": { - "@arduino/docs-arduino-cc": "^2.2.9-alpha.2", + "@arduino/docs-arduino-cc": "^2.2.9", "gatsby": "^5.11.0", "gatsby-background-image": "^1.6.0", "gatsby-image": "^3.11.0", @@ -315,9 +315,9 @@ } }, "node_modules/@arduino/docs-arduino-cc": { - "version": "2.2.9-alpha.2", - "resolved": "https://npm.pkg.github.com/download/@arduino/docs-arduino-cc/2.2.9-alpha.2/19f482f564ab94f3e2a83cc1e4c6397311407c47", - "integrity": "sha512-qx3PpwK5z55S+5HY3Shr/lRTRjHoem5wdUMOKps5M8OdWyfmf6jBFvqZ+uSWT6dGUmC5oin1KqctxKnwni7gTQ==", + "version": "2.2.9", + "resolved": "https://npm.pkg.github.com/download/@arduino/docs-arduino-cc/2.2.9/f8e62faa785b887e959c1e8108e9cfe82d0cc5f4", + "integrity": "sha512-yk22JYPzLiQIwX3oCY02GAWw+wCPL4lCg3F0XQLw4tPBYvMyKGaU0+rAXQ9lmZfZfMrTXveXuZsaLX5yXBwx6g==", "dependencies": { "@algolia/autocomplete-core": "^1.10.0", "@algolia/autocomplete-plugin-recent-searches": "^1.17.0", diff --git a/package.json b/package.json index a1ff448be1..cd68573e50 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ }, "homepage": "https://github.com/arduino/docs-content#readme", "dependencies": { - "@arduino/docs-arduino-cc": "^2.2.9-alpha.2", + "@arduino/docs-arduino-cc": "^2.2.9", "gatsby": "^5.11.0", "gatsby-background-image": "^1.6.0", "gatsby-image": "^3.11.0", From 2e2fedae6366e393af9291d2fcc94d8c5d378755 Mon Sep 17 00:00:00 2001 From: Matteo Marsala Date: Thu, 3 Sep 2026 10:15:30 +0200 Subject: [PATCH 17/19] fix: version --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9df9536bb3..74b60011e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "hasInstallScript": true, "license": "ISC", "dependencies": { - "@arduino/docs-arduino-cc": "^2.2.9", + "@arduino/docs-arduino-cc": "2.2.9", "gatsby": "^5.11.0", "gatsby-background-image": "^1.6.0", "gatsby-image": "^3.11.0", diff --git a/package.json b/package.json index cd68573e50..42cdd59510 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ }, "homepage": "https://github.com/arduino/docs-content#readme", "dependencies": { - "@arduino/docs-arduino-cc": "^2.2.9", + "@arduino/docs-arduino-cc": "2.2.9", "gatsby": "^5.11.0", "gatsby-background-image": "^1.6.0", "gatsby-image": "^3.11.0", From 0df8e21dd7272a70f2849050525b3885a07de012 Mon Sep 17 00:00:00 2001 From: Matteo Marsala Date: Thu, 3 Sep 2026 11:49:59 +0200 Subject: [PATCH 18/19] fix: review --- .github/workflows/deploy-production.yml | 19 ++++++++++++++----- .github/workflows/deploy-staging.yml | 20 ++++++++++++++------ .github/workflows/preview.yml | 19 ++++++++++++++----- 3 files changed, 42 insertions(+), 16 deletions(-) diff --git a/.github/workflows/deploy-production.yml b/.github/workflows/deploy-production.yml index d43decacbf..a1f3655358 100644 --- a/.github/workflows/deploy-production.yml +++ b/.github/workflows/deploy-production.yml @@ -50,7 +50,7 @@ jobs: with: fetch-depth: 1 - # Attempt 2 has failed outright before, not only stalled: one more wipe and one last try + # Attempt 2 has failed outright before, not only stalled: one more wipe and a last try, bounded by the job timeout - name: Reset workspace before last checkout attempt if: steps.checkout.outcome == 'failure' && steps.checkout-retry.outcome == 'failure' run: | @@ -114,7 +114,7 @@ jobs: fetch-depth: "0" filter: blob:none - # Attempt 2 has failed outright before, not only stalled: one more wipe and one last try + # Attempt 2 has failed outright before, not only stalled: one more wipe and a last try, bounded by the job timeout - name: Reset workspace before last checkout attempt if: steps.checkout.outcome == 'failure' && steps.checkout-retry.outcome == 'failure' run: | @@ -196,10 +196,15 @@ jobs: # echo "No oversized files found. New check passed." # fi - # Key on the paths and sizes of the files the step compresses, so it changes as soon as any of them does + # Key on the git blob hash of each file, not its size: two different images of equal weight would share a key - name: Compressed images key id: images-key - run: echo "hash=$(find content -type f \( -name '*.jpg' -o -name '*.jpeg' -o -name '*.png' \) -size +2M -printf '%p %s\n' | sort | sha256sum | cut -c1-40)" >> "$GITHUB_OUTPUT" + run: | + find content -type f \( -name '*.jpg' -o -name '*.jpeg' -o -name '*.png' \) -size +2M -print0 > /tmp/big-images.lst + xargs -0 -r git ls-files -s -- < /tmp/big-images.lst > /tmp/big-images.idx + # An untracked image would be compressed but absent from the key, so require one index line per file found + test "$(tr -dc '\0' < /tmp/big-images.lst | wc -c)" -eq "$(wc -l < /tmp/big-images.idx)" + echo "hash=$(sort /tmp/big-images.idx | sha256sum | cut -c1-40)" >> "$GITHUB_OUTPUT" - name: Compressed images cache uses: actions/cache@v5 @@ -216,6 +221,8 @@ jobs: exit 0 fi sudo apt-get update && sudo apt-get install -y jpegoptim optipng + # A missing compressor is a systemic failure and must stop the job, unlike the per-file errors tolerated below + command -v jpegoptim > /dev/null && command -v optipng > /dev/null # -exec ... \; spawns one process per file on a single core: xargs -P "$(nproc)" spreads the same work over every core find content -type f \( -name "*.jpg" -o -name "*.jpeg" \) -size +2M -print0 > /tmp/big-jpg.lst find content -type f -name "*.png" -size +2M -print0 > /tmp/big-png.lst @@ -253,14 +260,16 @@ jobs: # Gatsby defaults to physical cores, which is half the vCPUs of a runner GATSBY_CPU_COUNT: logical_cores - # A warm public/ is worth 38 minutes of sharp, and costs ~4 GB of quota: main writes it, every other branch only reads + # A warm public/ is worth 38 minutes of sharp and ~4 GB of quota: only a run on main writes the entry every branch reads - name: Save Gatsby main cache + if: github.ref_name == 'main' uses: actions/cache/save@v5 with: path: .cache key: ${{ runner.os }}-cache-gatsby-node22-main-${{ github.run_id }} - name: Save Gatsby Public Folder cache + if: github.ref_name == 'main' uses: actions/cache/save@v5 with: path: public/ diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml index 35dceb6340..b3e5b05d7c 100644 --- a/.github/workflows/deploy-staging.yml +++ b/.github/workflows/deploy-staging.yml @@ -50,7 +50,7 @@ jobs: with: fetch-depth: 1 - # Attempt 2 has failed outright before, not only stalled: one more wipe and one last try + # Attempt 2 has failed outright before, not only stalled: one more wipe and a last try, bounded by the job timeout - name: Reset workspace before last checkout attempt if: steps.checkout.outcome == 'failure' && steps.checkout-retry.outcome == 'failure' run: | @@ -114,7 +114,7 @@ jobs: fetch-depth: "0" filter: blob:none - # Attempt 2 has failed outright before, not only stalled: one more wipe and one last try + # Attempt 2 has failed outright before, not only stalled: one more wipe and a last try, bounded by the job timeout - name: Reset workspace before last checkout attempt if: steps.checkout.outcome == 'failure' && steps.checkout-retry.outcome == 'failure' run: | @@ -196,10 +196,15 @@ jobs: # echo "No oversized files found. New check passed." # fi - # Key on the paths and sizes of the files the step compresses, so it changes as soon as any of them does + # Key on the git blob hash of each file, not its size: two different images of equal weight would share a key - name: Compressed images key id: images-key - run: echo "hash=$(find content -type f \( -name '*.jpg' -o -name '*.jpeg' -o -name '*.png' \) -size +2M -printf '%p %s\n' | sort | sha256sum | cut -c1-40)" >> "$GITHUB_OUTPUT" + run: | + find content -type f \( -name '*.jpg' -o -name '*.jpeg' -o -name '*.png' \) -size +2M -print0 > /tmp/big-images.lst + xargs -0 -r git ls-files -s -- < /tmp/big-images.lst > /tmp/big-images.idx + # An untracked image would be compressed but absent from the key, so require one index line per file found + test "$(tr -dc '\0' < /tmp/big-images.lst | wc -c)" -eq "$(wc -l < /tmp/big-images.idx)" + echo "hash=$(sort /tmp/big-images.idx | sha256sum | cut -c1-40)" >> "$GITHUB_OUTPUT" - name: Compressed images cache uses: actions/cache@v5 @@ -216,6 +221,8 @@ jobs: exit 0 fi sudo apt-get update && sudo apt-get install -y jpegoptim optipng + # A missing compressor is a systemic failure and must stop the job, unlike the per-file errors tolerated below + command -v jpegoptim > /dev/null && command -v optipng > /dev/null # -exec ... \; spawns one process per file on a single core: xargs -P "$(nproc)" spreads the same work over every core find content -type f \( -name "*.jpg" -o -name "*.jpeg" \) -size +2M -print0 > /tmp/big-jpg.lst find content -type f -name "*.png" -size +2M -print0 > /tmp/big-png.lst @@ -227,8 +234,9 @@ jobs: # The list is captured before compressing: some files drop under 2M and find would no longer report them cat /tmp/big-jpg.lst /tmp/big-png.lst | tar --null -cf /tmp/compressed-images.tar -T - + # Staging runs one branch at a time, so it keeps its own entries; the quota was drained by per-PR previews, not by these - name: Gatsby main cache - uses: actions/cache/restore@v5 + uses: actions/cache@v5 id: gatsby-cache-folder with: path: .cache @@ -237,7 +245,7 @@ jobs: ${{ runner.os }}-cache-gatsby-node22-main - name: Gatsby Public Folder cache - uses: actions/cache/restore@v5 + uses: actions/cache@v5 id: gatsby-public-folder with: path: public/ diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 483fd69274..c34b842bd4 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -47,7 +47,7 @@ jobs: with: fetch-depth: 1 - # Attempt 2 has failed outright before, not only stalled: one more wipe and one last try + # Attempt 2 has failed outright before, not only stalled: one more wipe and a last try, bounded by the job timeout - name: Reset workspace before last checkout attempt if: steps.checkout.outcome == 'failure' && steps.checkout-retry.outcome == 'failure' run: | @@ -125,7 +125,7 @@ jobs: with: fetch-depth: 1 - # Attempt 2 has failed outright before, not only stalled: one more wipe and one last try + # Attempt 2 has failed outright before, not only stalled: one more wipe and a last try, bounded by the job timeout - name: Reset workspace before last checkout attempt if: steps.checkout.outcome == 'failure' && steps.checkout-retry.outcome == 'failure' run: | @@ -190,10 +190,15 @@ jobs: # echo "No oversized files found. New check passed." # fi - # Key on the paths and sizes of the files the step compresses, so it changes as soon as any of them does + # Key on the git blob hash of each file, not its size: two different images of equal weight would share a key - name: Compressed images key id: images-key - run: echo "hash=$(find content -type f \( -name '*.jpg' -o -name '*.jpeg' -o -name '*.png' \) -size +2M -printf '%p %s\n' | sort | sha256sum | cut -c1-40)" >> "$GITHUB_OUTPUT" + run: | + find content -type f \( -name '*.jpg' -o -name '*.jpeg' -o -name '*.png' \) -size +2M -print0 > /tmp/big-images.lst + xargs -0 -r git ls-files -s -- < /tmp/big-images.lst > /tmp/big-images.idx + # An untracked image would be compressed but absent from the key, so require one index line per file found + test "$(tr -dc '\0' < /tmp/big-images.lst | wc -c)" -eq "$(wc -l < /tmp/big-images.idx)" + echo "hash=$(sort /tmp/big-images.idx | sha256sum | cut -c1-40)" >> "$GITHUB_OUTPUT" - name: Compressed images cache uses: actions/cache@v5 @@ -210,6 +215,8 @@ jobs: exit 0 fi sudo apt-get update && sudo apt-get install -y jpegoptim optipng + # A missing compressor is a systemic failure and must stop the job, unlike the per-file errors tolerated below + command -v jpegoptim > /dev/null && command -v optipng > /dev/null # -exec ... \; spawns one process per file on a single core: xargs -P "$(nproc)" spreads the same work over every core find content -type f \( -name "*.jpg" -o -name "*.jpeg" \) -size +2M -print0 > /tmp/big-jpg.lst find content -type f -name "*.png" -size +2M -print0 > /tmp/big-png.lst @@ -221,8 +228,9 @@ jobs: # The list is captured before compressing: some files drop under 2M and find would no longer report them cat /tmp/big-jpg.lst /tmp/big-png.lst | tar --null -cf /tmp/compressed-images.tar -T - + # .cache is ~0.1 GB, so every PR can keep its own across pushes - name: Gatsby main cache - uses: actions/cache/restore@v5 + uses: actions/cache@v5 id: gatsby-cache-folder with: path: .cache @@ -230,6 +238,7 @@ jobs: restore-keys: | ${{ runner.os }}-cache-gatsby-node22-main + # public/ is ~3.9 GB: one entry per PR filled the 10 GB quota and evicted main's, which is the one every PR reads - name: Gatsby Public Folder uses: actions/cache/restore@v5 id: gatsby-public-folder From 8f0d99ac1edc54c93b600e5a2ad483599f6eea50 Mon Sep 17 00:00:00 2001 From: Matteo Marsala Date: Thu, 3 Sep 2026 15:43:10 +0200 Subject: [PATCH 19/19] fix: review --- .github/workflows/stale-branch-cleanup.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/stale-branch-cleanup.yml b/.github/workflows/stale-branch-cleanup.yml index 61f73b7a5a..e44655f333 100644 --- a/.github/workflows/stale-branch-cleanup.yml +++ b/.github/workflows/stale-branch-cleanup.yml @@ -37,8 +37,9 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} REPO: ${{ github.repository }} DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} + # A cron has nobody watching it, so it only reports unless a person dispatches and asks for the real run + DRY_RUN: ${{ github.event_name != 'workflow_dispatch' || github.event.inputs.dry_run }} # For scheduled runs the inputs are empty, so fall back to defaults. - DRY_RUN: ${{ github.event.inputs.dry_run || 'false' }} DAYS_THRESHOLD: ${{ github.event.inputs.days_threshold || '365' }} # A stale pull request gets this many reminders, one per run, before it is closed. MAX_REMINDERS: '3'