Skip to content

✨(web) add 2FA authentication on Django admin #147

✨(web) add 2FA authentication on Django admin

✨(web) add 2FA authentication on Django admin #147

name: PR Fields Check
on:
pull_request:
types: [opened, synchronize, reopened, edited, ready_for_review, labeled, unlabeled]
merge_group:
permissions:
pull-requests: read
jobs:
check-pr-fields:
runs-on: ubuntu-latest
steps:
- name: Check PR fields
# GH_TOKEN must be a PAT with read:project scope to query GitHub Projects v2
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.GH_TOKEN || github.token }}
script: |
const validLabels = new Set([
'breaking', 'added', 'modified', 'removed', 'bugfix', 'dependencies', 'documentation'
]);
const labels = context.payload.pull_request.labels.map(l => l.name);
const matching = labels.filter(l => validLabels.has(l));
if (matching.length !== 1) {
core.setFailed(
`This pull request must have exactly one changelog label (${[...validLabels].join(', ')}). Found: ${matching.length === 0 ? 'none' : matching.join(', ')}.`
);
return;
}
const { owner, repo } = context.repo;
const prNumber = context.payload.pull_request.number;
const query = `
query($owner: String!, $repo: String!, $number: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $number) {
closingIssuesReferences(first: 10) {
totalCount
}
projectItems(first: 10) {
nodes {
project {
title
}
fieldValues(first: 30) {
nodes {
... on ProjectV2ItemFieldSingleSelectValue {
name
field { ... on ProjectV2FieldCommon { name } }
}
... on ProjectV2ItemFieldIterationValue {
title
field { ... on ProjectV2FieldCommon { name } }
}
... on ProjectV2ItemFieldTextValue {
text
field { ... on ProjectV2FieldCommon { name } }
}
... on ProjectV2ItemFieldNumberValue {
number
field { ... on ProjectV2FieldCommon { name } }
}
}
}
}
}
}
}
}
`;
const result = await github.graphql(query, { owner, repo, number: prNumber });
const pr = result.repository.pullRequest;
const linkedIssuesCount = pr.closingIssuesReferences.totalCount;
const projectItems = pr.projectItems.nodes;
const hasDevelopment = linkedIssuesCount > 0;
const hasProjects = projectItems.length > 0;
if (!hasDevelopment && !hasProjects) {
core.setFailed(
'This pull request must have either the "Development" field (a linked issue) or be added to a "Projects" board.'
);
return;
}
if (hasProjects) {
const requiredFields = ['Importance', 'Size', 'Iteration', 'Epic'];
const errors = [];
for (const item of projectItems) {
const filledFields = new Set();
for (const fieldValue of item.fieldValues.nodes) {
const fieldName = fieldValue.field?.name;
if (!fieldName) continue;
const value = fieldValue.name ?? fieldValue.title ?? fieldValue.text ?? fieldValue.number;
if (value !== null && value !== undefined) {
filledFields.add(fieldName);
}
}
const missingFields = requiredFields.filter(f => !filledFields.has(f));
if (missingFields.length > 0) {
errors.push(
`Project "${item.project.title}" is missing required fields: ${missingFields.join(', ')}.`
);
}
}
if (errors.length > 0) {
core.setFailed(errors.join('\n'));
}
}