Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,14 @@ runs:
with:
name: codeboarding-base-${{ steps.state.outputs.cfg_hash }}-${{ steps.sync_commit.outputs.baseline_sha }}
path: ${{ runner.temp }}/cb-state/${{ github.action }}/out/base
retention-days: 30
# Longer than a review's 30 days on purpose, and the margin is the whole
# point: correctness comes from the renewal check, which republishes any
# base with less than a review's lifetime left, while this surplus
# decides how often that fires. Equal lifetimes renew on every run and
# publish a base per run rather than per merge base — more storage, not
# less. 60 leaves a 30-day reuse window, so a pull request open a month
# never triggers one.
retention-days: 60
if-no-files-found: ignore

- name: Publish baseline analysis for the analyzed commit
Expand All @@ -293,7 +300,14 @@ runs:
with:
name: codeboarding-base-${{ steps.state.outputs.cfg_hash }}-${{ steps.sync_commit.outputs.analyzed_sha }}
path: ${{ runner.temp }}/cb-state/${{ github.action }}/out/base
retention-days: 30
# Longer than a review's 30 days on purpose, and the margin is the whole
# point: correctness comes from the renewal check, which republishes any
# base with less than a review's lifetime left, while this surplus
# decides how often that fires. Equal lifetimes renew on every run and
# publish a base per run rather than per merge base — more storage, not
# less. 60 leaves a 30-day reuse window, so a pull request open a month
# never triggers one.
retention-days: 60
if-no-files-found: ignore

- name: Write sync summary
Expand Down Expand Up @@ -357,7 +371,14 @@ runs:
with:
name: ${{ steps.state.outputs.base_name }}
path: ${{ runner.temp }}/cb-state/${{ github.action }}/out/base
retention-days: 30
# Longer than a review's 30 days on purpose, and the margin is the whole
# point: correctness comes from the renewal check, which republishes any
# base with less than a review's lifetime left, while this surplus
# decides how often that fires. Equal lifetimes renew on every run and
# publish a base per run rather than per merge base — more storage, not
# less. 60 leaves a 30-day reuse window, so a pull request open a month
# never triggers one.
retention-days: 60
if-no-files-found: ignore

- name: Render review diagram
Expand Down
21 changes: 14 additions & 7 deletions tests/test_action_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -482,13 +482,20 @@ def test_the_base_is_inlined_whenever_no_artifact_holds_it(self) -> None:
self.assertIn("fetch_base.outputs.artifact_id == ''", inline[0])

def test_a_base_outlives_the_reviews_that_reference_it(self) -> None:
# A review artifact points at a base by id for 30 days, so a base kept
# for less leaves that review unusable for the rest of its life.
for step in self._uploads():
if "out/base" in step.get("path", ""):
self.assertEqual(
step.get("retention-days"), "30", f"{step['name']} may expire before the reviews naming it"
)
# A review points at a base by id for its whole life, so a base kept for
# the same period is only ever good at the instant it is written: the
# renewal check would then fire on every run and republish it every time,
# which is exactly the duplication that splitting it out removed.
review = next(s for s in self._uploads() if "review_artifact.outputs.artifact_dir" in s.get("path", ""))
review_days = int(review["retention-days"])
bases = [s for s in self._uploads() if "out/base" in s.get("path", "")]
self.assertTrue(bases, "no base publication step found")
for step in bases:
self.assertGreater(
int(step.get("retention-days", 0)),
review_days,
f"{step['name']} does not outlive the reviews that reference it",
)

def test_the_reusable_analysis_honours_the_configured_retention(self) -> None:
warmstart = [s for s in self._uploads() if "warmstart" in s.get("path", "")]
Expand Down
Loading