1
0
mirror of https://github.com/misskey-dev/misskey.git synced 2026-07-25 22:34:49 +02:00

Merge branch 'develop' into room

This commit is contained in:
syuilo
2026-07-03 15:40:38 +09:00
136 changed files with 7720 additions and 5974 deletions

View File

@@ -16,10 +16,10 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
uses: actions/checkout@v6.0.3
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
uses: pnpm/action-setup@v6.0.9
- name: Setup Node.js
uses: actions/setup-node@v6.4.0

View File

@@ -12,7 +12,7 @@ jobs:
steps:
- name: Checkout head
uses: actions/checkout@v6.0.2
uses: actions/checkout@v6.0.3
- name: Setup Node.js
uses: actions/setup-node@v6.4.0
with:

View File

@@ -18,7 +18,7 @@ jobs:
if: ${{ github.event.pull_request.mergeable == null || github.event.pull_request.mergeable == true }}
steps:
- name: checkout
uses: actions/checkout@v6.0.2
uses: actions/checkout@v6.0.3
with:
submodules: true
persist-credentials: false
@@ -66,7 +66,7 @@ jobs:
if: ${{ github.event.pull_request.mergeable == null || github.event.pull_request.mergeable == true }}
steps:
- name: checkout
uses: actions/checkout@v6.0.2
uses: actions/checkout@v6.0.3
with:
submodules: true
persist-credentials: false

View File

@@ -20,7 +20,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
uses: actions/checkout@v6.0.3
- name: Check version
run: |
if [ "$(jq -r '.version' package.json)" != "$(jq -r '.version' packages/misskey-js/package.json)" ]; then

View File

@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
uses: actions/checkout@v6.0.3
- name: Check
run: |
counter=0

View File

@@ -10,7 +10,7 @@ jobs:
check_copyright_year:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v6.0.3
- run: |
if [ "$(grep Copyright COPYING | sed -e 's/.*2014-\([0-9]*\) .*/\1/g')" -ne "$(date +%Y)" ]; then
echo "Please change copyright year!"

View File

@@ -27,9 +27,6 @@ jobs:
pr-ref: ${{ steps.get-ref.outputs.pr-ref }}
wait_time: ${{ steps.get-wait-time.outputs.wait_time }}
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
- name: Check allowed users
id: check-allowed-users
env:

View File

@@ -27,7 +27,7 @@ jobs:
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Check out the repo
uses: actions/checkout@v6.0.2
uses: actions/checkout@v6.0.3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Log in to Docker Hub

View File

@@ -32,7 +32,7 @@ jobs:
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Check out the repo
uses: actions/checkout@v6.0.2
uses: actions/checkout@v6.0.3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Docker meta

View File

@@ -17,7 +17,7 @@ jobs:
DOCKLE_VERSION: 0.4.15
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v6.0.3
- name: Download and install dockle v${{ env.DOCKLE_VERSION }}
run: |

View File

@@ -0,0 +1,318 @@
name: frontend-bundle-report-comment
on:
workflow_run:
workflows:
- frontend-bundle-report
types:
- completed
pull_request_target:
types:
- opened
- synchronize
- reopened
- ready_for_review
paths:
- packages/frontend/**
- packages/frontend-shared/**
- packages/frontend-builder/**
- packages/i18n/**
- packages/icons-subsetter/**
- packages/misskey-js/**
- packages/misskey-reversi/**
- packages/misskey-bubble-game/**
- package.json
- pnpm-lock.yaml
- pnpm-workspace.yaml
- .node-version
- .github/scripts/utility.mts
- .github/scripts/frontend-js-size.mts
- .github/workflows/frontend-bundle-report.yml
- .github/workflows/frontend-bundle-report-comment.yml
permissions:
actions: read
contents: read
issues: write
pull-requests: write
jobs:
comment:
name: Comment frontend bundle report
if: github.event_name == 'pull_request_target' || (github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success')
runs-on: ubuntu-latest
concurrency:
group: frontend-bundle-report-comment-${{ github.event.pull_request.number || github.event.workflow_run.id }}
cancel-in-progress: true
steps:
- name: Find bundle report run
if: github.event_name == 'pull_request_target'
id: find-report-run
uses: actions/github-script@v9
with:
script: |
const workflow_id = 'frontend-bundle-report.yml';
const artifactName = 'frontend-bundle-report';
const headSha = context.payload.pull_request.head.sha;
const prNumber = context.payload.pull_request.number;
const pollIntervalMs = 30_000;
const timeoutMs = 90 * 60_000;
const startedAt = Date.now();
const { owner, repo } = context.repo;
async function listReportWorkflowRuns() {
const runsForHead = await github.paginate(github.rest.actions.listWorkflowRuns, {
owner,
repo,
workflow_id,
event: 'pull_request',
head_sha: headSha,
per_page: 100,
});
if (runsForHead.length > 0) {
return runsForHead;
}
const recentRuns = await github.paginate(github.rest.actions.listWorkflowRuns, {
owner,
repo,
workflow_id,
event: 'pull_request',
per_page: 100,
});
return recentRuns.filter((run) =>
run.pull_requests?.some((pullRequest) => pullRequest.number === prNumber));
}
async function findReportRun() {
const runs = (await listReportWorkflowRuns())
.sort((a, b) => new Date(b.updated_at) - new Date(a.updated_at));
for (const run of runs) {
if (run.status !== 'completed') continue;
if (run.conclusion !== 'success') {
core.warning(`Frontend bundle report run ${run.id} completed with conclusion: ${run.conclusion}`);
return { done: true, run: null };
}
const artifacts = await github.paginate(github.rest.actions.listWorkflowRunArtifacts, {
owner,
repo,
run_id: run.id,
per_page: 100,
});
const report = artifacts.find((artifact) => artifact.name === artifactName && !artifact.expired);
if (report) return { done: true, run };
core.info(`Frontend bundle report run ${run.id} did not produce ${artifactName}.`);
return { done: true, run: null };
}
return { done: false, run: null };
}
while (Date.now() - startedAt < timeoutMs) {
const { done, run } = await findReportRun();
if (run) {
core.info(`Found frontend bundle report on workflow run ${run.id}.`);
core.setOutput('run-id', String(run.id));
return;
}
if (done) {
return;
}
core.info('Waiting for frontend bundle report artifact...');
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
}
core.warning(`Timed out waiting for ${artifactName} from ${workflow_id} for ${headSha}.`);
- name: Find bundle report artifact
if: github.event_name == 'workflow_run'
id: find-report-artifact
uses: actions/github-script@v9
with:
script: |
const artifactName = 'frontend-bundle-report';
const { owner, repo } = context.repo;
const artifacts = await github.paginate(github.rest.actions.listWorkflowRunArtifacts, {
owner,
repo,
run_id: context.payload.workflow_run.id,
per_page: 100,
});
const report = artifacts.find((artifact) => artifact.name === artifactName && !artifact.expired);
if (report) {
core.setOutput('exists', 'true');
} else {
core.info(`Workflow run ${context.payload.workflow_run.id} did not produce ${artifactName}.`);
core.setOutput('exists', 'false');
}
- name: Download bundle report from workflow_run
if: github.event_name == 'workflow_run' && steps.find-report-artifact.outputs.exists == 'true'
uses: actions/download-artifact@v8
with:
name: frontend-bundle-report
path: ${{ runner.temp }}/frontend-bundle-report
github-token: ${{ github.token }}
repository: ${{ github.repository }}
run-id: ${{ github.event.workflow_run.id }}
- name: Download bundle report from pull_request_target
if: github.event_name == 'pull_request_target' && steps.find-report-run.outputs.run-id != ''
uses: actions/download-artifact@v8
with:
name: frontend-bundle-report
path: ${{ runner.temp }}/frontend-bundle-report
github-token: ${{ github.token }}
repository: ${{ github.repository }}
run-id: ${{ steps.find-report-run.outputs.run-id }}
- name: Comment on pull request
if: (github.event_name == 'workflow_run' && steps.find-report-artifact.outputs.exists == 'true') || steps.find-report-run.outputs.run-id != ''
uses: actions/github-script@v9
with:
github-token: ${{ secrets.FRONTEND_BUNDLE_REPORT_COMMENT_TOKEN || secrets.FRONTEND_JS_SIZE_COMMENT_TOKEN || secrets.FRONTEND_BUNDLE_VISUALIZER_COMMENT_TOKEN || github.token }}
script: |
const fs = require('node:fs');
const path = require('node:path');
const jsSizeMarker = '<!-- misskey-frontend-js-size -->';
const visualizerMarker = '<!-- misskey-frontend-bundle-visualizer -->';
const reportMarkers = [jsSizeMarker, visualizerMarker];
const reportDir = path.join(process.env.RUNNER_TEMP, 'frontend-bundle-report');
const jsSizeReportPath = path.join(reportDir, 'frontend-js-size-report.md');
const prNumberPath = path.join(reportDir, 'pr-number.txt');
const headShaPath = path.join(reportDir, 'head-sha.txt');
const workflowRun = context.payload.workflow_run;
const pullRequest = context.payload.pull_request;
const eventHeadSha = workflowRun?.head_sha ?? pullRequest?.head?.sha ?? null;
const { owner, repo } = context.repo;
if (!fs.existsSync(jsSizeReportPath)) {
core.setFailed('The frontend bundle report artifact does not contain frontend-js-size-report.md.');
return;
}
const artifactHeadSha = fs.existsSync(headShaPath)
? fs.readFileSync(headShaPath, 'utf8').trim()
: null;
if (eventHeadSha != null && artifactHeadSha != null && artifactHeadSha !== eventHeadSha) {
core.info(`The artifact head SHA (${artifactHeadSha}) differs from the event head SHA (${eventHeadSha}). Using artifact metadata for PR validation.`);
}
const reportHeadSha = artifactHeadSha ?? eventHeadSha;
const artifactPrNumber = fs.existsSync(prNumberPath)
? Number(fs.readFileSync(prNumberPath, 'utf8').trim())
: null;
let issue_number = null;
if (pullRequest != null) {
issue_number = pullRequest.number;
if (Number.isInteger(artifactPrNumber) && artifactPrNumber !== issue_number) {
core.setFailed(`The artifact pull request number (${artifactPrNumber}) does not match the event pull request number (${issue_number}).`);
return;
}
} else if (workflowRun != null) {
const associatedPullRequests = new Map();
for (const pullRequest of workflowRun.pull_requests ?? []) {
if (Number.isInteger(pullRequest.number)) {
associatedPullRequests.set(pullRequest.number, pullRequest);
}
}
if (reportHeadSha != null) {
const pullRequestsForCommit = await github.paginate(github.rest.repos.listPullRequestsAssociatedWithCommit, {
owner,
repo,
commit_sha: reportHeadSha,
per_page: 100,
});
for (const pullRequest of pullRequestsForCommit) {
associatedPullRequests.set(pullRequest.number, pullRequest);
}
}
if (Number.isInteger(artifactPrNumber) && associatedPullRequests.has(artifactPrNumber)) {
issue_number = artifactPrNumber;
} else if (Number.isInteger(artifactPrNumber) && associatedPullRequests.size === 0) {
issue_number = artifactPrNumber;
} else if (!Number.isInteger(artifactPrNumber) && associatedPullRequests.size === 1) {
issue_number = [...associatedPullRequests.keys()][0];
} else if (Number.isInteger(artifactPrNumber)) {
core.setFailed(`The artifact pull request number (${artifactPrNumber}) is not associated with ${reportHeadSha}.`);
return;
} else {
core.setFailed(`Could not determine the pull request associated with ${reportHeadSha}.`);
return;
}
} else {
core.setFailed('Could not determine the pull request event for this report.');
return;
}
const currentPullRequest = await github.rest.pulls.get({
owner,
repo,
pull_number: issue_number,
});
const currentHeadSha = currentPullRequest.data.head?.sha;
if (reportHeadSha != null && currentHeadSha != null && reportHeadSha !== currentHeadSha) {
core.info(`The report head SHA (${reportHeadSha}) is not the current pull request head SHA (${currentHeadSha}). Skipping stale frontend bundle report.`);
return;
}
const jsSizeReport = fs.readFileSync(jsSizeReportPath, 'utf8').trim();
if (!jsSizeReport.includes(jsSizeMarker)) {
core.setFailed('The frontend JS size report is missing the expected marker.');
return;
}
let body = `${jsSizeReport}\n`;
const maxCommentLength = 65_000;
if (body.length > maxCommentLength) {
const reportLocation = workflowRun?.html_url != null
? `[workflow run](${workflowRun.html_url})`
: 'workflow artifact';
const footer = [
'',
'',
`_Report truncated because it exceeded ${maxCommentLength.toLocaleString('en-US')} characters. See the ${reportLocation} for the full report._`,
].join('\n');
body = `${body.slice(0, maxCommentLength - footer.length)}${footer}`;
}
const comments = await github.paginate(github.rest.issues.listComments, {
owner,
repo,
issue_number,
per_page: 100,
});
const previousReports = comments.filter((comment) =>
comment.user?.type === 'Bot' && reportMarkers.some((reportMarker) => comment.body?.includes(reportMarker)));
if (previousReports.length > 0) {
const [previous, ...duplicates] = previousReports;
await github.rest.issues.updateComment({
owner,
repo,
comment_id: previous.id,
body,
});
for (const duplicate of duplicates) {
await github.rest.issues.deleteComment({
owner,
repo,
comment_id: duplicate.id,
});
}
} else {
await github.rest.issues.createComment({
owner,
repo,
issue_number,
body,
});
}

View File

@@ -0,0 +1,170 @@
name: frontend-bundle-report
on:
pull_request:
types:
- opened
- synchronize
- reopened
- ready_for_review
paths:
- packages/frontend/**
- packages/frontend-shared/**
- packages/frontend-builder/**
- packages/i18n/**
- packages/icons-subsetter/**
- packages/misskey-js/**
- packages/misskey-reversi/**
- packages/misskey-bubble-game/**
- package.json
- pnpm-lock.yaml
- pnpm-workspace.yaml
- .node-version
- .github/scripts/utility.mts
- .github/scripts/frontend-js-size.mts
- .github/workflows/frontend-bundle-report.yml
- .github/workflows/frontend-bundle-report-comment.yml
permissions:
contents: read
pull-requests: read
concurrency:
group: frontend-bundle-report-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
report:
name: Build frontend bundle report
runs-on: ubuntu-latest
env:
FRONTEND_JS_SIZE_LOCALE: ja-JP
steps:
- name: Checkout base
uses: actions/checkout@v6.0.3
with:
repository: ${{ github.event.pull_request.base.repo.full_name }}
ref: ${{ github.event.pull_request.base.sha }}
path: before
submodules: true
- name: Checkout pull request
uses: actions/checkout@v6.0.3
with:
repository: ${{ github.event.pull_request.head.repo.full_name }}
ref: ${{ github.event.pull_request.head.sha }}
path: after
submodules: true
- name: Check base visualizer support
id: check-base-visualizer
shell: bash
run: |
if grep -q 'FRONTEND_BUNDLE_VISUALIZER' before/packages/frontend/vite.config.ts; then
echo 'supported=true' >> "$GITHUB_OUTPUT"
else
echo 'supported=false' >> "$GITHUB_OUTPUT"
echo 'Base commit does not support frontend bundle visualizer. Skipping frontend bundle report.' >> "$GITHUB_STEP_SUMMARY"
fi
- name: Setup pnpm
if: steps.check-base-visualizer.outputs.supported == 'true'
uses: pnpm/action-setup@v6.0.9
with:
package_json_file: after/package.json
- name: Setup Node.js
if: steps.check-base-visualizer.outputs.supported == 'true'
uses: actions/setup-node@v6.4.0
with:
node-version-file: after/.node-version
cache: pnpm
cache-dependency-path: |
before/pnpm-lock.yaml
after/pnpm-lock.yaml
- name: Install dependencies for base
if: steps.check-base-visualizer.outputs.supported == 'true'
working-directory: before
run: pnpm i --frozen-lockfile
- name: Build frontend dependencies for base
if: steps.check-base-visualizer.outputs.supported == 'true'
working-directory: before
run: pnpm --filter "frontend^..." run build
- name: Prepare report output
if: steps.check-base-visualizer.outputs.supported == 'true'
run: mkdir -p "$RUNNER_TEMP/frontend-bundle-report"
- name: Build frontend report for base
if: steps.check-base-visualizer.outputs.supported == 'true'
working-directory: before
env:
FRONTEND_BUNDLE_VISUALIZER: 'true'
FRONTEND_BUNDLE_VISUALIZER_FILE: ${{ runner.temp }}/frontend-bundle-report/before-stats.json
run: pnpm --filter frontend run build
- name: Install dependencies for pull request
if: steps.check-base-visualizer.outputs.supported == 'true'
working-directory: after
run: pnpm i --frozen-lockfile
- name: Build frontend dependencies for pull request
if: steps.check-base-visualizer.outputs.supported == 'true'
working-directory: after
run: pnpm --filter "frontend^..." run build
- name: Build frontend report for pull request
if: steps.check-base-visualizer.outputs.supported == 'true'
working-directory: after
env:
FRONTEND_BUNDLE_VISUALIZER: 'true'
FRONTEND_BUNDLE_VISUALIZER_FILE: ${{ runner.temp }}/frontend-bundle-report/after-stats.json
FRONTEND_BUNDLE_VISUALIZER_HTML_FILE: ${{ runner.temp }}/frontend-bundle-report/frontend-bundle-visualizer.html
run: pnpm --filter frontend run build
- name: Upload bundle visualizer
if: steps.check-base-visualizer.outputs.supported == 'true'
id: upload-bundle-visualizer
uses: actions/upload-artifact@v7
with:
name: frontend-bundle-visualizer
path: ${{ runner.temp }}/frontend-bundle-report/frontend-bundle-visualizer.html
if-no-files-found: error
archive: false
retention-days: 7
- name: Generate report markdown
if: steps.check-base-visualizer.outputs.supported == 'true'
shell: bash
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
PR_NUMBER: ${{ github.event.pull_request.number }}
FRONTEND_BUNDLE_REPORT_ARTIFACT_URL: ${{ steps.upload-bundle-visualizer.outputs.artifact-url }}
run: |
REPORT_DIR="$RUNNER_TEMP/frontend-bundle-report"
node after/.github/scripts/frontend-js-size.mts before after "$REPORT_DIR/before-stats.json" "$REPORT_DIR/after-stats.json" "$REPORT_DIR/frontend-js-size-report.md"
printf '%s\n' "$PR_NUMBER" > "$REPORT_DIR/pr-number.txt"
printf '%s\n' "$BASE_SHA" > "$REPORT_DIR/base-sha.txt"
printf '%s\n' "$HEAD_SHA" > "$REPORT_DIR/head-sha.txt"
printf '%s\n' "${{ github.event.pull_request.html_url }}" > "$REPORT_DIR/pr-url.txt"
- name: Check report
if: steps.check-base-visualizer.outputs.supported == 'true'
run: |
REPORT_DIR="$RUNNER_TEMP/frontend-bundle-report"
test -s "$REPORT_DIR/before-stats.json"
test -s "$REPORT_DIR/after-stats.json"
test -s "$REPORT_DIR/frontend-js-size-report.md"
cat "$REPORT_DIR/frontend-js-size-report.md" >> "$GITHUB_STEP_SUMMARY"
- name: Upload bundle report
if: steps.check-base-visualizer.outputs.supported == 'true'
uses: actions/upload-artifact@v7
with:
name: frontend-bundle-report
path: ${{ runner.temp }}/frontend-bundle-report/
if-no-files-found: error
retention-days: 7

View File

@@ -25,12 +25,12 @@ jobs:
ref: refs/pull/${{ github.event.number }}/merge
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v6.0.3
with:
ref: ${{ matrix.ref }}
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
uses: pnpm/action-setup@v6.0.9
- name: Use Node.js
uses: actions/setup-node@v6.4.0
with:

View File

@@ -9,7 +9,14 @@ on:
paths:
- packages/backend/**
- packages/misskey-js/**
- .github/scripts/utility.mts
- .github/scripts/backend-memory-report.mts
- .github/scripts/measure-backend-memory-comparison.mts
- .github/scripts/backend-js-footprint.mjs
- .github/scripts/backend-js-footprint-loader.mjs
- .github/scripts/backend-js-footprint-require.cjs
- .github/workflows/get-backend-memory.yml
- .github/workflows/report-backend-memory.yml
jobs:
get-memory-usage:
@@ -17,15 +24,6 @@ jobs:
permissions:
contents: read
strategy:
matrix:
memory-json-name: [memory-base.json, memory-head.json]
include:
- memory-json-name: memory-base.json
ref: ${{ github.base_ref }}
- memory-json-name: memory-head.json
ref: refs/pull/${{ github.event.number }}/merge
services:
postgres:
image: postgres:18
@@ -40,37 +38,84 @@ jobs:
- 56312:6379
steps:
- uses: actions/checkout@v6.0.2
- name: Checkout base
uses: actions/checkout@v6.0.3
with:
ref: ${{ matrix.ref }}
ref: ${{ github.base_ref }}
path: base
submodules: true
- name: Checkout head
uses: actions/checkout@v6.0.3
with:
ref: refs/pull/${{ github.event.number }}/merge
path: head
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
uses: pnpm/action-setup@v6.0.9
with:
package_json_file: head/package.json
- name: Use Node.js
uses: actions/setup-node@v6.4.0
with:
node-version-file: '.node-version'
node-version-file: 'head/.node-version'
cache: 'pnpm'
- run: pnpm i --frozen-lockfile
- name: Check pnpm-lock.yaml
cache-dependency-path: |
base/pnpm-lock.yaml
head/pnpm-lock.yaml
- name: Install base dependencies
working-directory: base
run: pnpm i --frozen-lockfile
- name: Check base pnpm-lock.yaml
working-directory: base
run: git diff --exit-code pnpm-lock.yaml
- name: Copy Configure
run: cp .github/misskey/test.yml .config/default.yml
- name: Compile Configure
run: pnpm compile-config
- name: Build
run: pnpm build
- name: Run migrations
run: pnpm --filter backend migrate
- name: Measure memory usage
- name: Configure base
working-directory: base
run: |
# Start the server and measure memory usage
node packages/backend/scripts/measure-memory.mjs > ${{ matrix.memory-json-name }}
cp .github/misskey/test.yml .config/default.yml
pnpm compile-config
- name: Build base
working-directory: base
run: pnpm build
- name: Install head dependencies
working-directory: head
run: pnpm i --frozen-lockfile
- name: Check head pnpm-lock.yaml
working-directory: head
run: git diff --exit-code pnpm-lock.yaml
- name: Configure head
working-directory: head
run: |
cp .github/misskey/test.yml .config/default.yml
pnpm compile-config
- name: Build head
working-directory: head
run: pnpm build
- name: Measure backend memory usage
env:
MK_MEMORY_COMPARE_ROUNDS: 5
MK_MEMORY_COMPARE_WARMUP_ROUNDS: 1
MK_MEMORY_HEAP_SNAPSHOT: 1
run: node head/.github/scripts/measure-backend-memory-comparison.mts base head memory-base.json memory-head.json
- name: Upload head heap snapshot
uses: actions/upload-artifact@v7
with:
name: backend-memory-head-heap-snapshot
path: head-heap-snapshot.heapsnapshot
if-no-files-found: error
retention-days: 7
- name: Measure backend loaded JS footprint
run: |
node head/.github/scripts/backend-js-footprint.mjs base js-footprint-base.json
node head/.github/scripts/backend-js-footprint.mjs head js-footprint-head.json
- name: Upload Artifact
uses: actions/upload-artifact@v7
with:
name: memory-artifact-${{ matrix.memory-json-name }}
path: ${{ matrix.memory-json-name }}
name: memory-artifact-results
path: |
memory-base.json
memory-head.json
js-footprint-base.json
js-footprint-head.json
save-pr-number:
runs-on: ubuntu-latest

View File

@@ -40,12 +40,12 @@ jobs:
pnpm_install:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v6.0.3
with:
fetch-depth: 0
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
uses: pnpm/action-setup@v6.0.9
- uses: actions/setup-node@v6.4.0
with:
node-version-file: '.node-version'
@@ -75,12 +75,12 @@ jobs:
eslint-cache-version: v1
eslint-cache-path: ${{ github.workspace }}/node_modules/.cache/eslint-${{ matrix.workspace }}
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v6.0.3
with:
fetch-depth: 0
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
uses: pnpm/action-setup@v6.0.9
- uses: actions/setup-node@v6.4.0
with:
node-version-file: '.node-version'
@@ -106,12 +106,12 @@ jobs:
- sw
- misskey-js
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v6.0.3
with:
fetch-depth: 0
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
uses: pnpm/action-setup@v6.0.9
- uses: actions/setup-node@v6.4.0
with:
node-version-file: '.node-version'

View File

@@ -16,12 +16,12 @@ jobs:
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v6.0.3
with:
fetch-depth: 0
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
uses: pnpm/action-setup@v6.0.9
- uses: actions/setup-node@v6.4.0
with:
node-version-file: ".node-version"

View File

@@ -16,11 +16,11 @@ jobs:
id-token: write
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v6.0.3
with:
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
uses: pnpm/action-setup@v6.0.9
- name: Use Node.js
uses: actions/setup-node@v6.4.0
with:

View File

@@ -11,44 +11,26 @@ jobs:
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'success' }}
permissions:
actions: read
pull-requests: write
# api-artifact
steps:
- name: Download artifact
uses: actions/github-script@v9
- name: Download artifacts
uses: actions/download-artifact@v8
with:
script: |
const fs = require('fs');
let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.payload.workflow_run.id,
});
let matchArtifacts = allArtifacts.data.artifacts.filter((artifact) => {
return artifact.name.startsWith("api-artifact-") || artifact.name == "api-artifact"
});
await Promise.all(matchArtifacts.map(async (artifact) => {
let download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: artifact.id,
archive_format: 'zip',
});
await fs.promises.writeFile(`${process.env.GITHUB_WORKSPACE}/${artifact.name}.zip`, Buffer.from(download.data));
}));
- name: Extract all artifacts
run: |
find . -mindepth 1 -maxdepth 1 -type f -name '*.zip' -exec unzip {} -d artifacts ';'
ls -la
pattern: api-artifact-*
path: artifacts
merge-multiple: true
github-token: ${{ github.token }}
repository: ${{ github.repository }}
run-id: ${{ github.event.workflow_run.id }}
- name: Check artifacts
run: ls -lh artifacts/
- name: Load PR Number
id: load-pr-num
run: echo "pr-number=$(cat artifacts/pr_number)" >> "$GITHUB_OUTPUT"
- name: Output base
run: cat ./artifacts/api-base.json
- name: Output head
run: cat ./artifacts/api-head.json
- name: Arrange json files
run: |
jq '.' ./artifacts/api-base.json > ./api-base.json
@@ -57,8 +39,6 @@ jobs:
run: diff -u --label=base --label=head ./api-base.json ./api-head.json | cat > api.json.diff
- name: Get full diff
run: diff --label=base --label=head --new-line-format='+%L' --old-line-format='-%L' --unchanged-line-format=' %L' ./api-base.json ./api-head.json | cat > api-full.json.diff
- name: Echo full diff
run: cat ./api-full.json.diff
- name: Upload full diff to Artifact
uses: actions/upload-artifact@v7
with:
@@ -85,7 +65,7 @@ jobs:
echo '```diff' >> ./output.md
cat ./api.json.diff >> ./output.md
echo '```' >> ./output.md
echo '</details>' >> .output.md
echo '</details>' >> ./output.md
fi
echo "$FOOTER" >> ./output.md

View File

@@ -11,157 +11,49 @@ jobs:
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'success' }}
permissions:
actions: read
contents: read
pull-requests: write
steps:
- name: Download artifact
uses: actions/github-script@v9
- name: Checkout
uses: actions/checkout@v6.0.3
- name: Download artifacts
uses: actions/download-artifact@v8
with:
script: |
const fs = require('fs');
let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.payload.workflow_run.id,
});
let matchArtifacts = allArtifacts.data.artifacts.filter((artifact) => {
return artifact.name.startsWith("memory-artifact-") || artifact.name == "memory-artifact"
});
await Promise.all(matchArtifacts.map(async (artifact) => {
let download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: artifact.id,
archive_format: 'zip',
});
await fs.promises.writeFile(`${process.env.GITHUB_WORKSPACE}/${artifact.name}.zip`, Buffer.from(download.data));
}));
- name: Extract all artifacts
run: |
find . -mindepth 1 -maxdepth 1 -type f -name '*.zip' -exec unzip {} -d artifacts ';'
ls -la artifacts/
pattern: memory-artifact-*
path: artifacts
merge-multiple: true
github-token: ${{ github.token }}
repository: ${{ github.repository }}
run-id: ${{ github.event.workflow_run.id }}
- name: Check artifacts
run: ls -lh artifacts/
- name: Load PR Number
id: load-pr-num
run: echo "pr-number=$(cat artifacts/pr_number)" >> "$GITHUB_OUTPUT"
- name: Find head heap snapshot artifact
id: find-heap-snapshot-artifact
uses: actions/github-script@v8
with:
script: |
const { owner, repo } = context.repo;
const run_id = context.payload.workflow_run.id;
const artifacts = await github.paginate(github.rest.actions.listWorkflowRunArtifacts, {
owner,
repo,
run_id,
});
const artifact = artifacts.find(artifact => artifact.name === 'backend-memory-head-heap-snapshot');
if (artifact == null) return;
core.setOutput('url', `https://github.com/${owner}/${repo}/actions/runs/${run_id}/artifacts/${artifact.id}`);
- name: Output base
run: cat ./artifacts/memory-base.json
- name: Output head
run: cat ./artifacts/memory-head.json
- name: Compare memory usage
id: compare
run: |
BASE_MEMORY=$(cat ./artifacts/memory-base.json)
HEAD_MEMORY=$(cat ./artifacts/memory-head.json)
variation() {
calc() {
BASE=$(echo "$BASE_MEMORY" | jq -r ".${1}.${2} // 0")
HEAD=$(echo "$HEAD_MEMORY" | jq -r ".${1}.${2} // 0")
DIFF=$((HEAD - BASE))
if [ "$BASE" -gt 0 ]; then
DIFF_PERCENT=$(echo "scale=2; ($DIFF * 100) / $BASE" | bc)
else
DIFF_PERCENT=0
fi
# Convert KB to MB for readability
BASE_MB=$(echo "scale=2; $BASE / 1024" | bc)
HEAD_MB=$(echo "scale=2; $HEAD / 1024" | bc)
DIFF_MB=$(echo "scale=2; $DIFF / 1024" | bc)
JSON=$(jq -c -n \
--argjson base "$BASE_MB" \
--argjson head "$HEAD_MB" \
--argjson diff "$DIFF_MB" \
--argjson diff_percent "$DIFF_PERCENT" \
'{base: $base, head: $head, diff: $diff, diff_percent: $diff_percent}')
echo "$JSON"
}
JSON=$(jq -c -n \
--argjson VmRSS "$(calc $1 VmRSS)" \
--argjson VmHWM "$(calc $1 VmHWM)" \
--argjson VmSize "$(calc $1 VmSize)" \
--argjson VmData "$(calc $1 VmData)" \
'{VmRSS: $VmRSS, VmHWM: $VmHWM, VmSize: $VmSize, VmData: $VmData}')
echo "$JSON"
}
JSON=$(jq -c -n \
--argjson beforeGc "$(variation beforeGc)" \
--argjson afterGc "$(variation afterGc)" \
--argjson afterRequest "$(variation afterRequest)" \
'{beforeGc: $beforeGc, afterGc: $afterGc, afterRequest: $afterRequest}')
echo "res=$JSON" >> "$GITHUB_OUTPUT"
- id: build-comment
name: Build memory comment
env:
RES: ${{ steps.compare.outputs.res }}
run: |
HEADER="## Backend memory usage comparison"
FOOTER="[See workflow logs for details](https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID})"
echo "$HEADER" > ./output.md
echo >> ./output.md
table() {
echo "| Metric | base (MB) | head (MB) | Diff (MB) | Diff (%) |" >> ./output.md
echo "|--------|------:|------:|------:|------:|" >> ./output.md
line() {
METRIC=$2
BASE=$(echo "$RES" | jq -r ".${1}.${2}.base")
HEAD=$(echo "$RES" | jq -r ".${1}.${2}.head")
DIFF=$(echo "$RES" | jq -r ".${1}.${2}.diff")
DIFF_PERCENT=$(echo "$RES" | jq -r ".${1}.${2}.diff_percent")
if (( $(echo "$DIFF_PERCENT > 0" | bc -l) )); then
DIFF="+$DIFF"
DIFF_PERCENT="+$DIFF_PERCENT"
fi
# highlight VmRSS
if [ "$2" = "VmRSS" ]; then
METRIC="**${METRIC}**"
BASE="**${BASE}**"
HEAD="**${HEAD}**"
DIFF="**${DIFF}**"
DIFF_PERCENT="**${DIFF_PERCENT}**"
fi
echo "| ${METRIC} | ${BASE} MB | ${HEAD} MB | ${DIFF} MB | ${DIFF_PERCENT}% |" >> ./output.md
}
line $1 VmRSS
line $1 VmHWM
line $1 VmSize
line $1 VmData
}
echo "### Before GC" >> ./output.md
table beforeGc
echo >> ./output.md
echo "### After GC" >> ./output.md
table afterGc
echo >> ./output.md
echo "### After Request" >> ./output.md
table afterRequest
echo >> ./output.md
# Determine if this is a significant change (more than 5% increase)
if [ "$(echo "$RES" | jq -r '.afterGc.VmRSS.diff_percent | tonumber > 5')" = "true" ]; then
echo "⚠️ **Warning**: Memory usage has increased by more than 5%. Please verify this is not an unintended change." >> ./output.md
echo >> ./output.md
fi
echo "$FOOTER" >> ./output.md
MK_MEMORY_HEAP_SNAPSHOT_ARTIFACT_URL_HEAD: ${{ steps.find-heap-snapshot-artifact.outputs.url }}
run: node .github/scripts/backend-memory-report.mts ./artifacts/memory-base.json ./artifacts/memory-head.json ./output.md ./artifacts/js-footprint-base.json ./artifacts/js-footprint-head.json
- uses: thollander/actions-comment-pull-request@v3
with:
pr-number: ${{ steps.load-pr-num.outputs.pr-number }}

View File

@@ -22,12 +22,12 @@ jobs:
NODE_OPTIONS: "--max_old_space_size=7168"
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v6.0.3
if: github.event_name != 'pull_request_target'
with:
fetch-depth: 0
submodules: true
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v6.0.3
if: github.event_name == 'pull_request_target'
with:
fetch-depth: 0
@@ -37,7 +37,7 @@ jobs:
if: github.event_name == 'pull_request_target'
run: git checkout "$(git rev-list --parents -n1 HEAD | cut -d" " -f3)"
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
uses: pnpm/action-setup@v6.0.9
- name: Use Node.js
uses: actions/setup-node@v6.4.0
with:

View File

@@ -19,12 +19,6 @@ on:
- .github/workflows/test-backend.yml
- .github/misskey/test.yml
workflow_dispatch:
inputs:
force_ffmpeg_cache_update:
description: 'Force update ffmpeg cache'
required: false
default: false
type: boolean
jobs:
unit:
@@ -49,7 +43,7 @@ jobs:
ports:
- 56312:6379
meilisearch:
image: getmeili/meilisearch:v1.42.1
image: getmeili/meilisearch:v1.48.1
ports:
- 57712:7700
env:
@@ -57,41 +51,14 @@ jobs:
MEILI_ENV: development
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v6.0.3
with:
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
- name: Get current date
id: current-date
run: echo "today=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
- name: Setup and Restore ffmpeg/ffprobe Cache
id: cache-ffmpeg
uses: actions/cache@v5
with:
path: |
/usr/local/bin/ffmpeg
/usr/local/bin/ffprobe
# daily cache
key: ${{ runner.os }}-ffmpeg-${{ steps.current-date.outputs.today }}
restore-keys: |
${{ runner.os }}-ffmpeg-${{ steps.current-date.outputs.today }}
uses: pnpm/action-setup@v6.0.9
- name: Install FFmpeg
if: steps.cache-ffmpeg.outputs.cache-hit != 'true' || github.event.inputs.force_ffmpeg_cache_update == true
run: |
for i in {1..3}; do
echo "Attempt $i: Installing FFmpeg..."
curl -s -L https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz -o ffmpeg.tar.xz && \
tar -xf ffmpeg.tar.xz && \
mv ffmpeg-*-static/ffmpeg /usr/local/bin/ && \
mv ffmpeg-*-static/ffprobe /usr/local/bin/ && \
rm -rf ffmpeg.tar.xz ffmpeg-*-static/ && \
break || sleep 10
if [ $i -eq 3 ]; then
echo "Failed to install FFmpeg after 3 attempts"
exit 1
fi
done
sudo apt install -y ffmpeg
- name: Use Node.js
uses: actions/setup-node@v6.4.0
with:
@@ -136,11 +103,11 @@ jobs:
- 56312:6379
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v6.0.3
with:
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
uses: pnpm/action-setup@v6.0.9
- name: Use Node.js
uses: actions/setup-node@v6.4.0
with:
@@ -180,11 +147,11 @@ jobs:
POSTGRES_HOST_AUTH_METHOD: trust
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v6.0.3
with:
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
uses: pnpm/action-setup@v6.0.9
- name: Get current date
id: current-date
run: echo "today=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT

View File

@@ -15,12 +15,6 @@ on:
- packages/misskey-js/**
- .github/workflows/test-federation.yml
workflow_dispatch:
inputs:
force_ffmpeg_cache_update:
description: 'Force update ffmpeg cache'
required: false
default: false
type: boolean
jobs:
test:
@@ -36,37 +30,10 @@ jobs:
with:
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
- name: Get current date
id: current-date
run: echo "today=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
- name: Setup and Restore ffmpeg/ffprobe Cache
id: cache-ffmpeg
uses: actions/cache@v5
with:
path: |
/usr/local/bin/ffmpeg
/usr/local/bin/ffprobe
# daily cache
key: ${{ runner.os }}-ffmpeg-${{ steps.current-date.outputs.today }}
restore-keys: |
${{ runner.os }}-ffmpeg-${{ steps.current-date.outputs.today }}
uses: pnpm/action-setup@v6.0.9
- name: Install FFmpeg
if: steps.cache-ffmpeg.outputs.cache-hit != 'true' || github.event.inputs.force_ffmpeg_cache_update == true
run: |
for i in {1..3}; do
echo "Attempt $i: Installing FFmpeg..."
curl -s -L https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz -o ffmpeg.tar.xz && \
tar -xf ffmpeg.tar.xz && \
mv ffmpeg-*-static/ffmpeg /usr/local/bin/ && \
mv ffmpeg-*-static/ffprobe /usr/local/bin/ && \
rm -rf ffmpeg.tar.xz ffmpeg-*-static/ && \
break || sleep 10
if [ $i -eq 3 ]; then
echo "Failed to install FFmpeg after 3 attempts"
exit 1
fi
done
sudo apt install -y ffmpeg
- name: Use Node.js
uses: actions/setup-node@v6.4.0
with:

View File

@@ -28,11 +28,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v6.0.3
with:
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
uses: pnpm/action-setup@v6.0.9
- name: Use Node.js
uses: actions/setup-node@v6.4.0
with:
@@ -76,7 +76,7 @@ jobs:
- 56312:6379
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v6.0.3
with:
submodules: true
# https://github.com/cypress-io/cypress-docker-images/issues/150
@@ -86,7 +86,7 @@ jobs:
#- uses: browser-actions/setup-firefox@latest
# if: ${{ matrix.browser == 'firefox' }}
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
uses: pnpm/action-setup@v6.0.9
- name: Use Node.js
uses: actions/setup-node@v6.4.0
with:
@@ -105,7 +105,7 @@ jobs:
- name: Cypress install
run: pnpm exec cypress install
- name: Cypress run
uses: cypress-io/github-action@v7.1.9
uses: cypress-io/github-action@v7.4.0
timeout-minutes: 15
with:
install: false

View File

@@ -22,10 +22,10 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
uses: actions/checkout@v6.0.3
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
uses: pnpm/action-setup@v6.0.9
- name: Setup Node.js
uses: actions/setup-node@v6.4.0

View File

@@ -16,11 +16,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v6.0.3
with:
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
uses: pnpm/action-setup@v6.0.9
- name: Use Node.js
uses: actions/setup-node@v6.4.0
with:

View File

@@ -17,11 +17,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v6.0.3
with:
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
uses: pnpm/action-setup@v6.0.9
- name: Use Node.js
uses: actions/setup-node@v6.4.0
with: