fix: wipe run artifacts before rerun

This commit is contained in:
Andreas Ahlenstorf 2026-05-11 19:56:25 +02:00
parent ba1c3e0288
commit 25f2dbab6d
4 changed files with 74 additions and 0 deletions

View file

@ -0,0 +1,11 @@
- id: 59220
run_id: 455620
repo_id: 62 # test_workflows
owner_id: 2 # user2
status: 2 # ArtifactStatusUploadConfirmed
- id: 59230
run_id: 455630
repo_id: 62 # test_workflows
owner_id: 2 # user2
status: 2 # ArtifactStatusUploadConfirmed

View file

@ -0,0 +1,11 @@
- id: 59240
run_id: 455640
repo_id: 62 # test_workflows
owner_id: 2 # user2
status: 2 # ArtifactStatusUploadConfirmed
- id: 59250
run_id: 455650
repo_id: 62 # test_workflows
owner_id: 2 # user2
status: 2 # ArtifactStatusUploadConfirmed

View file

@ -74,6 +74,12 @@ func RerunAllJobs(ctx context.Context, run *actions_model.ActionRun) ([]*actions
return fmt.Errorf("cannot prepare next attempt because run %d is active: %s", run.ID, run.Status.String())
}
// Wipe all artifacts before a rerun to prevent stale artifacts from polluting artifacts collected during the
// rerun.
if err := actions_model.SetArtifactsOfRunDeleted(ctx, run.ID); err != nil {
return fmt.Errorf("cannot remove artifacts of previous run of run %d: %w", run.ID, err)
}
run.PreviousDuration = run.Duration()
run.Status = actions_model.StatusWaiting
@ -138,6 +144,14 @@ func RerunJob(ctx context.Context, job *actions_model.ActionRunJob) ([]*actions_
return fmt.Errorf("could not load jobs of run %d: %w", job.RunID, err)
}
// Wipe all artifacts before a rerun to prevent stale artifacts from polluting the artifacts collected during
// the rerun. Because artifacts are bound to a run and not to a job, it is not possible to only remove the
// artifacts of the jobs that are going to be rerun. That means that artifacts created by jobs that are not
// rerun will be lost. That matches GitHub Actions' behaviour as of May 2026.
if err := actions_model.SetArtifactsOfRunDeleted(ctx, job.RunID); err != nil {
return fmt.Errorf("cannot remove artifacts of previous run of run %d: %w", job.RunID, err)
}
for _, jobToRerun := range GetAllRerunJobs(job, jobs) {
canBeRerun, err := jobToRerun.CanBeRerun(ctx)
if err != nil {

View file

@ -59,6 +59,11 @@ func TestRerun_RerunAllJobs(t *testing.T) {
run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ID: 455620})
unittest.AssertCount(t, &actions_model.ActionArtifact{RunID: run.ID}, 1)
unittest.AssertCount(t, &actions_model.ActionArtifact{
RunID: run.ID, Status: int64(actions_model.ArtifactStatusPendingDeletion),
}, 0)
rerunJobs, err := RerunAllJobs(t.Context(), run)
require.NoError(t, err)
@ -81,6 +86,10 @@ func TestRerun_RerunAllJobs(t *testing.T) {
assert.Equal(t, actions_model.StatusWaiting, rerunJobs[1].Status)
assert.Equal(t, timeutil.TimeStamp(0), rerunJobs[1].Started)
assert.Equal(t, timeutil.TimeStamp(0), rerunJobs[1].Stopped)
unittest.AssertCount(t, &actions_model.ActionArtifact{
RunID: run.ID, Status: int64(actions_model.ArtifactStatusPendingDeletion),
}, 1)
})
t.Run("Error if workflow running", func(t *testing.T) {
@ -89,6 +98,11 @@ func TestRerun_RerunAllJobs(t *testing.T) {
run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ID: 455630})
unittest.AssertCount(t, &actions_model.ActionArtifact{RunID: run.ID}, 1)
unittest.AssertCount(t, &actions_model.ActionArtifact{
RunID: run.ID, Status: int64(actions_model.ArtifactStatusPendingDeletion),
}, 0)
rerunJobs, err := RerunAllJobs(t.Context(), run)
require.ErrorContains(t, err, "workflow is still running")
@ -100,6 +114,11 @@ func TestRerun_RerunAllJobs(t *testing.T) {
assert.Equal(t, time.Duration(0), run.PreviousDuration)
assert.Empty(t, rerunJobs)
unittest.AssertCount(t, &actions_model.ActionArtifact{RunID: run.ID}, 1)
unittest.AssertCount(t, &actions_model.ActionArtifact{
RunID: run.ID, Status: int64(actions_model.ArtifactStatusPendingDeletion),
}, 0)
})
t.Run("Error if workflow invalid", func(t *testing.T) {
@ -153,6 +172,11 @@ func TestRerun_RerunJob(t *testing.T) {
job := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunJob{ID: 683910})
unittest.AssertCount(t, &actions_model.ActionArtifact{RunID: job.RunID}, 1)
unittest.AssertCount(t, &actions_model.ActionArtifact{
RunID: job.RunID, Status: int64(actions_model.ArtifactStatusPendingDeletion),
}, 0)
rerunJobs, err := RerunJob(t.Context(), job)
require.NoError(t, err)
@ -166,6 +190,10 @@ func TestRerun_RerunJob(t *testing.T) {
assert.Equal(t, actions_model.StatusWaiting, job.Status)
assert.Equal(t, timeutil.TimeStamp(0), job.Started)
assert.Equal(t, timeutil.TimeStamp(0), job.Stopped)
unittest.AssertCount(t, &actions_model.ActionArtifact{
RunID: job.RunID, Status: int64(actions_model.ArtifactStatusPendingDeletion),
}, 1)
})
t.Run("Rerun job needed by others", func(t *testing.T) {
@ -225,6 +253,11 @@ func TestRerun_RerunJob(t *testing.T) {
job := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunJob{ID: 683900})
unittest.AssertCount(t, &actions_model.ActionArtifact{RunID: job.RunID}, 1)
unittest.AssertCount(t, &actions_model.ActionArtifact{
RunID: job.RunID, Status: int64(actions_model.ArtifactStatusPendingDeletion),
}, 0)
rerunJobs, err := RerunJob(t.Context(), job)
require.ErrorContains(t, err, "workflow is invalid")
@ -236,6 +269,11 @@ func TestRerun_RerunJob(t *testing.T) {
assert.Equal(t, actions_model.StatusFailure, job.Status)
assert.Equal(t, timeutil.TimeStamp(0), job.Started)
assert.Equal(t, timeutil.TimeStamp(0), job.Stopped)
unittest.AssertCount(t, &actions_model.ActionArtifact{RunID: job.RunID}, 1)
unittest.AssertCount(t, &actions_model.ActionArtifact{
RunID: job.RunID, Status: int64(actions_model.ArtifactStatusPendingDeletion),
}, 0)
})
t.Run("Error if workflow disabled", func(t *testing.T) {