Skip to content

fix: DockerFile

fix: DockerFile #184

name: Ensure PR has linked issue
on:
pull_request:
types: [opened, edited, synchronize, reopened]
workflow_dispatch:
jobs:
check-linked-issue:
name: Ensure PR has linked issue # 👈 Must EXACTLY match your branch protection rule!
runs-on: ubuntu-latest
steps:
- name: Ensure PR is linked to an issue
uses: actions/github-script@v7
with:
script: |
const query = `
query($owner: String!, $repo: String!, $number: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $number) {
title
body
closingIssuesReferences(first: 10) {
nodes {
number
state
}
}
}
}
}
`;
const { repository: { pullRequest: pr } } = await github.graphql(query, {
owner: context.repo.owner,
repo: context.repo.repo,
number: context.issue.number
});
// Check PR body for issue references
const prTitle = pr.title || '';
// Skip check for release PRs
if (prTitle.startsWith('release: v')) {
console.log('🔄 Skipping linked issue check for release PR');
core.notice('✅ Release PR - linked issue check skipped');
return;
}
const textToCheck = `${pr.title} ${pr.body || ''}`;
const issuePatterns = [
/(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\s+#(\d+)/gi,
/#(\d+)/g,
/(?:issue|issues)\s+#?(\d+)/gi,
];
const linkedIssues = new Set();
for (const pattern of issuePatterns) {
for (const match of textToCheck.matchAll(pattern)) {
if (match[1]) linkedIssues.add(match[1]);
}
}
pr.closingIssuesReferences.nodes.forEach(node => {
linkedIssues.add(node.number.toString());
});
if (linkedIssues.size === 0) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: "## 🚫 Missing Linked Issue\n\nHi 👋 This pull request does not appear to be linked to any open issue yet.\n\nLinking your PR to an issue helps keep the project tidy and ensures the issue is closed automatically.\n\n### ✔️ How to fix this\n\n- Add a keyword like `Fixes #123` or `Closes #456` to your PR **description** or a **commit message**.\n- Or link it manually using the **\"Linked issues\"** panel in the PR sidebar.\n\n> ✅ **Tip:** You can link multiple issues.\n> 🚫 **Note:** If only one issue is linked, it must be open for this check to pass.\n\nOnce linked, this check will pass automatically on your next push or when you re-run the workflow.\n\nThanks for helping maintainers! 🙌"
});
core.setFailed('❌ No linked issue found.');
return;
}
let openIssues = 0;
for (const issueNumber of linkedIssues) {
const issueQuery = `
query($owner: String!, $repo: String!, $number: Int!) {
repository(owner: $owner, name: $repo) {
issue(number: $number) {
state
}
}
}
`;
const { repository: { issue } } = await github.graphql(issueQuery, {
owner: context.repo.owner,
repo: context.repo.repo,
number: parseInt(issueNumber, 10)
});
if (issue.state === 'OPEN') {
openIssues++;
}
}
if (linkedIssues.size === 1 && openIssues === 0) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: "## 🚫 Linked Issue is Closed\n\nHi 👋 This pull request links only **one issue**, but that issue is **closed**.\n\nTo pass this check, the linked issue must be **open** — or link an additional open issue.\n\n### ✔️ How to fix this\n\n- Reopen the linked issue if appropriate.\n- Or link another relevant **open** issue via the PR description or the **\"Linked issues\"** panel.\n\nThanks for keeping the project healthy! 🚀"
});
core.setFailed('❌ Linked issue is closed.');
} else {
console.log(`✅ PR is linked to issue(s): ${Array.from(linkedIssues).join(', ')}`);
console.log(`✅ Number of open issues: ${openIssues}`);
}