|
| 1 | +#!/usr/bin/env node |
| 2 | + |
| 3 | +// This script validates that a PR title also contains its labels |
| 4 | +// in the title. This is a requirement, because this makes it easier |
| 5 | +// to parse commit messages. For example, for generating a changelog |
| 6 | +// for a particular platform. |
| 7 | +// Usage: |
| 8 | +// PR_TITLE="Make some changes to Android" PR_LABELS="android" node validate-pr-title.ts |
| 9 | + |
| 10 | +export function validateTitle({ |
| 11 | + title, |
| 12 | + labels |
| 13 | +}: { |
| 14 | + title: string, |
| 15 | + labels: Set<string> |
| 16 | +}): { ok: true } | { ok: false, mismatches: string[] } { |
| 17 | + // these labels are the ones we care about |
| 18 | + const keywords = new Set(['node', 'core', 'ios', 'android', 'qt']); |
| 19 | + |
| 20 | + // when labels includes core, only 'core' is required |
| 21 | + const requiredKeyWords = labels.has('core') |
| 22 | + ? new Set(['core']) |
| 23 | + : labels.intersection(keywords); |
| 24 | + |
| 25 | + title = title.toLocaleLowerCase(); |
| 26 | + |
| 27 | + const actualKeywords = new Set(); |
| 28 | + for (const keyword of requiredKeyWords) { |
| 29 | + if (title.includes(keyword)) actualKeywords.add(keyword); |
| 30 | + } |
| 31 | + |
| 32 | + const mismatches = requiredKeyWords.difference(actualKeywords); |
| 33 | + |
| 34 | + if (mismatches.size === 0) return { ok: true }; |
| 35 | + return { ok: false, mismatches: [...mismatches] }; |
| 36 | +} |
| 37 | + |
| 38 | +if (import.meta.main) { |
| 39 | + if (!process.env.PR_TITLE) { |
| 40 | + console.log('::error::PR_TITLE environment variable is not set'); |
| 41 | + process.exit(1); |
| 42 | + } |
| 43 | + |
| 44 | + if (!process.env.PR_LABELS) { |
| 45 | + console.log('::error::PR_LABELS environment variable is not set'); |
| 46 | + process.exit(1); |
| 47 | + } |
| 48 | + |
| 49 | + const title = process.env.PR_TITLE; |
| 50 | + const labelsString = process.env.PR_LABELS.toLowerCase(); |
| 51 | + const labels = new Set(labelsString.split(',').map(l => l.trim()).filter(l => l)); |
| 52 | + |
| 53 | + const result = validateTitle({ |
| 54 | + title, |
| 55 | + labels |
| 56 | + }); |
| 57 | + if (result.ok) { |
| 58 | + console.log('✅ PR labels match the title'); |
| 59 | + process.exit(0); |
| 60 | + } |
| 61 | + |
| 62 | + if (!result.ok) { |
| 63 | + if (result.mismatches.length > 0) { |
| 64 | + console.log(`::error::PR title does not match PR labels. Mismatched: ${result.mismatches.join(', ')}. Title: "${process.env.PR_TITLE}". Labels: "${process.env.PR_LABELS}"`); |
| 65 | + process.exit(1); |
| 66 | + } |
| 67 | + } |
| 68 | +} |
0 commit comments