feat(cli): add otari import claude-code to backfill transcript usage #1723
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: PR Template Check | |
| on: | |
| # Use pull_request_target to have write access for PRs from forks. | |
| # This is safe because we only read the PR body from the event payload | |
| # and don't checkout or execute any code from the fork. | |
| pull_request_target: | |
| types: [opened, edited] | |
| schedule: | |
| # Run daily at midnight UTC to close stale PRs missing the template | |
| - cron: '0 0 * * *' | |
| jobs: | |
| check-template: | |
| # Key the skip on the PR author, not github.actor. The actor is whoever | |
| # triggered the event; on an `edited` event fired by a maintainer or | |
| # another bot the actor is the editor, so a github.actor guard would let | |
| # the check run against Dependabot's templateless body. | |
| if: github.event_name == 'pull_request_target' && github.event.pull_request.user.login != 'dependabot[bot]' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| issues: write | |
| pull-requests: write | |
| steps: | |
| - name: Check PR body for required template sections | |
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | |
| with: | |
| script: | | |
| const body = context.payload.pull_request.body || ''; | |
| // Check that the required template sections are all present. This | |
| // catches wholesale template stripping without depending on a | |
| // single literal checklist line that may be renamed or removed | |
| // when the template is updated. | |
| const hasAllTemplateSections = | |
| body.includes('## PR Type') && | |
| body.includes('## Checklist') && | |
| body.includes('## AI Usage'); | |
| const prNumber = context.payload.pull_request.number; | |
| const labelName = 'missing-template'; | |
| if (!hasAllTemplateSections) { | |
| // Check if we already labeled this PR | |
| const { data: labels } = await github.rest.issues.listLabelsOnIssue({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: prNumber | |
| }); | |
| if (labels.some(l => l.name === labelName)) { | |
| console.log('PR already labeled, skipping comment'); | |
| core.setFailed('PR template sections are missing'); | |
| return; | |
| } | |
| // Ensure the label exists | |
| try { | |
| await github.rest.issues.createLabel({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| name: labelName, | |
| color: 'e11d21', | |
| description: 'PR is missing required template sections' | |
| }); | |
| } catch (e) { | |
| // Label already exists, ignore | |
| } | |
| // Add label to track when this was flagged | |
| await github.rest.issues.addLabels({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: prNumber, | |
| labels: [labelName] | |
| }); | |
| // Add comment explaining the issue | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: prNumber, | |
| body: `⚠️ **PR Template Missing**\n\nThis PR appears to be missing required sections from the [PR template](https://github.com/${context.repo.owner}/${context.repo.repo}/blob/main/.github/pull_request_template.md).\n\nPlease edit your PR description to include the **PR Type**, **Checklist**, and **AI Usage** sections. The template helps maintainers review your contribution.\n\n**This PR will be automatically closed in 24 hours if the template is not restored.**\n\nIf you're using an AI coding tool, please ensure it preserves the PR template.` | |
| }); | |
| core.setFailed('PR template sections are missing'); | |
| } else { | |
| // Template is present, remove the label if it exists | |
| try { | |
| await github.rest.issues.removeLabel({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: prNumber, | |
| name: labelName | |
| }); | |
| console.log('Removed missing-template label'); | |
| } catch (e) { | |
| // Label wasn't present, ignore | |
| } | |
| // Clean up any warning comments left from a previous check | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: prNumber | |
| }); | |
| for (const comment of comments) { | |
| if (comment.user.login === 'github-actions[bot]' && | |
| comment.body.includes('PR Template Missing')) { | |
| await github.rest.issues.deleteComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: comment.id | |
| }); | |
| console.log(`Deleted warning comment ${comment.id}`); | |
| } | |
| } | |
| } | |
| close-stale: | |
| if: github.event_name == 'schedule' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| issues: write | |
| pull-requests: write | |
| steps: | |
| - name: Close PRs missing template for over 24 hours | |
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | |
| with: | |
| script: | | |
| const labelName = 'missing-template'; | |
| const cutoffMs = 24 * 60 * 60 * 1000; // 24 hours | |
| // Find open PRs with the missing-template label. Paginate so a | |
| // backlog of more than one page of labeled PRs is not silently | |
| // truncated. | |
| const prs = await github.paginate(github.rest.issues.listForRepo, { | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| state: 'open', | |
| labels: labelName, | |
| per_page: 100 | |
| }); | |
| for (const pr of prs) { | |
| // Only process pull requests (not issues) | |
| if (!pr.pull_request) continue; | |
| // Skip Dependabot PRs | |
| if (pr.user?.login === 'dependabot[bot]') { | |
| console.log(`Skipping Dependabot PR #${pr.number}`); | |
| continue; | |
| } | |
| // Check when the label was added by looking at timeline events. | |
| // Paginate: an active PR's timeline can exceed one page, which | |
| // could push the `labeled` event past the first 100 and leave a | |
| // stale PR open forever. | |
| const events = await github.paginate(github.rest.issues.listEventsForTimeline, { | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: pr.number, | |
| per_page: 100 | |
| }); | |
| const labelEvent = events | |
| .filter(e => e.event === 'labeled' && e.label?.name === labelName) | |
| .sort((a, b) => new Date(b.created_at) - new Date(a.created_at))[0]; | |
| if (!labelEvent) { | |
| console.log(`No label event found for PR #${pr.number}, skipping`); | |
| continue; | |
| } | |
| const labeledAt = new Date(labelEvent.created_at); | |
| const now = new Date(); | |
| const ageMs = now - labeledAt; | |
| if (ageMs < cutoffMs) { | |
| console.log(`PR #${pr.number} labeled ${Math.round(ageMs / 3600000)}h ago, not yet 24h`); | |
| continue; | |
| } | |
| console.log(`Closing PR #${pr.number} - missing template for over 24 hours`); | |
| // Add closing comment | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: pr.number, | |
| body: `This PR has been automatically closed because the required template sections were not restored within 24 hours.\n\nPlease create a new PR using the template and complete the checklist. The template helps maintainers review your contribution.` | |
| }); | |
| // Close the PR | |
| await github.rest.pulls.update({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: pr.number, | |
| state: 'closed' | |
| }); | |
| } |