Skip to content

feat(integration-github): emit event when pull request is approved#374

Closed
Re-Gouveia-QA wants to merge 13 commits into
4.xfrom
feat/github-pr-approved
Closed

feat(integration-github): emit event when pull request is approved#374
Re-Gouveia-QA wants to merge 13 commits into
4.xfrom
feat/github-pr-approved

Conversation

@Re-Gouveia-QA

Copy link
Copy Markdown

Contexto


  • Foi adicionado o evento GithubPullRequestApproved em integration-github.
  • O webhook de pull_request_review agora emite esse evento quando a review está com estado approved.
  • O evento carrega autor do PR, repositório, número do PR e data da aprovação.
  • Mantém o registro normal da contribuição de review via GithubContributionRecorded.
  • Adiciona testes para emissão do evento em review aprovada, fallback do autor do PR, não emissão em review não aprovada e não duplicação em reentrega do mesmo delivery id.

Closes #345

@Re-Gouveia-QA Re-Gouveia-QA requested a review from a team June 25, 2026 23:33
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Pro

Run ID: dcbeafb1-26cd-4fc5-8f82-dbb1477bdc71

📥 Commits

Reviewing files that changed from the base of the PR and between 3079a6f and e2c62ad.

📒 Files selected for processing (1)
  • composer.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • composer.json

📝 Walkthrough

Walkthrough

Adds onboarding and squads bounded-context docs/config, updates repo dependency mapping and root package requirements, and introduces a new GithubPullRequestApproved event emitted from approved pull_request_review webhooks with test coverage.

Possibly related issues

Suggested reviewers

  • danielhe4rt
  • Clintonrocha98
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The onboarding and squads modules, docs, and composer/PHPStan scaffolding are unrelated to #345. Split the onboarding/squads/module-scaffolding changes into separate PRs or remove them from this approval-event patch.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the main change: emitting an approval event from integration-github.
Description check ✅ Passed The description is directly about the same GitHub approval event and its tests.
Linked Issues check ✅ Passed The PR satisfies #345: it adds the event, emits it on approved reviews, uses the PR author, dedups by delivery ID, and adds tests.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (4)
composer.json (1)

32-32: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Inconsistent version constraints for new packages.

he4rt/onboarding and he4rt/squads use * while other he4rt/* packages use >=1 or ^1.0. Align constraints with the existing pattern to prevent accidental major-version upgrades.

Also applies to: 37-37

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@composer.json` at line 32, The new package constraints for he4rt/onboarding
and he4rt/squads are inconsistent with the rest of the he4rt/* entries in
composer.json. Update the dependency versions in the composer manifest to match
the existing pattern used by the other packages (such as >=1 or ^1.0) so the
added packages do not allow unrestricted major upgrades.
app-modules/onboarding/CONTEXT.md (1)

26-26: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add language specifiers to fenced code blocks.

-```
+```text

Also applies to: 41-41

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app-modules/onboarding/CONTEXT.md` at line 26, The fenced code block in
CONTEXT.md is missing a language specifier, so update the affected markdown
fences to use the appropriate format label; locate the code block(s) near the
onboarding context content and add the specifier consistently to both referenced
occurrences.
app-modules/squads/CONTEXT.md (1)

50-50: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add language specifier to fenced code block.

-```
+```text
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app-modules/squads/CONTEXT.md` at line 50, The fenced code block in
CONTEXT.md is missing a language specifier, so update the markdown fence to use
an explicit text label. Locate the affected fenced block in the context
documentation and change it to a properly annotated code block so the formatter
and renderers treat it as plain text.
app-modules/integration-github/src/Webhook/ProjectGithubEvent.php (1)

117-117: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use intFrom instead of casting a string-coerced value.

(int) $this->stringFrom(...) round-trips through string; intFrom already returns a typed int from the payload.

-                    pr_number: (int) $this->stringFrom($payload, 'pull_request.number'),
+                    pr_number: $this->intFrom($payload, 'pull_request.number') ?? 0,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app-modules/integration-github/src/Webhook/ProjectGithubEvent.php` at line
117, The pull request number parsing in ProjectGithubEvent is using a string
coercion followed by a cast, which is unnecessary and less direct. Update the
payload mapping in the event-handling code to use intFrom for pr_number instead
of casting the result of stringFrom, keeping the typed integer flow consistent
with the other payload accessors.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app-modules/integration-github/src/Webhook/ProjectGithubEvent.php`:
- Around line 111-121: The approved pull request event is being dispatched
inside the per-tenant review flow, which causes duplicate
`GithubPullRequestApproved` emissions when `execute()` iterates over multiple
tenants for the same repo. Move the `state === 'approved'` check and the
`event(new GithubPullRequestApproved(...))` call out of
`ProjectGithubEvent::review()` and into `maybeEmitApproved()` so the PR-level
event is emitted once per delivery, before or outside the tenant fan-out loop.

In `@app-modules/integration-github/tests/Feature/GithubWebhookTest.php`:
- Around line 178-187: The current webhook test only covers duplicate delivery
handling for one repository, so it does not exercise the multi-tenant fan-out
path in ProjectGithubEvent::review. Add a new test alongside GithubWebhookTest
that creates two tenant records tracking the same GithubRepository full_name,
then send the same pull_request_review webhook delivery and assert
GithubPullRequestApproved is dispatched exactly once. Use the existing
postGithubWebhook helper and Event::fake/assertDispatchedTimes to verify the
per-tenant deduplication behavior.

In `@app-modules/onboarding/composer.json`:
- Around line 1-27: The composer metadata for the onboarding package is out of
sync with the lock file, so update the dependency state and regenerate
composer.lock to include the new packages. Use the package definition in
composer.json for He4rt\\Onboarding and then run the appropriate Composer update
for the affected packages so he4rt/onboarding and he4rt/squads are reflected in
the lock file.

---

Nitpick comments:
In `@app-modules/integration-github/src/Webhook/ProjectGithubEvent.php`:
- Line 117: The pull request number parsing in ProjectGithubEvent is using a
string coercion followed by a cast, which is unnecessary and less direct. Update
the payload mapping in the event-handling code to use intFrom for pr_number
instead of casting the result of stringFrom, keeping the typed integer flow
consistent with the other payload accessors.

In `@app-modules/onboarding/CONTEXT.md`:
- Line 26: The fenced code block in CONTEXT.md is missing a language specifier,
so update the affected markdown fences to use the appropriate format label;
locate the code block(s) near the onboarding context content and add the
specifier consistently to both referenced occurrences.

In `@app-modules/squads/CONTEXT.md`:
- Line 50: The fenced code block in CONTEXT.md is missing a language specifier,
so update the markdown fence to use an explicit text label. Locate the affected
fenced block in the context documentation and change it to a properly annotated
code block so the formatter and renderers treat it as plain text.

In `@composer.json`:
- Line 32: The new package constraints for he4rt/onboarding and he4rt/squads are
inconsistent with the rest of the he4rt/* entries in composer.json. Update the
dependency versions in the composer manifest to match the existing pattern used
by the other packages (such as >=1 or ^1.0) so the added packages do not allow
unrestricted major upgrades.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 3e9a0da5-0326-46d0-9091-f10cf8fda1d5

📥 Commits

Reviewing files that changed from the base of the PR and between 407b7c0 and 3079a6f.

📒 Files selected for processing (29)
  • CONTEXT-MAP.md
  • app-modules/integration-github/src/Events/GithubPullRequestApproved.php
  • app-modules/integration-github/src/Webhook/ProjectGithubEvent.php
  • app-modules/integration-github/tests/Feature/GithubWebhookTest.php
  • app-modules/onboarding/CONTEXT.md
  • app-modules/onboarding/composer.json
  • app-modules/onboarding/database/factories/.gitkeep
  • app-modules/onboarding/database/migrations/.gitkeep
  • app-modules/onboarding/database/seeders/.gitkeep
  • app-modules/onboarding/docs/adr/0001-onboarding-polimorfico-por-tipo.md
  • app-modules/onboarding/docs/adr/0002-sinal-de-pr-aprovado-via-evento-de-dominio.md
  • app-modules/onboarding/phpstan.ignore.neon
  • app-modules/onboarding/phpstan.neon
  • app-modules/onboarding/src/Providers/OnboardingServiceProvider.php
  • app-modules/onboarding/tests/Feature/.gitkeep
  • app-modules/onboarding/tests/Unit/.gitkeep
  • app-modules/squads/CONTEXT.md
  • app-modules/squads/composer.json
  • app-modules/squads/database/factories/.gitkeep
  • app-modules/squads/database/migrations/.gitkeep
  • app-modules/squads/database/seeders/.gitkeep
  • app-modules/squads/docs/adr/0001-governanca-como-registro.md
  • app-modules/squads/docs/adr/0002-modelo-de-dados.md
  • app-modules/squads/phpstan.ignore.neon
  • app-modules/squads/phpstan.neon
  • app-modules/squads/src/Providers/SquadsServiceProvider.php
  • app-modules/squads/tests/Feature/.gitkeep
  • app-modules/squads/tests/Unit/.gitkeep
  • composer.json

Comment on lines +111 to +121
$state = $this->stringFrom($review, 'state');
if ($state === 'approved') {
event(
new GithubPullRequestApproved(
author_login: $this->stringFrom($payload, 'pull_request.user.login', 'ghost'),
repo: $repo,
pr_number: (int) $this->stringFrom($payload, 'pull_request.number'),
approved_at: $submittedAt,
),
);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Event emitted inside the per-tenant fan-out loop — duplicate emissions when multiple tenants track the same repo.

execute() calls review() once per tenant in tenantsTracking($repo). GithubPullRequestApproved carries no tenant_id and is emitted unconditionally on state === 'approved', so a single approval on a repo tracked by N tenants dispatches N events. Downstream resolves the PR author and awards coins/xp, so the author is rewarded N times. This bypasses the dedup guard RecordContribution uses (wasRecentlyCreated). Tests pass only because they create a single repository/tenant.

Emit this PR-level event once per delivery, outside the tenant loop.

Proposed direction
     public function execute(string $event, array $payload): void
     {
         $repo = Str::lower($this->stringFrom($payload, 'repository.full_name'));
         if ($repo === '') {
             return;
         }
+
+        if ($event === 'pull_request_review') {
+            $this->maybeEmitApproved($repo, $payload);
+        }
 
         foreach ($this->tenantsTracking($repo) as $tenantId) {
             match ($event) {

Move the approved-state check + event(...) into maybeEmitApproved() and drop it from review().

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app-modules/integration-github/src/Webhook/ProjectGithubEvent.php` around
lines 111 - 121, The approved pull request event is being dispatched inside the
per-tenant review flow, which causes duplicate `GithubPullRequestApproved`
emissions when `execute()` iterates over multiple tenants for the same repo.
Move the `state === 'approved'` check and the `event(new
GithubPullRequestApproved(...))` call out of `ProjectGithubEvent::review()` and
into `maybeEmitApproved()` so the PR-level event is emitted once per delivery,
before or outside the tenant fan-out loop.

Comment on lines +178 to +187
it('nao duplica GithubPullRequestApproved em reentrega do mesmo delivery id', function (): void {
Event::fake([GithubPullRequestApproved::class]);
GithubRepository::factory()->create(['full_name' => 'he4rt/heartdevs.com']);
$delivery = Str::uuid()->toString();

postGithubWebhook('pull_request_review', prReviewWebhookPayload(), delivery: $delivery)->assertSuccessful();
postGithubWebhook('pull_request_review', prReviewWebhookPayload(), delivery: $delivery)->assertSuccessful();

Event::assertDispatchedTimes(GithubPullRequestApproved::class, 1);
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Missing coverage: multi-tenant fan-out.

All tests create a single repository, so the per-tenant duplicate-emission path (see ProjectGithubEvent::review) is never exercised. Add a test that registers two tenants tracking the same full_name and asserts GithubPullRequestApproved dispatches exactly once.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app-modules/integration-github/tests/Feature/GithubWebhookTest.php` around
lines 178 - 187, The current webhook test only covers duplicate delivery
handling for one repository, so it does not exercise the multi-tenant fan-out
path in ProjectGithubEvent::review. Add a new test alongside GithubWebhookTest
that creates two tenant records tracking the same GithubRepository full_name,
then send the same pull_request_review webhook delivery and assert
GithubPullRequestApproved is dispatched exactly once. Use the existing
postGithubWebhook helper and Event::fake/assertDispatchedTimes to verify the
per-tenant deduplication behavior.

Comment on lines +1 to +27
{
"name": "he4rt/onboarding",
"description": "",
"type": "library",
"version": "1.0.0",
"license": "proprietary",
"autoload": {
"psr-4": {
"He4rt\\Onboarding\\": "src/",
"He4rt\\Onboarding\\Database\\Factories\\": "database/factories/",
"He4rt\\Onboarding\\Database\\Seeders\\": "database/seeders/"
}
},
"autoload-dev": {
"psr-4": {
"He4rt\\Onboarding\\Tests\\": "tests/"
}
},
"minimum-stability": "stable",
"extra": {
"laravel": {
"providers": [
"He4rt\\Onboarding\\Providers\\OnboardingServiceProvider"
]
}
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Regenerate composer.lock to include new packages.

The CI warning indicates the lock file is stale. Run composer update to pick up he4rt/onboarding and he4rt/squads.

🧰 Tools
🪛 GitHub Actions: Continuous Integration / Setup PHP

[warning] 1-1: Composer install warning: The lock file is not up to date with the latest changes in composer.json. Required packages are missing from composer.lock (he4rt/onboarding, he4rt/squads).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app-modules/onboarding/composer.json` around lines 1 - 27, The composer
metadata for the onboarding package is out of sync with the lock file, so update
the dependency state and regenerate composer.lock to include the new packages.
Use the package definition in composer.json for He4rt\\Onboarding and then run
the appropriate Composer update for the affected packages so he4rt/onboarding
and he4rt/squads are reflected in the lock file.

@Re-Gouveia-QA Re-Gouveia-QA changed the base branch from 4.x to feat/onboarding-squads June 26, 2026 11:13
@Re-Gouveia-QA Re-Gouveia-QA changed the base branch from feat/onboarding-squads to 4.x June 26, 2026 11:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(integration-github): emitir evento de domínio GithubPullRequestApproved

3 participants