What Happens When a Reviewer Is Removed from a Pull Request in the GitHub‑Asana Action
When a reviewer is removed from a pull request, the GitHub‑Asana Request Review Action processes a review_request_removed webhook event to synchronize the remaining reviewers with Asana sub-tasks while leaving the removed reviewer's artifacts untouched.
The keitap/github-asana-request-review-action repository automates the creation and management of Asana sub-tasks for GitHub pull request reviewers. When a reviewer is removed from a pull request, the action executes a specific synchronization flow in handler.go to ensure the Asana project reflects the current reviewer list without explicitly deleting orphaned sub-tasks.
Detecting the review_request_removed Event
The flow begins when GitHub dispatches a review_request_removed webhook event to the action. In handler.go, the updateReviewers function checks the incoming pull request action against the constant prEventActionReviewRequestedRemoved to identify removal events.
This detection occurs at lines 13‑19 of handler.go, where the action constants are defined. Once identified, the handler sets hasRequestedReviewersFields to true, signaling that the payload contains a pre-filtered reviewer list.
Retrieving the Current Reviewer List
Because the event type is review_request_removed, GitHub's payload already excludes the removed reviewer from the RequestedReviewers slice. The handler leverages this behavior at lines 101‑108 of handler.go to obtain the authoritative list of remaining reviewers.
Rather than maintaining a local cache or diffing against previous states, the action relies entirely on the GitHub API's current snapshot. This approach simplifies state management by treating each webhook event as the source of truth.
Mapping GitHub Users to Asana Accounts
For each reviewer present in the filtered list, the action must resolve the GitHub login to an Asana GID. The fetchAccount function handles this translation at lines 124‑135 of handler.go.
This mapping is critical for ensuring that sub-tasks are assigned to the correct Asana users. If a GitHub user lacks a configured Asana mapping, the function handles the lookup gracefully to prevent the entire synchronization from failing.
Synchronizing Sub-Tasks via Upsert Operations
The core synchronization logic resides in the upsertReviewer function, called for each remaining reviewer at lines 138‑143 of handler.go. This function implements an idempotent upsert pattern against the Asana API:
- Update existing sub-tasks: If a code-review sub-task already exists under the feature task for a given reviewer, the action calls
UpdateCodeReviewSubtaskto refresh metadata. - Create missing sub-tasks: If no sub-task exists for the reviewer, the action invokes
AddCodeReviewSubtaskto create a new code-review sub-task in Asana.
These operations are defined in asana.go, which handles the actual API communication with Asana's task management endpoints.
Preservation of Removed Reviewer Artifacts
Notably, the action does not delete sub-tasks belonging to reviewers who were removed from the pull request. The synchronization process exclusively ensures that the current set of reviewers is accurately reflected in Asana.
This design choice means that sub-tasks for removed reviewers persist in the Asana project, requiring manual cleanup if necessary. The action treats removal events purely as synchronization triggers rather than deletion commands.
Code Example
The following simplified Go code illustrates the removal handling logic implemented in handler.go:
func (h *Handler) updateReviewers(pr *github.PullRequestEvent, requester *Account, taskID string) error {
// 1️⃣ Detect removal event
hasRequestedReviewersFields := pr.GetAction() == prEventActionReviewRequestedRemoved
// 2️⃣ Get current reviewers (GitHub already omitted the removed one)
var ghReviewers []*github.User
if hasRequestedReviewersFields {
ghReviewers = pr.PullRequest.RequestedReviewers
}
// 3️⃣ Resolve to Asana accounts
reviewers := make([]*Account, len(ghReviewers))
for i, r := range ghReviewers {
reviewers[i], _ = h.fetchAccount(r.GetLogin())
}
// 4️⃣ Upsert each reviewer sub-task (create if missing, update otherwise)
for _, reviewer := range reviewers {
_ = h.upsertReviewer(pr, requester, reviewer, taskID)
}
return nil
}
Summary
- Event detection: The action identifies
review_request_removedevents using theprEventActionReviewRequestedRemovedconstant inhandler.go(lines 13‑19). - Stateless retrieval: Current reviewers are fetched directly from GitHub's pre-filtered
RequestedReviewersslice at lines 101‑108. - Account resolution: GitHub logins are mapped to Asana GIDs via
fetchAccount(lines 124‑135). - Idempotent sync:
upsertReviewercreates or updates sub-tasks viaAddCodeReviewSubtaskandUpdateCodeReviewSubtaskwithout deleting removed reviewer artifacts. - Source files: Core logic resides in
handler.go(lines 97‑146) with Asana API operations inasana.go.
Frequently Asked Questions
Does the action delete Asana sub-tasks when a reviewer is removed from a pull request?
No. The action does not implement deletion logic for sub-tasks when processing review_request_removed events. It only synchronizes the remaining reviewers' sub-tasks, leaving orphaned tasks in Asana for manual cleanup if desired.
How does the action know which reviewer was removed?
The action does not track which specific reviewer was removed. Instead, it relies on GitHub's RequestedReviewers slice in the webhook payload, which already excludes the removed user. The handler at lines 101‑108 of handler.go processes this filtered list as the authoritative current state.
What happens if a removed reviewer is re-added to the pull request?
If a reviewer is re-added, GitHub sends a review_request event, and the action treats this as a standard reviewer addition. The upsertReviewer function will recreate the sub-task via AddCodeReviewSubtask if it was previously removed manually, or update it via UpdateCodeReviewSubtask if it still exists.
Where is the event handling logic implemented?
The primary event handling logic is implemented in handler.go within the updateReviewers function (lines 97‑146). Constants for event types like prEventActionReviewRequestedRemoved are defined at lines 13‑19, while the actual Asana API operations reside in asana.go.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →