Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 14 additions & 24 deletions .github/workflows/labeler.yml
Original file line number Diff line number Diff line change
@@ -1,31 +1,21 @@
name: labeler

on: [pull_request]
on:
pull_request:
types: [opened, reopened, synchronize]

Comment on lines +3 to 6
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
on:
pull_request:
types: [opened, reopened, synchronize]
on:
pull_request_target:

This is actually the only thing needed to fix this, imo. Because the codelytv/pr-size-labeler doesn't need the code checked out, but only uses github API metadata, it shouldn't be a security risk

jobs:
labeler:
permissions:
pull-requests: write
contents: read
issues: write
save-pr-number:
runs-on: ubuntu-latest
name: Label the PR size
name: Save PR number
steps:
- uses: codelytv/pr-size-labeler@4ec67706cd878fbc1c8db0a5dcd28b6bb412e85a # v1
- name: Save PR number
run: |
mkdir -p ./pr
echo ${{ github.event.pull_request.number }} > ./pr/pr_number.txt
- name: Upload PR number
uses: actions/upload-artifact@v4
with:
xs_label: "size/xs"
xs_max_size: "10"
s_label: "size/s"
s_max_size: "100"
m_label: "size/m"
m_max_size: "500"
l_label: "size/l"
l_max_size: "1000"
xl_label: "size/xl"
fail_if_xl: "false"
message_if_xl: >
This PR exceeds the recommended size of 1000 lines.
Please make sure you are NOT addressing multiple issues with one PR.
Note this PR might be rejected due to its size.
github_api_url: "https://api.github.com"
files_to_ignore: ""
name: pr_number
path: pr/
retention-days: 1
149 changes: 149 additions & 0 deletions .github/workflows/labeler_apply.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
name: labeler_apply

on:
workflow_run:
workflows: ["labeler"]
types:
- completed

jobs:
apply-labels:
permissions:
pull-requests: write
contents: read
issues: write
runs-on: ubuntu-latest
name: Apply PR size label
if: ${{ github.event.workflow_run.conclusion == 'success' }}
steps:
- name: Download PR number artifact
uses: dawidd6/action-download-artifact@bf251b5aa9c2f7eeb574a96ee720e24f801b7c11 # v6
with:
workflow: labeler.yml
run_id: ${{ github.event.workflow_run.id }}
name: pr_number
path: pr

- name: Read PR number
id: pr_number
run: |
PR_NUMBER=$(cat pr/pr_number.txt)
echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT

- name: Calculate PR size and apply label
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
with:
github-token: ${{ github.token }}
script: |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if only there would be an action that does already all this ( CodelyTV/pr-size-labeler@4ec6770 👀)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assumed that it needs different inputs now? Yeah:

codelytv/pr-size-labeler is designed to run on pull_request events directly and reads the PR number from github.event.pull_request.number.

In a workflow_run context, that event payload isn't available — the event is the workflow_run object instead, so the action wouldn't know which PR to label.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I commented that on Slack... but assumed htere is a reason why it couldn't just use that.

const prNumber = ${{ steps.pr_number.outputs.pr_number }};
const owner = context.repo.owner;
const repo = context.repo.repo;

// Get PR details
const pr = await github.rest.pulls.get({
owner,
repo,
pull_number: prNumber
});

// Get PR files to calculate size (with pagination)
let totalChanges = 0;
const iterator = github.paginate.iterator(
github.rest.pulls.listFiles,
{
owner,
repo,
pull_number: prNumber,
per_page: 100
}
);

// Calculate total changes (additions + deletions)
for await (const response of iterator) {
for (const file of response.data) {
totalChanges += file.additions + file.deletions;
}
}

console.log(`Total changes: ${totalChanges}`);

// Determine size label based on thresholds
let sizeLabel = '';
if (totalChanges <= 10) {
sizeLabel = 'size/xs';
} else if (totalChanges <= 100) {
sizeLabel = 'size/s';
} else if (totalChanges <= 500) {
sizeLabel = 'size/m';
} else if (totalChanges <= 1000) {
sizeLabel = 'size/l';
} else {
sizeLabel = 'size/xl';
}

console.log(`Determined size label: ${sizeLabel}`);

// Get current labels on the PR
const currentLabels = pr.data.labels.map(label => label.name);
console.log(`Current labels: ${currentLabels.join(', ')}`);

// Remove any existing size labels
const sizeLabels = ['size/xs', 'size/s', 'size/m', 'size/l', 'size/xl'];
for (const label of currentLabels) {
if (sizeLabels.includes(label)) {
console.log(`Removing old size label: ${label}`);
try {
await github.rest.issues.removeLabel({
owner,
repo,
issue_number: prNumber,
name: label
});
} catch (error) {
// Ignore error if label doesn't exist
console.log(`Could not remove label ${label}: ${error.message}`);
}
}
}

// Add the new size label
console.log(`Adding new size label: ${sizeLabel}`);
await github.rest.issues.addLabels({
owner,
repo,
issue_number: prNumber,
labels: [sizeLabel]
});

// Post warning comment if size is XL
if (sizeLabel === 'size/xl') {
const warningMessage = `This PR exceeds the recommended size of 1000 lines.
Please make sure you are NOT addressing multiple issues with one PR.
Note this PR might be rejected due to its size.`;

// Check if we've already posted this warning
const comments = await github.rest.issues.listComments({
owner,
repo,
issue_number: prNumber
});

const botComment = comments.data.find(comment =>
comment.user.type === 'Bot' &&
comment.body.includes('This PR exceeds the recommended size of 1000 lines')
);

if (!botComment) {
console.log('Posting XL warning comment');
await github.rest.issues.createComment({
owner,
repo,
issue_number: prNumber,
body: warningMessage
});
} else {
console.log('XL warning comment already exists');
}
}

console.log('Labeling completed successfully');