feat: add SR&ED tracking and project management tools
This commit introduces several new files and updates to support SR&ED tracking and project management: - Adds a template for SR&ED tasks to standardize issue creation. - Adds a Makefile command to set up GitHub labels from a YAML file. - Adds a Makefile command to export SR&ED-eligible issues to a Markdown file. - Adds a Makefile command to create issues from a file. - Adds documentation for SR&ED tracking and development conventions. - Adds a YAML file to define GitHub labels. - Adds scripts to set up GitHub labels, export issues, and create issues from a file. - Updates the project plan to include SR&ED considerations. These changes aim to improve project organization, facilitate SR&ED claims, and streamline development workflows.
This commit is contained in:
92
scripts/create_issues.py
Executable file
92
scripts/create_issues.py
Executable file
@@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env python3
|
||||
import subprocess
|
||||
import os
|
||||
import re
|
||||
|
||||
# --- Configuration ---
|
||||
INPUT_FILE = "issues-to-create.md"
|
||||
PROJECT_TITLE = "Krow"
|
||||
# ---
|
||||
|
||||
def create_issue(title, body, labels, milestone):
|
||||
"""Creates a GitHub issue using the gh CLI."""
|
||||
command = ["gh", "issue", "create"]
|
||||
command.extend(["--title", title])
|
||||
command.extend(["--body", body])
|
||||
command.extend(["--project", PROJECT_TITLE])
|
||||
|
||||
if milestone:
|
||||
command.extend(["--milestone", milestone])
|
||||
|
||||
for label in labels:
|
||||
command.extend(["--label", label])
|
||||
|
||||
print(f" -> Creating issue: \"{title}\"")
|
||||
|
||||
try:
|
||||
result = subprocess.run(command, check=True, text=True, capture_output=True)
|
||||
print(result.stdout.strip())
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"❌ ERROR: Failed to create issue '{title}'.")
|
||||
print(f" Stderr: {e.stderr.strip()}")
|
||||
|
||||
|
||||
def main():
|
||||
"""Main function to parse the file and create issues."""
|
||||
print(f"🚀 Starting bulk creation of GitHub issues from '{INPUT_FILE}'...")
|
||||
|
||||
if subprocess.run(["which", "gh"], capture_output=True).returncode != 0:
|
||||
print("❌ ERROR: GitHub CLI (‘gh’) is not installed.")
|
||||
exit(1)
|
||||
if not os.path.exists(INPUT_FILE):
|
||||
print(f"❌ ERROR: Input file ‘{INPUT_FILE}’ not found.")
|
||||
exit(1)
|
||||
print("✅ Dependencies and input file found.")
|
||||
|
||||
print(f"2. Reading and parsing ‘{INPUT_FILE}’...")
|
||||
with open(INPUT_FILE, 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
# Split the content by lines starting with '# '
|
||||
issue_blocks = re.split(r'\n(?=#\s)', content)
|
||||
|
||||
for block in issue_blocks:
|
||||
if not block.strip():
|
||||
continue
|
||||
|
||||
lines = block.strip().split('\n')
|
||||
|
||||
title = lines[0].replace('# ', '').strip()
|
||||
|
||||
labels_line = ""
|
||||
milestone_line = ""
|
||||
body_start_index = 1
|
||||
|
||||
# Find all metadata lines (Labels, Milestone) at the beginning of the body
|
||||
for i, line in enumerate(lines[1:]):
|
||||
line_lower = line.strip().lower()
|
||||
if line_lower.startswith('labels:'):
|
||||
labels_line = line.split(':', 1)[1].strip()
|
||||
elif line_lower.startswith('milestone:'):
|
||||
milestone_line = line.split(':', 1)[1].strip()
|
||||
elif line.strip() == "":
|
||||
continue # Ignore blank lines in the metadata header
|
||||
else:
|
||||
# This is the first real line of the body
|
||||
body_start_index = i + 1
|
||||
break
|
||||
|
||||
body = "\n".join(lines[body_start_index:]).strip()
|
||||
labels = [label.strip() for label in labels_line.split(',') if label.strip()]
|
||||
milestone = milestone_line
|
||||
|
||||
if not title:
|
||||
print("⚠️ Skipping block with no title.")
|
||||
continue
|
||||
|
||||
create_issue(title, body, labels, milestone)
|
||||
|
||||
print("\n🎉 Bulk issue creation complete!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
63
scripts/export_issues.sh
Executable file
63
scripts/export_issues.sh
Executable file
@@ -0,0 +1,63 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ====================================================================================
|
||||
# SCRIPT TO EXPORT SR&ED-ELIGIBLE GITHUB ISSUES TO A MARKDOWN FILE
|
||||
# ====================================================================================
|
||||
set -e # Exit script if a command fails
|
||||
|
||||
# --- Configuration ---
|
||||
OUTPUT_FILE="sred-issues-export.md"
|
||||
# This is the label we will use to identify SR&ED-eligible tasks
|
||||
SRED_LABEL="sred-eligible"
|
||||
ISSUE_LIMIT=1000
|
||||
|
||||
echo "🚀 Starting export of SR&ED-eligible issues to '${OUTPUT_FILE}'..."
|
||||
|
||||
# --- Step 1: Dependency Check ---
|
||||
echo "1. Checking for 'gh' CLI dependency..."
|
||||
if ! command -v gh &> /dev/null; then
|
||||
echo "❌ ERROR: GitHub CLI ('gh') is not installed. Please install it to continue."
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ 'gh' CLI found."
|
||||
|
||||
# --- Step 2: Initialize Output File ---
|
||||
echo "# Export of SR&ED-Eligible Issues" > "$OUTPUT_FILE"
|
||||
echo "" >> "$OUTPUT_FILE"
|
||||
echo "*This document lists the systematic investigations and experimental development tasks undertaken during this period. Export generated on $(date)*." >> "$OUTPUT_FILE"
|
||||
echo "" >> "$OUTPUT_FILE"
|
||||
|
||||
# --- Step 3: Fetch SR&ED-Eligible Issues ---
|
||||
echo "2. Fetching open issues with the '${SRED_LABEL}' label..."
|
||||
|
||||
# We use 'gh issue list' with a JSON output and parse it with 'jq' for robustness.
|
||||
# This is more reliable than parsing text output.
|
||||
issue_numbers=$(gh issue list --state open --label "${SRED_LABEL}" --limit $ISSUE_LIMIT --json number | jq -r '.[].number')
|
||||
|
||||
if [ -z "$issue_numbers" ]; then
|
||||
echo "⚠️ No open issues found with the label '${SRED_LABEL}'. The export file will be minimal."
|
||||
echo "" >> "$OUTPUT_FILE"
|
||||
echo "**No SR&ED-eligible issues found for this period.**" >> "$OUTPUT_FILE"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
total_issues=$(echo "$issue_numbers" | wc -l | xargs)
|
||||
echo "✅ Found ${total_issues} SR&ED-eligible issue(s)."
|
||||
|
||||
# --- Step 4: Loop Through Each Issue and Format the Output ---
|
||||
echo "3. Formatting details for each issue..."
|
||||
|
||||
current_issue=0
|
||||
for number in $issue_numbers; do
|
||||
current_issue=$((current_issue + 1))
|
||||
echo " -> Processing issue #${number} (${current_issue}/${total_issues})"
|
||||
|
||||
# Use 'gh issue view' with a template to format the output for each issue
|
||||
# and append it to the output file.
|
||||
gh issue view "$number" --json number,title,body,author,createdAt --template \
|
||||
'\n### Task: [#{{.number}}] {{.title}}\n\n**Hypothesis/Goal:** \n> *(Briefly describe the technological uncertainty this task addresses. What was the technical challenge or question?)*\n\n**Systematic Investigation:**\n{{if .body}}\n{{.body}}\n{{else}}\n*No detailed description provided in the issue.*\n{{end}}\n\n**Team:** {{.author.login}} | **Date Initiated:** {{timefmt "2006-01-02" .createdAt}}\n***\n' >> "$OUTPUT_FILE"
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "🎉 Export complete!"
|
||||
echo "Your SR&ED-ready markdown file is ready: ${OUTPUT_FILE}"
|
||||
72
scripts/setup-github-labels.sh
Executable file
72
scripts/setup-github-labels.sh
Executable file
@@ -0,0 +1,72 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ====================================================================================
|
||||
# SCRIPT TO SETUP STANDARD GITHUB LABELS FROM A YAML FILE (v4 - Robust Bash Parsing)
|
||||
# ====================================================================================
|
||||
set -e # Exit script if a command fails
|
||||
|
||||
LABELS_FILE="labels.yml"
|
||||
|
||||
echo "🚀 Setting up GitHub labels from '${LABELS_FILE}'..."
|
||||
|
||||
# --- Function to create or edit a label ---
|
||||
create_or_edit_label() {
|
||||
NAME=$1
|
||||
DESCRIPTION=$2
|
||||
COLOR=$3
|
||||
|
||||
if [ -z "$NAME" ] || [ -z "$DESCRIPTION" ] || [ -z "$COLOR" ]; then
|
||||
echo "⚠️ Skipping invalid label entry."
|
||||
return
|
||||
fi
|
||||
|
||||
# The `gh api` command will exit with a non-zero status if the label is not found (404).
|
||||
# We redirect stderr to /dev/null to silence the expected "Not Found" error message.
|
||||
if gh api "repos/{owner}/{repo}/labels/${NAME}" --silent 2>/dev/null; then
|
||||
echo " - Editing existing label: '${NAME}'"
|
||||
gh label edit "${NAME}" --description "${DESCRIPTION}" --color "${COLOR}"
|
||||
else
|
||||
echo " - Creating new label: '${NAME}'"
|
||||
gh label create "${NAME}" --description "${DESCRIPTION}" --color "${COLOR}"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- Read and Parse YAML File using a robust while loop ---
|
||||
# This approach is more reliable than complex sed/awk pipelines.
|
||||
name=""
|
||||
description=""
|
||||
color=""
|
||||
|
||||
while IFS= read -r line || [[ -n "$line" ]]; do
|
||||
# Skip comments and empty lines
|
||||
if [[ "$line" =~ ^\s*# ]] || [[ -z "$line" ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Check for name
|
||||
if [[ "$line" =~ -[[:space:]]+name:[[:space:]]+\"(.*)\" ]]; then
|
||||
# If we find a new name, and the previous one was complete, process it.
|
||||
if [ -n "$name" ] && [ -n "$description" ] && [ -n "$color" ]; then
|
||||
create_or_edit_label "$name" "$description" "$color"
|
||||
# Reset for the next entry
|
||||
description=""
|
||||
color=""
|
||||
fi
|
||||
name="${BASH_REMATCH[1]}"
|
||||
# Check for description
|
||||
elif [[ "$line" =~ [[:space:]]+description:[[:space:]]+\"(.*)\" ]]; then
|
||||
description="${BASH_REMATCH[1]}"
|
||||
# Check for color
|
||||
elif [[ "$line" =~ [[:space:]]+color:[[:space:]]+\"(.*)\" ]]; then
|
||||
color="${BASH_REMATCH[1]}"
|
||||
fi
|
||||
done < "$LABELS_FILE"
|
||||
|
||||
# Process the very last label in the file
|
||||
if [ -n "$name" ] && [ -n "$description" ] && [ -n "$color" ]; then
|
||||
create_or_edit_label "$name" "$description" "$color"
|
||||
fi
|
||||
|
||||
|
||||
echo ""
|
||||
echo "🎉 All standard labels have been created or updated successfully."
|
||||
Reference in New Issue
Block a user