diff --git a/.github/workflows/pr-review-reusable.yml b/.github/workflows/pr-review-reusable.yml index 375cf62..02aab36 100644 --- a/.github/workflows/pr-review-reusable.yml +++ b/.github/workflows/pr-review-reusable.yml @@ -53,6 +53,8 @@ jobs: ref: ${{ inputs.harness-ref }} path: harness persist-credentials: false + - name: Install default review skill + run: install -D -m 0644 harness/examples/github-pr-reviewer/skills/pr-review/SKILL.md harness/skills/pr-review/SKILL.md - name: Install caller skill if: inputs.skill-path != '' env: @@ -60,8 +62,8 @@ jobs: run: | [[ "$SKILL_PATH" != /* && "$SKILL_PATH" != *..* ]] || exit 1 test -f "caller/$SKILL_PATH" - install -D -m 0644 "caller/$SKILL_PATH" harness/examples/github-pr-reviewer/skills/pr-review/SKILL.md - cmp -s "caller/$SKILL_PATH" harness/examples/github-pr-reviewer/skills/pr-review/SKILL.md + install -D -m 0644 "caller/$SKILL_PATH" harness/skills/pr-review/SKILL.md + cmp -s "caller/$SKILL_PATH" harness/skills/pr-review/SKILL.md - uses: actions/setup-go@v7 with: go-version-file: harness/go.mod @@ -102,6 +104,7 @@ jobs: REVIEW_HEAD: ${{ github.event.pull_request.head.sha }} VERTEX_AI_PROJECT_ID: ${{ vars.VERTEX_AI_PROJECT_ID }} VERTEX_AI_REGION: ${{ vars.VERTEX_AI_REGION }} + REVIEW_SKILL: ${{ github.workspace }}/harness/skills/pr-review/SKILL.md run: | token="$(gcloud auth print-access-token)" echo "::add-mask::$token" diff --git a/cmd/workflow_apply_test.go b/cmd/workflow_apply_test.go index 5c36b2d..d86a364 100644 --- a/cmd/workflow_apply_test.go +++ b/cmd/workflow_apply_test.go @@ -647,6 +647,68 @@ func TestCanonicalRunRequestResolvesConfigRelativeArtifacts(t *testing.T) { } } +func TestGitHubReviewerCustomSkillUsesExamplePayloadPath(t *testing.T) { + dir := t.TempDir() + exampleDir := filepath.Join("..", "examples", "github-pr-reviewer") + workflowPath := filepath.Join(dir, "opencode-harness.yaml") + workflowBytes, err := os.ReadFile(filepath.Join(exampleDir, "opencode-harness.yaml")) + if err != nil { + t.Fatalf("read reviewer workflow: %v", err) + } + if err := os.WriteFile(workflowPath, workflowBytes, 0o600); err != nil { + t.Fatalf("write reviewer workflow: %v", err) + } + configBytes, err := os.ReadFile(filepath.Join(exampleDir, "opencode-review.json")) + if err != nil { + t.Fatalf("read reviewer agent config: %v", err) + } + if err := os.WriteFile(filepath.Join(dir, "opencode-review.json"), configBytes, 0o600); err != nil { + t.Fatalf("write reviewer agent config: %v", err) + } + skillPath := filepath.Join(dir, "skills", "pr-review", "SKILL.md") + marker := "custom-skill-marker\n" + if err := os.MkdirAll(filepath.Dir(skillPath), 0o700); err != nil { + t.Fatalf("create skill directory: %v", err) + } + writeTestFile(t, skillPath, marker) + + diffPath := filepath.Join(dir, "pr.diff") + policyPath := filepath.Join(dir, "review-policy.yaml") + writeTestFile(t, diffPath, "diff --git a/file b/file\n") + writeTestFile(t, policyPath, "version: 1\n") + t.Setenv("REVIEW_DIFF", diffPath) + t.Setenv("REVIEW_POLICY", policyPath) + t.Setenv("REVIEW_REPOSITORY", "owner/repo") + t.Setenv("REVIEW_PR", "1") + t.Setenv("REVIEW_HEAD", "head") + t.Setenv("REVIEW_SKILL", skillPath) + + workflow, err := loadWorkflow(workflowPath, "", "", applyOverrides{}) + if err != nil { + t.Fatalf("loadWorkflow: %v", err) + } + req, cleanup, err := buildRunRequest(workflow) + if err != nil { + t.Fatalf("buildRunRequest: %v", err) + } + defer cleanup() + + for _, upload := range req.Uploads { + if upload.Dst != "/sandbox/review/skills/pr-review/SKILL.md" { + continue + } + got, err := os.ReadFile(upload.Src) + if err != nil { + t.Fatalf("read uploaded skill source: %v", err) + } + if string(got) != marker { + t.Fatalf("uploaded skill = %q, want marker %q", got, marker) + } + return + } + t.Fatal("review skill payload was not declared by the example") +} + func writeTestFile(t *testing.T, path, content string) { t.Helper() if err := os.WriteFile(path, []byte(content), 0o600); err != nil { diff --git a/examples/github-pr-reviewer/opencode-harness.yaml b/examples/github-pr-reviewer/opencode-harness.yaml index 65092b6..4104c02 100644 --- a/examples/github-pr-reviewer/opencode-harness.yaml +++ b/examples/github-pr-reviewer/opencode-harness.yaml @@ -18,7 +18,7 @@ sandbox: payloads: - source: ${REVIEW_DIFF} destination: /sandbox/review/pr.diff - - source: skills/pr-review/SKILL.md + - source: ${REVIEW_SKILL} destination: /sandbox/review/skills/pr-review/SKILL.md - source: opencode-review.json destination: /sandbox/opencode-review.json diff --git a/scripts/pr-review.sh b/scripts/pr-review.sh index e7d7e3f..f0dff21 100644 --- a/scripts/pr-review.sh +++ b/scripts/pr-review.sh @@ -129,6 +129,7 @@ run_review() { export REVIEW_DIFF="$REVIEW_DIR/pr.diff" export REVIEW_POLICY="$REVIEW_DIR/review-policy.yaml" + export REVIEW_SKILL="${REVIEW_SKILL:-examples/github-pr-reviewer/skills/pr-review/SKILL.md}" policy_template="${REVIEW_POLICY_TEMPLATE:-examples/github-pr-reviewer/review-policy.yaml}" sed \ -e "s|\${REVIEW_REPOSITORY}|$REVIEW_REPOSITORY|g" \