chore: lifecycle-stage template method and logger/resolution dedups#232
Open
dan2k3k4 wants to merge 10 commits into
Open
chore: lifecycle-stage template method and logger/resolution dedups#232dan2k3k4 wants to merge 10 commits into
dan2k3k4 wants to merge 10 commits into
Conversation
PollDeployProgressAppInstanceTrait is left unmigrated: it is a polling trait with no running/completed transition of its own — it never sets a *_RUNNING status, derives the instance status from a Lagoon deployment state mapping, and early-returns without a terminal status, which does not fit the validate -> running -> body -> completed template.
UpgradeAppInstanceTrait is left unmigrated: it sets UPGRADE_RUNNING without persisting it (no ->save()), while the template always saves the running status. Saving would fire the UPGRADE_RUNNING status-changed event and its listener dispatch, changing behavior.
Implements plan 010 from the advisory audit: - Both Polydock service providers hand-rolled the six logger methods that PolydockAppLoggerTrait already supplies — and their setLogger copies lacked the trait's cache-logger flush, silently dropping startup log lines buffered before a real logger attached. Both now use the trait (~100 lines removed); the trait's over-specific @return docblocks (hardcoding its two previous consumers) become @return $this. - LagoonProjectPurgeService::makeWithDefaults() duplicated the exact client resolution its lazy client() method performs — dropped the eager copy. - The authenticated API implemented the mutually-exclusive group_id/group_slug validation + lookup three times (getInstances, assignInstanceToGroup, resolveTargetGroup). One shared resolveExistingGroupFromRequest() helper now serves all three, with byte-identical validation messages; resolveTargetGroup keeps its group_name/personal-group creation paths.
Review feedback: before the template-method refactor the ': starting' info line fired unconditionally ahead of the adopted guard, so adopted detaches always produced it. The refactor deferred it into runLifecyclePhase, which only the non-adopted path reaches — restore the line inside the adopted guard in all three Remove traits so log correlation is unchanged.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
PR 6 of 6 — the closer of the advisory plan set: plans 009 + 010, the "less code" refactors. Net −221 lines of app code (+232 lines of new tests).
Plan 009 —
runLifecyclePhase()template method (17 of 19 traits)Every lifecycle stage repeated the same ~18-line skeleton (log context, four validation booleans, the 8-line validate call,
*_RUNNINGsave, try/catch →*_FAILED,*_COMPLETEDsave) with hand-typed status triples. Now one template method onGeneric\PolydockAppcarries the skeleton; each stage supplies its status quadruple, validation flags, and a body closure (which may short-circuit after setting its own terminal status — Deploy/Remove Lagoon-error paths preserved exactly).PollDeployProgressAppInstanceTrait(polling flow — no running/completed shape) andUpgradeAppInstanceTrait(setsUPGRADE_RUNNINGwithout saving; the template's save would newly fire a status event — behavior change, so left).RunLifecyclePhaseTestpins the template's three exit paths (complete / body short-circuit / exception → failed).Plan 010 — logger trait + small dedups
PolydockAppLoggerTraitsupplies — and theirsetLoggerlacked the trait's cache-flush, silently dropping buffered startup logs (latent bug, now fixed by reuse). Trait docblocks corrected to@return $this.LagoonProjectPurgeService::makeWithDefaults()eager-duplicated its own lazyclient()resolution — dropped.resolveExistingGroupFromRequest()helper; validation messages byte-identical (API tests pass unchanged).Testing
php artisan test— 454 passed (3 new)./vendor/bin/phpstan analyse— no errors; Pint cleanGreptile Summary
This PR closes two refactoring plans: a
runLifecyclePhase()template method onGeneric\PolydockAppthat absorbs the ~18-line boilerplate skeleton shared by 17 lifecycle stage traits, and a set of smaller deduplications covering the logger trait, group resolution, and the Lagoon purge service factory.runLifecyclePhase()with a status quadruple (expected/running/completed/failed) and a body closure; the skeleton (log start, validate, save RUNNING, try/catch → FAILED, save COMPLETED) lives in one place. Two justified exceptions remain: the poll-progress trait (no running/completed shape) andUpgradeAppInstanceTrait(intentionally skips saving UPGRADE_RUNNING to avoid a new status event).PolydockAppLoggerTraitinstead of six hand-rolled methods — fixing a latent bug where theirsetLoggeromitted the CacheLogger buffer flush, silently dropping startup logs.LagoonProjectPurgeService::makeWithDefaults()is simplified to rely on the already-present lazyclient()resolver, and the three copies of group-ID/slug XOR-validation in the API controller are consolidated into oneresolveExistingGroupFromRequest()helper.Confidence Score: 5/5
Safe to merge — all lifecycle stage migrations are behavior-preserving, the latent CacheLogger-flush bug is correctly fixed by trait adoption, and the purge-service factory simplification is backed by the already-present lazy resolver.
The template method is a straightforward extraction: status transitions, log strings, and validation flags match the originals, the two documented exceptions are recorded in commit messages, and 454 tests plus PHPStan confirm nothing regressed. No behavioral change introduces incorrect state or data loss.
No files require special attention. The Remove trait adopted-instance logging shift and the resolveTargetGroup XOR-validation addition were covered in prior review rounds.
Important Files Changed
runLifecyclePhase()template method; skeleton is correct — validates, saves RUNNING, calls body, catches \Exception, saves COMPLETED/FAILED. Named-parameter defaults preserve all per-trait flag combinations.resolveExistingGroupFromRequest(); XOR validation now present on all three callers including the previously-uncheckedresolveTargetGrouppath (behavioral shift noted in prior comments).use PolydockAppLoggerTrait;; fixes latent bug wheresetLoggerdidn't flush the CacheLogger buffer before switching to a real logger.makeWithDefaults()now defers client resolution to the existing lazyclient()method; constructor's second param is already?Client $client = nullso no arity mismatch.DEPLOY_RUNNINGas both$runningStatusand$completedStatus; the double-RUNNING save matches the original behavior and a comment documents the intentional design.runLifecyclePhase.@returnannotations corrected from explicit class union to$this; no functional changes to logger methods.Comments Outside Diff (1)
app/Http/Controllers/Api/AuthenticatedApiController.php, line 88-97 (link)resolveTargetGroupsilently gains XOR validation it didn't have beforeThe old
resolveTargetGroup(used by create/register flows) had no mutual-exclusion check — it just returned the first matching field. By delegating toresolveExistingGroupFromRequest, this method now throws aValidationExceptionif bothgroup_idandgroup_slugare present in the request. Any API client or test that previously relied on "group_id wins when both are sent" through this code path will start seeing a 422 instead. The change is logically correct, but it is an undocumented behavior shift for callers ofresolveTargetGroup.Reviews (2): Last reviewed commit: "chore: restore the starting log line for..." | Re-trigger Greptile