Skip to content

ci: added workflow to check if issue is linked with pr #1

ci: added workflow to check if issue is linked with pr

ci: added workflow to check if issue is linked with pr #1

name: Check Linked Issue
on:
pull_request:
types: [opened, edited, synchronize, reopened]
jobs:
check-linked-issue:
runs-on: ubuntu-latest
name: Ensure PR has linked issue
steps:
- name: Check for linked issue
uses: actions/github-script@v7
with:
script: |
const { data: pullRequest } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number,
});
// Check PR body for issue references
const prBody = pullRequest.body || '';
const prTitle = pullRequest.title || '';
// Common patterns for linking issues
const issuePatterns = [
/(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\s+#(\d+)/gi,
/(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\s+(?:https?:\/\/github\.com\/[^\/]+\/[^\/]+\/issues\/)(\d+)/gi,
/#(\d+)/g,
/(?:issue|issues)\s+#?(\d+)/gi
];
let hasLinkedIssue = false;
let linkedIssues = new Set(); // Use Set to avoid duplicates
// Check PR body and title for issue references
const textToCheck = `${prTitle} ${prBody}`;
for (const pattern of issuePatterns) {
const matches = textToCheck.matchAll(pattern);
for (const match of matches) {
const issueNumber = match[1];
if (issueNumber) {
linkedIssues.add(issueNumber);
hasLinkedIssue = true;
}
}
}
// Check if PR is currently linked to issues via GitHub's API
try {
// Get the PR's linked issues using GraphQL API for more accurate results
const query = `
query($owner: String!, $repo: String!, $number: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $number) {
closingIssuesReferences(first: 10) {
nodes {
number
title
}
}
}
}
}
`;
const variables = {
owner: context.repo.owner,
repo: context.repo.repo,
number: context.issue.number
};
const result = await github.graphql(query, variables);
const closingIssues = result.repository.pullRequest.closingIssuesReferences.nodes;
if (closingIssues && closingIssues.length > 0) {
hasLinkedIssue = true;
const issueNumbers = closingIssues.map(issue => issue.number);
issueNumbers.forEach(num => linkedIssues.add(num.toString()));
console.log(`Found ${closingIssues.length} linked issue(s) via GitHub API: ${issueNumbers.join(', ')}`);
}
} catch (error) {
console.log('Could not fetch linked issues via GraphQL:', error.message);
// Fallback: Check timeline events but with better logic for current state
try {
const { data: timelineEvents } = await github.rest.issues.listEventsForTimeline({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
// Track connected and disconnected events to find current state
const connectionEvents = timelineEvents.filter(event =>
event.event === 'connected' || event.event === 'disconnected'
).sort((a, b) => new Date(a.created_at) - new Date(b.created_at));
// Check the current connection state by looking at the latest events per issue
const currentConnections = new Map();
for (const event of connectionEvents) {
if (event.source && event.source.issue) {
const issueId = event.source.issue.id;
if (event.event === 'connected') {
currentConnections.set(issueId, true);
} else if (event.event === 'disconnected') {
currentConnections.set(issueId, false);
}
}
}
// Check if any issues are currently connected
const hasCurrentConnections = Array.from(currentConnections.values()).some(connected => connected);
if (hasCurrentConnections) {
hasLinkedIssue = true;
console.log('Found currently linked issues via timeline events fallback');
}
} catch (timelineError) {
console.log('Could not fetch timeline events:', timelineError.message);
}
}
if (!hasLinkedIssue) {
core.setFailed(`❌ This pull request must be linked to an issue.
Please link this PR to an issue by:
1. Adding "Fixes #<issue-number>" or "Closes #<issue-number>" to the PR description
2. Using GitHub's UI to link the PR to an existing issue
3. Referencing the issue number with #<issue-number> in the PR title or description
Example: "Fixes #123" or "Closes #456"`);
} else {
const issueList = Array.from(linkedIssues).join(', ');
console.log(`✅ PR is linked to issue(s): ${issueList}`);
core.notice(`✅ Pull request is properly linked to issue(s): ${issueList}`);
}
- name: Add comment if no linked issue
if: failure()
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `## ❌ Missing Linked Issue
This pull request needs to be linked to at least one issue before it can be merged.
### How to link an issue:
1. **Add keywords to PR description:**
- \`Fixes #123\`
- \`Closes #456\`
- \`Resolves #789\`
- \`Fixes #123, #456, and #789\` (multiple issues)
2. **Reference issue in PR title or description:**
- \`#123\`
- \`Issue #456\`
- \`Addresses #123 and #456\` (multiple issues)
3. **Use GitHub's UI:**
- Go to the "Development" section in the right sidebar
- Click "Link an issue"
- Select the relevant issue(s)
💡 **Tip:** You can link multiple issues using any combination of the above methods!
Once you've linked at least one issue, this check will automatically pass! 🚀`
})