Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ help:
@echo " go-fmt - Format Go code"
@echo " go-vet - Run go vet"
@echo " go-tidy - Run go mod tidy"
@echo " script-test - Run shell script tests (post-triage, validate-output-schema)"
@echo " script-test - Run shell script tests (post-triage, post-code, validate-output-schema)"
@echo " test - Run all checks: lint, go-vet, go-test, script-test"
@echo " e2e-test - Run admin e2e tests (requires E2E_GITHUB_SESSION_FILE or E2E_GITHUB_USERNAME + E2E_GITHUB_PASSWORD)"
@echo " e2e-export-session - Login to GitHub and export a Playwright session file"
Expand Down Expand Up @@ -99,6 +99,7 @@ go-tidy:

script-test:
bash internal/scaffold/fullsend-repo/scripts/post-triage-test.sh
bash internal/scaffold/fullsend-repo/scripts/post-code-test.sh
bash internal/scaffold/fullsend-repo/scripts/validate-output-schema-test.sh

test: lint go-vet go-test script-test
Expand Down
130 changes: 130 additions & 0 deletions internal/scaffold/fullsend-repo/scripts/post-code-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#!/usr/bin/env bash
# post-code-test.sh — Test the PR title injection logic from post-code.sh.
#
# Extracts and tests the title-rewriting logic in isolation using shell
# functions. This avoids needing a full git repo or GitHub API access.
#
# Run from the repo root:
# bash internal/scaffold/fullsend-repo/scripts/post-code-test.sh

set -euo pipefail

FAILURES=0

# ---------------------------------------------------------------------------
# Test helper — reimplements the title-rewriting logic from post-code.sh
# so we can test it without a git repo or network access.
# ---------------------------------------------------------------------------
rewrite_title() {
local commit_subject="$1"
local issue_number="$2"

if echo "${commit_subject}" | grep -qE '^[a-z]+\('; then
echo "${commit_subject}"
elif echo "${commit_subject}" | grep -qE '^[a-z]+: '; then
echo "${commit_subject}" | sed "s/^\([a-z]*\): /\1(#${issue_number}): /"
else
echo "${commit_subject}"
fi
}

run_test() {
local test_name="$1"
local commit_subject="$2"
local issue_number="$3"
local expected="$4"

local actual
actual="$(rewrite_title "${commit_subject}" "${issue_number}")"

if [ "${actual}" != "${expected}" ]; then
echo "FAIL: ${test_name}"
echo " input: '${commit_subject}' (issue #${issue_number})"
echo " expected: '${expected}'"
echo " actual: '${actual}'"
FAILURES=$((FAILURES + 1))
return
fi

echo "PASS: ${test_name}"
}

# --- Test cases ---

# Plain conventional commit — should inject issue reference
run_test "fix-without-scope" \
"fix: correct placeholder text in secrets page dropdowns" \
"837" \
"fix(#837): correct placeholder text in secrets page dropdowns"

run_test "feat-without-scope" \
"feat: add CSV export support" \
"42" \
"feat(#42): add CSV export support"

run_test "chore-without-scope" \
"chore: update dependencies" \
"100" \
"chore(#100): update dependencies"

run_test "docs-without-scope" \
"docs: update contributing guide" \
"55" \
"docs(#55): update contributing guide"

run_test "refactor-without-scope" \
"refactor: simplify error handling" \
"200" \
"refactor(#200): simplify error handling"

# Already has a scope — should NOT modify
run_test "already-has-issue-scope" \
"fix(#837): correct placeholder text" \
"837" \
"fix(#837): correct placeholder text"

run_test "already-has-jira-scope" \
"fix(KFLUXUI-1200): correct placeholder text" \
"837" \
"fix(KFLUXUI-1200): correct placeholder text"

run_test "already-has-component-scope" \
"feat(api): add new endpoint" \
"42" \
"feat(api): add new endpoint"

# Non-conventional titles — should NOT modify
run_test "non-conventional-title" \
"Add CSV export support" \
"42" \
"Add CSV export support"

run_test "uppercase-type" \
"Fix: correct placeholder text" \
"42" \
"Fix: correct placeholder text"

run_test "no-colon" \
"fix the placeholder text" \
"42" \
"fix the placeholder text"

# Edge cases
run_test "test-type" \
"test: add unit tests for export" \
"99" \
"test(#99): add unit tests for export"

run_test "ci-type" \
"ci: update workflow permissions" \
"10" \
"ci(#10): update workflow permissions"

# --- Summary ---

echo ""
if [ ${FAILURES} -gt 0 ]; then
echo "${FAILURES} test(s) failed"
exit 1
fi
echo "All tests passed"
19 changes: 18 additions & 1 deletion internal/scaffold/fullsend-repo/scripts/post-code.sh
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,24 @@ COMMIT_BODY="$(echo "${COMMIT_BODY_RAW}" | awk '
END { if (buf) print buf }
')"

PR_TITLE="${COMMIT_SUBJECT}"
# ---------------------------------------------------------------------------
# Ensure PR title includes an issue reference.
#
# Many repos enforce PR title conventions like "type(TICKET): description".
# The code agent may produce a plain "type: description" commit subject that
# omits the issue reference. When the title follows conventional commit format
# (word + colon), inject the issue number as a scope if no scope is present.
# ---------------------------------------------------------------------------
if echo "${COMMIT_SUBJECT}" | grep -qE '^[a-z]+\('; then
# Already has a scope — e.g. "fix(#42): ..." or "feat(PROJ-123): ..."
PR_TITLE="${COMMIT_SUBJECT}"
elif echo "${COMMIT_SUBJECT}" | grep -qE '^[a-z]+: '; then
# Conventional commit without scope — inject issue reference
PR_TITLE="$(echo "${COMMIT_SUBJECT}" | sed "s/^\([a-z]*\): /\1(#${ISSUE_NUMBER}): /")"
else
# Non-conventional title — leave as-is
PR_TITLE="${COMMIT_SUBJECT}"
fi

FILE_SUMMARY="$(echo "${CHANGED_FILES}" | sort | sed 's|^| - `|; s|$|`|')"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,11 @@ and `Glob` to inspect project configuration:
`package.json`, `pyproject.toml`, or equivalent build config.
3. **Check for linter configuration.** Use `Glob` to find files like
`.golangci.yml`, `.eslintrc*`, `.pre-commit-config.yaml`, `ruff.toml`.
4. **Check for PR title conventions.** Look for title format requirements
in `CLAUDE.md`, `CONTRIBUTING.md`, or `.github/workflows/` (e.g., a
`check-pr-title` action with a regex). If the repo requires a specific
format like `type(TICKET): description`, note the convention — you will
use it when writing the commit subject in step 10.

From these files, determine:

Expand All @@ -167,6 +172,10 @@ From these files, determine:
`npm test`, `pytest`)
- **Lint command** — how to run linters (e.g., `make lint`, `pre-commit run --files`)
- **Commit conventions** — signing requirements, message format
- **PR title conventions** — whether the repo enforces a title format via
CI (e.g., `type(TICKET): description`). The post-script uses the commit
subject as the PR title and will inject a `(#ISSUE_NUMBER)` scope if
missing, but matching the repo's expected format directly is preferred.
- **Branch conventions** — naming patterns, target branch

If a `TARGET_BRANCH` environment variable is set, use it. Otherwise, determine
Expand Down Expand Up @@ -581,7 +590,15 @@ The commit message must:
`CONTRIBUTING.md`, `CLAUDE.md`, `.gitlint`, or the existing commit history
uses a specific format (e.g., Conventional Commits, Angular-style, ticket
prefixes), follow it.
- **Fall back to `<type>: <description>` only if no convention was found.**
- **Include the issue reference in the commit subject.** The post-script
uses the commit subject as the PR title. Many repos enforce PR title
conventions like `type(TICKET): description`. Always include the issue
number as a scope: `<type>(#<number>): <description>`. If the repo uses
Jira-style ticket IDs (e.g., `PROJ-123`) and the issue title or body
contains one, use that instead: `<type>(PROJ-123): <description>`.
- **Fall back to `<type>(#<number>): <description>` if no convention was
found.** The `(#<number>)` scope ensures the PR title passes most
title-check CI jobs.
- Reference the issue number with `Closes #<number>` in the body.

**Title length — check `.gitlint` if it exists:**
Expand Down Expand Up @@ -624,7 +641,7 @@ The commit body should:
- Note any trade-offs, assumptions, or edge cases

```bash
git commit -s -m "<type>: <short-description>
git commit -s -m "<type>(#<number>): <short-description>

<What changed and why. Hard-wrap at the limit from
.gitlint if one is configured. Write substantive
Expand Down
Loading