Skip to content

Commit 20e3d7c

Browse files
Merge branch 'master' into extendedgcd
2 parents 063217d + 002ed91 commit 20e3d7c

157 files changed

Lines changed: 10767 additions & 2183 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/dependabot.yml

Lines changed: 46 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ updates:
1515
day: 'friday'
1616
time: '03:00'
1717
timezone: Europe/London
18+
cooldown:
19+
default-days: 2
1820
commit-message:
1921
prefix: 'chore (deps): '
2022
ignore:
@@ -25,16 +27,10 @@ updates:
2527
# see issue #2214 for rationale for each of these
2628
- dependency-name: '@xmldom/xmldom'
2729
versions: [ '>=0.9.0' ]
28-
- dependency-name: 'bcryptjs'
29-
versions: [ '>=3.0.0' ]
3030
- dependency-name: 'bootstrap'
3131
versions: [ '>=5.0.0' ]
32-
- dependency-name: 'bson'
33-
versions: [ '>=5.0.0' ]
3432
- dependency-name: 'cbor'
3533
versions: [ '>=10.0.0' ]
36-
- dependency-name: 'cspell'
37-
versions: [ '>=9.0.0' ]
3834
- dependency-name: 'eslint'
3935
versions: [ '>=10.0.0' ]
4036
- dependency-name: 'eslint-plugin-jsdoc'
@@ -45,30 +41,57 @@ updates:
4541
versions: [ '>=2.0.0' ]
4642
- dependency-name: 'jimp'
4743
versions: [ '1.6.1' ]
48-
- dependency-name: 'otpauth'
49-
versions: [ '>=9.4.0' ]
50-
- dependency-name: 'webpack-dev-server'
51-
versions: [ '>=5.1.0' ]
44+
- dependency-name: 'jq-web'
45+
versions: [ '>=0.6.0' ]
5246
groups:
5347
#
54-
# Grouping so we don't get a seperate PR for every patch version.
48+
# Grouping so patch version updates are batched together in a single PR
49+
# and similarly with minor version updates
5550
#
5651
patch-updates:
5752
applies-to: version-updates
5853
patterns:
5954
- '*'
6055
update-types:
6156
- 'patch'
57+
minor-updates:
58+
applies-to: version-updates
59+
patterns:
60+
- '*'
61+
update-types:
62+
- 'minor'
6263

63-
# Can't enable this until we are using Node 24 as the latest actions all require this version
64-
# - package-ecosystem: "github-actions"
65-
# # Workflow files stored in the default location of `.github/workflows`; no need to
66-
# # specify `/.github/workflows` for `directory`
67-
# directory: '/'
68-
# schedule:
69-
# interval: 'weekly'
70-
# day: 'friday'
71-
# time: '03:00'
72-
# timezone: Europe/London
73-
# commit-message:
74-
# prefix: 'chore (deps): '
64+
# Versioning on Github Actions
65+
- package-ecosystem: "github-actions"
66+
# Workflow files stored in the default location of `.github/workflows`; no need to
67+
# specify `/.github/workflows` for `directory`
68+
directory: '/'
69+
schedule:
70+
interval: 'weekly'
71+
day: 'friday'
72+
time: '03:00'
73+
timezone: Europe/London
74+
cooldown:
75+
default-days: 4
76+
commit-message:
77+
prefix: 'chore (deps): '
78+
groups:
79+
actions-dependencies:
80+
patterns:
81+
- "*"
82+
83+
- package-ecosystem: docker
84+
directory: /
85+
schedule:
86+
interval: 'weekly'
87+
day: 'friday'
88+
time: '03:00'
89+
timezone: Europe/London
90+
cooldown:
91+
default-days: 4
92+
commit-message:
93+
prefix: 'chore (deps): '
94+
groups:
95+
docker-dependencies:
96+
patterns:
97+
- "*"
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
name: Close Stale Unsigned CLA PRs
2+
3+
on:
4+
schedule:
5+
# Runs daily at 01:30 UTC.
6+
- cron: '30 1 * * *'
7+
workflow_dispatch: {}
8+
9+
permissions:
10+
contents: read
11+
pull-requests: write
12+
issues: write
13+
14+
# Configurable intervals (days).
15+
# DAYS_BEFORE_WARNING = grace period before the warning comment.
16+
# DAYS_BEFORE_CLOSURE = further period after the warning before closing.
17+
env:
18+
DAYS_BEFORE_WARNING: 7
19+
DAYS_BEFORE_CLOSURE: 21
20+
21+
jobs:
22+
stale:
23+
runs-on: ubuntu-latest
24+
steps:
25+
- name: Close stale unsigned-CLA PRs
26+
uses: actions/stale@eb5cf3af3ac0a1aa4c9c45633dd1ae542a27a899 #v10.3.0
27+
with:
28+
# ---- Guards: only act on PRs carrying the CLA label ----
29+
only-labels: 'awaiting cla'
30+
31+
# Never touch issues — PRs only.
32+
days-before-issue-stale: -1
33+
days-before-issue-close: -1
34+
35+
# ---- Timing ----
36+
# DAYS_BEFORE_WARNING: days of inactivity before the warning comment.
37+
days-before-pr-stale: ${{ env.DAYS_BEFORE_WARNING }}
38+
# DAYS_BEFORE_CLOSURE: days after being marked stale before closing.
39+
days-before-pr-close: ${{ env.DAYS_BEFORE_CLOSURE }}
40+
41+
# ---- Warning comment (posted once when marked stale) ----
42+
stale-pr-message: >
43+
As we are unable to accept contributions unless the CLA has
44+
been signed, this PR will be automatically closed if the CLA
45+
is not signed within ${{ env.DAYS_BEFORE_CLOSURE }} days.
46+
47+
# ---- Close comment ----
48+
close-pr-message: >
49+
This PR has been automatically closed as the CLA remains
50+
unsigned. We will be happy to have it reopened if the CLA
51+
is signed subsequently.
52+
53+
# A dedicated marker label so we can track stale state without
54+
# interfering with the "awaiting cla" label.
55+
stale-pr-label: 'cla-stale'
56+
57+
# If the PR is updated after being marked stale, remove the marker
58+
# so the warning-then-close cycle restarts cleanly.
59+
remove-pr-stale-when-updated: true
60+
61+
# Process enough PRs per run for busy repos.
62+
operations-per-run: 200

.github/workflows/cla-label.yml

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
name: CLA Label Sync
2+
3+
on:
4+
issue_comment:
5+
types: [created, edited]
6+
pull_request_target:
7+
types: [opened, synchronize, reopened]
8+
9+
permissions:
10+
pull-requests: write
11+
issues: write
12+
contents: read
13+
14+
jobs:
15+
sync-label:
16+
# Only run for PRs (issue_comment fires for issues too)
17+
if: >-
18+
github.event_name == 'pull_request_target' ||
19+
(github.event.issue.pull_request != null)
20+
runs-on: ubuntu-latest
21+
steps:
22+
- name: Sync "awaiting cla" label
23+
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 #v9.0.0
24+
env:
25+
AWAITING_LABEL: 'awaiting cla'
26+
# Bot login that posts the CLA comment. Common values:
27+
# 'github-actions[bot]', 'CLAassistant', 'cla-assistant[bot]'
28+
CLA_BOT_LOGINS: 'CLAassistant'
29+
# Regex (case-insensitive) that matches an UNSIGNED CLA comment
30+
NOT_SIGNED_REGEX: 'cla-assistant.io/pull/badge/not_signed'
31+
# Regex (case-insensitive) that matches a SIGNED CLA comment
32+
SIGNED_REGEX: 'cla-assistant.io/pull/badge/signed'
33+
with:
34+
script: |
35+
const awaitingLabel = process.env.AWAITING_LABEL;
36+
const botLogins = process.env.CLA_BOT_LOGINS.split(',').map(s => s.trim().toLowerCase());
37+
const notSigned = new RegExp(process.env.NOT_SIGNED_REGEX, 'i');
38+
const signed = new RegExp(process.env.SIGNED_REGEX, 'i');
39+
40+
// Resolve PR number for either trigger
41+
const prNumber = context.eventName === 'pull_request_target'
42+
? context.payload.pull_request.number
43+
: context.payload.issue.number;
44+
45+
const { owner, repo } = context.repo;
46+
47+
// Pull the full comment history to find the latest CLA bot comment
48+
const comments = await github.paginate(github.rest.issues.listComments, {
49+
owner, repo, issue_number: prNumber, per_page: 100,
50+
});
51+
52+
const claComments = comments.filter(c =>
53+
botLogins.includes((c.user?.login || '').toLowerCase()) &&
54+
(notSigned.test(c.body) || signed.test(c.body))
55+
);
56+
57+
if (claComments.length === 0) {
58+
core.info('No CLA Assistant comment found yet; nothing to do.');
59+
return;
60+
}
61+
62+
const latest = claComments[claComments.length - 1];
63+
const isSigned = signed.test(latest.body) && !notSigned.test(latest.body);
64+
65+
core.info(`Latest CLA comment (id ${latest.id}) => signed=${isSigned}`);
66+
67+
// Current labels
68+
const { data: issue } = await github.rest.issues.get({
69+
owner, repo, issue_number: prNumber,
70+
});
71+
const hasLabel = issue.labels.some(l =>
72+
(typeof l === 'string' ? l : l.name) === awaitingLabel
73+
);
74+
75+
if (isSigned && hasLabel) {
76+
await github.rest.issues.removeLabel({
77+
owner, repo, issue_number: prNumber, name: awaitingLabel,
78+
}).catch(e => core.warning(`removeLabel failed: ${e.message}`));
79+
core.info(`Removed "${awaitingLabel}".`);
80+
} else if (!isSigned && !hasLabel) {
81+
await github.rest.issues.addLabels({
82+
owner, repo, issue_number: prNumber, labels: [awaitingLabel],
83+
});
84+
core.info(`Added "${awaitingLabel}".`);
85+
} else {
86+
core.info('Label already in the correct state.');
87+
}

.github/workflows/master.yml

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ jobs:
1616
pages: write
1717
runs-on: ubuntu-latest
1818
steps:
19-
- uses: actions/checkout@v6
19+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
2020

2121
- name: Set node version
22-
uses: actions/setup-node@v6
22+
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
2323
with:
2424
node-version: 24
2525
registry-url: "https://registry.npmjs.org"
@@ -44,9 +44,17 @@ jobs:
4444
- name: Generate sitemap
4545
run: npx grunt exec:sitemap
4646

47+
- name: Setup Chrome
48+
id: setup-chrome
49+
if: success()
50+
run: |
51+
npx @puppeteer/browsers install chrome@148
52+
echo chromedir=$(dirname $(find `pwd`/chrome/* -name chrome -print -quit)) >> $GITHUB_OUTPUT
53+
4754
- name: UI Tests
4855
if: success()
4956
run: |
57+
export PATH=${{ steps.setup-chrome.outputs.chromedir }}:$PATH
5058
sudo apt-get install xvfb
5159
xvfb-run --server-args="-screen 0 1200x800x24" npx grunt testui
5260
@@ -56,7 +64,7 @@ jobs:
5664

5765
- name: Deploy to GitHub Pages
5866
if: success() && github.ref == 'refs/heads/master'
59-
uses: crazy-max/ghaction-github-pages@v3
67+
uses: crazy-max/ghaction-github-pages@1d6ee9b181a81033a16bd707a1401afa978daab4 # v5.0.0
6068
with:
6169
target_branch: gh-pages
6270
build_dir: ./build/prod

.github/workflows/pull_requests.yml

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ jobs:
1212
main:
1313
runs-on: ubuntu-latest
1414
steps:
15-
- uses: actions/checkout@v6
15+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
1616

1717
- name: Set node version
18-
uses: actions/setup-node@v6
18+
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
1919
with:
2020
node-version: 24
2121
registry-url: "https://registry.npmjs.org"
@@ -39,28 +39,36 @@ jobs:
3939

4040
- name: Upload Build Artefact
4141
if: success()
42-
uses: actions/upload-artifact@v7
42+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
4343
with:
4444
name: zipped-build
4545
path: build/prod/*.zip
4646
retention-days: 5
4747

48+
- name: Setup Chrome
49+
id: setup-chrome
50+
if: success()
51+
run: |
52+
npx @puppeteer/browsers install chrome@148
53+
echo chromedir=$(dirname $(find `pwd`/chrome/* -name chrome -print -quit)) >> $GITHUB_OUTPUT
54+
4855
- name: UI Tests
4956
if: success()
5057
run: |
58+
export PATH=${{ steps.setup-chrome.outputs.chromedir }}:$PATH
5159
sudo apt-get install xvfb
5260
xvfb-run --server-args="-screen 0 1200x800x24" npx grunt testui
5361
5462
- name: Set up Docker Buildx
5563
if: success()
56-
uses: docker/setup-buildx-action@v3
64+
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
5765

5866
- name: Set up QEMU
59-
uses: docker/setup-qemu-action@v3
67+
uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0
6068

6169
- name: Production Image Build
6270
if: success()
6371
id: build-image
64-
uses: docker/build-push-action@v6
72+
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
6573
with:
66-
platforms: linux/amd64,linux/arm64
74+
platforms: linux/amd64,linux/arm64,linux/arm/v7

0 commit comments

Comments
 (0)