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
129 changes: 129 additions & 0 deletions .github/workflows/add-files-changed-label.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
name: Add Files Changed Label

# Uses pull_request_target so it runs with base repo permissions for forked PRs.
# SECURITY: We do NOT check out or execute PR code. We only use the GitHub API.
on:
pull_request_target:
types:
- opened
- synchronize
- reopened
- ready_for_review
- edited

permissions:
pull-requests: write
issues: write

jobs:
add_files_changed_label:
runs-on: ubuntu-latest
steps:
- name: Add Files Changed Label
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const pr = context.payload.pull_request;
if (!pr) {
core.info('No pull_request in context. Skipping.');
return;
}

const owner = context.repo.owner;
const repo = context.repo.repo;
const pull_number = pr.number;

// Get all files (with pagination) and count them
const files = await github.paginate(github.rest.pulls.listFiles, {
owner,
repo,
pull_number,
per_page: 100,
});
const count = files.length;

// Determine the label based on the number of files changed
const newLabel = `files-changed: ${count}`;

// Set color based on the number of files changed
let labelColor;
if (count === 0) {
labelColor = 'cccccc'; // Gray
} else if (count === 1) {
labelColor = '0e8a16'; // Green
} else if (count >= 2 && count <= 5) {
labelColor = 'fbca04'; // Yellow
} else if (count >= 6 && count <= 10) {
labelColor = 'ff9800'; // Orange
} else {
labelColor = 'e74c3c'; // Red (project's preferred red color)
}

// Set grammatically correct description
const description = count === 1 ? 'PR changes 1 file' : `PR changes ${count} files`;

// Get current labels on the PR
const { data: current } = await github.rest.issues.listLabelsOnIssue({
owner,
repo,
issue_number: pull_number,
per_page: 100
});
const currentNames = new Set(current.map(l => l.name));

// Remove any existing files-changed labels
const filesChangedRegex = /^files-changed:/i;
for (const name of currentNames) {
if (filesChangedRegex.test(name) && name !== newLabel) {
try {
await github.rest.issues.removeLabel({
owner,
repo,
issue_number: pull_number,
name
});
core.info(`Removed label ${name}`);
} catch (err) {
core.warning(`Failed to remove label ${name}: ${err.message}`);
}
}
}

// Ensure the new label exists (create if missing)
async function ensureLabelExists(labelName) {
try {
await github.rest.issues.getLabel({ owner, repo, name: labelName });
} catch (e) {
if (e.status === 404) {
await github.rest.issues.createLabel({
owner,
repo,
name: labelName,
color: labelColor,
description: description,
});
core.info(`Created label ${labelName}`);
} else {
throw e;
}
}
}

await ensureLabelExists(newLabel);

// Add the label if it isn't already present
if (!currentNames.has(newLabel)) {
await github.rest.issues.addLabels({
owner,
repo,
issue_number: pull_number,
labels: [newLabel]
});
core.info(`Applied label ${newLabel} to PR #${pull_number}`);
} else {
core.info(`Label ${newLabel} already present on PR #${pull_number}`);
}

// Log the count for transparency
core.info(`PR #${pull_number} has ${count} changed file(s).`);
34 changes: 34 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: PR Validation

on:
pull_request:
branches: [ main ]

jobs:
validate:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Lint
run: npm run lint

- name: Format check
run: npm run format:check

- name: Run tests
run: npm test

- name: Security audit
run: npm audit --audit-level=high
Loading
Loading