Skip to content

Feature: Entity Framework Core provider (BLite.EntityFrameworkCore) #1

Feature: Entity Framework Core provider (BLite.EntityFrameworkCore)

Feature: Entity Framework Core provider (BLite.EntityFrameworkCore) #1

name: Issue Pre-check
on:
issues:
types: [opened, reopened]
permissions:
issues: write
jobs:
precheck:
# Only run on real issues, not PRs converted to issues
if: github.event.issue.pull_request == null
runs-on: ubuntu-latest
steps:
- name: Validate and label issue
uses: actions/github-script@v7
with:
script: |
const body = context.payload.issue.body ?? '';
const labels = [];
const problems = [];
// ── Helpers ────────────────────────────────────────────────────────
/** Extract the content of a ### Section from the issue body. */
function section(heading) {
const re = new RegExp(
`###\\s+${heading.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\s*\\n([\\s\\S]*?)(?=\\n###|$)`,
'i'
);
const m = body.match(re);
return m ? m[1].trim() : '';
}
const PLACEHOLDER_RE = [
/^e\.g\./i,
/\/\/\s*paste your minimal repro here/i,
/\/\/\s*appsettings\.json snippet/i,
/\/\/\s*client code or test/i,
];
function isPlaceholder(text) {
return PLACEHOLDER_RE.some(re => re.test(text));
}
// ── Only validate bug reports (they have a "Minimal reproduction" section) ──
const isBugReport = body.includes('### Minimal reproduction');
if (!isBugReport) {
// Feature requests get a simple triage label
await github.rest.issues.addLabels({
...context.repo,
issue_number: context.issue.number,
labels: ['triage'],
});
return;
}
// ── Field checks ───────────────────────────────────────────────────
const version = section('BLite.Server version');
if (!version || isPlaceholder(version)) {
problems.push('**BLite.Server version** — missing or still contains the placeholder (e.g. `1.2.3`).');
}
const dotnet = section('.NET version');
if (!dotnet || isPlaceholder(dotnet)) {
problems.push('**\\.NET version** — missing or still contains the placeholder.');
}
const os = section('Operating system');
if (!os || isPlaceholder(os)) {
problems.push('**Operating system** — missing or still contains the placeholder.');
}
const description = section('Description');
if (!description || description.length < 15) {
problems.push('**Description** — too short or missing.');
}
const repro = section('Minimal reproduction');
if (!repro || repro.length < 30 || isPlaceholder(repro)) {
problems.push('**Minimal reproduction** — missing or appears to be just the placeholder. Please provide a small, self-contained snippet (config + client code or curl request).');
}
const expected = section('Expected behavior');
if (!expected || expected.length < 10) {
problems.push('**Expected behavior** — missing or too short.');
}
const actual = section('Actual behavior');
if (!actual || actual.length < 10) {
problems.push('**Actual behavior** — missing or too short.');
}
// ── Auto-label by Affected area ────────────────────────────────────
const area = section('Affected area').toLowerCase();
const areaMap = {
'grpc': 'area/grpc',
'rest api': 'area/rest',
'blazor studio': 'area/studio',
'authentication': 'area/auth',
'transaction': 'area/transactions',
'configuration': 'area/config',
};
for (const [key, label] of Object.entries(areaMap)) {
if (area.includes(key)) { labels.push(label); break; }
}
// ── Status label ───────────────────────────────────────────────────
labels.push(problems.length > 0 ? 'incomplete' : 'triage');
// ── Create labels (best-effort, ignore if they already exist) ──────
const labelDefs = {
'incomplete': { color: 'e11d48', description: 'Issue is missing required information' },
'triage': { color: '0ea5e9', description: 'Needs triage by a maintainer' },
'area/grpc': { color: '7c3aed', description: 'Affects the gRPC layer' },
'area/rest': { color: '7c3aed', description: 'Affects the REST API' },
'area/studio': { color: '7c3aed', description: 'Affects the Blazor Studio' },
'area/auth': { color: '7c3aed', description: 'Affects authentication or authorization' },
'area/transactions': { color: '7c3aed', description: 'Affects the transaction manager' },
'area/config': { color: '7c3aed', description: 'Affects configuration or startup' },
};
for (const label of labels) {
if (labelDefs[label]) {
try {
await github.rest.issues.createLabel({
...context.repo,
name: label,
...labelDefs[label],
});
} catch (_) { /* already exists */ }
}
}
await github.rest.issues.addLabels({
...context.repo,
issue_number: context.issue.number,
labels,
});
// ── Comment ────────────────────────────────────────────────────────
if (problems.length > 0) {
const list = problems.map(p => `- ${p}`).join('\n');
await github.rest.issues.createComment({
...context.repo,
issue_number: context.issue.number,
body: [
':wave: Thanks for opening this issue!',
'',
'It looks like some required information is missing or incomplete:',
'',
list,
'',
'Please **edit the issue** and fill in all the missing sections.',
'We will start the investigation once the issue is complete.',
].join('\n'),
});
} else {
await github.rest.issues.createComment({
...context.repo,
issue_number: context.issue.number,
body: ':wave: Thanks for the well-formed bug report! It has been added to the triage queue.',
});
}