Reconcile obsolete staging assets before verifying a new Nightly generation

オープン
#1,078 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
48/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
rust
領域
release

調査の方向性

Start with the staging upload, verification and cleanup flow in tools/src/publication.rs near line 777, then read the Remote and generation helpers in tools/tests/publication.rs. Run the focused audit_stale_staging_generation test with the provided Cargo command to reproduce the extra-asset failure. Done means mocked regressions cover interrupted, repeated, stale and conflicting attempts plus cleanup failures, while final verification still checks all 29 assets and preserves the previous public Nightly.

索引モデルが issue の本文から書いたものです。

説明

bug ci help wanted

Problem

A partial upload to the private nightly-staging draft can prevent a later Nightly generation from being published. The publisher uploads the new generation and verifies an exact remote asset set before it removes obsolete assets from the previous staging generation. Any leftover old filename therefore makes verification fail before cleanup can run.

Starting point: staging upload, verification and cleanup.

Reproduction

Audited canonical master e1f8effd195b6339c3979b1e091e63c25f1da983 on Linux amd64 with checkout-built Wave 0.0.1-alpha-dev, matching std, Rust 1.89.0, Cargo jobs=2 and LLVM 21.1.8. The master SHA was rechecked before registration. Publication was exercised through the existing stateful mock API, without creating or changing any real GitHub release.

Using the Remote and generation helpers in tools/tests/publication.rs, append this focused test to an isolated copy of that integration-test fixture:

#[test]
fn audit_stale_staging_generation() {
    let temporary = tempfile::tempdir().unwrap();
    let mut remote = Remote::new();

    let (directory, mut first) = generation(temporary.path(), 'a', 1);
    publication::promote(&mut remote, &directory, &mut first).unwrap();
    let previous_public = remote.releases[&1].clone();

    let (directory, mut partial) = generation(temporary.path(), 'b', 2);
    remote.fault = Some((
        "GET".into(),
        "releases/2/assets?per_page=100&page=1".into(),
        false,
    ));
    assert!(publication::promote(&mut remote, &directory, &mut partial).is_err());
    let asset = storage::files(&directory).unwrap().into_iter().next().unwrap();
    remote.upload(&asset, "nightly-staging").unwrap();

    let (directory, mut next) = generation(temporary.path(), 'c', 3);
    let result = publication::promote(&mut remote, &directory, &mut next);
    println!("result={result:?}");
    println!("staging assets={}", remote.assets[&2].len());
    println!("previous public retained={}", remote.releases[&1] == previous_public);
    println!("obsolete deletions={:?}", remote.calls.iter()
        .filter(|call| call.starts_with("DELETE releases/assets"))
        .collect::<Vec<_>>());
}

Run the focused test against the audited wave-tools crate. For a temporary local test added to that fixture, the equivalent Cargo command is:

cargo +1.89.0 test --locked --jobs 2 -p wave-tools --test publication audit_stale_staging_generation -- --nocapture

The audit ran the same fixture-based sequence from an isolated test harness linked against the current crate. It first creates a valid published generation, leaves one real staged asset from a partial later generation, and then promotes a newer generation.

Observed:

result=Err("remote Nightly asset set differs from the verified generation")
staging assets=30
previous public retained=true
obsolete deletions=[]

The simulated partial upload is intentional: one old-generation artifact remains alongside the 29 artifacts of the new generation. The final exact-set verifier rejects the extra artifact, so the subsequent deletion loop is unreachable. Repeating the new promotion does not remove the obsolete asset.

Scope

Reconcile obsolete assets owned by the staging draft before final exact-set verification, or use an equivalent retry-safe generation transition. Preserve digest/size/source/run/attempt identity checks and fail on conflicting current-generation assets. Never delete assets from the active public generation to repair staging.

Related: #831 owns the broader Nightly publication contract and final-cutover recovery. This issue isolates the independently reproducible stale-draft asset ordering defect.

Completion criteria

  • A partial older staging generation does not permanently block a valid newer generation or workflow attempt.
  • Final verification still requires exactly the expected 29 assets for all nine package targets with correct digests, sizes and identity.
  • Interrupted upload, repeated identical attempts, stale attempts, conflicting current filenames and cleanup failures have deterministic mocked regressions.
  • Failures preserve the previously usable public Nightly and all canonical CI/installer approval gates.
主要言語
Rust
スター
56
フォーク
21
平均マージ
22時間 57分
マージ済み PR(30日)
46

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

wavefnd/Wave のほかの issue

wavefnd/Wave の issue をすべて見る

似ている issue

Rust の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。