Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions .github/ISSUE_TEMPLATE/tracking-issue.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# SPDX-FileCopyrightText: Copyright 2024 LG Electronics Inc.
# SPDX-License-Identifier: Apache-2.0

name: Tracking Issue (Merged PR)
description: Retroactively document a merged pull request that had no linked issue.
title: "[Tracking] "
labels: ["tracking", "needs-info"]
body:
- type: markdown
attributes:
value: |
Use this template to create a tracking issue for a pull request that was merged without a linked issue.
Fill in all sections to provide full context for the work that was done.

- type: input
id: pr_reference
attributes:
label: Merged Pull Request
description: Link to the merged PR (e.g. `#9`)
placeholder: "#9"
validations:
required: true

- type: textarea
id: what_changed
attributes:
label: What Was Changed
description: Summarize the changes introduced by the pull request.
placeholder: |
- Added X module
- Modified Y to support Z
- Removed deprecated W
validations:
required: true

- type: textarea
id: motivation
attributes:
label: Motivation / Context
description: Why was this change needed? What problem does it solve?
placeholder: Describe the background and motivation for the change.
validations:
required: true

- type: textarea
id: acceptance_criteria
attributes:
label: Acceptance Criteria
description: What conditions must be met for this issue to be considered resolved?
value: |
- [ ]
validations:
required: false

- type: checkboxes
id: testing
attributes:
label: Testing
options:
- label: Unit tests added or updated
- label: Integration tests added or updated
- label: Manual verification steps documented

- type: checkboxes
id: documentation
attributes:
label: Documentation
options:
- label: README updated if needed
- label: Architecture docs updated if needed
185 changes: 185 additions & 0 deletions .github/workflows/create-issue-for-merged-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
# SPDX-FileCopyrightText: Copyright 2024 LG Electronics Inc.
# SPDX-License-Identifier: Apache-2.0

name: Create Issue for Merged PR Without Linked Issue

on:
pull_request:
types: [closed]
workflow_dispatch:
inputs:
pr_numbers:
description: 'Comma-separated PR numbers to create issues for (e.g. "9,10,11")'
required: true
type: string

permissions:
issues: write
pull-requests: read

jobs:
process-merged-prs:
name: Create Tracking Issues for Merged PRs
runs-on: ubuntu-latest
# Run on PR merge or on manual dispatch
if: |
(github.event_name == 'pull_request' && github.event.pull_request.merged == true) ||
github.event_name == 'workflow_dispatch'

steps:
- name: Ensure required labels exist
uses: actions/github-script@v7
with:
script: |
const requiredLabels = [
{ name: 'tracking', color: '0075ca', description: 'Tracking issue for a merged PR' },
{ name: 'needs-info', color: 'e4e669', description: 'More information is needed to complete this issue' },
];
for (const label of requiredLabels) {
try {
await github.rest.issues.getLabel({
owner: context.repo.owner,
repo: context.repo.repo,
name: label.name,
});
} catch {
await github.rest.issues.createLabel({
owner: context.repo.owner,
repo: context.repo.repo,
name: label.name,
color: label.color,
description: label.description,
});
console.log(`Created label: ${label.name}`);
}
}

- name: Create tracking issues for merged PRs without linked issues
uses: actions/github-script@v7
with:
script: |
// ── Shared helpers ──────────────────────────────────────────────

const LINKED_ISSUE_PATTERN =
/(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\s+#\d+/gi;

function buildIssueBody(prNumber, prTitle, prAuthor, mergedBy, headRef, prBody) {
return [
`## Overview`,
``,
`This tracking issue was automatically created because **PR #${prNumber}** was merged without a linked issue.`,
`Please fill in the details below to document the work that was done.`,
``,
`## Merged PR Details`,
``,
`| Field | Value |`,
`|-------------|-------|`,
`| PR | #${prNumber} — ${prTitle} |`,
`| Author | @${prAuthor} |`,
`| Merged by | @${mergedBy} |`,
`| Branch | \`${headRef}\` |`,
``,
`## What Was Changed`,
``,
`<!-- Summarize the changes introduced by the PR -->`,
``,
`## Motivation / Context`,
``,
`<!-- Why was this change needed? What problem does it solve? -->`,
``,
`## Acceptance Criteria`,
``,
`- [ ] Describe expected behavior or outcomes`,
``,
`## Testing`,
``,
`- [ ] Unit tests added/updated`,
`- [ ] Integration tests added/updated`,
`- [ ] Manual verification steps documented`,
``,
`## Documentation`,
``,
`- [ ] README updated if needed`,
`- [ ] Architecture docs updated if needed`,
``,
`---`,
``,
`_Original PR description:_`,
``,
`<details>`,
`<summary>PR #${prNumber} body</summary>`,
``,
prBody || '_No description provided._',
``,
`</details>`,
].join('\n');
}

async function createTrackingIssue(prData) {
const { number: prNumber, title, user, merged_by, head, body } = prData;
const prBody = body || '';

if (LINKED_ISSUE_PATTERN.test(prBody)) {
console.log(`PR #${prNumber} already references linked issues. Skipping.`);
return;
}

const issueBody = buildIssueBody(
prNumber,
title,
user?.login || 'unknown',
merged_by?.login || 'unknown',
head?.ref || 'unknown',
prBody
);

const { data: issue } = await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `[Tracking] ${title}`,
body: issueBody,
labels: ['tracking', 'needs-info'],
});

console.log(
`Created tracking issue #${issue.number} for PR #${prNumber}: ${issue.html_url}`
);
}

// ── Event dispatch ────────────────────────────────────────────

if (context.eventName === 'pull_request') {
// Triggered automatically on PR merge
await createTrackingIssue(context.payload.pull_request);

} else if (context.eventName === 'workflow_dispatch') {
// Triggered manually to backfill issues for already-merged PRs
const rawInput = '${{ inputs.pr_numbers }}';
const prNumbers = rawInput
.split(',')
.map((n) => parseInt(n.trim(), 10))
.filter((n) => !isNaN(n));

if (prNumbers.length === 0) {
core.setFailed('No valid PR numbers provided.');
return;
}

for (const prNumber of prNumbers) {
console.log(`\nProcessing PR #${prNumber}...`);
try {
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber,
});
if (!pr.merged) {
console.log(`PR #${prNumber} is not merged. Skipping.`);
continue;
}
await createTrackingIssue(pr);
} catch (err) {
console.error(`Failed to process PR #${prNumber}: ${err.message}`);
}
}
}