Skip to content
Closed
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
101 changes: 101 additions & 0 deletions .github/actions/triage-issues/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
name: "triage-issue"
Copy link

Copilot AI Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The composite action is named "triage-issue" (singular) in the action metadata, but the directory name is "triage-issues" (plural). This naming inconsistency can cause confusion. Consider making them consistent - either both singular or both plural.

Suggested change
name: "triage-issue"
name: "triage-issues"

Copilot uses AI. Check for mistakes.
description: "Composite action to create monthly triage issue and optionally close previous month"
inputs:
close-previous:
description: "Whether to close last month’s triage issue (true/false)"
required: false
default: "true"
label:
description: "Label to apply to triage issue"
required: false
default: "triage"
body-template:
description: "Custom body template (supports {{MONTH}} placeholder)"
required: false
default: |
### Monthly GitHub Triage – {{MONTH}}

This automatically generated issue tracks triage activities for {{MONTH}}.

**Purpose**
- Collect new issues for classification.
- Track placeholders.
- Consolidate duplicates.

**Automation**
- Weekly summary comments (companion workflow).
- Future enhancements: stale detection, cross-links.

:octocat: :copilot: Created automatically.
runs:
using: "composite"
steps:
- name: Compute dates
id: dates
shell: bash
run: |
CURR=$(date -u +'%Y-%m')
PREV=$(date -u -d "$(date -u +%Y-%m-01) -1 month" +'%Y-%m')
echo "curr=$CURR" >> $GITHUB_OUTPUT
echo "prev=$PREV" >> $GITHUB_OUTPUT

- name: Ensure triage issue
uses: actions/github-script@v7
with:
script: |
const closePrev = (process.env.INPUT_CLOSE_PREVIOUS || 'true').toLowerCase() === 'true';
const label = process.env.INPUT_LABEL || 'triage';
const bodyTemplate = process.env.INPUT_BODY_TEMPLATE;
const curr = '${{ steps.dates.outputs.curr }}';
const prev = '${{ steps.dates.outputs.prev }}';
const currTitle = `GitHub Triage: ${curr}`;
const prevTitle = `GitHub Triage: ${prev}`;

async function findIssue(title) {
const perPage = 100;
for (let page = 1; page < 50; page++) {
const { data } = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'all',
per_page: perPage,
page
});
if (!data.length) break;
const hit = data.find(i => i.title === title);
if (hit) return hit;
if (data.length < perPage) break;
}
return null;
}

if (closePrev) {
const prevIssue = await findIssue(prevTitle);
if (prevIssue && prevIssue.state === 'open') {
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prevIssue.number,
state: 'closed'
});
core.info(`Closed previous triage issue #${prevIssue.number} (${prevTitle})`);
} else {
core.info(`Previous triage issue not open or not found (${prevTitle}).`);
}
}

const currIssue = await findIssue(currTitle);
if (currIssue) {
core.info(`Current triage issue already exists: #${currIssue.number}`);
return;
}

const body = bodyTemplate.replace(/{{MONTH}}/g, curr);
const created = await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: currTitle,
body,
labels: [label]
});
core.notice(`Created triage issue #${created.data.number} (${currTitle}).`);
Comment on lines +42 to +101
Copy link

Copilot AI Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The composite action reads inputs via environment variables (e.g., process.env.INPUT_CLOSE_PREVIOUS, process.env.INPUT_LABEL, process.env.INPUT_BODY_TEMPLATE), but these environment variables are never set. In GitHub Actions, inputs need to be explicitly passed as environment variables using the env key in the step. Without this, the script will use default values or undefined behavior.

Copilot uses AI. Check for mistakes.
54 changes: 54 additions & 0 deletions .github/monthly-instructions.md

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typically docs are not put inside the .github folder.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. Having read this more, I think it was just your prompt for Copilot to build the scripts. If that is the case, I would not commit this. I totally thought I should read this first, thinking it was the documentation for the above workflow files.

Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Below is a consolidated, step-by-step guide and the complete, updated code to implement an automated process that:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would change this to an actual title, so I know what it does. Right now, this is super generic title.


- Ensures a monthly “GitHub Triage: YYYY-MM” issue exists and closes last month’s issue if still open
- Posts weekly comments to the current month’s triage issue, listing and categorizing issues opened in the last 7 days, with each issue reference on its own line
- Provides a reusable composite action for triage issue creation/closing
- Offers a workflow that uses the composite action
- Follow the steps and use the files exactly as provided.

# Step-by-step implementation guide

1. Choose your branch and prepare directories
- Decide your branch (example: update-monthly-review).
- Ensure you have the following directories:
- .github/workflows
- .github/actions/triage-issue

2. Add the monthly triage workflow (creates current month’s triage issue and closes previous)
- This workflow runs monthly. It ensures an issue titled “GitHub Triage: YYYY-MM” exists and closes last month’s triage issue if it is still open.

3. Add the weekly triage comment workflow
- This runs weekly and posts a comment to the current month’s triage issue with:
- Counts by category
- A list of each new issue in the last 7 days with one line per issue (e.g., “- #223”)
- A note that Mona (Copilot) reviewed
- It uses JavaScript via actions/github-script and the GitHub Search API (created:>=YYYY-MM-DD).

4. Add the reusable composite action
- Encapsulates logic to:
- Optionally close last month’s triage issue
Copy link

Copilot AI Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: "Optionaly" should be "Optionally".

Copilot uses AI. Check for mistakes.
-Create the current month’s triage issue
Copy link

Copilot AI Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing space after hyphen. Should be "- Create the current month's triage issue" (with a space after the hyphen).

Suggested change
-Create the current month’s triage issue
- Create the current month’s triage issue

Copilot uses AI. Check for mistakes.
- This makes future reuse and refactoring easier.

5. Add a workflow that uses the composite action
- Example monthly workflow that calls the composite action instead of embedding the logic directly.
- Useful for decoupling and reusability.

6. Commit and push
- Add all files.
- Commit with a message, such as: add monthly triage + weekly review workflows
- Push to your branch.

7. Validate and optionally trigger
- Go to the GitHub repository’s Actions tab.
- Confirm workflows are present.
- Manually trigger them if desired via workflow_dispatch.
- Confirm labels and issue creation/comments work.

8. Future enhancements
- Pagination beyond 1000 items if needed.
- Slack/Teams notifications.
- GraphQL query optimization for exact-title lookups.
- NLP-based categorization improvements.
- JSON artifact uploads for reports and dashboards.
- Templating: externalize comment templates into env vars or repository files.
97 changes: 97 additions & 0 deletions .github/workflows/auto-triage-issue.yml

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you could integrate this directly into weekly-content-review.yml. That workflow already a check that throws an error if the issue does exist. So, instead of throwing an error, it would just trigger the issue to be created first.

In that case, I think you could also get rid of triage-issues/action.yml and use-composite-triage.yml‎. :)

Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
name: Auto Create Monthly GitHub Triage Issue (Create + Close Previous)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I misinterpreted the name of this file and the title.
I was a bit confused how you can triage "1" issue. Coming in I figured you meant to make it plural.
Now, I get that it is creating a new issue.


on:
schedule:
- cron: '5 7 1 * *' # 07:05 UTC on the 1st day of each month
workflow_dispatch:

permissions:
issues: write
contents: read

jobs:
ensure-triage-issue:
runs-on: ubuntu-latest
steps:
- name: Compute date context
id: dates
run: |
YEAR_MONTH=$(date -u +'%Y-%m')
PREV_YEAR_MONTH=$(date -u -d "$(date -u +%Y-%m-01) -1 month" +'%Y-%m')
echo "year_month=$YEAR_MONTH" >> $GITHUB_OUTPUT
echo "prev_year_month=$PREV_YEAR_MONTH" >> $GITHUB_OUTPUT

- name: Create current triage & close previous
uses: actions/github-script@v7
with:
script: |
const current = core.getInput('current') || '${{ steps.dates.outputs.year_month }}';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit confused. This workflow has no inputs. Where is "current" coming from?
Does this actually run?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, generic variables again. Current issue?, Current Date?

const previous = core.getInput('previous') || '${{ steps.dates.outputs.prev_year_month }}';
const currentTitle = `GitHub Triage: ${current}`;
const previousTitle = `GitHub Triage: ${previous}`;

async function findIssueByExactTitle(title) {
const perPage = 100;
for (let page = 1; page < 50; page++) {
const { data } = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'all',
per_page: perPage,
page
});
if (!data.length) break;
const hit = data.find(i => i.title === title);
if (hit) return hit;
if (data.length < perPage) break;
}
return null;
Comment on lines +34 to +48
Copy link

Copilot AI Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pagination logic iterates through up to 5000 issues (50 pages × 100 per page) to find a single issue by exact title match. This is inefficient and will result in many unnecessary API calls. Consider using the GitHub Search API with a query like repo:owner/repo is:issue "${title}" to find the issue directly, which would be a single API call instead of potentially many.

Suggested change
const perPage = 100;
for (let page = 1; page < 50; page++) {
const { data } = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'all',
per_page: perPage,
page
});
if (!data.length) break;
const hit = data.find(i => i.title === title);
if (hit) return hit;
if (data.length < perPage) break;
}
return null;
// Use GitHub Search API for efficiency
const query = [
`repo:${context.repo.owner}/${context.repo.repo}`,
'is:issue',
'in:title',
`"${title.replace(/"/g, '\\"')}"`
].join(' ');
const { data } = await github.rest.search.issuesAndPullRequests({
q: query,
per_page: 10,
});
const hit = data.items.find(i => i.title === title);
return hit || null;

Copilot uses AI. Check for mistakes.
}
Comment on lines +33 to +49
Copy link

Copilot AI Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The findIssueByExactTitle function logic is duplicated across multiple files (here and in weekly-content-review.yml line 32-48, and triage-issues/action.yml line 54-70). This duplication makes maintenance harder as any bug fixes or improvements need to be applied in multiple places. Consider consolidating this logic into a shared GitHub Action or a reusable JavaScript module.

Copilot uses AI. Check for mistakes.

// Close previous month issue if open
const prevIssue = await findIssueByExactTitle(previousTitle);
if (prevIssue && prevIssue.state === 'open') {
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prevIssue.number,
state: 'closed'
});
core.notice(`Closed previous triage issue #${prevIssue.number} (${previousTitle}).`);
} else {
core.info(`No open previous triage issue to close (title: ${previousTitle}).`);
}

// Ensure current month issue
const currIssue = await findIssueByExactTitle(currentTitle);
if (currIssue) {
core.info(`Current triage issue already exists: #${currIssue.number}`);
return;
}

const body = `
### Monthly GitHub Triage – ${current}

Automatically generated tracking issue for ${current}.

#### Purpose
- Collect newly opened issues for classification.
- Track placeholders (titles containing \`[REPLACE_WITH_MODULE_TITLE]\`).
- Identify consolidation / closure candidates.

#### Actions
- Apply governance labels.
- Escalate support or experience issues.
- Prepare weekly summaries (see companion workflow).

:octocat: :copilot: Created automatically.
`.trim();

const created = await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: currentTitle,
body,
labels: ['triage']
});
core.notice(`Created new triage issue #${created.data.number} (${currentTitle}).`);
29 changes: 29 additions & 0 deletions .github/workflows/use-composite-triage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Monthly Triage via Composite Action

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend keeping the workflow name and file name the same. This makes it easier to identify from the Actions tab to the actual file.


on:
schedule:
- cron: '2 7 1 * *' # 07:02 UTC on 1st day of month
workflow_dispatch:

permissions:
issues: write

jobs:
triage:
runs-on: ubuntu-latest
steps:
Copy link

Copilot AI Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workflow references a local composite action at ./.github/actions/triage-issue, but there's no actions/checkout@v4 step before it. Without checking out the repository, the local action files won't be available, causing the workflow to fail. Add a checkout step before line 15.

Suggested change
steps:
steps:
- name: Check out repository
uses: actions/checkout@v4

Copilot uses AI. Check for mistakes.
- name: Run composite triage action
uses: ./.github/actions/triage-issue
Copy link

Copilot AI Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The composite action path referenced here (triage-issue) doesn't match the actual directory name (triage-issues with an 's'). This will cause the workflow to fail when trying to locate the action. The path should be ./.github/actions/triage-issues.

Suggested change
uses: ./.github/actions/triage-issue
uses: ./.github/actions/triage-issues

Copilot uses AI. Check for mistakes.
with:
close-previous: "true"
label: "triage"
body-template: |

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good use of putting the template in the ENV area. Makes it much easier to read and update without worry of breaking the script.

### Monthly GitHub Triage – {{MONTH}}
Auto-created via composite action.

**Goals**
- Classify new issues
- Close stale placeholders
- Prepare weekly summary comments

:octocat: :copilot: Automation initialized.
Loading