Added ticket refinement bot #4
53
.github/issue_template/ai-refinement.md
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
---
|
||||
|
ztimson marked this conversation as resolved
|
||||
|
||||
name: "AI refinement"
|
||||
about: "Use AI to refine ticket"
|
||||
ref: "develop"
|
||||
labels:
|
||||
- Review/AI
|
||||
|
||||
---
|
||||
|
||||
# [Module] - [Add/Change/Fix/Refactor/Remove] [Feature/Component]
|
||||
|
||||
|
assistant
commented
The Type field shows format '[Bug/DevOps/Enhancement/Refactor/Security]' which suggests selecting one option, but the parsing code expects 'Type: Bug' format. This mismatch between template and parsing logic will cause issues. Clarify the expected format. The Type field shows format '[Bug/DevOps/Enhancement/Refactor/Security]' which suggests selecting one option, but the parsing code expects 'Type: Bug' format. This mismatch between template and parsing logic will cause issues. Clarify the expected format.
|
||||
## Type: [Bug/DevOps/Enhancement/Refactor/Security]
|
||||
|
||||
| | Score |
|
||||
|------------|----------|
|
||||
| Size | 0-5 |
|
||||
| Complexity | 0-5 |
|
||||
| Unknowns | 0-5 |
|
||||
| **Total** | **0-15** |
|
||||
|
||||
## Description
|
||||
|
||||
A clear explanation of the issue, feature, or change needed
|
||||
|
||||
## Current Behavior
|
||||
|
||||
For bugs: what's happening now
|
||||
For refactors: what exists today
|
||||
For enhancements: current state/gap
|
||||
|
||||
## Expected Behavior
|
||||
|
||||
What should happen instead
|
||||
|
||||
## Steps to Reproduce
|
||||
|
||||
1. First step
|
||||
2. Second step
|
||||
3. Third step
|
||||
|
||||
## Additional Context
|
||||
|
||||
Logs, screenshots, links, related issues
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] Todo requirement
|
||||
- [X] Completed requirement
|
||||
|
ztimson marked this conversation as resolved
assistant
commented
Confusing checkbox example: The template shows Confusing checkbox example: The template shows `- [X] Completed requirement` which suggests a completed item, but this is meant to be a template for new tickets. This might confuse users. Consider using only unchecked examples `- [ ]` or clarifying with a comment.
|
||||
|
||||
## Technical Notes
|
||||
|
||||
Implementation details, constraints, dependencies, design decisions
|
||||
@@ -1,4 +1,5 @@
|
||||
name: Code review
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
26
.github/workflows/ticket-refinement.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
name: Ticket refinement
|
||||
|
||||
on:
|
||||
issues:
|
||||
|
assistant
commented
The workflow triggers on both 'opened' and 'labeled' events, which could cause the workflow to run twice if an issue is opened with the Review/AI label already applied. Consider adding a condition to check if the specific label was added. The workflow triggers on both 'opened' and 'labeled' events, which could cause the workflow to run twice if an issue is opened with the Review/AI label already applied. Consider adding a condition to check if the specific label was added.
|
||||
types: [opened, labeled]
|
||||
|
ztimson marked this conversation as resolved
assistant
commented
Missing conditional check: The workflow triggers on both 'opened' and 'labeled' events, but there's no conditional to prevent it from running twice when an issue is opened with the 'Review/AI' label already attached. Consider adding an Missing conditional check: The workflow triggers on both 'opened' and 'labeled' events, but there's no conditional to prevent it from running twice when an issue is opened with the 'Review/AI' label already attached. Consider adding an `if` condition to check the label state.
assistant
commented
The workflow triggers on both 'opened' and 'labeled' events, but doesn't filter for the specific label. This means it will run for ANY label addition. Consider adding a condition to only run when the 'Review/AI' label is added: The workflow triggers on both 'opened' and 'labeled' events, but doesn't filter for the specific label. This means it will run for ANY label addition. Consider adding a condition to only run when the 'Review/AI' label is added: `if: contains(github.event.issue.labels.*.name, 'Review/AI')`.
|
||||
jobs:
|
||||
format:
|
||||
runs-on: ubuntu-latest
|
||||
container: node:22
|
||||
steps:
|
||||
- name: Fetch code
|
||||
run: |
|
||||
|
ztimson marked this conversation as resolved
assistant
commented
Security concern: Using Security concern: Using `github.token` for git clone authentication may not have sufficient permissions. The workflow later uses `secrets.ASSISTANT_TOKEN` for API calls. Consider using the same token for consistency and proper permissions, or document why different tokens are needed.
assistant
commented
Using 'github.token' in the git clone URL may not have sufficient permissions to push changes or may not be the intended token. The workflow uses 'secrets.ASSISTANT_TOKEN' for API calls (line 25) but 'github.token' for cloning. Consider using the same token for consistency, or document why different tokens are needed. Using 'github.token' in the git clone URL may not have sufficient permissions to push changes or may not be the intended token. The workflow uses 'secrets.ASSISTANT_TOKEN' for API calls (line 25) but 'github.token' for cloning. Consider using the same token for consistency, or document why different tokens are needed.
|
||||
git clone "$(echo ${{github.server_url}}/${{github.repository}}.git | sed s%://%://${{github.token}}@% )" .
|
||||
|
ztimson marked this conversation as resolved
assistant
commented
The git clone command uses shell parameter expansion which could fail if github.token contains special characters. Consider using GitHub Actions' built-in checkout action instead: The git clone command uses shell parameter expansion which could fail if github.token contains special characters. Consider using GitHub Actions' built-in checkout action instead: `actions/checkout@v4`.
assistant
commented
The git clone command uses sed to inject the token, but this approach is fragile and exposes the token in process lists. Consider using git credential helpers or the safer 'actions/checkout@v4' action instead. The git clone command uses sed to inject the token, but this approach is fragile and exposes the token in process lists. Consider using git credential helpers or the safer 'actions/checkout@v4' action instead.
|
||||
git checkout ${{ github.event.repository.default_branch }}
|
||||
|
||||
- name: Run AI Formatter
|
||||
|
ztimson marked this conversation as resolved
assistant
commented
Path mismatch: The workflow references Path mismatch: The workflow references `.github/issue_templates/ai-refinement.md` but the actual file is located at `.github/issue_template/ai-refinement.md` (singular "template" not "templates"). This will cause the workflow to fail when trying to read the template file.
assistant
commented
Command name mismatch: The workflow runs Command name mismatch: The workflow runs `npx -y @ztimson/ai-agents@latest format` but according to package.json, the binary is named "refine", not "format". This should be `npx -y @ztimson/ai-agents@latest refine`.
assistant
commented
The workflow calls 'format' subcommand but package.json defines 'refine' as the binary name. This mismatch will cause the workflow to fail. Either change the command to 'npx -y @ztimson/ai-agents@latest refine' or update package.json to use 'format' as the binary name. The workflow calls 'format' subcommand but package.json defines 'refine' as the binary name. This mismatch will cause the workflow to fail. Either change the command to 'npx -y @ztimson/ai-agents@latest refine' or update package.json to use 'format' as the binary name.
|
||||
run: npx -y @ztimson/ai-agents@latest refine .github/issue_template/ai-refinement.md
|
||||
env:
|
||||
AI_HOST: anthropic
|
||||
|
ztimson marked this conversation as resolved
assistant
commented
Invalid model name: Invalid model name: `claude-sonnet-4-5` is not a valid Anthropic model name. It should likely be `claude-sonnet-4` or `claude-3-5-sonnet-20241022` (or similar valid Anthropic model identifier).
assistant
commented
The AI_MODEL value 'claude-sonnet-4-5' appears incorrect. Claude model names typically use format like 'claude-sonnet-4-20250514' or 'claude-3-5-sonnet-20241022'. Verify this is a valid model identifier. The AI_MODEL value 'claude-sonnet-4-5' appears incorrect. Claude model names typically use format like 'claude-sonnet-4-20250514' or 'claude-3-5-sonnet-20241022'. Verify this is a valid model identifier.
|
||||
AI_MODEL: claude-sonnet-4-5
|
||||
|
ztimson marked this conversation as resolved
assistant
commented
Hardcoded AI model "claude-sonnet-4-5" appears to be incorrect. The correct model name should be "claude-sonnet-4" or "claude-3-5-sonnet-20240620" based on Anthropic's naming conventions. This will cause API errors. Hardcoded AI model "claude-sonnet-4-5" appears to be incorrect. The correct model name should be "claude-sonnet-4" or "claude-3-5-sonnet-20240620" based on Anthropic's naming conventions. This will cause API errors.
|
||||
AI_TOKEN: ${{ secrets.ANTHROPIC_TOKEN }}
|
||||
GIT_HOST: ${{ github.server_url }}
|
||||
GIT_OWNER: ${{ github.repository_owner }}
|
||||
GIT_REPO: ${{ github.event.repository.name }}
|
||||
|
assistant
commented
Using github.token for git operations but secrets.ASSISTANT_TOKEN for API calls creates confusion. If ASSISTANT_TOKEN has the necessary permissions, use it consistently. Otherwise, document why two different tokens are needed. Using github.token for git operations but secrets.ASSISTANT_TOKEN for API calls creates confusion. If ASSISTANT_TOKEN has the necessary permissions, use it consistently. Otherwise, document why two different tokens are needed.
|
||||
GIT_TOKEN: ${{ secrets.ASSISTANT_TOKEN }}
|
||||
TICKET: ${{ github.event.issue.number }}
|
||||
@@ -1,12 +1,13 @@
|
||||
{
|
||||
"name": "@ztimson/ai-agents",
|
||||
"version": "0.0.3",
|
||||
"version": "0.0.4",
|
||||
"description": "AI agents",
|
||||
"keywords": ["ai", "review"],
|
||||
"author": "ztimson",
|
||||
"license": "ISC",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
"refine": "./src/refine.mjs",
|
||||
"review": "./src/review.mjs"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
110
src/refine.mjs
Normal file
@@ -0,0 +1,110 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import {Ai} from '@ztimson/ai-utils';
|
||||
import * as os from 'node:os';
|
||||
import * as dotenv from 'dotenv';
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
|
||||
dotenv.config({quiet: true});
|
||||
dotenv.config({path: '.env.local', override: true, quiet: true});
|
||||
|
||||
(async () => {
|
||||
|
assistant
commented
The entire script is wrapped in an async IIFE without proper error handling. If any unhandled error occurs, it will cause an unhandled promise rejection. Add a .catch() block at the end to handle errors gracefully. The entire script is wrapped in an async IIFE without proper error handling. If any unhandled error occurs, it will cause an unhandled promise rejection. Add a .catch() block at the end to handle errors gracefully.
|
||||
let p = process.argv[process.argv.length - 1];
|
||||
|
ztimson marked this conversation as resolved
assistant
commented
Wrong script name in condition: The check Wrong script name in condition: The check `if(p === 'review' || p.endsWith('review.mjs'))` should be `if(p === 'refine' || p.endsWith('refine.mjs'))` since this is the refine.mjs script, not review.mjs.
|
||||
if(p === 'refine' || p.endsWith('refine.mjs')) p = null;
|
||||
|
ztimson marked this conversation as resolved
assistant
commented
The path detection regex '/(\/|[A-Z]:)/.test(p)' checks if the path is absolute, but the logic is inverted - if it's NOT absolute, it joins with cwd. However, this doesn't handle edge cases like './' or '../' relative paths correctly, which would be treated as absolute due to the '/' character. The path detection regex '/(\\/|[A-Z]:)/.test(p)' checks if the path is absolute, but the logic is inverted - if it's NOT absolute, it joins with cwd. However, this doesn't handle edge cases like './' or '../' relative paths correctly, which would be treated as absolute due to the '/' character.
assistant
commented
Path validation regex uses 'm' flag unnecessarily. The multiline flag isn't needed for this single-line path check. Also, the regex doesn't handle relative paths starting with './' or '../' which are valid. Path validation regex uses 'm' flag unnecessarily. The multiline flag isn't needed for this single-line path check. Also, the regex doesn't handle relative paths starting with './' or '../' which are valid.
|
||||
if(!/^(\/|[A-Z]:)/m.test(p)) p = path.join(process.cwd(), p);
|
||||
|
||||
if(!p || !fs.existsSync(p)) throw new Error('Please provide a template');
|
||||
|
||||
|
assistant
commented
Missing validation for required environment variables. If any of git, owner, repo, auth, ticket, host, model, or token are undefined, the script will fail with unclear error messages. Add validation and provide helpful error messages for missing configuration. Missing validation for required environment variables. If any of git, owner, repo, auth, ticket, host, model, or token are undefined, the script will fail with unclear error messages. Add validation and provide helpful error messages for missing configuration.
|
||||
const git = process.env['GIT_HOST'],
|
||||
owner = process.env['GIT_OWNER'],
|
||||
repo = process.env['GIT_REPO'],
|
||||
auth = process.env['GIT_TOKEN'],
|
||||
ticket = process.env['TICKET'],
|
||||
host = process.env['AI_HOST'],
|
||||
model = process.env['AI_MODEL'],
|
||||
token = process.env['AI_TOKEN'];
|
||||
|
ztimson marked this conversation as resolved
assistant
commented
Missing validation for required environment variables. If any of git, owner, repo, auth, ticket, host, model, or token are undefined, the script will fail with cryptic errors. Add explicit validation and helpful error messages at the start. Missing validation for required environment variables. If any of git, owner, repo, auth, ticket, host, model, or token are undefined, the script will fail with cryptic errors. Add explicit validation and helpful error messages at the start.
|
||||
|
||||
|
ztimson marked this conversation as resolved
assistant
commented
Missing environment variable validation: Required environment variables (GIT_HOST, GIT_OWNER, GIT_REPO, GIT_TOKEN, TICKET, AI_HOST, AI_MODEL, AI_TOKEN) are not validated before use. If any are undefined, the script will fail with cryptic errors. Add validation with helpful error messages. Missing environment variable validation: Required environment variables (GIT_HOST, GIT_OWNER, GIT_REPO, GIT_TOKEN, TICKET, AI_HOST, AI_MODEL, AI_TOKEN) are not validated before use. If any are undefined, the script will fail with cryptic errors. Add validation with helpful error messages.
|
||||
console.log(`Processing issue #${ticket}`);
|
||||
|
assistant
commented
Missing validation for required environment variables. If any of git, owner, repo, auth, ticket, host, model, or token are undefined, the script will fail with cryptic errors. Add validation to check these values exist before proceeding. Missing validation for required environment variables. If any of git, owner, repo, auth, ticket, host, model, or token are undefined, the script will fail with cryptic errors. Add validation to check these values exist before proceeding.
|
||||
|
||||
// Fetch issue
|
||||
|
ztimson marked this conversation as resolved
assistant
commented
Hardcoded API path: The API path Hardcoded API path: The API path `/api/v1/repos/` suggests this is Gitea-specific. This won't work with GitHub, GitLab, or other Git hosting platforms. Consider making the API structure configurable or detecting the platform type.
|
||||
const issueRes = await fetch(`${git}/api/v1/repos/${owner}/${repo}/issues/${ticket}`, {
|
||||
|
ztimson marked this conversation as resolved
assistant
commented
The API endpoint pattern '/api/v1/repos/' suggests this is for Gitea/Forgejo, not GitHub. The workflow uses github context variables which work, but the hardcoded API path is not compatible with GitHub's API (/repos/ without /api/v1/). This will fail if run on GitHub Actions. The API endpoint pattern '/api/v1/repos/' suggests this is for Gitea/Forgejo, not GitHub. The workflow uses github context variables which work, but the hardcoded API path is not compatible with GitHub's API (/repos/ without /api/v1/). This will fail if run on GitHub Actions.
assistant
commented
The API endpoint path suggests this is Gitea-specific (api/v1). Consider documenting this requirement or making it configurable to support other Git platforms like GitHub or GitLab. The API endpoint path suggests this is Gitea-specific (api/v1). Consider documenting this requirement or making it configurable to support other Git platforms like GitHub or GitLab.
assistant
commented
The fetch URL appears to be hardcoded for Gitea API (api/v1). This won't work with GitHub or GitLab. Consider making the API path configurable or detecting the git host type. The fetch URL appears to be hardcoded for Gitea API (api/v1). This won't work with GitHub or GitLab. Consider making the API path configurable or detecting the git host type.
|
||||
headers: {'Authorization': `token ${auth}`}
|
||||
});
|
||||
if(!issueRes.ok) throw new Error(`${issueRes.status} ${await issueRes.text()}`);
|
||||
const issueData = await issueRes.json();
|
||||
if(!issueData.labels?.some(l => l.name === 'Review/AI')) {
|
||||
console.log('Skipping');
|
||||
|
ztimson marked this conversation as resolved
assistant
commented
Incorrect exit call: Incorrect exit call: `return process.exit()` is redundant - `process.exit()` doesn't return. Should be just `process.exit(0)` or `return` (not both).
|
||||
return process.exit();
|
||||
|
ztimson marked this conversation as resolved
assistant
commented
The workflow checks for 'Review/AI' label but the issue template defines the label as 'Review/AI' in the YAML frontmatter. However, this early exit happens AFTER fetching the issue. Consider adding a condition in the workflow to only trigger when the correct label is present, rather than fetching and then skipping. The workflow checks for 'Review/AI' label but the issue template defines the label as 'Review/AI' in the YAML frontmatter. However, this early exit happens AFTER fetching the issue. Consider adding a condition in the workflow to only trigger when the correct label is present, rather than fetching and then skipping.
assistant
commented
The early exit on line 38 happens after the async IIFE has already started. Using The early exit on line 38 happens after the async IIFE has already started. Using `return process.exit()` is redundant - either use `return` or `process.exit()`, not both.
assistant
commented
Using process.exit() without an exit code defaults to 0 (success), which is misleading when skipping. Use process.exit(0) explicitly or consider this might not be an error condition. Using process.exit() without an exit code defaults to 0 (success), which is misleading when skipping. Use process.exit(0) explicitly or consider this might not be an error condition.
|
||||
}
|
||||
|
||||
let readme = '', readmeP = path.join(process.cwd(), 'README.md');
|
||||
if(fs.existsSync(readmeP)) readme = fs.readFileSync(readmeP, 'utf-8');
|
||||
const template = fs.readFileSync(p, 'utf-8');
|
||||
|
||||
let options = {ollama: {model, host}};
|
||||
|
ztimson marked this conversation as resolved
assistant
commented
The Ollama configuration incorrectly uses The Ollama configuration incorrectly uses `host` as the `model` parameter: `{ollama: {model, host}}`. Based on typical Ollama SDK usage, this should likely be `{ollama: {model, endpoint: host}}` or similar. The current configuration will not work correctly for Ollama.
assistant
commented
The default options object sets 'ollama' configuration even when using other providers. This creates an unnecessary object with model and host properties. Consider initializing options as an empty object or only setting the relevant provider. The default options object sets 'ollama' configuration even when using other providers. This creates an unnecessary object with model and host properties. Consider initializing options as an empty object or only setting the relevant provider.
|
||||
if(host === 'anthropic') options = {anthropic: {model, token}};
|
||||
else if(host === 'openai') options = {openAi: {model, token}};
|
||||
const ai = new Ai({
|
||||
...options,
|
||||
model: [host, model],
|
||||
path: process.env['path'] || os.tmpdir(),
|
||||
system: `You are a ticket formatter. Transform raw issue descriptions into structured tickets.
|
||||
|
||||
**CRITICAL RULES:**
|
||||
1. Identify the ticket type (Bug, DevOps, Enhancement, Refactor, Security)
|
||||
2. Output MUST only contain the new ticket information in markdown, no extra fluff
|
||||
3. Follow the template structure EXACTLY:
|
||||
- Title format: [Module] - [Verb] [noun]
|
||||
Example: Storage - Fix file uploads
|
||||
- Fill in the identified ticket type
|
||||
- Write a clear description
|
||||
- For bugs: fill Steps to Reproduce with numbered list
|
||||
- For enhancements/refactors: REMOVE the Steps to Reproduce section entirely
|
||||
- Acceptance Criteria: convert requirements into checkboxes (- [ ])
|
||||
- Weight scoring (0-5 each):
|
||||
* Size: Number of modules, layers & files affected by change
|
||||
* Complexity: Technical difficulty to implement
|
||||
* Unknowns: Research/uncertainty in work estimation
|
||||
* Calculate Total as sum of the three
|
||||
- Remove sections that are not applicable based on ticket type
|
||||
- Use proper markdown headers (##)
|
||||
|
||||
**README:**
|
||||
\`\`\`markdown
|
||||
${readme.trim() || 'No README available'}
|
||||
\`\`\`
|
||||
|
||||
**TEMPLATE:**
|
||||
\`\`\`markdown
|
||||
${template.trim()}
|
||||
\`\`\`
|
||||
|
||||
Output ONLY the formatted ticket, no explanation.`
|
||||
})
|
||||
|
||||
const messages = await ai.language.ask(`Title: ${issueData.title}\n\nDescription:\n${issueData.body || 'No description provided'}`).catch(() => []);
|
||||
|
ztimson marked this conversation as resolved
Outdated
assistant
commented
No error handling for AI call: The No error handling for AI call: The `ai.language.ask()` call has no try-catch block. If the AI service fails, times out, or returns an unexpected format, the script will crash without helpful error messages.
assistant
commented
Double semicolon syntax error. Remove one semicolon from '.catch(() => []);;' Double semicolon syntax error. Remove one semicolon from '.catch(() => []);;'
assistant
commented
Error handling with Error handling with `.catch(() => [])` silently swallows all errors from the AI request. This makes debugging difficult. Consider logging the error or providing more context about what went wrong.
assistant
commented
Error handling with .catch(() => []) silently swallows all errors, making debugging difficult. At minimum, log the error before returning an empty array, or let it propagate for better error visibility. Error handling with .catch(() => []) silently swallows all errors, making debugging difficult. At minimum, log the error before returning an empty array, or let it propagate for better error visibility.
|
||||
const content = messages?.pop()?.content;
|
||||
|
ztimson marked this conversation as resolved
Outdated
assistant
commented
Unsafe array access: Unsafe array access: `messages.pop()` assumes the array is non-empty. If the AI returns an empty response, this will throw an error when accessing `.content`. Add a check to ensure messages exist.
|
||||
if(!content) {
|
||||
console.log('Invalid response from AI');
|
||||
|
ztimson marked this conversation as resolved
Outdated
assistant
commented
Potential runtime error: Potential runtime error: `type[0].toUpperCase()` will throw if `type` is an empty string. The fallback 'Unassigned' is set earlier, but if the regex extracts an empty string, this will fail. Add a check: `type && type.length > 0` before accessing `type[0]`.
|
||||
return process.exit(1);
|
||||
}
|
||||
const title = /^# (.+)$/m.exec(content)?.[1] || issueData.title;
|
||||
const typeMatch = /^## Type:\s*(.+)$/m.exec(content);
|
||||
|
assistant
commented
Type extraction logic is fragile. The split('/')[0] assumes the format is "Type/Subtype" but the template shows "Type: [Option1/Option2/...]". This will incorrectly parse "[Bug" instead of "Bug". Use a more robust regex or trim brackets. Type extraction logic is fragile. The split('/')[0] assumes the format is "Type/Subtype" but the template shows "Type: [Option1/Option2/...]". This will incorrectly parse "[Bug" instead of "Bug". Use a more robust regex or trim brackets.
|
||||
const type = typeMatch?.[1]?.split('/')[0]?.trim() || 'Unassigned';
|
||||
|
ztimson marked this conversation as resolved
assistant
commented
The type extraction logic 'type[0].toUpperCase() + type.slice(1).toLowerCase()' operates on a string but 'type' is already a string (not an array), so 'type[0]' gets the first character. While this works, the variable name is misleading. Also, this doesn't handle the 'Unassigned' case - it would create a 'Kind/Unassigned' label which may not be desired. The type extraction logic 'type[0].toUpperCase() + type.slice(1).toLowerCase()' operates on a string but 'type' is already a string (not an array), so 'type[0]' gets the first character. While this works, the variable name is misleading. Also, this doesn't handle the 'Unassigned' case - it would create a 'Kind/Unassigned' label which may not be desired.
assistant
commented
The type parsing logic The type parsing logic `type?.split('/')[0]?.trim()` assumes a specific format but then constructs a label with `Kind/${type}`. This creates a mismatch - if the AI returns "Bug", the label becomes "Kind/Bug", but the check on line 36 looks for "Review/AI". Consider standardizing the label format.
|
||||
const body = content.replace(/^# .+$/m, '').replace(/^## Type:.+$/m, '').trim();
|
||||
|
assistant
commented
The body processing removes the title and type lines, but doesn't preserve the Type line in the final output. The API update only sends the body without the Type header, which means the formatted ticket loses the Type information visually. The body processing removes the title and type lines, but doesn't preserve the Type line in the final output. The API update only sends the body without the Type header, which means the formatted ticket loses the Type information visually.
|
||||
const updateRes = await fetch(`${git}/api/v1/repos/${owner}/${repo}/issues/${ticket}`, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Authorization': `token ${auth}`,
|
||||
'Content-Type': 'application/json'
|
||||
|
ztimson marked this conversation as resolved
assistant
commented
Label replacement issue: The code sets labels to Label replacement issue: The code sets labels to `[Type/${type}]` which replaces all existing labels. This will remove the 'Review/AI' label and any other labels the issue had. Consider appending to existing labels or preserving important ones.
|
||||
},
|
||||
body: JSON.stringify({
|
||||
title,
|
||||
body,
|
||||
|
assistant
commented
The PATCH request replaces all labels with just the type label, which will remove the "Review/AI" label that triggered the workflow. This could cause issues if the workflow is re-triggered or if other labels are needed. Consider appending to existing labels instead of replacing them. The PATCH request replaces all labels with just the type label, which will remove the "Review/AI" label that triggered the workflow. This could cause issues if the workflow is re-triggered or if other labels are needed. Consider appending to existing labels instead of replacing them.
|
||||
labels: type?.length ? [`Kind/${type[0].toUpperCase() + type.slice(1).toLowerCase()}`] : []
|
||||
|
ztimson marked this conversation as resolved
assistant
commented
The label update logic replaces ALL labels with just the Kind label. This will remove the 'Review/AI' label and any other existing labels. Consider appending to existing labels or filtering more carefully: The label update logic replaces ALL labels with just the Kind label. This will remove the 'Review/AI' label and any other existing labels. Consider appending to existing labels or filtering more carefully: `labels: [...issueData.labels.map(l => l.name).filter(n => !n.startsWith('Kind/')), ...]`
assistant
commented
Label assignment logic has a bug: checking 'type?.length' on a string will always be truthy (even empty string has length property). This should check if type is truthy or has non-zero length. Also, the label format assumes "Kind/" prefix which may not match existing label conventions. Label assignment logic has a bug: checking 'type?.length' on a string will always be truthy (even empty string has length property). This should check if type is truthy or has non-zero length. Also, the label format assumes "Kind/" prefix which may not match existing label conventions.
assistant
commented
The labels array assignment completely replaces existing labels. This will remove the "Review/AI" label that triggered the workflow, and any other labels the user added. Consider appending to existing labels instead of replacing them. The labels array assignment completely replaces existing labels. This will remove the "Review/AI" label that triggered the workflow, and any other labels the user added. Consider appending to existing labels instead of replacing them.
|
||||
})
|
||||
});
|
||||
if(!updateRes.ok) throw new Error(`${updateRes.status} ${await updateRes.text()}`);
|
||||
console.log(body);
|
||||
})();
|
||||
The directory name should be
ISSUE_TEMPLATE(uppercase) notissue_template(lowercase) to be recognized by GitHub. The current path won't work as an issue template.