Skip to content
Latchkey

Evaluate Submission workflow (jslee02/awesome-robotics-libraries)

The Evaluate Submission workflow from jslee02/awesome-robotics-libraries, explained and optimized by Latchkey.

C

CI health: C - fair

Point runs-on at Latchkey and get caching, job timeouts, self-healing for flaky steps, and up to 58% lower cost, applied automatically.

Grade your own workflow free or run it on Latchkey →
Source: jslee02/awesome-robotics-libraries.github/workflows/evaluate-submission.ymlLicense CC0-1.0View source

What it does

This is the Evaluate Submission workflow from the jslee02/awesome-robotics-libraries repository, a real project running GitHub Actions. It is shown here with attribution under its CC0-1.0 license.

Below, Latchkey shows a faster, safer version produced by its optimization engine.

The workflow

workflow (.yml)
name: Evaluate Submission

on:
  issues:
    types: [edited, labeled]
  issue_comment:
    types: [created]

jobs:
  evaluate:
    if: github.event_name == 'issues' && github.event.action == 'labeled' && github.event.label.name == 'suggestion'
    runs-on: ubuntu-latest
    permissions:
      actions: write
      contents: read
      issues: write
    steps:
      - uses: actions/checkout@v7

      - uses: actions/setup-python@v6
        with:
          python-version: "3.12"

      - run: pip install pyyaml

      - name: Extract GitHub repo from issue body
        id: extract
        uses: actions/github-script@v9
        with:
          script: |
            const body = context.payload.issue.body || '';

            function normalizeGitHubRepo(value) {
              if (!value) return '';
              const trimmed = value.trim();
              const slugMatch = trimmed.match(/^(?:https?:\/\/github\.com\/)?([a-zA-Z0-9._-]+\/[a-zA-Z0-9._-]+?)(?:\.git|\/)?$/);
              return slugMatch ? slugMatch[1] : '';
            }

            // Try the structured "github" field first (from issue template)
            const ghFieldMatch = body.match(/### GitHub Repository\s*\n\s*\n?\s*([\s\S]*?)(?=\n###|$)/);
            const ghRepo = normalizeGitHubRepo(ghFieldMatch ? ghFieldMatch[1] : '');
            if (ghRepo) {
              core.setOutput('repo', ghRepo);
              return;
            }

            // Fallback: extract from any GitHub URL in the body
            const urlMatch = body.match(/github\.com\/([a-zA-Z0-9._-]+\/[a-zA-Z0-9._-]+)/);
            if (urlMatch) {
              core.setOutput('repo', urlMatch[1]);
              return;
            }

            core.setOutput('repo', '');

      - name: Run evaluation
        if: steps.extract.outputs.repo != ''
        id: eval
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          REPORT=$(python3 scripts/evaluate_entry.py --data-dir data/ "${{ steps.extract.outputs.repo }}" 2>&1) || true
          echo "$REPORT" > /tmp/eval-report.md

          python3 scripts/evaluate_entry.py --data-dir data/ --json "${{ steps.extract.outputs.repo }}" 2>/dev/null > /tmp/eval-result.json || true
          REC=$(python3 -c "import sys,json; print(json.load(open('/tmp/eval-result.json')).get('recommendation','error'))" 2>/dev/null || echo "error")
          ARCHIVED=$(python3 -c "import sys,json; print(str(json.load(open('/tmp/eval-result.json')).get('archived',False)).lower())" 2>/dev/null || echo "false")
          echo "recommendation=$REC" >> "$GITHUB_OUTPUT"
          echo "archived=$ARCHIVED" >> "$GITHUB_OUTPUT"

      - name: Post evaluation comment
        if: steps.extract.outputs.repo != ''
        uses: actions/github-script@v9
        with:
          script: |
            const fs = require('fs');
            const report = fs.readFileSync('/tmp/eval-report.md', 'utf8');
            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              body: report
            });

      - name: Apply label and handle outcome
        if: steps.extract.outputs.repo != ''
        uses: actions/github-script@v9
        with:
          script: |
            const rec = '${{ steps.eval.outputs.recommendation }}';
            const archived = '${{ steps.eval.outputs.archived }}' === 'true';
            const issue = context.issue.number;
            const owner = context.repo.owner;
            const repo = context.repo.repo;

            // Archived rejects close immediately; 0-score rejects stay in incubator queue
            let label;
            if (rec === 'reject' && archived) {
              label = 'rejected';
            } else {
              const labelMap = {
                'accept': 'accepted',
                'likely_accept': 'accepted',
                'incubator': 'incubator',
                'reject': 'incubator',
                'duplicate': 'duplicate',
                'error': 'needs-review',
              };
              label = labelMap[rec] || 'needs-review';
            }
            await github.rest.issues.addLabels({ owner, repo, issue_number: issue, labels: [label] });

            if (label === 'accepted') {
              await github.rest.actions.createWorkflowDispatch({
                owner,
                repo,
                workflow_id: 'add-accepted-entry.yml',
                ref: context.payload.repository.default_branch,
                inputs: {
                  issue_number: String(issue),
                },
              });
            }

            // Auto-close duplicates and archived rejects
            if (rec === 'duplicate' || (rec === 'reject' && archived)) {
              await github.rest.issues.update({
                owner, repo, issue_number: issue,
                state: 'closed',
                state_reason: 'not_planned',
              });
            }

      - name: Post fallback comment (no repo found)
        if: steps.extract.outputs.repo == ''
        uses: actions/github-script@v9
        with:
          script: |
            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              body: [
                '👋 Thanks for the suggestion!',
                '',
                'I couldn\'t find a GitHub repository in this issue. Could you add the **GitHub Repository** field ',
                '(e.g., `owner/repo`) so I can run an automated evaluation?',
                '',
                'If the project isn\'t on GitHub, please reply confirming that this should be reviewed as a non-GitHub resource and include any public repository or documentation link maintainers should use.',
                '',
                'This issue is labeled `question` while waiting for author input. If there is no update for about two weeks, automation will mark it stale; after another two weeks without activity, it may close automatically.',
              ].join('\n')
            });
            await github.rest.issues.addLabels({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              labels: ['needs-review', 'question']
            });

  clear-author-question:
    if: |
      (github.event_name == 'issues' && github.event.action == 'edited') ||
      (github.event_name == 'issue_comment' && !github.event.issue.pull_request)
    runs-on: ubuntu-latest
    permissions:
      issues: write
    steps:
      - name: Clear author-action labels after author update
        uses: actions/github-script@v9
        with:
          script: |
            const issue = context.payload.issue;
            const labels = (issue.labels || []).map(label => typeof label === 'string' ? label : label.name);
            if (!labels.includes('suggestion') || !labels.includes('question')) {
              return;
            }

            const author = issue.user.login;
            const sender = context.payload.sender.login;
            if (sender !== author) {
              return;
            }

            const owner = context.repo.owner;
            const repo = context.repo.repo;
            const issue_number = issue.number;

            async function removeLabel(label) {
              try {
                await github.rest.issues.removeLabel({ owner, repo, issue_number, name: label });
              } catch (error) {
                if (error.status !== 404) {
                  throw error;
                }
              }
            }

            await removeLabel('question');
            await removeLabel('stale');

The same workflow, on Latchkey

Estimated ~20% faster on cache hits, plus fewer wasted runs and a safer supply chain. Added and changed lines are highlighted.

name: Evaluate Submission
 
on:
  issues:
    types: [edited, labeled]
  issue_comment:
    types: [created]
 
jobs:
  evaluate:
    timeout-minutes: 30
    if: github.event_name == 'issues' && github.event.action == 'labeled' && github.event.label.name == 'suggestion'
    runs-on: latchkey-small
    permissions:
      actions: write
      contents: read
      issues: write
    steps:
      - uses: actions/checkout@v7
 
      - uses: actions/setup-python@v6
        with:
          cache: 'pip'
          python-version: "3.12"
 
      - run: pip install pyyaml
 
      - name: Extract GitHub repo from issue body
        id: extract
        uses: actions/github-script@v9
        with:
          script: |
            const body = context.payload.issue.body || '';
 
            function normalizeGitHubRepo(value) {
              if (!value) return '';
              const trimmed = value.trim();
              const slugMatch = trimmed.match(/^(?:https?:\/\/github\.com\/)?([a-zA-Z0-9._-]+\/[a-zA-Z0-9._-]+?)(?:\.git|\/)?$/);
              return slugMatch ? slugMatch[1] : '';
            }
 
            // Try the structured "github" field first (from issue template)
            const ghFieldMatch = body.match(/### GitHub Repository\s*\n\s*\n?\s*([\s\S]*?)(?=\n###|$)/);
            const ghRepo = normalizeGitHubRepo(ghFieldMatch ? ghFieldMatch[1] : '');
            if (ghRepo) {
              core.setOutput('repo', ghRepo);
              return;
            }
 
            // Fallback: extract from any GitHub URL in the body
            const urlMatch = body.match(/github\.com\/([a-zA-Z0-9._-]+\/[a-zA-Z0-9._-]+)/);
            if (urlMatch) {
              core.setOutput('repo', urlMatch[1]);
              return;
            }
 
            core.setOutput('repo', '');
 
      - name: Run evaluation
        if: steps.extract.outputs.repo != ''
        id: eval
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          REPORT=$(python3 scripts/evaluate_entry.py --data-dir data/ "${{ steps.extract.outputs.repo }}" 2>&1) || true
          echo "$REPORT" > /tmp/eval-report.md
 
          python3 scripts/evaluate_entry.py --data-dir data/ --json "${{ steps.extract.outputs.repo }}" 2>/dev/null > /tmp/eval-result.json || true
          REC=$(python3 -c "import sys,json; print(json.load(open('/tmp/eval-result.json')).get('recommendation','error'))" 2>/dev/null || echo "error")
          ARCHIVED=$(python3 -c "import sys,json; print(str(json.load(open('/tmp/eval-result.json')).get('archived',False)).lower())" 2>/dev/null || echo "false")
          echo "recommendation=$REC" >> "$GITHUB_OUTPUT"
          echo "archived=$ARCHIVED" >> "$GITHUB_OUTPUT"
 
      - name: Post evaluation comment
        if: steps.extract.outputs.repo != ''
        uses: actions/github-script@v9
        with:
          script: |
            const fs = require('fs');
            const report = fs.readFileSync('/tmp/eval-report.md', 'utf8');
            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              body: report
            });
 
      - name: Apply label and handle outcome
        if: steps.extract.outputs.repo != ''
        uses: actions/github-script@v9
        with:
          script: |
            const rec = '${{ steps.eval.outputs.recommendation }}';
            const archived = '${{ steps.eval.outputs.archived }}' === 'true';
            const issue = context.issue.number;
            const owner = context.repo.owner;
            const repo = context.repo.repo;
 
            // Archived rejects close immediately; 0-score rejects stay in incubator queue
            let label;
            if (rec === 'reject' && archived) {
              label = 'rejected';
            } else {
              const labelMap = {
                'accept': 'accepted',
                'likely_accept': 'accepted',
                'incubator': 'incubator',
                'reject': 'incubator',
                'duplicate': 'duplicate',
                'error': 'needs-review',
              };
              label = labelMap[rec] || 'needs-review';
            }
            await github.rest.issues.addLabels({ owner, repo, issue_number: issue, labels: [label] });
 
            if (label === 'accepted') {
              await github.rest.actions.createWorkflowDispatch({
                owner,
                repo,
                workflow_id: 'add-accepted-entry.yml',
                ref: context.payload.repository.default_branch,
                inputs: {
                  issue_number: String(issue),
                },
              });
            }
 
            // Auto-close duplicates and archived rejects
            if (rec === 'duplicate' || (rec === 'reject' && archived)) {
              await github.rest.issues.update({
                owner, repo, issue_number: issue,
                state: 'closed',
                state_reason: 'not_planned',
              });
            }
 
      - name: Post fallback comment (no repo found)
        if: steps.extract.outputs.repo == ''
        uses: actions/github-script@v9
        with:
          script: |
            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              body: [
                '👋 Thanks for the suggestion!',
                '',
                'I couldn\'t find a GitHub repository in this issue. Could you add the **GitHub Repository** field ',
                '(e.g., `owner/repo`) so I can run an automated evaluation?',
                '',
                'If the project isn\'t on GitHub, please reply confirming that this should be reviewed as a non-GitHub resource and include any public repository or documentation link maintainers should use.',
                '',
                'This issue is labeled `question` while waiting for author input. If there is no update for about two weeks, automation will mark it stale; after another two weeks without activity, it may close automatically.',
              ].join('\n')
            });
            await github.rest.issues.addLabels({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              labels: ['needs-review', 'question']
            });
 
  clear-author-question:
    timeout-minutes: 30
    if: |
      (github.event_name == 'issues' && github.event.action == 'edited') ||
      (github.event_name == 'issue_comment' && !github.event.issue.pull_request)
    runs-on: latchkey-small
    permissions:
      issues: write
    steps:
      - name: Clear author-action labels after author update
        uses: actions/github-script@v9
        with:
          script: |
            const issue = context.payload.issue;
            const labels = (issue.labels || []).map(label => typeof label === 'string' ? label : label.name);
            if (!labels.includes('suggestion') || !labels.includes('question')) {
              return;
            }
 
            const author = issue.user.login;
            const sender = context.payload.sender.login;
            if (sender !== author) {
              return;
            }
 
            const owner = context.repo.owner;
            const repo = context.repo.repo;
            const issue_number = issue.number;
 
            async function removeLabel(label) {
              try {
                await github.rest.issues.removeLabel({ owner, repo, issue_number, name: label });
              } catch (error) {
                if (error.status !== 404) {
                  throw error;
                }
              }
            }
 
            await removeLabel('question');
            await removeLabel('stale');
 

What changed

What Latchkey heals here

This workflow has steps that commonly fail on transient issues (network, registries, flaky browsers). On Latchkey managed runners they are detected, retried, and self-healed instead of failing your build:

This workflow runs 2 jobs per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.

Actions used in this workflow