Skip to content

chore: added automatic title prefix #1

chore: added automatic title prefix

chore: added automatic title prefix #1

name: PR Labeller
on:
pull_request:
types: [opened, edited]
jobs:
label-pr:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4.2.2
- name: Update PR labels and title
uses: actions/github-script@v7.0.1
with:
script: |
const prBody = context.payload.pull_request.body;
const shouldHaveLabels = new Set();
const labelMappings = {
'Bug fix': 'Bug',
'New feature': 'Feature',
'UI/UX improvement': 'UI/UX',
'Weather data processing': 'Data Processing',
'Optimisation': 'Optimisation',
'Security': 'Security',
'Documentation update': 'Documentation',
'Chore': 'Chore'
};
const titlePrefixMappings = {
'Bug': 'fix',
'Feature': 'feat',
'UI/UX': 'ui',
'Data Processing': 'data',
'Optimisation': 'perf',
'Security': 'security',
'Documentation': 'docs',
'Chore': 'chore'
};
const validPrefixes = Object.values(titlePrefixMappings);
// Determine which labels should be present
for (const [text, label] of Object.entries(labelMappings)) {
if (prBody && prBody.includes(`- [x] ${text}`)) {
shouldHaveLabels.add(label);
}
}
// Get current labels
const currentLabels = await github.rest.issues.listLabelsOnIssue({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
});
const currentLabelNames = new Set(currentLabels.data.map(l => l.name));
const allMappedLabels = new Set(Object.values(labelMappings));
// Remove labels that shouldn't be there
const labelsToRemove = [...currentLabelNames].filter(label =>
allMappedLabels.has(label) && !shouldHaveLabels.has(label)
);
for (const label of labelsToRemove) {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
name: label
});
}
// Add missing labels
const labelsToAdd = [...shouldHaveLabels].filter(label =>
!currentLabelNames.has(label)
);
if (labelsToAdd.length > 0) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
labels: labelsToAdd
});
}
// Update PR title with prefix
const selectedLabel = [...shouldHaveLabels][0];
if (selectedLabel) {
const prefix = titlePrefixMappings[selectedLabel];
let currentTitle = context.payload.pull_request.title;
// Check if current title has any prefix (including non-standard ones)
const prefixMatch = currentTitle.match(/^([a-zA-Z]+):\s*/);
if (prefixMatch) {
const currentPrefix = prefixMatch[1].toLowerCase();
// Only update if current prefix is not the correct one
if (!validPrefixes.includes(currentPrefix) || currentPrefix !== prefix) {
currentTitle = currentTitle.replace(/^[a-zA-Z]+:\s*/, '');
const newTitle = `${prefix}: ${currentTitle}`;
await github.rest.pulls.update({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.payload.pull_request.number,
title: newTitle.toLowerCase()
});
}
} else {
// No prefix exists, add new one
const newTitle = `${prefix}: ${currentTitle}`;
await github.rest.pulls.update({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.payload.pull_request.number,
title: newTitle.toLowerCase()
});
}
}