diff --git a/.github/workflows/resolution-time.yml b/.github/workflows/resolution-time.yml new file mode 100644 index 000000000..24d1026d3 --- /dev/null +++ b/.github/workflows/resolution-time.yml @@ -0,0 +1,168 @@ +name: Resolution time benchmark + +on: + pull_request: + workflow_dispatch: + inputs: + target_branch: + description: 'Target branch to compare against' + required: true + default: 'main' + +jobs: + resolution-time: + permissions: + contents: read + issues: write + pull-requests: write + runs-on: ubuntu-latest + steps: + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 10.27.0 + run_install: false + + - name: Checkout PR branch + uses: actions/checkout@v4 + with: + path: pr-branch + + - name: Checkout target branch + uses: actions/checkout@v4 + with: + path: target-branch + ref: ${{ github.event_name == 'workflow_dispatch' && inputs.target_branch || github.base_ref }} + + - name: Checkout release branch + uses: actions/checkout@v4 + with: + path: release-branch + ref: release + + - name: Copy resolution-time app into target and release branches + run: | + cp -r pr-branch/apps/resolution-time target-branch/apps/resolution-time + cp -r pr-branch/apps/resolution-time release-branch/apps/resolution-time + + - name: Install dependencies (PR branch) + working-directory: pr-branch + run: pnpm install + + - name: Install dependencies (target branch) + working-directory: target-branch + run: pnpm install + + - name: Install dependencies (release branch) + working-directory: release-branch + run: pnpm install + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 24.x + cache: 'pnpm' + cache-dependency-path: | + pr-branch/pnpm-lock.yaml + target-branch/pnpm-lock.yaml + release-branch/pnpm-lock.yaml + + - name: Run benchmark on PR branch + working-directory: pr-branch + run: pnpm --filter resolution-time resolution-time + + - name: Run benchmark on target branch + working-directory: target-branch + run: pnpm --filter resolution-time resolution-time + continue-on-error: true + + - name: Run benchmark on release branch + working-directory: release-branch + run: pnpm --filter resolution-time resolution-time + continue-on-error: true + + - name: Generate charts + run: | + SCRIPT=pr-branch/apps/resolution-time/generateChart.ts + + DEPTH_ARGS="--input PR:pr-branch/apps/resolution-time/results-max-depth.json" + LINEAR_ARGS="--input PR:pr-branch/apps/resolution-time/results-linear-recursion.json" + + if [ -f target-branch/apps/resolution-time/results-max-depth.json ]; then + DEPTH_ARGS="$DEPTH_ARGS --input target:target-branch/apps/resolution-time/results-max-depth.json" + LINEAR_ARGS="$LINEAR_ARGS --input target:target-branch/apps/resolution-time/results-linear-recursion.json" + fi + + if [ -f release-branch/apps/resolution-time/results-max-depth.json ]; then + DEPTH_ARGS="$DEPTH_ARGS --input release:release-branch/apps/resolution-time/results-max-depth.json" + LINEAR_ARGS="$LINEAR_ARGS --input release:release-branch/apps/resolution-time/results-linear-recursion.json" + fi + + node $SCRIPT $DEPTH_ARGS --title "Resolution Time vs Max Depth" --xAxisTitle "max depth" --yAxisTitle "time (ms)" --output max-depth.md + node $SCRIPT $LINEAR_ARGS --title "Resolution Time vs Linear Recursion" --xAxisTitle "max depth" --yAxisTitle "time (ms)" --output linear-recursion.md + + - name: Build comment + run: | + { + echo '' + echo '## Resolution Time Benchmark' + echo '' + echo '### Max Depth (branching=2)' + cat max-depth.md + echo '' + echo '### Linear Recursion (branching=1)' + cat linear-recursion.md + } > comment.md + + - name: Comment PR with results + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const comment = fs.readFileSync('comment.md', 'utf8'); + + const botCommentIdentifier = ''; + + async function findBotComment(issueNumber) { + if (!issueNumber) return null; + const comments = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issueNumber, + }); + return comments.data.find((c) => + c.body.includes(botCommentIdentifier) + ); + } + + async function createOrUpdateComment(issueNumber) { + if (!issueNumber) { + console.log('No issue number provided. Cannot post or update comment.'); + return; + } + + const existingComment = await findBotComment(issueNumber); + if (existingComment) { + await github.rest.issues.updateComment({ + ...context.repo, + comment_id: existingComment.id, + body: comment, + }); + } else { + await github.rest.issues.createComment({ + ...context.repo, + issue_number: issueNumber, + body: comment, + }); + } + } + + const issueNumber = context.issue.number; + if (!issueNumber) { + console.log('No issue number found in context. Skipping comment.'); + } else { + await createOrUpdateComment(issueNumber); + } + await core.summary + .addRaw(comment) + .write();