Add dependency update and automerge workflows
This commit is contained in:
1 parent
aa47344a9d
commit
20f1abc2e8
4 files changed
+1047
No files matched your search
@@ -0,0 +1,39 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
day: "monday"
|
||||
time: "09:00"
|
||||
timezone: "Asia/Shanghai"
|
||||
open-pull-requests-limit: 5
|
||||
labels:
|
||||
- "dependencies"
|
||||
commit-message:
|
||||
prefix: "deps"
|
||||
rebase-strategy: "auto"
|
||||
groups:
|
||||
production-dependencies:
|
||||
dependency-type: "direct:production"
|
||||
patterns:
|
||||
- "*"
|
||||
development-dependencies:
|
||||
dependency-type: "direct:development"
|
||||
patterns:
|
||||
- "*"
|
||||
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
day: "monday"
|
||||
time: "09:15"
|
||||
timezone: "Asia/Shanghai"
|
||||
open-pull-requests-limit: 3
|
||||
labels:
|
||||
- "dependencies"
|
||||
- "github-actions"
|
||||
commit-message:
|
||||
prefix: "deps"
|
||||
rebase-strategy: "auto"
|
||||
@@ -0,0 +1,116 @@
|
||||
name: Auto-merge dependency updates
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows:
|
||||
- CI
|
||||
types:
|
||||
- completed
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
automerge:
|
||||
if: >
|
||||
github.event.workflow_run.conclusion == 'success' &&
|
||||
github.event.workflow_run.event == 'pull_request'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Auto-merge safe Dependabot PRs
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const pullRequests = context.payload.workflow_run.pull_requests || [];
|
||||
|
||||
if (pullRequests.length === 0) {
|
||||
core.info('No pull requests were attached to this workflow run.');
|
||||
return;
|
||||
}
|
||||
|
||||
const parseVersion = (raw) => {
|
||||
const cleaned = raw.trim().replace(/^v/i, '');
|
||||
if (!/^\d+(\.\d+){0,3}$/.test(cleaned)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const parts = cleaned.split('.').map((value) => Number.parseInt(value, 10));
|
||||
while (parts.length < 3) {
|
||||
parts.push(0);
|
||||
}
|
||||
return parts.slice(0, 3);
|
||||
};
|
||||
|
||||
const getUpdateType = (title) => {
|
||||
const match = title.match(/\sfrom\s+([^\s]+)\s+to\s+([^\s]+)/i);
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const from = parseVersion(match[1]);
|
||||
const to = parseVersion(match[2]);
|
||||
if (!from || !to) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (to[0] !== from[0]) {
|
||||
return 'major';
|
||||
}
|
||||
if (to[1] !== from[1]) {
|
||||
return 'minor';
|
||||
}
|
||||
if (to[2] !== from[2]) {
|
||||
return 'patch';
|
||||
}
|
||||
return 'none';
|
||||
};
|
||||
|
||||
for (const prRef of pullRequests) {
|
||||
const { data: pr } = await github.rest.pulls.get({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: prRef.number,
|
||||
});
|
||||
|
||||
if (pr.user?.login !== 'dependabot[bot]') {
|
||||
core.info(`#${pr.number} skipped: author is ${pr.user?.login}.`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pr.draft) {
|
||||
core.info(`#${pr.number} skipped: PR is a draft.`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const labels = pr.labels.map((label) => label.name);
|
||||
if (labels.includes('automerge:disabled')) {
|
||||
core.info(`#${pr.number} skipped: automerge disabled by label.`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const updateType = getUpdateType(pr.title);
|
||||
if (!updateType || !['minor', 'patch'].includes(updateType)) {
|
||||
core.info(`#${pr.number} skipped: unsupported update type (${updateType ?? 'unknown'}).`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const reviewDecision = pr.requested_reviewers?.length || pr.requested_teams?.length;
|
||||
if (reviewDecision) {
|
||||
core.info(`#${pr.number} skipped: PR is still waiting for requested review.`);
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
await github.rest.pulls.merge({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: pr.number,
|
||||
merge_method: 'squash',
|
||||
});
|
||||
core.info(`#${pr.number} merged successfully.`);
|
||||
} catch (error) {
|
||||
core.warning(`#${pr.number} was not merged automatically: ${error.message}`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ci-${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
verify:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: npm
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Lint
|
||||
run: npm run lint
|
||||
|
||||
- name: Run tests
|
||||
run: npm run test:ci
|
||||
Reference in new issue
Block a user