Guidance for AI agents and contributors working in this repository.
Human-facing docs: README.md, DEVELOPMENT.md, CONTRIBUTING.md. Prefer those for end-user usage; this file is for how to change the action safely.
Docker-based GitHub Action that scans a PR diff for LaunchDarkly feature flag keys (and aliases), then:
- Sets workflow outputs (
any-changed,modified-flags,extinct-flags, etc.) - Optionally comments on the PR (and updates/deletes an existing LaunchDarkly comment)
- Optionally creates LaunchDarkly flag links
Published as launchdarkly/find-code-references-in-pull-request (current major: v2). Owners: @launchdarkly/team-foundation (CODEOWNERS).
Not supported: monorepos / searching across multiple LaunchDarkly projects.
Pipeline in main.go:
config → LD flags → PR diff → preprocess → match → summarize → outputs → comment → flag links
| Package / path | Role |
|---|---|
action.yml + Dockerfile |
Root Action contract and container build (multi-stage; final image has binary + git) |
docker/action.yml |
Opt-in composite entry point with dockerImage override (docker run) |
config/ |
Parse/validate INPUT_* env vars; GitHub client (incl. GHE) |
diff/ |
Preprocess PR diffs; ignore paths; scan hunks into the builder |
search/ |
Build matcher via ld-find-code-refs + alias generation |
internal/references/ |
Cap flags (max-flags); net add/delete → outputs modified-* (FlagsAdded), removed-*, optional extinct-* |
internal/extinctions/ |
Confirm removed flags are gone from the workspace |
comments/ |
Render PR comment HTML/Markdown from flag metadata |
internal/ldclient/ |
LaunchDarkly API: list flags, create flag links |
internal/github_actions/ |
GITHUB_OUTPUT via SetOutput, masks, log groups, notices |
internal/version/ |
Semver string for releases (Version) |
ignore/ |
.ldignore / ignore rules for scanned paths |
vendor/ |
Vendored Go modules — do not hand-edit |
Upstream library: launchdarkly/ld-find-code-refs (aliases, matchers, YAML options). Alias config comes from .launchdarkly/coderefs.yaml when present in the consumer repo (Viper also accepts coderefs.yml; see README / ld-find-code-refs docs).
# Unit tests
go test ./...
# Closer to CI:
# gotestsum --packages="./..." -- -tags=launchdarkly_easyjson -p=1
# Lint (matches pre-commit)
pre-commit run --all-files
# or: golangci-lint run -D funlen -D bodyclose -D typecheck
# Regenerate README inputs/outputs tables from action.yml
make docs
# After go.mod changes — always vendor
go mod tidy && go mod vendor
# Local e2e with nektos/act (use large runner; secrets from .secrets — see .secrets.example.env)
act -e testdata/act/pull-request.jsonGo version comes from go.mod (go-version-file: go.mod in CI). Current module requires Go 1.25.
When you add/change an input or output:
- Update
action.yml - Wire parsing/defaults in
config/config.go(and use inmain.go/ packages) - Run
make docsso README tables stay in sync (<!-- action-docs-* -->blocks) - Add a
CHANGELOG.mdentry under## [Unreleased] - Add/extend unit tests near the logic (
diff/,comments/,internal/references/)
When bumping dependencies:
- Update
go.mod/go.sum - Run
go mod tidy && go mod vendor - Prefer splitting huge vendor diffs across PRs if needed — the action’s own e2e job fetches the PR diff via the GitHub API and historically failed on oversized diffs (now has
git difffallback on HTTP 406, but keep PRs reviewable)
When bumping ld-find-code-refs, note behavioral changes that affect scanning (e.g. workflow file scanning) in the CHANGELOG.
max-flags: Finish scanning each diff file before applying the cap. Stopping mid-file caused false removals (#232).- Net classification: Classify by net add/delete counts so delete-then-re-add churn is modified, not removed.
- Large diffs: GitHub API may return 406; fallback path uses
git diffbetween merge-base and head (#172). Preserve that path and keepgitin the Docker image. - Comment identity: Existing comments are found by body containing
LaunchDarkly flag references. Do not change that marker without a migration plan. skip-commentpolarity: Always callsetOutputsand still build the comment body for flag-link dedupe. Whenskip-commentistrue, do not callpostGithubComment(skip ⇒ no GitHub comment write). Matchaction.yml/ README, not any inverted condition inmain.go.- Tokens: Mask
access-token/repo-tokenviagha.MaskInput. Never log secrets. Never commit.secretsor real tokens (only.secrets.example.env). - GHE: Non-
https://github.comGITHUB_SERVER_URLmust keep Enterprise client URLs (config.getGithubClient). - Defaults: Treat
action.ymldefaults as the product contract (create-flag-linksdefaulttruewas a v2 breaking change).
Recent merges use conventional-ish prefixes:
feat:,fix:,chore:,docs:,chore(deps):- Optional Jira:
[REL-xxxxx]in title/body when tracked - Release prep:
prepare X.Y.Z release— bumpCHANGELOG.md+internal/version/version.gotogether
PR checklist for agents:
- Scope is focused; avoid mixing feature work with large unrelated vendor bumps
- Tests for classification / comment / config behavior when logic changes
-
CHANGELOG.md[Unreleased]updated for user-visible changes -
make docsifaction.ymlchanged -
go mod vendorcommitted when modules change - No hand-edits under
vendor/except viago mod vendor
Do not add reviewers; CODEOWNERS / maintainers handle that (CONTRIBUTING.md).
- Same-repo PRs:
.github/workflows/main.ymlrunsgo-test,e2e-tests(needs secrets),e2e-docker-entrypoint(local + GHCR mirror/dockerpath), andgenerate-docs. - Fork PRs: secret-dependent jobs are skipped on
pull_request. Maintainers add thesafe-to-testlabel to run.github/workflows/test-fork-pr.yml(pull_request_target)..github/workflows/remove-safe-to-test-label.ymlstrips the label on new pushes — do not “fix around” that security gate. - e2e uses this action against itself (
uses: ./) with sandbox project credentials.
Follow DEVELOPMENT.md:
- Move
[Unreleased]notes into a new version section inCHANGELOG.md - Set
internal/version/version.goto match - Bump default
dockerImageindocker/action.yml(+ README pins) to the new semver - Publish via GitHub Marketplace release flow (manual publish step)
- Maintain major floating tag (
v2for 2.x) in addition to semver tags - Publish the runtime image
launchdarkly/find-code-references-in-pull-request:X.Y.Zvia.github/workflows/publish-image.yml(tag push orworkflow_dispatch; Hub creds viarelease-secrets+vars.AWS_ROLE_ARN/ SSM, same asld-find-code-refs)
Optional follow-up: thin the root Dockerfile to FROM that published image so default @v2 users also skip compile-on-run.
- Never commit secrets, PATs, or LaunchDarkly tokens
- Never weaken
safe-to-test/pull_request_targetcontrols without explicit maintainer request - Prefer fixing vulns by upgrading modules + vendoring (see Dependabot / remediation PRs)
- Do not expand scope to monorepo multi-project scanning unless that is an explicit product decision with docs + CHANGELOG
| Task | Start here |
|---|---|
| New input / output | action.yml, config/config.go, main.go, make docs |
| False positive/negative flags | diff/, internal/references/, search/ |
| Comment formatting | comments/ |
| Flag links / LD API | internal/ldclient/ |
| Extinct flags | internal/extinctions/, check-extinctions input |
| CI / fork testing | .github/workflows/ |
| Version / release | CHANGELOG.md, internal/version/version.go |