config-replace: guarded config:set across a pipeline stage - #2
Merged
Conversation
Sets <VAR> to <new-value> on every app in a stage, but only where the current value is exactly <old-value>. Apps without the var are skipped (counted on stderr, or recorded with -a/--all); apps whose value differs are left untouched but reported, so drift stays visible. --dry-run previews the writes. The chunked-parallel/streaming skeleton of pipeline-cmd moves into a shared run_pipeline_workers helper; both commands now differ only in their per-app worker. Two hazards are handled explicitly: a failed config:get is surfaced as an error record instead of having its error text compared against <old-value>, and a failed config:set is captured before strip_heroku_noise so pipefail can't turn it into a bogus "var not set" skip. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.
Adds a new subcommand for the "update every app that has VAR=old to VAR=new, ignore the rest" workflow:
Per app in the stage:
<old-value>→config:set <VAR>=<new-value>(its output is the record)-a/--allemits askipped: <VAR> not setrecord instead)skipped: <VAR> is "..." (expected "...")) so drift stays visibleconfig:getitself fails (no access, app gone) →error: ...record, never a write--dry-runreads every current value and reports what would change without setting anythingImplementation
The chunked-parallel / streaming / table-CSV / skip-summary skeleton of
pipeline-cmdis extracted into a sharedrun_pipeline_workershelper;pipeline-cmdandconfig-replacenow differ only in their per-app worker. No behavior change topipeline-cmd(all pre-existing tests pass unchanged).Two hazards handled explicitly, both pinned by regression tests:
config:getexit status is checked, so its error text is never compared against<old-value>(worst case, a matching message would have authorized a write to an app whose value was never read)config:setis captured beforestrip_heroku_noise, because underpipefailthe pipeline status would make the worker return non-zero and silently misreport the failed write as a "var not set" skipKnown limitation (documented in README and
usage()):config:getprints the same empty line for an unset var and one set to the empty string, so a var set to""is treated as not set.Testing
shellcheck bin/heroku-scripts install.shcleanbats test: 37/37 pass (27 pre-existing + 10 new config-replace tests)🤖 Generated with Claude Code