diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e9f18d9..05c8dbd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,13 +45,13 @@ jobs: run: rustup self update && rustup update stable - name: Start the local environment - run: docker-compose up -d + run: docker compose up -d - name: Run the local release process for channel ${{ matrix.channel }} run: ./run.sh release ${{ matrix.channel }} - name: Validate the generated signatures - run: docker-compose exec -T local /src/local/check-signature.sh ${{ matrix.channel }} + run: docker compose exec -T local /src/local/check-signature.sh ${{ matrix.channel }} - name: Remove the previously installed ${{ matrix.channel }} toolchain run: rustup toolchain remove ${{ matrix.channel }} @@ -78,7 +78,7 @@ jobs: run: rustup self update && rustup update stable - name: Start the local environment - run: docker-compose up -d + run: docker compose up -d - name: Run the local release process for channel ${{ matrix.channel }} run: ./run.sh rustup ${{ matrix.channel }} @@ -104,7 +104,7 @@ jobs: if: github.event_name == 'push' && github.repository == 'rust-lang/promote-release' && github.ref == 'refs/heads/master' - name: Upload the Docker image we built to GitHub Actions artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: docker-image path: promote-release.tar.zstd @@ -122,7 +122,7 @@ jobs: steps: - name: Download the Docker image previously built - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: docker-image diff --git a/docker-compose.yml b/docker-compose.yml index fd12ca5..5b99bbc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,4 @@ --- -version: '3' - services: minio: image: quay.io/minio/minio:RELEASE.2023-04-13T03-08-07Z diff --git a/run.sh b/run.sh index 2a4e0f3..8c102cb 100755 --- a/run.sh +++ b/run.sh @@ -28,7 +28,7 @@ fi channel="$2" override_commit="${3-}" -container_id="$(docker-compose ps -q local)" +container_id="$(docker compose ps -q local)" if [[ "${container_id}" == "" ]]; then container_status="missing" else @@ -38,7 +38,7 @@ if [[ "${container_status}" != "running" ]]; then echo "Error: the local environment is not running!" echo "You can start it by running in a new terminal the following command:" echo - echo " docker-compose up" + echo " docker compose up" echo exit 1 fi @@ -49,4 +49,4 @@ if [[ "$(uname)" == "Linux" ]]; then fi # Run the command inside the docker environment. -docker-compose exec -T local "/src/local/${command}.sh" "${channel}" "${override_commit}" +docker compose exec -T local /src/local/run.sh "${channel}" "${override_commit}" diff --git a/src/github.rs b/src/github.rs index e1ddc1e..a371f40 100644 --- a/src/github.rs +++ b/src/github.rs @@ -355,51 +355,48 @@ impl RepositoryClient<'_> { start: &str, path: &str, ) -> anyhow::Result { - self.start_new_request()?; - self.client.get(true)?; - self.client.url(&format!( - "https://api.github.com/repos/{repo}/commits/{start}", - repo = self.repo - ))?; - let resolved_start = self - .client - .without_body() - .send_with_response::()? - .sha; - for page in 1..20 { + const MAX_COMMITS: usize = 200; + const BORS_EMAIL: &str = "bors@rust-lang.org"; + + let mut commit = start.to_string(); + let mut scanned_commits = 0; + for _ in 0..MAX_COMMITS { + scanned_commits += 1; + self.start_new_request()?; self.client.get(true)?; self.client.url(&format!( - "https://api.github.com/repos/{repo}/commits?sha={resolved_start}&per_page=100&page={page}&author=bors", + "https://api.github.com/repos/{repo}/commits/{commit}", repo = self.repo ))?; - let commits = self + + let commit_data = self .client .without_body() - .send_with_response::>()?; - for commit in commits { - self.start_new_request()?; - self.client.get(true)?; - self.client.url(&format!( - "https://api.github.com/repos/{repo}/commits/{sha}", - repo = self.repo, - sha = commit.sha, - ))?; - let commit = self - .client - .without_body() - .send_with_response::()?; - if commit.files.iter().any(|f| f.filename == path) { - return Ok(commit); - } + .send_with_response::()?; + + // We pick the *first* parent commit to continue walking through the commit graph. In + // a merge commit, the first parent is always the merge base (i.e. the master branch), + // while the second parent is always the branch being merged in. + // + // This is important because we only want bors merge commits for branches merged into + // Rust's master branch, not bors merge commits in subtrees being pulled in. + let Some(parent) = &commit_data.parents.first() else { + break; + }; + commit.clone_from(&parent.sha); + + if commit_data.commit.author.email != BORS_EMAIL { + continue; + } + if commit_data.files.iter().any(|f| f.filename == path) { + return Ok(commit_data); } } anyhow::bail!( - "Failed to find bors commit touching {:?} in start={} ancestors (scanned {} commits)", - path, - start, - 20 * 100, + "Failed to find bors commit touching {path:?} in \ + start={start} ancestors (scanned {scanned_commits} commits)" ); } @@ -511,15 +508,21 @@ pub(crate) struct CreateTag<'a> { #[derive(serde::Deserialize)] pub(crate) struct FullCommitData { - #[allow(unused)] + #[cfg_attr(not(test), allow(unused))] pub(crate) sha: String, pub(crate) parents: Vec, + pub(crate) commit: CommitCommit, pub(crate) files: Vec, } #[derive(serde::Deserialize)] -pub(crate) struct CommitData { - pub(crate) sha: String, +pub(crate) struct CommitCommit { + pub(crate) author: CommitAuthor, +} + +#[derive(serde::Deserialize)] +pub(crate) struct CommitAuthor { + pub(crate) email: String, } #[derive(serde::Deserialize)] diff --git a/src/main.rs b/src/main.rs index ad12f93..ceb8fac 100644 --- a/src/main.rs +++ b/src/main.rs @@ -380,7 +380,7 @@ impl Context { .arg("cp") .arg("--recursive") .arg("--only-show-errors") - .arg(&self.s3_artifacts_url(&format!("{}/", rev))) + .arg(self.s3_artifacts_url(&format!("{}/", rev))) .arg(format!("{}/", dl.display())))?; let mut files = dl.read_dir()?;