Skip to content

Commit e390e6b

Browse files
authored
Merge pull request #90 from fulll/feat/promotion-polish
feat: promotion polish — docs UX, CLI hyperlinks, completions auto-install
2 parents ebb77b2 + 5a7f0fa commit e390e6b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+3812
-204
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Reusable composite action — Start VitePress preview server
2+
#
3+
# Starts `bun run docs:preview` in the background and polls until the server
4+
# responds (or fails after a configurable timeout). Reused by a11y.yaml,
5+
# responsive.yaml, and any future workflow that needs a running docs preview.
6+
#
7+
# Usage:
8+
# - name: Start VitePress preview server
9+
# uses: ./.github/actions/start-preview-server
10+
# # (optionally) with:
11+
# # port: "4173"
12+
# # base: "/github-code-search/"
13+
# # timeout: "60"
14+
name: "Start VitePress preview server"
15+
description: >
16+
Starts `bun run docs:preview` in the background on a given port and polls
17+
until the server responds — or fails after a configurable timeout.
18+
19+
inputs:
20+
port:
21+
description: TCP port the preview server should listen on.
22+
default: "4173"
23+
base:
24+
description: Base URL path to poll when checking readiness.
25+
default: "/github-code-search/"
26+
timeout:
27+
description: Maximum number of seconds to wait for the server to be ready.
28+
default: "60"
29+
30+
runs:
31+
using: composite
32+
steps:
33+
- name: Start VitePress preview
34+
shell: bash
35+
run: bun run docs:preview -- --port ${{ inputs.port }} &
36+
37+
- name: Wait for preview server to be ready
38+
shell: bash
39+
run: |
40+
URL="http://localhost:${{ inputs.port }}${{ inputs.base }}"
41+
echo "Waiting for ${URL} …"
42+
DEADLINE=$(( $(date +%s) + ${{ inputs.timeout }} ))
43+
until curl -sf "${URL}" > /dev/null 2>&1; do
44+
if [ "$(date +%s)" -ge "${DEADLINE}" ]; then
45+
echo "::error::Preview server did not respond within ${{ inputs.timeout }} s on ${URL}."
46+
exit 1
47+
fi
48+
echo "… retrying in 2 s"
49+
sleep 2
50+
done
51+
echo "Preview server is ready."

.github/instructions/bug-fixing.instructions.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ excludeAgent: "code-review"
55

66
# Bug fixing — instructions for Copilot coding agent
77

8+
> **Skill reference:** for the extended symptom → module diagnostic table, test-first patterns and minimal fix principles read `.github/skills/bug-fixing.md` first.
9+
810
Follow these steps when fixing a bug in this repository.
911

1012
## 1. Reproduce the bug before writing any fix

.github/instructions/documentation.instructions.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ applyTo: "docs/**"
44

55
# Documentation — instructions for Copilot coding agent
66

7+
> **Skill reference:** for deep domain knowledge (VitePress theme architecture, CSS variables, accessibility patterns, responsive patterns, full validation commands) read `.github/skills/documentation.md` first.
8+
79
Follow these conventions when writing or editing pages in the `docs/` directory.
810

911
## 1. Tool & rendering pipeline
@@ -93,9 +95,20 @@ docs/
9395
Before opening a PR for any docs change:
9496

9597
```bash
96-
bun run docs:build # must complete without errors
97-
bun run format:check # oxfmt — no formatting diff
98+
bun run docs:build # must complete without errors or dead-link warnings
99+
bun run format:check # oxfmt — no formatting diff
98100
```
99101

100102
- All internal links must resolve (VitePress reports dead links on build).
101103
- No new `bun run knip` violations (docs/\*\* is excluded but `package.json` changes are not).
104+
105+
If the PR modifies any Vue component, CSS, or page layout, also run the accessibility and responsive suites:
106+
107+
```bash
108+
bun run docs:build:a11y
109+
bun run docs:preview -- --port 4173 &
110+
bun run docs:a11y # pa11y-ci WCAG 2.1 AA — must report 0 errors
111+
bun run docs:test:responsive # Playwright — 20/20 tests green (4 viewports × 5 pages)
112+
```
113+
114+
See `.github/skills/documentation.md` for pa11y configuration details, WCAG contrast rules, accessible component patterns, and responsive breakpoint guidance.
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
---
2+
applyTo: ".github/workflows/**"
3+
---
4+
5+
# GitHub Actions — instructions for Copilot coding agent
6+
7+
> **Skill reference:** for the full best-practices guide, action-pinning decision table, composite action patterns and PR comment strategies read `.github/skills/github-actions.md` first.
8+
9+
Follow these steps when creating or modifying GitHub Actions workflows in this repository.
10+
11+
## 1. File conventions
12+
13+
- All workflow files use the **`.yaml`** extension (not `.yml`).
14+
- File names use **kebab-case**: `a11y.yaml`, `lighthouse.yaml`, `docs.yaml`.
15+
- Every workflow must start with a block comment explaining its purpose, triggers and strategy.
16+
17+
## 2. Pinning third-party actions
18+
19+
**Every third-party action (anything not `actions/*` from GitHub itself) MUST be pinned
20+
to an exact commit SHA, never to a tag or a branch.**
21+
22+
```yaml
23+
# ✅ correct — SHA-pinned with tag comment
24+
uses: owner/repo@<40-char-sha> # v1.2.3
25+
26+
# ❌ wrong — mutable tag
27+
uses: owner/repo@v1
28+
29+
# ❌ wrong — branch (can be force-pushed)
30+
uses: owner/repo@main
31+
```
32+
33+
To resolve a tag to its commit SHA:
34+
35+
```bash
36+
git ls-remote https://github.com/<owner>/<repo>.git refs/tags/<tag> refs/tags/<tag>^{}
37+
# The ^{} peeled SHA (second line, if present) is the actual commit. Use that one.
38+
```
39+
40+
Add a comment `# v1.2.3` to the right of the hash so the version is human-readable.
41+
42+
**First-party GitHub actions** (`actions/checkout`, `actions/upload-artifact`, etc.) should
43+
also be pinned. Always resolve the latest released tag before using any action.
44+
45+
## 3. Coordinated version upgrades
46+
47+
When bumping an action version, update **every workflow file** that uses it in the same commit.
48+
Actions that appear in multiple workflows (e.g. `actions/checkout`, `oven-sh/setup-bun`) must
49+
always reference **the same commit SHA** across all files. Use `grep` to find all usages before
50+
opening a PR.
51+
52+
```bash
53+
grep -r "oven-sh/setup-bun" .github/workflows/
54+
```
55+
56+
## 4. DRY — composite action for shared steps
57+
58+
If two or more workflows share identical steps (e.g. starting a preview server, waiting for it
59+
to be ready), extract them into a **composite action** under `.github/actions/<name>/action.yml`.
60+
61+
```yaml
62+
# In a workflow:
63+
- name: Start VitePress preview server
64+
uses: ./.github/actions/start-preview-server
65+
```
66+
67+
The composite action must declare all inputs with defaults and document each one. Never
68+
duplicate multi-step shell sequences across workflows.
69+
70+
## 5. PR comment reports
71+
72+
Every workflow that produces a structured report (audit scores, coverage, test results) **must**:
73+
74+
1. Generate a formatted Markdown summary (table preferred).
75+
2. Post it as a **sticky PR comment** using
76+
`marocchino/sticky-pull-request-comment@<sha> # v2.9.4` with a unique `header:` value
77+
so the comment is updated (not duplicated) on each push to the PR.
78+
3. Use `actions/github-script` to build the comment body when the data comes from JSON files
79+
produced by the workflow (avoids shelling out to `jq` / Python).
80+
81+
```yaml
82+
- name: Generate scores comment
83+
id: comment-body
84+
if: github.event_name == 'pull_request'
85+
uses: actions/github-script@<sha> # v7
86+
with:
87+
result-encoding: string
88+
script: |
89+
// ... parse JSON, build Markdown table, return body
90+
91+
- name: Post / update comment on PR
92+
if: github.event_name == 'pull_request'
93+
uses: marocchino/sticky-pull-request-comment@<sha> # v2.9.4
94+
with:
95+
header: <unique-identifier>
96+
message: ${{ steps.comment-body.outputs.result }}
97+
```
98+
99+
## 6. Minimum required permissions
100+
101+
Set `permissions: contents: read` at the **workflow level** as the default.
102+
Override to `write` **at the job level** only for the exact permissions needed:
103+
104+
```yaml
105+
permissions:
106+
contents: read # workflow-level default (principle of least privilege)
107+
108+
jobs:
109+
audit:
110+
permissions:
111+
contents: read
112+
pull-requests: write # needed only to post the PR comment
113+
```
114+
115+
## 7. Concurrency
116+
117+
Every workflow that produces side-effects (deploy, comment, upload) must define a
118+
`concurrency` block to cancel stale runs:
119+
120+
```yaml
121+
concurrency:
122+
group: <workflow-name>-${{ github.ref }}
123+
cancel-in-progress: true
124+
```
125+
126+
## 8. Validation checklist before opening a PR
127+
128+
```bash
129+
# Lint all workflow files locally (requires actionlint):
130+
actionlint .github/workflows/*.yaml .github/actions/**/*.yml
131+
132+
# Confirm every action is pinned:
133+
grep -rn "uses:" .github/workflows/ | grep -v "@[a-f0-9]\{40\}"
134+
# → must return nothing
135+
```
136+
137+
Also verify:
138+
139+
- [ ] All `.yml` workflow files have been renamed to `.yaml`
140+
- [ ] Every new third-party action has a `# vX.Y.Z` comment after its SHA
141+
- [ ] New reusable composite actions are under `.github/actions/<name>/action.yml`
142+
- [ ] The workflow self-references the correct filename (e.g. in `paths:`)
143+
- [ ] `pull-requests: write` is set only on jobs that post comments
144+
- [ ] No `bunx` in workflow `run:` steps — use binaries from `node_modules/.bin/` or
145+
scripts defined in `package.json` via `bun run <script>`

.github/instructions/implement-feature.instructions.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ excludeAgent: "code-review"
55

66
# Implement feature — instructions for Copilot coding agent
77

8+
> **Skill reference:** for the full architectural layer map, type-first design patterns, CLI option conventions, render sub-module extension playbook and test strategies read `.github/skills/feature.md` first.
9+
810
Follow these steps when implementing a new feature in this repository.
911

1012
## 1. Understand the task scope before writing code

.github/instructions/refactoring.instructions.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ excludeAgent: "code-review"
55

66
# Refactoring — instructions for Copilot coding agent
77

8+
> **Skill reference:** for architectural invariants, safe rename playbook, module extraction patterns, characterisation test strategy and `knip` output interpretation read `.github/skills/refactoring.md` first.
9+
810
Follow these steps when refactoring existing code in this repository.
911

1012
## 1. Define the goal and scope

.github/instructions/release.instructions.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ excludeAgent: "code-review"
55

66
# Release — instructions for Copilot coding agent
77

8+
> **Skill reference:** for the semver decision guide, CD pipeline mechanics, binary targets, blog post format reference and versioned docs snapshot details read `.github/skills/release.md` first.
9+
810
Follow these steps when cutting a new release of `github-code-search`.
911

1012
## 1. Determine the version bump

.github/skills/bug-fixing.md

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
# Bug fixing skill — github-code-search
2+
3+
Deep reference for diagnosing and fixing bugs in this codebase.
4+
This skill complements `.github/instructions/bug-fixing.instructions.md`.
5+
6+
---
7+
8+
## Symptom → module diagnostic table
9+
10+
| Symptom | Primary suspect | Secondary suspect |
11+
| ----------------------------------------------------------- | ----------------------------------------------- | --------------------------------- |
12+
| Results missing or duplicated | `src/aggregate.ts` | `src/api.ts` (pagination) |
13+
| Wrong repository grouping | `src/group.ts` | `src/aggregate.ts` |
14+
| `--exclude-repositories` / `--exclude-extracts` not working | `src/aggregate.ts` | `github-code-search.ts` (parsing) |
15+
| Markdown output malformed | `src/output.ts` ||
16+
| JSON output missing fields or wrong shape | `src/output.ts` | `src/types.ts` (interface) |
17+
| Syntax highlighting wrong colour / wrong language | `src/render/highlight.ts` ||
18+
| Row navigation skips or wraps incorrectly | `src/render/rows.ts` | `src/tui.ts` (key handler) |
19+
| Select-all / select-none inconsistent | `src/render/selection.ts` | `src/tui.ts` |
20+
| Filter count / stats incorrect | `src/render/filter.ts`, `src/render/summary.ts` ||
21+
| Path filter (`/regex/`) doesn't match expected | `src/render/filter-match.ts` | `src/tui.ts` (filter state) |
22+
| API returns 0 results or stops paginating | `src/api.ts` | `src/api-utils.ts` |
23+
| Rate limit hit / 429 not retried | `src/api-utils.ts` (`fetchWithRetry`) ||
24+
| TUI shows blank screen or wrong row | `src/tui.ts` | `src/render/rows.ts` |
25+
| Help overlay doesn't appear / has wrong keys | `src/render.ts` (`renderHelpOverlay`) | `src/tui.ts` |
26+
| Upgrade fails or replaces wrong binary | `src/upgrade.ts` ||
27+
| Completion script wrong content | `src/completions.ts` ||
28+
| Completion file written to wrong path | `src/completions.ts` (`getCompletionFilePath`) | env vars (`XDG_*`, `ZDOTDIR`) |
29+
| Completion not refreshed after upgrade | `src/upgrade.ts` (`refreshCompletions`) ||
30+
| `--version` shows wrong info | `build.ts` (SHA injection) ||
31+
| CLI option ignored or parsed wrong | `github-code-search.ts` | `src/types.ts` (`OutputType`) |
32+
33+
---
34+
35+
## Reproducing a bug
36+
37+
A complete bug report must have:
38+
39+
1. **Exact command** (redact `GITHUB_TOKEN` with `***`):
40+
```
41+
GITHUB_TOKEN=*** github-code-search query "pattern" --org acme
42+
```
43+
2. **Observed output** vs **expected output**.
44+
3. **Version string**: `github-code-search --version` → e.g. `1.8.0 (a1b2c3d · darwin/arm64)`.
45+
4. **Bun version** (when running from source): `bun --version`.
46+
47+
If the report is missing items 1 or 3, read the relevant module(s) to hypothesise the root cause before asking for more info.
48+
49+
---
50+
51+
## Test-first patterns for bugs
52+
53+
### Pure function bug (aggregate, group, output, render/\*)
54+
55+
```typescript
56+
// src/aggregate.test.ts
57+
describe("applyFiltersAndExclusions — bug #N", () => {
58+
it("excludes org-prefixed repo names correctly", () => {
59+
const result = applyFiltersAndExclusions(matches, {
60+
excludeRepositories: ["acme/my-repo"], // the previously broken form
61+
});
62+
expect(result).not.toContainEqual(expect.objectContaining({ repo: "acme/my-repo" }));
63+
});
64+
});
65+
```
66+
67+
The test must **fail** with the current code before the fix. Commit the test, then fix.
68+
69+
### api-utils bug (retry / pagination)
70+
71+
```typescript
72+
// src/api-utils.test.ts
73+
it("retries on 429 with Retry-After header", async () => {
74+
let callCount = 0;
75+
globalThis.fetch = async () => {
76+
callCount++;
77+
if (callCount === 1) {
78+
return new Response(null, {
79+
status: 429,
80+
headers: { "Retry-After": "0" },
81+
});
82+
}
83+
return new Response(JSON.stringify({ ok: true }), { status: 200 });
84+
};
85+
await fetchWithRetry("https://api.github.com/test");
86+
expect(callCount).toBe(2);
87+
});
88+
```
89+
90+
### Side-effectful bug (tui, api) — no unit test possible
91+
92+
Document manual repro steps in the PR description:
93+
94+
```markdown
95+
## Steps to reproduce (before fix)
96+
97+
1. `GITHUB_TOKEN=... github-code-search query "foo" --org acme`
98+
2. Press `` past the last result
99+
3. Expected: cursor stays on last row / Expected: wraps to first row
100+
4. Observed: cursor jumps to blank row
101+
```
102+
103+
---
104+
105+
## Minimal fix principles
106+
107+
- **Touch only the root cause.** Do not opportunistically refactor neighbouring code in the same PR — it makes the fix harder to review and risks introducing new bugs.
108+
- **Respect pure/IO layering**: a fix in `aggregate.ts` must not add a `console.log` call.
109+
- **Type changes cascade**: if `src/types.ts` must change, run `bun run knip` to find all affected consumers and update them all in the same PR.
110+
- **Regression comment**: if the root cause is non-obvious, add one line above the fix:
111+
```typescript
112+
// Fix: short names ("repo") and qualified names ("org/repo") must both match — see issue #N
113+
```
114+
115+
---
116+
117+
## Validation after fix
118+
119+
```bash
120+
bun test # the previously failing test now passes; full suite still green
121+
bun run lint # oxlint — zero errors
122+
bun run format:check # oxfmt — no formatting diff
123+
bun run knip # no unused exports or imports
124+
bun run build.ts # binary compiles without errors
125+
```

0 commit comments

Comments
 (0)