Skip to content

Create Daily Issues from Teaching Material During Student Repo Setup #80

@FelixTJDietrich

Description

@FelixTJDietrich

Summary

When creating a student repository, automatically create all daily issues from the daily_issues/ directory of the teaching material GitLab repo. Issues are created once during setup — no separate scheduling, no tracking table.

Addresses #22. Depends on #77 and #78.

Context

Teaching Material Issue Templates

daily_issues/
    day1_git_basics.md
    day1_software_engineering_1.md
    day1_swiftui_1.md
    day2_software_engineering_2_aom.md
    day2_software_engineering_2_glossary.md
    day2_software_engineering_2_product_backlog.md
    day3_software_engineering_3.md
    day4_software_engineering_4_component.md

Each file is Markdown: first # heading is the issue title, everything else is the description.

Changes

1. Parse Issue Templates

Fetch and parse issue files from the teaching material repo (same gitlabClient, same token):

type IssueTemplate struct {
    Identifier  string // "day1_git_basics" (filename without .md)
    Title       string // extracted from first # heading
    Description string // everything after the title
}

func parseIssueTemplates(files []TemplateFile) []IssueTemplate {
    // Filter for daily_issues/*.md
    // Split on first "# " line → title
    // Remaining content → description
    // Sort by filename (day1 before day2, etc.)
}

2. Create Issues During Student Setup

After pushing template files, create all issues:

func (s *InfrastructureService) createStudentIssues(projectID int64) error {
    templates, err := s.fetchIssueTemplates()
    if err != nil {
        return fmt.Errorf("failed to fetch issue templates: %w", err)
    }

    for _, tmpl := range templates {
        _, _, err := s.gitlabClient.Issues.CreateIssue(projectID, &gitlab.CreateIssueOptions{
            Title:       gitlab.Ptr(tmpl.Title),
            Description: gitlab.Ptr(tmpl.Description),
        })
        if err != nil {
            // Log and continue — one failed issue should not block the others
            log.WithField("issue", tmpl.Identifier).Error("failed to create issue: ", err)
            continue
        }
    }
    return nil
}

3. Idempotency via GitLab Check (No Tracking Table)

On re-run, check GitLab directly for existing issues by title:

// Before creating, check if issue with same title already exists
existingIssues, _, _ := s.gitlabClient.Issues.ListProjectIssues(projectID, &gitlab.ListProjectIssuesOptions{
    Search: gitlab.Ptr(tmpl.Title),
})
for _, existing := range existingIssues {
    if existing.Title == tmpl.Title {
        // Already exists, skip
        continue
    }
}

No student_issue_tracking table. GitLab is the source of truth for what issues exist. Duplicating this state in Postgres creates staleness risk for zero benefit. If you need to know which issues were created by PROMPT vs. by the student, the title match is sufficient — course issues have structured titles like "Day 1: Create Problem Statement..."

4. Cache Issue Templates

Issue templates are fetched alongside template files (from #78). Use the same caching pattern: fetch once per server lifetime.

Deletion Considerations (Future, Out of Scope)

If issue deletion is ever needed, note:

  • Students create their own issues (user stories, backlog items)
  • Never delete all issues — only delete issues matching the exact titles from the templates
  • Check for student activity (comments, status changes, linked MRs) before deleting
  • This is inherently dangerous and should require explicit confirmation

Acceptance Criteria

  • Issue templates parsed from daily_issues/ (title from # heading)
  • All issues created during student repo setup
  • Partial failure doesn't block other issues (log and continue)
  • Re-running setup skips issues that already exist (title match via GitLab API)
  • Cached with template files (one fetch per server lifetime)
  • Tests for issue template parsing

Out of Scope

  • student_issue_tracking table (not needed — GitLab is source of truth)
  • Day-by-day scheduling (all created at once)
  • Issue deletion
  • Issue labels/milestones
  • Late student catch-up (handled by re-running setup, which creates missing issues)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions