diff --git a/.gitignore b/.gitignore index 37c8717f..9dbca849 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target **/*.rs.bk .env +/db/ diff --git a/Cargo.lock b/Cargo.lock index ef0fa9e9..883566ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,17 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + [[package]] name = "aho-corasick" version = "0.7.18" @@ -467,6 +478,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + [[package]] name = "fastrand" version = "1.7.0" @@ -704,7 +721,7 @@ dependencies = [ "indexmap", "slab", "tokio", - "tokio-util 0.7.1", + "tokio-util", "tracing", ] @@ -714,6 +731,24 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashlink" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69fe1fcf8b4278d860ad0548329f892a3631fb63f82574df68275f34cdbe0ffa" +dependencies = [ + "hashbrown 0.12.3", +] + [[package]] name = "hermit-abi" version = "0.1.19" @@ -867,7 +902,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.11.2", "serde", ] @@ -928,6 +963,17 @@ version = "0.2.123" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb691a747a7ab48abc15c5b42066eaafde10dc427e3b6ee2a1cf43db04c763bd" +[[package]] +name = "libsqlite3-sys" +version = "0.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29f835d03d717946d28b1d1ed632eb6f0e24a299388ee623d0c23118d3e8a7fa" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "lock_api" version = "0.4.7" @@ -1171,27 +1217,25 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.11.2" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ - "instant", "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" -version = "0.8.5" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" dependencies = [ "cfg-if", - "instant", "libc", "redox_syscall", "smallvec", - "winapi", + "windows-sys", ] [[package]] @@ -1254,18 +1298,18 @@ dependencies = [ [[package]] name = "phf" -version = "0.10.1" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" +checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" dependencies = [ "phf_shared", ] [[package]] name = "phf_shared" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" dependencies = [ "siphasher", ] @@ -1363,7 +1407,8 @@ dependencies = [ "postgres-protocol", "serde", "serde_json", - "uuid", + "uuid 0.8.2", + "uuid 1.3.0", ] [[package]] @@ -1529,6 +1574,23 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746" +[[package]] +name = "rusqlite" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01e213bc3ecb39ac32e81e51ebe31fd888a940515173e3a18a35f8c6e896422a" +dependencies = [ + "bitflags", + "chrono", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "serde_json", + "smallvec", + "uuid 1.3.0", +] + [[package]] name = "rust_team_data" version = "1.0.0" @@ -1917,15 +1979,16 @@ dependencies = [ [[package]] name = "tokio-postgres" -version = "0.7.5" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b6c8b33df661b548dcd8f9bf87debb8c56c05657ed291122e1188698c2ece95" +checksum = "29a12c1b3e0704ae7dfc25562629798b29c72e6b1d0a681b6f29ab4ae5e7f7bf" dependencies = [ "async-trait", "byteorder", "bytes", "fallible-iterator", - "futures", + "futures-channel", + "futures-util", "log", "parking_lot", "percent-encoding", @@ -1935,21 +1998,7 @@ dependencies = [ "postgres-types", "socket2", "tokio", - "tokio-util 0.6.9", -] - -[[package]] -name = "tokio-util" -version = "0.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "log", - "pin-project-lite", - "tokio", + "tokio-util", ] [[package]] @@ -1986,7 +2035,7 @@ dependencies = [ "pin-project", "pin-project-lite", "tokio", - "tokio-util 0.7.1", + "tokio-util", "tower-layer", "tower-service", "tracing", @@ -2073,6 +2122,7 @@ version = "0.1.0" dependencies = [ "anyhow", "async-trait", + "bytes", "chrono", "comrak", "cron", @@ -2097,6 +2147,7 @@ dependencies = [ "regex", "reqwest", "route-recognizer", + "rusqlite", "rust_team_data", "serde", "serde_json", @@ -2109,7 +2160,7 @@ dependencies = [ "tracing", "tracing-subscriber", "url", - "uuid", + "uuid 1.3.0", ] [[package]] @@ -2271,6 +2322,12 @@ name = "uuid" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" + +[[package]] +name = "uuid" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79" dependencies = [ "getrandom", "serde", @@ -2446,6 +2503,72 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" + [[package]] name = "winreg" version = "0.10.1" diff --git a/Cargo.toml b/Cargo.toml index 26780fa6..15decd9a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ hyper = { version = "0.14.4", features = ["server", "stream"]} tokio = { version = "1.7.1", features = ["macros", "time", "rt"] } futures = { version = "0.3", default-features = false, features = ["std"] } async-trait = "0.1.31" -uuid = { version = "0.8", features = ["v4", "serde"] } +uuid = { version = "1.3", features = ["v4", "serde"] } tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } url = "2.1.0" @@ -42,8 +42,10 @@ tower = { version = "0.4.13", features = ["util", "limit", "buffer", "load-shed" github-graphql = { path = "github-graphql" } rand = "0.8.5" ignore = "0.4.18" -postgres-types = { version = "0.2.4", features = ["derive"] } +postgres-types = { version = "0.2.4", features = ["derive", "with-uuid-1"] } cron = { version = "0.12.0" } +bytes = "1.1.0" +rusqlite = { version = "0.28.0", features = ["bundled", "chrono", "serde_json", "uuid"] } [dependencies.serde] version = "1" diff --git a/Dockerfile b/Dockerfile index dbd7084b..f9495286 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,12 +18,19 @@ RUN apt-get update -y && \ pkg-config \ git \ cmake \ - zlib1g-dev + zlib1g-dev \ + postgresql + +# postgres does not allow running as root +RUN groupadd -r builder && useradd -m -r -g builder builder +USER builder RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- \ --default-toolchain stable --profile minimal -y -COPY . . +COPY --chown=builder . /triagebot +WORKDIR /triagebot + RUN bash -c 'source $HOME/.cargo/env && cargo test --release --all' RUN bash -c 'source $HOME/.cargo/env && cargo build --release' @@ -38,7 +45,7 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \ RUN mkdir -p /opt/triagebot -COPY --from=build /target/release/triagebot /usr/local/bin/ +COPY --from=build /triagebot/target/release/triagebot /usr/local/bin/ COPY templates /opt/triagebot/templates WORKDIR /opt/triagebot ENV PORT=80 diff --git a/README.md b/README.md index 69983c48..8d12aefb 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ The Triagebot webserver also includes several other endpoints intended for users Triagebot uses a Postgres database to retain some state. In production, it uses [RDS](https://aws.amazon.com/rds/). +For local testing you can use SQLite (see below). The server at https://triage.rust-lang.org/ runs on ECS and is configured via [Terraform](https://github.com/rust-lang/simpleinfra/blob/master/terraform/shared/services/triagebot/main.tf#L8). Updates are automatically deployed when merged to master. @@ -34,38 +35,117 @@ Some developers may settle with testing in production as the risks tend to be lo The general overview of what you will need to do: +1. Create a repo on GitHub to run tests on. +2. [Configure a database](#configure-a-database) +3. [Configure webhook forwarding](#configure-webhook-forwarding) +4. Configure the `.env` file: + + 1. Copy `.env.sample` to `.env` + 2. `GITHUB_API_TOKEN`: This is a token needed for Triagebot to send requests to GitHub. Go to GitHub Settings > Developer Settings > Personal Access Token, and create a new token. The `repo` permission should be sufficient. + If this is not set, Triagebot will also look in `~/.gitconfig` in the `github.oauth-token` setting. + 3. `DATABASE_URL`: This is the URL to the database. See [Configuring a database](#configuring-a-database). + 4. `GITHUB_WEBHOOK_SECRET`: Enter the secret you entered in the webhook above. + 5. `RUST_LOG`: Set this to `debug`. + +5. Run `cargo run --bin triagebot`. This starts the http server listening for webhooks on port 8000. +6. Add a `triagebot.toml` file to the main branch of your GitHub repo with whichever services you want to try out. +7. Try interacting with your repo, such as issuing `@rustbot` commands or interacting with PRs and issues (depending on which services you enabled in `triagebot.toml`). Watch the logs from the server to see what's going on. + +### Configure a database + +For testing, it is probably easiest to use SQLite. +If you want something closer to production, then you might want to set up Postgres. + +#### SQLite + +To use SQLite, all you need to do is in the `.env` file set `DATABASE_URL` to a file: + +```bash +DATABASE_URL=db/triagebot.sqlite +``` + +If you have the [`sqlite3` CLI program](https://sqlite.org/cli.html) installed, you can use that to interactively run queries against the database with `sqlite3 db/triagebot.sqlite`. + +#### Postgres + +To use Postgres, you will need to install it and configure it: + 1. Install Postgres. Look online for any help with installing and setting up Postgres (particularly if you need to create a user and set up permissions). 2. Create a database: `createdb triagebot` -3. Provide a way for GitHub to access the Triagebot webserver. - There are various ways to do this (such as placing it behind a proxy, or poking holes in your firewall). - Or, you can use a service such as https://ngrok.com/ to access on your local dev machine via localhost. - Installation is fairly simple, though requires setting up a (free) account. - Run the command `ngrok http 8000` to forward to port 8000 on localhost. -4. Create a GitHub repo to run some tests on. -5. Configure the webhook in your GitHub repo. - I recommend at least skimming the [GitHub webhook documentation](https://docs.github.com/en/developers/webhooks-and-events/webhooks/about-webhooks) if you are not familiar with webhooks. In short: - - 1. Go to the settings page. +3. In the `.env` file, set the `DATABASE_URL`: + + ```sh + DATABASE_URL=postgres://eric@localhost/triagebot + ``` + + replacing `eric` with the username on your local system. + +### Configure webhook forwarding + +I recommend at least skimming the [GitHub webhook documentation](https://docs.github.com/en/developers/webhooks-and-events/webhooks/about-webhooks) if you are not familiar with webhooks. +In order for GitHub's webhooks to reach your triagebot server, you'll need to figure out some way to route them to your machine. +There are various options on how to do this. +You can poke holes into your firewall or use a proxy, but you shouldn't expose your machine to the the internet. +There are various services which help with this problem. +These generally involve running a program on your machine that connects to an external server which relays the hooks into your machine. +There are several to choose from: + +* [gh webhook](#gh-webhook) — This is a GitHub-native service, but it is currently in beta (getting access is easy, though). This is the easiest to use. +* [ngrok](#ngrok) — This is pretty easy to use, but requires setting up a free account. +* — This is another service recommended by GitHub. +* — This is another service recommended by GitHub. + +#### gh webhook + +The [`gh` CLI](https://github.com/cli/cli) is the official CLI tool which I highly recommend getting familiar with. +There is an official extension which provides webhook forwarding and also takes care of all the configuration. +See [cli/gh-webhook](https://docs.github.com/en/developers/webhooks-and-events/webhooks/receiving-webhooks-with-the-github-cli) for more information on installing it. + +This is super easy to use, and doesn't require manually configuring webhook settings. +The command to run looks something like: + +```sh +gh webhook forward --repo=ehuss/triagebot-test --events=* \ + --url=http://127.0.0.1:8000/github-hook --secret somelongsekrit +``` + +Where the value in `--secret` is the secret value you place in `GITHUB_WEBHOOK_SECRET` in the `.env` file, and `--repo` is the repo you want to test against. + +#### ngrok + +The following is an example of using to provide webhook forwarding. +You need to sign up for a free account, and also deal with configuring the GitHub webhook settings. + +1. Install ngrok. +2. Run `ngrok http 8000`. This will forward webhook events to localhost on port 8000. +3. Configure GitHub webhooks in the test repo you created. + In short: + + 1. Go to the settings page for your GitHub repo. 2. Go to the webhook section. 3. Click "Add webhook" 4. Include the settings: - - Payload URL: This is the URL to your Triagebot server, for example http://7e9ea9dc.ngrok.io/github-hook. This URL is displayed when you ran the `ngrok` command above. - - Content type: application/json - - Secret: Enter a shared secret (some longish random text) - - Events: "Send me everything" -6. Configure the `.env` file: + * Payload URL: This is the URL to your Triagebot server, for example http://7e9ea9dc.ngrok.io/github-hook. This URL is displayed when you ran the `ngrok` command above. + * Content type: application/json + * Secret: Enter a shared secret (some longish random text) + * Events: "Send me everything" - 1. Copy `.env.sample` to `.env` - 2. `GITHUB_API_TOKEN`: This is a token needed for Triagebot to send requests to GitHub. Go to GitHub Settings > Developer Settings > Personal Access Token, and create a new token. The `repo` permission should be sufficient. - If this is not set, Triagebot will also look in `~/.gitconfig` in the `github.oauth-token` setting. - 3. `DATABASE_URL`: This is the URL to the Postgres database. Something like `postgres://eric@localhost/triagebot` should work, replacing `eric` with your username. - 4. `GITHUB_WEBHOOK_SECRET`: Enter the secret you entered in the webhook above. - 5. `RUST_LOG`: Set this to `debug`. +## Tests + +When possible, writing unittests is very helpful and one of the easiest ways to test. +For more advanced testing, there is an integration test called `testsuite` which provides an end-to-end service for testing triagebot. +There are several parts to it: + +* [`github_client`](tests/github_client/mod.rs) — Tests specifically targeting `GithubClient`. + This sets up an HTTP server that mimics api.github.com and verifies the client's behavior. +* [`server_test`](tests/server_test/mod.rs) — This tests the `triagebot` server itself and its behavior when it receives a webhook. + This launches the `triagebot` server, sets up HTTP servers to intercept api.github.com requests, launches PostgreSQL in a sandbox, and then injects webhook events into the `triagebot` server and validates its response. +* [`db`](tests/db/mod.rs) — These are tests for the database API. -7. Run `cargo run --bin triagebot`. This starts the http server listening on port 8000. -8. Add a `triagebot.toml` file to the main branch of your GitHub repo with whichever services you want to try out. -9. Try interacting with your repo, such as issuing `@rustbot` commands or interacting with PRs and issues (depending on which services you enabled in `triagebot.toml`). Watch the logs from the server to see what's going on. +The real GitHub API responses are recorded in JSON files that the tests can later replay to verify the behavior of triagebot. +These recordings are enabled with the `TRIAGEBOT_TEST_RECORD` environment variable. +See the documentation in `github_client` and `server_test` for the steps for setting up recording to write a test. ## License diff --git a/src/actions.rs b/src/actions.rs index 6e7af814..f0824dd2 100644 --- a/src/actions.rs +++ b/src/actions.rs @@ -3,7 +3,6 @@ use std::collections::HashMap; use std::sync::Arc; use async_trait::async_trait; -use reqwest::Client; use serde::{Deserialize, Serialize}; use tera::{Context, Tera}; @@ -87,7 +86,7 @@ pub fn to_human(d: DateTime) -> String { #[async_trait] impl<'a> Action for Step<'a> { async fn call(&self) -> anyhow::Result { - let gh = GithubClient::new_with_default_token(Client::new()); + let gh = GithubClient::new_from_env(); // retrieve all Rust compiler meetings // from today for 7 days diff --git a/src/config.rs b/src/config.rs index 053aa682..3bfcc64e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -300,10 +300,13 @@ impl fmt::Display for ConfigurationError { Add a `triagebot.toml` in the root of the default branch to enable it." ), ConfigurationError::Toml(e) => { - write!(f, "Malformed `triagebot.toml` in default branch.\n{}", e) + write!(f, "Malformed `triagebot.toml` in default branch.\n{e}") } - ConfigurationError::Http(_) => { - write!(f, "Failed to query configuration for this repository.") + ConfigurationError::Http(e) => { + write!( + f, + "Failed to query configuration for this repository.\n{e:?}" + ) } } } diff --git a/src/db.rs b/src/db.rs index a696be99..f6a9afd7 100644 --- a/src/db.rs +++ b/src/db.rs @@ -1,276 +1,204 @@ -use crate::handlers::jobs::handle_job; -use crate::{db::jobs::*, handlers::Context}; -use anyhow::Context as _; -use chrono::Utc; -use native_tls::{Certificate, TlsConnector}; -use postgres_native_tls::MakeTlsConnector; +use self::jobs::Job; +use self::notifications::{Identifier, Notification, NotificationData}; +use anyhow::Result; +use chrono::{DateTime, FixedOffset, Utc}; +use serde::Serialize; use std::sync::{Arc, Mutex}; use tokio::sync::{OwnedSemaphorePermit, Semaphore}; -use tokio_postgres::Client as DbClient; +use uuid::Uuid; pub mod issue_data; pub mod jobs; pub mod notifications; -pub mod rustc_commits; +pub mod postgres; +pub mod sqlite; + +/// A bors merge commit. +#[derive(Debug, Serialize)] +pub struct Commit { + pub sha: String, + pub parent_sha: String, + pub time: DateTime, + pub pr: Option, +} + +#[async_trait::async_trait] +pub trait Connection: Send + Sync { + async fn transaction(&mut self) -> Box; + + // Pings + async fn record_username(&mut self, user_id: i64, username: String) -> Result<()>; + async fn record_ping(&mut self, notification: &Notification) -> Result<()>; + + // Rustc commits + async fn get_missing_commits(&mut self) -> Result>; + async fn record_commit(&mut self, commit: &Commit) -> Result<()>; + async fn has_commit(&mut self, sha: &str) -> Result; + async fn get_commits_with_artifacts(&mut self) -> Result>; + + // Notifications + async fn get_notifications(&mut self, username: &str) -> Result>; + async fn delete_ping( + &mut self, + user_id: i64, + identifier: Identifier<'_>, + ) -> Result>; + async fn add_metadata( + &mut self, + user_id: i64, + idx: usize, + metadata: Option<&str>, + ) -> Result<()>; + async fn move_indices(&mut self, user_id: i64, from: usize, to: usize) -> Result<()>; + + // Jobs + async fn insert_job( + &mut self, + name: &str, + scheduled_at: &DateTime, + metadata: &serde_json::Value, + ) -> Result<()>; + async fn delete_job(&mut self, id: &Uuid) -> Result<()>; + async fn update_job_error_message(&mut self, id: &Uuid, message: &str) -> Result<()>; + async fn update_job_executed_at(&mut self, id: &Uuid) -> Result<()>; + async fn get_job_by_name_and_scheduled_at( + &mut self, + name: &str, + scheduled_at: &DateTime, + ) -> Result; + async fn get_jobs_to_execute(&mut self) -> Result>; + + // Issue data + async fn lock_and_load_issue_data( + &mut self, + repo: &str, + issue_number: i32, + key: &str, + ) -> Result<(Box, Option)>; + async fn save_issue_data( + &mut self, + repo: &str, + issue_number: i32, + key: &str, + data: &serde_json::Value, + ) -> Result<()>; +} -const CERT_URL: &str = "https://s3.amazonaws.com/rds-downloads/rds-ca-2019-root.pem"; +#[async_trait::async_trait] +pub trait Transaction: Send + Sync { + fn conn(&mut self) -> &mut dyn Connection; + fn conn_ref(&self) -> &dyn Connection; + + async fn commit(self: Box) -> Result<(), anyhow::Error>; + async fn finish(self: Box) -> Result<(), anyhow::Error>; +} -lazy_static::lazy_static! { - static ref CERTIFICATE_PEM: Vec = { - let client = reqwest::blocking::Client::new(); - let resp = client - .get(CERT_URL) - .send() - .expect("failed to get RDS cert"); - resp.bytes().expect("failed to get RDS cert body").to_vec() - }; +#[async_trait::async_trait] +pub trait ConnectionManager { + type Connection; + async fn open(&self) -> Self::Connection; + async fn is_valid(&self, c: &mut Self::Connection) -> bool; } -pub struct ClientPool { - connections: Arc>>, +pub struct ConnectionPool { + connections: Arc>>, permits: Arc, + manager: M, } -pub struct PooledClient { - client: Option, - #[allow(unused)] // only used for drop impl +pub struct ManagedConnection { + conn: Option, + connections: Arc>>, + #[allow(unused)] permit: OwnedSemaphorePermit, - pool: Arc>>, } -impl Drop for PooledClient { - fn drop(&mut self) { - let mut clients = self.pool.lock().unwrap_or_else(|e| e.into_inner()); - clients.push(self.client.take().unwrap()); +impl std::ops::Deref for ManagedConnection { + type Target = T; + fn deref(&self) -> &Self::Target { + self.conn.as_ref().unwrap() } } - -impl std::ops::Deref for PooledClient { - type Target = tokio_postgres::Client; - - fn deref(&self) -> &Self::Target { - self.client.as_ref().unwrap() +impl std::ops::DerefMut for ManagedConnection { + fn deref_mut(&mut self) -> &mut Self::Target { + self.conn.as_mut().unwrap() } } -impl std::ops::DerefMut for PooledClient { - fn deref_mut(&mut self) -> &mut Self::Target { - self.client.as_mut().unwrap() +impl Drop for ManagedConnection { + fn drop(&mut self) { + let conn = self.conn.take().unwrap(); + self.connections + .lock() + .unwrap_or_else(|e| e.into_inner()) + .push(conn); } } -impl ClientPool { - pub fn new() -> ClientPool { - ClientPool { +impl ConnectionPool +where + T: Send, + M: ConnectionManager, +{ + fn new(manager: M) -> Self { + ConnectionPool { connections: Arc::new(Mutex::new(Vec::with_capacity(16))), permits: Arc::new(Semaphore::new(16)), + manager, } } - pub async fn get(&self) -> PooledClient { + pub fn raw(&mut self) -> &mut M { + &mut self.manager + } + + async fn get(&self) -> ManagedConnection { let permit = self.permits.clone().acquire_owned().await.unwrap(); - { + let conn = { let mut slots = self.connections.lock().unwrap_or_else(|e| e.into_inner()); - // Pop connections until we hit a non-closed connection (or there are no - // "possibly open" connections left). - while let Some(c) = slots.pop() { - if !c.is_closed() { - return PooledClient { - client: Some(c), - permit, - pool: self.connections.clone(), - }; - } + slots.pop() + }; + if let Some(mut c) = conn { + if self.manager.is_valid(&mut c).await { + return ManagedConnection { + conn: Some(c), + permit, + connections: self.connections.clone(), + }; } } - PooledClient { - client: Some(make_client().await.unwrap()), + let conn = self.manager.open().await; + ManagedConnection { + conn: Some(conn), + connections: self.connections.clone(), permit, - pool: self.connections.clone(), } } } -async fn make_client() -> anyhow::Result { - let db_url = std::env::var("DATABASE_URL").expect("needs DATABASE_URL"); - if db_url.contains("rds.amazonaws.com") { - let cert = &CERTIFICATE_PEM[..]; - let cert = Certificate::from_pem(&cert).context("made certificate")?; - let connector = TlsConnector::builder() - .add_root_certificate(cert) - .build() - .context("built TlsConnector")?; - let connector = MakeTlsConnector::new(connector); - - let (db_client, connection) = match tokio_postgres::connect(&db_url, connector).await { - Ok(v) => v, - Err(e) => { - anyhow::bail!("failed to connect to DB: {}", e); - } - }; - tokio::task::spawn(async move { - if let Err(e) = connection.await { - eprintln!("database connection error: {}", e); - } - }); - - Ok(db_client) - } else { - eprintln!("Warning: Non-TLS connection to non-RDS DB"); - let (db_client, connection) = - match tokio_postgres::connect(&db_url, tokio_postgres::NoTls).await { - Ok(v) => v, - Err(e) => { - anyhow::bail!("failed to connect to DB: {}", e); - } - }; - tokio::spawn(async move { - if let Err(e) = connection.await { - eprintln!("database connection error: {}", e); - } - }); - - Ok(db_client) - } +pub enum Pool { + Sqlite(ConnectionPool), + Postgres(ConnectionPool), } -pub async fn run_migrations(client: &DbClient) -> anyhow::Result<()> { - client - .execute( - "CREATE TABLE IF NOT EXISTS database_versions ( - zero INTEGER PRIMARY KEY, - migration_counter INTEGER - );", - &[], - ) - .await - .context("creating database versioning table")?; - - client - .execute( - "INSERT INTO database_versions (zero, migration_counter) - VALUES (0, 0) - ON CONFLICT DO NOTHING", - &[], - ) - .await - .context("inserting initial database_versions")?; - - let migration_idx: i32 = client - .query_one("SELECT migration_counter FROM database_versions", &[]) - .await - .context("getting migration counter")? - .get(0); - let migration_idx = migration_idx as usize; - - for (idx, migration) in MIGRATIONS.iter().enumerate() { - if idx >= migration_idx { - client - .execute(*migration, &[]) - .await - .with_context(|| format!("executing {}th migration", idx))?; - client - .execute( - "UPDATE database_versions SET migration_counter = $1", - &[&(idx as i32 + 1)], - ) - .await - .with_context(|| format!("updating migration counter to {}", idx))?; +impl Pool { + pub async fn connection(&self) -> Box { + match self { + Pool::Sqlite(p) => Box::new(sqlite::SqliteConnection::new(p.get().await)), + Pool::Postgres(p) => Box::new(p.get().await), } } - Ok(()) -} - -pub async fn schedule_jobs(db: &DbClient, jobs: Vec) -> anyhow::Result<()> { - for job in jobs { - let mut upcoming = job.schedule.upcoming(Utc).take(1); - - if let Some(scheduled_at) = upcoming.next() { - if let Err(_) = get_job_by_name_and_scheduled_at(&db, &job.name, &scheduled_at).await { - // mean there's no job already in the db with that name and scheduled_at - insert_job(&db, &job.name, &scheduled_at, &job.metadata).await?; - } + pub fn open(uri: &str) -> Pool { + if uri.starts_with("postgres") { + Pool::Postgres(ConnectionPool::new(postgres::Postgres::new(uri.into()))) + } else { + Pool::Sqlite(ConnectionPool::new(sqlite::Sqlite::new(uri.into()))) } } - Ok(()) -} - -pub async fn run_scheduled_jobs(ctx: &Context, db: &DbClient) -> anyhow::Result<()> { - let jobs = get_jobs_to_execute(&db).await.unwrap(); - tracing::trace!("jobs to execute: {:#?}", jobs); - - for job in jobs.iter() { - update_job_executed_at(&db, &job.id).await?; - - match handle_job(&ctx, &job.name, &job.metadata).await { - Ok(_) => { - tracing::trace!("job successfully executed (id={})", job.id); - delete_job(&db, &job.id).await?; - } - Err(e) => { - tracing::error!("job failed on execution (id={:?}, error={:?})", job.id, e); - update_job_error_message(&db, &job.id, &e.to_string()).await?; - } - } + pub fn new_from_env() -> Pool { + Self::open(&std::env::var("DATABASE_URL").expect("needs DATABASE_URL")) } - - Ok(()) } - -static MIGRATIONS: &[&str] = &[ - " -CREATE TABLE notifications ( - notification_id BIGSERIAL PRIMARY KEY, - user_id BIGINT, - origin_url TEXT NOT NULL, - origin_html TEXT, - time TIMESTAMP WITH TIME ZONE -); -", - " -CREATE TABLE users ( - user_id BIGINT PRIMARY KEY, - username TEXT NOT NULL -); -", - "ALTER TABLE notifications ADD COLUMN short_description TEXT;", - "ALTER TABLE notifications ADD COLUMN team_name TEXT;", - "ALTER TABLE notifications ADD COLUMN idx INTEGER;", - "ALTER TABLE notifications ADD COLUMN metadata TEXT;", - " -CREATE TABLE rustc_commits ( - sha TEXT PRIMARY KEY, - parent_sha TEXT NOT NULL, - time TIMESTAMP WITH TIME ZONE -); -", - "ALTER TABLE rustc_commits ADD COLUMN pr INTEGER;", - " -CREATE TABLE issue_data ( - repo TEXT, - issue_number INTEGER, - key TEXT, - data JSONB, - PRIMARY KEY (repo, issue_number, key) -); -", - " -CREATE TABLE jobs ( - id UUID DEFAULT gen_random_uuid() PRIMARY KEY, - name TEXT NOT NULL, - scheduled_at TIMESTAMP WITH TIME ZONE NOT NULL, - metadata JSONB, - executed_at TIMESTAMP WITH TIME ZONE, - error_message TEXT -); -", - " -CREATE UNIQUE INDEX jobs_name_scheduled_at_unique_index - ON jobs ( - name, scheduled_at - ); -", -]; diff --git a/src/db/issue_data.rs b/src/db/issue_data.rs index 4f2d43a0..bad50181 100644 --- a/src/db/issue_data.rs +++ b/src/db/issue_data.rs @@ -8,17 +8,15 @@ //! Note that this uses crude locking, so try to keep the duration between //! loading and saving to a minimum. -use crate::github::Issue; -use anyhow::{Context, Result}; +use crate::db; +use anyhow::Result; use serde::{Deserialize, Serialize}; -use tokio_postgres::types::Json; -use tokio_postgres::{Client as DbClient, Transaction}; pub struct IssueData<'db, T> where T: for<'a> Deserialize<'a> + Serialize + Default + std::fmt::Debug + Sync, { - transaction: Transaction<'db>, + transaction: Box, repo: String, issue_number: i32, key: String, @@ -30,27 +28,18 @@ where T: for<'a> Deserialize<'a> + Serialize + Default + std::fmt::Debug + Sync, { pub async fn load( - db: &'db mut DbClient, - issue: &Issue, + connection: &'db mut dyn db::Connection, + repo: String, + issue_number: i32, key: &str, ) -> Result> { - let repo = issue.repository().to_string(); - let issue_number = issue.number as i32; - let transaction = db.transaction().await?; - transaction - .execute("LOCK TABLE issue_data", &[]) - .await - .context("locking issue data")?; - let data = transaction - .query_opt( - "SELECT data FROM issue_data WHERE \ - repo = $1 AND issue_number = $2 AND key = $3", - &[&repo, &issue_number, &key], - ) - .await - .context("selecting issue data")? - .map(|row| row.get::>(0).0) - .unwrap_or_default(); + let (transaction, raw) = connection + .lock_and_load_issue_data(&repo, issue_number, key) + .await?; + let data = match raw { + Some(raw) => T::deserialize(raw)?, + None => T::default(), + }; Ok(IssueData { transaction, repo, @@ -60,20 +49,13 @@ where }) } - pub async fn save(self) -> Result<()> { + pub async fn save(mut self) -> Result<()> { + let raw_data = serde_json::to_value(self.data)?; self.transaction - .execute( - "INSERT INTO issue_data (repo, issue_number, key, data) \ - VALUES ($1, $2, $3, $4) \ - ON CONFLICT (repo, issue_number, key) DO UPDATE SET data=EXCLUDED.data", - &[&self.repo, &self.issue_number, &self.key, &Json(&self.data)], - ) - .await - .context("inserting issue data")?; - self.transaction - .commit() - .await - .context("committing issue data")?; + .conn() + .save_issue_data(&self.repo, self.issue_number, &self.key, &raw_data) + .await?; + self.transaction.commit().await?; Ok(()) } } diff --git a/src/db/jobs.rs b/src/db/jobs.rs index 5db66b0f..51621d3e 100644 --- a/src/db/jobs.rs +++ b/src/db/jobs.rs @@ -1,9 +1,13 @@ //! The `jobs` table provides a way to have scheduled jobs -use anyhow::{Context as _, Result}; -use chrono::{DateTime, Utc}; + +use crate::db::Connection; +use crate::handlers::jobs::handle_job; +use crate::handlers::Context; +use anyhow::Result; +use chrono::DateTime; +use chrono::Utc; use cron::Schedule; use serde::{Deserialize, Serialize}; -use tokio_postgres::Client as DbClient; use uuid::Uuid; pub struct JobSchedule { @@ -22,116 +26,46 @@ pub struct Job { pub error_message: Option, } -pub async fn insert_job( - db: &DbClient, - name: &String, - scheduled_at: &DateTime, - metadata: &serde_json::Value, -) -> Result<()> { - tracing::trace!("insert_job(name={})", name); - - db.execute( - "INSERT INTO jobs (name, scheduled_at, metadata) VALUES ($1, $2, $3) - ON CONFLICT (name, scheduled_at) DO UPDATE SET metadata = EXCLUDED.metadata", - &[&name, &scheduled_at, &metadata], - ) - .await - .context("Inserting job")?; - - Ok(()) -} - -pub async fn delete_job(db: &DbClient, id: &Uuid) -> Result<()> { - tracing::trace!("delete_job(id={})", id); - - db.execute("DELETE FROM jobs WHERE id = $1", &[&id]) - .await - .context("Deleting job")?; - - Ok(()) -} - -pub async fn update_job_error_message(db: &DbClient, id: &Uuid, message: &String) -> Result<()> { - tracing::trace!("update_job_error_message(id={})", id); - - db.execute( - "UPDATE jobs SET error_message = $2 WHERE id = $1", - &[&id, &message], - ) - .await - .context("Updating job error message")?; - - Ok(()) -} - -pub async fn update_job_executed_at(db: &DbClient, id: &Uuid) -> Result<()> { - tracing::trace!("update_job_executed_at(id={})", id); - - db.execute("UPDATE jobs SET executed_at = now() WHERE id = $1", &[&id]) - .await - .context("Updating job executed at")?; - - Ok(()) -} - -pub async fn get_job_by_name_and_scheduled_at( - db: &DbClient, - name: &String, - scheduled_at: &DateTime, -) -> Result { - tracing::trace!( - "get_job_by_name_and_scheduled_at(name={}, scheduled_at={})", - name, - scheduled_at - ); - - let job = db - .query_one( - "SELECT * FROM jobs WHERE name = $1 AND scheduled_at = $2", - &[&name, &scheduled_at], - ) - .await - .context("Select job by name and scheduled at")?; - - deserialize_job(&job) -} - -// Selects all jobs with: -// - scheduled_at in the past -// - error_message is null or executed_at is at least 60 minutes ago (intended to make repeat executions rare enough) -pub async fn get_jobs_to_execute(db: &DbClient) -> Result> { - let jobs = db - .query( - " - SELECT * FROM jobs WHERE scheduled_at <= now() AND (error_message IS NULL OR executed_at <= now() - INTERVAL '60 minutes')", - &[], - ) - .await - .context("Getting jobs data")?; - - let mut data = Vec::with_capacity(jobs.len()); +pub async fn schedule_jobs(connection: &mut dyn Connection, jobs: Vec) -> Result<()> { for job in jobs { - let serialized_job = deserialize_job(&job); - data.push(serialized_job.unwrap()); + let mut upcoming = job.schedule.upcoming(Utc).take(1); + + if let Some(scheduled_at) = upcoming.next() { + if let Err(_) = connection + .get_job_by_name_and_scheduled_at(&job.name, &scheduled_at) + .await + { + // mean there's no job already in the db with that name and scheduled_at + connection + .insert_job(&job.name, &scheduled_at, &job.metadata) + .await?; + } + } } - Ok(data) + Ok(()) } -fn deserialize_job(row: &tokio_postgres::row::Row) -> Result { - let id: Uuid = row.try_get(0)?; - let name: String = row.try_get(1)?; - let scheduled_at: DateTime = row.try_get(2)?; - let metadata: serde_json::Value = row.try_get(3)?; - let executed_at: Option> = row.try_get(4)?; - let error_message: Option = row.try_get(5)?; +pub async fn run_scheduled_jobs(ctx: &Context, connection: &mut dyn Connection) -> Result<()> { + let jobs = connection.get_jobs_to_execute().await.unwrap(); + tracing::trace!("jobs to execute: {:#?}", jobs); + + for job in jobs.iter() { + connection.update_job_executed_at(&job.id).await?; + + match handle_job(&ctx, &job.name, &job.metadata).await { + Ok(_) => { + tracing::trace!("job successfully executed (id={})", job.id); + connection.delete_job(&job.id).await?; + } + Err(e) => { + tracing::error!("job failed on execution (id={:?}, error={:?})", job.id, e); + connection + .update_job_error_message(&job.id, &e.to_string()) + .await?; + } + } + } - Ok(Job { - id, - name, - scheduled_at, - metadata, - executed_at, - error_message, - }) + Ok(()) } diff --git a/src/db/notifications.rs b/src/db/notifications.rs index 5b185793..a675f089 100644 --- a/src/db/notifications.rs +++ b/src/db/notifications.rs @@ -1,8 +1,10 @@ -use anyhow::Context as _; +//! Database support for the notifications feature for tracking `@` mentions. +//! +//! See + use chrono::{DateTime, FixedOffset}; -use tokio_postgres::Client as DbClient; -use tracing as log; +/// Tracking `@` mentions for users in issues/PRs. pub struct Notification { pub user_id: i64, pub origin_url: String, @@ -15,160 +17,7 @@ pub struct Notification { pub team_name: Option, } -pub async fn record_username(db: &DbClient, user_id: i64, username: String) -> anyhow::Result<()> { - db.execute( - "INSERT INTO users (user_id, username) VALUES ($1, $2) ON CONFLICT DO NOTHING", - &[&user_id, &username], - ) - .await - .context("inserting user id / username")?; - Ok(()) -} - -pub async fn record_ping(db: &DbClient, notification: &Notification) -> anyhow::Result<()> { - db.execute("INSERT INTO notifications (user_id, origin_url, origin_html, time, short_description, team_name, idx) - VALUES ( - $1, $2, $3, $4, $5, $6, - (SELECT max(notifications.idx) + 1 from notifications where notifications.user_id = $1) - )", - &[¬ification.user_id, ¬ification.origin_url, ¬ification.origin_html, ¬ification.time, ¬ification.short_description, ¬ification.team_name], - ).await.context("inserting notification")?; - - Ok(()) -} - -#[derive(Copy, Clone)] -pub enum Identifier<'a> { - Url(&'a str), - Index(std::num::NonZeroUsize), - /// Glob identifier (`all` or `*`). - All, -} - -pub async fn delete_ping( - db: &mut DbClient, - user_id: i64, - identifier: Identifier<'_>, -) -> anyhow::Result> { - match identifier { - Identifier::Url(origin_url) => { - let rows = db - .query( - "DELETE FROM notifications WHERE user_id = $1 and origin_url = $2 - RETURNING origin_html, time, short_description, metadata", - &[&user_id, &origin_url], - ) - .await - .context("delete notification query")?; - Ok(rows - .into_iter() - .map(|row| { - let origin_text: String = row.get(0); - let time: DateTime = row.get(1); - let short_description: Option = row.get(2); - let metadata: Option = row.get(3); - NotificationData { - origin_url: origin_url.to_owned(), - origin_text, - time, - short_description, - metadata, - } - }) - .collect()) - } - Identifier::Index(idx) => loop { - let t = db - .build_transaction() - .isolation_level(tokio_postgres::IsolationLevel::Serializable) - .start() - .await - .context("begin transaction")?; - - let notifications = t - .query( - "select notification_id, idx, user_id - from notifications - where user_id = $1 - order by idx asc nulls last;", - &[&user_id], - ) - .await - .context("failed to get ordering")?; - - let notification_id: i64 = notifications - .get(idx.get() - 1) - .ok_or_else(|| anyhow::anyhow!("No such notification with index {}", idx.get()))? - .get(0); - - let row = t - .query_one( - "DELETE FROM notifications WHERE notification_id = $1 - RETURNING origin_url, origin_html, time, short_description, metadata", - &[¬ification_id], - ) - .await - .context(format!( - "Failed to delete notification with id {}", - notification_id - ))?; - - let origin_url: String = row.get(0); - let origin_text: String = row.get(1); - let time: DateTime = row.get(2); - let short_description: Option = row.get(3); - let metadata: Option = row.get(4); - let deleted_notification = NotificationData { - origin_url, - origin_text, - time, - short_description, - metadata, - }; - - if let Err(e) = t.commit().await { - if e.code().map_or(false, |c| { - *c == tokio_postgres::error::SqlState::T_R_SERIALIZATION_FAILURE - }) { - log::trace!("serialization failure, restarting deletion"); - continue; - } else { - return Err(e).context("transaction commit failure"); - } - } else { - return Ok(vec![deleted_notification]); - } - }, - Identifier::All => { - let rows = db - .query( - "DELETE FROM notifications WHERE user_id = $1 - RETURNING origin_url, origin_html, time, short_description, metadata", - &[&user_id], - ) - .await - .context("delete all notifications query")?; - Ok(rows - .into_iter() - .map(|row| { - let origin_url: String = row.get(0); - let origin_text: String = row.get(1); - let time: DateTime = row.get(2); - let short_description: Option = row.get(3); - let metadata: Option = row.get(4); - NotificationData { - origin_url, - origin_text, - time, - short_description, - metadata, - } - }) - .collect()) - } - } -} - +/// Metadata associated with an `@` notification that the user can set via Zulip. #[derive(Debug)] pub struct NotificationData { pub origin_url: String, @@ -178,179 +27,11 @@ pub struct NotificationData { pub metadata: Option, } -pub async fn move_indices( - db: &mut DbClient, - user_id: i64, - from: usize, - to: usize, -) -> anyhow::Result<()> { - loop { - let t = db - .build_transaction() - .isolation_level(tokio_postgres::IsolationLevel::Serializable) - .start() - .await - .context("begin transaction")?; - - let notifications = t - .query( - "select notification_id, idx, user_id - from notifications - where user_id = $1 - order by idx asc nulls last;", - &[&user_id], - ) - .await - .context("failed to get initial ordering")?; - - let mut notifications = notifications - .into_iter() - .map(|n| n.get(0)) - .collect::>(); - - if notifications.get(from).is_none() { - anyhow::bail!( - "`from` index not present, must be less than {}", - notifications.len() - ); - } - - if notifications.get(to).is_none() { - anyhow::bail!( - "`to` index not present, must be less than {}", - notifications.len() - ); - } - - if from < to { - notifications[from..=to].rotate_left(1); - } else if to < from { - notifications[to..=from].rotate_right(1); - } - - for (idx, id) in notifications.into_iter().enumerate() { - t.execute( - "update notifications SET idx = $2 - where notification_id = $1", - &[&id, &(idx as i32)], - ) - .await - .context("update notification id")?; - } - - if let Err(e) = t.commit().await { - if e.code().map_or(false, |c| { - *c == tokio_postgres::error::SqlState::T_R_SERIALIZATION_FAILURE - }) { - log::trace!("serialization failure, restarting index movement"); - continue; - } else { - return Err(e).context("transaction commit failure"); - } - } else { - break; - } - } - - Ok(()) -} - -pub async fn add_metadata( - db: &mut DbClient, - user_id: i64, - idx: usize, - metadata: Option<&str>, -) -> anyhow::Result<()> { - loop { - let t = db - .build_transaction() - .isolation_level(tokio_postgres::IsolationLevel::Serializable) - .start() - .await - .context("begin transaction")?; - - let notifications = t - .query( - "select notification_id, idx, user_id - from notifications - where user_id = $1 - order by idx asc nulls last;", - &[&user_id], - ) - .await - .context("failed to get initial ordering")?; - - let notifications = notifications - .into_iter() - .map(|n| n.get(0)) - .collect::>(); - - match notifications.get(idx) { - None => anyhow::bail!( - "index not present, must be less than {}", - notifications.len() - ), - Some(id) => { - t.execute( - "update notifications SET metadata = $2 - where notification_id = $1", - &[&id, &metadata], - ) - .await - .context("update notification id")?; - } - } - - if let Err(e) = t.commit().await { - if e.code().map_or(false, |c| { - *c == tokio_postgres::error::SqlState::T_R_SERIALIZATION_FAILURE - }) { - log::trace!("serialization failure, restarting index movement"); - continue; - } else { - return Err(e).context("transaction commit failure"); - } - } else { - break; - } - } - - Ok(()) -} - -pub async fn get_notifications( - db: &DbClient, - username: &str, -) -> anyhow::Result> { - let notifications = db - .query( - " - select username, origin_url, origin_html, time, short_description, idx, metadata - from notifications - join users on notifications.user_id = users.user_id - where username = $1 - order by notifications.idx asc nulls last;", - &[&username], - ) - .await - .context("Getting notification data")?; - - let mut data = Vec::new(); - for notification in notifications { - let origin_url: String = notification.get(1); - let origin_text: String = notification.get(2); - let time: DateTime = notification.get(3); - let short_description: Option = notification.get(4); - let metadata: Option = notification.get(6); - - data.push(NotificationData { - origin_url, - origin_text, - short_description, - time, - metadata, - }); - } - - Ok(data) +/// Selector for deleting `@` notifications. +#[derive(Copy, Clone)] +pub enum Identifier<'a> { + Url(&'a str), + Index(std::num::NonZeroUsize), + /// Glob identifier (`all` or `*`). + All, } diff --git a/src/db/postgres.rs b/src/db/postgres.rs new file mode 100644 index 00000000..b9b96d8c --- /dev/null +++ b/src/db/postgres.rs @@ -0,0 +1,841 @@ +use super::{Commit, Identifier, Job, Notification, NotificationData}; +use crate::db::{Connection, ConnectionManager, ManagedConnection, Transaction}; +use anyhow::Context as _; +use anyhow::Result; +use chrono::Utc; +use chrono::{DateTime, FixedOffset}; +use native_tls::{Certificate, TlsConnector}; +use postgres_native_tls::MakeTlsConnector; +use tokio_postgres::types::Json; +use tokio_postgres::{GenericClient, TransactionBuilder}; +use tracing::trace; +use uuid::Uuid; + +pub struct Postgres(String, std::sync::Once); + +impl Postgres { + pub fn new(url: String) -> Self { + Postgres(url, std::sync::Once::new()) + } +} + +const CERT_URL: &str = "https://s3.amazonaws.com/rds-downloads/rds-ca-2019-root.pem"; + +lazy_static::lazy_static! { + static ref CERTIFICATE_PEM: Vec = { + let client = reqwest::blocking::Client::new(); + let resp = client + .get(CERT_URL) + .send() + .expect("failed to get RDS cert"); + resp.bytes().expect("failed to get RDS cert body").to_vec() + }; +} + +async fn make_client(db_url: &str) -> Result { + if db_url.contains("rds.amazonaws.com") { + let cert = &CERTIFICATE_PEM[..]; + let cert = Certificate::from_pem(&cert).context("made certificate")?; + let connector = TlsConnector::builder() + .add_root_certificate(cert) + .build() + .context("built TlsConnector")?; + let connector = MakeTlsConnector::new(connector); + + let (db_client, connection) = match tokio_postgres::connect(&db_url, connector).await { + Ok(v) => v, + Err(e) => { + anyhow::bail!("failed to connect to DB: {}", e); + } + }; + tokio::spawn(async move { + if let Err(e) = connection.await { + eprintln!("database connection error: {}", e); + } + }); + + Ok(db_client) + } else { + eprintln!("Warning: Non-TLS connection to non-RDS DB"); + let (db_client, connection) = + match tokio_postgres::connect(&db_url, tokio_postgres::NoTls).await { + Ok(v) => v, + Err(e) => { + anyhow::bail!("failed to connect to DB: {}", e); + } + }; + tokio::spawn(async move { + if let Err(e) = connection.await { + eprintln!("database connection error: {}", e); + } + }); + + Ok(db_client) + } +} + +static MIGRATIONS: &[&str] = &[ + " +CREATE TABLE notifications ( + notification_id BIGSERIAL PRIMARY KEY, + user_id BIGINT, + origin_url TEXT NOT NULL, + origin_html TEXT, + time TIMESTAMP WITH TIME ZONE +); +", + " +CREATE TABLE users ( + user_id BIGINT PRIMARY KEY, + username TEXT NOT NULL +); +", + "ALTER TABLE notifications ADD COLUMN short_description TEXT;", + "ALTER TABLE notifications ADD COLUMN team_name TEXT;", + "ALTER TABLE notifications ADD COLUMN idx INTEGER;", + "ALTER TABLE notifications ADD COLUMN metadata TEXT;", + " +CREATE TABLE rustc_commits ( + sha TEXT PRIMARY KEY, + parent_sha TEXT NOT NULL, + time TIMESTAMP WITH TIME ZONE +); +", + "ALTER TABLE rustc_commits ADD COLUMN pr INTEGER;", + " +CREATE TABLE issue_data ( + repo TEXT, + issue_number INTEGER, + key TEXT, + data JSONB, + PRIMARY KEY (repo, issue_number, key) +); +", + " +CREATE TABLE jobs ( + id UUID DEFAULT gen_random_uuid() PRIMARY KEY, + name TEXT NOT NULL, + scheduled_at TIMESTAMP WITH TIME ZONE NOT NULL, + metadata JSONB, + executed_at TIMESTAMP WITH TIME ZONE, + error_message TEXT +); +", + " +CREATE UNIQUE INDEX jobs_name_scheduled_at_unique_index + ON jobs ( + name, scheduled_at + ); +", +]; + +#[async_trait::async_trait] +impl ConnectionManager for Postgres { + type Connection = PostgresConnection; + async fn open(&self) -> Self::Connection { + let client = make_client(&self.0).await.unwrap(); + let mut should_init = false; + self.1.call_once(|| { + should_init = true; + }); + if should_init { + run_migrations(&client).await.unwrap(); + } + PostgresConnection::new(client).await + } + async fn is_valid(&self, conn: &mut Self::Connection) -> bool { + !conn.conn.is_closed() + } +} + +pub async fn run_migrations(client: &tokio_postgres::Client) -> Result<()> { + client + .execute( + "CREATE TABLE IF NOT EXISTS database_versions ( + zero INTEGER PRIMARY KEY, + migration_counter INTEGER + );", + &[], + ) + .await + .context("creating database versioning table")?; + + client + .execute( + "INSERT INTO database_versions (zero, migration_counter) + VALUES (0, 0) + ON CONFLICT DO NOTHING", + &[], + ) + .await + .context("inserting initial database_versions")?; + + let migration_idx: i32 = client + .query_one("SELECT migration_counter FROM database_versions", &[]) + .await + .context("getting migration counter")? + .get(0); + let migration_idx = migration_idx as usize; + + for (idx, migration) in MIGRATIONS.iter().enumerate() { + if idx >= migration_idx { + client + .execute(*migration, &[]) + .await + .with_context(|| format!("executing {}th migration", idx))?; + client + .execute( + "UPDATE database_versions SET migration_counter = $1", + &[&(idx as i32 + 1)], + ) + .await + .with_context(|| format!("updating migration counter to {}", idx))?; + } + } + + Ok(()) +} + +#[async_trait::async_trait] +impl<'a> Transaction for PostgresTransaction<'a> { + async fn commit(self: Box) -> Result<(), anyhow::Error> { + Ok(self.conn.commit().await?) + } + async fn finish(self: Box) -> Result<(), anyhow::Error> { + Ok(self.conn.rollback().await?) + } + fn conn(&mut self) -> &mut dyn Connection { + self + } + fn conn_ref(&self) -> &dyn Connection { + self + } +} + +pub struct PostgresTransaction<'a> { + conn: tokio_postgres::Transaction<'a>, +} + +pub struct PostgresConnection { + conn: tokio_postgres::Client, +} + +impl Into for PostgresConnection { + fn into(self) -> tokio_postgres::Client { + self.conn + } +} + +pub trait PClient { + type Client: Send + Sync + tokio_postgres::GenericClient; + fn conn(&self) -> &Self::Client; + fn conn_mut(&mut self) -> &mut Self::Client; + fn build_transaction(&mut self) -> TransactionBuilder; +} + +impl<'a> PClient for PostgresTransaction<'a> { + type Client = tokio_postgres::Transaction<'a>; + fn conn(&self) -> &Self::Client { + &self.conn + } + fn conn_mut(&mut self) -> &mut Self::Client { + &mut self.conn + } + fn build_transaction(&mut self) -> TransactionBuilder { + panic!("nested transactions not supported"); + } +} + +impl PClient for ManagedConnection { + type Client = tokio_postgres::Client; + fn conn(&self) -> &Self::Client { + &(&**self).conn + } + fn conn_mut(&mut self) -> &mut Self::Client { + &mut (&mut **self).conn + } + fn build_transaction(&mut self) -> TransactionBuilder { + self.conn_mut().build_transaction() + } +} + +impl PostgresConnection { + pub async fn new(conn: tokio_postgres::Client) -> Self { + PostgresConnection { conn } + } +} + +#[async_trait::async_trait] +impl Connection for P +where + P: Send + Sync + PClient, +{ + async fn transaction(&mut self) -> Box { + let tx = self.conn_mut().transaction().await.unwrap(); + Box::new(PostgresTransaction { conn: tx }) + } + + async fn record_username(&mut self, user_id: i64, username: String) -> Result<()> { + self.conn() + .execute( + "INSERT INTO users (user_id, username) VALUES ($1, $2) ON CONFLICT DO NOTHING", + &[&user_id, &username], + ) + .await + .context("inserting user id / username")?; + Ok(()) + } + + async fn record_ping(&mut self, notification: &Notification) -> Result<()> { + self.conn() + .execute( + "INSERT INTO notifications + (user_id, origin_url, origin_html, time, short_description, team_name, idx) + VALUES ( + $1, $2, $3, $4, $5, $6, + (SELECT max(notifications.idx) + 1 from notifications + where notifications.user_id = $1) + )", + &[ + ¬ification.user_id, + ¬ification.origin_url, + ¬ification.origin_html, + ¬ification.time, + ¬ification.short_description, + ¬ification.team_name, + ], + ) + .await + .context("inserting notification")?; + + Ok(()) + } + + async fn get_missing_commits(&mut self) -> Result> { + let missing = self + .conn() + .query( + " + SELECT parent_sha + FROM rustc_commits + WHERE parent_sha NOT IN ( + SELECT sha + FROM rustc_commits + )", + &[], + ) + .await + .context("fetching missing commits")?; + Ok(missing.into_iter().map(|row| row.get(0)).collect()) + } + + async fn record_commit(&mut self, commit: &Commit) -> Result<()> { + trace!("record_commit(sha={})", commit.sha); + let pr = commit.pr.expect("commit has pr"); + self.conn() + .execute( + "INSERT INTO rustc_commits (sha, parent_sha, time, pr) + VALUES ($1, $2, $3, $4) ON CONFLICT DO NOTHING", + &[&commit.sha, &commit.parent_sha, &commit.time, &(pr as i32)], + ) + .await + .context("inserting commit")?; + Ok(()) + } + + async fn has_commit(&mut self, sha: &str) -> Result { + self.conn() + .query("SELECT 1 FROM rustc_commits WHERE sha = $1", &[&sha]) + .await + .context("selecting from rustc_commits") + .map(|commits| !commits.is_empty()) + } + + async fn get_commits_with_artifacts(&mut self) -> Result> { + let commits = self + .conn() + .query( + " + select sha, parent_sha, time, pr + from rustc_commits + where time >= current_date - interval '168 days' + order by time desc;", + &[], + ) + .await + .context("Getting commit data")?; + + let mut data = Vec::with_capacity(commits.len()); + for commit in commits { + let sha: String = commit.get(0); + let parent_sha: String = commit.get(1); + let time: DateTime = commit.get(2); + let pr: Option = commit.get(3); + + data.push(Commit { + sha, + parent_sha, + time, + pr: pr.map(|n| n as u32), + }); + } + + Ok(data) + } + + async fn get_notifications(&mut self, username: &str) -> Result> { + let notifications = self + .conn() + .query( + "SELECT username, origin_url, origin_html, time, short_description, idx, metadata + FROM notifications + JOIN users ON notifications.user_id = users.user_id + WHERE username = $1 + ORDER BY notifications.idx ASC NULLS LAST;", + &[&username], + ) + .await + .context("Getting notification data")?; + + let mut data = Vec::new(); + for notification in notifications { + let origin_url: String = notification.get(1); + let origin_text: String = notification.get(2); + let time: DateTime = notification.get(3); + let short_description: Option = notification.get(4); + let metadata: Option = notification.get(6); + + data.push(NotificationData { + origin_url, + origin_text, + short_description, + time, + metadata, + }); + } + + Ok(data) + } + + async fn delete_ping( + &mut self, + user_id: i64, + identifier: Identifier<'_>, + ) -> Result> { + match identifier { + Identifier::Url(origin_url) => { + let rows = self + .conn() + .query( + "DELETE FROM notifications WHERE user_id = $1 and origin_url = $2 + RETURNING origin_html, time, short_description, metadata", + &[&user_id, &origin_url], + ) + .await + .context("delete notification query")?; + Ok(rows + .into_iter() + .map(|row| { + let origin_text: String = row.get(0); + let time: DateTime = row.get(1); + let short_description: Option = row.get(2); + let metadata: Option = row.get(3); + NotificationData { + origin_url: origin_url.to_owned(), + origin_text, + time, + short_description, + metadata, + } + }) + .collect()) + } + Identifier::Index(idx) => loop { + let t = self + .build_transaction() + .isolation_level(tokio_postgres::IsolationLevel::Serializable) + .start() + .await + .context("begin transaction")?; + + let notifications = t + .query( + "SELECT notification_id, idx, user_id + FROM notifications + WHERE user_id = $1 + ORDER BY idx ASC NULLS LAST;", + &[&user_id], + ) + .await + .context("failed to get ordering")?; + + let notification_id: i64 = notifications + .get(idx.get() - 1) + .ok_or_else(|| { + anyhow::anyhow!("No such notification with index {}", idx.get()) + })? + .get(0); + + let row = t + .query_one( + "DELETE FROM notifications WHERE notification_id = $1 + RETURNING origin_url, origin_html, time, short_description, metadata", + &[¬ification_id], + ) + .await + .context(format!( + "Failed to delete notification with id {}", + notification_id + ))?; + + let origin_url: String = row.get(0); + let origin_text: String = row.get(1); + let time: DateTime = row.get(2); + let short_description: Option = row.get(3); + let metadata: Option = row.get(4); + let deleted_notification = NotificationData { + origin_url, + origin_text, + time, + short_description, + metadata, + }; + + if let Err(e) = t.commit().await { + if e.code().map_or(false, |c| { + *c == tokio_postgres::error::SqlState::T_R_SERIALIZATION_FAILURE + }) { + trace!("serialization failure, restarting deletion"); + continue; + } else { + return Err(e).context("transaction commit failure"); + } + } else { + return Ok(vec![deleted_notification]); + } + }, + Identifier::All => { + let rows = self + .conn() + .query( + "DELETE FROM notifications WHERE user_id = $1 + RETURNING origin_url, origin_html, time, short_description, metadata", + &[&user_id], + ) + .await + .context("delete all notifications query")?; + Ok(rows + .into_iter() + .map(|row| { + let origin_url: String = row.get(0); + let origin_text: String = row.get(1); + let time: DateTime = row.get(2); + let short_description: Option = row.get(3); + let metadata: Option = row.get(4); + NotificationData { + origin_url, + origin_text, + time, + short_description, + metadata, + } + }) + .collect()) + } + } + } + + async fn add_metadata( + &mut self, + user_id: i64, + idx: usize, + metadata: Option<&str>, + ) -> Result<()> { + loop { + let t = self + .build_transaction() + .isolation_level(tokio_postgres::IsolationLevel::Serializable) + .start() + .await + .context("begin transaction")?; + + let notifications = t + .query( + "SELECT notification_id, idx, user_id + FROM notifications + WHERE user_id = $1 + ORDER BY idx ASC NULLS LAST;", + &[&user_id], + ) + .await + .context("failed to get initial ordering")?; + + let notifications = notifications + .into_iter() + .map(|n| n.get(0)) + .collect::>(); + + match notifications.get(idx) { + None => anyhow::bail!( + "index not present, must be less than {}", + notifications.len() + ), + Some(id) => { + t.execute( + "UPDATE notifications SET metadata = $2 + WHERE notification_id = $1", + &[&id, &metadata], + ) + .await + .context("update notification id")?; + } + } + + if let Err(e) = t.commit().await { + if e.code().map_or(false, |c| { + *c == tokio_postgres::error::SqlState::T_R_SERIALIZATION_FAILURE + }) { + trace!("serialization failure, restarting index movement"); + continue; + } else { + return Err(e).context("transaction commit failure"); + } + } else { + break; + } + } + + Ok(()) + } + + async fn move_indices(&mut self, user_id: i64, from: usize, to: usize) -> Result<()> { + loop { + let t = self + .build_transaction() + .isolation_level(tokio_postgres::IsolationLevel::Serializable) + .start() + .await + .context("begin transaction")?; + + let notifications = t + .query( + "SELECT notification_id, idx, user_id + FROM notifications + WHERE user_id = $1 + ORDER BY idx ASC NULLS LAST;", + &[&user_id], + ) + .await + .context("failed to get initial ordering")?; + + let mut notifications = notifications + .into_iter() + .map(|n| n.get(0)) + .collect::>(); + + if notifications.get(from).is_none() { + anyhow::bail!( + "`from` index not present, must be less than {}", + notifications.len() + ); + } + + if notifications.get(to).is_none() { + anyhow::bail!( + "`to` index not present, must be less than {}", + notifications.len() + ); + } + + if from < to { + notifications[from..=to].rotate_left(1); + } else if to < from { + notifications[to..=from].rotate_right(1); + } + + for (idx, id) in notifications.into_iter().enumerate() { + t.execute( + "UPDATE notifications SET idx = $2 + WHERE notification_id = $1", + &[&id, &(idx as i32)], + ) + .await + .context("update notification id")?; + } + + if let Err(e) = t.commit().await { + if e.code().map_or(false, |c| { + *c == tokio_postgres::error::SqlState::T_R_SERIALIZATION_FAILURE + }) { + trace!("serialization failure, restarting index movement"); + continue; + } else { + return Err(e).context("transaction commit failure"); + } + } else { + break; + } + } + + Ok(()) + } + + async fn insert_job( + &mut self, + name: &str, + scheduled_at: &DateTime, + metadata: &serde_json::Value, + ) -> Result<()> { + tracing::trace!("insert_job(name={})", name); + + self.conn() + .execute( + "INSERT INTO jobs (name, scheduled_at, metadata) VALUES ($1, $2, $3) + ON CONFLICT (name, scheduled_at) DO UPDATE SET metadata = EXCLUDED.metadata", + &[&name, &scheduled_at, &metadata], + ) + .await + .context("Inserting job")?; + + Ok(()) + } + + async fn delete_job(&mut self, id: &Uuid) -> Result<()> { + tracing::trace!("delete_job(id={})", id); + + self.conn() + .execute("DELETE FROM jobs WHERE id = $1", &[id]) + .await + .context("Deleting job")?; + + Ok(()) + } + + async fn update_job_error_message(&mut self, id: &Uuid, message: &str) -> Result<()> { + tracing::trace!("update_job_error_message(id={})", id); + + self.conn() + .execute( + "UPDATE jobs SET error_message = $2 WHERE id = $1", + &[&id, &message], + ) + .await + .context("Updating job error message")?; + + Ok(()) + } + + async fn update_job_executed_at(&mut self, id: &Uuid) -> Result<()> { + tracing::trace!("update_job_executed_at(id={})", id); + + self.conn() + .execute("UPDATE jobs SET executed_at = now() WHERE id = $1", &[&id]) + .await + .context("Updating job executed at")?; + + Ok(()) + } + + async fn get_job_by_name_and_scheduled_at( + &mut self, + name: &str, + scheduled_at: &DateTime, + ) -> Result { + tracing::trace!( + "get_job_by_name_and_scheduled_at(name={}, scheduled_at={})", + name, + scheduled_at + ); + + let job = self + .conn() + .query_one( + "SELECT * FROM jobs WHERE name = $1 AND scheduled_at = $2", + &[&name, &scheduled_at], + ) + .await + .context("Select job by name and scheduled at")?; + + deserialize_job(&job) + } + + async fn get_jobs_to_execute(&mut self) -> Result> { + let jobs = self + .conn() + .query( + "SELECT * FROM jobs WHERE scheduled_at <= now() + AND (error_message IS NULL OR executed_at <= now() - INTERVAL '60 minutes')", + &[], + ) + .await + .context("Getting jobs data")?; + + let mut data = Vec::with_capacity(jobs.len()); + for job in jobs { + let serialized_job = deserialize_job(&job); + data.push(serialized_job.unwrap()); + } + + Ok(data) + } + + async fn lock_and_load_issue_data( + &mut self, + repo: &str, + issue_number: i32, + key: &str, + ) -> Result<(Box, Option)> { + let transaction = self.conn_mut().transaction().await?; + transaction + .execute("LOCK TABLE issue_data", &[]) + .await + .context("locking issue data")?; + let data = transaction + .query_opt( + "SELECT data FROM issue_data WHERE \ + repo = $1 AND issue_number = $2 AND key = $3", + &[&repo, &issue_number, &key], + ) + .await + .context("selecting issue data")? + .map(|row| row.get::>(0).0); + Ok((Box::new(PostgresTransaction { conn: transaction }), data)) + } + + async fn save_issue_data( + &mut self, + repo: &str, + issue_number: i32, + key: &str, + data: &serde_json::Value, + ) -> Result<()> { + self.conn() + .execute( + "INSERT INTO issue_data (repo, issue_number, key, data) \ + VALUES ($1, $2, $3, $4) \ + ON CONFLICT (repo, issue_number, key) DO UPDATE SET data=EXCLUDED.data", + &[&repo, &issue_number, &key, &Json(&data)], + ) + .await + .context("inserting issue data")?; + Ok(()) + } +} + +fn deserialize_job(row: &tokio_postgres::row::Row) -> Result { + let id: Uuid = row.try_get(0)?; + let name: String = row.try_get(1)?; + let scheduled_at: DateTime = row.try_get(2)?; + let metadata: serde_json::Value = row.try_get(3)?; + let executed_at: Option> = row.try_get(4)?; + let error_message: Option = row.try_get(5)?; + + Ok(Job { + id, + name, + scheduled_at, + metadata, + executed_at, + error_message, + }) +} diff --git a/src/db/rustc_commits.rs b/src/db/rustc_commits.rs deleted file mode 100644 index b272d44c..00000000 --- a/src/db/rustc_commits.rs +++ /dev/null @@ -1,79 +0,0 @@ -use anyhow::Context as _; -use chrono::{DateTime, FixedOffset}; -use tokio_postgres::Client as DbClient; - -/// A bors merge commit. -#[derive(Debug, serde::Serialize)] -pub struct Commit { - pub sha: String, - pub parent_sha: String, - pub time: DateTime, - pub pr: Option, -} - -pub async fn record_commit(db: &DbClient, commit: Commit) -> anyhow::Result<()> { - tracing::trace!("record_commit(sha={})", commit.sha); - let pr = commit.pr.expect("commit has pr"); - db.execute( - "INSERT INTO rustc_commits (sha, parent_sha, time, pr) VALUES ($1, $2, $3, $4) ON CONFLICT DO NOTHING", - &[&commit.sha, &commit.parent_sha, &commit.time, &(pr as i32)], - ) - .await - .context("inserting commit")?; - Ok(()) -} - -pub async fn has_commit(db: &DbClient, sha: &str) -> bool { - !db.query("SELECT 1 FROM rustc_commits WHERE sha = $1", &[&sha]) - .await - .unwrap() - .is_empty() -} - -pub async fn get_missing_commits(db: &DbClient) -> Vec { - let missing = db - .query( - " - SELECT parent_sha - FROM rustc_commits - WHERE parent_sha NOT IN ( - SELECT sha - FROM rustc_commits - )", - &[], - ) - .await - .unwrap(); - missing.into_iter().map(|row| row.get(0)).collect() -} - -pub async fn get_commits_with_artifacts(db: &DbClient) -> anyhow::Result> { - let commits = db - .query( - " - select sha, parent_sha, time, pr - from rustc_commits - where time >= current_date - interval '168 days' - order by time desc;", - &[], - ) - .await - .context("Getting commit data")?; - - let mut data = Vec::with_capacity(commits.len()); - for commit in commits { - let sha: String = commit.get(0); - let parent_sha: String = commit.get(1); - let time: DateTime = commit.get(2); - let pr: Option = commit.get(3); - - data.push(Commit { - sha, - parent_sha, - time, - pr: pr.map(|n| n as u32), - }); - } - - Ok(data) -} diff --git a/src/db/sqlite.rs b/src/db/sqlite.rs new file mode 100644 index 00000000..77267ac1 --- /dev/null +++ b/src/db/sqlite.rs @@ -0,0 +1,742 @@ +use super::{Commit, Identifier, Notification, NotificationData}; +use crate::db::{Connection, ConnectionManager, Job, ManagedConnection, Transaction}; +use anyhow::{Context, Result}; +use chrono::DateTime; +use chrono::Utc; +use rusqlite::params; +use std::path::PathBuf; +use std::sync::Mutex; +use std::sync::Once; +use uuid::Uuid; + +pub struct SqliteTransaction<'a> { + conn: &'a mut SqliteConnection, + finished: bool, +} + +#[async_trait::async_trait] +impl<'a> Transaction for SqliteTransaction<'a> { + async fn commit(mut self: Box) -> Result<(), anyhow::Error> { + self.finished = true; + Ok(self.conn.raw().execute_batch("COMMIT")?) + } + + async fn finish(mut self: Box) -> Result<(), anyhow::Error> { + self.finished = true; + Ok(self.conn.raw().execute_batch("ROLLBACK")?) + } + fn conn(&mut self) -> &mut dyn Connection { + &mut *self.conn + } + fn conn_ref(&self) -> &dyn Connection { + &*self.conn + } +} + +impl std::ops::Deref for SqliteTransaction<'_> { + type Target = dyn Connection; + fn deref(&self) -> &Self::Target { + &*self.conn + } +} + +impl std::ops::DerefMut for SqliteTransaction<'_> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.conn + } +} + +impl Drop for SqliteTransaction<'_> { + fn drop(&mut self) { + if !self.finished { + self.conn.raw().execute_batch("ROLLBACK").unwrap(); + } + } +} + +pub struct Sqlite(PathBuf, Once); + +impl Sqlite { + pub fn new(path: PathBuf) -> Self { + if let Some(parent) = path.parent() { + if !parent.exists() { + std::fs::create_dir_all(parent).unwrap(); + } + } + Sqlite(path, Once::new()) + } +} + +struct Migration { + /// One or more SQL statements, each terminated by a semicolon. + sql: &'static str, + + /// If false, indicates that foreign key checking should be delayed until after execution of + /// the migration SQL, and foreign key `ON UPDATE` and `ON DELETE` actions disabled completely. + foreign_key_constraints_enabled: bool, +} + +impl Migration { + /// Returns a `Migration` with foreign key constraints enabled during execution. + const fn new(sql: &'static str) -> Migration { + Migration { + sql, + foreign_key_constraints_enabled: true, + } + } + + /// Returns a `Migration` with foreign key checking delayed until after execution, and foreign + /// key `ON UPDATE` and `ON DELETE` actions disabled completely. + /// + /// SQLite has limited `ALTER TABLE` capabilities, so some schema alterations require the + /// approach of replacing a table with a new one having the desired schema. Because there might + /// be other tables with foreign key constraints on the table, these constraints need to be + /// disabled during execution of such migration SQL, and reenabled after. Otherwise, dropping + /// the old table may trigger `ON DELETE` actions in the referencing tables. See [SQLite + /// documentation](https://www.sqlite.org/lang_altertable.html) for more information. + #[allow(dead_code)] + const fn without_foreign_key_constraints(sql: &'static str) -> Migration { + Migration { + sql, + foreign_key_constraints_enabled: false, + } + } + + fn execute(&self, conn: &mut rusqlite::Connection, migration_id: i32) { + if self.foreign_key_constraints_enabled { + let tx = conn.transaction().unwrap(); + tx.execute_batch(&self.sql).unwrap(); + tx.pragma_update(None, "user_version", &migration_id) + .unwrap(); + tx.commit().unwrap(); + return; + } + + // The following steps are reproduced from https://www.sqlite.org/lang_altertable.html, + // from the section titled, "Making Other Kinds Of Table Schema Changes". + + // 1. If foreign key constraints are enabled, disable them using PRAGMA foreign_keys=OFF. + conn.pragma_update(None, "foreign_keys", &"OFF").unwrap(); + + // 2. Start a transaction. + let tx = conn.transaction().unwrap(); + + // The migration SQL is responsible for steps 3 through 9. + + // 3. Remember the format of all indexes, triggers, and views associated with table X. + // This information will be needed in step 8 below. One way to do this is to run a + // query like the following: SELECT type, sql FROM sqlite_schema WHERE tbl_name='X'. + // + // 4. Use CREATE TABLE to construct a new table "new_X" that is in the desired revised + // format of table X. Make sure that the name "new_X" does not collide with any + // existing table name, of course. + // + // 5. Transfer content from X into new_X using a statement like: INSERT INTO new_X SELECT + // ... FROM X. + // + // 6. Drop the old table X: DROP TABLE X. + // + // 7. Change the name of new_X to X using: ALTER TABLE new_X RENAME TO X. + // + // 8. Use CREATE INDEX, CREATE TRIGGER, and CREATE VIEW to reconstruct indexes, triggers, + // and views associated with table X. Perhaps use the old format of the triggers, + // indexes, and views saved from step 3 above as a guide, making changes as appropriate + // for the alteration. + // + // 9. If any views refer to table X in a way that is affected by the schema change, then + // drop those views using DROP VIEW and recreate them with whatever changes are + // necessary to accommodate the schema change using CREATE VIEW. + tx.execute_batch(&self.sql).unwrap(); + + // 10. If foreign key constraints were originally enabled then run PRAGMA foreign_key_check + // to verify that the schema change did not break any foreign key constraints. + tx.pragma_query(None, "foreign_key_check", |row| { + let table: String = row.get_unwrap(0); + let row_id: Option = row.get_unwrap(1); + let foreign_table: String = row.get_unwrap(2); + let fk_idx: i64 = row.get_unwrap(3); + + tx.query_row::<(), _, _>( + "select * from pragma_foreign_key_list(?) where id = ?", + params![&table, &fk_idx], + |row| { + let col: String = row.get_unwrap(3); + let foreign_col: String = row.get_unwrap(4); + panic!( + "Foreign key violation encountered during migration\n\ + table: {},\n\ + column: {},\n\ + row_id: {:?},\n\ + foreign table: {},\n\ + foreign column: {}\n\ + migration ID: {}\n", + table, col, row_id, foreign_table, foreign_col, migration_id, + ); + }, + ) + .unwrap(); + Ok(()) + }) + .unwrap(); + + tx.pragma_update(None, "user_version", &migration_id) + .unwrap(); + + // 11. Commit the transaction started in step 2. + tx.commit().unwrap(); + + // 12. If foreign keys constraints were originally enabled, reenable them now. + conn.pragma_update(None, "foreign_keys", &"ON").unwrap(); + } +} + +static MIGRATIONS: &[Migration] = &[ + Migration::new(""), + Migration::new( + r#" +CREATE TABLE notifications ( + notification_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + user_id BIGINT, + origin_url TEXT NOT NULL, + origin_html TEXT, + time TEXT NOT NULL, + short_description TEXT, + team_name TEXT, + idx INTEGER, + metadata TEXT +); + "#, + ), + Migration::new( + r#" +CREATE TABLE users ( + user_id BIGINT PRIMARY KEY, + username TEXT NOT NULL +); + "#, + ), + Migration::new( + r#" +CREATE TABLE rustc_commits ( + sha TEXT PRIMARY KEY, + parent_sha TEXT NOT NULL, + time TEXT NOT NULL, + pr INTEGER +); + "#, + ), + Migration::new( + r#" +CREATE TABLE issue_data ( + repo TEXT, + issue_number INTEGER, + key TEXT, + data JSONB, + PRIMARY KEY (repo, issue_number, key) +); + "#, + ), + Migration::new( + r#" +CREATE TABLE jobs ( + id TEXT PRIMARY KEY, + name TEXT NOT NULL, + scheduled_at TIMESTAMP WITH TIME ZONE NOT NULL, + metadata JSONB, + executed_at TIMESTAMP WITH TIME ZONE, + error_message TEXT +); + "#, + ), + Migration::new( + r#" +CREATE UNIQUE INDEX jobs_name_scheduled_at_unique_index + ON jobs ( + name, scheduled_at + ); + "#, + ), +]; + +#[async_trait::async_trait] +impl ConnectionManager for Sqlite { + type Connection = Mutex; + async fn open(&self) -> Self::Connection { + let mut conn = rusqlite::Connection::open(&self.0).unwrap(); + conn.pragma_update(None, "cache_size", &-128000).unwrap(); + conn.pragma_update(None, "journal_mode", &"WAL").unwrap(); + conn.pragma_update(None, "foreign_keys", &"ON").unwrap(); + + self.1.call_once(|| { + let version: i32 = conn + .query_row( + "select user_version from pragma_user_version;", + params![], + |row| row.get(0), + ) + .unwrap(); + for mid in (version as usize + 1)..MIGRATIONS.len() { + MIGRATIONS[mid].execute(&mut conn, mid as i32); + } + }); + + Mutex::new(conn) + } + async fn is_valid(&self, conn: &mut Self::Connection) -> bool { + conn.get_mut() + .unwrap_or_else(|e| e.into_inner()) + .execute_batch("") + .is_ok() + } +} + +pub struct SqliteConnection { + conn: ManagedConnection>, +} + +#[async_trait::async_trait] +impl Connection for SqliteConnection { + async fn transaction(&mut self) -> Box { + Box::new(self.raw_transaction()) + } + + async fn record_username(&mut self, user_id: i64, username: String) -> Result<()> { + self.raw().execute( + "INSERT INTO users (user_id, username) VALUES (?, ?) ON CONFLICT DO NOTHING", + params![user_id, username], + )?; + Ok(()) + } + + async fn record_ping(&mut self, notification: &Notification) -> Result<()> { + self.raw().execute( + "INSERT INTO notifications + (user_id, origin_url, origin_html, time, short_description, team_name, idx) + VALUES ( + ?, ?, ?, ?, ?, ?, + (SELECT ifnull(max(notifications.idx), 0) + 1 from notifications + where notifications.user_id = ?) + )", + params![ + notification.user_id, + notification.origin_url, + notification.origin_html, + notification.time, + notification.short_description, + notification.team_name, + notification.user_id, + ], + )?; + Ok(()) + } + + async fn get_missing_commits(&mut self) -> Result> { + let commits = self + .raw() + .prepare( + " + SELECT parent_sha + FROM rustc_commits + WHERE parent_sha NOT IN ( + SELECT sha + FROM rustc_commits + )", + )? + .query_map([], |row| row.get(0))? + .collect::>()?; + Ok(commits) + } + + async fn record_commit(&mut self, commit: &Commit) -> Result<()> { + let pr = commit.pr.expect("commit has pr"); + // let time = commit.time.timestamp(); + self.raw().execute( + "INSERT INTO rustc_commits (sha, parent_sha, time, pr) \ + VALUES (?, ?, ?, ?) ON CONFLICT DO NOTHING", + params![commit.sha, commit.parent_sha, commit.time, pr], + )?; + Ok(()) + } + + async fn has_commit(&mut self, sha: &str) -> Result { + Ok(self + .raw() + .prepare("SELECT 1 FROM rustc_commits WHERE sha = ?")? + .query([sha])? + .next()? + .is_some()) + } + + async fn get_commits_with_artifacts(&mut self) -> Result> { + let commits = self + .raw() + .prepare( + "SELECT sha, parent_sha, time, pr + FROM rustc_commits + WHERE time >= datetime('now', '-168 days') + ORDER BY time DESC;", + )? + .query_map([], |row| { + let c = Commit { + sha: row.get(0)?, + parent_sha: row.get(1)?, + time: row.get(2)?, + pr: row.get(3)?, + }; + Ok(c) + })? + .collect::>()?; + Ok(commits) + } + + async fn get_notifications(&mut self, username: &str) -> Result> { + let notifications = self + .raw() + .prepare( + "SELECT username, origin_url, origin_html, time, short_description, idx, metadata + FROM notifications + JOIN users ON notifications.user_id = users.user_id + WHERE username = ? + ORDER BY notifications.idx ASC NULLS LAST;", + )? + .query_map([username], |row| { + let n = NotificationData { + origin_url: row.get(1)?, + origin_text: row.get(2)?, + time: row.get(3)?, + short_description: row.get(4)?, + metadata: row.get(6)?, + }; + Ok(n) + })? + .collect::>()?; + Ok(notifications) + } + + async fn delete_ping( + &mut self, + user_id: i64, + identifier: Identifier<'_>, + ) -> Result> { + match identifier { + Identifier::Url(origin_url) => { + let rows = self + .raw() + .prepare( + "DELETE FROM notifications WHERE user_id = ? and origin_url = ? + RETURNING origin_html, time, short_description, metadata", + )? + .query_map(params![user_id, origin_url], |row| { + let n = NotificationData { + origin_url: origin_url.to_string(), + origin_text: row.get(0)?, + time: row.get(1)?, + short_description: row.get(2)?, + metadata: row.get(3)?, + }; + Ok(n) + })? + .collect::>()?; + Ok(rows) + } + Identifier::Index(idx) => { + let deleted_notifications: Vec<_> = self + .raw() + .prepare( + "DELETE FROM notifications WHERE notification_id = ( + SELECT notification_id FROM notifications + WHERE user_id = ? + ORDER BY idx ASC NULLS LAST + LIMIT 1 OFFSET ? + ) + RETURNING origin_url, origin_html, time, short_description, metadata", + )? + .query_map(params![user_id, idx.get() - 1], |row| { + let n = NotificationData { + origin_url: row.get(0)?, + origin_text: row.get(1)?, + time: row.get(2)?, + short_description: row.get(3)?, + metadata: row.get(4)?, + }; + Ok(n) + })? + .collect::>()?; + if deleted_notifications.is_empty() { + anyhow::bail!("No such notification with index {}", idx.get()); + } + return Ok(deleted_notifications); + } + Identifier::All => { + let rows = self + .raw() + .prepare( + "DELETE FROM notifications WHERE user_id = ? + RETURNING origin_url, origin_html, time, short_description, metadata", + )? + .query_map([&user_id], |row| { + let n = NotificationData { + origin_url: row.get(0)?, + origin_text: row.get(1)?, + time: row.get(2)?, + short_description: row.get(3)?, + metadata: row.get(4)?, + }; + Ok(n) + })? + .collect::>()?; + Ok(rows) + } + } + } + + async fn add_metadata( + &mut self, + user_id: i64, + idx: usize, + metadata: Option<&str>, + ) -> Result<()> { + let t = self.raw().transaction()?; + + let notifications = t + .prepare( + "SELECT notification_id + FROM notifications + WHERE user_id = ? + ORDER BY idx ASC NULLS LAST", + )? + .query_map([user_id], |row| row.get(0)) + .context("failed to get initial ordering")? + .collect::, rusqlite::Error>>()?; + + match notifications.get(idx) { + None => anyhow::bail!( + "index not present, must be less than {}", + notifications.len() + ), + Some(id) => { + t.prepare( + "UPDATE notifications SET metadata = ? + WHERE notification_id = ?", + )? + .execute(params![metadata, id]) + .context("update notification id")?; + } + } + t.commit()?; + + Ok(()) + } + + async fn move_indices(&mut self, user_id: i64, from: usize, to: usize) -> Result<()> { + let t = self.raw().transaction()?; + + let mut notifications = t + .prepare( + "SELECT notification_id + FROM notifications + WHERE user_id = ? + ORDER BY idx ASC NULLS LAST;", + )? + .query_map([user_id], |row| row.get(0)) + .context("failed to get initial ordering")? + .collect::, rusqlite::Error>>()?; + + if notifications.get(from).is_none() { + anyhow::bail!( + "`from` index not present, must be less than {}", + notifications.len() + ); + } + + if notifications.get(to).is_none() { + anyhow::bail!( + "`to` index not present, must be less than {}", + notifications.len() + ); + } + + if from < to { + notifications[from..=to].rotate_left(1); + } else if to < from { + notifications[to..=from].rotate_right(1); + } + + for (idx, id) in notifications.into_iter().enumerate() { + t.prepare( + "UPDATE notifications SET idx = ? + WHERE notification_id = ?", + )? + .execute(params![idx, id]) + .context("update notification id")?; + } + t.commit()?; + + Ok(()) + } + + async fn insert_job( + &mut self, + name: &str, + scheduled_at: &DateTime, + metadata: &serde_json::Value, + ) -> Result<()> { + tracing::trace!("insert_job(name={})", name); + + let id = Uuid::new_v4(); + self.raw() + .execute( + "INSERT INTO jobs (id, name, scheduled_at, metadata) VALUES (?, ?, ?, ?) + ON CONFLICT (name, scheduled_at) DO UPDATE SET metadata = EXCLUDED.metadata", + params![id, name, scheduled_at, metadata], + ) + .context("Inserting job")?; + + Ok(()) + } + + async fn delete_job(&mut self, id: &Uuid) -> Result<()> { + tracing::trace!("delete_job(id={})", id); + + self.raw() + .execute("DELETE FROM jobs WHERE id = ?", [id]) + .context("Deleting job")?; + + Ok(()) + } + + async fn update_job_error_message(&mut self, id: &Uuid, message: &str) -> Result<()> { + tracing::trace!("update_job_error_message(id={})", id); + + self.raw() + .execute( + "UPDATE jobs SET error_message = ? WHERE id = ?", + params![message, id], + ) + .context("Updating job error message")?; + + Ok(()) + } + + async fn update_job_executed_at(&mut self, id: &Uuid) -> Result<()> { + tracing::trace!("update_job_executed_at(id={})", id); + + self.raw() + .execute( + "UPDATE jobs SET executed_at = datetime('now') WHERE id = ?", + [id], + ) + .context("Updating job executed at")?; + + Ok(()) + } + + async fn get_job_by_name_and_scheduled_at( + &mut self, + name: &str, + scheduled_at: &DateTime, + ) -> Result { + tracing::trace!( + "get_job_by_name_and_scheduled_at(name={}, scheduled_at={})", + name, + scheduled_at + ); + + let job = self + .raw() + .query_row( + "SELECT * FROM jobs WHERE name = ? AND scheduled_at = ?", + params![name, scheduled_at], + |row| deserialize_job(row), + ) + .context("Select job by name and scheduled at")?; + Ok(job) + } + + async fn get_jobs_to_execute(&mut self) -> Result> { + let jobs = self + .raw() + .prepare( + "SELECT * FROM jobs WHERE scheduled_at <= datetime('now') + AND (error_message IS NULL OR executed_at <= datetime('now', '-60 minutes'))", + )? + .query_map([], |row| deserialize_job(row))? + .collect::>()?; + Ok(jobs) + } + + async fn lock_and_load_issue_data( + &mut self, + repo: &str, + issue_number: i32, + key: &str, + ) -> Result<(Box, Option)> { + let transaction = self.raw_transaction(); + let data = match transaction + .conn + .raw() + .prepare( + "SELECT data FROM issue_data WHERE \ + repo = ? AND issue_number = ? AND key = ?", + )? + .query_row(params![repo, issue_number, key], |row| row.get(0)) + { + Err(rusqlite::Error::QueryReturnedNoRows) => None, + Err(e) => return Err(e.into()), + Ok(d) => Some(d), + }; + Ok((Box::new(transaction), data)) + } + + async fn save_issue_data( + &mut self, + repo: &str, + issue_number: i32, + key: &str, + data: &serde_json::Value, + ) -> Result<()> { + self.raw() + .execute( + "INSERT INTO issue_data (repo, issue_number, key, data) \ + VALUES (?, ?, ?, ?) \ + ON CONFLICT (repo, issue_number, key) DO UPDATE SET data=EXCLUDED.data", + params![repo, issue_number, key, data], + ) + .context("inserting issue data")?; + Ok(()) + } +} + +fn assert_sync() {} + +impl SqliteConnection { + pub fn new(conn: ManagedConnection>) -> Self { + assert_sync::(); + Self { conn } + } + + pub fn raw(&mut self) -> &mut rusqlite::Connection { + self.conn.get_mut().unwrap_or_else(|e| e.into_inner()) + } + pub fn raw_ref(&self) -> std::sync::MutexGuard { + self.conn.lock().unwrap_or_else(|e| e.into_inner()) + } + fn raw_transaction(&mut self) -> SqliteTransaction<'_> { + self.raw().execute_batch("BEGIN DEFERRED").unwrap(); + SqliteTransaction { + conn: self, + finished: false, + } + } +} + +fn deserialize_job(row: &rusqlite::Row<'_>) -> std::result::Result { + Ok(Job { + id: row.get(0)?, + name: row.get(1)?, + scheduled_at: row.get(2)?, + metadata: row.get(3)?, + executed_at: row.get(4)?, + error_message: row.get(5)?, + }) +} diff --git a/src/github.rs b/src/github.rs index 35309b2b..b7234e02 100644 --- a/src/github.rs +++ b/src/github.rs @@ -1,5 +1,7 @@ +use crate::test_record; use anyhow::Context; use async_trait::async_trait; +use bytes::Bytes; use chrono::{DateTime, FixedOffset, Utc}; use futures::{future::BoxFuture, FutureExt}; use hyper::header::HeaderValue; @@ -9,7 +11,7 @@ use reqwest::{Client, Request, RequestBuilder, Response, StatusCode}; use std::collections::{HashMap, HashSet}; use std::convert::TryInto; use std::{ - fmt, + fmt::{self, Write}, time::{Duration, SystemTime}, }; use tracing as log; @@ -21,22 +23,32 @@ pub struct User { } impl GithubClient { - async fn _send_req(&self, req: RequestBuilder) -> anyhow::Result<(Response, String)> { + async fn send_req(&self, req: RequestBuilder) -> anyhow::Result<(Bytes, String)> { const MAX_ATTEMPTS: usize = 2; - log::debug!("_send_req with {:?}", req); + log::debug!("send_req with {:?}", req); let req_dbg = format!("{:?}", req); let req = req .build() .with_context(|| format!("building reqwest {}", req_dbg))?; + let test_capture_info = test_record::capture_request(&req); + let mut resp = self.client.execute(req.try_clone().unwrap()).await?; if let Some(sleep) = Self::needs_retry(&resp).await { resp = self.retry(req, sleep, MAX_ATTEMPTS).await?; } + let status = resp.status(); + let maybe_err = resp.error_for_status_ref().err(); + let body = resp + .bytes() + .await + .with_context(|| format!("failed to read response body {req_dbg}"))?; + test_record::record_request(test_capture_info, status, &body); + if let Some(e) = maybe_err { + return Err(anyhow::Error::new(e)).with_context(|| format!("response: {}", String::from_utf8_lossy(&body))); + } - resp.error_for_status_ref()?; - - Ok((resp, req_dbg)) + Ok((body, req_dbg)) } async fn needs_retry(resp: &Response) -> Option { @@ -110,12 +122,13 @@ impl GithubClient { .client .execute( self.client - .get("https://api.github.com/rate_limit") + .get(&format!("{}/rate_limit", self.api_url)) .configure(self) .build() .unwrap(), ) .await?; + rate_resp.error_for_status_ref()?; let rate_limit_response = rate_resp.json::().await?; // Check url for search path because github has different rate limits for the search api @@ -151,33 +164,20 @@ impl GithubClient { .boxed() } - async fn send_req(&self, req: RequestBuilder) -> anyhow::Result> { - let (mut resp, req_dbg) = self._send_req(req).await?; - - let mut body = Vec::new(); - while let Some(chunk) = resp.chunk().await.transpose() { - let chunk = chunk - .context("reading stream failed") - .map_err(anyhow::Error::from) - .context(req_dbg.clone())?; - body.extend_from_slice(&chunk); - } - - Ok(body) - } - pub async fn json(&self, req: RequestBuilder) -> anyhow::Result where T: serde::de::DeserializeOwned, { - let (resp, req_dbg) = self._send_req(req).await?; - Ok(resp.json().await.context(req_dbg)?) + let (body, _req_dbg) = self.send_req(req).await?; + Ok(serde_json::from_slice(&body)?) } } impl User { pub async fn current(client: &GithubClient) -> anyhow::Result { - client.json(client.get("https://api.github.com/user")).await + client + .json(client.get(&format!("{}/user", client.api_url))) + .await } pub async fn is_team_member<'a>(&'a self, client: &'a GithubClient) -> anyhow::Result { @@ -252,7 +252,7 @@ pub struct Issue { pub number: u64, #[serde(deserialize_with = "opt_string")] pub body: String, - created_at: chrono::DateTime, + pub created_at: chrono::DateTime, pub updated_at: chrono::DateTime, /// The SHA for a merge commit. /// @@ -402,18 +402,18 @@ impl fmt::Display for IssueRepository { } impl IssueRepository { - fn url(&self) -> String { + fn url(&self, client: &GithubClient) -> String { format!( - "https://api.github.com/repos/{}/{}", - self.organization, self.repository + "{}/repos/{}/{}", + client.api_url, self.organization, self.repository ) } async fn has_label(&self, client: &GithubClient, label: &str) -> anyhow::Result { #[allow(clippy::redundant_pattern_matching)] - let url = format!("{}/labels/{}", self.url(), label); - match client._send_req(client.get(&url)).await { - Ok((_, _)) => Ok(true), + let url = format!("{}/labels/{}", self.url(client), label); + match client.send_req(client.get(&url)).await { + Ok(_) => Ok(true), Err(e) => { if e.downcast_ref::() .map_or(false, |e| e.status() == Some(StatusCode::NOT_FOUND)) @@ -481,19 +481,25 @@ impl Issue { } pub async fn get_comment(&self, client: &GithubClient, id: usize) -> anyhow::Result { - let comment_url = format!("{}/issues/comments/{}", self.repository().url(), id); + let comment_url = format!("{}/issues/comments/{}", self.repository().url(client), id); + let comment = client.json(client.get(&comment_url)).await?; + Ok(comment) + } + + pub async fn get_comments(&self, client: &GithubClient) -> anyhow::Result> { + let comment_url = format!("{}/issues/{}/comments", self.repository().url(client), self.number); let comment = client.json(client.get(&comment_url)).await?; Ok(comment) } pub async fn edit_body(&self, client: &GithubClient, body: &str) -> anyhow::Result<()> { - let edit_url = format!("{}/issues/{}", self.repository().url(), self.number); + let edit_url = format!("{}/issues/{}", self.repository().url(client), self.number); #[derive(serde::Serialize)] struct ChangedIssue<'a> { body: &'a str, } client - ._send_req(client.patch(&edit_url).json(&ChangedIssue { body })) + .send_req(client.patch(&edit_url).json(&ChangedIssue { body })) .await .context("failed to edit issue body")?; Ok(()) @@ -505,13 +511,13 @@ impl Issue { id: usize, new_body: &str, ) -> anyhow::Result<()> { - let comment_url = format!("{}/issues/comments/{}", self.repository().url(), id); + let comment_url = format!("{}/issues/comments/{}", self.repository().url(client), id); #[derive(serde::Serialize)] struct NewComment<'a> { body: &'a str, } client - ._send_req( + .send_req( client .patch(&comment_url) .json(&NewComment { body: new_body }), @@ -526,8 +532,13 @@ impl Issue { struct PostComment<'a> { body: &'a str, } + let comments_path = self + .comments_url + .strip_prefix("https://api.github.com") + .expect("expected api host"); + let comments_url = format!("{}{comments_path}", client.api_url); client - ._send_req(client.post(&self.comments_url).json(&PostComment { body })) + .send_req(client.post(&comments_url).json(&PostComment { body })) .await .context("failed to post comment")?; Ok(()) @@ -538,7 +549,7 @@ impl Issue { // DELETE /repos/:owner/:repo/issues/:number/labels/{name} let url = format!( "{repo_url}/issues/{number}/labels/{name}", - repo_url = self.repository().url(), + repo_url = self.repository().url(client), number = self.number, name = label, ); @@ -553,7 +564,7 @@ impl Issue { } client - ._send_req(client.delete(&url)) + .send_req(client.delete(&url)) .await .context("failed to delete label")?; @@ -570,7 +581,7 @@ impl Issue { // repo_url = https://api.github.com/repos/Codertocat/Hello-World let url = format!( "{repo_url}/issues/{number}/labels", - repo_url = self.repository().url(), + repo_url = self.repository().url(client), number = self.number ); @@ -610,7 +621,7 @@ impl Issue { } client - ._send_req(client.post(&url).json(&LabelsReq { + .send_req(client.post(&url).json(&LabelsReq { labels: known_labels, })) .await @@ -637,7 +648,7 @@ impl Issue { log::info!("remove {:?} assignees for {}", selection, self.global_id()); let url = format!( "{repo_url}/issues/{number}/assignees", - repo_url = self.repository().url(), + repo_url = self.repository().url(client), number = self.number ); @@ -661,7 +672,7 @@ impl Issue { assignees: &'a [&'a str], } client - ._send_req(client.delete(&url).json(&AssigneeReq { + .send_req(client.delete(&url).json(&AssigneeReq { assignees: &assignees[..], })) .await @@ -677,7 +688,7 @@ impl Issue { log::info!("add_assignee {} for {}", user, self.global_id()); let url = format!( "{repo_url}/issues/{number}/assignees", - repo_url = self.repository().url(), + repo_url = self.repository().url(client), number = self.number ); @@ -723,7 +734,7 @@ impl Issue { title ); - let create_url = format!("{}/milestones", self.repository().url()); + let create_url = format!("{}/milestones", self.repository().url(client)); let resp = client .send_req( client @@ -735,7 +746,7 @@ impl Issue { // fine, it just means the milestone was already created. log::trace!("Created milestone: {:?}", resp); - let list_url = format!("{}/milestones", self.repository().url()); + let list_url = format!("{}/milestones", self.repository().url(client)); let milestone_list: Vec = client.json(client.get(&list_url)).await?; let milestone_no = if let Some(milestone) = milestone_list.iter().find(|v| v.title == title) { @@ -752,9 +763,9 @@ impl Issue { struct SetMilestone { milestone: u64, } - let url = format!("{}/issues/{}", self.repository().url(), self.number); + let url = format!("{}/issues/{}", self.repository().url(client), self.number); client - ._send_req(client.patch(&url).json(&SetMilestone { + .send_req(client.patch(&url).json(&SetMilestone { milestone: milestone_no, })) .await @@ -763,13 +774,13 @@ impl Issue { } pub async fn close(&self, client: &GithubClient) -> anyhow::Result<()> { - let edit_url = format!("{}/issues/{}", self.repository().url(), self.number); + let edit_url = format!("{}/issues/{}", self.repository().url(client), self.number); #[derive(serde::Serialize)] struct CloseIssue<'a> { state: &'a str, } client - ._send_req( + .send_req( client .patch(&edit_url) .json(&CloseIssue { state: "closed" }), @@ -789,13 +800,14 @@ impl Issue { let mut req = client.get(&format!( "{}/compare/{}...{}", - self.repository().url(), + self.repository().url(client), before, after )); req = req.header("Accept", "application/vnd.github.v3.diff"); - let diff = client.send_req(req).await?; - Ok(Some(String::from(String::from_utf8_lossy(&diff)))) + let (diff, _) = client.send_req(req).await?; + let body = String::from_utf8_lossy(&diff).to_string(); + Ok(Some(body)) } /// Returns the commits from this pull request (no commits are returned if this `Issue` is not @@ -810,7 +822,7 @@ impl Issue { loop { let req = client.get(&format!( "{}/pulls/{}/commits?page={page}&per_page=100", - self.repository().url(), + self.repository().url(client), self.number )); @@ -832,7 +844,7 @@ impl Issue { let req = client.get(&format!( "{}/pulls/{}/files", - self.repository().url(), + self.repository().url(client), self.number )); Ok(client.json(req).await?) @@ -1004,11 +1016,8 @@ struct Ordering<'a> { } impl Repository { - const GITHUB_API_URL: &'static str = "https://api.github.com"; - const GITHUB_GRAPHQL_API_URL: &'static str = "https://api.github.com/graphql"; - - fn url(&self) -> String { - format!("{}/repos/{}", Repository::GITHUB_API_URL, self.full_name) + fn url(&self, client: &GithubClient) -> String { + format!("{}/repos/{}", client.api_url, self.full_name) } pub fn owner(&self) -> &str { @@ -1070,11 +1079,17 @@ impl Repository { let mut issues = vec![]; loop { let url = if use_search_api { - self.build_search_issues_url(&filters, include_labels, exclude_labels, ordering) + self.build_search_issues_url( + client, + &filters, + include_labels, + exclude_labels, + ordering, + ) } else if is_pr { - self.build_pulls_url(&filters, include_labels, ordering) + self.build_pulls_url(client, &filters, include_labels, ordering) } else { - self.build_issues_url(&filters, include_labels, ordering) + self.build_issues_url(client, &filters, include_labels, ordering) }; let result = client.get(&url); @@ -1103,24 +1118,27 @@ impl Repository { fn build_issues_url( &self, + client: &GithubClient, filters: &Vec<(&str, &str)>, include_labels: &Vec<&str>, ordering: Ordering<'_>, ) -> String { - self.build_endpoint_url("issues", filters, include_labels, ordering) + self.build_endpoint_url(client, "issues", filters, include_labels, ordering) } fn build_pulls_url( &self, + client: &GithubClient, filters: &Vec<(&str, &str)>, include_labels: &Vec<&str>, ordering: Ordering<'_>, ) -> String { - self.build_endpoint_url("pulls", filters, include_labels, ordering) + self.build_endpoint_url(client, "pulls", filters, include_labels, ordering) } fn build_endpoint_url( &self, + client: &GithubClient, endpoint: &str, filters: &Vec<(&str, &str)>, include_labels: &Vec<&str>, @@ -1143,15 +1161,13 @@ impl Repository { .join("&"); format!( "{}/repos/{}/{}?{}", - Repository::GITHUB_API_URL, - self.full_name, - endpoint, - filters + client.api_url, self.full_name, endpoint, filters ) } fn build_search_issues_url( &self, + client: &GithubClient, filters: &Vec<(&str, &str)>, include_labels: &Vec<&str>, exclude_labels: &Vec<&str>, @@ -1176,7 +1192,7 @@ impl Repository { .join("+"); format!( "{}/search/issues?q={}&sort={}&order={}&per_page={}&page={}", - Repository::GITHUB_API_URL, + client.api_url, filters, ordering.sort, ordering.direction, @@ -1187,7 +1203,7 @@ impl Repository { /// Retrieves a git commit for the given SHA. pub async fn git_commit(&self, client: &GithubClient, sha: &str) -> anyhow::Result { - let url = format!("{}/git/commits/{sha}", self.url()); + let url = format!("{}/git/commits/{sha}", self.url(client)); client .json(client.get(&url)) .await @@ -1202,7 +1218,7 @@ impl Repository { parents: &[&str], tree: &str, ) -> anyhow::Result { - let url = format!("{}/git/commits", self.url()); + let url = format!("{}/git/commits", self.url(client)); client .json(client.post(&url).json(&serde_json::json!({ "message": message, @@ -1213,29 +1229,63 @@ impl Repository { .with_context(|| format!("{} failed to create commit for tree {tree}", self.full_name)) } + /// TODO: encoding should be either "utf-8" or "base64". + pub async fn create_blob( + &self, + client: &GithubClient, + content: &str, + encoding: &str, + ) -> anyhow::Result { + let url = format!("{}/git/blobs", self.url(client)); + let resp: serde_json::Value = client + .json(client.post(&url).json(&serde_json::json!({ + "content": content, + "encoding": encoding, + }))) + .await + .with_context(|| format!("{} failed to create blob", self.full_name))?; + Ok(resp["sha"].as_str().unwrap().to_string()) + } + /// Retrieves a git reference for the given refname. pub async fn get_reference( &self, client: &GithubClient, refname: &str, ) -> anyhow::Result { - let url = format!("{}/git/ref/{}", self.url(), refname); + let url = format!("{}/git/ref/{}", self.url(client), refname); client .json(client.get(&url)) .await .with_context(|| format!("{} failed to get git reference {refname}", self.full_name)) } + pub async fn create_reference( + &self, + client: &GithubClient, + refname: &str, + sha: &str, + ) -> anyhow::Result { + let url = format!("{}/git/refs", self.url(client)); + client + .json(client.post(&url).json(&serde_json::json!({ + "ref": format!("refs/{refname}"), + "sha": sha, + }))) + .await + .with_context(|| format!("{} failed to create reference", self.full_name)) + } + /// Updates an existing git reference to a new SHA. pub async fn update_reference( &self, client: &GithubClient, refname: &str, sha: &str, - ) -> anyhow::Result<()> { - let url = format!("{}/git/refs/{}", self.url(), refname); + ) -> anyhow::Result { + let url = format!("{}/git/refs/{}", self.url(client), refname); client - ._send_req(client.patch(&url).json(&serde_json::json!({ + .json(client.patch(&url).json(&serde_json::json!({ "sha": sha, "force": true, }))) @@ -1245,8 +1295,26 @@ impl Repository { "{} failed to update reference {refname} to {sha}", self.full_name ) - })?; - Ok(()) + }) + } + + pub async fn create_or_update_reference( + &self, + client: &GithubClient, + refname: &str, + sha: &str, + ) -> anyhow::Result { + if let Err(e) = self.get_reference(client, refname).await { + if e.downcast_ref::() + .map_or(false, |e| e.status() == Some(StatusCode::NOT_FOUND)) + { + return self.create_reference(client, refname, sha).await; + } else { + return Err(e); + } + } else { + return self.update_reference(client, refname, sha).await; + } } /// Returns a list of recent commits on the given branch. @@ -1285,7 +1353,7 @@ impl Repository { let query = RecentCommits::build(args.clone()); let data = client .json::>( - client.post(Repository::GITHUB_GRAPHQL_API_URL).json(&query), + client.post(&client.graphql_url).json(&query), ) .await .with_context(|| { @@ -1424,7 +1492,7 @@ impl Repository { base_tree: &str, tree: &[GitTreeEntry], ) -> anyhow::Result { - let url = format!("{}/git/trees", self.url()); + let url = format!("{}/git/trees", self.url(client)); client .json(client.post(&url).json(&serde_json::json!({ "base_tree": base_tree, @@ -1449,7 +1517,7 @@ impl Repository { path: &str, refname: Option<&str>, ) -> anyhow::Result { - let mut url = format!("{}/contents/{}", self.url(), path); + let mut url = format!("{}/contents/{}", self.url(client), path); if let Some(refname) = refname { url.push_str("?ref="); url.push_str(refname); @@ -1471,7 +1539,7 @@ impl Repository { base: &str, body: &str, ) -> anyhow::Result { - let url = format!("{}/pulls", self.url()); + let url = format!("{}/pulls", self.url(client)); let mut issue: Issue = client .json(client.post(&url).json(&serde_json::json!({ "title": title, @@ -1490,11 +1558,48 @@ impl Repository { Ok(issue) } + pub async fn get_prs(&self, client: &GithubClient, + state: &str, + head: Option<&str>, + base: Option<&str>, + sort: Option<&str>, + direction: Option<&str>, + )-> anyhow::Result> { + let mut url = format!("{}/pulls?state={state}", self.url(client)); + if let Some(head) = head { + write!(url, "&head={head}&base={}", base.expect("base must be set if head is set")).unwrap(); + } + if let Some(sort) = sort { + write!(url, "&sort={sort}").unwrap(); + } + if let Some(direction) = direction { + write!(url, "&direction={direction}").unwrap(); + } + let mut issues: Vec = client + .json(client.get(&url)) + .await + .with_context(|| format!("{} failed to get prs", self.full_name))?; + for issue in &mut issues { + issue.pull_request = Some(PullRequestDetails {}); + } + Ok(issues) + } + + pub async fn get_pr(&self, client: &GithubClient, pull_number: u64) -> anyhow::Result { + let url = format!("{}/pulls/{pull_number}", self.url(client)); + let mut issue: Issue = client + .json(client.get(&url)) + .await + .with_context(|| format!("{} failed to get pr {pull_number}", self.full_name))?; + issue.pull_request = Some(PullRequestDetails {}); + Ok(issue) + } + /// Synchronize a branch (in a forked repository) by pulling in its upstream contents. pub async fn merge_upstream(&self, client: &GithubClient, branch: &str) -> anyhow::Result<()> { - let url = format!("{}/merge-upstream", self.url()); + let url = format!("{}/merge-upstream", self.url(client)); client - ._send_req(client.post(&url).json(&serde_json::json!({ + .send_req(client.post(&url).json(&serde_json::json!({ "branch": branch, }))) .await @@ -1506,6 +1611,42 @@ impl Repository { })?; Ok(()) } + + pub async fn has_label(&self, client: &GithubClient, label: &str) -> anyhow::Result { + // TODO merge with IssueRepository + let url = format!("{}/labels/{}", self.url(client), label); + match client.send_req(client.get(&url)).await { + Ok(_) => Ok(true), + Err(e) => { + if e.downcast_ref::() + .map_or(false, |e| e.status() == Some(StatusCode::NOT_FOUND)) + { + Ok(false) + } else { + Err(e) + } + } + } + } + + pub async fn create_label( + &self, + client: &GithubClient, + name: &str, + color: &str, + description: &str, + ) -> anyhow::Result<()> { + let url = format!("{}/labels", self.url(client)); + client + .send_req(client.post(&url).json(&serde_json::json!({ + "name": name, + "color": color, + "description": description, + }))) + .await + .with_context(|| format!("{} failed to create label {name}", self.full_name))?; + Ok(()) + } } pub struct Query<'a> { @@ -1763,15 +1904,32 @@ fn get_token_from_git_config() -> anyhow::Result { pub struct GithubClient { token: String, client: Client, + api_url: String, + graphql_url: String, + raw_url: String, } impl GithubClient { - pub fn new(client: Client, token: String) -> Self { - GithubClient { client, token } + pub fn new(token: String, api_url: String, graphql_url: String, raw_url: String) -> Self { + GithubClient { + client: Client::new(), + token, + api_url, + graphql_url, + raw_url, + } } - pub fn new_with_default_token(client: Client) -> Self { - Self::new(client, default_token_from_env()) + pub fn new_from_env() -> Self { + Self::new( + default_token_from_env(), + std::env::var("GITHUB_API_URL") + .unwrap_or_else(|_| "https://api.github.com".to_string()), + std::env::var("GITHUB_GRAPHQL_API_URL") + .unwrap_or_else(|_| "https://api.github.com/graphql".to_string()), + std::env::var("GITHUB_RAW_URL") + .unwrap_or_else(|_| "https://raw.githubusercontent.com".to_string()), + ) } pub fn raw(&self) -> &Client { @@ -1783,30 +1941,23 @@ impl GithubClient { repo: &str, branch: &str, path: &str, - ) -> anyhow::Result>> { - let url = format!( - "https://raw.githubusercontent.com/{}/{}/{}", - repo, branch, path - ); + ) -> anyhow::Result> { + let url = format!("{}/{repo}/{branch}/{path}", self.raw_url); let req = self.get(&url); let req_dbg = format!("{:?}", req); let req = req .build() .with_context(|| format!("failed to build request {:?}", req_dbg))?; - let mut resp = self.client.execute(req).await.context(req_dbg.clone())?; + let test_capture_info = test_record::capture_request(&req); + let resp = self.client.execute(req).await.context(req_dbg.clone())?; let status = resp.status(); + let body = resp + .bytes() + .await + .with_context(|| format!("failed to read response body {req_dbg}"))?; + test_record::record_request(test_capture_info, status, &body); match status { - StatusCode::OK => { - let mut buf = Vec::with_capacity(resp.content_length().unwrap_or(4) as usize); - while let Some(chunk) = resp.chunk().await.transpose() { - let chunk = chunk - .context("reading stream failed") - .map_err(anyhow::Error::from) - .context(req_dbg.clone())?; - buf.extend_from_slice(&chunk); - } - Ok(Some(buf)) - } + StatusCode::OK => Ok(Some(body)), StatusCode::NOT_FOUND => Ok(None), status => anyhow::bail!("failed to GET {}: {}", url, status), } @@ -1855,8 +2006,8 @@ impl GithubClient { pub async fn rust_commit(&self, sha: &str) -> Option { let req = self.get(&format!( - "https://api.github.com/repos/rust-lang/rust/commits/{}", - sha + "{}/repos/rust-lang/rust/commits/{sha}", + self.api_url )); match self.json(req).await { Ok(r) => Some(r), @@ -1869,7 +2020,10 @@ impl GithubClient { /// This does not retrieve all of them, only the last several. pub async fn bors_commits(&self) -> Vec { - let req = self.get("https://api.github.com/repos/rust-lang/rust/commits?author=bors"); + let req = self.get(&format!( + "{}/repos/rust-lang/rust/commits?author=bors", + self.api_url + )); match self.json(req).await { Ok(r) => r, Err(e) => { @@ -1884,9 +2038,7 @@ impl GithubClient { pub async fn is_new_contributor(&self, repo: &Repository, author: &str) -> bool { let url = format!( "{}/repos/{}/commits?author={}", - Repository::GITHUB_API_URL, - repo.full_name, - author, + self.api_url, repo.full_name, author, ); let req = self.get(&url); match self.json::>(req).await { @@ -1896,7 +2048,7 @@ impl GithubClient { Ok(res) => res.is_empty(), Err(e) => { log::warn!( - "failed to search for user commits in {} for author {author}: {e}", + "failed to search for user commits in {} for author {author}: {e:?}", repo.full_name ); false @@ -1908,7 +2060,7 @@ impl GithubClient { /// /// The `full_name` should be something like `rust-lang/rust`. pub async fn repository(&self, full_name: &str) -> anyhow::Result { - let req = self.get(&format!("{}/repos/{full_name}", Repository::GITHUB_API_URL)); + let req = self.get(&format!("{}/repos/{full_name}", self.api_url)); self.json(req) .await .with_context(|| format!("{} failed to get repo", full_name)) @@ -1953,7 +2105,13 @@ pub struct GitTreeEntry { pub mode: String, #[serde(rename = "type")] pub object_type: String, - pub sha: String, + /// `sha` and `contents` are mutually exclusive. + /// + /// Set `sha` to `Some(None)` to delete a file. + #[serde(skip_serializing_if="Option::is_none")] + pub sha: Option>, + #[serde(skip_serializing_if="Option::is_none")] + pub content: Option, } pub struct RecentCommit { @@ -2007,14 +2165,11 @@ impl IssuesQuery for LeastRecentlyReviewedPullRequests { }; loop { let query = queries::LeastRecentlyReviewedPullRequests::build(args.clone()); - let req = client.post(Repository::GITHUB_GRAPHQL_API_URL); + let req = client.post(&format!("{}/graphql", client.api_url)); let req = req.json(&query); - let (resp, req_dbg) = client._send_req(req).await?; - let data = resp - .json::>() - .await - .context(req_dbg)?; + let data: cynic::GraphQlResponse = + client.json(req).await?; if let Some(errors) = data.errors { anyhow::bail!("There were graphql errors. {:?}", errors); } diff --git a/src/handlers.rs b/src/handlers.rs index da39943b..5578b63b 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -279,7 +279,7 @@ command_handlers! { pub struct Context { pub github: GithubClient, - pub db: crate::db::ClientPool, + pub db: crate::db::Pool, pub username: String, pub octocrab: Octocrab, } diff --git a/src/handlers/docs_update.rs b/src/handlers/docs_update.rs index 1c2d0eb2..e95848b4 100644 --- a/src/handlers/docs_update.rs +++ b/src/handlers/docs_update.rs @@ -5,7 +5,6 @@ use crate::github::{self, GitTreeEntry, GithubClient, Repository}; use anyhow::Context; use anyhow::Result; use cron::Schedule; -use reqwest::Client; use std::fmt::Write; use std::str::FromStr; @@ -60,7 +59,7 @@ pub async fn handle_job() -> Result<()> { } async fn docs_update() -> Result<()> { - let gh = GithubClient::new_with_default_token(Client::new()); + let gh = GithubClient::new_from_env(); let work_repo = gh.repository(WORK_REPO).await?; work_repo .merge_upstream(&gh, &work_repo.default_branch) @@ -169,7 +168,8 @@ async fn create_commit( path: update.path.clone(), mode: "160000".to_string(), object_type: "commit".to_string(), - sha: update.new_hash.clone(), + sha: Some(Some(update.new_hash.clone())), + content: None, }) .collect(); let new_tree = rust_repo diff --git a/src/handlers/github_releases.rs b/src/handlers/github_releases.rs index 745d74fd..0df9b872 100644 --- a/src/handlers/github_releases.rs +++ b/src/handlers/github_releases.rs @@ -132,7 +132,7 @@ async fn load_changelog( .await? .ok_or_else(|| anyhow::Error::msg("missing file"))?; - Ok(String::from_utf8(resp)?) + Ok(String::from_utf8(resp.to_vec())?) } async fn load_paginated(ctx: &Context, url: &str, key: F) -> anyhow::Result> diff --git a/src/handlers/mentions.rs b/src/handlers/mentions.rs index 1c888bea..0e77b0f4 100644 --- a/src/handlers/mentions.rs +++ b/src/handlers/mentions.rs @@ -90,9 +90,11 @@ pub(super) async fn handle_input( event: &IssuesEvent, input: MentionsInput, ) -> anyhow::Result<()> { - let mut client = ctx.db.get().await; + let mut connection = ctx.db.connection().await; + let repo = event.issue.repository().to_string(); + let issue_number = event.issue.number as i32; let mut state: IssueData<'_, MentionState> = - IssueData::load(&mut client, &event.issue, MENTIONS_KEY).await?; + IssueData::load(&mut *connection, repo, issue_number, MENTIONS_KEY).await?; // Build the message to post to the issue. let mut result = String::new(); for to_mention in &input.paths { diff --git a/src/handlers/no_merges.rs b/src/handlers/no_merges.rs index b9ed89ff..14f2b41e 100644 --- a/src/handlers/no_merges.rs +++ b/src/handlers/no_merges.rs @@ -77,9 +77,11 @@ pub(super) async fn handle_input( event: &IssuesEvent, input: NoMergesInput, ) -> anyhow::Result<()> { - let mut client = ctx.db.get().await; - let mut state: IssueData<'_, NoMergesState> = - IssueData::load(&mut client, &event.issue, NO_MERGES_KEY).await?; + let mut connection = ctx.db.connection().await; + let repo = event.issue.repository().to_string(); + let issue_number = event.issue.number as i32; + let mut state: IssueData = + IssueData::load(&mut *connection, repo, issue_number, NO_MERGES_KEY).await?; let since_last_posted = if state.data.mentioned_merge_commits.is_empty() { "" diff --git a/src/handlers/notification.rs b/src/handlers/notification.rs index 718b2b24..87fbd080 100644 --- a/src/handlers/notification.rs +++ b/src/handlers/notification.rs @@ -4,8 +4,8 @@ //! //! Parsing is done in the `parser::command::ping` module. -use crate::db::notifications; use crate::{ + db::notifications::Notification, github::{self, Event}, handlers::Context, }; @@ -93,33 +93,32 @@ pub async fn handle(ctx: &Context, event: &Event) -> anyhow::Result<()> { } }; - let client = ctx.db.get().await; + let mut connection = ctx.db.connection().await; for user in users { if !users_notified.insert(user.id.unwrap()) { // Skip users already associated with this event. continue; } - if let Err(err) = notifications::record_username(&client, user.id.unwrap(), user.login) + if let Err(err) = connection + .record_username(user.id.unwrap(), user.login) .await .context("failed to record username") { log::error!("record username: {:?}", err); } - if let Err(err) = notifications::record_ping( - &client, - ¬ifications::Notification { + if let Err(err) = connection + .record_ping(&Notification { user_id: user.id.unwrap(), origin_url: event.html_url().unwrap().to_owned(), origin_html: body.to_owned(), time: event.time().unwrap(), short_description: Some(short_description.clone()), team_name: team_name.clone(), - }, - ) - .await - .context("failed to record ping") + }) + .await + .context("failed to record ping") { log::error!("record ping: {:?}", err); } diff --git a/src/handlers/rustc_commits.rs b/src/handlers/rustc_commits.rs index 4724bb2b..91c59386 100644 --- a/src/handlers/rustc_commits.rs +++ b/src/handlers/rustc_commits.rs @@ -1,6 +1,5 @@ use crate::db::jobs::JobSchedule; -use crate::db::rustc_commits; -use crate::db::rustc_commits::get_missing_commits; +use crate::db::Commit; use crate::{ github::{self, Event}, handlers::Context, @@ -87,7 +86,7 @@ async fn synchronize_commits(ctx: &Context, sha: &str, pr: u32) { } pub async fn synchronize_commits_inner(ctx: &Context, starter: Option<(String, u32)>) { - let db = ctx.db.get().await; + let mut connection = ctx.db.connection().await; // List of roots to be resolved. Each root and its parents will be recursively resolved // until an existing commit is found. @@ -96,14 +95,15 @@ pub async fn synchronize_commits_inner(ctx: &Context, starter: Option<(String, u to_be_resolved.push_back((sha.to_string(), Some(pr))); } to_be_resolved.extend( - get_missing_commits(&db) + connection + .get_missing_commits() .await + .unwrap() .into_iter() .map(|c| (c, None::)), ); log::info!("synchronize_commits for {:?}", to_be_resolved); - let db = ctx.db.get().await; while let Some((sha, mut pr)) = to_be_resolved.pop_front() { let mut gc = match ctx.github.rust_commit(&sha).await { Some(c) => c, @@ -132,19 +132,17 @@ pub async fn synchronize_commits_inner(ctx: &Context, starter: Option<(String, u } }; - let res = rustc_commits::record_commit( - &db, - rustc_commits::Commit { + let res = connection + .record_commit(&Commit { sha: gc.sha, parent_sha: parent_sha.clone(), time: gc.commit.author.date, pr: Some(pr), - }, - ) - .await; + }) + .await; match res { Ok(()) => { - if !rustc_commits::has_commit(&db, &parent_sha).await { + if !connection.has_commit(&parent_sha).await.unwrap() { to_be_resolved.push_back((parent_sha, None)) } } diff --git a/src/lib.rs b/src/lib.rs index aafa5eea..40e5da1c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,6 +26,7 @@ pub mod payload; pub mod rfcbot; pub mod team; mod team_data; +pub mod test_record; pub mod triage; pub mod zulip; diff --git a/src/main.rs b/src/main.rs index d119e3c9..8c026bc8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,6 @@ use anyhow::Context as _; use futures::future::FutureExt; use futures::StreamExt; use hyper::{header, Body, Request, Response, Server, StatusCode}; -use reqwest::Client; use route_recognizer::Router; use std::{env, net::SocketAddr, sync::Arc}; use tokio::{task, time}; @@ -83,7 +82,8 @@ async fn serve_req( .unwrap()); } if req.uri.path() == "/bors-commit-list" { - let res = db::rustc_commits::get_commits_with_artifacts(&*ctx.db.get().await).await; + let mut connection = ctx.db.connection().await; + let res = connection.get_commits_with_artifacts().await; let res = match res { Ok(r) => r, Err(e) => { @@ -103,10 +103,11 @@ async fn serve_req( if let Some(query) = req.uri.query() { let user = url::form_urlencoded::parse(query.as_bytes()).find(|(k, _)| k == "user"); if let Some((_, name)) = user { + let mut connection = ctx.db.connection().await; return Ok(Response::builder() .status(StatusCode::OK) .body(Body::from( - notification_listing::render(&ctx.db.get().await, &*name).await, + notification_listing::render(&mut *connection, &*name).await, )) .unwrap()); } @@ -219,6 +220,7 @@ async fn serve_req( .unwrap()); } }; + triagebot::test_record::record_event(&event, &payload); match triagebot::webhook(event, payload, &ctx).await { Ok(true) => Ok(Response::new(Body::from("processed request"))), @@ -234,41 +236,9 @@ async fn serve_req( } async fn run_server(addr: SocketAddr) -> anyhow::Result<()> { - let pool = db::ClientPool::new(); - db::run_migrations(&*pool.get().await) - .await - .context("database migrations")?; + let pool = db::Pool::new_from_env(); - // spawning a background task that will schedule the jobs - // every JOB_SCHEDULING_CADENCE_IN_SECS - task::spawn(async move { - loop { - let res = task::spawn(async move { - let pool = db::ClientPool::new(); - let mut interval = - time::interval(time::Duration::from_secs(JOB_SCHEDULING_CADENCE_IN_SECS)); - - loop { - interval.tick().await; - db::schedule_jobs(&*pool.get().await, jobs()) - .await - .context("database schedule jobs") - .unwrap(); - } - }); - - match res.await { - Err(err) if err.is_panic() => { - /* handle panic in above task, re-launching */ - tracing::trace!("schedule_jobs task died (error={})", err); - } - _ => unreachable!(), - } - } - }); - - let client = Client::new(); - let gh = github::GithubClient::new_with_default_token(client.clone()); + let gh = github::GithubClient::new_from_env(); let oc = octocrab::OctocrabBuilder::new() .personal_token(github::default_token_from_env()) .build() @@ -280,35 +250,10 @@ async fn run_server(addr: SocketAddr) -> anyhow::Result<()> { octocrab: oc, }); - // spawning a background task that will run the scheduled jobs - // every JOB_PROCESSING_CADENCE_IN_SECS - let ctx2 = ctx.clone(); - task::spawn(async move { - loop { - let ctx = ctx2.clone(); - let res = task::spawn(async move { - let pool = db::ClientPool::new(); - let mut interval = - time::interval(time::Duration::from_secs(JOB_PROCESSING_CADENCE_IN_SECS)); - - loop { - interval.tick().await; - db::run_scheduled_jobs(&ctx, &*pool.get().await) - .await - .context("run database scheduled jobs") - .unwrap(); - } - }); - - match res.await { - Err(err) if err.is_panic() => { - /* handle panic in above task, re-launching */ - tracing::trace!("run_scheduled_jobs task died (error={})", err); - } - _ => unreachable!(), - } - } - }); + if !is_scheduled_jobs_disabled() { + spawn_job_scheduler(); + spawn_job_runner(ctx.clone()); + } let agenda = tower::ServiceBuilder::new() .buffer(10) @@ -351,6 +296,89 @@ async fn run_server(addr: SocketAddr) -> anyhow::Result<()> { Ok(()) } +/// Spawns a background tokio task which runs continuously to queue up jobs +/// to be run by the job runner. +/// +/// The scheduler wakes up every `JOB_SCHEDULING_CADENCE_IN_SECS` seconds to +/// check if there are any jobs ready to run. Jobs get inserted into the the +/// database which acts as a queue. +fn spawn_job_scheduler() { + task::spawn(async move { + loop { + let res = task::spawn(async move { + let pool = db::Pool::new_from_env(); + let mut interval = + time::interval(time::Duration::from_secs(JOB_SCHEDULING_CADENCE_IN_SECS)); + + loop { + interval.tick().await; + let mut connection = pool.connection().await; + db::jobs::schedule_jobs(&mut *connection, jobs()) + .await + .context("database schedule jobs") + .unwrap(); + } + }); + + match res.await { + Err(err) if err.is_panic() => { + /* handle panic in above task, re-launching */ + tracing::error!("schedule_jobs task died (error={})", err); + tokio::time::sleep(std::time::Duration::new(5, 0)).await; + } + _ => unreachable!(), + } + } + }); +} + +/// Spawns a background tokio task which runs continuously to run scheduled +/// jobs. +/// +/// The runner wakes up every `JOB_PROCESSING_CADENCE_IN_SECS` seconds to +/// check if any jobs have been put into the queue by the scheduler. They +/// will get popped off the queue and run if any are found. +fn spawn_job_runner(ctx: Arc) { + task::spawn(async move { + loop { + let ctx = ctx.clone(); + let res = task::spawn(async move { + let pool = db::Pool::new_from_env(); + let mut interval = + time::interval(time::Duration::from_secs(JOB_PROCESSING_CADENCE_IN_SECS)); + + loop { + interval.tick().await; + let mut connection = pool.connection().await; + db::jobs::run_scheduled_jobs(&ctx, &mut *connection) + .await + .context("run database scheduled jobs") + .unwrap(); + } + }); + + match res.await { + Err(err) if err.is_panic() => { + /* handle panic in above task, re-launching */ + tracing::error!("run_scheduled_jobs task died (error={})", err); + tokio::time::sleep(std::time::Duration::new(5, 0)).await; + } + _ => unreachable!(), + } + } + }); +} + +/// Determines whether or not background scheduled jobs should be disabled for +/// the purpose of testing. +/// +/// This helps avoid having random jobs run while testing other things. +fn is_scheduled_jobs_disabled() -> bool { + // TRIAGEBOT_TEST_DISABLE_JOBS is set automatically by the test runner, + // and shouldn't be needed to be set manually. + env::var_os("TRIAGEBOT_TEST_DISABLE_JOBS").is_some() || triagebot::test_record::is_recording() +} + #[tokio::main(flavor = "current_thread")] async fn main() { dotenv::dotenv().ok(); @@ -359,6 +387,7 @@ async fn main() { .with_ansi(std::env::var_os("DISABLE_COLOR").is_none()) .try_init() .unwrap(); + triagebot::test_record::init().unwrap(); let port = env::var("PORT") .ok() diff --git a/src/notification_listing.rs b/src/notification_listing.rs index 033fc9b3..d827a8b2 100644 --- a/src/notification_listing.rs +++ b/src/notification_listing.rs @@ -1,7 +1,5 @@ -use crate::db::notifications::get_notifications; - -pub async fn render(db: &crate::db::PooledClient, user: &str) -> String { - let notifications = match get_notifications(db, user).await { +pub async fn render(connection: &mut dyn crate::db::Connection, user: &str) -> String { + let notifications = match connection.get_notifications(user).await { Ok(n) => n, Err(e) => { return format!("{:?}", e.context("getting notifications")); diff --git a/src/payload.rs b/src/payload.rs index f05e13a1..bd2f73f3 100644 --- a/src/payload.rs +++ b/src/payload.rs @@ -12,6 +12,13 @@ impl fmt::Display for SignedPayloadError { impl std::error::Error for SignedPayloadError {} +pub fn sign(secret: &str, payload: &[u8]) -> Vec { + let key = PKey::hmac(secret.as_bytes()).unwrap(); + let mut signer = Signer::new(MessageDigest::sha1(), &key).unwrap(); + signer.update(&payload).unwrap(); + signer.sign_to_vec().unwrap() +} + pub fn assert_signed(signature: &str, payload: &[u8]) -> Result<(), SignedPayloadError> { let signature = signature.get("sha1=".len()..).ok_or(SignedPayloadError)?; let signature = match hex::decode(&signature) { @@ -22,15 +29,8 @@ pub fn assert_signed(signature: &str, payload: &[u8]) -> Result<(), SignedPayloa } }; - let key = PKey::hmac( - std::env::var("GITHUB_WEBHOOK_SECRET") - .expect("Missing GITHUB_WEBHOOK_SECRET") - .as_bytes(), - ) - .unwrap(); - let mut signer = Signer::new(MessageDigest::sha1(), &key).unwrap(); - signer.update(&payload).unwrap(); - let hmac = signer.sign_to_vec().unwrap(); + let secret = std::env::var("GITHUB_WEBHOOK_SECRET").expect("Missing GITHUB_WEBHOOK_SECRET"); + let hmac = sign(&secret, payload); if !memcmp::eq(&hmac, &signature) { return Err(SignedPayloadError); diff --git a/src/team_data.rs b/src/team_data.rs index 4f7e1b15..d58ff408 100644 --- a/src/team_data.rs +++ b/src/team_data.rs @@ -4,7 +4,8 @@ use rust_team_data::v1::{Teams, ZulipMapping, BASE_URL}; use serde::de::DeserializeOwned; async fn by_url(client: &GithubClient, path: &str) -> anyhow::Result { - let url = format!("{}{}", BASE_URL, path); + let base = std::env::var("TEAMS_API_URL").unwrap_or(BASE_URL.to_string()); + let url = format!("{}{}", base, path); for _ in 0i32..3 { let map: Result = client.json(client.raw().get(&url)).await; match map { diff --git a/src/test_record.rs b/src/test_record.rs new file mode 100644 index 00000000..08d79a14 --- /dev/null +++ b/src/test_record.rs @@ -0,0 +1,237 @@ +//! Support for recording network activity for test playback. +//! +//! See `testsuite.rs` for more information on test recording. + +use crate::EventName; +use anyhow::Context; +use anyhow::Result; +use reqwest::{Request, StatusCode}; +use serde::{Deserialize, Serialize}; +use std::fs::{self, File}; +use std::io::BufWriter; +use std::path::Path; +use std::path::PathBuf; +use std::sync::atomic::{AtomicU32, Ordering}; +use tracing::{error, info, warn}; + +/// A representation of the recording of activity of triagebot. +/// +/// Activities are stored as JSON on disk. The test framework injects the +/// `Webhook` and then checks for the appropriate requests and sends the +/// recorded responses. +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "kind")] +pub enum Activity { + /// A webhook event received from GitHub. + Webhook { + webhook_event: String, + payload: serde_json::Value, + }, + /// An outgoing request to api.github.com or raw.githubusercontent.com, and its response. + Request { + method: String, + path: String, + query: Option, + request_body: String, + response_code: u16, + /// The body of the response. + /// + /// For non-JSON requests, it is encoded as a `Value::String` under + /// the assumption that GitHub never returns a JSON string for a + /// response. This is done so that the JSON bodies can be formatted + /// nicely in the `.json` bodies to make inspecting them easier. + response_body: serde_json::Value, + }, + /// Sent by the mock HTTP server to the test framework when it detects + /// something is wrong. + Error { message: String }, + /// Sent by the mock HTTP server to the test framework to tell it that all + /// activities have been processed. + Finished, +} + +/// Information about an HTTP request that is captured before sending. +/// +/// This is needed to avoid messing with cloning the Request. +#[derive(Debug)] +pub struct RequestInfo { + method: String, + path: String, + query: Option, + body: String, +} + +/// Returns whether or not TRIAGEBOT_TEST_RECORD_DIR has been set to enable +/// recording. +pub fn is_recording() -> bool { + record_dir().is_some() +} + +/// The directory where the JSON recordings should be stored. +/// +/// Returns `None` if recording is disabled. +fn record_dir() -> Option { + let test_record = std::env::var("TRIAGEBOT_TEST_RECORD_DIR").ok()?; + let mut record_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + record_dir.push("tests"); + record_dir.push(test_record); + Some(record_dir) +} + +pub fn record_live_repo() -> Option { + std::env::var("TRIAGEBOT_TEST_LIVE_REPO").ok() +} + +fn next_sequence() -> u32 { + static NEXT_ID: AtomicU32 = AtomicU32::new(0); + NEXT_ID.fetch_add(1, Ordering::SeqCst) +} + +/// Initializes the test recording system. +/// +/// This sets up the directory where JSON files are stored if the +/// `TRIAGEBOT_TEST_RECORD_DIR` environment variable is set. +pub fn init() -> Result<()> { + let Some(record_dir) = record_dir() else { return Ok(()) }; + fs::create_dir_all(&record_dir) + .with_context(|| format!("failed to create recording directory {record_dir:?}"))?; + // Clear any old recording data. + for entry in fs::read_dir(&record_dir)? { + let entry = entry?; + let path = entry.path(); + if path.extension().and_then(|p| p.to_str()) == Some("json") { + warn!("deleting old recording at {path:?}"); + fs::remove_file(&path) + .with_context(|| format!("failed to remove old recording {path:?}"))?; + } + } + Ok(()) +} + +/// Records a webhook event for the test framework. +/// +/// The recording is only saved if the `TRIAGEBOT_TEST_RECORD_DIR` environment +/// variable is set. +pub fn record_event(event: &EventName, payload: &str) { + let Some(record_dir) = record_dir() else { return }; + + let payload_json: serde_json::Value = serde_json::from_str(payload).expect("valid json"); + let name = match event { + EventName::PullRequest => { + let action = payload_json["action"].as_str().unwrap(); + let number = payload_json["number"].as_u64().unwrap(); + format!("pr{number}_{action}") + } + EventName::PullRequestReview => { + let action = payload_json["action"].as_str().unwrap(); + let number = payload_json["pull_request"]["number"].as_u64().unwrap(); + format!("pr{number}_review_{action}") + } + EventName::PullRequestReviewComment => { + let action = payload_json["action"].as_str().unwrap(); + let number = payload_json["pull_request"]["number"].as_u64().unwrap(); + format!("pr{number}_review_comment_{action}") + } + EventName::IssueComment => { + let action = payload_json["action"].as_str().unwrap(); + let number = payload_json["issue"]["number"].as_u64().unwrap(); + format!("issue{number}_comment_{action}") + } + EventName::Issue => { + let action = payload_json["action"].as_str().unwrap(); + let number = payload_json["issue"]["number"].as_u64().unwrap(); + format!("issue{number}_{action}") + } + EventName::Push => { + let after = payload_json["after"].as_str().unwrap(); + format!("push_{after}") + } + EventName::Create => { + let ref_type = payload_json["ref_type"].as_str().unwrap(); + let git_ref = payload_json["ref"].as_str().unwrap(); + format!("create_{ref_type}_{git_ref}") + } + EventName::Other => { + return; + } + }; + let activity = Activity::Webhook { + webhook_event: event.to_string(), + payload: payload_json, + }; + let filename = format!("{:02}-webhook-{name}.json", next_sequence()); + save_activity(&record_dir.join(filename), &activity); +} + +/// Captures information about a Request to be used for a test recording. +/// +/// This value is passed to `record_request` after the request has been sent. +pub fn capture_request(req: &Request) -> Option { + if !is_recording() { + return None; + } + let url = req.url(); + let body = req + .body() + .and_then(|body| body.as_bytes()) + .map(|bytes| String::from_utf8(bytes.to_vec()).unwrap()) + .unwrap_or_default(); + let info = RequestInfo { + method: req.method().to_string(), + path: url.path().to_string(), + query: url.query().map(|q| q.to_string()), + body, + }; + Some(info) +} + +/// Records an HTTP request and response for the test framework. +/// +/// The recording is only saved if the `TRIAGEBOT_TEST_RECORD_DIR` environment +/// variable is set. +pub fn record_request(info: Option, status: StatusCode, body: &[u8]) { + let Some(info) = info else { return }; + let Some(record_dir) = record_dir() else { return }; + let response_code = status.as_u16(); + let mut munged_path = info.path.replace(['/', '.'], "_"); + if munged_path.starts_with('_') { + munged_path.remove(0); + } + let name = format!("{}-{}", info.method, munged_path); + // This is a hack to reduce the amount of data stored in the test + // directory. This file gets requested many times, and it is very + // large. + let response_body = if info.path == "/v1/teams.json" { + serde_json::json!(null) + } else { + match serde_json::from_slice(body) { + Ok(json) => json, + Err(_) => serde_json::Value::String(String::from_utf8_lossy(body).to_string()), + } + }; + let activity = Activity::Request { + method: info.method, + path: info.path, + query: info.query, + request_body: info.body, + response_code, + response_body, + }; + + let filename = format!("{:02}-{name}.json", next_sequence()); + save_activity(&record_dir.join(filename), &activity); +} + +/// Helper for saving an [`Activity`] to disk as JSON. +fn save_activity(path: &Path, activity: &Activity) { + let save_activity_inner = || -> Result<()> { + let file = File::create(path)?; + let file = BufWriter::new(file); + serde_json::to_writer_pretty(file, &activity)?; + Ok(()) + }; + if let Err(e) = save_activity_inner() { + error!("failed to save test activity {path:?}: {e:?}"); + }; + info!("test activity saved to {path:?}"); +} diff --git a/src/zulip.rs b/src/zulip.rs index 5f943982..c2ef621b 100644 --- a/src/zulip.rs +++ b/src/zulip.rs @@ -1,5 +1,4 @@ -use crate::db::notifications::add_metadata; -use crate::db::notifications::{self, delete_ping, move_indices, record_ping, Identifier}; +use crate::db::notifications::{Identifier, Notification}; use crate::github::{self, GithubClient}; use crate::handlers::Context; use anyhow::Context as _; @@ -548,8 +547,8 @@ async fn acknowledge( } else { Identifier::Url(filter) }; - let mut db = ctx.db.get().await; - match delete_ping(&mut *db, gh_id, ident).await { + let mut connection = ctx.db.connection().await; + match connection.delete_ping(gh_id, ident).await { Ok(deleted) => { let resp = if deleted.is_empty() { format!( @@ -603,18 +602,17 @@ async fn add_notification( assert_eq!(description.pop(), Some(' ')); // pop trailing space Some(description) }; - match record_ping( - &*ctx.db.get().await, - ¬ifications::Notification { + let mut connection = ctx.db.connection().await; + match connection + .record_ping(&Notification { user_id: gh_id, origin_url: url.to_owned(), origin_html: String::new(), short_description: description, time: chrono::Utc::now().into(), team_name: None, - }, - ) - .await + }) + .await { Ok(()) => Ok(serde_json::to_string(&Response { content: "Created!", @@ -652,8 +650,11 @@ async fn add_meta_notification( assert_eq!(description.pop(), Some(' ')); // pop trailing space Some(description) }; - let mut db = ctx.db.get().await; - match add_metadata(&mut db, gh_id, idx, description.as_deref()).await { + let mut connection = ctx.db.connection().await; + match connection + .add_metadata(gh_id, idx, description.as_deref()) + .await + { Ok(()) => Ok(serde_json::to_string(&Response { content: "Added metadata!", }) @@ -688,7 +689,8 @@ async fn move_notification( .context("to index")? .checked_sub(1) .ok_or_else(|| anyhow::anyhow!("1-based indexes"))?; - match move_indices(&mut *ctx.db.get().await, gh_id, from, to).await { + let mut connection = ctx.db.connection().await; + match connection.move_indices(gh_id, from, to).await { Ok(()) => Ok(serde_json::to_string(&Response { // to 1-base indices content: &format!("Moved {} to {}.", from + 1, to + 1), diff --git a/tests/db/issue_data.rs b/tests/db/issue_data.rs new file mode 100644 index 00000000..26e47099 --- /dev/null +++ b/tests/db/issue_data.rs @@ -0,0 +1,30 @@ +use super::run_test; +use serde::{Deserialize, Serialize}; +use triagebot::db::issue_data::IssueData; + +#[derive(Serialize, Deserialize, Default, Debug)] +struct MyData { + f1: String, + f2: u32, +} + +#[test] +fn issue_data() { + run_test(|mut connection| async move { + let repo = "rust-lang/rust".to_string(); + let mut id: IssueData = + IssueData::load(&mut *connection, repo.clone(), 1234, "test") + .await + .unwrap(); + assert_eq!(id.data.f1, ""); + assert_eq!(id.data.f2, 0); + id.data.f1 = "new data".to_string(); + id.data.f2 = 1; + id.save().await.unwrap(); + let id: IssueData = IssueData::load(&mut *connection, repo.clone(), 1234, "test") + .await + .unwrap(); + assert_eq!(id.data.f1, "new data"); + assert_eq!(id.data.f2, 1); + }); +} diff --git a/tests/db/jobs.rs b/tests/db/jobs.rs new file mode 100644 index 00000000..a2941063 --- /dev/null +++ b/tests/db/jobs.rs @@ -0,0 +1,113 @@ +use super::run_test; +use crate::assert_datetime_approx_equal; +use serde_json::json; + +#[test] +fn jobs() { + run_test(|mut connection| async move { + // Create some jobs and check that ones scheduled in the past are returned. + let past = chrono::Utc::now() - chrono::Duration::minutes(5); + let future = chrono::Utc::now() + chrono::Duration::hours(1); + connection + .insert_job("sample_job1", &past, &json! {{"foo": 123}}) + .await + .unwrap(); + connection + .insert_job("sample_job2", &past, &json! {{}}) + .await + .unwrap(); + connection + .insert_job("sample_job1", &future, &json! {{}}) + .await + .unwrap(); + let jobs = connection.get_jobs_to_execute().await.unwrap(); + assert_eq!(jobs.len(), 2); + assert_eq!(jobs[0].name, "sample_job1"); + assert_datetime_approx_equal(&jobs[0].scheduled_at, &past); + assert_eq!(jobs[0].metadata, json! {{"foo": 123}}); + assert_eq!(jobs[0].executed_at, None); + assert_eq!(jobs[0].error_message, None); + + assert_eq!(jobs[1].name, "sample_job2"); + assert_datetime_approx_equal(&jobs[1].scheduled_at, &past); + assert_eq!(jobs[1].metadata, json! {{}}); + assert_eq!(jobs[1].executed_at, None); + assert_eq!(jobs[1].error_message, None); + + // Get job by name + let job = connection + .get_job_by_name_and_scheduled_at("sample_job1", &future) + .await + .unwrap(); + assert_eq!(job.metadata, json! {{}}); + assert_eq!(job.error_message, None); + + // Update error message + connection + .update_job_error_message(&job.id, "an error") + .await + .unwrap(); + let job = connection + .get_job_by_name_and_scheduled_at("sample_job1", &future) + .await + .unwrap(); + assert_eq!(job.error_message.as_deref(), Some("an error")); + + // Delete job + let job = connection + .get_job_by_name_and_scheduled_at("sample_job1", &past) + .await + .unwrap(); + connection.delete_job(&job.id).await.unwrap(); + let jobs = connection.get_jobs_to_execute().await.unwrap(); + assert_eq!(jobs.len(), 1); + assert_eq!(jobs[0].name, "sample_job2"); + }); +} + +#[test] +fn on_conflict() { + // Verify that inserting a job with different data updates the data. + run_test(|mut connection| async move { + let past = chrono::Utc::now() - chrono::Duration::minutes(5); + connection + .insert_job("sample_job1", &past, &json! {{"foo": 123}}) + .await + .unwrap(); + connection + .insert_job("sample_job1", &past, &json! {{"foo": 456}}) + .await + .unwrap(); + let job = connection + .get_job_by_name_and_scheduled_at("sample_job1", &past) + .await + .unwrap(); + assert_eq!(job.metadata, json! {{"foo": 456}}); + }); +} + +#[test] +fn update_job_executed_at() { + run_test(|mut connection| async move { + let now = chrono::Utc::now(); + let past = now - chrono::Duration::minutes(5); + connection + .insert_job("sample_job1", &past, &json! {{"foo": 123}}) + .await + .unwrap(); + let jobs = connection.get_jobs_to_execute().await.unwrap(); + assert_eq!(jobs.len(), 1); + assert_eq!(jobs[0].executed_at, None); + connection + .update_job_executed_at(&jobs[0].id) + .await + .unwrap(); + let jobs = connection.get_jobs_to_execute().await.unwrap(); + assert_eq!(jobs.len(), 1); + let executed_at = jobs[0].executed_at.expect("executed_at should be set"); + // The timestamp should be approximately "now". + if executed_at - now > chrono::Duration::minutes(1) { + panic!("executed_at timestamp unexpected {executed_at:?} vs {now:?}"); + } + }); +} diff --git a/tests/db/mod.rs b/tests/db/mod.rs new file mode 100644 index 00000000..ef2dffd0 --- /dev/null +++ b/tests/db/mod.rs @@ -0,0 +1,208 @@ +//! Tests for the database API. +//! +//! These tests help verify the database interaction. The [`run_test`] +//! function helps set up the database and gives your callback a connection to +//! interact with. The general form of a test is: +//! +//! ```rust +//! #[test] +//! fn example() { +//! run_test(|mut connection| async move { +//! // Call methods on `connection` and verify its behavior. +//! }); +//! } +//! ``` +//! +//! The `run_test` function will run your test on both SQLite and Postgres (if +//! it is installed). + +use futures::Future; +use std::path::{Path, PathBuf}; +use std::process::Command; +use triagebot::db::{Connection, Pool}; + +mod issue_data; +mod jobs; +mod notification; +mod rustc_commits; + +struct PgContext { + db_dir: PathBuf, + pool: Pool, +} + +impl PgContext { + fn new(db_dir: PathBuf) -> PgContext { + let database_url = postgres_database_url(&db_dir); + let pool = Pool::open(&database_url); + PgContext { db_dir, pool } + } +} + +impl Drop for PgContext { + fn drop(&mut self) { + stop_postgres(&self.db_dir); + } +} + +struct SqliteContext { + pool: Pool, +} + +impl SqliteContext { + fn new() -> SqliteContext { + let db_path = super::test_dir().join("triagebot.sqlite3"); + let pool = Pool::open(db_path.to_str().unwrap()); + SqliteContext { pool } + } +} + +fn run_test(f: F) +where + F: Fn(Box) -> Fut + Send + Sync + 'static, + Fut: Future + Send, +{ + // Only run postgres if postgres can be found or on CI. + if let Some(db_dir) = setup_postgres() { + eprintln!("testing Postgres"); + let ctx = PgContext::new(db_dir); + tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap() + .block_on(async { f(ctx.pool.connection().await).await }); + } else if std::env::var_os("CI").is_some() { + panic!("postgres must be installed in CI"); + } + + eprintln!("\n\ntesting Sqlite"); + let ctx = SqliteContext::new(); + tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap() + .block_on(async { f(ctx.pool.connection().await).await }); +} + +pub fn postgres_database_url(db_dir: &PathBuf) -> String { + format!( + "postgres:///triagebot?user=triagebot&host={}", + db_dir.display() + ) +} + +pub fn setup_postgres() -> Option { + let pg_dir = find_postgres()?; + // Set up a directory where this test can store all its stuff. + let test_dir = super::test_dir(); + let db_dir = test_dir.join("db"); + + std::fs::create_dir(&db_dir).unwrap(); + let db_dir_str = db_dir.to_str().unwrap(); + run_command( + &pg_dir.join("initdb"), + &["--auth=trust", "--username=triagebot", "-D", db_dir_str], + &db_dir, + ); + run_command( + &pg_dir.join("pg_ctl"), + &[ + // -h '' tells it to not listen on TCP + // -k tells it where to place the unix-domain socket + "-o", + &format!("-h '' -k {db_dir_str}"), + // -D is the data dir where everything is stored + "-D", + db_dir_str, + // -l enables logging to a file instead of stdout + "-l", + db_dir.join("postgres.log").to_str().unwrap(), + "start", + ], + &db_dir, + ); + run_command( + &pg_dir.join("createdb"), + &["--user", "triagebot", "-h", db_dir_str, "triagebot"], + &db_dir, + ); + Some(db_dir) +} + +pub fn stop_postgres(db_dir: &Path) { + // Shut down postgres. + let pg_dir = find_postgres().unwrap(); + match Command::new(pg_dir.join("pg_ctl")) + .args(&["-D", db_dir.to_str().unwrap(), "stop"]) + .output() + { + Ok(output) => { + if !output.status.success() { + eprintln!( + "failed to stop postgres:\n\ + ---stdout\n\ + {}\n\ + ---stderr\n\ + {}\n\ + ", + std::str::from_utf8(&output.stdout).unwrap(), + std::str::from_utf8(&output.stderr).unwrap() + ); + } + } + Err(e) => eprintln!("could not run pg_ctl to stop: {e}"), + } +} + +/// Finds the root for PostgreSQL commands. +/// +/// For various reasons, some Linux distros hide some postgres commands and +/// don't put them on PATH, making them difficult to access. +fn find_postgres() -> Option { + // Check if on PATH first. + if let Ok(o) = Command::new("initdb").arg("-V").output() { + if o.status.success() { + return Some(PathBuf::new()); + } + } + if let Ok(dirs) = std::fs::read_dir("/usr/lib/postgresql") { + let mut versions: Vec<_> = dirs + .filter_map(|entry| { + let entry = entry.unwrap(); + // Versions are generally of the form 9.3 or 14, but this + // might be broken if other forms are used. + if let Ok(n) = entry.file_name().to_str().unwrap().parse::() { + Some((n, entry.path())) + } else { + None + } + }) + .collect(); + if !versions.is_empty() { + versions.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap()); + return Some(versions.last().unwrap().1.join("bin")); + } + } + None +} + +fn run_command(command: &Path, args: &[&str], cwd: &Path) { + eprintln!("running {command:?}: {args:?}"); + let output = Command::new(command) + .args(args) + .current_dir(cwd) + .output() + .unwrap_or_else(|e| panic!("`{command:?}` failed to run: {e}")); + if !output.status.success() { + panic!( + "{command:?} failed:\n\ + ---stdout\n\ + {}\n\ + ---stderr\n\ + {}\n\ + ", + std::str::from_utf8(&output.stdout).unwrap(), + std::str::from_utf8(&output.stderr).unwrap() + ); + } +} diff --git a/tests/db/notification.rs b/tests/db/notification.rs new file mode 100644 index 00000000..8edd986b --- /dev/null +++ b/tests/db/notification.rs @@ -0,0 +1,261 @@ +use super::run_test; +use crate::assert_datetime_approx_equal; +use std::num::NonZeroUsize; +use triagebot::db::notifications::{Identifier, Notification}; + +#[test] +fn notification() { + run_test(|mut connection| async move { + let now = chrono::Utc::now(); + connection + .record_username(43198, "ehuss".to_string()) + .await + .unwrap(); + connection + .record_username(14314532, "weihanglo".to_string()) + .await + .unwrap(); + connection + .record_ping(&Notification { + user_id: 43198, + origin_url: "https://github.com/rust-lang/rust/issues/1".to_string(), + origin_html: "This comment mentions @ehuss.".to_string(), + short_description: Some("Comment on some issue".to_string()), + time: now.into(), + team_name: None, + }) + .await + .unwrap(); + + connection + .record_ping(&Notification { + user_id: 43198, + origin_url: "https://github.com/rust-lang/rust/issues/2".to_string(), + origin_html: "This comment mentions @rust-lang/cargo.".to_string(), + short_description: Some("Comment on some issue".to_string()), + time: now.into(), + team_name: Some("cargo".to_string()), + }) + .await + .unwrap(); + connection + .record_ping(&Notification { + user_id: 14314532, + origin_url: "https://github.com/rust-lang/rust/issues/2".to_string(), + origin_html: "This comment mentions @rust-lang/cargo.".to_string(), + short_description: Some("Comment on some issue".to_string()), + time: now.into(), + team_name: Some("cargo".to_string()), + }) + .await + .unwrap(); + + let notifications = connection.get_notifications("ehuss").await.unwrap(); + assert_eq!(notifications.len(), 2); + assert_eq!( + notifications[0].origin_url, + "https://github.com/rust-lang/rust/issues/1" + ); + assert_eq!( + notifications[0].origin_text, + "This comment mentions @ehuss." + ); + assert_eq!( + notifications[0].short_description.as_deref(), + Some("Comment on some issue") + ); + assert_datetime_approx_equal(¬ifications[0].time, &now); + assert_eq!(notifications[0].metadata, None); + + assert_eq!( + notifications[1].origin_url, + "https://github.com/rust-lang/rust/issues/2" + ); + assert_eq!( + notifications[1].origin_text, + "This comment mentions @rust-lang/cargo." + ); + assert_eq!( + notifications[1].short_description.as_deref(), + Some("Comment on some issue") + ); + assert_datetime_approx_equal(¬ifications[1].time, &now); + assert_eq!(notifications[1].metadata, None); + + let notifications = connection.get_notifications("weihanglo").await.unwrap(); + assert_eq!(notifications.len(), 1); + assert_eq!( + notifications[0].origin_url, + "https://github.com/rust-lang/rust/issues/2" + ); + assert_eq!( + notifications[0].origin_text, + "This comment mentions @rust-lang/cargo." + ); + assert_eq!( + notifications[0].short_description.as_deref(), + Some("Comment on some issue") + ); + assert_datetime_approx_equal(¬ifications[0].time, &now); + assert_eq!(notifications[0].metadata, None); + + let notifications = connection.get_notifications("octocat").await.unwrap(); + assert_eq!(notifications.len(), 0); + }); +} + +#[test] +fn delete_ping() { + run_test(|mut connection| async move { + connection + .record_username(43198, "ehuss".to_string()) + .await + .unwrap(); + let now = chrono::Utc::now(); + for x in 1..4 { + connection + .record_ping(&Notification { + user_id: 43198, + origin_url: x.to_string(), + origin_html: "@ehuss {n}".to_string(), + short_description: Some("Comment on some issue".to_string()), + time: now.into(), + team_name: None, + }) + .await + .unwrap(); + } + + let notifications = connection.get_notifications("ehuss").await.unwrap(); + assert_eq!(notifications.len(), 3); + assert_eq!(notifications[0].origin_url, "1"); + assert_eq!(notifications[1].origin_url, "2"); + assert_eq!(notifications[2].origin_url, "3"); + + match connection + .delete_ping(43198, Identifier::Index(NonZeroUsize::new(5).unwrap())) + .await + { + Err(e) => assert_eq!(e.to_string(), "No such notification with index 5"), + Ok(deleted) => panic!("did not expect success {deleted:?}"), + } + + let deleted = connection + .delete_ping(43198, Identifier::Index(NonZeroUsize::new(2).unwrap())) + .await + .unwrap(); + assert_eq!(deleted.len(), 1); + assert_eq!(deleted[0].origin_url, "2"); + let notifications = connection.get_notifications("ehuss").await.unwrap(); + assert_eq!(notifications.len(), 2); + assert_eq!(notifications[0].origin_url, "1"); + assert_eq!(notifications[1].origin_url, "3"); + + let deleted = connection + .delete_ping(43198, Identifier::Url("1")) + .await + .unwrap(); + assert_eq!(deleted.len(), 1); + assert_eq!(deleted[0].origin_url, "1"); + let notifications = connection.get_notifications("ehuss").await.unwrap(); + assert_eq!(notifications.len(), 1); + assert_eq!(notifications[0].origin_url, "3"); + + for x in 4..6 { + connection + .record_ping(&Notification { + user_id: 43198, + origin_url: x.to_string(), + origin_html: "@ehuss {n}".to_string(), + short_description: Some("Comment on some issue".to_string()), + time: now.into(), + team_name: None, + }) + .await + .unwrap(); + } + + let notifications = connection.get_notifications("ehuss").await.unwrap(); + assert_eq!(notifications.len(), 3); + assert_eq!(notifications[0].origin_url, "3"); + assert_eq!(notifications[1].origin_url, "4"); + assert_eq!(notifications[2].origin_url, "5"); + + let deleted = connection + .delete_ping(43198, Identifier::Index(NonZeroUsize::new(2).unwrap())) + .await + .unwrap(); + assert_eq!(deleted.len(), 1); + assert_eq!(deleted[0].origin_url, "4"); + + let deleted = connection + .delete_ping(43198, Identifier::All) + .await + .unwrap(); + assert_eq!(deleted.len(), 2); + assert_eq!(deleted[0].origin_url, "3"); + assert_eq!(deleted[1].origin_url, "5"); + + let notifications = connection.get_notifications("ehuss").await.unwrap(); + assert_eq!(notifications.len(), 0); + }); +} + +#[test] +fn meta_notification() { + run_test(|mut connection| async move { + let now = chrono::Utc::now(); + connection + .record_username(43198, "ehuss".to_string()) + .await + .unwrap(); + connection + .record_ping(&Notification { + user_id: 43198, + origin_url: "1".to_string(), + origin_html: "This comment mentions @ehuss.".to_string(), + short_description: Some("Comment on some issue".to_string()), + time: now.into(), + team_name: None, + }) + .await + .unwrap(); + connection + .add_metadata(43198, 0, Some("metadata 1")) + .await + .unwrap(); + let notifications = connection.get_notifications("ehuss").await.unwrap(); + assert_eq!(notifications.len(), 1); + assert_eq!(notifications[0].metadata.as_deref(), Some("metadata 1")); + }); +} + +#[test] +fn move_indices() { + run_test(|mut connection| async move { + let now = chrono::Utc::now(); + connection + .record_username(43198, "ehuss".to_string()) + .await + .unwrap(); + for x in 1..4 { + connection + .record_ping(&Notification { + user_id: 43198, + origin_url: x.to_string(), + origin_html: "@ehuss {n}".to_string(), + short_description: Some("Comment on some issue".to_string()), + time: now.into(), + team_name: None, + }) + .await + .unwrap(); + } + connection.move_indices(43198, 1, 0).await.unwrap(); + let notifications = connection.get_notifications("ehuss").await.unwrap(); + assert_eq!(notifications.len(), 3); + assert_eq!(notifications[0].origin_url, "2"); + assert_eq!(notifications[1].origin_url, "1"); + assert_eq!(notifications[2].origin_url, "3"); + }); +} diff --git a/tests/db/rustc_commits.rs b/tests/db/rustc_commits.rs new file mode 100644 index 00000000..8c36c6fb --- /dev/null +++ b/tests/db/rustc_commits.rs @@ -0,0 +1,87 @@ +use super::run_test; +use crate::assert_datetime_approx_equal; +use triagebot::db::Commit; + +#[test] +fn rustc_commits() { + run_test(|mut connection| async move { + // Using current time since `get_commits_with_artifacts` is relative to the current time. + let now = chrono::offset::Utc::now(); + connection + .record_commit(&Commit { + sha: "eebdfb55fce148676c24555505aebf648123b2de".to_string(), + parent_sha: "73f40197ecabf77ed59028af61739404eb60dd2e".to_string(), + time: now.into(), + pr: Some(108228), + }) + .await + .unwrap(); + + // A little older to ensure sorting is consistent. + let now3 = now - chrono::Duration::hours(3); + connection + .record_commit(&Commit { + sha: "73f40197ecabf77ed59028af61739404eb60dd2e".to_string(), + parent_sha: "fcdbd1c07f0b6c8e7d8bbd727c6ca69a1af8c7e9".to_string(), + time: now3.into(), + pr: Some(107772), + }) + .await + .unwrap(); + + // In the distant past, won't show up in get_commits_with_artifacts. + connection + .record_commit(&Commit { + sha: "26904687275a55864f32f3a7ba87b7711d063fd5".to_string(), + parent_sha: "3b348d932aa5c9884310d025cf7c516023fd0d9a".to_string(), + time: "2022-02-19T23:25:06Z".parse().unwrap(), + pr: Some(92911), + }) + .await + .unwrap(); + + assert!(connection + .has_commit("eebdfb55fce148676c24555505aebf648123b2de") + .await + .unwrap()); + assert!(connection + .has_commit("73f40197ecabf77ed59028af61739404eb60dd2e") + .await + .unwrap()); + assert!(connection + .has_commit("26904687275a55864f32f3a7ba87b7711d063fd5") + .await + .unwrap()); + assert!(!connection + .has_commit("fcdbd1c07f0b6c8e7d8bbd727c6ca69a1af8c7e9") + .await + .unwrap()); + + let missing = connection.get_missing_commits().await.unwrap(); + assert_eq!( + &missing[..], + [ + "fcdbd1c07f0b6c8e7d8bbd727c6ca69a1af8c7e9", + "3b348d932aa5c9884310d025cf7c516023fd0d9a" + ] + ); + + let commits = connection.get_commits_with_artifacts().await.unwrap(); + assert_eq!(commits.len(), 2); + assert_eq!(commits[0].sha, "eebdfb55fce148676c24555505aebf648123b2de"); + assert_eq!( + commits[0].parent_sha, + "73f40197ecabf77ed59028af61739404eb60dd2e" + ); + assert_datetime_approx_equal(&commits[0].time, &now); + assert_eq!(commits[0].pr, Some(108228)); + + assert_eq!(commits[1].sha, "73f40197ecabf77ed59028af61739404eb60dd2e"); + assert_eq!( + commits[1].parent_sha, + "fcdbd1c07f0b6c8e7d8bbd727c6ca69a1af8c7e9" + ); + assert_datetime_approx_equal(&commits[1].time, &now3); + assert_eq!(commits[1].pr, Some(107772)); + }); +} diff --git a/tests/github_client/bors_commits/00-GET-repos_rust-lang_rust_commits.json b/tests/github_client/bors_commits/00-GET-repos_rust-lang_rust_commits.json new file mode 100644 index 00000000..b0658429 --- /dev/null +++ b/tests/github_client/bors_commits/00-GET-repos_rust-lang_rust_commits.json @@ -0,0 +1,2530 @@ +{ + "kind": "Request", + "method": "GET", + "path": "/repos/rust-lang/rust/commits", + "query": "author=bors", + "request_body": "", + "response_code": 200, + "response_body": [ + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/7f97aeaf73047268299ab55288b3dd886130be47/comments", + "commit": { + "author": { + "date": "2023-02-05T11:10:11Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-05T11:10:11Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107679 - est31:less_import_overhead, r=compiler-errors\n\nLess import overhead for errors\n\nThis removes huge (3+ lines) import lists found in files that had their error reporting migrated. These lists are bad for developer workflows as adding, removing, or editing a single error's name might cause a chain reaction that bloats the git diff. As the error struct names are long, the likelihood of such chain reactions is high.\n\nFollows the suggestion by `@Nilstrieb` in the [zulip thread](https://rust-lang.zulipchat.com/#narrow/stream/147480-t-compiler.2Fwg-diagnostics/topic/massive.20use.20statements) to replace the `use errors::{FooErr, BarErr};` with `use errors;` and then changing to `errors::FooErr` on the usage sites.\n\nI have used sed to do most of the changes, i.e. something like:\n\n```\nsed -i -E 's/(create_err|create_feature_err|emit_err|create_note|emit_fatal|emit_warning)\\(([[:alnum:]]+|[A-Z][[:alnum:]:]*)( \\{|\\))/\\1(errors::\\2\\3/' path/to/file.rs\n```\n\n& then I manually fixed the errors that occured. Most manual changes were required in `compiler/rustc_parse/src/parser/expr.rs`.\n\nr? `@compiler-errors`", + "tree": { + "sha": "28ef3869cb8034a8ab5e4ad389c139ec7dbd6df1", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/28ef3869cb8034a8ab5e4ad389c139ec7dbd6df1" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/7f97aeaf73047268299ab55288b3dd886130be47", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/7f97aeaf73047268299ab55288b3dd886130be47", + "node_id": "C_kwDOAAsO6NoAKDdmOTdhZWFmNzMwNDcyNjgyOTlhYjU1Mjg4YjNkZDg4NjEzMGJlNDc", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/2a6ff729233c62d1d991da5ed4d01aa29e59d637", + "sha": "2a6ff729233c62d1d991da5ed4d01aa29e59d637", + "url": "https://api.github.com/repos/rust-lang/rust/commits/2a6ff729233c62d1d991da5ed4d01aa29e59d637" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/580cc89e9c36a89d3cc13a352c96f874eaa76581", + "sha": "580cc89e9c36a89d3cc13a352c96f874eaa76581", + "url": "https://api.github.com/repos/rust-lang/rust/commits/580cc89e9c36a89d3cc13a352c96f874eaa76581" + } + ], + "sha": "7f97aeaf73047268299ab55288b3dd886130be47", + "url": "https://api.github.com/repos/rust-lang/rust/commits/7f97aeaf73047268299ab55288b3dd886130be47" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/2a6ff729233c62d1d991da5ed4d01aa29e59d637/comments", + "commit": { + "author": { + "date": "2023-02-05T07:36:37Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-05T07:36:37Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107434 - BoxyUwU:nll_const_equate, r=compiler-errors\n\nemit `ConstEquate` in `TypeRelating`\n\nemitting `ConstEquate` during mir typeck is useful since it can help catch bugs in hir typeck incase our impl of `ConstEquate` is wrong.\n\ndoing this did actually catch a bug, when relating `Expr::Call` we `==` the types of all the argument consts which spuriously returns false if the type contains const projections/aliases which causes us to fall through to the `expected_found` error arm.\nGenerally its an ICE if the `Const`'s `Ty`s arent equal but `ConstKind::Expr` is kind of special since they are sort of like const items that are `const CALL` though we dont actually explicitly represent the `F` type param explicitly in `Expr::Call` so I just made us relate the `Const`'s ty field to avoid getting ICEs from the tests I added and the following existing test:\n```rust\n// tests/ui/const-generics/generic_const_exprs/different-fn.rs\n#![feature(generic_const_exprs)]\n#![allow(incomplete_features)]\n\nuse std::mem::size_of;\nuse std::marker::PhantomData;\n\nstruct Foo(PhantomData);\n\nfn test() -> [u8; size_of::()] {\n [0; size_of::>()]\n //~^ ERROR unconstrained generic constant\n //~| ERROR mismatched types\n}\n\nfn main() {\n test::();\n}\n```\nwhich has us relate two `ConstKind::Value` one for the fn item of `size_of::>` and one for the fn item of `size_of::()`, these only differ by their `Ty` and if we don't relate the `Ty` we'll end up getting an ICE from the checks that ensure the `ty` fields always match.\n\nIn theory `Expr::UnOp` has the same problem so I added a call to `relate` for the ty's, although I was unable to create a repro test.", + "tree": { + "sha": "2304fe8c3bff131573b1cd5e6de1b3fb1c0ce7ad", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/2304fe8c3bff131573b1cd5e6de1b3fb1c0ce7ad" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/2a6ff729233c62d1d991da5ed4d01aa29e59d637", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/2a6ff729233c62d1d991da5ed4d01aa29e59d637", + "node_id": "C_kwDOAAsO6NoAKDJhNmZmNzI5MjMzYzYyZDFkOTkxZGE1ZWQ0ZDAxYWEyOWU1OWQ2Mzc", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/50d3ba5bcbf5c7e13d4ce068d3339710701dd603", + "sha": "50d3ba5bcbf5c7e13d4ce068d3339710701dd603", + "url": "https://api.github.com/repos/rust-lang/rust/commits/50d3ba5bcbf5c7e13d4ce068d3339710701dd603" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/d85d906f8c44dd98bf6bc0e4b753aa241839c323", + "sha": "d85d906f8c44dd98bf6bc0e4b753aa241839c323", + "url": "https://api.github.com/repos/rust-lang/rust/commits/d85d906f8c44dd98bf6bc0e4b753aa241839c323" + } + ], + "sha": "2a6ff729233c62d1d991da5ed4d01aa29e59d637", + "url": "https://api.github.com/repos/rust-lang/rust/commits/2a6ff729233c62d1d991da5ed4d01aa29e59d637" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/50d3ba5bcbf5c7e13d4ce068d3339710701dd603/comments", + "commit": { + "author": { + "date": "2023-02-04T21:07:10Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-04T21:07:10Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107672 - matthiaskrgr:rollup-7e6dbuk, r=matthiaskrgr\n\nRollup of 3 pull requests\n\nSuccessful merges:\n\n - #107116 (consolidate bootstrap docs)\n - #107646 (Provide structured suggestion for binding needing type on E0594)\n - #107661 (Remove Esteban from review queues for a while)\n\nFailed merges:\n\nr? `@ghost`\n`@rustbot` modify labels: rollup", + "tree": { + "sha": "932463b8bde694e38b6ed2bd27d772fc2ce0255f", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/932463b8bde694e38b6ed2bd27d772fc2ce0255f" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/50d3ba5bcbf5c7e13d4ce068d3339710701dd603", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/50d3ba5bcbf5c7e13d4ce068d3339710701dd603", + "node_id": "C_kwDOAAsO6NoAKDUwZDNiYTViY2JmNWM3ZTEzZDRjZTA2OGQzMzM5NzEwNzAxZGQ2MDM", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/3de7d7fb22a579a3d59ddb1c959d1b3da224aafa", + "sha": "3de7d7fb22a579a3d59ddb1c959d1b3da224aafa", + "url": "https://api.github.com/repos/rust-lang/rust/commits/3de7d7fb22a579a3d59ddb1c959d1b3da224aafa" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/47fc625a921aed430c08d6015246e65362256343", + "sha": "47fc625a921aed430c08d6015246e65362256343", + "url": "https://api.github.com/repos/rust-lang/rust/commits/47fc625a921aed430c08d6015246e65362256343" + } + ], + "sha": "50d3ba5bcbf5c7e13d4ce068d3339710701dd603", + "url": "https://api.github.com/repos/rust-lang/rust/commits/50d3ba5bcbf5c7e13d4ce068d3339710701dd603" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/3de7d7fb22a579a3d59ddb1c959d1b3da224aafa/comments", + "commit": { + "author": { + "date": "2023-02-04T18:11:02Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-04T18:11:02Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107549 - Zoxc:rustc-shared, r=jyn514\n\nMove code in `rustc_driver` out to a new `rustc_driver_impl` crate to allow pipelining\n\nThat adds a `rustc_shared` library which contains all the rustc library crates in a single dylib. It takes over this role from `rustc_driver`. This is done so that `rustc_driver` can be compiled in parallel with other crates. `rustc_shared` is intentionally left empty so it only does linking.\n\nAn alternative could be to move the code currently in `rustc_driver` into a new crate to avoid changing the name of the distributed library.", + "tree": { + "sha": "0d3e9447ea00657b717fbba42f6a854bc0b95355", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/0d3e9447ea00657b717fbba42f6a854bc0b95355" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/3de7d7fb22a579a3d59ddb1c959d1b3da224aafa", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/3de7d7fb22a579a3d59ddb1c959d1b3da224aafa", + "node_id": "C_kwDOAAsO6NoAKDNkZTdkN2ZiMjJhNTc5YTNkNTlkZGIxYzk1OWQxYjNkYTIyNGFhZmE", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/9dee4e4c42d23b0c5afd6d8fed025181f70fbe12", + "sha": "9dee4e4c42d23b0c5afd6d8fed025181f70fbe12", + "url": "https://api.github.com/repos/rust-lang/rust/commits/9dee4e4c42d23b0c5afd6d8fed025181f70fbe12" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/2b8f8922ee5852f97e92082b209c0f4d940a6edb", + "sha": "2b8f8922ee5852f97e92082b209c0f4d940a6edb", + "url": "https://api.github.com/repos/rust-lang/rust/commits/2b8f8922ee5852f97e92082b209c0f4d940a6edb" + } + ], + "sha": "3de7d7fb22a579a3d59ddb1c959d1b3da224aafa", + "url": "https://api.github.com/repos/rust-lang/rust/commits/3de7d7fb22a579a3d59ddb1c959d1b3da224aafa" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/9dee4e4c42d23b0c5afd6d8fed025181f70fbe12/comments", + "commit": { + "author": { + "date": "2023-02-04T15:17:32Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-04T15:17:32Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107267 - cjgillot:keep-aggregate, r=oli-obk\n\nDo not deaggregate MIR\n\nThis turns out to simplify a lot of things.\nI haven't checked the consequences for miri yet.\n\ncc `@JakobDegen`\nr? `@oli-obk`", + "tree": { + "sha": "9e854d084f562af0f8369eca144ad1fb044b248f", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/9e854d084f562af0f8369eca144ad1fb044b248f" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/9dee4e4c42d23b0c5afd6d8fed025181f70fbe12", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/9dee4e4c42d23b0c5afd6d8fed025181f70fbe12", + "node_id": "C_kwDOAAsO6NoAKDlkZWU0ZTRjNDJkMjNiMGM1YWZkNmQ4ZmVkMDI1MTgxZjcwZmJlMTI", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/4aa6afa7f8a418a7dae5dbe4c95371d4f3bcc0e1", + "sha": "4aa6afa7f8a418a7dae5dbe4c95371d4f3bcc0e1", + "url": "https://api.github.com/repos/rust-lang/rust/commits/4aa6afa7f8a418a7dae5dbe4c95371d4f3bcc0e1" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/5c39ba20279e338e2cd421bc799d4a5d3397c3b9", + "sha": "5c39ba20279e338e2cd421bc799d4a5d3397c3b9", + "url": "https://api.github.com/repos/rust-lang/rust/commits/5c39ba20279e338e2cd421bc799d4a5d3397c3b9" + } + ], + "sha": "9dee4e4c42d23b0c5afd6d8fed025181f70fbe12", + "url": "https://api.github.com/repos/rust-lang/rust/commits/9dee4e4c42d23b0c5afd6d8fed025181f70fbe12" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/4aa6afa7f8a418a7dae5dbe4c95371d4f3bcc0e1/comments", + "commit": { + "author": { + "date": "2023-02-04T11:22:31Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-04T11:22:31Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107618 - chriswailes:linker-arg, r=albertlarsan68\n\nAdd a linker argument back to boostrap.py\n\nIn https://github.com/rust-lang/rust/pull/101783 I accidentally removed a load-bearing linker argument. This PR adds it back in.\n\nr? jyn514", + "tree": { + "sha": "eac1bf39849eae33d4bb2b9bdb80304e8a03dd48", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/eac1bf39849eae33d4bb2b9bdb80304e8a03dd48" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/4aa6afa7f8a418a7dae5dbe4c95371d4f3bcc0e1", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/4aa6afa7f8a418a7dae5dbe4c95371d4f3bcc0e1", + "node_id": "C_kwDOAAsO6NoAKDRhYTZhZmE3ZjhhNDE4YTdkYWU1ZGJlNGM5NTM3MWQ0ZjNiY2MwZTE", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/91eb6f9acfcfde6832d547959ad2d95b1ac0b5dc", + "sha": "91eb6f9acfcfde6832d547959ad2d95b1ac0b5dc", + "url": "https://api.github.com/repos/rust-lang/rust/commits/91eb6f9acfcfde6832d547959ad2d95b1ac0b5dc" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/134a5aea52641715dd1ea1e4ad0e6a5693fbedc6", + "sha": "134a5aea52641715dd1ea1e4ad0e6a5693fbedc6", + "url": "https://api.github.com/repos/rust-lang/rust/commits/134a5aea52641715dd1ea1e4ad0e6a5693fbedc6" + } + ], + "sha": "4aa6afa7f8a418a7dae5dbe4c95371d4f3bcc0e1", + "url": "https://api.github.com/repos/rust-lang/rust/commits/4aa6afa7f8a418a7dae5dbe4c95371d4f3bcc0e1" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/91eb6f9acfcfde6832d547959ad2d95b1ac0b5dc/comments", + "commit": { + "author": { + "date": "2023-02-04T03:41:57Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-04T03:41:57Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107591 - krasimirgg:llvm-17-pgoopts, r=cuviper\n\nllvm-wrapper: adapt for LLVM API changes\n\nAdapts the wrapper for https://github.com/llvm/llvm-project/commit/516e301752560311d2cd8c2b549493eb0f98d01b, where the constructor of PGOOptions gained a new FileSystem argument. Adapted to use the real file system, similarly to the changes inside of LLVM:\nhttps://github.com/llvm/llvm-project/commit/516e301752560311d2cd8c2b549493eb0f98d01b#diff-f409934ba27ad86494f3012324e9a3995b56e0743609ded7a387ba62bbf5edb0R236\n\nFound via our experimental Rust + LLVM at HEAD bot: https://buildkite.com/llvm-project/rust-llvm-integrate-prototype/builds/16853#01860e2e-5eba-4f07-8359-0325913ff410/219-517", + "tree": { + "sha": "eac1bf39849eae33d4bb2b9bdb80304e8a03dd48", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/eac1bf39849eae33d4bb2b9bdb80304e8a03dd48" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/91eb6f9acfcfde6832d547959ad2d95b1ac0b5dc", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/91eb6f9acfcfde6832d547959ad2d95b1ac0b5dc", + "node_id": "C_kwDOAAsO6NoAKDkxZWI2ZjlhY2ZjZmRlNjgzMmQ1NDc5NTlhZDJkOTViMWFjMGI1ZGM", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/886b2c3e005b153b3c8263f48193e0df7de0f5b3", + "sha": "886b2c3e005b153b3c8263f48193e0df7de0f5b3", + "url": "https://api.github.com/repos/rust-lang/rust/commits/886b2c3e005b153b3c8263f48193e0df7de0f5b3" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/4614e5b5bf1331907bf3baf70cf0eb705f2959e9", + "sha": "4614e5b5bf1331907bf3baf70cf0eb705f2959e9", + "url": "https://api.github.com/repos/rust-lang/rust/commits/4614e5b5bf1331907bf3baf70cf0eb705f2959e9" + } + ], + "sha": "91eb6f9acfcfde6832d547959ad2d95b1ac0b5dc", + "url": "https://api.github.com/repos/rust-lang/rust/commits/91eb6f9acfcfde6832d547959ad2d95b1ac0b5dc" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/886b2c3e005b153b3c8263f48193e0df7de0f5b3/comments", + "commit": { + "author": { + "date": "2023-02-03T22:37:53Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-03T22:37:53Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107650 - compiler-errors:rollup-4pntchf, r=compiler-errors\n\nRollup of 8 pull requests\n\nSuccessful merges:\n\n - #106887 (Make const/fn return params more suggestable)\n - #107519 (Add type alias for raw OS errors)\n - #107551 ( Replace `ConstFnMutClosure` with const closures )\n - #107595 (Retry opening proc-macro DLLs a few times on Windows.)\n - #107615 (Replace nbsp in all rustdoc code blocks)\n - #107621 (Intern external constraints in new solver)\n - #107631 (loudly tell people when they change `Cargo.lock`)\n - #107632 (Clarifying that .map() returns None if None.)\n\nFailed merges:\n\nr? `@ghost`\n`@rustbot` modify labels: rollup", + "tree": { + "sha": "4bd560ab45691d951ce6a3b70229091e093a69b7", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/4bd560ab45691d951ce6a3b70229091e093a69b7" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/886b2c3e005b153b3c8263f48193e0df7de0f5b3", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/886b2c3e005b153b3c8263f48193e0df7de0f5b3", + "node_id": "C_kwDOAAsO6NoAKDg4NmIyYzNlMDA1YjE1M2IzYzgyNjNmNDgxOTNlMGRmN2RlMGY1YjM", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/658fad6c5506f41c35b64fb1a22ceb0992697ff3", + "sha": "658fad6c5506f41c35b64fb1a22ceb0992697ff3", + "url": "https://api.github.com/repos/rust-lang/rust/commits/658fad6c5506f41c35b64fb1a22ceb0992697ff3" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/13bd75f425f084d63817336db5ca433bc0655786", + "sha": "13bd75f425f084d63817336db5ca433bc0655786", + "url": "https://api.github.com/repos/rust-lang/rust/commits/13bd75f425f084d63817336db5ca433bc0655786" + } + ], + "sha": "886b2c3e005b153b3c8263f48193e0df7de0f5b3", + "url": "https://api.github.com/repos/rust-lang/rust/commits/886b2c3e005b153b3c8263f48193e0df7de0f5b3" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/658fad6c5506f41c35b64fb1a22ceb0992697ff3/comments", + "commit": { + "author": { + "date": "2023-02-03T17:53:49Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-03T17:53:49Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107642 - Dylan-DPC:rollup-edcqhm5, r=Dylan-DPC\n\nRollup of 6 pull requests\n\nSuccessful merges:\n\n - #107082 (Autotrait bounds on dyn-safe trait methods)\n - #107427 (Add candidates for DiscriminantKind builtin)\n - #107539 (Emit warnings on unused parens in index expressions)\n - #107544 (Improve `TokenCursor`.)\n - #107585 (Don't cause a cycle when formatting query description that references a FnDef)\n - #107633 (Fix suggestion for coercing Option<&String> to Option<&str>)\n\nFailed merges:\n\nr? `@ghost`\n`@rustbot` modify labels: rollup", + "tree": { + "sha": "d9beffb3e496848ea5acbe6d9caf2d102f473eab", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/d9beffb3e496848ea5acbe6d9caf2d102f473eab" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/658fad6c5506f41c35b64fb1a22ceb0992697ff3", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/658fad6c5506f41c35b64fb1a22ceb0992697ff3", + "node_id": "C_kwDOAAsO6NoAKDY1OGZhZDZjNTUwNmY0MWMzNWI2NGZiMWEyMmNlYjA5OTI2OTdmZjM", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/9545094994f1ab45cab5799d5b45980871a9e97b", + "sha": "9545094994f1ab45cab5799d5b45980871a9e97b", + "url": "https://api.github.com/repos/rust-lang/rust/commits/9545094994f1ab45cab5799d5b45980871a9e97b" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/c9270272df5bd7254b6ce1c7b69d41c75e443406", + "sha": "c9270272df5bd7254b6ce1c7b69d41c75e443406", + "url": "https://api.github.com/repos/rust-lang/rust/commits/c9270272df5bd7254b6ce1c7b69d41c75e443406" + } + ], + "sha": "658fad6c5506f41c35b64fb1a22ceb0992697ff3", + "url": "https://api.github.com/repos/rust-lang/rust/commits/658fad6c5506f41c35b64fb1a22ceb0992697ff3" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/9545094994f1ab45cab5799d5b45980871a9e97b/comments", + "commit": { + "author": { + "date": "2023-02-03T14:22:42Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-03T14:22:42Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107599 - clubby789:debug-less-ref, r=nnethercote\n\nDon't generate unecessary `&&self.field` in deriving Debug\n\nSince unsized fields may only be the last one in a struct, we only need to generate a double reference (`&&self.field`) for the final one.\n\ncc `@nnethercote`", + "tree": { + "sha": "f20e2d08b8836fe5498948b0863680019083975c", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/f20e2d08b8836fe5498948b0863680019083975c" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/9545094994f1ab45cab5799d5b45980871a9e97b", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/9545094994f1ab45cab5799d5b45980871a9e97b", + "node_id": "C_kwDOAAsO6NoAKDk1NDUwOTQ5OTRmMWFiNDVjYWI1Nzk5ZDViNDU5ODA4NzFhOWU5N2I", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/a94b9fd0ace1336a3dd93f51f1c0db6ca0fd7f92", + "sha": "a94b9fd0ace1336a3dd93f51f1c0db6ca0fd7f92", + "url": "https://api.github.com/repos/rust-lang/rust/commits/a94b9fd0ace1336a3dd93f51f1c0db6ca0fd7f92" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/d8651aae22d3b2251045647e7313fea37381362a", + "sha": "d8651aae22d3b2251045647e7313fea37381362a", + "url": "https://api.github.com/repos/rust-lang/rust/commits/d8651aae22d3b2251045647e7313fea37381362a" + } + ], + "sha": "9545094994f1ab45cab5799d5b45980871a9e97b", + "url": "https://api.github.com/repos/rust-lang/rust/commits/9545094994f1ab45cab5799d5b45980871a9e97b" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/a94b9fd0ace1336a3dd93f51f1c0db6ca0fd7f92/comments", + "commit": { + "author": { + "date": "2023-02-03T11:19:03Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-03T11:19:03Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107569 - petrochenkov:optattr, r=nnethercote\n\nast: Optimize list and value extraction primitives for attributes\n\nIt's not necessary to convert the whole attribute into a meta item to extract something specific.", + "tree": { + "sha": "a2064cce0219090bcdba2de58a84a62b78fc0270", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/a2064cce0219090bcdba2de58a84a62b78fc0270" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/a94b9fd0ace1336a3dd93f51f1c0db6ca0fd7f92", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/a94b9fd0ace1336a3dd93f51f1c0db6ca0fd7f92", + "node_id": "C_kwDOAAsO6NoAKGE5NGI5ZmQwYWNlMTMzNmEzZGQ5M2Y1MWYxYzBkYjZjYTBmZDdmOTI", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/7c46fb2111936ad21a8e3aa41e9128752357f5d8", + "sha": "7c46fb2111936ad21a8e3aa41e9128752357f5d8", + "url": "https://api.github.com/repos/rust-lang/rust/commits/7c46fb2111936ad21a8e3aa41e9128752357f5d8" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/a9c8a5c0255d056f78f1347c431fd88bc727febb", + "sha": "a9c8a5c0255d056f78f1347c431fd88bc727febb", + "url": "https://api.github.com/repos/rust-lang/rust/commits/a9c8a5c0255d056f78f1347c431fd88bc727febb" + } + ], + "sha": "a94b9fd0ace1336a3dd93f51f1c0db6ca0fd7f92", + "url": "https://api.github.com/repos/rust-lang/rust/commits/a94b9fd0ace1336a3dd93f51f1c0db6ca0fd7f92" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/7c46fb2111936ad21a8e3aa41e9128752357f5d8/comments", + "commit": { + "author": { + "date": "2023-02-03T08:07:47Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-03T08:07:47Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107625 - matthiaskrgr:rollup-xr9oldy, r=matthiaskrgr\n\nRollup of 6 pull requests\n\nSuccessful merges:\n\n - #106575 (Suggest `move` in nested closure when appropriate)\n - #106805 (Suggest `{var:?}` when finding `{?:var}` in inline format strings)\n - #107500 (Add tests to assert current behavior of large future sizes)\n - #107598 (Fix benchmarks in library/core with black_box)\n - #107602 (Parse and recover from type ascription in patterns)\n - #107608 (Use triple rather than arch for fuchsia test-runner)\n\nFailed merges:\n\nr? `@ghost`\n`@rustbot` modify labels: rollup", + "tree": { + "sha": "d3bdac647485a029e043f15ab0b46529058a437c", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/d3bdac647485a029e043f15ab0b46529058a437c" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/7c46fb2111936ad21a8e3aa41e9128752357f5d8", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/7c46fb2111936ad21a8e3aa41e9128752357f5d8", + "node_id": "C_kwDOAAsO6NoAKDdjNDZmYjIxMTE5MzZhZDIxYThlM2FhNDFlOTEyODc1MjM1N2Y1ZDg", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/5d32458343f34bd8de6d96cbaab2a9cf879dd1b8", + "sha": "5d32458343f34bd8de6d96cbaab2a9cf879dd1b8", + "url": "https://api.github.com/repos/rust-lang/rust/commits/5d32458343f34bd8de6d96cbaab2a9cf879dd1b8" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/b6e8ebf33b0203ab16bbb26eb95a6654ee00ac8e", + "sha": "b6e8ebf33b0203ab16bbb26eb95a6654ee00ac8e", + "url": "https://api.github.com/repos/rust-lang/rust/commits/b6e8ebf33b0203ab16bbb26eb95a6654ee00ac8e" + } + ], + "sha": "7c46fb2111936ad21a8e3aa41e9128752357f5d8", + "url": "https://api.github.com/repos/rust-lang/rust/commits/7c46fb2111936ad21a8e3aa41e9128752357f5d8" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/5d32458343f34bd8de6d96cbaab2a9cf879dd1b8/comments", + "commit": { + "author": { + "date": "2023-02-03T04:49:50Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-03T04:49:50Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107543 - ehuss:protocol-sparse, r=jyn514\n\nEnable Cargo's sparse protocol in CI\n\nThis enables the sparse protocol in CI in order to exercise and dogfood it. This is intended test the production server in a real-world situation.\n\nCloses #107342", + "tree": { + "sha": "9c2f45b42f042b5f78bfd1b8c491958f83dd1351", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/9c2f45b42f042b5f78bfd1b8c491958f83dd1351" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/5d32458343f34bd8de6d96cbaab2a9cf879dd1b8", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/5d32458343f34bd8de6d96cbaab2a9cf879dd1b8", + "node_id": "C_kwDOAAsO6NoAKDVkMzI0NTgzNDNmMzRiZDhkZTZkOTZjYmFhYjJhOWNmODc5ZGQxYjg", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/f02439dea78e5c2df42198c7a03e2db6002ff263", + "sha": "f02439dea78e5c2df42198c7a03e2db6002ff263", + "url": "https://api.github.com/repos/rust-lang/rust/commits/f02439dea78e5c2df42198c7a03e2db6002ff263" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/5e90940a4b742e7f1e86f21c26b56e99a8733458", + "sha": "5e90940a4b742e7f1e86f21c26b56e99a8733458", + "url": "https://api.github.com/repos/rust-lang/rust/commits/5e90940a4b742e7f1e86f21c26b56e99a8733458" + } + ], + "sha": "5d32458343f34bd8de6d96cbaab2a9cf879dd1b8", + "url": "https://api.github.com/repos/rust-lang/rust/commits/5d32458343f34bd8de6d96cbaab2a9cf879dd1b8" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/f02439dea78e5c2df42198c7a03e2db6002ff263/comments", + "commit": { + "author": { + "date": "2023-02-03T01:19:04Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-03T01:19:04Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107241 - clubby789:bootstrap-lto-off, r=simulacrum\n\nAdd `rust.lto=off` to bootstrap and set as compiler/library default\n\nCloses #107202\n\nThe issue mentions `embed-bitcode=on`, but here https://github.com/rust-lang/rust/blob/c8e6a9e8b6251bbc8276cb78cabe1998deecbed7/src/bootstrap/compile.rs#L379-L381\nit appears that this is always set for std stage 1+, so I'm unsure if changes are needed here.\n\n`@rustbot` label +A-bootstrap", + "tree": { + "sha": "ba934c044e040c794ecaf64c5d0ddea604210a5c", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/ba934c044e040c794ecaf64c5d0ddea604210a5c" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/f02439dea78e5c2df42198c7a03e2db6002ff263", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/f02439dea78e5c2df42198c7a03e2db6002ff263", + "node_id": "C_kwDOAAsO6NoAKGYwMjQzOWRlYTc4ZTVjMmRmNDIxOThjN2EwM2UyZGI2MDAyZmYyNjM", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/6c991b07403a3234dd1ec0ac973b8ef97055e605", + "sha": "6c991b07403a3234dd1ec0ac973b8ef97055e605", + "url": "https://api.github.com/repos/rust-lang/rust/commits/6c991b07403a3234dd1ec0ac973b8ef97055e605" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/2adf26fc72f354aabd65da176eb9f8806b0d2ef2", + "sha": "2adf26fc72f354aabd65da176eb9f8806b0d2ef2", + "url": "https://api.github.com/repos/rust-lang/rust/commits/2adf26fc72f354aabd65da176eb9f8806b0d2ef2" + } + ], + "sha": "f02439dea78e5c2df42198c7a03e2db6002ff263", + "url": "https://api.github.com/repos/rust-lang/rust/commits/f02439dea78e5c2df42198c7a03e2db6002ff263" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/6c991b07403a3234dd1ec0ac973b8ef97055e605/comments", + "commit": { + "author": { + "date": "2023-02-02T21:14:44Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-02T21:14:44Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107000 - GuillaumeGomez:fix-items-in-doc-hidden-block, r=notriddle,petrochenkov\n\nFix handling of items inside a `doc(hidden)` block\n\nFixes #106373.\n\ncc `@aDotInTheVoid`\nr? `@notriddle`", + "tree": { + "sha": "e9fd955533d898249d8602ae2e2cc9b6040b264b", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/e9fd955533d898249d8602ae2e2cc9b6040b264b" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/6c991b07403a3234dd1ec0ac973b8ef97055e605", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/6c991b07403a3234dd1ec0ac973b8ef97055e605", + "node_id": "C_kwDOAAsO6NoAKDZjOTkxYjA3NDAzYTMyMzRkZDFlYzBhYzk3M2I4ZWY5NzA1NWU2MDU", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/f3126500f25114ba4e0ac3e76694dd45a22de56d", + "sha": "f3126500f25114ba4e0ac3e76694dd45a22de56d", + "url": "https://api.github.com/repos/rust-lang/rust/commits/f3126500f25114ba4e0ac3e76694dd45a22de56d" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/ea844187b27fbcff521bcbcbe6615d51d0196fa2", + "sha": "ea844187b27fbcff521bcbcbe6615d51d0196fa2", + "url": "https://api.github.com/repos/rust-lang/rust/commits/ea844187b27fbcff521bcbcbe6615d51d0196fa2" + } + ], + "sha": "6c991b07403a3234dd1ec0ac973b8ef97055e605", + "url": "https://api.github.com/repos/rust-lang/rust/commits/6c991b07403a3234dd1ec0ac973b8ef97055e605" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/f3126500f25114ba4e0ac3e76694dd45a22de56d/comments", + "commit": { + "author": { + "date": "2023-02-02T17:56:53Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-02T17:56:53Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107601 - matthiaskrgr:rollup-07zaafe, r=matthiaskrgr\n\nRollup of 7 pull requests\n\nSuccessful merges:\n\n - #106919 (Recover `_` as `..` in field pattern)\n - #107493 (Improve diagnostic for missing space in range pattern)\n - #107515 (Improve pretty-printing of `HirIdValidator` errors)\n - #107524 (Remove both StorageLive and StorageDead in CopyProp.)\n - #107532 (Erase regions before doing uninhabited check in borrowck)\n - #107559 (Rename `rust_2015` → `is_rust_2015`)\n - #107577 (Reinstate the `hir-stats.rs` tests on stage 1.)\n\nFailed merges:\n\nr? `@ghost`\n`@rustbot` modify labels: rollup", + "tree": { + "sha": "ab016ef14231c6193f6a9d086fca0cda4a159f9a", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/ab016ef14231c6193f6a9d086fca0cda4a159f9a" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/f3126500f25114ba4e0ac3e76694dd45a22de56d", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/f3126500f25114ba4e0ac3e76694dd45a22de56d", + "node_id": "C_kwDOAAsO6NoAKGYzMTI2NTAwZjI1MTE0YmE0ZTBhYzNlNzY2OTRkZDQ1YTIyZGU1NmQ", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/97872b792c9dd6a9bc5c3f4e62a0bd5958b09cdc", + "sha": "97872b792c9dd6a9bc5c3f4e62a0bd5958b09cdc", + "url": "https://api.github.com/repos/rust-lang/rust/commits/97872b792c9dd6a9bc5c3f4e62a0bd5958b09cdc" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/08181eabfeb468e22e5ce179492979d57d0cdf85", + "sha": "08181eabfeb468e22e5ce179492979d57d0cdf85", + "url": "https://api.github.com/repos/rust-lang/rust/commits/08181eabfeb468e22e5ce179492979d57d0cdf85" + } + ], + "sha": "f3126500f25114ba4e0ac3e76694dd45a22de56d", + "url": "https://api.github.com/repos/rust-lang/rust/commits/f3126500f25114ba4e0ac3e76694dd45a22de56d" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/97872b792c9dd6a9bc5c3f4e62a0bd5958b09cdc/comments", + "commit": { + "author": { + "date": "2023-02-02T12:01:17Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-02T12:01:17Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107478 - compiler-errors:anon-enum-tys-are-ambiguous, r=estebank\n\nRevert \"Teach parser to understand fake anonymous enum syntax\" and related commits\n\nanonymous enum types are currently ambiguous in positions like:\n\n* `|` operator: `a as fn() -> B | C`\n* closure args: `|_: as fn() -> A | B`\n\nI first tried to thread around `RecoverAnonEnum` into all these positions, but the resulting complexity in the compiler is IMO not worth it, or at least worth a bit more thinking time. In the mean time, let's revert this syntax for now, so we can go back to the drawing board.\n\nFixes #107461\n\ncc: `@estebank` `@cjgillot` #106960\n\n---\n### Squashed revert commits:\n\nRevert \"review comment: Remove AST AnonTy\"\n\nThis reverts commit 020cca8d36cb678e3ddc2ead41364be314d19e93.\n\nRevert \"Ensure macros are not affected\"\n\nThis reverts commit 12d18e403139eeeeb339e8611b2bed4910864edb.\n\nRevert \"Emit fewer errors on patterns with possible type ascription\"\n\nThis reverts commit c847a01a3b1f620c4fdb98c75805033e768975d1.\n\nRevert \"Teach parser to understand fake anonymous enum syntax\"\n\nThis reverts commit 2d824206655bfb26cb5eed43490ee396542b153e.", + "tree": { + "sha": "ac382c6f916b98074fe5ce756d3778d5d3f0d407", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/ac382c6f916b98074fe5ce756d3778d5d3f0d407" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/97872b792c9dd6a9bc5c3f4e62a0bd5958b09cdc", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/97872b792c9dd6a9bc5c3f4e62a0bd5958b09cdc", + "node_id": "C_kwDOAAsO6NoAKDk3ODcyYjc5MmM5ZGQ2YTliYzVjM2Y0ZTYyYTBiZDU5NThiMDljZGM", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/a9985cf172e7cb8ab5c58ce2818752c3572754fc", + "sha": "a9985cf172e7cb8ab5c58ce2818752c3572754fc", + "url": "https://api.github.com/repos/rust-lang/rust/commits/a9985cf172e7cb8ab5c58ce2818752c3572754fc" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/39db65c526ae3b97f0ee90642242c8c07865707e", + "sha": "39db65c526ae3b97f0ee90642242c8c07865707e", + "url": "https://api.github.com/repos/rust-lang/rust/commits/39db65c526ae3b97f0ee90642242c8c07865707e" + } + ], + "sha": "97872b792c9dd6a9bc5c3f4e62a0bd5958b09cdc", + "url": "https://api.github.com/repos/rust-lang/rust/commits/97872b792c9dd6a9bc5c3f4e62a0bd5958b09cdc" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/a9985cf172e7cb8ab5c58ce2818752c3572754fc/comments", + "commit": { + "author": { + "date": "2023-02-02T09:05:18Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-02T09:05:18Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107584 - matthiaskrgr:rollup-vav4ljz, r=matthiaskrgr\n\nRollup of 5 pull requests\n\nSuccessful merges:\n\n - #107201 (Remove confusing 'while checking' note from opaque future type mismatches)\n - #107312 (Add Style Guide rules for let-else statements)\n - #107488 (Fix syntax in `-Zunpretty-expanded` output for derived `PartialEq`.)\n - #107531 (Inline CSS background images directly into the CSS)\n - #107576 (Add proc-macro boilerplate to crt-static test)\n\nFailed merges:\n\nr? `@ghost`\n`@rustbot` modify labels: rollup", + "tree": { + "sha": "dbb937247db20bbd75be7bde50d74213d674dbde", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/dbb937247db20bbd75be7bde50d74213d674dbde" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/a9985cf172e7cb8ab5c58ce2818752c3572754fc", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/a9985cf172e7cb8ab5c58ce2818752c3572754fc", + "node_id": "C_kwDOAAsO6NoAKGE5OTg1Y2YxNzJlN2NiOGFiNWM1OGNlMjgxODc1MmMzNTcyNzU0ZmM", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/821b2a8e39588fedda894d10b9b3abd7293f0383", + "sha": "821b2a8e39588fedda894d10b9b3abd7293f0383", + "url": "https://api.github.com/repos/rust-lang/rust/commits/821b2a8e39588fedda894d10b9b3abd7293f0383" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/643fc97fd3b3f4f34eb2d66af1deac9218835527", + "sha": "643fc97fd3b3f4f34eb2d66af1deac9218835527", + "url": "https://api.github.com/repos/rust-lang/rust/commits/643fc97fd3b3f4f34eb2d66af1deac9218835527" + } + ], + "sha": "a9985cf172e7cb8ab5c58ce2818752c3572754fc", + "url": "https://api.github.com/repos/rust-lang/rust/commits/a9985cf172e7cb8ab5c58ce2818752c3572754fc" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/821b2a8e39588fedda894d10b9b3abd7293f0383/comments", + "commit": { + "author": { + "date": "2023-02-02T05:26:09Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-02T05:26:09Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #106925 - imWildCat:imWildCat/remove-hardcoded-ios-macbi-target-version, r=wesleywiser\n\nRemove hardcoded iOS version of clang target for Mac Catalyst\n\n## Background\n\nFrom `clang` 13.x, `-target x86_64-apple-ios13.0-macabi` fails while linking:\n\n```\n = note: clang: error: invalid version number in '-target x86_64-apple-ios13.0-macabi'\n```\n\n\nVerbose output\n\n```\nerror: linking with `cc` failed: exit status: 1\n |\n = note: LC_ALL=\"C\" PATH=\"[removed]\" VSLANG=\"1033\" ZERO_AR_DATE=\"1\" \"cc\" \"-Wl,-exported_symbols_list,/var/folders/p8/qpmzbsdn07g5gxykwfxxw7y40000gn/T/rustci8tkvp/list\" \"-target\" \"x86_64-apple-ios13.0-macabi\" \"/var/folders/p8/qpmzbsdn07g5gxykwfxxw7y40000gn/T/rustci8tkvp/symbols.o\" \"/path/to/my/[project]/[user]/target/x86_64-apple-ios-macabi/release/deps/[user].[user].a2ccc648-cgu.0.rcgu.o\" \"-L\" \"/path/to/my/[project]/[user]/target/x86_64-apple-ios-macabi/release/deps\" \"-L\" \"/path/to/my/[project]/[user]/target/release/deps\" \"-L\" \"/path/to/my/[project]/[user]/target/x86_64-apple-ios-macabi/release/build/blake3-74e6ba91506ce712/out\" \"-L\" \"/path/to/my/[project]/[user]/target/x86_64-apple-ios-macabi/release/build/blake3-74e6ba91506ce712/out\" \"-L\" \"/Users/[user]/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/x86_64-apple-ios-macabi/lib\" \"/var/folders/p8/qpmzbsdn07g5gxykwfxxw7y40000gn/T/rustci8tkvp/libblake3-343c1616c8f62c66.rlib\" \"/path/to/my/[project]/[user]/target/x86_64-apple-ios-macabi/release/deps/libcompiler_builtins-15d4f20b641cf9ef.rlib\" \"-framework\" \"Security\" \"-framework\" \"CoreFoundation\" \"-framework\" \"Security\" \"-liconv\" \"-lSystem\" \"-lobjc\" \"-framework\" \"Security\" \"-framework\" \"Foundation\" \"-lc\" \"-lm\" \"-isysroot\" \"/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.1.sdk\" \"-Wl,-syslibroot\" \"/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.1.sdk\" \"-L\" \"/Users/[user]/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/x86_64-apple-ios-macabi/lib\" \"-o\" \"/path/to/my/[project]/[user]/target/x86_64-apple-ios-macabi/release/deps/lib[user].dylib\" \"-Wl,-dead_strip\" \"-dynamiclib\" \"-Wl,-dylib\" \"-nodefaultlibs\"\n = note: clang: error: invalid version number in '-target x86_64-apple-ios13.0-macabi'\n\nwarning: `[user]` (lib) generated 6 warnings\nerror: could not compile `[user]` due to previous error; 6 warnings emitted\n```\n\n\n### Minimal example\n\nC code:\n\n```c\n#include \nvoid main() {\n int a = 1;\n int b = 2;\n int c = a + b;\n printf(\"%d\", c);\n}\n```\n\n`clang` command sample:\n\n```\n➜ 202301 clang -target x86_64-apple-ios13.0-macabi main.c\nclang: error: invalid version number in '-target x86_64-apple-ios13.0-macabi'\n➜ 202301 clang -target x86_64-apple-ios14.0-macabi main.c\nmain.c:2:1: warning: return type of 'main' is not 'int' [-Wmain-return-type]\nvoid main() {\n^\nmain.c:2:1: note: change return type to 'int'\nvoid main() {\n^~~~\nint\n1 warning generated.\n➜ 202301 clang -target x86_64-apple-ios15.0-macabi main.c\nmain.c:2:1: warning: return type of 'main' is not 'int' [-Wmain-return-type]\nvoid main() {\n^\nmain.c:2:1: note: change return type to 'int'\nvoid main() {\n^~~~\nint\n1 warning generated.\n➜ 202301 clang -target x86_64-apple-ios-macabi main.c\nmain.c:2:1: warning: return type of 'main' is not 'int' [-Wmain-return-type]\nvoid main() {\n^\nmain.c:2:1: note: change return type to 'int'\nvoid main() {\n^~~~\nint\n1 warning generated.\n\n➜ 202301 clang --version\nApple clang version 14.0.0 (clang-1400.0.29.202)\nTarget: arm64-apple-darwin22.2.0\nThread model: posix\nInstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin\n```\n\nThis PR is a simplified version of #96392, inspired by https://github.com/rust-lang/cc-rs/pull/727", + "tree": { + "sha": "0f1eba14a5ae3fa1c9c700ec5d1b07c0dab8b554", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/0f1eba14a5ae3fa1c9c700ec5d1b07c0dab8b554" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/821b2a8e39588fedda894d10b9b3abd7293f0383", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/821b2a8e39588fedda894d10b9b3abd7293f0383", + "node_id": "C_kwDOAAsO6NoAKDgyMWIyYThlMzk1ODhmZWRkYTg5NGQxMGI5YjNhYmQ3MjkzZjAzODM", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/131f0c6df6777800aa884963bdba0739299cd31f", + "sha": "131f0c6df6777800aa884963bdba0739299cd31f", + "url": "https://api.github.com/repos/rust-lang/rust/commits/131f0c6df6777800aa884963bdba0739299cd31f" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/5209d6f5fdac2054666a15c64f78450d6cb99717", + "sha": "5209d6f5fdac2054666a15c64f78450d6cb99717", + "url": "https://api.github.com/repos/rust-lang/rust/commits/5209d6f5fdac2054666a15c64f78450d6cb99717" + } + ], + "sha": "821b2a8e39588fedda894d10b9b3abd7293f0383", + "url": "https://api.github.com/repos/rust-lang/rust/commits/821b2a8e39588fedda894d10b9b3abd7293f0383" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/131f0c6df6777800aa884963bdba0739299cd31f/comments", + "commit": { + "author": { + "date": "2023-02-02T02:23:31Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-02T02:23:31Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #105670 - Xiretza:rustc_parse-diagnostics-4, r=davidtwco\n\nrustc_parse: diagnostics migration, v4\n\nThis is all the `rustc_parse` migrations I have in store right now; unfortunately life is pretty busy right now, so I won't be able to do much more in the near future.\n\ncc #100717\n\nr? `@davidtwco`", + "tree": { + "sha": "44543518d5568584010021497a2e187328bf9b06", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/44543518d5568584010021497a2e187328bf9b06" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/131f0c6df6777800aa884963bdba0739299cd31f", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/131f0c6df6777800aa884963bdba0739299cd31f", + "node_id": "C_kwDOAAsO6NoAKDEzMWYwYzZkZjY3Nzc4MDBhYTg4NDk2M2JkYmEwNzM5Mjk5Y2QzMWY", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/8789e5392975203137765d7818fb23ad125782b3", + "sha": "8789e5392975203137765d7818fb23ad125782b3", + "url": "https://api.github.com/repos/rust-lang/rust/commits/8789e5392975203137765d7818fb23ad125782b3" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/0d0d36991599d230d4781432391608f9821765fa", + "sha": "0d0d36991599d230d4781432391608f9821765fa", + "url": "https://api.github.com/repos/rust-lang/rust/commits/0d0d36991599d230d4781432391608f9821765fa" + } + ], + "sha": "131f0c6df6777800aa884963bdba0739299cd31f", + "url": "https://api.github.com/repos/rust-lang/rust/commits/131f0c6df6777800aa884963bdba0739299cd31f" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/8789e5392975203137765d7818fb23ad125782b3/comments", + "commit": { + "author": { + "date": "2023-02-01T22:45:27Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-01T22:45:27Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107574 - compiler-errors:back-to-old-mac-builders-pls, r=pietroalbini\n\nRevert \"switch to the macos-12-xl builder\"\n\nThis reverts commit fcbae989ae790d5b9a0a23ceba242d0b0d4e6c5b.\n\nThis should fix the bors failures in https://rust-lang.zulipchat.com/#narrow/stream/242791-t-infra/topic/Every.20rust-lang.2Frust.20PR.20is.20failing.20bors", + "tree": { + "sha": "68f1f608bda41a90ec8a74295dbc3deb7e6c783c", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/68f1f608bda41a90ec8a74295dbc3deb7e6c783c" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/8789e5392975203137765d7818fb23ad125782b3", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/8789e5392975203137765d7818fb23ad125782b3", + "node_id": "C_kwDOAAsO6NoAKDg3ODllNTM5Mjk3NTIwMzEzNzc2NWQ3ODE4ZmIyM2FkMTI1NzgyYjM", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/11d96b59307b1702fffe871bfc2d0145d070881e", + "sha": "11d96b59307b1702fffe871bfc2d0145d070881e", + "url": "https://api.github.com/repos/rust-lang/rust/commits/11d96b59307b1702fffe871bfc2d0145d070881e" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/e63ec2e1402eaff949e5c53b8f6062b152010fcc", + "sha": "e63ec2e1402eaff949e5c53b8f6062b152010fcc", + "url": "https://api.github.com/repos/rust-lang/rust/commits/e63ec2e1402eaff949e5c53b8f6062b152010fcc" + } + ], + "sha": "8789e5392975203137765d7818fb23ad125782b3", + "url": "https://api.github.com/repos/rust-lang/rust/commits/8789e5392975203137765d7818fb23ad125782b3" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/11d96b59307b1702fffe871bfc2d0145d070881e/comments", + "commit": { + "author": { + "date": "2023-02-01T11:37:24Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-01T11:37:24Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107257 - inquisitivecrystal:ffi-attr, r=davidtwco\n\nStrengthen validation of FFI attributes\n\nPreviously, `codegen_attrs` validated the attributes `#[ffi_pure]`, `#[ffi_const]`, and `#[ffi_returns_twice]` to make sure that they were only used on foreign functions. However, this validation was insufficient in two ways:\n\n1. `codegen_attrs` only sees items for which code must be generated, so it was unable to raise errors when the attribute was incorrectly applied to macros and the like.\n2. the validation code only checked that the item with the attr was foreign, but not that it was a foreign function, allowing these attributes to be applied to foreign statics as well.\n\nThis PR moves the validation to `check_attr`, which sees all items. It additionally changes the validation to ensure that the attribute's target is `Target::ForeignFunction`, only allowing the attributes on foreign functions and not foreign statics. Because these attributes are unstable, there is no risk for backwards compatibility. The changes also ending up making the code much easier to read.\n\nThis PR is best reviewed commit by commit. Additionally, I was considering moving the tests to the `attribute` subdirectory, to get them out of the general UI directory. I could do that as part of this PR or a follow-up, as the reviewer prefers.\n\nCC: #58328, #58329", + "tree": { + "sha": "af26139253d2807f229208f8301714afc803c306", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/af26139253d2807f229208f8301714afc803c306" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/11d96b59307b1702fffe871bfc2d0145d070881e", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/11d96b59307b1702fffe871bfc2d0145d070881e", + "node_id": "C_kwDOAAsO6NoAKDExZDk2YjU5MzA3YjE3MDJmZmZlODcxYmZjMmQwMTQ1ZDA3MDg4MWU", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/3b639486c17e9144a9176382ecb2a0b801263935", + "sha": "3b639486c17e9144a9176382ecb2a0b801263935", + "url": "https://api.github.com/repos/rust-lang/rust/commits/3b639486c17e9144a9176382ecb2a0b801263935" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/bc23e9aa4c78066043be246a47627746341480dd", + "sha": "bc23e9aa4c78066043be246a47627746341480dd", + "url": "https://api.github.com/repos/rust-lang/rust/commits/bc23e9aa4c78066043be246a47627746341480dd" + } + ], + "sha": "11d96b59307b1702fffe871bfc2d0145d070881e", + "url": "https://api.github.com/repos/rust-lang/rust/commits/11d96b59307b1702fffe871bfc2d0145d070881e" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/3b639486c17e9144a9176382ecb2a0b801263935/comments", + "commit": { + "author": { + "date": "2023-02-01T07:47:29Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-01T07:47:29Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107546 - matthiaskrgr:rollup-9rgf2gx, r=matthiaskrgr\n\nRollup of 6 pull requests\n\nSuccessful merges:\n\n - #107389 (Fixing confusion between mod and remainder)\n - #107442 (improve panic message for slice windows and chunks)\n - #107470 (Small bootstrap improvements)\n - #107487 (Make the \"extra if in let...else block\" hint a suggestion)\n - #107499 (Do not depend on Generator trait when deducing closure signature)\n - #107533 (Extend `-Z print-type-sizes` to distinguish generator upvars+locals from \"normal\" fields.)\n\nFailed merges:\n\nr? `@ghost`\n`@rustbot` modify labels: rollup", + "tree": { + "sha": "7a062a4c43bf11d1fa11b1efdfd496d8a6f40d78", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/7a062a4c43bf11d1fa11b1efdfd496d8a6f40d78" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/3b639486c17e9144a9176382ecb2a0b801263935", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/3b639486c17e9144a9176382ecb2a0b801263935", + "node_id": "C_kwDOAAsO6NoAKDNiNjM5NDg2YzE3ZTkxNDRhOTE3NjM4MmVjYjJhMGI4MDEyNjM5MzU", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/0d32c8f2ce10710b6560dcb75f32f79c378410d0", + "sha": "0d32c8f2ce10710b6560dcb75f32f79c378410d0", + "url": "https://api.github.com/repos/rust-lang/rust/commits/0d32c8f2ce10710b6560dcb75f32f79c378410d0" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/f41f154dfbe2aa943e35a21c0e2a8de002443424", + "sha": "f41f154dfbe2aa943e35a21c0e2a8de002443424", + "url": "https://api.github.com/repos/rust-lang/rust/commits/f41f154dfbe2aa943e35a21c0e2a8de002443424" + } + ], + "sha": "3b639486c17e9144a9176382ecb2a0b801263935", + "url": "https://api.github.com/repos/rust-lang/rust/commits/3b639486c17e9144a9176382ecb2a0b801263935" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/0d32c8f2ce10710b6560dcb75f32f79c378410d0/comments", + "commit": { + "author": { + "date": "2023-02-01T04:53:29Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-01T04:53:29Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107541 - weihanglo:update-cargo, r=weihanglo\n\nUpdate cargo\n\n18 commits in 3c5af6bed9a1a243a693e8e22ee2486bd5b82a6c..e84a7928d93a31f284b497c214a2ece69b4d7719 2023-01-24 15:48:15 +0000 to 2023-01-31 22:18:09 +0000\n\n- chore: Add autolabel for `Command-*` labels (rust-lang/cargo#11664)\n- Update cross test instructions for aarch64-apple-darwin (rust-lang/cargo#11663)\n- Make cargo install report needed features (rust-lang/cargo#11647)\n- docs(contrib): Remove out-of-date process step (rust-lang/cargo#11662)\n- Do not error for `auth-required: true` without `-Z sparse-registry` (rust-lang/cargo#11661)\n- Warn on commits to non-default branches. (rust-lang/cargo#11655)\n- Avoid saving the same future_incompat warning multiple times (rust-lang/cargo#11648)\n- Mention current default value in `publish.timeout` docs (rust-lang/cargo#11652)\n- Make cargo aware of dwp files. (rust-lang/cargo#11572)\n- Reduce target info rustc query calls (rust-lang/cargo#11633)\n- Bump to 0.70.0; update changelog (rust-lang/cargo#11640)\n- Enable sparse protocol in CI (rust-lang/cargo#11632)\n- Fix split-debuginfo support detection (rust-lang/cargo#11347)\n- refactor(toml): Move `TomlWorkspaceDependency` out of `TomlDependency` (rust-lang/cargo#11565)\n- book: describe how the current resolver sometimes duplicates deps (rust-lang/cargo#11604)\n- `cargo add` check `[dependencies]` order without considering the dotted item (rust-lang/cargo#11612)\n- Link CoC to www.rust-lang.org/conduct.html (rust-lang/cargo#11622)\n- Add more labels to triagebot (rust-lang/cargo#11621)\n\nr? `@ghost`", + "tree": { + "sha": "9e08bab8c2e9b024e7ce120ed0c1fa7bbea9c463", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/9e08bab8c2e9b024e7ce120ed0c1fa7bbea9c463" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/0d32c8f2ce10710b6560dcb75f32f79c378410d0", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/0d32c8f2ce10710b6560dcb75f32f79c378410d0", + "node_id": "C_kwDOAAsO6NoAKDBkMzJjOGYyY2UxMDcxMGI2NTYwZGNiNzVmMzJmNzljMzc4NDEwZDA", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/ad8e1dc2863f63c35ef3ceef3064d0851a1d2582", + "sha": "ad8e1dc2863f63c35ef3ceef3064d0851a1d2582", + "url": "https://api.github.com/repos/rust-lang/rust/commits/ad8e1dc2863f63c35ef3ceef3064d0851a1d2582" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/bb2af4f28ca89b5088db433645f9e61f03c9ac2c", + "sha": "bb2af4f28ca89b5088db433645f9e61f03c9ac2c", + "url": "https://api.github.com/repos/rust-lang/rust/commits/bb2af4f28ca89b5088db433645f9e61f03c9ac2c" + } + ], + "sha": "0d32c8f2ce10710b6560dcb75f32f79c378410d0", + "url": "https://api.github.com/repos/rust-lang/rust/commits/0d32c8f2ce10710b6560dcb75f32f79c378410d0" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/ad8e1dc2863f63c35ef3ceef3064d0851a1d2582/comments", + "commit": { + "author": { + "date": "2023-02-01T01:15:02Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-01T01:15:02Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107536 - GuillaumeGomez:rollup-xv7dx2h, r=GuillaumeGomez\n\nRollup of 12 pull requests\n\nSuccessful merges:\n\n - #106898 (Include both md and yaml ICE ticket templates)\n - #107331 (Clean up eslint annotations and remove unused JS function)\n - #107348 (small refactor to new projection code)\n - #107354 (rustdoc: update Source Serif 4 from 4.004 to 4.005)\n - #107412 (avoid needless checks)\n - #107467 (Improve enum checks)\n - #107486 (Track bound types like bound regions)\n - #107491 (rustdoc: remove unused CSS from `.setting-check`)\n - #107508 (`Edition` micro refactor)\n - #107525 (PointeeInfo is advisory only)\n - #107527 (rustdoc: stop making unstable items transparent)\n - #107535 (Replace unwrap with ? in TcpListener doc)\n\nFailed merges:\n\nr? `@ghost`\n`@rustbot` modify labels: rollup", + "tree": { + "sha": "64d8db18dc8c8e118fd859c74061a34efbcae9d4", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/64d8db18dc8c8e118fd859c74061a34efbcae9d4" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/ad8e1dc2863f63c35ef3ceef3064d0851a1d2582", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/ad8e1dc2863f63c35ef3ceef3064d0851a1d2582", + "node_id": "C_kwDOAAsO6NoAKGFkOGUxZGMyODYzZjYzYzM1ZWYzY2VlZjMwNjRkMDg1MWExZDI1ODI", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/5b6ed253c42a69b93e7447fb0874a89ab6bc1cfb", + "sha": "5b6ed253c42a69b93e7447fb0874a89ab6bc1cfb", + "url": "https://api.github.com/repos/rust-lang/rust/commits/5b6ed253c42a69b93e7447fb0874a89ab6bc1cfb" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/adc3f8a44b943463577a5f8870da8fd18b749351", + "sha": "adc3f8a44b943463577a5f8870da8fd18b749351", + "url": "https://api.github.com/repos/rust-lang/rust/commits/adc3f8a44b943463577a5f8870da8fd18b749351" + } + ], + "sha": "ad8e1dc2863f63c35ef3ceef3064d0851a1d2582", + "url": "https://api.github.com/repos/rust-lang/rust/commits/ad8e1dc2863f63c35ef3ceef3064d0851a1d2582" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/5b6ed253c42a69b93e7447fb0874a89ab6bc1cfb/comments", + "commit": { + "author": { + "date": "2023-01-31T22:34:26Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-01-31T22:34:26Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #102513 - RalfJung:no-more-unaligned-reference, r=cjgillot,scottmcm\n\nmake unaligned_reference a hard error\n\nThe `unaligned_references` lint has been warn-by-default since Rust 1.53 (https://github.com/rust-lang/rust/pull/82525) and deny-by-default with mention in cargo future-incompat reports since Rust 1.62 (https://github.com/rust-lang/rust/pull/95372). Current nightly will become Rust 1.66, so (unless major surprises show up with crater) I think it is time we make this a hard error, and close this old soundness gap in the language.\n\nEDIT: Turns out this will only land for Rust 1.67, so there is another 6 weeks of time here for crates to adjust.\n\nFixes https://github.com/rust-lang/rust/issues/82523.", + "tree": { + "sha": "ba7e23c105713658431c3101d22977d8282e397f", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/ba7e23c105713658431c3101d22977d8282e397f" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/5b6ed253c42a69b93e7447fb0874a89ab6bc1cfb", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/5b6ed253c42a69b93e7447fb0874a89ab6bc1cfb", + "node_id": "C_kwDOAAsO6NoAKDViNmVkMjUzYzQyYTY5YjkzZTc0NDdmYjA4NzRhODlhYjZiYzFjZmI", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/dc1d9d50fba2f6a1ccab8748a0050cde38253f60", + "sha": "dc1d9d50fba2f6a1ccab8748a0050cde38253f60", + "url": "https://api.github.com/repos/rust-lang/rust/commits/dc1d9d50fba2f6a1ccab8748a0050cde38253f60" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/dfc4a7b2d02528f246e455f587605cce224bb99c", + "sha": "dfc4a7b2d02528f246e455f587605cce224bb99c", + "url": "https://api.github.com/repos/rust-lang/rust/commits/dfc4a7b2d02528f246e455f587605cce224bb99c" + } + ], + "sha": "5b6ed253c42a69b93e7447fb0874a89ab6bc1cfb", + "url": "https://api.github.com/repos/rust-lang/rust/commits/5b6ed253c42a69b93e7447fb0874a89ab6bc1cfb" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/dc1d9d50fba2f6a1ccab8748a0050cde38253f60/comments", + "commit": { + "author": { + "date": "2023-01-31T19:24:29Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-01-31T19:24:29Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107297 - Mark-Simulacrum:bump-bootstrap, r=pietroalbini\n\nBump bootstrap compiler to 1.68\n\nThis also changes our stage0.json to include the rustc component for the rustfmt pinned nightly toolchain, which is currently necessary due to rustfmt dynamically linking to that toolchain's librustc_driver and libstd.\n\nr? `@pietroalbini`", + "tree": { + "sha": "1497db582bb148e212d04fb4acc229d85aff2617", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/1497db582bb148e212d04fb4acc229d85aff2617" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/dc1d9d50fba2f6a1ccab8748a0050cde38253f60", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/dc1d9d50fba2f6a1ccab8748a0050cde38253f60", + "node_id": "C_kwDOAAsO6NoAKGRjMWQ5ZDUwZmJhMmY2YTFjY2FiODc0OGEwMDUwY2RlMzgyNTNmNjA", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/f361413cbf44ce2f144df59fc440cd484af4a56e", + "sha": "f361413cbf44ce2f144df59fc440cd484af4a56e", + "url": "https://api.github.com/repos/rust-lang/rust/commits/f361413cbf44ce2f144df59fc440cd484af4a56e" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/652f79e83543eab07c33840748cf5df37b42ac66", + "sha": "652f79e83543eab07c33840748cf5df37b42ac66", + "url": "https://api.github.com/repos/rust-lang/rust/commits/652f79e83543eab07c33840748cf5df37b42ac66" + } + ], + "sha": "dc1d9d50fba2f6a1ccab8748a0050cde38253f60", + "url": "https://api.github.com/repos/rust-lang/rust/commits/dc1d9d50fba2f6a1ccab8748a0050cde38253f60" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/f361413cbf44ce2f144df59fc440cd484af4a56e/comments", + "commit": { + "author": { + "date": "2023-01-31T13:53:40Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-01-31T13:53:40Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #106399 - estebank:type-err-span-label, r=nagisa\n\nModify primary span label for E0308\n\nLooking at the reactions to https://hachyderm.io/`@ekuber/109622160673605438,` a lot of people seem to have trouble understanding the current output, where the primary span label on type errors talks about the specific types that diverged, but these can be deeply nested type parameters. Because of that we could see \"expected i32, found u32\" in the label while the note said \"expected Vec, found Vec\". This understandably confuses people. I believe that once people learn to read these errors it starts to make more sense, but this PR changes the output to be more in line with what people might expect, without sacrificing terseness.\n\nFix #68220.", + "tree": { + "sha": "cecf91d94ee20df2d6bec7c88796b90fa34f9887", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/cecf91d94ee20df2d6bec7c88796b90fa34f9887" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/f361413cbf44ce2f144df59fc440cd484af4a56e", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/f361413cbf44ce2f144df59fc440cd484af4a56e", + "node_id": "C_kwDOAAsO6NoAKGYzNjE0MTNjYmY0NGNlMmYxNDRkZjU5ZmM0NDBjZDQ4NGFmNGE1NmU", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/a64ef7d07d0411315be85a646586cb85eeb9c136", + "sha": "a64ef7d07d0411315be85a646586cb85eeb9c136", + "url": "https://api.github.com/repos/rust-lang/rust/commits/a64ef7d07d0411315be85a646586cb85eeb9c136" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/449dfc64f0792f2320ef68bc08f238281199f53d", + "sha": "449dfc64f0792f2320ef68bc08f238281199f53d", + "url": "https://api.github.com/repos/rust-lang/rust/commits/449dfc64f0792f2320ef68bc08f238281199f53d" + } + ], + "sha": "f361413cbf44ce2f144df59fc440cd484af4a56e", + "url": "https://api.github.com/repos/rust-lang/rust/commits/f361413cbf44ce2f144df59fc440cd484af4a56e" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/a64ef7d07d0411315be85a646586cb85eeb9c136/comments", + "commit": { + "author": { + "date": "2023-01-31T10:20:58Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-01-31T10:20:58Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #100754 - davidtwco:translation-incremental, r=compiler-errors\n\nincremental: migrate diagnostics\n\n- Apply the diagnostic migration lints to more functions on `Session`, namely: `span_warn`, `span_warn_with_code`, `warn` `note_without_error`, `span_note_without_error`, `struct_note_without_error`.\n- Add impls of `IntoDiagnosticArg` for `std::io::Error`, `std::path::Path` and `std::path::PathBuf`.\n- Migrate the `rustc_incremental` crate's diagnostics to translatable diagnostic structs.\n\nr? `@compiler-errors`\ncc #100717", + "tree": { + "sha": "e4b006e2f97095541ee5ff8b1beab16675e5eb86", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/e4b006e2f97095541ee5ff8b1beab16675e5eb86" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/a64ef7d07d0411315be85a646586cb85eeb9c136", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/a64ef7d07d0411315be85a646586cb85eeb9c136", + "node_id": "C_kwDOAAsO6NoAKGE2NGVmN2QwN2QwNDExMzE1YmU4NWE2NDY1ODZjYjg1ZWViOWMxMzY", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/7c4a9a971ca6962533bed01ffbd0c1f6b5250abc", + "sha": "7c4a9a971ca6962533bed01ffbd0c1f6b5250abc", + "url": "https://api.github.com/repos/rust-lang/rust/commits/7c4a9a971ca6962533bed01ffbd0c1f6b5250abc" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/2ff46641a92c27a32db3e0dc94ae86295e6c3277", + "sha": "2ff46641a92c27a32db3e0dc94ae86295e6c3277", + "url": "https://api.github.com/repos/rust-lang/rust/commits/2ff46641a92c27a32db3e0dc94ae86295e6c3277" + } + ], + "sha": "a64ef7d07d0411315be85a646586cb85eeb9c136", + "url": "https://api.github.com/repos/rust-lang/rust/commits/a64ef7d07d0411315be85a646586cb85eeb9c136" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/7c4a9a971ca6962533bed01ffbd0c1f6b5250abc/comments", + "commit": { + "author": { + "date": "2023-01-31T06:25:30Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-01-31T06:25:30Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107498 - JohnTitor:rollup-2i6g4uk, r=JohnTitor\n\nRollup of 8 pull requests\n\nSuccessful merges:\n\n - #107245 (Implement unsizing in the new trait solver)\n - #107445 (Remove `GenFuture` from core)\n - #107473 (Update books)\n - #107476 (rustdoc: remove unnecessary wrapper `div.item-decl` from HTML)\n - #107477 (Migrate last part of CSS themes to CSS variables)\n - #107479 (Use `ObligationCtxt::new_in_snapshot` in `satisfied_from_param_env`)\n - #107482 (rustdoc: remove meta keywords from HTML)\n - #107494 (fix link in std::path::Path::display())\n\nFailed merges:\n\nr? `@ghost`\n`@rustbot` modify labels: rollup", + "tree": { + "sha": "904e6bf143781822be126e176f256545da3767dd", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/904e6bf143781822be126e176f256545da3767dd" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/7c4a9a971ca6962533bed01ffbd0c1f6b5250abc", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/7c4a9a971ca6962533bed01ffbd0c1f6b5250abc", + "node_id": "C_kwDOAAsO6NoAKDdjNGE5YTk3MWNhNjk2MjUzM2JlZDAxZmZiZDBjMWY2YjUyNTBhYmM", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/dc3e59cb3fe05ebd752d3a2269f501c00327be22", + "sha": "dc3e59cb3fe05ebd752d3a2269f501c00327be22", + "url": "https://api.github.com/repos/rust-lang/rust/commits/dc3e59cb3fe05ebd752d3a2269f501c00327be22" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/150340bafdcd48becbe612a0d4d5631efe23621c", + "sha": "150340bafdcd48becbe612a0d4d5631efe23621c", + "url": "https://api.github.com/repos/rust-lang/rust/commits/150340bafdcd48becbe612a0d4d5631efe23621c" + } + ], + "sha": "7c4a9a971ca6962533bed01ffbd0c1f6b5250abc", + "url": "https://api.github.com/repos/rust-lang/rust/commits/7c4a9a971ca6962533bed01ffbd0c1f6b5250abc" + } + ] +} diff --git a/tests/github_client/create_commit/00-GET-repos_ehuss_rust.json b/tests/github_client/create_commit/00-GET-repos_ehuss_rust.json new file mode 100644 index 00000000..2e719ca7 --- /dev/null +++ b/tests/github_client/create_commit/00-GET-repos_ehuss_rust.json @@ -0,0 +1,365 @@ +{ + "kind": "Request", + "method": "GET", + "path": "/repos/ehuss/rust", + "query": null, + "request_body": "", + "response_code": 200, + "response_body": { + "allow_auto_merge": false, + "allow_forking": true, + "allow_merge_commit": true, + "allow_rebase_merge": true, + "allow_squash_merge": true, + "allow_update_branch": false, + "archive_url": "https://api.github.com/repos/ehuss/rust/{archive_format}{/ref}", + "archived": false, + "assignees_url": "https://api.github.com/repos/ehuss/rust/assignees{/user}", + "blobs_url": "https://api.github.com/repos/ehuss/rust/git/blobs{/sha}", + "branches_url": "https://api.github.com/repos/ehuss/rust/branches{/branch}", + "clone_url": "https://github.com/ehuss/rust.git", + "collaborators_url": "https://api.github.com/repos/ehuss/rust/collaborators{/collaborator}", + "comments_url": "https://api.github.com/repos/ehuss/rust/comments{/number}", + "commits_url": "https://api.github.com/repos/ehuss/rust/commits{/sha}", + "compare_url": "https://api.github.com/repos/ehuss/rust/compare/{base}...{head}", + "contents_url": "https://api.github.com/repos/ehuss/rust/contents/{+path}", + "contributors_url": "https://api.github.com/repos/ehuss/rust/contributors", + "created_at": "2018-01-14T20:35:48Z", + "default_branch": "master", + "delete_branch_on_merge": false, + "deployments_url": "https://api.github.com/repos/ehuss/rust/deployments", + "description": "A safe, concurrent, practical language.", + "disabled": false, + "downloads_url": "https://api.github.com/repos/ehuss/rust/downloads", + "events_url": "https://api.github.com/repos/ehuss/rust/events", + "fork": true, + "forks": 0, + "forks_count": 0, + "forks_url": "https://api.github.com/repos/ehuss/rust/forks", + "full_name": "ehuss/rust", + "git_commits_url": "https://api.github.com/repos/ehuss/rust/git/commits{/sha}", + "git_refs_url": "https://api.github.com/repos/ehuss/rust/git/refs{/sha}", + "git_tags_url": "https://api.github.com/repos/ehuss/rust/git/tags{/sha}", + "git_url": "git://github.com/ehuss/rust.git", + "has_discussions": false, + "has_downloads": true, + "has_issues": false, + "has_pages": false, + "has_projects": true, + "has_wiki": false, + "homepage": "https://www.rust-lang.org", + "hooks_url": "https://api.github.com/repos/ehuss/rust/hooks", + "html_url": "https://github.com/ehuss/rust", + "id": 117464625, + "is_template": false, + "issue_comment_url": "https://api.github.com/repos/ehuss/rust/issues/comments{/number}", + "issue_events_url": "https://api.github.com/repos/ehuss/rust/issues/events{/number}", + "issues_url": "https://api.github.com/repos/ehuss/rust/issues{/number}", + "keys_url": "https://api.github.com/repos/ehuss/rust/keys{/key_id}", + "labels_url": "https://api.github.com/repos/ehuss/rust/labels{/name}", + "language": "Rust", + "languages_url": "https://api.github.com/repos/ehuss/rust/languages", + "license": { + "key": "other", + "name": "Other", + "node_id": "MDc6TGljZW5zZTA=", + "spdx_id": "NOASSERTION", + "url": null + }, + "merge_commit_message": "PR_TITLE", + "merge_commit_title": "MERGE_MESSAGE", + "merges_url": "https://api.github.com/repos/ehuss/rust/merges", + "milestones_url": "https://api.github.com/repos/ehuss/rust/milestones{/number}", + "mirror_url": null, + "name": "rust", + "network_count": 10326, + "node_id": "MDEwOlJlcG9zaXRvcnkxMTc0NjQ2MjU=", + "notifications_url": "https://api.github.com/repos/ehuss/rust/notifications{?since,all,participating}", + "open_issues": 0, + "open_issues_count": 0, + "owner": { + "avatar_url": "https://avatars.githubusercontent.com/u/43198?v=4", + "events_url": "https://api.github.com/users/ehuss/events{/privacy}", + "followers_url": "https://api.github.com/users/ehuss/followers", + "following_url": "https://api.github.com/users/ehuss/following{/other_user}", + "gists_url": "https://api.github.com/users/ehuss/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/ehuss", + "id": 43198, + "login": "ehuss", + "node_id": "MDQ6VXNlcjQzMTk4", + "organizations_url": "https://api.github.com/users/ehuss/orgs", + "received_events_url": "https://api.github.com/users/ehuss/received_events", + "repos_url": "https://api.github.com/users/ehuss/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/ehuss/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ehuss/subscriptions", + "type": "User", + "url": "https://api.github.com/users/ehuss" + }, + "parent": { + "allow_forking": true, + "archive_url": "https://api.github.com/repos/rust-lang/rust/{archive_format}{/ref}", + "archived": false, + "assignees_url": "https://api.github.com/repos/rust-lang/rust/assignees{/user}", + "blobs_url": "https://api.github.com/repos/rust-lang/rust/git/blobs{/sha}", + "branches_url": "https://api.github.com/repos/rust-lang/rust/branches{/branch}", + "clone_url": "https://github.com/rust-lang/rust.git", + "collaborators_url": "https://api.github.com/repos/rust-lang/rust/collaborators{/collaborator}", + "comments_url": "https://api.github.com/repos/rust-lang/rust/comments{/number}", + "commits_url": "https://api.github.com/repos/rust-lang/rust/commits{/sha}", + "compare_url": "https://api.github.com/repos/rust-lang/rust/compare/{base}...{head}", + "contents_url": "https://api.github.com/repos/rust-lang/rust/contents/{+path}", + "contributors_url": "https://api.github.com/repos/rust-lang/rust/contributors", + "created_at": "2010-06-16T20:39:03Z", + "default_branch": "master", + "deployments_url": "https://api.github.com/repos/rust-lang/rust/deployments", + "description": "Empowering everyone to build reliable and efficient software.", + "disabled": false, + "downloads_url": "https://api.github.com/repos/rust-lang/rust/downloads", + "events_url": "https://api.github.com/repos/rust-lang/rust/events", + "fork": false, + "forks": 10326, + "forks_count": 10326, + "forks_url": "https://api.github.com/repos/rust-lang/rust/forks", + "full_name": "rust-lang/rust", + "git_commits_url": "https://api.github.com/repos/rust-lang/rust/git/commits{/sha}", + "git_refs_url": "https://api.github.com/repos/rust-lang/rust/git/refs{/sha}", + "git_tags_url": "https://api.github.com/repos/rust-lang/rust/git/tags{/sha}", + "git_url": "git://github.com/rust-lang/rust.git", + "has_discussions": false, + "has_downloads": true, + "has_issues": true, + "has_pages": false, + "has_projects": true, + "has_wiki": false, + "homepage": "https://www.rust-lang.org", + "hooks_url": "https://api.github.com/repos/rust-lang/rust/hooks", + "html_url": "https://github.com/rust-lang/rust", + "id": 724712, + "is_template": false, + "issue_comment_url": "https://api.github.com/repos/rust-lang/rust/issues/comments{/number}", + "issue_events_url": "https://api.github.com/repos/rust-lang/rust/issues/events{/number}", + "issues_url": "https://api.github.com/repos/rust-lang/rust/issues{/number}", + "keys_url": "https://api.github.com/repos/rust-lang/rust/keys{/key_id}", + "labels_url": "https://api.github.com/repos/rust-lang/rust/labels{/name}", + "language": "Rust", + "languages_url": "https://api.github.com/repos/rust-lang/rust/languages", + "license": { + "key": "other", + "name": "Other", + "node_id": "MDc6TGljZW5zZTA=", + "spdx_id": "NOASSERTION", + "url": null + }, + "merges_url": "https://api.github.com/repos/rust-lang/rust/merges", + "milestones_url": "https://api.github.com/repos/rust-lang/rust/milestones{/number}", + "mirror_url": null, + "name": "rust", + "node_id": "MDEwOlJlcG9zaXRvcnk3MjQ3MTI=", + "notifications_url": "https://api.github.com/repos/rust-lang/rust/notifications{?since,all,participating}", + "open_issues": 9513, + "open_issues_count": 9513, + "owner": { + "avatar_url": "https://avatars.githubusercontent.com/u/5430905?v=4", + "events_url": "https://api.github.com/users/rust-lang/events{/privacy}", + "followers_url": "https://api.github.com/users/rust-lang/followers", + "following_url": "https://api.github.com/users/rust-lang/following{/other_user}", + "gists_url": "https://api.github.com/users/rust-lang/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/rust-lang", + "id": 5430905, + "login": "rust-lang", + "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MzA5MDU=", + "organizations_url": "https://api.github.com/users/rust-lang/orgs", + "received_events_url": "https://api.github.com/users/rust-lang/received_events", + "repos_url": "https://api.github.com/users/rust-lang/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/rust-lang/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rust-lang/subscriptions", + "type": "Organization", + "url": "https://api.github.com/users/rust-lang" + }, + "private": false, + "pulls_url": "https://api.github.com/repos/rust-lang/rust/pulls{/number}", + "pushed_at": "2023-02-05T18:16:26Z", + "releases_url": "https://api.github.com/repos/rust-lang/rust/releases{/id}", + "size": 1066392, + "ssh_url": "git@github.com:rust-lang/rust.git", + "stargazers_count": 77401, + "stargazers_url": "https://api.github.com/repos/rust-lang/rust/stargazers", + "statuses_url": "https://api.github.com/repos/rust-lang/rust/statuses/{sha}", + "subscribers_url": "https://api.github.com/repos/rust-lang/rust/subscribers", + "subscription_url": "https://api.github.com/repos/rust-lang/rust/subscription", + "svn_url": "https://github.com/rust-lang/rust", + "tags_url": "https://api.github.com/repos/rust-lang/rust/tags", + "teams_url": "https://api.github.com/repos/rust-lang/rust/teams", + "topics": [ + "compiler", + "hacktoberfest", + "language", + "rust" + ], + "trees_url": "https://api.github.com/repos/rust-lang/rust/git/trees{/sha}", + "updated_at": "2023-02-05T17:54:34Z", + "url": "https://api.github.com/repos/rust-lang/rust", + "visibility": "public", + "watchers": 77401, + "watchers_count": 77401, + "web_commit_signoff_required": false + }, + "permissions": { + "admin": true, + "maintain": true, + "pull": true, + "push": true, + "triage": true + }, + "private": false, + "pulls_url": "https://api.github.com/repos/ehuss/rust/pulls{/number}", + "pushed_at": "2023-02-05T19:01:28Z", + "releases_url": "https://api.github.com/repos/ehuss/rust/releases{/id}", + "security_and_analysis": { + "secret_scanning": { + "status": "disabled" + }, + "secret_scanning_push_protection": { + "status": "disabled" + } + }, + "size": 1054343, + "source": { + "allow_forking": true, + "archive_url": "https://api.github.com/repos/rust-lang/rust/{archive_format}{/ref}", + "archived": false, + "assignees_url": "https://api.github.com/repos/rust-lang/rust/assignees{/user}", + "blobs_url": "https://api.github.com/repos/rust-lang/rust/git/blobs{/sha}", + "branches_url": "https://api.github.com/repos/rust-lang/rust/branches{/branch}", + "clone_url": "https://github.com/rust-lang/rust.git", + "collaborators_url": "https://api.github.com/repos/rust-lang/rust/collaborators{/collaborator}", + "comments_url": "https://api.github.com/repos/rust-lang/rust/comments{/number}", + "commits_url": "https://api.github.com/repos/rust-lang/rust/commits{/sha}", + "compare_url": "https://api.github.com/repos/rust-lang/rust/compare/{base}...{head}", + "contents_url": "https://api.github.com/repos/rust-lang/rust/contents/{+path}", + "contributors_url": "https://api.github.com/repos/rust-lang/rust/contributors", + "created_at": "2010-06-16T20:39:03Z", + "default_branch": "master", + "deployments_url": "https://api.github.com/repos/rust-lang/rust/deployments", + "description": "Empowering everyone to build reliable and efficient software.", + "disabled": false, + "downloads_url": "https://api.github.com/repos/rust-lang/rust/downloads", + "events_url": "https://api.github.com/repos/rust-lang/rust/events", + "fork": false, + "forks": 10326, + "forks_count": 10326, + "forks_url": "https://api.github.com/repos/rust-lang/rust/forks", + "full_name": "rust-lang/rust", + "git_commits_url": "https://api.github.com/repos/rust-lang/rust/git/commits{/sha}", + "git_refs_url": "https://api.github.com/repos/rust-lang/rust/git/refs{/sha}", + "git_tags_url": "https://api.github.com/repos/rust-lang/rust/git/tags{/sha}", + "git_url": "git://github.com/rust-lang/rust.git", + "has_discussions": false, + "has_downloads": true, + "has_issues": true, + "has_pages": false, + "has_projects": true, + "has_wiki": false, + "homepage": "https://www.rust-lang.org", + "hooks_url": "https://api.github.com/repos/rust-lang/rust/hooks", + "html_url": "https://github.com/rust-lang/rust", + "id": 724712, + "is_template": false, + "issue_comment_url": "https://api.github.com/repos/rust-lang/rust/issues/comments{/number}", + "issue_events_url": "https://api.github.com/repos/rust-lang/rust/issues/events{/number}", + "issues_url": "https://api.github.com/repos/rust-lang/rust/issues{/number}", + "keys_url": "https://api.github.com/repos/rust-lang/rust/keys{/key_id}", + "labels_url": "https://api.github.com/repos/rust-lang/rust/labels{/name}", + "language": "Rust", + "languages_url": "https://api.github.com/repos/rust-lang/rust/languages", + "license": { + "key": "other", + "name": "Other", + "node_id": "MDc6TGljZW5zZTA=", + "spdx_id": "NOASSERTION", + "url": null + }, + "merges_url": "https://api.github.com/repos/rust-lang/rust/merges", + "milestones_url": "https://api.github.com/repos/rust-lang/rust/milestones{/number}", + "mirror_url": null, + "name": "rust", + "node_id": "MDEwOlJlcG9zaXRvcnk3MjQ3MTI=", + "notifications_url": "https://api.github.com/repos/rust-lang/rust/notifications{?since,all,participating}", + "open_issues": 9513, + "open_issues_count": 9513, + "owner": { + "avatar_url": "https://avatars.githubusercontent.com/u/5430905?v=4", + "events_url": "https://api.github.com/users/rust-lang/events{/privacy}", + "followers_url": "https://api.github.com/users/rust-lang/followers", + "following_url": "https://api.github.com/users/rust-lang/following{/other_user}", + "gists_url": "https://api.github.com/users/rust-lang/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/rust-lang", + "id": 5430905, + "login": "rust-lang", + "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MzA5MDU=", + "organizations_url": "https://api.github.com/users/rust-lang/orgs", + "received_events_url": "https://api.github.com/users/rust-lang/received_events", + "repos_url": "https://api.github.com/users/rust-lang/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/rust-lang/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rust-lang/subscriptions", + "type": "Organization", + "url": "https://api.github.com/users/rust-lang" + }, + "private": false, + "pulls_url": "https://api.github.com/repos/rust-lang/rust/pulls{/number}", + "pushed_at": "2023-02-05T18:16:26Z", + "releases_url": "https://api.github.com/repos/rust-lang/rust/releases{/id}", + "size": 1066392, + "ssh_url": "git@github.com:rust-lang/rust.git", + "stargazers_count": 77401, + "stargazers_url": "https://api.github.com/repos/rust-lang/rust/stargazers", + "statuses_url": "https://api.github.com/repos/rust-lang/rust/statuses/{sha}", + "subscribers_url": "https://api.github.com/repos/rust-lang/rust/subscribers", + "subscription_url": "https://api.github.com/repos/rust-lang/rust/subscription", + "svn_url": "https://github.com/rust-lang/rust", + "tags_url": "https://api.github.com/repos/rust-lang/rust/tags", + "teams_url": "https://api.github.com/repos/rust-lang/rust/teams", + "topics": [ + "compiler", + "hacktoberfest", + "language", + "rust" + ], + "trees_url": "https://api.github.com/repos/rust-lang/rust/git/trees{/sha}", + "updated_at": "2023-02-05T17:54:34Z", + "url": "https://api.github.com/repos/rust-lang/rust", + "visibility": "public", + "watchers": 77401, + "watchers_count": 77401, + "web_commit_signoff_required": false + }, + "squash_merge_commit_message": "COMMIT_MESSAGES", + "squash_merge_commit_title": "COMMIT_OR_PR_TITLE", + "ssh_url": "git@github.com:ehuss/rust.git", + "stargazers_count": 0, + "stargazers_url": "https://api.github.com/repos/ehuss/rust/stargazers", + "statuses_url": "https://api.github.com/repos/ehuss/rust/statuses/{sha}", + "subscribers_count": 0, + "subscribers_url": "https://api.github.com/repos/ehuss/rust/subscribers", + "subscription_url": "https://api.github.com/repos/ehuss/rust/subscription", + "svn_url": "https://github.com/ehuss/rust", + "tags_url": "https://api.github.com/repos/ehuss/rust/tags", + "teams_url": "https://api.github.com/repos/ehuss/rust/teams", + "temp_clone_token": "", + "topics": [], + "trees_url": "https://api.github.com/repos/ehuss/rust/git/trees{/sha}", + "updated_at": "2021-11-03T23:44:04Z", + "url": "https://api.github.com/repos/ehuss/rust", + "use_squash_pr_title_as_default": false, + "visibility": "public", + "watchers": 0, + "watchers_count": 0, + "web_commit_signoff_required": false + } +} diff --git a/tests/github_client/create_commit/01-POST-repos_ehuss_rust_git_commits.json b/tests/github_client/create_commit/01-POST-repos_ehuss_rust_git_commits.json new file mode 100644 index 00000000..08cc813f --- /dev/null +++ b/tests/github_client/create_commit/01-POST-repos_ehuss_rust_git_commits.json @@ -0,0 +1,42 @@ +{ + "kind": "Request", + "method": "POST", + "path": "/repos/ehuss/rust/git/commits", + "query": null, + "request_body": "{\"message\":\"test reference commit\",\"parents\":[\"319b88c463fe6f51bb6badbbd3bb97252a60f3a5\"],\"tree\":\"45aae523b087e418f2778d4557489de38fede6a3\"}", + "response_code": 201, + "response_body": { + "author": { + "date": "2023-02-05T19:08:57Z", + "email": "eric@huss.org", + "name": "Eric Huss" + }, + "committer": { + "date": "2023-02-05T19:08:57Z", + "email": "eric@huss.org", + "name": "Eric Huss" + }, + "html_url": "https://github.com/ehuss/rust/commit/88a426017fa4635ba42203c3b1d1c19f6a028184", + "message": "test reference commit", + "node_id": "C_kwDOBwBeMdoAKDg4YTQyNjAxN2ZhNDYzNWJhNDIyMDNjM2IxZDFjMTlmNmEwMjgxODQ", + "parents": [ + { + "html_url": "https://github.com/ehuss/rust/commit/319b88c463fe6f51bb6badbbd3bb97252a60f3a5", + "sha": "319b88c463fe6f51bb6badbbd3bb97252a60f3a5", + "url": "https://api.github.com/repos/ehuss/rust/git/commits/319b88c463fe6f51bb6badbbd3bb97252a60f3a5" + } + ], + "sha": "88a426017fa4635ba42203c3b1d1c19f6a028184", + "tree": { + "sha": "45aae523b087e418f2778d4557489de38fede6a3", + "url": "https://api.github.com/repos/ehuss/rust/git/trees/45aae523b087e418f2778d4557489de38fede6a3" + }, + "url": "https://api.github.com/repos/ehuss/rust/git/commits/88a426017fa4635ba42203c3b1d1c19f6a028184", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + } +} diff --git a/tests/github_client/get_issues_no_search/00-GET-repos_rust-lang_rust.json b/tests/github_client/get_issues_no_search/00-GET-repos_rust-lang_rust.json new file mode 100644 index 00000000..3589a6e8 --- /dev/null +++ b/tests/github_client/get_issues_no_search/00-GET-repos_rust-lang_rust.json @@ -0,0 +1,160 @@ +{ + "kind": "Request", + "method": "GET", + "path": "/repos/rust-lang/rust", + "query": null, + "request_body": "", + "response_code": 200, + "response_body": { + "allow_auto_merge": false, + "allow_forking": true, + "allow_merge_commit": true, + "allow_rebase_merge": false, + "allow_squash_merge": false, + "allow_update_branch": false, + "archive_url": "https://api.github.com/repos/rust-lang/rust/{archive_format}{/ref}", + "archived": false, + "assignees_url": "https://api.github.com/repos/rust-lang/rust/assignees{/user}", + "blobs_url": "https://api.github.com/repos/rust-lang/rust/git/blobs{/sha}", + "branches_url": "https://api.github.com/repos/rust-lang/rust/branches{/branch}", + "clone_url": "https://github.com/rust-lang/rust.git", + "collaborators_url": "https://api.github.com/repos/rust-lang/rust/collaborators{/collaborator}", + "comments_url": "https://api.github.com/repos/rust-lang/rust/comments{/number}", + "commits_url": "https://api.github.com/repos/rust-lang/rust/commits{/sha}", + "compare_url": "https://api.github.com/repos/rust-lang/rust/compare/{base}...{head}", + "contents_url": "https://api.github.com/repos/rust-lang/rust/contents/{+path}", + "contributors_url": "https://api.github.com/repos/rust-lang/rust/contributors", + "created_at": "2010-06-16T20:39:03Z", + "default_branch": "master", + "delete_branch_on_merge": true, + "deployments_url": "https://api.github.com/repos/rust-lang/rust/deployments", + "description": "Empowering everyone to build reliable and efficient software.", + "disabled": false, + "downloads_url": "https://api.github.com/repos/rust-lang/rust/downloads", + "events_url": "https://api.github.com/repos/rust-lang/rust/events", + "fork": false, + "forks": 10326, + "forks_count": 10326, + "forks_url": "https://api.github.com/repos/rust-lang/rust/forks", + "full_name": "rust-lang/rust", + "git_commits_url": "https://api.github.com/repos/rust-lang/rust/git/commits{/sha}", + "git_refs_url": "https://api.github.com/repos/rust-lang/rust/git/refs{/sha}", + "git_tags_url": "https://api.github.com/repos/rust-lang/rust/git/tags{/sha}", + "git_url": "git://github.com/rust-lang/rust.git", + "has_discussions": false, + "has_downloads": true, + "has_issues": true, + "has_pages": false, + "has_projects": true, + "has_wiki": false, + "homepage": "https://www.rust-lang.org", + "hooks_url": "https://api.github.com/repos/rust-lang/rust/hooks", + "html_url": "https://github.com/rust-lang/rust", + "id": 724712, + "is_template": false, + "issue_comment_url": "https://api.github.com/repos/rust-lang/rust/issues/comments{/number}", + "issue_events_url": "https://api.github.com/repos/rust-lang/rust/issues/events{/number}", + "issues_url": "https://api.github.com/repos/rust-lang/rust/issues{/number}", + "keys_url": "https://api.github.com/repos/rust-lang/rust/keys{/key_id}", + "labels_url": "https://api.github.com/repos/rust-lang/rust/labels{/name}", + "language": "Rust", + "languages_url": "https://api.github.com/repos/rust-lang/rust/languages", + "license": { + "key": "other", + "name": "Other", + "node_id": "MDc6TGljZW5zZTA=", + "spdx_id": "NOASSERTION", + "url": null + }, + "merge_commit_message": "PR_TITLE", + "merge_commit_title": "MERGE_MESSAGE", + "merges_url": "https://api.github.com/repos/rust-lang/rust/merges", + "milestones_url": "https://api.github.com/repos/rust-lang/rust/milestones{/number}", + "mirror_url": null, + "name": "rust", + "network_count": 10326, + "node_id": "MDEwOlJlcG9zaXRvcnk3MjQ3MTI=", + "notifications_url": "https://api.github.com/repos/rust-lang/rust/notifications{?since,all,participating}", + "open_issues": 9513, + "open_issues_count": 9513, + "organization": { + "avatar_url": "https://avatars.githubusercontent.com/u/5430905?v=4", + "events_url": "https://api.github.com/users/rust-lang/events{/privacy}", + "followers_url": "https://api.github.com/users/rust-lang/followers", + "following_url": "https://api.github.com/users/rust-lang/following{/other_user}", + "gists_url": "https://api.github.com/users/rust-lang/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/rust-lang", + "id": 5430905, + "login": "rust-lang", + "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MzA5MDU=", + "organizations_url": "https://api.github.com/users/rust-lang/orgs", + "received_events_url": "https://api.github.com/users/rust-lang/received_events", + "repos_url": "https://api.github.com/users/rust-lang/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/rust-lang/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rust-lang/subscriptions", + "type": "Organization", + "url": "https://api.github.com/users/rust-lang" + }, + "owner": { + "avatar_url": "https://avatars.githubusercontent.com/u/5430905?v=4", + "events_url": "https://api.github.com/users/rust-lang/events{/privacy}", + "followers_url": "https://api.github.com/users/rust-lang/followers", + "following_url": "https://api.github.com/users/rust-lang/following{/other_user}", + "gists_url": "https://api.github.com/users/rust-lang/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/rust-lang", + "id": 5430905, + "login": "rust-lang", + "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MzA5MDU=", + "organizations_url": "https://api.github.com/users/rust-lang/orgs", + "received_events_url": "https://api.github.com/users/rust-lang/received_events", + "repos_url": "https://api.github.com/users/rust-lang/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/rust-lang/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rust-lang/subscriptions", + "type": "Organization", + "url": "https://api.github.com/users/rust-lang" + }, + "permissions": { + "admin": false, + "maintain": false, + "pull": true, + "push": true, + "triage": true + }, + "private": false, + "pulls_url": "https://api.github.com/repos/rust-lang/rust/pulls{/number}", + "pushed_at": "2023-02-05T18:16:26Z", + "releases_url": "https://api.github.com/repos/rust-lang/rust/releases{/id}", + "size": 1066392, + "squash_merge_commit_message": "COMMIT_MESSAGES", + "squash_merge_commit_title": "COMMIT_OR_PR_TITLE", + "ssh_url": "git@github.com:rust-lang/rust.git", + "stargazers_count": 77402, + "stargazers_url": "https://api.github.com/repos/rust-lang/rust/stargazers", + "statuses_url": "https://api.github.com/repos/rust-lang/rust/statuses/{sha}", + "subscribers_count": 1487, + "subscribers_url": "https://api.github.com/repos/rust-lang/rust/subscribers", + "subscription_url": "https://api.github.com/repos/rust-lang/rust/subscription", + "svn_url": "https://github.com/rust-lang/rust", + "tags_url": "https://api.github.com/repos/rust-lang/rust/tags", + "teams_url": "https://api.github.com/repos/rust-lang/rust/teams", + "temp_clone_token": "", + "topics": [ + "compiler", + "hacktoberfest", + "language", + "rust" + ], + "trees_url": "https://api.github.com/repos/rust-lang/rust/git/trees{/sha}", + "updated_at": "2023-02-05T19:09:47Z", + "url": "https://api.github.com/repos/rust-lang/rust", + "use_squash_pr_title_as_default": false, + "visibility": "public", + "watchers": 77402, + "watchers_count": 77402, + "web_commit_signoff_required": false + } +} diff --git a/tests/github_client/get_issues_no_search/01-GET-repos_rust-lang_rust_issues.json b/tests/github_client/get_issues_no_search/01-GET-repos_rust-lang_rust_issues.json new file mode 100644 index 00000000..d0a8d7d1 --- /dev/null +++ b/tests/github_client/get_issues_no_search/01-GET-repos_rust-lang_rust_issues.json @@ -0,0 +1,431 @@ +{ + "kind": "Request", + "method": "GET", + "path": "/repos/rust-lang/rust/issues", + "query": "labels=A-coherence&filter=all&sort=created&direction=asc&per_page=100", + "request_body": "", + "response_code": 200, + "response_body": [ + { + "active_lock_reason": null, + "assignee": { + "avatar_url": "https://avatars.githubusercontent.com/u/16256974?v=4", + "events_url": "https://api.github.com/users/atsuzaki/events{/privacy}", + "followers_url": "https://api.github.com/users/atsuzaki/followers", + "following_url": "https://api.github.com/users/atsuzaki/following{/other_user}", + "gists_url": "https://api.github.com/users/atsuzaki/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/atsuzaki", + "id": 16256974, + "login": "atsuzaki", + "node_id": "MDQ6VXNlcjE2MjU2OTc0", + "organizations_url": "https://api.github.com/users/atsuzaki/orgs", + "received_events_url": "https://api.github.com/users/atsuzaki/received_events", + "repos_url": "https://api.github.com/users/atsuzaki/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/atsuzaki/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/atsuzaki/subscriptions", + "type": "User", + "url": "https://api.github.com/users/atsuzaki" + }, + "assignees": [ + { + "avatar_url": "https://avatars.githubusercontent.com/u/16256974?v=4", + "events_url": "https://api.github.com/users/atsuzaki/events{/privacy}", + "followers_url": "https://api.github.com/users/atsuzaki/followers", + "following_url": "https://api.github.com/users/atsuzaki/following{/other_user}", + "gists_url": "https://api.github.com/users/atsuzaki/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/atsuzaki", + "id": 16256974, + "login": "atsuzaki", + "node_id": "MDQ6VXNlcjE2MjU2OTc0", + "organizations_url": "https://api.github.com/users/atsuzaki/orgs", + "received_events_url": "https://api.github.com/users/atsuzaki/received_events", + "repos_url": "https://api.github.com/users/atsuzaki/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/atsuzaki/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/atsuzaki/subscriptions", + "type": "User", + "url": "https://api.github.com/users/atsuzaki" + } + ], + "author_association": "MEMBER", + "body": "We consider projections to be foreign types during orphan check\n\nhttps://github.com/rust-lang/rust/blob/ceeb5ade201e4181c6d5df2ba96ae5fb2193aadc/compiler/rustc_trait_selection/src/traits/coherence.rs#L731\n\nbut do not consider them to be parameters when checking for uncovered types https://github.com/rust-lang/rust/blob/ceeb5ade201e4181c6d5df2ba96ae5fb2193aadc/compiler/rustc_trait_selection/src/traits/coherence.rs#L621\n\nThis is more obvious after #99552\n\nthis means that the following impl passes the orphan check even though it shouldn't\n```rust\n// crate a\npub trait Foreign {\n type Assoc;\n}\n\n// crate b\nuse a::Foreign;\n\ntrait Id {\n type Assoc;\n}\n\nimpl Id for T {\n type Assoc = T;\n}\n\npub struct B;\nimpl Foreign for ::Assoc {\n type Assoc = usize;\n}\n```\nThe impl in `b` overlaps with an impl `impl Foreign for LocalTy` in another crate `c` which passes the orphan check.\n\nWhile I wasn't able to cause runtime UB with this, I was able to get an ICE during `codegen_fulfill_obligation`: https://github.com/lcnr/orphan-check-ub\n\ncc @rust-lang/types \n\n\n\n\n\n\n\n\n", + "closed_at": null, + "comments": 5, + "comments_url": "https://api.github.com/repos/rust-lang/rust/issues/99554/comments", + "created_at": "2022-07-21T10:56:00Z", + "events_url": "https://api.github.com/repos/rust-lang/rust/issues/99554/events", + "html_url": "https://github.com/rust-lang/rust/issues/99554", + "id": 1313070635, + "labels": [ + { + "color": "f7e101", + "default": false, + "description": "Area: Trait system", + "id": 13836860, + "name": "A-traits", + "node_id": "MDU6TGFiZWwxMzgzNjg2MA==", + "url": "https://api.github.com/repos/rust-lang/rust/labels/A-traits" + }, + { + "color": "02E10C", + "default": false, + "description": "Call for participation: This issue has a mentor. Use RustcContributor::new on Zulip for discussion.", + "id": 67766349, + "name": "E-mentor", + "node_id": "MDU6TGFiZWw2Nzc2NjM0OQ==", + "url": "https://api.github.com/repos/rust-lang/rust/labels/E-mentor" + }, + { + "color": "f7e101", + "default": false, + "description": "Area: Associated items such as associated types and consts.", + "id": 149689562, + "name": "A-associated-items", + "node_id": "MDU6TGFiZWwxNDk2ODk1NjI=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/A-associated-items" + }, + { + "color": "eb6420", + "default": false, + "description": "High priority", + "id": 203429200, + "name": "P-high", + "node_id": "MDU6TGFiZWwyMDM0MjkyMDA=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/P-high" + }, + { + "color": "e11d21", + "default": false, + "description": "Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness", + "id": 267612997, + "name": "I-unsound", + "node_id": "MDU6TGFiZWwyNjc2MTI5OTc=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/I-unsound" + }, + { + "color": "02e10c", + "default": false, + "description": "Call for participation: Experience needed to fix: Medium / intermediate", + "id": 419557634, + "name": "E-medium", + "node_id": "MDU6TGFiZWw0MTk1NTc2MzQ=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/E-medium" + }, + { + "color": "f5f1fd", + "default": false, + "description": "Category: This is a bug.", + "id": 650731663, + "name": "C-bug", + "node_id": "MDU6TGFiZWw2NTA3MzE2NjM=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/C-bug" + }, + { + "color": "bfd4f2", + "default": false, + "description": "Relevant to the types team, which will review and decide on the PR/issue.", + "id": 4172483496, + "name": "T-types", + "node_id": "LA_kwDOAAsO6M74swuo", + "url": "https://api.github.com/repos/rust-lang/rust/labels/T-types" + }, + { + "color": "f7e101", + "default": false, + "description": "Area: Coherence", + "id": 4917350639, + "name": "A-coherence", + "node_id": "LA_kwDOAAsO6M8AAAABJRjQ7w", + "url": "https://api.github.com/repos/rust-lang/rust/labels/A-coherence" + } + ], + "labels_url": "https://api.github.com/repos/rust-lang/rust/issues/99554/labels{/name}", + "locked": false, + "milestone": null, + "node_id": "I_kwDOAAsO6M5OQ94r", + "number": 99554, + "performed_via_github_app": null, + "reactions": { + "+1": 0, + "-1": 0, + "confused": 0, + "eyes": 0, + "heart": 0, + "hooray": 0, + "laugh": 0, + "rocket": 0, + "total_count": 0, + "url": "https://api.github.com/repos/rust-lang/rust/issues/99554/reactions" + }, + "repository_url": "https://api.github.com/repos/rust-lang/rust", + "state": "open", + "state_reason": null, + "timeline_url": "https://api.github.com/repos/rust-lang/rust/issues/99554/timeline", + "title": "orphan check incorrectly handles projections", + "updated_at": "2023-01-27T17:08:45Z", + "url": "https://api.github.com/repos/rust-lang/rust/issues/99554", + "user": { + "avatar_url": "https://avatars.githubusercontent.com/u/29864074?v=4", + "events_url": "https://api.github.com/users/lcnr/events{/privacy}", + "followers_url": "https://api.github.com/users/lcnr/followers", + "following_url": "https://api.github.com/users/lcnr/following{/other_user}", + "gists_url": "https://api.github.com/users/lcnr/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/lcnr", + "id": 29864074, + "login": "lcnr", + "node_id": "MDQ6VXNlcjI5ODY0MDc0", + "organizations_url": "https://api.github.com/users/lcnr/orgs", + "received_events_url": "https://api.github.com/users/lcnr/received_events", + "repos_url": "https://api.github.com/users/lcnr/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/lcnr/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/lcnr/subscriptions", + "type": "User", + "url": "https://api.github.com/users/lcnr" + } + }, + { + "active_lock_reason": null, + "assignee": null, + "assignees": [], + "author_association": "MEMBER", + "body": "which is unsound during coherence, as coherence requires completeness\r\n```rust\r\n#![feature(specialization)]\r\n\r\ntrait Default {\r\n type Id;\r\n}\r\n\r\nimpl Default for T {\r\n default type Id = T;\r\n}\r\n\r\ntrait Overlap {\r\n type Assoc;\r\n}\r\n\r\nimpl Overlap for u32 {\r\n type Assoc = usize;\r\n}\r\n\r\nimpl Overlap for ::Id {\r\n type Assoc = Box;\r\n}\r\n```\r\n\r\nhttps://github.com/rust-lang/rust/blob/03770f0e2b60c02db8fcf52fed5fb36aac70cedc/compiler/rustc_trait_selection/src/traits/project.rs#L1526", + "closed_at": null, + "comments": 0, + "comments_url": "https://api.github.com/repos/rust-lang/rust/issues/105782/comments", + "created_at": "2022-12-16T15:11:15Z", + "events_url": "https://api.github.com/repos/rust-lang/rust/issues/105782/events", + "html_url": "https://github.com/rust-lang/rust/issues/105782", + "id": 1500394507, + "labels": [ + { + "color": "f7e101", + "default": false, + "description": "Area: Trait system", + "id": 13836860, + "name": "A-traits", + "node_id": "MDU6TGFiZWwxMzgzNjg2MA==", + "url": "https://api.github.com/repos/rust-lang/rust/labels/A-traits" + }, + { + "color": "e11d21", + "default": false, + "description": "Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness", + "id": 267612997, + "name": "I-unsound", + "node_id": "MDU6TGFiZWwyNjc2MTI5OTc=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/I-unsound" + }, + { + "color": "f7e101", + "default": false, + "description": "Area: Trait impl specialization", + "id": 347795552, + "name": "A-specialization", + "node_id": "MDU6TGFiZWwzNDc3OTU1NTI=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/A-specialization" + }, + { + "color": "f5f1fd", + "default": false, + "description": "Category: This is a bug.", + "id": 650731663, + "name": "C-bug", + "node_id": "MDU6TGFiZWw2NTA3MzE2NjM=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/C-bug" + }, + { + "color": "76dcde", + "default": false, + "description": "This issue requires a nightly compiler in some way.", + "id": 1472563007, + "name": "requires-nightly", + "node_id": "MDU6TGFiZWwxNDcyNTYzMDA3", + "url": "https://api.github.com/repos/rust-lang/rust/labels/requires-nightly" + }, + { + "color": "f9c0cc", + "default": false, + "description": "`#![feature(specialization)]`", + "id": 1472579062, + "name": "F-specialization", + "node_id": "MDU6TGFiZWwxNDcyNTc5MDYy", + "url": "https://api.github.com/repos/rust-lang/rust/labels/F-specialization" + }, + { + "color": "f7e101", + "default": false, + "description": "Area: Coherence", + "id": 4917350639, + "name": "A-coherence", + "node_id": "LA_kwDOAAsO6M8AAAABJRjQ7w", + "url": "https://api.github.com/repos/rust-lang/rust/labels/A-coherence" + } + ], + "labels_url": "https://api.github.com/repos/rust-lang/rust/issues/105782/labels{/name}", + "locked": false, + "milestone": null, + "node_id": "I_kwDOAAsO6M5ZbjQL", + "number": 105782, + "performed_via_github_app": null, + "reactions": { + "+1": 0, + "-1": 0, + "confused": 0, + "eyes": 0, + "heart": 0, + "hooray": 0, + "laugh": 0, + "rocket": 0, + "total_count": 0, + "url": "https://api.github.com/repos/rust-lang/rust/issues/105782/reactions" + }, + "repository_url": "https://api.github.com/repos/rust-lang/rust", + "state": "open", + "state_reason": null, + "timeline_url": "https://api.github.com/repos/rust-lang/rust/issues/105782/timeline", + "title": "specialization: default items completely drop candidates instead of ambiguity", + "updated_at": "2022-12-16T16:17:41Z", + "url": "https://api.github.com/repos/rust-lang/rust/issues/105782", + "user": { + "avatar_url": "https://avatars.githubusercontent.com/u/29864074?v=4", + "events_url": "https://api.github.com/users/lcnr/events{/privacy}", + "followers_url": "https://api.github.com/users/lcnr/followers", + "following_url": "https://api.github.com/users/lcnr/following{/other_user}", + "gists_url": "https://api.github.com/users/lcnr/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/lcnr", + "id": 29864074, + "login": "lcnr", + "node_id": "MDQ6VXNlcjI5ODY0MDc0", + "organizations_url": "https://api.github.com/users/lcnr/orgs", + "received_events_url": "https://api.github.com/users/lcnr/received_events", + "repos_url": "https://api.github.com/users/lcnr/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/lcnr/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/lcnr/subscriptions", + "type": "User", + "url": "https://api.github.com/users/lcnr" + } + }, + { + "active_lock_reason": null, + "assignee": null, + "assignees": [], + "author_association": "MEMBER", + "body": "```rust\r\n// Using the higher ranked projection hack to prevent us from replacing the projection\r\n// with an inference variable.\r\ntrait ToUnit<'a> {\r\n type Unit;\r\n}\r\n\r\nstruct LocalTy;\r\nimpl<'a> ToUnit<'a> for *const LocalTy {\r\n type Unit = ();\r\n}\r\n\r\nimpl<'a, T: Copy + ?Sized> ToUnit<'a> for *const T {\r\n type Unit = ();\r\n}\r\n\r\ntrait Overlap {\r\n type Assoc;\r\n}\r\n\r\ntype Assoc<'a, T> = <*const T as ToUnit<'a>>::Unit;\r\n\r\nimpl Overlap for T {\r\n type Assoc = usize;\r\n}\r\n\r\nimpl Overlap fn(&'a (), Assoc<'a, T>)> for T\r\nwhere\r\n for<'a> *const T: ToUnit<'a>,\r\n{\r\n type Assoc = Box;\r\n}\r\n\r\nfn foo, U>(x: T::Assoc) -> T::Assoc {\r\n x\r\n}\r\n\r\nfn main() {\r\n foo:: fn(&'a (), ()), for<'a> fn(&'a (), ())>(3usize);\r\n}\r\n```\r\n\r\n`for<'a> fn(&'a (), ())>: Overlap fn(&'a (), ())>>` can be satisfied using both impls, ignoring a deficiency of the current normalization routine which means that right now the second impl pretty much never applies.\r\n\r\nCurrently inference constraints from equating the self type are not used to normalize the trait argument so we fail when equating `()` with `Assoc<'a, for<'a> fn(&'a (), ())>` even those these two are the same type. This will change once deferred projection equality is implemented.\r\n\r\n## why this currently passes coherence\r\n\r\nCoherence does a pairwise check for all relevant impls. It starts by instantiating the impl parameters with inference vars and equating the impl headers. When we do that with `Overlap for T` and `Overlap fn(&'a (), Assoc<'a, T>)> for T` we have:\r\n\r\n- `eq(?0: Overflap0>, ?1: Overlap fn(&'a (), <*const ?1 as ToUnit<'a>>::Unit)>)`\r\n - `eq(?0, ?1)` constrains `?1` to be equal to `?0`\r\n - `eq(?0, for<'a> fn(&'a (), <*const ?0 as ToUnit<'a>>::Unit)>)`: this now fails the occurs check\r\n\r\nThe occurs check is necessary to prevent ourselves from creating infinitely large types, e.g. `?0 = Vec0>`. But it does mean that coherence considers these two impls to be disjoint. Because the inference var only occurs inside of a projection, there's a way to equate these two types without resulting in an infinitely large type by normalizing the projection.", + "closed_at": null, + "comments": 1, + "comments_url": "https://api.github.com/repos/rust-lang/rust/issues/105787/comments", + "created_at": "2022-12-16T16:16:11Z", + "events_url": "https://api.github.com/repos/rust-lang/rust/issues/105787/events", + "html_url": "https://github.com/rust-lang/rust/issues/105787", + "id": 1500501670, + "labels": [ + { + "color": "f7e101", + "default": false, + "description": "Area: Trait system", + "id": 13836860, + "name": "A-traits", + "node_id": "MDU6TGFiZWwxMzgzNjg2MA==", + "url": "https://api.github.com/repos/rust-lang/rust/labels/A-traits" + }, + { + "color": "eb6420", + "default": false, + "description": "Medium priority", + "id": 60344715, + "name": "P-medium", + "node_id": "MDU6TGFiZWw2MDM0NDcxNQ==", + "url": "https://api.github.com/repos/rust-lang/rust/labels/P-medium" + }, + { + "color": "e11d21", + "default": false, + "description": "Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness", + "id": 267612997, + "name": "I-unsound", + "node_id": "MDU6TGFiZWwyNjc2MTI5OTc=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/I-unsound" + }, + { + "color": "f5f1fd", + "default": false, + "description": "Category: This is a bug.", + "id": 650731663, + "name": "C-bug", + "node_id": "MDU6TGFiZWw2NTA3MzE2NjM=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/C-bug" + }, + { + "color": "bfd4f2", + "default": false, + "description": "Relevant to the types team, which will review and decide on the PR/issue.", + "id": 4172483496, + "name": "T-types", + "node_id": "LA_kwDOAAsO6M74swuo", + "url": "https://api.github.com/repos/rust-lang/rust/labels/T-types" + }, + { + "color": "f7e101", + "default": false, + "description": "Area: Coherence", + "id": 4917350639, + "name": "A-coherence", + "node_id": "LA_kwDOAAsO6M8AAAABJRjQ7w", + "url": "https://api.github.com/repos/rust-lang/rust/labels/A-coherence" + } + ], + "labels_url": "https://api.github.com/repos/rust-lang/rust/issues/105787/labels{/name}", + "locked": false, + "milestone": null, + "node_id": "I_kwDOAAsO6M5Zb9am", + "number": 105787, + "performed_via_github_app": null, + "reactions": { + "+1": 0, + "-1": 0, + "confused": 0, + "eyes": 0, + "heart": 0, + "hooray": 0, + "laugh": 0, + "rocket": 0, + "total_count": 0, + "url": "https://api.github.com/repos/rust-lang/rust/issues/105787/reactions" + }, + "repository_url": "https://api.github.com/repos/rust-lang/rust", + "state": "open", + "state_reason": null, + "timeline_url": "https://api.github.com/repos/rust-lang/rust/issues/105787/timeline", + "title": "occurs check with projections results in error, not ambiguity", + "updated_at": "2022-12-17T05:07:04Z", + "url": "https://api.github.com/repos/rust-lang/rust/issues/105787", + "user": { + "avatar_url": "https://avatars.githubusercontent.com/u/29864074?v=4", + "events_url": "https://api.github.com/users/lcnr/events{/privacy}", + "followers_url": "https://api.github.com/users/lcnr/followers", + "following_url": "https://api.github.com/users/lcnr/following{/other_user}", + "gists_url": "https://api.github.com/users/lcnr/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/lcnr", + "id": 29864074, + "login": "lcnr", + "node_id": "MDQ6VXNlcjI5ODY0MDc0", + "organizations_url": "https://api.github.com/users/lcnr/orgs", + "received_events_url": "https://api.github.com/users/lcnr/received_events", + "repos_url": "https://api.github.com/users/lcnr/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/lcnr/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/lcnr/subscriptions", + "type": "User", + "url": "https://api.github.com/users/lcnr" + } + } + ] +} diff --git a/tests/github_client/get_issues_with_search/00-GET-repos_rust-lang_rust.json b/tests/github_client/get_issues_with_search/00-GET-repos_rust-lang_rust.json new file mode 100644 index 00000000..fd9dcba7 --- /dev/null +++ b/tests/github_client/get_issues_with_search/00-GET-repos_rust-lang_rust.json @@ -0,0 +1,160 @@ +{ + "kind": "Request", + "method": "GET", + "path": "/repos/rust-lang/rust", + "query": null, + "request_body": "", + "response_code": 200, + "response_body": { + "allow_auto_merge": false, + "allow_forking": true, + "allow_merge_commit": true, + "allow_rebase_merge": false, + "allow_squash_merge": false, + "allow_update_branch": false, + "archive_url": "https://api.github.com/repos/rust-lang/rust/{archive_format}{/ref}", + "archived": false, + "assignees_url": "https://api.github.com/repos/rust-lang/rust/assignees{/user}", + "blobs_url": "https://api.github.com/repos/rust-lang/rust/git/blobs{/sha}", + "branches_url": "https://api.github.com/repos/rust-lang/rust/branches{/branch}", + "clone_url": "https://github.com/rust-lang/rust.git", + "collaborators_url": "https://api.github.com/repos/rust-lang/rust/collaborators{/collaborator}", + "comments_url": "https://api.github.com/repos/rust-lang/rust/comments{/number}", + "commits_url": "https://api.github.com/repos/rust-lang/rust/commits{/sha}", + "compare_url": "https://api.github.com/repos/rust-lang/rust/compare/{base}...{head}", + "contents_url": "https://api.github.com/repos/rust-lang/rust/contents/{+path}", + "contributors_url": "https://api.github.com/repos/rust-lang/rust/contributors", + "created_at": "2010-06-16T20:39:03Z", + "default_branch": "master", + "delete_branch_on_merge": true, + "deployments_url": "https://api.github.com/repos/rust-lang/rust/deployments", + "description": "Empowering everyone to build reliable and efficient software.", + "disabled": false, + "downloads_url": "https://api.github.com/repos/rust-lang/rust/downloads", + "events_url": "https://api.github.com/repos/rust-lang/rust/events", + "fork": false, + "forks": 10327, + "forks_count": 10327, + "forks_url": "https://api.github.com/repos/rust-lang/rust/forks", + "full_name": "rust-lang/rust", + "git_commits_url": "https://api.github.com/repos/rust-lang/rust/git/commits{/sha}", + "git_refs_url": "https://api.github.com/repos/rust-lang/rust/git/refs{/sha}", + "git_tags_url": "https://api.github.com/repos/rust-lang/rust/git/tags{/sha}", + "git_url": "git://github.com/rust-lang/rust.git", + "has_discussions": false, + "has_downloads": true, + "has_issues": true, + "has_pages": false, + "has_projects": true, + "has_wiki": false, + "homepage": "https://www.rust-lang.org", + "hooks_url": "https://api.github.com/repos/rust-lang/rust/hooks", + "html_url": "https://github.com/rust-lang/rust", + "id": 724712, + "is_template": false, + "issue_comment_url": "https://api.github.com/repos/rust-lang/rust/issues/comments{/number}", + "issue_events_url": "https://api.github.com/repos/rust-lang/rust/issues/events{/number}", + "issues_url": "https://api.github.com/repos/rust-lang/rust/issues{/number}", + "keys_url": "https://api.github.com/repos/rust-lang/rust/keys{/key_id}", + "labels_url": "https://api.github.com/repos/rust-lang/rust/labels{/name}", + "language": "Rust", + "languages_url": "https://api.github.com/repos/rust-lang/rust/languages", + "license": { + "key": "other", + "name": "Other", + "node_id": "MDc6TGljZW5zZTA=", + "spdx_id": "NOASSERTION", + "url": null + }, + "merge_commit_message": "PR_TITLE", + "merge_commit_title": "MERGE_MESSAGE", + "merges_url": "https://api.github.com/repos/rust-lang/rust/merges", + "milestones_url": "https://api.github.com/repos/rust-lang/rust/milestones{/number}", + "mirror_url": null, + "name": "rust", + "network_count": 10327, + "node_id": "MDEwOlJlcG9zaXRvcnk3MjQ3MTI=", + "notifications_url": "https://api.github.com/repos/rust-lang/rust/notifications{?since,all,participating}", + "open_issues": 9516, + "open_issues_count": 9516, + "organization": { + "avatar_url": "https://avatars.githubusercontent.com/u/5430905?v=4", + "events_url": "https://api.github.com/users/rust-lang/events{/privacy}", + "followers_url": "https://api.github.com/users/rust-lang/followers", + "following_url": "https://api.github.com/users/rust-lang/following{/other_user}", + "gists_url": "https://api.github.com/users/rust-lang/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/rust-lang", + "id": 5430905, + "login": "rust-lang", + "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MzA5MDU=", + "organizations_url": "https://api.github.com/users/rust-lang/orgs", + "received_events_url": "https://api.github.com/users/rust-lang/received_events", + "repos_url": "https://api.github.com/users/rust-lang/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/rust-lang/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rust-lang/subscriptions", + "type": "Organization", + "url": "https://api.github.com/users/rust-lang" + }, + "owner": { + "avatar_url": "https://avatars.githubusercontent.com/u/5430905?v=4", + "events_url": "https://api.github.com/users/rust-lang/events{/privacy}", + "followers_url": "https://api.github.com/users/rust-lang/followers", + "following_url": "https://api.github.com/users/rust-lang/following{/other_user}", + "gists_url": "https://api.github.com/users/rust-lang/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/rust-lang", + "id": 5430905, + "login": "rust-lang", + "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MzA5MDU=", + "organizations_url": "https://api.github.com/users/rust-lang/orgs", + "received_events_url": "https://api.github.com/users/rust-lang/received_events", + "repos_url": "https://api.github.com/users/rust-lang/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/rust-lang/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rust-lang/subscriptions", + "type": "Organization", + "url": "https://api.github.com/users/rust-lang" + }, + "permissions": { + "admin": false, + "maintain": false, + "pull": true, + "push": true, + "triage": true + }, + "private": false, + "pulls_url": "https://api.github.com/repos/rust-lang/rust/pulls{/number}", + "pushed_at": "2023-02-05T21:22:12Z", + "releases_url": "https://api.github.com/repos/rust-lang/rust/releases{/id}", + "size": 1066392, + "squash_merge_commit_message": "COMMIT_MESSAGES", + "squash_merge_commit_title": "COMMIT_OR_PR_TITLE", + "ssh_url": "git@github.com:rust-lang/rust.git", + "stargazers_count": 77405, + "stargazers_url": "https://api.github.com/repos/rust-lang/rust/stargazers", + "statuses_url": "https://api.github.com/repos/rust-lang/rust/statuses/{sha}", + "subscribers_count": 1487, + "subscribers_url": "https://api.github.com/repos/rust-lang/rust/subscribers", + "subscription_url": "https://api.github.com/repos/rust-lang/rust/subscription", + "svn_url": "https://github.com/rust-lang/rust", + "tags_url": "https://api.github.com/repos/rust-lang/rust/tags", + "teams_url": "https://api.github.com/repos/rust-lang/rust/teams", + "temp_clone_token": "", + "topics": [ + "compiler", + "hacktoberfest", + "language", + "rust" + ], + "trees_url": "https://api.github.com/repos/rust-lang/rust/git/trees{/sha}", + "updated_at": "2023-02-05T21:23:12Z", + "url": "https://api.github.com/repos/rust-lang/rust", + "use_squash_pr_title_as_default": false, + "visibility": "public", + "watchers": 77405, + "watchers_count": 77405, + "web_commit_signoff_required": false + } +} diff --git a/tests/github_client/get_issues_with_search/01-GET-search_issues.json b/tests/github_client/get_issues_with_search/01-GET-search_issues.json new file mode 100644 index 00000000..cbc12b0e --- /dev/null +++ b/tests/github_client/get_issues_with_search/01-GET-search_issues.json @@ -0,0 +1,614 @@ +{ + "kind": "Request", + "method": "GET", + "path": "/search/issues", + "query": "q=state:closed+is:pull-request+label:beta-nominated+label:beta-accepted+repo:rust-lang/rust&sort=created&order=asc&per_page=100&page=1", + "request_body": "", + "response_code": 200, + "response_body": { + "incomplete_results": false, + "items": [ + { + "active_lock_reason": null, + "assignee": { + "avatar_url": "https://avatars.githubusercontent.com/u/5047365?v=4", + "events_url": "https://api.github.com/users/Mark-Simulacrum/events{/privacy}", + "followers_url": "https://api.github.com/users/Mark-Simulacrum/followers", + "following_url": "https://api.github.com/users/Mark-Simulacrum/following{/other_user}", + "gists_url": "https://api.github.com/users/Mark-Simulacrum/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/Mark-Simulacrum", + "id": 5047365, + "login": "Mark-Simulacrum", + "node_id": "MDQ6VXNlcjUwNDczNjU=", + "organizations_url": "https://api.github.com/users/Mark-Simulacrum/orgs", + "received_events_url": "https://api.github.com/users/Mark-Simulacrum/received_events", + "repos_url": "https://api.github.com/users/Mark-Simulacrum/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/Mark-Simulacrum/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/Mark-Simulacrum/subscriptions", + "type": "User", + "url": "https://api.github.com/users/Mark-Simulacrum" + }, + "assignees": [ + { + "avatar_url": "https://avatars.githubusercontent.com/u/5047365?v=4", + "events_url": "https://api.github.com/users/Mark-Simulacrum/events{/privacy}", + "followers_url": "https://api.github.com/users/Mark-Simulacrum/followers", + "following_url": "https://api.github.com/users/Mark-Simulacrum/following{/other_user}", + "gists_url": "https://api.github.com/users/Mark-Simulacrum/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/Mark-Simulacrum", + "id": 5047365, + "login": "Mark-Simulacrum", + "node_id": "MDQ6VXNlcjUwNDczNjU=", + "organizations_url": "https://api.github.com/users/Mark-Simulacrum/orgs", + "received_events_url": "https://api.github.com/users/Mark-Simulacrum/received_events", + "repos_url": "https://api.github.com/users/Mark-Simulacrum/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/Mark-Simulacrum/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/Mark-Simulacrum/subscriptions", + "type": "User", + "url": "https://api.github.com/users/Mark-Simulacrum" + } + ], + "author_association": "MEMBER", + "body": "They were missing after recent move from src/test to tests.\r\n\r\ncc @albertlarsan68\r\n\r\nFixes #107081", + "closed_at": "2023-01-26T03:10:34Z", + "comments": 5, + "comments_url": "https://api.github.com/repos/rust-lang/rust/issues/107239/comments", + "created_at": "2023-01-23T20:54:12Z", + "draft": false, + "events_url": "https://api.github.com/repos/rust-lang/rust/issues/107239/events", + "html_url": "https://github.com/rust-lang/rust/pull/107239", + "id": 1553798773, + "labels": [ + { + "color": "1e76d9", + "default": false, + "description": "Nominated for backporting to the compiler in the beta channel.", + "id": 201991156, + "name": "beta-nominated", + "node_id": "MDU6TGFiZWwyMDE5OTExNTY=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/beta-nominated" + }, + { + "color": "1e76d9", + "default": false, + "description": "Accepted for backporting to the compiler in the beta channel.", + "id": 203428830, + "name": "beta-accepted", + "node_id": "MDU6TGFiZWwyMDM0Mjg4MzA=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/beta-accepted" + }, + { + "color": "bfd4f2", + "default": false, + "description": "Relevant to the bootstrap subteam: Rust's build system (x.py and src/bootstrap)", + "id": 325438536, + "name": "T-bootstrap", + "node_id": "MDU6TGFiZWwzMjU0Mzg1MzY=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/T-bootstrap" + }, + { + "color": "d3dddd", + "default": false, + "description": "Status: Waiting on bors to run and complete tests. Bors will change the label on completion.", + "id": 583437191, + "name": "S-waiting-on-bors", + "node_id": "MDU6TGFiZWw1ODM0MzcxOTE=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/S-waiting-on-bors" + }, + { + "color": "bfd4f2", + "default": false, + "description": "Relevant to the infrastructure team, which will review and decide on the PR/issue.", + "id": 593503757, + "name": "T-infra", + "node_id": "MDU6TGFiZWw1OTM1MDM3NTc=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/T-infra" + } + ], + "labels_url": "https://api.github.com/repos/rust-lang/rust/issues/107239/labels{/name}", + "locked": false, + "milestone": { + "closed_at": null, + "closed_issues": 270, + "created_at": "2023-01-22T13:22:36Z", + "creator": { + "avatar_url": "https://avatars.githubusercontent.com/u/47979223?v=4", + "events_url": "https://api.github.com/users/rustbot/events{/privacy}", + "followers_url": "https://api.github.com/users/rustbot/followers", + "following_url": "https://api.github.com/users/rustbot/following{/other_user}", + "gists_url": "https://api.github.com/users/rustbot/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/rustbot", + "id": 47979223, + "login": "rustbot", + "node_id": "MDQ6VXNlcjQ3OTc5MjIz", + "organizations_url": "https://api.github.com/users/rustbot/orgs", + "received_events_url": "https://api.github.com/users/rustbot/received_events", + "repos_url": "https://api.github.com/users/rustbot/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/rustbot/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rustbot/subscriptions", + "type": "User", + "url": "https://api.github.com/users/rustbot" + }, + "description": null, + "due_on": null, + "html_url": "https://github.com/rust-lang/rust/milestone/102", + "id": 8951616, + "labels_url": "https://api.github.com/repos/rust-lang/rust/milestones/102/labels", + "node_id": "MI_kwDOAAsO6M4AiJdA", + "number": 102, + "open_issues": 0, + "state": "open", + "title": "1.69.0", + "updated_at": "2023-02-05T20:33:07Z", + "url": "https://api.github.com/repos/rust-lang/rust/milestones/102" + }, + "node_id": "PR_kwDOAAsO6M5IXTOo", + "number": 107239, + "performed_via_github_app": null, + "pull_request": { + "diff_url": "https://github.com/rust-lang/rust/pull/107239.diff", + "html_url": "https://github.com/rust-lang/rust/pull/107239", + "merged_at": "2023-01-26T03:10:34Z", + "patch_url": "https://github.com/rust-lang/rust/pull/107239.patch", + "url": "https://api.github.com/repos/rust-lang/rust/pulls/107239" + }, + "reactions": { + "+1": 0, + "-1": 0, + "confused": 0, + "eyes": 0, + "heart": 0, + "hooray": 0, + "laugh": 0, + "rocket": 0, + "total_count": 0, + "url": "https://api.github.com/repos/rust-lang/rust/issues/107239/reactions" + }, + "repository_url": "https://api.github.com/repos/rust-lang/rust", + "score": 1.0, + "state": "closed", + "state_reason": null, + "timeline_url": "https://api.github.com/repos/rust-lang/rust/issues/107239/timeline", + "title": "Bring tests back into rustc source tarball", + "updated_at": "2023-01-26T09:15:41Z", + "url": "https://api.github.com/repos/rust-lang/rust/issues/107239", + "user": { + "avatar_url": "https://avatars.githubusercontent.com/u/51362316?v=4", + "events_url": "https://api.github.com/users/tmiasko/events{/privacy}", + "followers_url": "https://api.github.com/users/tmiasko/followers", + "following_url": "https://api.github.com/users/tmiasko/following{/other_user}", + "gists_url": "https://api.github.com/users/tmiasko/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/tmiasko", + "id": 51362316, + "login": "tmiasko", + "node_id": "MDQ6VXNlcjUxMzYyMzE2", + "organizations_url": "https://api.github.com/users/tmiasko/orgs", + "received_events_url": "https://api.github.com/users/tmiasko/received_events", + "repos_url": "https://api.github.com/users/tmiasko/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/tmiasko/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/tmiasko/subscriptions", + "type": "User", + "url": "https://api.github.com/users/tmiasko" + } + }, + { + "active_lock_reason": null, + "assignee": { + "avatar_url": "https://avatars.githubusercontent.com/u/1593513?v=4", + "events_url": "https://api.github.com/users/notriddle/events{/privacy}", + "followers_url": "https://api.github.com/users/notriddle/followers", + "following_url": "https://api.github.com/users/notriddle/following{/other_user}", + "gists_url": "https://api.github.com/users/notriddle/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/notriddle", + "id": 1593513, + "login": "notriddle", + "node_id": "MDQ6VXNlcjE1OTM1MTM=", + "organizations_url": "https://api.github.com/users/notriddle/orgs", + "received_events_url": "https://api.github.com/users/notriddle/received_events", + "repos_url": "https://api.github.com/users/notriddle/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/notriddle/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/notriddle/subscriptions", + "type": "User", + "url": "https://api.github.com/users/notriddle" + }, + "assignees": [ + { + "avatar_url": "https://avatars.githubusercontent.com/u/1593513?v=4", + "events_url": "https://api.github.com/users/notriddle/events{/privacy}", + "followers_url": "https://api.github.com/users/notriddle/followers", + "following_url": "https://api.github.com/users/notriddle/following{/other_user}", + "gists_url": "https://api.github.com/users/notriddle/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/notriddle", + "id": 1593513, + "login": "notriddle", + "node_id": "MDQ6VXNlcjE1OTM1MTM=", + "organizations_url": "https://api.github.com/users/notriddle/orgs", + "received_events_url": "https://api.github.com/users/notriddle/received_events", + "repos_url": "https://api.github.com/users/notriddle/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/notriddle/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/notriddle/subscriptions", + "type": "User", + "url": "https://api.github.com/users/notriddle" + } + ], + "author_association": "MEMBER", + "body": "Fixes https://github.com/rust-lang/rust/issues/107350.\r\n\r\nWe'll also need to backport this fix to beta.\r\n\r\nr? @notriddle ", + "closed_at": "2023-01-27T21:20:36Z", + "comments": 3, + "comments_url": "https://api.github.com/repos/rust-lang/rust/issues/107357/comments", + "created_at": "2023-01-27T11:11:41Z", + "draft": false, + "events_url": "https://api.github.com/repos/rust-lang/rust/issues/107357/events", + "html_url": "https://github.com/rust-lang/rust/pull/107357", + "id": 1559575358, + "labels": [ + { + "color": "bfd4f2", + "default": false, + "description": "Relevant to the rustdoc team, which will review and decide on the PR/issue.", + "id": 203738, + "name": "T-rustdoc", + "node_id": "MDU6TGFiZWwyMDM3Mzg=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/T-rustdoc" + }, + { + "color": "1e76d9", + "default": false, + "description": "Nominated for backporting to the compiler in the beta channel.", + "id": 201991156, + "name": "beta-nominated", + "node_id": "MDU6TGFiZWwyMDE5OTExNTY=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/beta-nominated" + }, + { + "color": "1e76d9", + "default": false, + "description": "Accepted for backporting to the compiler in the beta channel.", + "id": 203428830, + "name": "beta-accepted", + "node_id": "MDU6TGFiZWwyMDM0Mjg4MzA=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/beta-accepted" + }, + { + "color": "d3dddd", + "default": false, + "description": "Status: Waiting on bors to run and complete tests. Bors will change the label on completion.", + "id": 583437191, + "name": "S-waiting-on-bors", + "node_id": "MDU6TGFiZWw1ODM0MzcxOTE=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/S-waiting-on-bors" + } + ], + "labels_url": "https://api.github.com/repos/rust-lang/rust/issues/107357/labels{/name}", + "locked": false, + "milestone": { + "closed_at": null, + "closed_issues": 270, + "created_at": "2023-01-22T13:22:36Z", + "creator": { + "avatar_url": "https://avatars.githubusercontent.com/u/47979223?v=4", + "events_url": "https://api.github.com/users/rustbot/events{/privacy}", + "followers_url": "https://api.github.com/users/rustbot/followers", + "following_url": "https://api.github.com/users/rustbot/following{/other_user}", + "gists_url": "https://api.github.com/users/rustbot/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/rustbot", + "id": 47979223, + "login": "rustbot", + "node_id": "MDQ6VXNlcjQ3OTc5MjIz", + "organizations_url": "https://api.github.com/users/rustbot/orgs", + "received_events_url": "https://api.github.com/users/rustbot/received_events", + "repos_url": "https://api.github.com/users/rustbot/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/rustbot/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rustbot/subscriptions", + "type": "User", + "url": "https://api.github.com/users/rustbot" + }, + "description": null, + "due_on": null, + "html_url": "https://github.com/rust-lang/rust/milestone/102", + "id": 8951616, + "labels_url": "https://api.github.com/repos/rust-lang/rust/milestones/102/labels", + "node_id": "MI_kwDOAAsO6M4AiJdA", + "number": 102, + "open_issues": 0, + "state": "open", + "title": "1.69.0", + "updated_at": "2023-02-05T20:33:07Z", + "url": "https://api.github.com/repos/rust-lang/rust/milestones/102" + }, + "node_id": "PR_kwDOAAsO6M5Iqrzr", + "number": 107357, + "performed_via_github_app": null, + "pull_request": { + "diff_url": "https://github.com/rust-lang/rust/pull/107357.diff", + "html_url": "https://github.com/rust-lang/rust/pull/107357", + "merged_at": "2023-01-27T21:20:36Z", + "patch_url": "https://github.com/rust-lang/rust/pull/107357.patch", + "url": "https://api.github.com/repos/rust-lang/rust/pulls/107357" + }, + "reactions": { + "+1": 0, + "-1": 0, + "confused": 0, + "eyes": 0, + "heart": 0, + "hooray": 0, + "laugh": 0, + "rocket": 1, + "total_count": 1, + "url": "https://api.github.com/repos/rust-lang/rust/issues/107357/reactions" + }, + "repository_url": "https://api.github.com/repos/rust-lang/rust", + "score": 1.0, + "state": "closed", + "state_reason": null, + "timeline_url": "https://api.github.com/repos/rust-lang/rust/issues/107357/timeline", + "title": "Fix infinite loop in rustdoc get_all_import_attributes function", + "updated_at": "2023-02-01T22:14:14Z", + "url": "https://api.github.com/repos/rust-lang/rust/issues/107357", + "user": { + "avatar_url": "https://avatars.githubusercontent.com/u/3050060?v=4", + "events_url": "https://api.github.com/users/GuillaumeGomez/events{/privacy}", + "followers_url": "https://api.github.com/users/GuillaumeGomez/followers", + "following_url": "https://api.github.com/users/GuillaumeGomez/following{/other_user}", + "gists_url": "https://api.github.com/users/GuillaumeGomez/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/GuillaumeGomez", + "id": 3050060, + "login": "GuillaumeGomez", + "node_id": "MDQ6VXNlcjMwNTAwNjA=", + "organizations_url": "https://api.github.com/users/GuillaumeGomez/orgs", + "received_events_url": "https://api.github.com/users/GuillaumeGomez/received_events", + "repos_url": "https://api.github.com/users/GuillaumeGomez/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/GuillaumeGomez/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/GuillaumeGomez/subscriptions", + "type": "User", + "url": "https://api.github.com/users/GuillaumeGomez" + } + }, + { + "active_lock_reason": null, + "assignee": { + "avatar_url": "https://avatars.githubusercontent.com/u/1822483?v=4", + "events_url": "https://api.github.com/users/cjgillot/events{/privacy}", + "followers_url": "https://api.github.com/users/cjgillot/followers", + "following_url": "https://api.github.com/users/cjgillot/following{/other_user}", + "gists_url": "https://api.github.com/users/cjgillot/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/cjgillot", + "id": 1822483, + "login": "cjgillot", + "node_id": "MDQ6VXNlcjE4MjI0ODM=", + "organizations_url": "https://api.github.com/users/cjgillot/orgs", + "received_events_url": "https://api.github.com/users/cjgillot/received_events", + "repos_url": "https://api.github.com/users/cjgillot/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/cjgillot/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/cjgillot/subscriptions", + "type": "User", + "url": "https://api.github.com/users/cjgillot" + }, + "assignees": [ + { + "avatar_url": "https://avatars.githubusercontent.com/u/1822483?v=4", + "events_url": "https://api.github.com/users/cjgillot/events{/privacy}", + "followers_url": "https://api.github.com/users/cjgillot/followers", + "following_url": "https://api.github.com/users/cjgillot/following{/other_user}", + "gists_url": "https://api.github.com/users/cjgillot/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/cjgillot", + "id": 1822483, + "login": "cjgillot", + "node_id": "MDQ6VXNlcjE4MjI0ODM=", + "organizations_url": "https://api.github.com/users/cjgillot/orgs", + "received_events_url": "https://api.github.com/users/cjgillot/received_events", + "repos_url": "https://api.github.com/users/cjgillot/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/cjgillot/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/cjgillot/subscriptions", + "type": "User", + "url": "https://api.github.com/users/cjgillot" + } + ], + "author_association": "MEMBER", + "body": "This includes a revert of https://github.com/rust-lang/rust/pull/105221 to restore fat archive reading with LlvmArchiveBuilder.\r\n\r\nShould fix #107162, #107334 and https://github.com/google/shaderc-rs/issues/133", + "closed_at": "2023-01-28T06:46:40Z", + "comments": 18, + "comments_url": "https://api.github.com/repos/rust-lang/rust/issues/107360/comments", + "created_at": "2023-01-27T11:52:10Z", + "draft": false, + "events_url": "https://api.github.com/repos/rust-lang/rust/issues/107360/events", + "html_url": "https://github.com/rust-lang/rust/pull/107360", + "id": 1559626690, + "labels": [ + { + "color": "1e76d9", + "default": false, + "description": "Nominated for backporting to the compiler in the beta channel.", + "id": 201991156, + "name": "beta-nominated", + "node_id": "MDU6TGFiZWwyMDE5OTExNTY=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/beta-nominated" + }, + { + "color": "1e76d9", + "default": false, + "description": "Accepted for backporting to the compiler in the beta channel.", + "id": 203428830, + "name": "beta-accepted", + "node_id": "MDU6TGFiZWwyMDM0Mjg4MzA=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/beta-accepted" + }, + { + "color": "bfd4f2", + "default": false, + "description": "Relevant to the compiler team, which will review and decide on the PR/issue.", + "id": 211668100, + "name": "T-compiler", + "node_id": "MDU6TGFiZWwyMTE2NjgxMDA=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/T-compiler" + }, + { + "color": "d3dddd", + "default": false, + "description": "Status: Waiting on bors to run and complete tests. Bors will change the label on completion.", + "id": 583437191, + "name": "S-waiting-on-bors", + "node_id": "MDU6TGFiZWw1ODM0MzcxOTE=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/S-waiting-on-bors" + }, + { + "color": "00229c", + "default": false, + "description": "Nominated for backporting to the compiler in the stable channel.", + "id": 980125335, + "name": "stable-nominated", + "node_id": "MDU6TGFiZWw5ODAxMjUzMzU=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/stable-nominated" + }, + { + "color": "00229c", + "default": false, + "description": "Accepted for backporting to the compiler in the stable channel.", + "id": 980125489, + "name": "stable-accepted", + "node_id": "MDU6TGFiZWw5ODAxMjU0ODk=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/stable-accepted" + }, + { + "color": "dae4e4", + "default": false, + "description": "This PR was explicitly merged by bors", + "id": 1223998418, + "name": "merged-by-bors", + "node_id": "MDU6TGFiZWwxMjIzOTk4NDE4", + "url": "https://api.github.com/repos/rust-lang/rust/labels/merged-by-bors" + }, + { + "color": "e4008a", + "default": false, + "description": "Performance regressions", + "id": 3116384996, + "name": "perf-regression", + "node_id": "MDU6TGFiZWwzMTE2Mzg0OTk2", + "url": "https://api.github.com/repos/rust-lang/rust/labels/perf-regression" + }, + { + "color": "e4008a", + "default": false, + "description": "The performance regression has been triaged.", + "id": 3145771546, + "name": "perf-regression-triaged", + "node_id": "MDU6TGFiZWwzMTQ1NzcxNTQ2", + "url": "https://api.github.com/repos/rust-lang/rust/labels/perf-regression-triaged" + } + ], + "labels_url": "https://api.github.com/repos/rust-lang/rust/issues/107360/labels{/name}", + "locked": false, + "milestone": { + "closed_at": null, + "closed_issues": 270, + "created_at": "2023-01-22T13:22:36Z", + "creator": { + "avatar_url": "https://avatars.githubusercontent.com/u/47979223?v=4", + "events_url": "https://api.github.com/users/rustbot/events{/privacy}", + "followers_url": "https://api.github.com/users/rustbot/followers", + "following_url": "https://api.github.com/users/rustbot/following{/other_user}", + "gists_url": "https://api.github.com/users/rustbot/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/rustbot", + "id": 47979223, + "login": "rustbot", + "node_id": "MDQ6VXNlcjQ3OTc5MjIz", + "organizations_url": "https://api.github.com/users/rustbot/orgs", + "received_events_url": "https://api.github.com/users/rustbot/received_events", + "repos_url": "https://api.github.com/users/rustbot/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/rustbot/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rustbot/subscriptions", + "type": "User", + "url": "https://api.github.com/users/rustbot" + }, + "description": null, + "due_on": null, + "html_url": "https://github.com/rust-lang/rust/milestone/102", + "id": 8951616, + "labels_url": "https://api.github.com/repos/rust-lang/rust/milestones/102/labels", + "node_id": "MI_kwDOAAsO6M4AiJdA", + "number": 102, + "open_issues": 0, + "state": "open", + "title": "1.69.0", + "updated_at": "2023-02-05T20:33:07Z", + "url": "https://api.github.com/repos/rust-lang/rust/milestones/102" + }, + "node_id": "PR_kwDOAAsO6M5Iq2_Z", + "number": 107360, + "performed_via_github_app": null, + "pull_request": { + "diff_url": "https://github.com/rust-lang/rust/pull/107360.diff", + "html_url": "https://github.com/rust-lang/rust/pull/107360", + "merged_at": "2023-01-28T06:46:40Z", + "patch_url": "https://github.com/rust-lang/rust/pull/107360.patch", + "url": "https://api.github.com/repos/rust-lang/rust/pulls/107360" + }, + "reactions": { + "+1": 0, + "-1": 0, + "confused": 0, + "eyes": 0, + "heart": 0, + "hooray": 0, + "laugh": 0, + "rocket": 0, + "total_count": 0, + "url": "https://api.github.com/repos/rust-lang/rust/issues/107360/reactions" + }, + "repository_url": "https://api.github.com/repos/rust-lang/rust", + "score": 1.0, + "state": "closed", + "state_reason": null, + "timeline_url": "https://api.github.com/repos/rust-lang/rust/issues/107360/timeline", + "title": "Fix thin archive reading", + "updated_at": "2023-02-02T20:35:26Z", + "url": "https://api.github.com/repos/rust-lang/rust/issues/107360", + "user": { + "avatar_url": "https://avatars.githubusercontent.com/u/17426603?v=4", + "events_url": "https://api.github.com/users/bjorn3/events{/privacy}", + "followers_url": "https://api.github.com/users/bjorn3/followers", + "following_url": "https://api.github.com/users/bjorn3/following{/other_user}", + "gists_url": "https://api.github.com/users/bjorn3/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bjorn3", + "id": 17426603, + "login": "bjorn3", + "node_id": "MDQ6VXNlcjE3NDI2NjAz", + "organizations_url": "https://api.github.com/users/bjorn3/orgs", + "received_events_url": "https://api.github.com/users/bjorn3/received_events", + "repos_url": "https://api.github.com/users/bjorn3/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bjorn3/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bjorn3/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bjorn3" + } + } + ], + "total_count": 3 + } +} diff --git a/tests/github_client/get_reference/00-GET-repos_rust-lang_rust.json b/tests/github_client/get_reference/00-GET-repos_rust-lang_rust.json new file mode 100644 index 00000000..3589a6e8 --- /dev/null +++ b/tests/github_client/get_reference/00-GET-repos_rust-lang_rust.json @@ -0,0 +1,160 @@ +{ + "kind": "Request", + "method": "GET", + "path": "/repos/rust-lang/rust", + "query": null, + "request_body": "", + "response_code": 200, + "response_body": { + "allow_auto_merge": false, + "allow_forking": true, + "allow_merge_commit": true, + "allow_rebase_merge": false, + "allow_squash_merge": false, + "allow_update_branch": false, + "archive_url": "https://api.github.com/repos/rust-lang/rust/{archive_format}{/ref}", + "archived": false, + "assignees_url": "https://api.github.com/repos/rust-lang/rust/assignees{/user}", + "blobs_url": "https://api.github.com/repos/rust-lang/rust/git/blobs{/sha}", + "branches_url": "https://api.github.com/repos/rust-lang/rust/branches{/branch}", + "clone_url": "https://github.com/rust-lang/rust.git", + "collaborators_url": "https://api.github.com/repos/rust-lang/rust/collaborators{/collaborator}", + "comments_url": "https://api.github.com/repos/rust-lang/rust/comments{/number}", + "commits_url": "https://api.github.com/repos/rust-lang/rust/commits{/sha}", + "compare_url": "https://api.github.com/repos/rust-lang/rust/compare/{base}...{head}", + "contents_url": "https://api.github.com/repos/rust-lang/rust/contents/{+path}", + "contributors_url": "https://api.github.com/repos/rust-lang/rust/contributors", + "created_at": "2010-06-16T20:39:03Z", + "default_branch": "master", + "delete_branch_on_merge": true, + "deployments_url": "https://api.github.com/repos/rust-lang/rust/deployments", + "description": "Empowering everyone to build reliable and efficient software.", + "disabled": false, + "downloads_url": "https://api.github.com/repos/rust-lang/rust/downloads", + "events_url": "https://api.github.com/repos/rust-lang/rust/events", + "fork": false, + "forks": 10326, + "forks_count": 10326, + "forks_url": "https://api.github.com/repos/rust-lang/rust/forks", + "full_name": "rust-lang/rust", + "git_commits_url": "https://api.github.com/repos/rust-lang/rust/git/commits{/sha}", + "git_refs_url": "https://api.github.com/repos/rust-lang/rust/git/refs{/sha}", + "git_tags_url": "https://api.github.com/repos/rust-lang/rust/git/tags{/sha}", + "git_url": "git://github.com/rust-lang/rust.git", + "has_discussions": false, + "has_downloads": true, + "has_issues": true, + "has_pages": false, + "has_projects": true, + "has_wiki": false, + "homepage": "https://www.rust-lang.org", + "hooks_url": "https://api.github.com/repos/rust-lang/rust/hooks", + "html_url": "https://github.com/rust-lang/rust", + "id": 724712, + "is_template": false, + "issue_comment_url": "https://api.github.com/repos/rust-lang/rust/issues/comments{/number}", + "issue_events_url": "https://api.github.com/repos/rust-lang/rust/issues/events{/number}", + "issues_url": "https://api.github.com/repos/rust-lang/rust/issues{/number}", + "keys_url": "https://api.github.com/repos/rust-lang/rust/keys{/key_id}", + "labels_url": "https://api.github.com/repos/rust-lang/rust/labels{/name}", + "language": "Rust", + "languages_url": "https://api.github.com/repos/rust-lang/rust/languages", + "license": { + "key": "other", + "name": "Other", + "node_id": "MDc6TGljZW5zZTA=", + "spdx_id": "NOASSERTION", + "url": null + }, + "merge_commit_message": "PR_TITLE", + "merge_commit_title": "MERGE_MESSAGE", + "merges_url": "https://api.github.com/repos/rust-lang/rust/merges", + "milestones_url": "https://api.github.com/repos/rust-lang/rust/milestones{/number}", + "mirror_url": null, + "name": "rust", + "network_count": 10326, + "node_id": "MDEwOlJlcG9zaXRvcnk3MjQ3MTI=", + "notifications_url": "https://api.github.com/repos/rust-lang/rust/notifications{?since,all,participating}", + "open_issues": 9513, + "open_issues_count": 9513, + "organization": { + "avatar_url": "https://avatars.githubusercontent.com/u/5430905?v=4", + "events_url": "https://api.github.com/users/rust-lang/events{/privacy}", + "followers_url": "https://api.github.com/users/rust-lang/followers", + "following_url": "https://api.github.com/users/rust-lang/following{/other_user}", + "gists_url": "https://api.github.com/users/rust-lang/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/rust-lang", + "id": 5430905, + "login": "rust-lang", + "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MzA5MDU=", + "organizations_url": "https://api.github.com/users/rust-lang/orgs", + "received_events_url": "https://api.github.com/users/rust-lang/received_events", + "repos_url": "https://api.github.com/users/rust-lang/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/rust-lang/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rust-lang/subscriptions", + "type": "Organization", + "url": "https://api.github.com/users/rust-lang" + }, + "owner": { + "avatar_url": "https://avatars.githubusercontent.com/u/5430905?v=4", + "events_url": "https://api.github.com/users/rust-lang/events{/privacy}", + "followers_url": "https://api.github.com/users/rust-lang/followers", + "following_url": "https://api.github.com/users/rust-lang/following{/other_user}", + "gists_url": "https://api.github.com/users/rust-lang/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/rust-lang", + "id": 5430905, + "login": "rust-lang", + "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MzA5MDU=", + "organizations_url": "https://api.github.com/users/rust-lang/orgs", + "received_events_url": "https://api.github.com/users/rust-lang/received_events", + "repos_url": "https://api.github.com/users/rust-lang/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/rust-lang/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rust-lang/subscriptions", + "type": "Organization", + "url": "https://api.github.com/users/rust-lang" + }, + "permissions": { + "admin": false, + "maintain": false, + "pull": true, + "push": true, + "triage": true + }, + "private": false, + "pulls_url": "https://api.github.com/repos/rust-lang/rust/pulls{/number}", + "pushed_at": "2023-02-05T18:16:26Z", + "releases_url": "https://api.github.com/repos/rust-lang/rust/releases{/id}", + "size": 1066392, + "squash_merge_commit_message": "COMMIT_MESSAGES", + "squash_merge_commit_title": "COMMIT_OR_PR_TITLE", + "ssh_url": "git@github.com:rust-lang/rust.git", + "stargazers_count": 77402, + "stargazers_url": "https://api.github.com/repos/rust-lang/rust/stargazers", + "statuses_url": "https://api.github.com/repos/rust-lang/rust/statuses/{sha}", + "subscribers_count": 1487, + "subscribers_url": "https://api.github.com/repos/rust-lang/rust/subscribers", + "subscription_url": "https://api.github.com/repos/rust-lang/rust/subscription", + "svn_url": "https://github.com/rust-lang/rust", + "tags_url": "https://api.github.com/repos/rust-lang/rust/tags", + "teams_url": "https://api.github.com/repos/rust-lang/rust/teams", + "temp_clone_token": "", + "topics": [ + "compiler", + "hacktoberfest", + "language", + "rust" + ], + "trees_url": "https://api.github.com/repos/rust-lang/rust/git/trees{/sha}", + "updated_at": "2023-02-05T19:09:47Z", + "url": "https://api.github.com/repos/rust-lang/rust", + "use_squash_pr_title_as_default": false, + "visibility": "public", + "watchers": 77402, + "watchers_count": 77402, + "web_commit_signoff_required": false + } +} diff --git a/tests/github_client/get_reference/01-GET-repos_rust-lang_rust_git_ref_heads_stable.json b/tests/github_client/get_reference/01-GET-repos_rust-lang_rust_git_ref_heads_stable.json new file mode 100644 index 00000000..b2a68fa9 --- /dev/null +++ b/tests/github_client/get_reference/01-GET-repos_rust-lang_rust_git_ref_heads_stable.json @@ -0,0 +1,18 @@ +{ + "kind": "Request", + "method": "GET", + "path": "/repos/rust-lang/rust/git/ref/heads/stable", + "query": null, + "request_body": "", + "response_code": 200, + "response_body": { + "node_id": "MDM6UmVmNzI0NzEyOnJlZnMvaGVhZHMvc3RhYmxl", + "object": { + "sha": "fc594f15669680fa70d255faec3ca3fb507c3405", + "type": "commit", + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/fc594f15669680fa70d255faec3ca3fb507c3405" + }, + "ref": "refs/heads/stable", + "url": "https://api.github.com/repos/rust-lang/rust/git/refs/heads/stable" + } +} diff --git a/tests/github_client/git_commit/00-GET-repos_rust-lang_rust.json b/tests/github_client/git_commit/00-GET-repos_rust-lang_rust.json new file mode 100644 index 00000000..a1ab4e0a --- /dev/null +++ b/tests/github_client/git_commit/00-GET-repos_rust-lang_rust.json @@ -0,0 +1,148 @@ +{ + "kind": "Request", + "method": "GET", + "path": "/repos/rust-lang/rust", + "query": null, + "request_body": "", + "response_code": 200, + "response_body": { + "allow_forking": true, + "archive_url": "https://api.github.com/repos/rust-lang/rust/{archive_format}{/ref}", + "archived": false, + "assignees_url": "https://api.github.com/repos/rust-lang/rust/assignees{/user}", + "blobs_url": "https://api.github.com/repos/rust-lang/rust/git/blobs{/sha}", + "branches_url": "https://api.github.com/repos/rust-lang/rust/branches{/branch}", + "clone_url": "https://github.com/rust-lang/rust.git", + "collaborators_url": "https://api.github.com/repos/rust-lang/rust/collaborators{/collaborator}", + "comments_url": "https://api.github.com/repos/rust-lang/rust/comments{/number}", + "commits_url": "https://api.github.com/repos/rust-lang/rust/commits{/sha}", + "compare_url": "https://api.github.com/repos/rust-lang/rust/compare/{base}...{head}", + "contents_url": "https://api.github.com/repos/rust-lang/rust/contents/{+path}", + "contributors_url": "https://api.github.com/repos/rust-lang/rust/contributors", + "created_at": "2010-06-16T20:39:03Z", + "default_branch": "master", + "deployments_url": "https://api.github.com/repos/rust-lang/rust/deployments", + "description": "Empowering everyone to build reliable and efficient software.", + "disabled": false, + "downloads_url": "https://api.github.com/repos/rust-lang/rust/downloads", + "events_url": "https://api.github.com/repos/rust-lang/rust/events", + "fork": false, + "forks": 10323, + "forks_count": 10323, + "forks_url": "https://api.github.com/repos/rust-lang/rust/forks", + "full_name": "rust-lang/rust", + "git_commits_url": "https://api.github.com/repos/rust-lang/rust/git/commits{/sha}", + "git_refs_url": "https://api.github.com/repos/rust-lang/rust/git/refs{/sha}", + "git_tags_url": "https://api.github.com/repos/rust-lang/rust/git/tags{/sha}", + "git_url": "git://github.com/rust-lang/rust.git", + "has_discussions": false, + "has_downloads": true, + "has_issues": true, + "has_pages": false, + "has_projects": true, + "has_wiki": false, + "homepage": "https://www.rust-lang.org", + "hooks_url": "https://api.github.com/repos/rust-lang/rust/hooks", + "html_url": "https://github.com/rust-lang/rust", + "id": 724712, + "is_template": false, + "issue_comment_url": "https://api.github.com/repos/rust-lang/rust/issues/comments{/number}", + "issue_events_url": "https://api.github.com/repos/rust-lang/rust/issues/events{/number}", + "issues_url": "https://api.github.com/repos/rust-lang/rust/issues{/number}", + "keys_url": "https://api.github.com/repos/rust-lang/rust/keys{/key_id}", + "labels_url": "https://api.github.com/repos/rust-lang/rust/labels{/name}", + "language": "Rust", + "languages_url": "https://api.github.com/repos/rust-lang/rust/languages", + "license": { + "key": "other", + "name": "Other", + "node_id": "MDc6TGljZW5zZTA=", + "spdx_id": "NOASSERTION", + "url": null + }, + "merges_url": "https://api.github.com/repos/rust-lang/rust/merges", + "milestones_url": "https://api.github.com/repos/rust-lang/rust/milestones{/number}", + "mirror_url": null, + "name": "rust", + "network_count": 10323, + "node_id": "MDEwOlJlcG9zaXRvcnk3MjQ3MTI=", + "notifications_url": "https://api.github.com/repos/rust-lang/rust/notifications{?since,all,participating}", + "open_issues": 9508, + "open_issues_count": 9508, + "organization": { + "avatar_url": "https://avatars.githubusercontent.com/u/5430905?v=4", + "events_url": "https://api.github.com/users/rust-lang/events{/privacy}", + "followers_url": "https://api.github.com/users/rust-lang/followers", + "following_url": "https://api.github.com/users/rust-lang/following{/other_user}", + "gists_url": "https://api.github.com/users/rust-lang/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/rust-lang", + "id": 5430905, + "login": "rust-lang", + "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MzA5MDU=", + "organizations_url": "https://api.github.com/users/rust-lang/orgs", + "received_events_url": "https://api.github.com/users/rust-lang/received_events", + "repos_url": "https://api.github.com/users/rust-lang/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/rust-lang/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rust-lang/subscriptions", + "type": "Organization", + "url": "https://api.github.com/users/rust-lang" + }, + "owner": { + "avatar_url": "https://avatars.githubusercontent.com/u/5430905?v=4", + "events_url": "https://api.github.com/users/rust-lang/events{/privacy}", + "followers_url": "https://api.github.com/users/rust-lang/followers", + "following_url": "https://api.github.com/users/rust-lang/following{/other_user}", + "gists_url": "https://api.github.com/users/rust-lang/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/rust-lang", + "id": 5430905, + "login": "rust-lang", + "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MzA5MDU=", + "organizations_url": "https://api.github.com/users/rust-lang/orgs", + "received_events_url": "https://api.github.com/users/rust-lang/received_events", + "repos_url": "https://api.github.com/users/rust-lang/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/rust-lang/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rust-lang/subscriptions", + "type": "Organization", + "url": "https://api.github.com/users/rust-lang" + }, + "permissions": { + "admin": false, + "maintain": false, + "pull": true, + "push": true, + "triage": true + }, + "private": false, + "pulls_url": "https://api.github.com/repos/rust-lang/rust/pulls{/number}", + "pushed_at": "2023-02-05T14:37:25Z", + "releases_url": "https://api.github.com/repos/rust-lang/rust/releases{/id}", + "size": 1066289, + "ssh_url": "git@github.com:rust-lang/rust.git", + "stargazers_count": 77396, + "stargazers_url": "https://api.github.com/repos/rust-lang/rust/stargazers", + "statuses_url": "https://api.github.com/repos/rust-lang/rust/statuses/{sha}", + "subscribers_count": 1488, + "subscribers_url": "https://api.github.com/repos/rust-lang/rust/subscribers", + "subscription_url": "https://api.github.com/repos/rust-lang/rust/subscription", + "svn_url": "https://github.com/rust-lang/rust", + "tags_url": "https://api.github.com/repos/rust-lang/rust/tags", + "teams_url": "https://api.github.com/repos/rust-lang/rust/teams", + "topics": [ + "compiler", + "hacktoberfest", + "language", + "rust" + ], + "trees_url": "https://api.github.com/repos/rust-lang/rust/git/trees{/sha}", + "updated_at": "2023-02-05T14:42:37Z", + "url": "https://api.github.com/repos/rust-lang/rust", + "visibility": "public", + "watchers": 77396, + "watchers_count": 77396, + "web_commit_signoff_required": false + } +} diff --git a/tests/github_client/git_commit/01-GET-repos_rust-lang_rust_git_commits_109cccbe4f345c0f0785ce860788580c3e2a29f5.json b/tests/github_client/git_commit/01-GET-repos_rust-lang_rust_git_commits_109cccbe4f345c0f0785ce860788580c3e2a29f5.json new file mode 100644 index 00000000..40cc3973 --- /dev/null +++ b/tests/github_client/git_commit/01-GET-repos_rust-lang_rust_git_commits_109cccbe4f345c0f0785ce860788580c3e2a29f5.json @@ -0,0 +1,47 @@ +{ + "kind": "Request", + "method": "GET", + "path": "/repos/rust-lang/rust/git/commits/109cccbe4f345c0f0785ce860788580c3e2a29f5", + "query": null, + "request_body": "", + "response_code": 200, + "response_body": { + "author": { + "date": "2022-12-13T07:10:53Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "committer": { + "date": "2022-12-13T07:10:53Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/109cccbe4f345c0f0785ce860788580c3e2a29f5", + "message": "Auto merge of #105350 - compiler-errors:faster-binder-relate, r=oli-obk\n\nFast-path some binder relations\n\nA simpler approach than #104598\n\nFixes #104583\n\nr? types", + "node_id": "C_kwDOAAsO6NoAKDEwOWNjY2JlNGYzNDVjMGYwNzg1Y2U4NjA3ODg1ODBjM2UyYTI5ZjU", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/71ec1457ee9868a838e4521a3510cdd416c0c295", + "sha": "71ec1457ee9868a838e4521a3510cdd416c0c295", + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/71ec1457ee9868a838e4521a3510cdd416c0c295" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/2025a96ee1a699722da73993995b6f0572374757", + "sha": "2025a96ee1a699722da73993995b6f0572374757", + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/2025a96ee1a699722da73993995b6f0572374757" + } + ], + "sha": "109cccbe4f345c0f0785ce860788580c3e2a29f5", + "tree": { + "sha": "e67d87c61892169977204cc2e3fd89b2a19e13bb", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/e67d87c61892169977204cc2e3fd89b2a19e13bb" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/109cccbe4f345c0f0785ce860788580c3e2a29f5", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + } +} diff --git a/tests/github_client/is_new_contributor/00-GET-repos_rust-lang_rust.json b/tests/github_client/is_new_contributor/00-GET-repos_rust-lang_rust.json new file mode 100644 index 00000000..2ec17b5e --- /dev/null +++ b/tests/github_client/is_new_contributor/00-GET-repos_rust-lang_rust.json @@ -0,0 +1,148 @@ +{ + "kind": "Request", + "method": "GET", + "path": "/repos/rust-lang/rust", + "query": null, + "request_body": "", + "response_code": 200, + "response_body": { + "allow_forking": true, + "archive_url": "https://api.github.com/repos/rust-lang/rust/{archive_format}{/ref}", + "archived": false, + "assignees_url": "https://api.github.com/repos/rust-lang/rust/assignees{/user}", + "blobs_url": "https://api.github.com/repos/rust-lang/rust/git/blobs{/sha}", + "branches_url": "https://api.github.com/repos/rust-lang/rust/branches{/branch}", + "clone_url": "https://github.com/rust-lang/rust.git", + "collaborators_url": "https://api.github.com/repos/rust-lang/rust/collaborators{/collaborator}", + "comments_url": "https://api.github.com/repos/rust-lang/rust/comments{/number}", + "commits_url": "https://api.github.com/repos/rust-lang/rust/commits{/sha}", + "compare_url": "https://api.github.com/repos/rust-lang/rust/compare/{base}...{head}", + "contents_url": "https://api.github.com/repos/rust-lang/rust/contents/{+path}", + "contributors_url": "https://api.github.com/repos/rust-lang/rust/contributors", + "created_at": "2010-06-16T20:39:03Z", + "default_branch": "master", + "deployments_url": "https://api.github.com/repos/rust-lang/rust/deployments", + "description": "Empowering everyone to build reliable and efficient software.", + "disabled": false, + "downloads_url": "https://api.github.com/repos/rust-lang/rust/downloads", + "events_url": "https://api.github.com/repos/rust-lang/rust/events", + "fork": false, + "forks": 10323, + "forks_count": 10323, + "forks_url": "https://api.github.com/repos/rust-lang/rust/forks", + "full_name": "rust-lang/rust", + "git_commits_url": "https://api.github.com/repos/rust-lang/rust/git/commits{/sha}", + "git_refs_url": "https://api.github.com/repos/rust-lang/rust/git/refs{/sha}", + "git_tags_url": "https://api.github.com/repos/rust-lang/rust/git/tags{/sha}", + "git_url": "git://github.com/rust-lang/rust.git", + "has_discussions": false, + "has_downloads": true, + "has_issues": true, + "has_pages": false, + "has_projects": true, + "has_wiki": false, + "homepage": "https://www.rust-lang.org", + "hooks_url": "https://api.github.com/repos/rust-lang/rust/hooks", + "html_url": "https://github.com/rust-lang/rust", + "id": 724712, + "is_template": false, + "issue_comment_url": "https://api.github.com/repos/rust-lang/rust/issues/comments{/number}", + "issue_events_url": "https://api.github.com/repos/rust-lang/rust/issues/events{/number}", + "issues_url": "https://api.github.com/repos/rust-lang/rust/issues{/number}", + "keys_url": "https://api.github.com/repos/rust-lang/rust/keys{/key_id}", + "labels_url": "https://api.github.com/repos/rust-lang/rust/labels{/name}", + "language": "Rust", + "languages_url": "https://api.github.com/repos/rust-lang/rust/languages", + "license": { + "key": "other", + "name": "Other", + "node_id": "MDc6TGljZW5zZTA=", + "spdx_id": "NOASSERTION", + "url": null + }, + "merges_url": "https://api.github.com/repos/rust-lang/rust/merges", + "milestones_url": "https://api.github.com/repos/rust-lang/rust/milestones{/number}", + "mirror_url": null, + "name": "rust", + "network_count": 10323, + "node_id": "MDEwOlJlcG9zaXRvcnk3MjQ3MTI=", + "notifications_url": "https://api.github.com/repos/rust-lang/rust/notifications{?since,all,participating}", + "open_issues": 9504, + "open_issues_count": 9504, + "organization": { + "avatar_url": "https://avatars.githubusercontent.com/u/5430905?v=4", + "events_url": "https://api.github.com/users/rust-lang/events{/privacy}", + "followers_url": "https://api.github.com/users/rust-lang/followers", + "following_url": "https://api.github.com/users/rust-lang/following{/other_user}", + "gists_url": "https://api.github.com/users/rust-lang/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/rust-lang", + "id": 5430905, + "login": "rust-lang", + "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MzA5MDU=", + "organizations_url": "https://api.github.com/users/rust-lang/orgs", + "received_events_url": "https://api.github.com/users/rust-lang/received_events", + "repos_url": "https://api.github.com/users/rust-lang/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/rust-lang/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rust-lang/subscriptions", + "type": "Organization", + "url": "https://api.github.com/users/rust-lang" + }, + "owner": { + "avatar_url": "https://avatars.githubusercontent.com/u/5430905?v=4", + "events_url": "https://api.github.com/users/rust-lang/events{/privacy}", + "followers_url": "https://api.github.com/users/rust-lang/followers", + "following_url": "https://api.github.com/users/rust-lang/following{/other_user}", + "gists_url": "https://api.github.com/users/rust-lang/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/rust-lang", + "id": 5430905, + "login": "rust-lang", + "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MzA5MDU=", + "organizations_url": "https://api.github.com/users/rust-lang/orgs", + "received_events_url": "https://api.github.com/users/rust-lang/received_events", + "repos_url": "https://api.github.com/users/rust-lang/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/rust-lang/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rust-lang/subscriptions", + "type": "Organization", + "url": "https://api.github.com/users/rust-lang" + }, + "permissions": { + "admin": false, + "maintain": false, + "pull": true, + "push": true, + "triage": true + }, + "private": false, + "pulls_url": "https://api.github.com/repos/rust-lang/rust/pulls{/number}", + "pushed_at": "2023-02-05T14:10:34Z", + "releases_url": "https://api.github.com/repos/rust-lang/rust/releases{/id}", + "size": 1066264, + "ssh_url": "git@github.com:rust-lang/rust.git", + "stargazers_count": 77394, + "stargazers_url": "https://api.github.com/repos/rust-lang/rust/stargazers", + "statuses_url": "https://api.github.com/repos/rust-lang/rust/statuses/{sha}", + "subscribers_count": 1488, + "subscribers_url": "https://api.github.com/repos/rust-lang/rust/subscribers", + "subscription_url": "https://api.github.com/repos/rust-lang/rust/subscription", + "svn_url": "https://github.com/rust-lang/rust", + "tags_url": "https://api.github.com/repos/rust-lang/rust/tags", + "teams_url": "https://api.github.com/repos/rust-lang/rust/teams", + "topics": [ + "compiler", + "hacktoberfest", + "language", + "rust" + ], + "trees_url": "https://api.github.com/repos/rust-lang/rust/git/trees{/sha}", + "updated_at": "2023-02-05T14:20:35Z", + "url": "https://api.github.com/repos/rust-lang/rust", + "visibility": "public", + "watchers": 77394, + "watchers_count": 77394, + "web_commit_signoff_required": false + } +} diff --git a/tests/github_client/is_new_contributor/01-GET-repos_rust-lang_rust_commits.json b/tests/github_client/is_new_contributor/01-GET-repos_rust-lang_rust_commits.json new file mode 100644 index 00000000..d7219399 --- /dev/null +++ b/tests/github_client/is_new_contributor/01-GET-repos_rust-lang_rust_commits.json @@ -0,0 +1,9 @@ +{ + "kind": "Request", + "method": "GET", + "path": "/repos/rust-lang/rust/commits", + "query": "author=octocat", + "request_body": "", + "response_code": 200, + "response_body": [] +} diff --git a/tests/github_client/is_new_contributor/02-GET-repos_rust-lang_rust_commits.json b/tests/github_client/is_new_contributor/02-GET-repos_rust-lang_rust_commits.json new file mode 100644 index 00000000..4fcaca4f --- /dev/null +++ b/tests/github_client/is_new_contributor/02-GET-repos_rust-lang_rust_commits.json @@ -0,0 +1,2380 @@ +{ + "kind": "Request", + "method": "GET", + "path": "/repos/rust-lang/rust/commits", + "query": "author=brson", + "request_body": "", + "response_code": 200, + "response_body": [ + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/147214?v=4", + "events_url": "https://api.github.com/users/brson/events{/privacy}", + "followers_url": "https://api.github.com/users/brson/followers", + "following_url": "https://api.github.com/users/brson/following{/other_user}", + "gists_url": "https://api.github.com/users/brson/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/brson", + "id": 147214, + "login": "brson", + "node_id": "MDQ6VXNlcjE0NzIxNA==", + "organizations_url": "https://api.github.com/users/brson/orgs", + "received_events_url": "https://api.github.com/users/brson/received_events", + "repos_url": "https://api.github.com/users/brson/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/brson/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/brson/subscriptions", + "type": "User", + "url": "https://api.github.com/users/brson" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/356848c9b9a3bd8226bbabd08611b1e519acc9c7/comments", + "commit": { + "author": { + "date": "2020-05-07T02:42:12Z", + "email": "andersrb@gmail.com", + "name": "Brian Anderson" + }, + "comment_count": 0, + "committer": { + "date": "2020-05-07T02:42:12Z", + "email": "andersrb@gmail.com", + "name": "Brian Anderson" + }, + "message": "Add two more TiKV bugs to trophy case", + "tree": { + "sha": "d1aae96f10ecb490d6caebc63de18f34885cb73d", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/d1aae96f10ecb490d6caebc63de18f34885cb73d" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/356848c9b9a3bd8226bbabd08611b1e519acc9c7", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/147214?v=4", + "events_url": "https://api.github.com/users/brson/events{/privacy}", + "followers_url": "https://api.github.com/users/brson/followers", + "following_url": "https://api.github.com/users/brson/following{/other_user}", + "gists_url": "https://api.github.com/users/brson/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/brson", + "id": 147214, + "login": "brson", + "node_id": "MDQ6VXNlcjE0NzIxNA==", + "organizations_url": "https://api.github.com/users/brson/orgs", + "received_events_url": "https://api.github.com/users/brson/received_events", + "repos_url": "https://api.github.com/users/brson/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/brson/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/brson/subscriptions", + "type": "User", + "url": "https://api.github.com/users/brson" + }, + "html_url": "https://github.com/rust-lang/rust/commit/356848c9b9a3bd8226bbabd08611b1e519acc9c7", + "node_id": "MDY6Q29tbWl0NzI0NzEyOjM1Njg0OGM5YjlhM2JkODIyNmJiYWJkMDg2MTFiMWU1MTlhY2M5Yzc=", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/308458a4ab210da24c8fd481d0f930e50f512886", + "sha": "308458a4ab210da24c8fd481d0f930e50f512886", + "url": "https://api.github.com/repos/rust-lang/rust/commits/308458a4ab210da24c8fd481d0f930e50f512886" + } + ], + "sha": "356848c9b9a3bd8226bbabd08611b1e519acc9c7", + "url": "https://api.github.com/repos/rust-lang/rust/commits/356848c9b9a3bd8226bbabd08611b1e519acc9c7" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/147214?v=4", + "events_url": "https://api.github.com/users/brson/events{/privacy}", + "followers_url": "https://api.github.com/users/brson/followers", + "following_url": "https://api.github.com/users/brson/following{/other_user}", + "gists_url": "https://api.github.com/users/brson/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/brson", + "id": 147214, + "login": "brson", + "node_id": "MDQ6VXNlcjE0NzIxNA==", + "organizations_url": "https://api.github.com/users/brson/orgs", + "received_events_url": "https://api.github.com/users/brson/received_events", + "repos_url": "https://api.github.com/users/brson/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/brson/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/brson/subscriptions", + "type": "User", + "url": "https://api.github.com/users/brson" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/5e25dfaef83d1a2855cc4e4a1aecca77ba0dc47a/comments", + "commit": { + "author": { + "date": "2020-05-01T21:34:16Z", + "email": "andersrb@gmail.com", + "name": "Brian Anderson" + }, + "comment_count": 0, + "committer": { + "date": "2020-05-01T21:34:16Z", + "email": "andersrb@gmail.com", + "name": "Brian Anderson" + }, + "message": "Add another tikv stacked borrowing error to trophy case", + "tree": { + "sha": "bbf63e95c9e9eac80d7f92875061c05352759cac", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/bbf63e95c9e9eac80d7f92875061c05352759cac" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/5e25dfaef83d1a2855cc4e4a1aecca77ba0dc47a", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/147214?v=4", + "events_url": "https://api.github.com/users/brson/events{/privacy}", + "followers_url": "https://api.github.com/users/brson/followers", + "following_url": "https://api.github.com/users/brson/following{/other_user}", + "gists_url": "https://api.github.com/users/brson/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/brson", + "id": 147214, + "login": "brson", + "node_id": "MDQ6VXNlcjE0NzIxNA==", + "organizations_url": "https://api.github.com/users/brson/orgs", + "received_events_url": "https://api.github.com/users/brson/received_events", + "repos_url": "https://api.github.com/users/brson/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/brson/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/brson/subscriptions", + "type": "User", + "url": "https://api.github.com/users/brson" + }, + "html_url": "https://github.com/rust-lang/rust/commit/5e25dfaef83d1a2855cc4e4a1aecca77ba0dc47a", + "node_id": "MDY6Q29tbWl0NzI0NzEyOjVlMjVkZmFlZjgzZDFhMjg1NWNjNGU0YTFhZWNjYTc3YmEwZGM0N2E=", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/d606172f32a4ca6c6ce73147760ee0ca1ed439b9", + "sha": "d606172f32a4ca6c6ce73147760ee0ca1ed439b9", + "url": "https://api.github.com/repos/rust-lang/rust/commits/d606172f32a4ca6c6ce73147760ee0ca1ed439b9" + } + ], + "sha": "5e25dfaef83d1a2855cc4e4a1aecca77ba0dc47a", + "url": "https://api.github.com/repos/rust-lang/rust/commits/5e25dfaef83d1a2855cc4e4a1aecca77ba0dc47a" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/147214?v=4", + "events_url": "https://api.github.com/users/brson/events{/privacy}", + "followers_url": "https://api.github.com/users/brson/followers", + "following_url": "https://api.github.com/users/brson/following{/other_user}", + "gists_url": "https://api.github.com/users/brson/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/brson", + "id": 147214, + "login": "brson", + "node_id": "MDQ6VXNlcjE0NzIxNA==", + "organizations_url": "https://api.github.com/users/brson/orgs", + "received_events_url": "https://api.github.com/users/brson/received_events", + "repos_url": "https://api.github.com/users/brson/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/brson/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/brson/subscriptions", + "type": "User", + "url": "https://api.github.com/users/brson" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/488f3801e2a22afb093d03cf176169d91212374c/comments", + "commit": { + "author": { + "date": "2020-04-30T00:03:43Z", + "email": "andersrb@gmail.com", + "name": "Brian Anderson" + }, + "comment_count": 0, + "committer": { + "date": "2020-04-30T00:03:43Z", + "email": "andersrb@gmail.com", + "name": "Brian Anderson" + }, + "message": "Add servo_arc to trophy case", + "tree": { + "sha": "bb1cf8cc877de4c14875aed208aca50321759c7f", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/bb1cf8cc877de4c14875aed208aca50321759c7f" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/488f3801e2a22afb093d03cf176169d91212374c", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/147214?v=4", + "events_url": "https://api.github.com/users/brson/events{/privacy}", + "followers_url": "https://api.github.com/users/brson/followers", + "following_url": "https://api.github.com/users/brson/following{/other_user}", + "gists_url": "https://api.github.com/users/brson/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/brson", + "id": 147214, + "login": "brson", + "node_id": "MDQ6VXNlcjE0NzIxNA==", + "organizations_url": "https://api.github.com/users/brson/orgs", + "received_events_url": "https://api.github.com/users/brson/received_events", + "repos_url": "https://api.github.com/users/brson/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/brson/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/brson/subscriptions", + "type": "User", + "url": "https://api.github.com/users/brson" + }, + "html_url": "https://github.com/rust-lang/rust/commit/488f3801e2a22afb093d03cf176169d91212374c", + "node_id": "MDY6Q29tbWl0NzI0NzEyOjQ4OGYzODAxZTJhMjJhZmIwOTNkMDNjZjE3NjE2OWQ5MTIxMjM3NGM=", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/dc91c172a469b51cf038d97e361458cd09b13fbd", + "sha": "dc91c172a469b51cf038d97e361458cd09b13fbd", + "url": "https://api.github.com/repos/rust-lang/rust/commits/dc91c172a469b51cf038d97e361458cd09b13fbd" + } + ], + "sha": "488f3801e2a22afb093d03cf176169d91212374c", + "url": "https://api.github.com/repos/rust-lang/rust/commits/488f3801e2a22afb093d03cf176169d91212374c" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/147214?v=4", + "events_url": "https://api.github.com/users/brson/events{/privacy}", + "followers_url": "https://api.github.com/users/brson/followers", + "following_url": "https://api.github.com/users/brson/following{/other_user}", + "gists_url": "https://api.github.com/users/brson/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/brson", + "id": 147214, + "login": "brson", + "node_id": "MDQ6VXNlcjE0NzIxNA==", + "organizations_url": "https://api.github.com/users/brson/orgs", + "received_events_url": "https://api.github.com/users/brson/received_events", + "repos_url": "https://api.github.com/users/brson/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/brson/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/brson/subscriptions", + "type": "User", + "url": "https://api.github.com/users/brson" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/f84aa4a424221a8b3739f6232fec8f419d176fba/comments", + "commit": { + "author": { + "date": "2020-04-23T08:46:36Z", + "email": "andersrb@gmail.com", + "name": "Brian Anderson" + }, + "comment_count": 0, + "committer": { + "date": "2020-04-23T08:46:36Z", + "email": "noreply@github.com", + "name": "GitHub" + }, + "message": "Update README.md\n\nCo-Authored-By: Ralf Jung ", + "tree": { + "sha": "9ad87c344ce2232649af262bad2e4b10d7b5cddc", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/9ad87c344ce2232649af262bad2e4b10d7b5cddc" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/f84aa4a424221a8b3739f6232fec8f419d176fba", + "verification": { + "payload": "tree 9ad87c344ce2232649af262bad2e4b10d7b5cddc\nparent 5b60f0df2afba76fb6bd4cc3ae0c85ea2cfd484c\nauthor Brian Anderson 1587631596 -0600\ncommitter GitHub
Connection for P +where + P: Send + Sync + PClient, +{ + async fn transaction(&mut self) -> Box { + let tx = self.conn_mut().transaction().await.unwrap(); + Box::new(PostgresTransaction { conn: tx }) + } + + async fn record_username(&mut self, user_id: i64, username: String) -> Result<()> { + self.conn() + .execute( + "INSERT INTO users (user_id, username) VALUES ($1, $2) ON CONFLICT DO NOTHING", + &[&user_id, &username], + ) + .await + .context("inserting user id / username")?; + Ok(()) + } + + async fn record_ping(&mut self, notification: &Notification) -> Result<()> { + self.conn() + .execute( + "INSERT INTO notifications + (user_id, origin_url, origin_html, time, short_description, team_name, idx) + VALUES ( + $1, $2, $3, $4, $5, $6, + (SELECT max(notifications.idx) + 1 from notifications + where notifications.user_id = $1) + )", + &[ + ¬ification.user_id, + ¬ification.origin_url, + ¬ification.origin_html, + ¬ification.time, + ¬ification.short_description, + ¬ification.team_name, + ], + ) + .await + .context("inserting notification")?; + + Ok(()) + } + + async fn get_missing_commits(&mut self) -> Result> { + let missing = self + .conn() + .query( + " + SELECT parent_sha + FROM rustc_commits + WHERE parent_sha NOT IN ( + SELECT sha + FROM rustc_commits + )", + &[], + ) + .await + .context("fetching missing commits")?; + Ok(missing.into_iter().map(|row| row.get(0)).collect()) + } + + async fn record_commit(&mut self, commit: &Commit) -> Result<()> { + trace!("record_commit(sha={})", commit.sha); + let pr = commit.pr.expect("commit has pr"); + self.conn() + .execute( + "INSERT INTO rustc_commits (sha, parent_sha, time, pr) + VALUES ($1, $2, $3, $4) ON CONFLICT DO NOTHING", + &[&commit.sha, &commit.parent_sha, &commit.time, &(pr as i32)], + ) + .await + .context("inserting commit")?; + Ok(()) + } + + async fn has_commit(&mut self, sha: &str) -> Result { + self.conn() + .query("SELECT 1 FROM rustc_commits WHERE sha = $1", &[&sha]) + .await + .context("selecting from rustc_commits") + .map(|commits| !commits.is_empty()) + } + + async fn get_commits_with_artifacts(&mut self) -> Result> { + let commits = self + .conn() + .query( + " + select sha, parent_sha, time, pr + from rustc_commits + where time >= current_date - interval '168 days' + order by time desc;", + &[], + ) + .await + .context("Getting commit data")?; + + let mut data = Vec::with_capacity(commits.len()); + for commit in commits { + let sha: String = commit.get(0); + let parent_sha: String = commit.get(1); + let time: DateTime = commit.get(2); + let pr: Option = commit.get(3); + + data.push(Commit { + sha, + parent_sha, + time, + pr: pr.map(|n| n as u32), + }); + } + + Ok(data) + } + + async fn get_notifications(&mut self, username: &str) -> Result> { + let notifications = self + .conn() + .query( + "SELECT username, origin_url, origin_html, time, short_description, idx, metadata + FROM notifications + JOIN users ON notifications.user_id = users.user_id + WHERE username = $1 + ORDER BY notifications.idx ASC NULLS LAST;", + &[&username], + ) + .await + .context("Getting notification data")?; + + let mut data = Vec::new(); + for notification in notifications { + let origin_url: String = notification.get(1); + let origin_text: String = notification.get(2); + let time: DateTime = notification.get(3); + let short_description: Option = notification.get(4); + let metadata: Option = notification.get(6); + + data.push(NotificationData { + origin_url, + origin_text, + short_description, + time, + metadata, + }); + } + + Ok(data) + } + + async fn delete_ping( + &mut self, + user_id: i64, + identifier: Identifier<'_>, + ) -> Result> { + match identifier { + Identifier::Url(origin_url) => { + let rows = self + .conn() + .query( + "DELETE FROM notifications WHERE user_id = $1 and origin_url = $2 + RETURNING origin_html, time, short_description, metadata", + &[&user_id, &origin_url], + ) + .await + .context("delete notification query")?; + Ok(rows + .into_iter() + .map(|row| { + let origin_text: String = row.get(0); + let time: DateTime = row.get(1); + let short_description: Option = row.get(2); + let metadata: Option = row.get(3); + NotificationData { + origin_url: origin_url.to_owned(), + origin_text, + time, + short_description, + metadata, + } + }) + .collect()) + } + Identifier::Index(idx) => loop { + let t = self + .build_transaction() + .isolation_level(tokio_postgres::IsolationLevel::Serializable) + .start() + .await + .context("begin transaction")?; + + let notifications = t + .query( + "SELECT notification_id, idx, user_id + FROM notifications + WHERE user_id = $1 + ORDER BY idx ASC NULLS LAST;", + &[&user_id], + ) + .await + .context("failed to get ordering")?; + + let notification_id: i64 = notifications + .get(idx.get() - 1) + .ok_or_else(|| { + anyhow::anyhow!("No such notification with index {}", idx.get()) + })? + .get(0); + + let row = t + .query_one( + "DELETE FROM notifications WHERE notification_id = $1 + RETURNING origin_url, origin_html, time, short_description, metadata", + &[¬ification_id], + ) + .await + .context(format!( + "Failed to delete notification with id {}", + notification_id + ))?; + + let origin_url: String = row.get(0); + let origin_text: String = row.get(1); + let time: DateTime = row.get(2); + let short_description: Option = row.get(3); + let metadata: Option = row.get(4); + let deleted_notification = NotificationData { + origin_url, + origin_text, + time, + short_description, + metadata, + }; + + if let Err(e) = t.commit().await { + if e.code().map_or(false, |c| { + *c == tokio_postgres::error::SqlState::T_R_SERIALIZATION_FAILURE + }) { + trace!("serialization failure, restarting deletion"); + continue; + } else { + return Err(e).context("transaction commit failure"); + } + } else { + return Ok(vec![deleted_notification]); + } + }, + Identifier::All => { + let rows = self + .conn() + .query( + "DELETE FROM notifications WHERE user_id = $1 + RETURNING origin_url, origin_html, time, short_description, metadata", + &[&user_id], + ) + .await + .context("delete all notifications query")?; + Ok(rows + .into_iter() + .map(|row| { + let origin_url: String = row.get(0); + let origin_text: String = row.get(1); + let time: DateTime = row.get(2); + let short_description: Option = row.get(3); + let metadata: Option = row.get(4); + NotificationData { + origin_url, + origin_text, + time, + short_description, + metadata, + } + }) + .collect()) + } + } + } + + async fn add_metadata( + &mut self, + user_id: i64, + idx: usize, + metadata: Option<&str>, + ) -> Result<()> { + loop { + let t = self + .build_transaction() + .isolation_level(tokio_postgres::IsolationLevel::Serializable) + .start() + .await + .context("begin transaction")?; + + let notifications = t + .query( + "SELECT notification_id, idx, user_id + FROM notifications + WHERE user_id = $1 + ORDER BY idx ASC NULLS LAST;", + &[&user_id], + ) + .await + .context("failed to get initial ordering")?; + + let notifications = notifications + .into_iter() + .map(|n| n.get(0)) + .collect::>(); + + match notifications.get(idx) { + None => anyhow::bail!( + "index not present, must be less than {}", + notifications.len() + ), + Some(id) => { + t.execute( + "UPDATE notifications SET metadata = $2 + WHERE notification_id = $1", + &[&id, &metadata], + ) + .await + .context("update notification id")?; + } + } + + if let Err(e) = t.commit().await { + if e.code().map_or(false, |c| { + *c == tokio_postgres::error::SqlState::T_R_SERIALIZATION_FAILURE + }) { + trace!("serialization failure, restarting index movement"); + continue; + } else { + return Err(e).context("transaction commit failure"); + } + } else { + break; + } + } + + Ok(()) + } + + async fn move_indices(&mut self, user_id: i64, from: usize, to: usize) -> Result<()> { + loop { + let t = self + .build_transaction() + .isolation_level(tokio_postgres::IsolationLevel::Serializable) + .start() + .await + .context("begin transaction")?; + + let notifications = t + .query( + "SELECT notification_id, idx, user_id + FROM notifications + WHERE user_id = $1 + ORDER BY idx ASC NULLS LAST;", + &[&user_id], + ) + .await + .context("failed to get initial ordering")?; + + let mut notifications = notifications + .into_iter() + .map(|n| n.get(0)) + .collect::>(); + + if notifications.get(from).is_none() { + anyhow::bail!( + "`from` index not present, must be less than {}", + notifications.len() + ); + } + + if notifications.get(to).is_none() { + anyhow::bail!( + "`to` index not present, must be less than {}", + notifications.len() + ); + } + + if from < to { + notifications[from..=to].rotate_left(1); + } else if to < from { + notifications[to..=from].rotate_right(1); + } + + for (idx, id) in notifications.into_iter().enumerate() { + t.execute( + "UPDATE notifications SET idx = $2 + WHERE notification_id = $1", + &[&id, &(idx as i32)], + ) + .await + .context("update notification id")?; + } + + if let Err(e) = t.commit().await { + if e.code().map_or(false, |c| { + *c == tokio_postgres::error::SqlState::T_R_SERIALIZATION_FAILURE + }) { + trace!("serialization failure, restarting index movement"); + continue; + } else { + return Err(e).context("transaction commit failure"); + } + } else { + break; + } + } + + Ok(()) + } + + async fn insert_job( + &mut self, + name: &str, + scheduled_at: &DateTime, + metadata: &serde_json::Value, + ) -> Result<()> { + tracing::trace!("insert_job(name={})", name); + + self.conn() + .execute( + "INSERT INTO jobs (name, scheduled_at, metadata) VALUES ($1, $2, $3) + ON CONFLICT (name, scheduled_at) DO UPDATE SET metadata = EXCLUDED.metadata", + &[&name, &scheduled_at, &metadata], + ) + .await + .context("Inserting job")?; + + Ok(()) + } + + async fn delete_job(&mut self, id: &Uuid) -> Result<()> { + tracing::trace!("delete_job(id={})", id); + + self.conn() + .execute("DELETE FROM jobs WHERE id = $1", &[id]) + .await + .context("Deleting job")?; + + Ok(()) + } + + async fn update_job_error_message(&mut self, id: &Uuid, message: &str) -> Result<()> { + tracing::trace!("update_job_error_message(id={})", id); + + self.conn() + .execute( + "UPDATE jobs SET error_message = $2 WHERE id = $1", + &[&id, &message], + ) + .await + .context("Updating job error message")?; + + Ok(()) + } + + async fn update_job_executed_at(&mut self, id: &Uuid) -> Result<()> { + tracing::trace!("update_job_executed_at(id={})", id); + + self.conn() + .execute("UPDATE jobs SET executed_at = now() WHERE id = $1", &[&id]) + .await + .context("Updating job executed at")?; + + Ok(()) + } + + async fn get_job_by_name_and_scheduled_at( + &mut self, + name: &str, + scheduled_at: &DateTime, + ) -> Result { + tracing::trace!( + "get_job_by_name_and_scheduled_at(name={}, scheduled_at={})", + name, + scheduled_at + ); + + let job = self + .conn() + .query_one( + "SELECT * FROM jobs WHERE name = $1 AND scheduled_at = $2", + &[&name, &scheduled_at], + ) + .await + .context("Select job by name and scheduled at")?; + + deserialize_job(&job) + } + + async fn get_jobs_to_execute(&mut self) -> Result> { + let jobs = self + .conn() + .query( + "SELECT * FROM jobs WHERE scheduled_at <= now() + AND (error_message IS NULL OR executed_at <= now() - INTERVAL '60 minutes')", + &[], + ) + .await + .context("Getting jobs data")?; + + let mut data = Vec::with_capacity(jobs.len()); + for job in jobs { + let serialized_job = deserialize_job(&job); + data.push(serialized_job.unwrap()); + } + + Ok(data) + } + + async fn lock_and_load_issue_data( + &mut self, + repo: &str, + issue_number: i32, + key: &str, + ) -> Result<(Box, Option)> { + let transaction = self.conn_mut().transaction().await?; + transaction + .execute("LOCK TABLE issue_data", &[]) + .await + .context("locking issue data")?; + let data = transaction + .query_opt( + "SELECT data FROM issue_data WHERE \ + repo = $1 AND issue_number = $2 AND key = $3", + &[&repo, &issue_number, &key], + ) + .await + .context("selecting issue data")? + .map(|row| row.get::>(0).0); + Ok((Box::new(PostgresTransaction { conn: transaction }), data)) + } + + async fn save_issue_data( + &mut self, + repo: &str, + issue_number: i32, + key: &str, + data: &serde_json::Value, + ) -> Result<()> { + self.conn() + .execute( + "INSERT INTO issue_data (repo, issue_number, key, data) \ + VALUES ($1, $2, $3, $4) \ + ON CONFLICT (repo, issue_number, key) DO UPDATE SET data=EXCLUDED.data", + &[&repo, &issue_number, &key, &Json(&data)], + ) + .await + .context("inserting issue data")?; + Ok(()) + } +} + +fn deserialize_job(row: &tokio_postgres::row::Row) -> Result { + let id: Uuid = row.try_get(0)?; + let name: String = row.try_get(1)?; + let scheduled_at: DateTime = row.try_get(2)?; + let metadata: serde_json::Value = row.try_get(3)?; + let executed_at: Option> = row.try_get(4)?; + let error_message: Option = row.try_get(5)?; + + Ok(Job { + id, + name, + scheduled_at, + metadata, + executed_at, + error_message, + }) +} diff --git a/src/db/rustc_commits.rs b/src/db/rustc_commits.rs deleted file mode 100644 index b272d44c..00000000 --- a/src/db/rustc_commits.rs +++ /dev/null @@ -1,79 +0,0 @@ -use anyhow::Context as _; -use chrono::{DateTime, FixedOffset}; -use tokio_postgres::Client as DbClient; - -/// A bors merge commit. -#[derive(Debug, serde::Serialize)] -pub struct Commit { - pub sha: String, - pub parent_sha: String, - pub time: DateTime, - pub pr: Option, -} - -pub async fn record_commit(db: &DbClient, commit: Commit) -> anyhow::Result<()> { - tracing::trace!("record_commit(sha={})", commit.sha); - let pr = commit.pr.expect("commit has pr"); - db.execute( - "INSERT INTO rustc_commits (sha, parent_sha, time, pr) VALUES ($1, $2, $3, $4) ON CONFLICT DO NOTHING", - &[&commit.sha, &commit.parent_sha, &commit.time, &(pr as i32)], - ) - .await - .context("inserting commit")?; - Ok(()) -} - -pub async fn has_commit(db: &DbClient, sha: &str) -> bool { - !db.query("SELECT 1 FROM rustc_commits WHERE sha = $1", &[&sha]) - .await - .unwrap() - .is_empty() -} - -pub async fn get_missing_commits(db: &DbClient) -> Vec { - let missing = db - .query( - " - SELECT parent_sha - FROM rustc_commits - WHERE parent_sha NOT IN ( - SELECT sha - FROM rustc_commits - )", - &[], - ) - .await - .unwrap(); - missing.into_iter().map(|row| row.get(0)).collect() -} - -pub async fn get_commits_with_artifacts(db: &DbClient) -> anyhow::Result> { - let commits = db - .query( - " - select sha, parent_sha, time, pr - from rustc_commits - where time >= current_date - interval '168 days' - order by time desc;", - &[], - ) - .await - .context("Getting commit data")?; - - let mut data = Vec::with_capacity(commits.len()); - for commit in commits { - let sha: String = commit.get(0); - let parent_sha: String = commit.get(1); - let time: DateTime = commit.get(2); - let pr: Option = commit.get(3); - - data.push(Commit { - sha, - parent_sha, - time, - pr: pr.map(|n| n as u32), - }); - } - - Ok(data) -} diff --git a/src/db/sqlite.rs b/src/db/sqlite.rs new file mode 100644 index 00000000..77267ac1 --- /dev/null +++ b/src/db/sqlite.rs @@ -0,0 +1,742 @@ +use super::{Commit, Identifier, Notification, NotificationData}; +use crate::db::{Connection, ConnectionManager, Job, ManagedConnection, Transaction}; +use anyhow::{Context, Result}; +use chrono::DateTime; +use chrono::Utc; +use rusqlite::params; +use std::path::PathBuf; +use std::sync::Mutex; +use std::sync::Once; +use uuid::Uuid; + +pub struct SqliteTransaction<'a> { + conn: &'a mut SqliteConnection, + finished: bool, +} + +#[async_trait::async_trait] +impl<'a> Transaction for SqliteTransaction<'a> { + async fn commit(mut self: Box) -> Result<(), anyhow::Error> { + self.finished = true; + Ok(self.conn.raw().execute_batch("COMMIT")?) + } + + async fn finish(mut self: Box) -> Result<(), anyhow::Error> { + self.finished = true; + Ok(self.conn.raw().execute_batch("ROLLBACK")?) + } + fn conn(&mut self) -> &mut dyn Connection { + &mut *self.conn + } + fn conn_ref(&self) -> &dyn Connection { + &*self.conn + } +} + +impl std::ops::Deref for SqliteTransaction<'_> { + type Target = dyn Connection; + fn deref(&self) -> &Self::Target { + &*self.conn + } +} + +impl std::ops::DerefMut for SqliteTransaction<'_> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.conn + } +} + +impl Drop for SqliteTransaction<'_> { + fn drop(&mut self) { + if !self.finished { + self.conn.raw().execute_batch("ROLLBACK").unwrap(); + } + } +} + +pub struct Sqlite(PathBuf, Once); + +impl Sqlite { + pub fn new(path: PathBuf) -> Self { + if let Some(parent) = path.parent() { + if !parent.exists() { + std::fs::create_dir_all(parent).unwrap(); + } + } + Sqlite(path, Once::new()) + } +} + +struct Migration { + /// One or more SQL statements, each terminated by a semicolon. + sql: &'static str, + + /// If false, indicates that foreign key checking should be delayed until after execution of + /// the migration SQL, and foreign key `ON UPDATE` and `ON DELETE` actions disabled completely. + foreign_key_constraints_enabled: bool, +} + +impl Migration { + /// Returns a `Migration` with foreign key constraints enabled during execution. + const fn new(sql: &'static str) -> Migration { + Migration { + sql, + foreign_key_constraints_enabled: true, + } + } + + /// Returns a `Migration` with foreign key checking delayed until after execution, and foreign + /// key `ON UPDATE` and `ON DELETE` actions disabled completely. + /// + /// SQLite has limited `ALTER TABLE` capabilities, so some schema alterations require the + /// approach of replacing a table with a new one having the desired schema. Because there might + /// be other tables with foreign key constraints on the table, these constraints need to be + /// disabled during execution of such migration SQL, and reenabled after. Otherwise, dropping + /// the old table may trigger `ON DELETE` actions in the referencing tables. See [SQLite + /// documentation](https://www.sqlite.org/lang_altertable.html) for more information. + #[allow(dead_code)] + const fn without_foreign_key_constraints(sql: &'static str) -> Migration { + Migration { + sql, + foreign_key_constraints_enabled: false, + } + } + + fn execute(&self, conn: &mut rusqlite::Connection, migration_id: i32) { + if self.foreign_key_constraints_enabled { + let tx = conn.transaction().unwrap(); + tx.execute_batch(&self.sql).unwrap(); + tx.pragma_update(None, "user_version", &migration_id) + .unwrap(); + tx.commit().unwrap(); + return; + } + + // The following steps are reproduced from https://www.sqlite.org/lang_altertable.html, + // from the section titled, "Making Other Kinds Of Table Schema Changes". + + // 1. If foreign key constraints are enabled, disable them using PRAGMA foreign_keys=OFF. + conn.pragma_update(None, "foreign_keys", &"OFF").unwrap(); + + // 2. Start a transaction. + let tx = conn.transaction().unwrap(); + + // The migration SQL is responsible for steps 3 through 9. + + // 3. Remember the format of all indexes, triggers, and views associated with table X. + // This information will be needed in step 8 below. One way to do this is to run a + // query like the following: SELECT type, sql FROM sqlite_schema WHERE tbl_name='X'. + // + // 4. Use CREATE TABLE to construct a new table "new_X" that is in the desired revised + // format of table X. Make sure that the name "new_X" does not collide with any + // existing table name, of course. + // + // 5. Transfer content from X into new_X using a statement like: INSERT INTO new_X SELECT + // ... FROM X. + // + // 6. Drop the old table X: DROP TABLE X. + // + // 7. Change the name of new_X to X using: ALTER TABLE new_X RENAME TO X. + // + // 8. Use CREATE INDEX, CREATE TRIGGER, and CREATE VIEW to reconstruct indexes, triggers, + // and views associated with table X. Perhaps use the old format of the triggers, + // indexes, and views saved from step 3 above as a guide, making changes as appropriate + // for the alteration. + // + // 9. If any views refer to table X in a way that is affected by the schema change, then + // drop those views using DROP VIEW and recreate them with whatever changes are + // necessary to accommodate the schema change using CREATE VIEW. + tx.execute_batch(&self.sql).unwrap(); + + // 10. If foreign key constraints were originally enabled then run PRAGMA foreign_key_check + // to verify that the schema change did not break any foreign key constraints. + tx.pragma_query(None, "foreign_key_check", |row| { + let table: String = row.get_unwrap(0); + let row_id: Option = row.get_unwrap(1); + let foreign_table: String = row.get_unwrap(2); + let fk_idx: i64 = row.get_unwrap(3); + + tx.query_row::<(), _, _>( + "select * from pragma_foreign_key_list(?) where id = ?", + params![&table, &fk_idx], + |row| { + let col: String = row.get_unwrap(3); + let foreign_col: String = row.get_unwrap(4); + panic!( + "Foreign key violation encountered during migration\n\ + table: {},\n\ + column: {},\n\ + row_id: {:?},\n\ + foreign table: {},\n\ + foreign column: {}\n\ + migration ID: {}\n", + table, col, row_id, foreign_table, foreign_col, migration_id, + ); + }, + ) + .unwrap(); + Ok(()) + }) + .unwrap(); + + tx.pragma_update(None, "user_version", &migration_id) + .unwrap(); + + // 11. Commit the transaction started in step 2. + tx.commit().unwrap(); + + // 12. If foreign keys constraints were originally enabled, reenable them now. + conn.pragma_update(None, "foreign_keys", &"ON").unwrap(); + } +} + +static MIGRATIONS: &[Migration] = &[ + Migration::new(""), + Migration::new( + r#" +CREATE TABLE notifications ( + notification_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + user_id BIGINT, + origin_url TEXT NOT NULL, + origin_html TEXT, + time TEXT NOT NULL, + short_description TEXT, + team_name TEXT, + idx INTEGER, + metadata TEXT +); + "#, + ), + Migration::new( + r#" +CREATE TABLE users ( + user_id BIGINT PRIMARY KEY, + username TEXT NOT NULL +); + "#, + ), + Migration::new( + r#" +CREATE TABLE rustc_commits ( + sha TEXT PRIMARY KEY, + parent_sha TEXT NOT NULL, + time TEXT NOT NULL, + pr INTEGER +); + "#, + ), + Migration::new( + r#" +CREATE TABLE issue_data ( + repo TEXT, + issue_number INTEGER, + key TEXT, + data JSONB, + PRIMARY KEY (repo, issue_number, key) +); + "#, + ), + Migration::new( + r#" +CREATE TABLE jobs ( + id TEXT PRIMARY KEY, + name TEXT NOT NULL, + scheduled_at TIMESTAMP WITH TIME ZONE NOT NULL, + metadata JSONB, + executed_at TIMESTAMP WITH TIME ZONE, + error_message TEXT +); + "#, + ), + Migration::new( + r#" +CREATE UNIQUE INDEX jobs_name_scheduled_at_unique_index + ON jobs ( + name, scheduled_at + ); + "#, + ), +]; + +#[async_trait::async_trait] +impl ConnectionManager for Sqlite { + type Connection = Mutex; + async fn open(&self) -> Self::Connection { + let mut conn = rusqlite::Connection::open(&self.0).unwrap(); + conn.pragma_update(None, "cache_size", &-128000).unwrap(); + conn.pragma_update(None, "journal_mode", &"WAL").unwrap(); + conn.pragma_update(None, "foreign_keys", &"ON").unwrap(); + + self.1.call_once(|| { + let version: i32 = conn + .query_row( + "select user_version from pragma_user_version;", + params![], + |row| row.get(0), + ) + .unwrap(); + for mid in (version as usize + 1)..MIGRATIONS.len() { + MIGRATIONS[mid].execute(&mut conn, mid as i32); + } + }); + + Mutex::new(conn) + } + async fn is_valid(&self, conn: &mut Self::Connection) -> bool { + conn.get_mut() + .unwrap_or_else(|e| e.into_inner()) + .execute_batch("") + .is_ok() + } +} + +pub struct SqliteConnection { + conn: ManagedConnection>, +} + +#[async_trait::async_trait] +impl Connection for SqliteConnection { + async fn transaction(&mut self) -> Box { + Box::new(self.raw_transaction()) + } + + async fn record_username(&mut self, user_id: i64, username: String) -> Result<()> { + self.raw().execute( + "INSERT INTO users (user_id, username) VALUES (?, ?) ON CONFLICT DO NOTHING", + params![user_id, username], + )?; + Ok(()) + } + + async fn record_ping(&mut self, notification: &Notification) -> Result<()> { + self.raw().execute( + "INSERT INTO notifications + (user_id, origin_url, origin_html, time, short_description, team_name, idx) + VALUES ( + ?, ?, ?, ?, ?, ?, + (SELECT ifnull(max(notifications.idx), 0) + 1 from notifications + where notifications.user_id = ?) + )", + params![ + notification.user_id, + notification.origin_url, + notification.origin_html, + notification.time, + notification.short_description, + notification.team_name, + notification.user_id, + ], + )?; + Ok(()) + } + + async fn get_missing_commits(&mut self) -> Result> { + let commits = self + .raw() + .prepare( + " + SELECT parent_sha + FROM rustc_commits + WHERE parent_sha NOT IN ( + SELECT sha + FROM rustc_commits + )", + )? + .query_map([], |row| row.get(0))? + .collect::>()?; + Ok(commits) + } + + async fn record_commit(&mut self, commit: &Commit) -> Result<()> { + let pr = commit.pr.expect("commit has pr"); + // let time = commit.time.timestamp(); + self.raw().execute( + "INSERT INTO rustc_commits (sha, parent_sha, time, pr) \ + VALUES (?, ?, ?, ?) ON CONFLICT DO NOTHING", + params![commit.sha, commit.parent_sha, commit.time, pr], + )?; + Ok(()) + } + + async fn has_commit(&mut self, sha: &str) -> Result { + Ok(self + .raw() + .prepare("SELECT 1 FROM rustc_commits WHERE sha = ?")? + .query([sha])? + .next()? + .is_some()) + } + + async fn get_commits_with_artifacts(&mut self) -> Result> { + let commits = self + .raw() + .prepare( + "SELECT sha, parent_sha, time, pr + FROM rustc_commits + WHERE time >= datetime('now', '-168 days') + ORDER BY time DESC;", + )? + .query_map([], |row| { + let c = Commit { + sha: row.get(0)?, + parent_sha: row.get(1)?, + time: row.get(2)?, + pr: row.get(3)?, + }; + Ok(c) + })? + .collect::>()?; + Ok(commits) + } + + async fn get_notifications(&mut self, username: &str) -> Result> { + let notifications = self + .raw() + .prepare( + "SELECT username, origin_url, origin_html, time, short_description, idx, metadata + FROM notifications + JOIN users ON notifications.user_id = users.user_id + WHERE username = ? + ORDER BY notifications.idx ASC NULLS LAST;", + )? + .query_map([username], |row| { + let n = NotificationData { + origin_url: row.get(1)?, + origin_text: row.get(2)?, + time: row.get(3)?, + short_description: row.get(4)?, + metadata: row.get(6)?, + }; + Ok(n) + })? + .collect::>()?; + Ok(notifications) + } + + async fn delete_ping( + &mut self, + user_id: i64, + identifier: Identifier<'_>, + ) -> Result> { + match identifier { + Identifier::Url(origin_url) => { + let rows = self + .raw() + .prepare( + "DELETE FROM notifications WHERE user_id = ? and origin_url = ? + RETURNING origin_html, time, short_description, metadata", + )? + .query_map(params![user_id, origin_url], |row| { + let n = NotificationData { + origin_url: origin_url.to_string(), + origin_text: row.get(0)?, + time: row.get(1)?, + short_description: row.get(2)?, + metadata: row.get(3)?, + }; + Ok(n) + })? + .collect::>()?; + Ok(rows) + } + Identifier::Index(idx) => { + let deleted_notifications: Vec<_> = self + .raw() + .prepare( + "DELETE FROM notifications WHERE notification_id = ( + SELECT notification_id FROM notifications + WHERE user_id = ? + ORDER BY idx ASC NULLS LAST + LIMIT 1 OFFSET ? + ) + RETURNING origin_url, origin_html, time, short_description, metadata", + )? + .query_map(params![user_id, idx.get() - 1], |row| { + let n = NotificationData { + origin_url: row.get(0)?, + origin_text: row.get(1)?, + time: row.get(2)?, + short_description: row.get(3)?, + metadata: row.get(4)?, + }; + Ok(n) + })? + .collect::>()?; + if deleted_notifications.is_empty() { + anyhow::bail!("No such notification with index {}", idx.get()); + } + return Ok(deleted_notifications); + } + Identifier::All => { + let rows = self + .raw() + .prepare( + "DELETE FROM notifications WHERE user_id = ? + RETURNING origin_url, origin_html, time, short_description, metadata", + )? + .query_map([&user_id], |row| { + let n = NotificationData { + origin_url: row.get(0)?, + origin_text: row.get(1)?, + time: row.get(2)?, + short_description: row.get(3)?, + metadata: row.get(4)?, + }; + Ok(n) + })? + .collect::>()?; + Ok(rows) + } + } + } + + async fn add_metadata( + &mut self, + user_id: i64, + idx: usize, + metadata: Option<&str>, + ) -> Result<()> { + let t = self.raw().transaction()?; + + let notifications = t + .prepare( + "SELECT notification_id + FROM notifications + WHERE user_id = ? + ORDER BY idx ASC NULLS LAST", + )? + .query_map([user_id], |row| row.get(0)) + .context("failed to get initial ordering")? + .collect::, rusqlite::Error>>()?; + + match notifications.get(idx) { + None => anyhow::bail!( + "index not present, must be less than {}", + notifications.len() + ), + Some(id) => { + t.prepare( + "UPDATE notifications SET metadata = ? + WHERE notification_id = ?", + )? + .execute(params![metadata, id]) + .context("update notification id")?; + } + } + t.commit()?; + + Ok(()) + } + + async fn move_indices(&mut self, user_id: i64, from: usize, to: usize) -> Result<()> { + let t = self.raw().transaction()?; + + let mut notifications = t + .prepare( + "SELECT notification_id + FROM notifications + WHERE user_id = ? + ORDER BY idx ASC NULLS LAST;", + )? + .query_map([user_id], |row| row.get(0)) + .context("failed to get initial ordering")? + .collect::, rusqlite::Error>>()?; + + if notifications.get(from).is_none() { + anyhow::bail!( + "`from` index not present, must be less than {}", + notifications.len() + ); + } + + if notifications.get(to).is_none() { + anyhow::bail!( + "`to` index not present, must be less than {}", + notifications.len() + ); + } + + if from < to { + notifications[from..=to].rotate_left(1); + } else if to < from { + notifications[to..=from].rotate_right(1); + } + + for (idx, id) in notifications.into_iter().enumerate() { + t.prepare( + "UPDATE notifications SET idx = ? + WHERE notification_id = ?", + )? + .execute(params![idx, id]) + .context("update notification id")?; + } + t.commit()?; + + Ok(()) + } + + async fn insert_job( + &mut self, + name: &str, + scheduled_at: &DateTime, + metadata: &serde_json::Value, + ) -> Result<()> { + tracing::trace!("insert_job(name={})", name); + + let id = Uuid::new_v4(); + self.raw() + .execute( + "INSERT INTO jobs (id, name, scheduled_at, metadata) VALUES (?, ?, ?, ?) + ON CONFLICT (name, scheduled_at) DO UPDATE SET metadata = EXCLUDED.metadata", + params![id, name, scheduled_at, metadata], + ) + .context("Inserting job")?; + + Ok(()) + } + + async fn delete_job(&mut self, id: &Uuid) -> Result<()> { + tracing::trace!("delete_job(id={})", id); + + self.raw() + .execute("DELETE FROM jobs WHERE id = ?", [id]) + .context("Deleting job")?; + + Ok(()) + } + + async fn update_job_error_message(&mut self, id: &Uuid, message: &str) -> Result<()> { + tracing::trace!("update_job_error_message(id={})", id); + + self.raw() + .execute( + "UPDATE jobs SET error_message = ? WHERE id = ?", + params![message, id], + ) + .context("Updating job error message")?; + + Ok(()) + } + + async fn update_job_executed_at(&mut self, id: &Uuid) -> Result<()> { + tracing::trace!("update_job_executed_at(id={})", id); + + self.raw() + .execute( + "UPDATE jobs SET executed_at = datetime('now') WHERE id = ?", + [id], + ) + .context("Updating job executed at")?; + + Ok(()) + } + + async fn get_job_by_name_and_scheduled_at( + &mut self, + name: &str, + scheduled_at: &DateTime, + ) -> Result { + tracing::trace!( + "get_job_by_name_and_scheduled_at(name={}, scheduled_at={})", + name, + scheduled_at + ); + + let job = self + .raw() + .query_row( + "SELECT * FROM jobs WHERE name = ? AND scheduled_at = ?", + params![name, scheduled_at], + |row| deserialize_job(row), + ) + .context("Select job by name and scheduled at")?; + Ok(job) + } + + async fn get_jobs_to_execute(&mut self) -> Result> { + let jobs = self + .raw() + .prepare( + "SELECT * FROM jobs WHERE scheduled_at <= datetime('now') + AND (error_message IS NULL OR executed_at <= datetime('now', '-60 minutes'))", + )? + .query_map([], |row| deserialize_job(row))? + .collect::>()?; + Ok(jobs) + } + + async fn lock_and_load_issue_data( + &mut self, + repo: &str, + issue_number: i32, + key: &str, + ) -> Result<(Box, Option)> { + let transaction = self.raw_transaction(); + let data = match transaction + .conn + .raw() + .prepare( + "SELECT data FROM issue_data WHERE \ + repo = ? AND issue_number = ? AND key = ?", + )? + .query_row(params![repo, issue_number, key], |row| row.get(0)) + { + Err(rusqlite::Error::QueryReturnedNoRows) => None, + Err(e) => return Err(e.into()), + Ok(d) => Some(d), + }; + Ok((Box::new(transaction), data)) + } + + async fn save_issue_data( + &mut self, + repo: &str, + issue_number: i32, + key: &str, + data: &serde_json::Value, + ) -> Result<()> { + self.raw() + .execute( + "INSERT INTO issue_data (repo, issue_number, key, data) \ + VALUES (?, ?, ?, ?) \ + ON CONFLICT (repo, issue_number, key) DO UPDATE SET data=EXCLUDED.data", + params![repo, issue_number, key, data], + ) + .context("inserting issue data")?; + Ok(()) + } +} + +fn assert_sync() {} + +impl SqliteConnection { + pub fn new(conn: ManagedConnection>) -> Self { + assert_sync::(); + Self { conn } + } + + pub fn raw(&mut self) -> &mut rusqlite::Connection { + self.conn.get_mut().unwrap_or_else(|e| e.into_inner()) + } + pub fn raw_ref(&self) -> std::sync::MutexGuard { + self.conn.lock().unwrap_or_else(|e| e.into_inner()) + } + fn raw_transaction(&mut self) -> SqliteTransaction<'_> { + self.raw().execute_batch("BEGIN DEFERRED").unwrap(); + SqliteTransaction { + conn: self, + finished: false, + } + } +} + +fn deserialize_job(row: &rusqlite::Row<'_>) -> std::result::Result { + Ok(Job { + id: row.get(0)?, + name: row.get(1)?, + scheduled_at: row.get(2)?, + metadata: row.get(3)?, + executed_at: row.get(4)?, + error_message: row.get(5)?, + }) +} diff --git a/src/github.rs b/src/github.rs index 35309b2b..b7234e02 100644 --- a/src/github.rs +++ b/src/github.rs @@ -1,5 +1,7 @@ +use crate::test_record; use anyhow::Context; use async_trait::async_trait; +use bytes::Bytes; use chrono::{DateTime, FixedOffset, Utc}; use futures::{future::BoxFuture, FutureExt}; use hyper::header::HeaderValue; @@ -9,7 +11,7 @@ use reqwest::{Client, Request, RequestBuilder, Response, StatusCode}; use std::collections::{HashMap, HashSet}; use std::convert::TryInto; use std::{ - fmt, + fmt::{self, Write}, time::{Duration, SystemTime}, }; use tracing as log; @@ -21,22 +23,32 @@ pub struct User { } impl GithubClient { - async fn _send_req(&self, req: RequestBuilder) -> anyhow::Result<(Response, String)> { + async fn send_req(&self, req: RequestBuilder) -> anyhow::Result<(Bytes, String)> { const MAX_ATTEMPTS: usize = 2; - log::debug!("_send_req with {:?}", req); + log::debug!("send_req with {:?}", req); let req_dbg = format!("{:?}", req); let req = req .build() .with_context(|| format!("building reqwest {}", req_dbg))?; + let test_capture_info = test_record::capture_request(&req); + let mut resp = self.client.execute(req.try_clone().unwrap()).await?; if let Some(sleep) = Self::needs_retry(&resp).await { resp = self.retry(req, sleep, MAX_ATTEMPTS).await?; } + let status = resp.status(); + let maybe_err = resp.error_for_status_ref().err(); + let body = resp + .bytes() + .await + .with_context(|| format!("failed to read response body {req_dbg}"))?; + test_record::record_request(test_capture_info, status, &body); + if let Some(e) = maybe_err { + return Err(anyhow::Error::new(e)).with_context(|| format!("response: {}", String::from_utf8_lossy(&body))); + } - resp.error_for_status_ref()?; - - Ok((resp, req_dbg)) + Ok((body, req_dbg)) } async fn needs_retry(resp: &Response) -> Option { @@ -110,12 +122,13 @@ impl GithubClient { .client .execute( self.client - .get("https://api.github.com/rate_limit") + .get(&format!("{}/rate_limit", self.api_url)) .configure(self) .build() .unwrap(), ) .await?; + rate_resp.error_for_status_ref()?; let rate_limit_response = rate_resp.json::().await?; // Check url for search path because github has different rate limits for the search api @@ -151,33 +164,20 @@ impl GithubClient { .boxed() } - async fn send_req(&self, req: RequestBuilder) -> anyhow::Result> { - let (mut resp, req_dbg) = self._send_req(req).await?; - - let mut body = Vec::new(); - while let Some(chunk) = resp.chunk().await.transpose() { - let chunk = chunk - .context("reading stream failed") - .map_err(anyhow::Error::from) - .context(req_dbg.clone())?; - body.extend_from_slice(&chunk); - } - - Ok(body) - } - pub async fn json(&self, req: RequestBuilder) -> anyhow::Result where T: serde::de::DeserializeOwned, { - let (resp, req_dbg) = self._send_req(req).await?; - Ok(resp.json().await.context(req_dbg)?) + let (body, _req_dbg) = self.send_req(req).await?; + Ok(serde_json::from_slice(&body)?) } } impl User { pub async fn current(client: &GithubClient) -> anyhow::Result { - client.json(client.get("https://api.github.com/user")).await + client + .json(client.get(&format!("{}/user", client.api_url))) + .await } pub async fn is_team_member<'a>(&'a self, client: &'a GithubClient) -> anyhow::Result { @@ -252,7 +252,7 @@ pub struct Issue { pub number: u64, #[serde(deserialize_with = "opt_string")] pub body: String, - created_at: chrono::DateTime, + pub created_at: chrono::DateTime, pub updated_at: chrono::DateTime, /// The SHA for a merge commit. /// @@ -402,18 +402,18 @@ impl fmt::Display for IssueRepository { } impl IssueRepository { - fn url(&self) -> String { + fn url(&self, client: &GithubClient) -> String { format!( - "https://api.github.com/repos/{}/{}", - self.organization, self.repository + "{}/repos/{}/{}", + client.api_url, self.organization, self.repository ) } async fn has_label(&self, client: &GithubClient, label: &str) -> anyhow::Result { #[allow(clippy::redundant_pattern_matching)] - let url = format!("{}/labels/{}", self.url(), label); - match client._send_req(client.get(&url)).await { - Ok((_, _)) => Ok(true), + let url = format!("{}/labels/{}", self.url(client), label); + match client.send_req(client.get(&url)).await { + Ok(_) => Ok(true), Err(e) => { if e.downcast_ref::() .map_or(false, |e| e.status() == Some(StatusCode::NOT_FOUND)) @@ -481,19 +481,25 @@ impl Issue { } pub async fn get_comment(&self, client: &GithubClient, id: usize) -> anyhow::Result { - let comment_url = format!("{}/issues/comments/{}", self.repository().url(), id); + let comment_url = format!("{}/issues/comments/{}", self.repository().url(client), id); + let comment = client.json(client.get(&comment_url)).await?; + Ok(comment) + } + + pub async fn get_comments(&self, client: &GithubClient) -> anyhow::Result> { + let comment_url = format!("{}/issues/{}/comments", self.repository().url(client), self.number); let comment = client.json(client.get(&comment_url)).await?; Ok(comment) } pub async fn edit_body(&self, client: &GithubClient, body: &str) -> anyhow::Result<()> { - let edit_url = format!("{}/issues/{}", self.repository().url(), self.number); + let edit_url = format!("{}/issues/{}", self.repository().url(client), self.number); #[derive(serde::Serialize)] struct ChangedIssue<'a> { body: &'a str, } client - ._send_req(client.patch(&edit_url).json(&ChangedIssue { body })) + .send_req(client.patch(&edit_url).json(&ChangedIssue { body })) .await .context("failed to edit issue body")?; Ok(()) @@ -505,13 +511,13 @@ impl Issue { id: usize, new_body: &str, ) -> anyhow::Result<()> { - let comment_url = format!("{}/issues/comments/{}", self.repository().url(), id); + let comment_url = format!("{}/issues/comments/{}", self.repository().url(client), id); #[derive(serde::Serialize)] struct NewComment<'a> { body: &'a str, } client - ._send_req( + .send_req( client .patch(&comment_url) .json(&NewComment { body: new_body }), @@ -526,8 +532,13 @@ impl Issue { struct PostComment<'a> { body: &'a str, } + let comments_path = self + .comments_url + .strip_prefix("https://api.github.com") + .expect("expected api host"); + let comments_url = format!("{}{comments_path}", client.api_url); client - ._send_req(client.post(&self.comments_url).json(&PostComment { body })) + .send_req(client.post(&comments_url).json(&PostComment { body })) .await .context("failed to post comment")?; Ok(()) @@ -538,7 +549,7 @@ impl Issue { // DELETE /repos/:owner/:repo/issues/:number/labels/{name} let url = format!( "{repo_url}/issues/{number}/labels/{name}", - repo_url = self.repository().url(), + repo_url = self.repository().url(client), number = self.number, name = label, ); @@ -553,7 +564,7 @@ impl Issue { } client - ._send_req(client.delete(&url)) + .send_req(client.delete(&url)) .await .context("failed to delete label")?; @@ -570,7 +581,7 @@ impl Issue { // repo_url = https://api.github.com/repos/Codertocat/Hello-World let url = format!( "{repo_url}/issues/{number}/labels", - repo_url = self.repository().url(), + repo_url = self.repository().url(client), number = self.number ); @@ -610,7 +621,7 @@ impl Issue { } client - ._send_req(client.post(&url).json(&LabelsReq { + .send_req(client.post(&url).json(&LabelsReq { labels: known_labels, })) .await @@ -637,7 +648,7 @@ impl Issue { log::info!("remove {:?} assignees for {}", selection, self.global_id()); let url = format!( "{repo_url}/issues/{number}/assignees", - repo_url = self.repository().url(), + repo_url = self.repository().url(client), number = self.number ); @@ -661,7 +672,7 @@ impl Issue { assignees: &'a [&'a str], } client - ._send_req(client.delete(&url).json(&AssigneeReq { + .send_req(client.delete(&url).json(&AssigneeReq { assignees: &assignees[..], })) .await @@ -677,7 +688,7 @@ impl Issue { log::info!("add_assignee {} for {}", user, self.global_id()); let url = format!( "{repo_url}/issues/{number}/assignees", - repo_url = self.repository().url(), + repo_url = self.repository().url(client), number = self.number ); @@ -723,7 +734,7 @@ impl Issue { title ); - let create_url = format!("{}/milestones", self.repository().url()); + let create_url = format!("{}/milestones", self.repository().url(client)); let resp = client .send_req( client @@ -735,7 +746,7 @@ impl Issue { // fine, it just means the milestone was already created. log::trace!("Created milestone: {:?}", resp); - let list_url = format!("{}/milestones", self.repository().url()); + let list_url = format!("{}/milestones", self.repository().url(client)); let milestone_list: Vec = client.json(client.get(&list_url)).await?; let milestone_no = if let Some(milestone) = milestone_list.iter().find(|v| v.title == title) { @@ -752,9 +763,9 @@ impl Issue { struct SetMilestone { milestone: u64, } - let url = format!("{}/issues/{}", self.repository().url(), self.number); + let url = format!("{}/issues/{}", self.repository().url(client), self.number); client - ._send_req(client.patch(&url).json(&SetMilestone { + .send_req(client.patch(&url).json(&SetMilestone { milestone: milestone_no, })) .await @@ -763,13 +774,13 @@ impl Issue { } pub async fn close(&self, client: &GithubClient) -> anyhow::Result<()> { - let edit_url = format!("{}/issues/{}", self.repository().url(), self.number); + let edit_url = format!("{}/issues/{}", self.repository().url(client), self.number); #[derive(serde::Serialize)] struct CloseIssue<'a> { state: &'a str, } client - ._send_req( + .send_req( client .patch(&edit_url) .json(&CloseIssue { state: "closed" }), @@ -789,13 +800,14 @@ impl Issue { let mut req = client.get(&format!( "{}/compare/{}...{}", - self.repository().url(), + self.repository().url(client), before, after )); req = req.header("Accept", "application/vnd.github.v3.diff"); - let diff = client.send_req(req).await?; - Ok(Some(String::from(String::from_utf8_lossy(&diff)))) + let (diff, _) = client.send_req(req).await?; + let body = String::from_utf8_lossy(&diff).to_string(); + Ok(Some(body)) } /// Returns the commits from this pull request (no commits are returned if this `Issue` is not @@ -810,7 +822,7 @@ impl Issue { loop { let req = client.get(&format!( "{}/pulls/{}/commits?page={page}&per_page=100", - self.repository().url(), + self.repository().url(client), self.number )); @@ -832,7 +844,7 @@ impl Issue { let req = client.get(&format!( "{}/pulls/{}/files", - self.repository().url(), + self.repository().url(client), self.number )); Ok(client.json(req).await?) @@ -1004,11 +1016,8 @@ struct Ordering<'a> { } impl Repository { - const GITHUB_API_URL: &'static str = "https://api.github.com"; - const GITHUB_GRAPHQL_API_URL: &'static str = "https://api.github.com/graphql"; - - fn url(&self) -> String { - format!("{}/repos/{}", Repository::GITHUB_API_URL, self.full_name) + fn url(&self, client: &GithubClient) -> String { + format!("{}/repos/{}", client.api_url, self.full_name) } pub fn owner(&self) -> &str { @@ -1070,11 +1079,17 @@ impl Repository { let mut issues = vec![]; loop { let url = if use_search_api { - self.build_search_issues_url(&filters, include_labels, exclude_labels, ordering) + self.build_search_issues_url( + client, + &filters, + include_labels, + exclude_labels, + ordering, + ) } else if is_pr { - self.build_pulls_url(&filters, include_labels, ordering) + self.build_pulls_url(client, &filters, include_labels, ordering) } else { - self.build_issues_url(&filters, include_labels, ordering) + self.build_issues_url(client, &filters, include_labels, ordering) }; let result = client.get(&url); @@ -1103,24 +1118,27 @@ impl Repository { fn build_issues_url( &self, + client: &GithubClient, filters: &Vec<(&str, &str)>, include_labels: &Vec<&str>, ordering: Ordering<'_>, ) -> String { - self.build_endpoint_url("issues", filters, include_labels, ordering) + self.build_endpoint_url(client, "issues", filters, include_labels, ordering) } fn build_pulls_url( &self, + client: &GithubClient, filters: &Vec<(&str, &str)>, include_labels: &Vec<&str>, ordering: Ordering<'_>, ) -> String { - self.build_endpoint_url("pulls", filters, include_labels, ordering) + self.build_endpoint_url(client, "pulls", filters, include_labels, ordering) } fn build_endpoint_url( &self, + client: &GithubClient, endpoint: &str, filters: &Vec<(&str, &str)>, include_labels: &Vec<&str>, @@ -1143,15 +1161,13 @@ impl Repository { .join("&"); format!( "{}/repos/{}/{}?{}", - Repository::GITHUB_API_URL, - self.full_name, - endpoint, - filters + client.api_url, self.full_name, endpoint, filters ) } fn build_search_issues_url( &self, + client: &GithubClient, filters: &Vec<(&str, &str)>, include_labels: &Vec<&str>, exclude_labels: &Vec<&str>, @@ -1176,7 +1192,7 @@ impl Repository { .join("+"); format!( "{}/search/issues?q={}&sort={}&order={}&per_page={}&page={}", - Repository::GITHUB_API_URL, + client.api_url, filters, ordering.sort, ordering.direction, @@ -1187,7 +1203,7 @@ impl Repository { /// Retrieves a git commit for the given SHA. pub async fn git_commit(&self, client: &GithubClient, sha: &str) -> anyhow::Result { - let url = format!("{}/git/commits/{sha}", self.url()); + let url = format!("{}/git/commits/{sha}", self.url(client)); client .json(client.get(&url)) .await @@ -1202,7 +1218,7 @@ impl Repository { parents: &[&str], tree: &str, ) -> anyhow::Result { - let url = format!("{}/git/commits", self.url()); + let url = format!("{}/git/commits", self.url(client)); client .json(client.post(&url).json(&serde_json::json!({ "message": message, @@ -1213,29 +1229,63 @@ impl Repository { .with_context(|| format!("{} failed to create commit for tree {tree}", self.full_name)) } + /// TODO: encoding should be either "utf-8" or "base64". + pub async fn create_blob( + &self, + client: &GithubClient, + content: &str, + encoding: &str, + ) -> anyhow::Result { + let url = format!("{}/git/blobs", self.url(client)); + let resp: serde_json::Value = client + .json(client.post(&url).json(&serde_json::json!({ + "content": content, + "encoding": encoding, + }))) + .await + .with_context(|| format!("{} failed to create blob", self.full_name))?; + Ok(resp["sha"].as_str().unwrap().to_string()) + } + /// Retrieves a git reference for the given refname. pub async fn get_reference( &self, client: &GithubClient, refname: &str, ) -> anyhow::Result { - let url = format!("{}/git/ref/{}", self.url(), refname); + let url = format!("{}/git/ref/{}", self.url(client), refname); client .json(client.get(&url)) .await .with_context(|| format!("{} failed to get git reference {refname}", self.full_name)) } + pub async fn create_reference( + &self, + client: &GithubClient, + refname: &str, + sha: &str, + ) -> anyhow::Result { + let url = format!("{}/git/refs", self.url(client)); + client + .json(client.post(&url).json(&serde_json::json!({ + "ref": format!("refs/{refname}"), + "sha": sha, + }))) + .await + .with_context(|| format!("{} failed to create reference", self.full_name)) + } + /// Updates an existing git reference to a new SHA. pub async fn update_reference( &self, client: &GithubClient, refname: &str, sha: &str, - ) -> anyhow::Result<()> { - let url = format!("{}/git/refs/{}", self.url(), refname); + ) -> anyhow::Result { + let url = format!("{}/git/refs/{}", self.url(client), refname); client - ._send_req(client.patch(&url).json(&serde_json::json!({ + .json(client.patch(&url).json(&serde_json::json!({ "sha": sha, "force": true, }))) @@ -1245,8 +1295,26 @@ impl Repository { "{} failed to update reference {refname} to {sha}", self.full_name ) - })?; - Ok(()) + }) + } + + pub async fn create_or_update_reference( + &self, + client: &GithubClient, + refname: &str, + sha: &str, + ) -> anyhow::Result { + if let Err(e) = self.get_reference(client, refname).await { + if e.downcast_ref::() + .map_or(false, |e| e.status() == Some(StatusCode::NOT_FOUND)) + { + return self.create_reference(client, refname, sha).await; + } else { + return Err(e); + } + } else { + return self.update_reference(client, refname, sha).await; + } } /// Returns a list of recent commits on the given branch. @@ -1285,7 +1353,7 @@ impl Repository { let query = RecentCommits::build(args.clone()); let data = client .json::>( - client.post(Repository::GITHUB_GRAPHQL_API_URL).json(&query), + client.post(&client.graphql_url).json(&query), ) .await .with_context(|| { @@ -1424,7 +1492,7 @@ impl Repository { base_tree: &str, tree: &[GitTreeEntry], ) -> anyhow::Result { - let url = format!("{}/git/trees", self.url()); + let url = format!("{}/git/trees", self.url(client)); client .json(client.post(&url).json(&serde_json::json!({ "base_tree": base_tree, @@ -1449,7 +1517,7 @@ impl Repository { path: &str, refname: Option<&str>, ) -> anyhow::Result { - let mut url = format!("{}/contents/{}", self.url(), path); + let mut url = format!("{}/contents/{}", self.url(client), path); if let Some(refname) = refname { url.push_str("?ref="); url.push_str(refname); @@ -1471,7 +1539,7 @@ impl Repository { base: &str, body: &str, ) -> anyhow::Result { - let url = format!("{}/pulls", self.url()); + let url = format!("{}/pulls", self.url(client)); let mut issue: Issue = client .json(client.post(&url).json(&serde_json::json!({ "title": title, @@ -1490,11 +1558,48 @@ impl Repository { Ok(issue) } + pub async fn get_prs(&self, client: &GithubClient, + state: &str, + head: Option<&str>, + base: Option<&str>, + sort: Option<&str>, + direction: Option<&str>, + )-> anyhow::Result> { + let mut url = format!("{}/pulls?state={state}", self.url(client)); + if let Some(head) = head { + write!(url, "&head={head}&base={}", base.expect("base must be set if head is set")).unwrap(); + } + if let Some(sort) = sort { + write!(url, "&sort={sort}").unwrap(); + } + if let Some(direction) = direction { + write!(url, "&direction={direction}").unwrap(); + } + let mut issues: Vec = client + .json(client.get(&url)) + .await + .with_context(|| format!("{} failed to get prs", self.full_name))?; + for issue in &mut issues { + issue.pull_request = Some(PullRequestDetails {}); + } + Ok(issues) + } + + pub async fn get_pr(&self, client: &GithubClient, pull_number: u64) -> anyhow::Result { + let url = format!("{}/pulls/{pull_number}", self.url(client)); + let mut issue: Issue = client + .json(client.get(&url)) + .await + .with_context(|| format!("{} failed to get pr {pull_number}", self.full_name))?; + issue.pull_request = Some(PullRequestDetails {}); + Ok(issue) + } + /// Synchronize a branch (in a forked repository) by pulling in its upstream contents. pub async fn merge_upstream(&self, client: &GithubClient, branch: &str) -> anyhow::Result<()> { - let url = format!("{}/merge-upstream", self.url()); + let url = format!("{}/merge-upstream", self.url(client)); client - ._send_req(client.post(&url).json(&serde_json::json!({ + .send_req(client.post(&url).json(&serde_json::json!({ "branch": branch, }))) .await @@ -1506,6 +1611,42 @@ impl Repository { })?; Ok(()) } + + pub async fn has_label(&self, client: &GithubClient, label: &str) -> anyhow::Result { + // TODO merge with IssueRepository + let url = format!("{}/labels/{}", self.url(client), label); + match client.send_req(client.get(&url)).await { + Ok(_) => Ok(true), + Err(e) => { + if e.downcast_ref::() + .map_or(false, |e| e.status() == Some(StatusCode::NOT_FOUND)) + { + Ok(false) + } else { + Err(e) + } + } + } + } + + pub async fn create_label( + &self, + client: &GithubClient, + name: &str, + color: &str, + description: &str, + ) -> anyhow::Result<()> { + let url = format!("{}/labels", self.url(client)); + client + .send_req(client.post(&url).json(&serde_json::json!({ + "name": name, + "color": color, + "description": description, + }))) + .await + .with_context(|| format!("{} failed to create label {name}", self.full_name))?; + Ok(()) + } } pub struct Query<'a> { @@ -1763,15 +1904,32 @@ fn get_token_from_git_config() -> anyhow::Result { pub struct GithubClient { token: String, client: Client, + api_url: String, + graphql_url: String, + raw_url: String, } impl GithubClient { - pub fn new(client: Client, token: String) -> Self { - GithubClient { client, token } + pub fn new(token: String, api_url: String, graphql_url: String, raw_url: String) -> Self { + GithubClient { + client: Client::new(), + token, + api_url, + graphql_url, + raw_url, + } } - pub fn new_with_default_token(client: Client) -> Self { - Self::new(client, default_token_from_env()) + pub fn new_from_env() -> Self { + Self::new( + default_token_from_env(), + std::env::var("GITHUB_API_URL") + .unwrap_or_else(|_| "https://api.github.com".to_string()), + std::env::var("GITHUB_GRAPHQL_API_URL") + .unwrap_or_else(|_| "https://api.github.com/graphql".to_string()), + std::env::var("GITHUB_RAW_URL") + .unwrap_or_else(|_| "https://raw.githubusercontent.com".to_string()), + ) } pub fn raw(&self) -> &Client { @@ -1783,30 +1941,23 @@ impl GithubClient { repo: &str, branch: &str, path: &str, - ) -> anyhow::Result>> { - let url = format!( - "https://raw.githubusercontent.com/{}/{}/{}", - repo, branch, path - ); + ) -> anyhow::Result> { + let url = format!("{}/{repo}/{branch}/{path}", self.raw_url); let req = self.get(&url); let req_dbg = format!("{:?}", req); let req = req .build() .with_context(|| format!("failed to build request {:?}", req_dbg))?; - let mut resp = self.client.execute(req).await.context(req_dbg.clone())?; + let test_capture_info = test_record::capture_request(&req); + let resp = self.client.execute(req).await.context(req_dbg.clone())?; let status = resp.status(); + let body = resp + .bytes() + .await + .with_context(|| format!("failed to read response body {req_dbg}"))?; + test_record::record_request(test_capture_info, status, &body); match status { - StatusCode::OK => { - let mut buf = Vec::with_capacity(resp.content_length().unwrap_or(4) as usize); - while let Some(chunk) = resp.chunk().await.transpose() { - let chunk = chunk - .context("reading stream failed") - .map_err(anyhow::Error::from) - .context(req_dbg.clone())?; - buf.extend_from_slice(&chunk); - } - Ok(Some(buf)) - } + StatusCode::OK => Ok(Some(body)), StatusCode::NOT_FOUND => Ok(None), status => anyhow::bail!("failed to GET {}: {}", url, status), } @@ -1855,8 +2006,8 @@ impl GithubClient { pub async fn rust_commit(&self, sha: &str) -> Option { let req = self.get(&format!( - "https://api.github.com/repos/rust-lang/rust/commits/{}", - sha + "{}/repos/rust-lang/rust/commits/{sha}", + self.api_url )); match self.json(req).await { Ok(r) => Some(r), @@ -1869,7 +2020,10 @@ impl GithubClient { /// This does not retrieve all of them, only the last several. pub async fn bors_commits(&self) -> Vec { - let req = self.get("https://api.github.com/repos/rust-lang/rust/commits?author=bors"); + let req = self.get(&format!( + "{}/repos/rust-lang/rust/commits?author=bors", + self.api_url + )); match self.json(req).await { Ok(r) => r, Err(e) => { @@ -1884,9 +2038,7 @@ impl GithubClient { pub async fn is_new_contributor(&self, repo: &Repository, author: &str) -> bool { let url = format!( "{}/repos/{}/commits?author={}", - Repository::GITHUB_API_URL, - repo.full_name, - author, + self.api_url, repo.full_name, author, ); let req = self.get(&url); match self.json::>(req).await { @@ -1896,7 +2048,7 @@ impl GithubClient { Ok(res) => res.is_empty(), Err(e) => { log::warn!( - "failed to search for user commits in {} for author {author}: {e}", + "failed to search for user commits in {} for author {author}: {e:?}", repo.full_name ); false @@ -1908,7 +2060,7 @@ impl GithubClient { /// /// The `full_name` should be something like `rust-lang/rust`. pub async fn repository(&self, full_name: &str) -> anyhow::Result { - let req = self.get(&format!("{}/repos/{full_name}", Repository::GITHUB_API_URL)); + let req = self.get(&format!("{}/repos/{full_name}", self.api_url)); self.json(req) .await .with_context(|| format!("{} failed to get repo", full_name)) @@ -1953,7 +2105,13 @@ pub struct GitTreeEntry { pub mode: String, #[serde(rename = "type")] pub object_type: String, - pub sha: String, + /// `sha` and `contents` are mutually exclusive. + /// + /// Set `sha` to `Some(None)` to delete a file. + #[serde(skip_serializing_if="Option::is_none")] + pub sha: Option>, + #[serde(skip_serializing_if="Option::is_none")] + pub content: Option, } pub struct RecentCommit { @@ -2007,14 +2165,11 @@ impl IssuesQuery for LeastRecentlyReviewedPullRequests { }; loop { let query = queries::LeastRecentlyReviewedPullRequests::build(args.clone()); - let req = client.post(Repository::GITHUB_GRAPHQL_API_URL); + let req = client.post(&format!("{}/graphql", client.api_url)); let req = req.json(&query); - let (resp, req_dbg) = client._send_req(req).await?; - let data = resp - .json::>() - .await - .context(req_dbg)?; + let data: cynic::GraphQlResponse = + client.json(req).await?; if let Some(errors) = data.errors { anyhow::bail!("There were graphql errors. {:?}", errors); } diff --git a/src/handlers.rs b/src/handlers.rs index da39943b..5578b63b 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -279,7 +279,7 @@ command_handlers! { pub struct Context { pub github: GithubClient, - pub db: crate::db::ClientPool, + pub db: crate::db::Pool, pub username: String, pub octocrab: Octocrab, } diff --git a/src/handlers/docs_update.rs b/src/handlers/docs_update.rs index 1c2d0eb2..e95848b4 100644 --- a/src/handlers/docs_update.rs +++ b/src/handlers/docs_update.rs @@ -5,7 +5,6 @@ use crate::github::{self, GitTreeEntry, GithubClient, Repository}; use anyhow::Context; use anyhow::Result; use cron::Schedule; -use reqwest::Client; use std::fmt::Write; use std::str::FromStr; @@ -60,7 +59,7 @@ pub async fn handle_job() -> Result<()> { } async fn docs_update() -> Result<()> { - let gh = GithubClient::new_with_default_token(Client::new()); + let gh = GithubClient::new_from_env(); let work_repo = gh.repository(WORK_REPO).await?; work_repo .merge_upstream(&gh, &work_repo.default_branch) @@ -169,7 +168,8 @@ async fn create_commit( path: update.path.clone(), mode: "160000".to_string(), object_type: "commit".to_string(), - sha: update.new_hash.clone(), + sha: Some(Some(update.new_hash.clone())), + content: None, }) .collect(); let new_tree = rust_repo diff --git a/src/handlers/github_releases.rs b/src/handlers/github_releases.rs index 745d74fd..0df9b872 100644 --- a/src/handlers/github_releases.rs +++ b/src/handlers/github_releases.rs @@ -132,7 +132,7 @@ async fn load_changelog( .await? .ok_or_else(|| anyhow::Error::msg("missing file"))?; - Ok(String::from_utf8(resp)?) + Ok(String::from_utf8(resp.to_vec())?) } async fn load_paginated(ctx: &Context, url: &str, key: F) -> anyhow::Result> diff --git a/src/handlers/mentions.rs b/src/handlers/mentions.rs index 1c888bea..0e77b0f4 100644 --- a/src/handlers/mentions.rs +++ b/src/handlers/mentions.rs @@ -90,9 +90,11 @@ pub(super) async fn handle_input( event: &IssuesEvent, input: MentionsInput, ) -> anyhow::Result<()> { - let mut client = ctx.db.get().await; + let mut connection = ctx.db.connection().await; + let repo = event.issue.repository().to_string(); + let issue_number = event.issue.number as i32; let mut state: IssueData<'_, MentionState> = - IssueData::load(&mut client, &event.issue, MENTIONS_KEY).await?; + IssueData::load(&mut *connection, repo, issue_number, MENTIONS_KEY).await?; // Build the message to post to the issue. let mut result = String::new(); for to_mention in &input.paths { diff --git a/src/handlers/no_merges.rs b/src/handlers/no_merges.rs index b9ed89ff..14f2b41e 100644 --- a/src/handlers/no_merges.rs +++ b/src/handlers/no_merges.rs @@ -77,9 +77,11 @@ pub(super) async fn handle_input( event: &IssuesEvent, input: NoMergesInput, ) -> anyhow::Result<()> { - let mut client = ctx.db.get().await; - let mut state: IssueData<'_, NoMergesState> = - IssueData::load(&mut client, &event.issue, NO_MERGES_KEY).await?; + let mut connection = ctx.db.connection().await; + let repo = event.issue.repository().to_string(); + let issue_number = event.issue.number as i32; + let mut state: IssueData = + IssueData::load(&mut *connection, repo, issue_number, NO_MERGES_KEY).await?; let since_last_posted = if state.data.mentioned_merge_commits.is_empty() { "" diff --git a/src/handlers/notification.rs b/src/handlers/notification.rs index 718b2b24..87fbd080 100644 --- a/src/handlers/notification.rs +++ b/src/handlers/notification.rs @@ -4,8 +4,8 @@ //! //! Parsing is done in the `parser::command::ping` module. -use crate::db::notifications; use crate::{ + db::notifications::Notification, github::{self, Event}, handlers::Context, }; @@ -93,33 +93,32 @@ pub async fn handle(ctx: &Context, event: &Event) -> anyhow::Result<()> { } }; - let client = ctx.db.get().await; + let mut connection = ctx.db.connection().await; for user in users { if !users_notified.insert(user.id.unwrap()) { // Skip users already associated with this event. continue; } - if let Err(err) = notifications::record_username(&client, user.id.unwrap(), user.login) + if let Err(err) = connection + .record_username(user.id.unwrap(), user.login) .await .context("failed to record username") { log::error!("record username: {:?}", err); } - if let Err(err) = notifications::record_ping( - &client, - ¬ifications::Notification { + if let Err(err) = connection + .record_ping(&Notification { user_id: user.id.unwrap(), origin_url: event.html_url().unwrap().to_owned(), origin_html: body.to_owned(), time: event.time().unwrap(), short_description: Some(short_description.clone()), team_name: team_name.clone(), - }, - ) - .await - .context("failed to record ping") + }) + .await + .context("failed to record ping") { log::error!("record ping: {:?}", err); } diff --git a/src/handlers/rustc_commits.rs b/src/handlers/rustc_commits.rs index 4724bb2b..91c59386 100644 --- a/src/handlers/rustc_commits.rs +++ b/src/handlers/rustc_commits.rs @@ -1,6 +1,5 @@ use crate::db::jobs::JobSchedule; -use crate::db::rustc_commits; -use crate::db::rustc_commits::get_missing_commits; +use crate::db::Commit; use crate::{ github::{self, Event}, handlers::Context, @@ -87,7 +86,7 @@ async fn synchronize_commits(ctx: &Context, sha: &str, pr: u32) { } pub async fn synchronize_commits_inner(ctx: &Context, starter: Option<(String, u32)>) { - let db = ctx.db.get().await; + let mut connection = ctx.db.connection().await; // List of roots to be resolved. Each root and its parents will be recursively resolved // until an existing commit is found. @@ -96,14 +95,15 @@ pub async fn synchronize_commits_inner(ctx: &Context, starter: Option<(String, u to_be_resolved.push_back((sha.to_string(), Some(pr))); } to_be_resolved.extend( - get_missing_commits(&db) + connection + .get_missing_commits() .await + .unwrap() .into_iter() .map(|c| (c, None::)), ); log::info!("synchronize_commits for {:?}", to_be_resolved); - let db = ctx.db.get().await; while let Some((sha, mut pr)) = to_be_resolved.pop_front() { let mut gc = match ctx.github.rust_commit(&sha).await { Some(c) => c, @@ -132,19 +132,17 @@ pub async fn synchronize_commits_inner(ctx: &Context, starter: Option<(String, u } }; - let res = rustc_commits::record_commit( - &db, - rustc_commits::Commit { + let res = connection + .record_commit(&Commit { sha: gc.sha, parent_sha: parent_sha.clone(), time: gc.commit.author.date, pr: Some(pr), - }, - ) - .await; + }) + .await; match res { Ok(()) => { - if !rustc_commits::has_commit(&db, &parent_sha).await { + if !connection.has_commit(&parent_sha).await.unwrap() { to_be_resolved.push_back((parent_sha, None)) } } diff --git a/src/lib.rs b/src/lib.rs index aafa5eea..40e5da1c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,6 +26,7 @@ pub mod payload; pub mod rfcbot; pub mod team; mod team_data; +pub mod test_record; pub mod triage; pub mod zulip; diff --git a/src/main.rs b/src/main.rs index d119e3c9..8c026bc8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,6 @@ use anyhow::Context as _; use futures::future::FutureExt; use futures::StreamExt; use hyper::{header, Body, Request, Response, Server, StatusCode}; -use reqwest::Client; use route_recognizer::Router; use std::{env, net::SocketAddr, sync::Arc}; use tokio::{task, time}; @@ -83,7 +82,8 @@ async fn serve_req( .unwrap()); } if req.uri.path() == "/bors-commit-list" { - let res = db::rustc_commits::get_commits_with_artifacts(&*ctx.db.get().await).await; + let mut connection = ctx.db.connection().await; + let res = connection.get_commits_with_artifacts().await; let res = match res { Ok(r) => r, Err(e) => { @@ -103,10 +103,11 @@ async fn serve_req( if let Some(query) = req.uri.query() { let user = url::form_urlencoded::parse(query.as_bytes()).find(|(k, _)| k == "user"); if let Some((_, name)) = user { + let mut connection = ctx.db.connection().await; return Ok(Response::builder() .status(StatusCode::OK) .body(Body::from( - notification_listing::render(&ctx.db.get().await, &*name).await, + notification_listing::render(&mut *connection, &*name).await, )) .unwrap()); } @@ -219,6 +220,7 @@ async fn serve_req( .unwrap()); } }; + triagebot::test_record::record_event(&event, &payload); match triagebot::webhook(event, payload, &ctx).await { Ok(true) => Ok(Response::new(Body::from("processed request"))), @@ -234,41 +236,9 @@ async fn serve_req( } async fn run_server(addr: SocketAddr) -> anyhow::Result<()> { - let pool = db::ClientPool::new(); - db::run_migrations(&*pool.get().await) - .await - .context("database migrations")?; + let pool = db::Pool::new_from_env(); - // spawning a background task that will schedule the jobs - // every JOB_SCHEDULING_CADENCE_IN_SECS - task::spawn(async move { - loop { - let res = task::spawn(async move { - let pool = db::ClientPool::new(); - let mut interval = - time::interval(time::Duration::from_secs(JOB_SCHEDULING_CADENCE_IN_SECS)); - - loop { - interval.tick().await; - db::schedule_jobs(&*pool.get().await, jobs()) - .await - .context("database schedule jobs") - .unwrap(); - } - }); - - match res.await { - Err(err) if err.is_panic() => { - /* handle panic in above task, re-launching */ - tracing::trace!("schedule_jobs task died (error={})", err); - } - _ => unreachable!(), - } - } - }); - - let client = Client::new(); - let gh = github::GithubClient::new_with_default_token(client.clone()); + let gh = github::GithubClient::new_from_env(); let oc = octocrab::OctocrabBuilder::new() .personal_token(github::default_token_from_env()) .build() @@ -280,35 +250,10 @@ async fn run_server(addr: SocketAddr) -> anyhow::Result<()> { octocrab: oc, }); - // spawning a background task that will run the scheduled jobs - // every JOB_PROCESSING_CADENCE_IN_SECS - let ctx2 = ctx.clone(); - task::spawn(async move { - loop { - let ctx = ctx2.clone(); - let res = task::spawn(async move { - let pool = db::ClientPool::new(); - let mut interval = - time::interval(time::Duration::from_secs(JOB_PROCESSING_CADENCE_IN_SECS)); - - loop { - interval.tick().await; - db::run_scheduled_jobs(&ctx, &*pool.get().await) - .await - .context("run database scheduled jobs") - .unwrap(); - } - }); - - match res.await { - Err(err) if err.is_panic() => { - /* handle panic in above task, re-launching */ - tracing::trace!("run_scheduled_jobs task died (error={})", err); - } - _ => unreachable!(), - } - } - }); + if !is_scheduled_jobs_disabled() { + spawn_job_scheduler(); + spawn_job_runner(ctx.clone()); + } let agenda = tower::ServiceBuilder::new() .buffer(10) @@ -351,6 +296,89 @@ async fn run_server(addr: SocketAddr) -> anyhow::Result<()> { Ok(()) } +/// Spawns a background tokio task which runs continuously to queue up jobs +/// to be run by the job runner. +/// +/// The scheduler wakes up every `JOB_SCHEDULING_CADENCE_IN_SECS` seconds to +/// check if there are any jobs ready to run. Jobs get inserted into the the +/// database which acts as a queue. +fn spawn_job_scheduler() { + task::spawn(async move { + loop { + let res = task::spawn(async move { + let pool = db::Pool::new_from_env(); + let mut interval = + time::interval(time::Duration::from_secs(JOB_SCHEDULING_CADENCE_IN_SECS)); + + loop { + interval.tick().await; + let mut connection = pool.connection().await; + db::jobs::schedule_jobs(&mut *connection, jobs()) + .await + .context("database schedule jobs") + .unwrap(); + } + }); + + match res.await { + Err(err) if err.is_panic() => { + /* handle panic in above task, re-launching */ + tracing::error!("schedule_jobs task died (error={})", err); + tokio::time::sleep(std::time::Duration::new(5, 0)).await; + } + _ => unreachable!(), + } + } + }); +} + +/// Spawns a background tokio task which runs continuously to run scheduled +/// jobs. +/// +/// The runner wakes up every `JOB_PROCESSING_CADENCE_IN_SECS` seconds to +/// check if any jobs have been put into the queue by the scheduler. They +/// will get popped off the queue and run if any are found. +fn spawn_job_runner(ctx: Arc) { + task::spawn(async move { + loop { + let ctx = ctx.clone(); + let res = task::spawn(async move { + let pool = db::Pool::new_from_env(); + let mut interval = + time::interval(time::Duration::from_secs(JOB_PROCESSING_CADENCE_IN_SECS)); + + loop { + interval.tick().await; + let mut connection = pool.connection().await; + db::jobs::run_scheduled_jobs(&ctx, &mut *connection) + .await + .context("run database scheduled jobs") + .unwrap(); + } + }); + + match res.await { + Err(err) if err.is_panic() => { + /* handle panic in above task, re-launching */ + tracing::error!("run_scheduled_jobs task died (error={})", err); + tokio::time::sleep(std::time::Duration::new(5, 0)).await; + } + _ => unreachable!(), + } + } + }); +} + +/// Determines whether or not background scheduled jobs should be disabled for +/// the purpose of testing. +/// +/// This helps avoid having random jobs run while testing other things. +fn is_scheduled_jobs_disabled() -> bool { + // TRIAGEBOT_TEST_DISABLE_JOBS is set automatically by the test runner, + // and shouldn't be needed to be set manually. + env::var_os("TRIAGEBOT_TEST_DISABLE_JOBS").is_some() || triagebot::test_record::is_recording() +} + #[tokio::main(flavor = "current_thread")] async fn main() { dotenv::dotenv().ok(); @@ -359,6 +387,7 @@ async fn main() { .with_ansi(std::env::var_os("DISABLE_COLOR").is_none()) .try_init() .unwrap(); + triagebot::test_record::init().unwrap(); let port = env::var("PORT") .ok() diff --git a/src/notification_listing.rs b/src/notification_listing.rs index 033fc9b3..d827a8b2 100644 --- a/src/notification_listing.rs +++ b/src/notification_listing.rs @@ -1,7 +1,5 @@ -use crate::db::notifications::get_notifications; - -pub async fn render(db: &crate::db::PooledClient, user: &str) -> String { - let notifications = match get_notifications(db, user).await { +pub async fn render(connection: &mut dyn crate::db::Connection, user: &str) -> String { + let notifications = match connection.get_notifications(user).await { Ok(n) => n, Err(e) => { return format!("{:?}", e.context("getting notifications")); diff --git a/src/payload.rs b/src/payload.rs index f05e13a1..bd2f73f3 100644 --- a/src/payload.rs +++ b/src/payload.rs @@ -12,6 +12,13 @@ impl fmt::Display for SignedPayloadError { impl std::error::Error for SignedPayloadError {} +pub fn sign(secret: &str, payload: &[u8]) -> Vec { + let key = PKey::hmac(secret.as_bytes()).unwrap(); + let mut signer = Signer::new(MessageDigest::sha1(), &key).unwrap(); + signer.update(&payload).unwrap(); + signer.sign_to_vec().unwrap() +} + pub fn assert_signed(signature: &str, payload: &[u8]) -> Result<(), SignedPayloadError> { let signature = signature.get("sha1=".len()..).ok_or(SignedPayloadError)?; let signature = match hex::decode(&signature) { @@ -22,15 +29,8 @@ pub fn assert_signed(signature: &str, payload: &[u8]) -> Result<(), SignedPayloa } }; - let key = PKey::hmac( - std::env::var("GITHUB_WEBHOOK_SECRET") - .expect("Missing GITHUB_WEBHOOK_SECRET") - .as_bytes(), - ) - .unwrap(); - let mut signer = Signer::new(MessageDigest::sha1(), &key).unwrap(); - signer.update(&payload).unwrap(); - let hmac = signer.sign_to_vec().unwrap(); + let secret = std::env::var("GITHUB_WEBHOOK_SECRET").expect("Missing GITHUB_WEBHOOK_SECRET"); + let hmac = sign(&secret, payload); if !memcmp::eq(&hmac, &signature) { return Err(SignedPayloadError); diff --git a/src/team_data.rs b/src/team_data.rs index 4f7e1b15..d58ff408 100644 --- a/src/team_data.rs +++ b/src/team_data.rs @@ -4,7 +4,8 @@ use rust_team_data::v1::{Teams, ZulipMapping, BASE_URL}; use serde::de::DeserializeOwned; async fn by_url(client: &GithubClient, path: &str) -> anyhow::Result { - let url = format!("{}{}", BASE_URL, path); + let base = std::env::var("TEAMS_API_URL").unwrap_or(BASE_URL.to_string()); + let url = format!("{}{}", base, path); for _ in 0i32..3 { let map: Result = client.json(client.raw().get(&url)).await; match map { diff --git a/src/test_record.rs b/src/test_record.rs new file mode 100644 index 00000000..08d79a14 --- /dev/null +++ b/src/test_record.rs @@ -0,0 +1,237 @@ +//! Support for recording network activity for test playback. +//! +//! See `testsuite.rs` for more information on test recording. + +use crate::EventName; +use anyhow::Context; +use anyhow::Result; +use reqwest::{Request, StatusCode}; +use serde::{Deserialize, Serialize}; +use std::fs::{self, File}; +use std::io::BufWriter; +use std::path::Path; +use std::path::PathBuf; +use std::sync::atomic::{AtomicU32, Ordering}; +use tracing::{error, info, warn}; + +/// A representation of the recording of activity of triagebot. +/// +/// Activities are stored as JSON on disk. The test framework injects the +/// `Webhook` and then checks for the appropriate requests and sends the +/// recorded responses. +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "kind")] +pub enum Activity { + /// A webhook event received from GitHub. + Webhook { + webhook_event: String, + payload: serde_json::Value, + }, + /// An outgoing request to api.github.com or raw.githubusercontent.com, and its response. + Request { + method: String, + path: String, + query: Option, + request_body: String, + response_code: u16, + /// The body of the response. + /// + /// For non-JSON requests, it is encoded as a `Value::String` under + /// the assumption that GitHub never returns a JSON string for a + /// response. This is done so that the JSON bodies can be formatted + /// nicely in the `.json` bodies to make inspecting them easier. + response_body: serde_json::Value, + }, + /// Sent by the mock HTTP server to the test framework when it detects + /// something is wrong. + Error { message: String }, + /// Sent by the mock HTTP server to the test framework to tell it that all + /// activities have been processed. + Finished, +} + +/// Information about an HTTP request that is captured before sending. +/// +/// This is needed to avoid messing with cloning the Request. +#[derive(Debug)] +pub struct RequestInfo { + method: String, + path: String, + query: Option, + body: String, +} + +/// Returns whether or not TRIAGEBOT_TEST_RECORD_DIR has been set to enable +/// recording. +pub fn is_recording() -> bool { + record_dir().is_some() +} + +/// The directory where the JSON recordings should be stored. +/// +/// Returns `None` if recording is disabled. +fn record_dir() -> Option { + let test_record = std::env::var("TRIAGEBOT_TEST_RECORD_DIR").ok()?; + let mut record_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + record_dir.push("tests"); + record_dir.push(test_record); + Some(record_dir) +} + +pub fn record_live_repo() -> Option { + std::env::var("TRIAGEBOT_TEST_LIVE_REPO").ok() +} + +fn next_sequence() -> u32 { + static NEXT_ID: AtomicU32 = AtomicU32::new(0); + NEXT_ID.fetch_add(1, Ordering::SeqCst) +} + +/// Initializes the test recording system. +/// +/// This sets up the directory where JSON files are stored if the +/// `TRIAGEBOT_TEST_RECORD_DIR` environment variable is set. +pub fn init() -> Result<()> { + let Some(record_dir) = record_dir() else { return Ok(()) }; + fs::create_dir_all(&record_dir) + .with_context(|| format!("failed to create recording directory {record_dir:?}"))?; + // Clear any old recording data. + for entry in fs::read_dir(&record_dir)? { + let entry = entry?; + let path = entry.path(); + if path.extension().and_then(|p| p.to_str()) == Some("json") { + warn!("deleting old recording at {path:?}"); + fs::remove_file(&path) + .with_context(|| format!("failed to remove old recording {path:?}"))?; + } + } + Ok(()) +} + +/// Records a webhook event for the test framework. +/// +/// The recording is only saved if the `TRIAGEBOT_TEST_RECORD_DIR` environment +/// variable is set. +pub fn record_event(event: &EventName, payload: &str) { + let Some(record_dir) = record_dir() else { return }; + + let payload_json: serde_json::Value = serde_json::from_str(payload).expect("valid json"); + let name = match event { + EventName::PullRequest => { + let action = payload_json["action"].as_str().unwrap(); + let number = payload_json["number"].as_u64().unwrap(); + format!("pr{number}_{action}") + } + EventName::PullRequestReview => { + let action = payload_json["action"].as_str().unwrap(); + let number = payload_json["pull_request"]["number"].as_u64().unwrap(); + format!("pr{number}_review_{action}") + } + EventName::PullRequestReviewComment => { + let action = payload_json["action"].as_str().unwrap(); + let number = payload_json["pull_request"]["number"].as_u64().unwrap(); + format!("pr{number}_review_comment_{action}") + } + EventName::IssueComment => { + let action = payload_json["action"].as_str().unwrap(); + let number = payload_json["issue"]["number"].as_u64().unwrap(); + format!("issue{number}_comment_{action}") + } + EventName::Issue => { + let action = payload_json["action"].as_str().unwrap(); + let number = payload_json["issue"]["number"].as_u64().unwrap(); + format!("issue{number}_{action}") + } + EventName::Push => { + let after = payload_json["after"].as_str().unwrap(); + format!("push_{after}") + } + EventName::Create => { + let ref_type = payload_json["ref_type"].as_str().unwrap(); + let git_ref = payload_json["ref"].as_str().unwrap(); + format!("create_{ref_type}_{git_ref}") + } + EventName::Other => { + return; + } + }; + let activity = Activity::Webhook { + webhook_event: event.to_string(), + payload: payload_json, + }; + let filename = format!("{:02}-webhook-{name}.json", next_sequence()); + save_activity(&record_dir.join(filename), &activity); +} + +/// Captures information about a Request to be used for a test recording. +/// +/// This value is passed to `record_request` after the request has been sent. +pub fn capture_request(req: &Request) -> Option { + if !is_recording() { + return None; + } + let url = req.url(); + let body = req + .body() + .and_then(|body| body.as_bytes()) + .map(|bytes| String::from_utf8(bytes.to_vec()).unwrap()) + .unwrap_or_default(); + let info = RequestInfo { + method: req.method().to_string(), + path: url.path().to_string(), + query: url.query().map(|q| q.to_string()), + body, + }; + Some(info) +} + +/// Records an HTTP request and response for the test framework. +/// +/// The recording is only saved if the `TRIAGEBOT_TEST_RECORD_DIR` environment +/// variable is set. +pub fn record_request(info: Option, status: StatusCode, body: &[u8]) { + let Some(info) = info else { return }; + let Some(record_dir) = record_dir() else { return }; + let response_code = status.as_u16(); + let mut munged_path = info.path.replace(['/', '.'], "_"); + if munged_path.starts_with('_') { + munged_path.remove(0); + } + let name = format!("{}-{}", info.method, munged_path); + // This is a hack to reduce the amount of data stored in the test + // directory. This file gets requested many times, and it is very + // large. + let response_body = if info.path == "/v1/teams.json" { + serde_json::json!(null) + } else { + match serde_json::from_slice(body) { + Ok(json) => json, + Err(_) => serde_json::Value::String(String::from_utf8_lossy(body).to_string()), + } + }; + let activity = Activity::Request { + method: info.method, + path: info.path, + query: info.query, + request_body: info.body, + response_code, + response_body, + }; + + let filename = format!("{:02}-{name}.json", next_sequence()); + save_activity(&record_dir.join(filename), &activity); +} + +/// Helper for saving an [`Activity`] to disk as JSON. +fn save_activity(path: &Path, activity: &Activity) { + let save_activity_inner = || -> Result<()> { + let file = File::create(path)?; + let file = BufWriter::new(file); + serde_json::to_writer_pretty(file, &activity)?; + Ok(()) + }; + if let Err(e) = save_activity_inner() { + error!("failed to save test activity {path:?}: {e:?}"); + }; + info!("test activity saved to {path:?}"); +} diff --git a/src/zulip.rs b/src/zulip.rs index 5f943982..c2ef621b 100644 --- a/src/zulip.rs +++ b/src/zulip.rs @@ -1,5 +1,4 @@ -use crate::db::notifications::add_metadata; -use crate::db::notifications::{self, delete_ping, move_indices, record_ping, Identifier}; +use crate::db::notifications::{Identifier, Notification}; use crate::github::{self, GithubClient}; use crate::handlers::Context; use anyhow::Context as _; @@ -548,8 +547,8 @@ async fn acknowledge( } else { Identifier::Url(filter) }; - let mut db = ctx.db.get().await; - match delete_ping(&mut *db, gh_id, ident).await { + let mut connection = ctx.db.connection().await; + match connection.delete_ping(gh_id, ident).await { Ok(deleted) => { let resp = if deleted.is_empty() { format!( @@ -603,18 +602,17 @@ async fn add_notification( assert_eq!(description.pop(), Some(' ')); // pop trailing space Some(description) }; - match record_ping( - &*ctx.db.get().await, - ¬ifications::Notification { + let mut connection = ctx.db.connection().await; + match connection + .record_ping(&Notification { user_id: gh_id, origin_url: url.to_owned(), origin_html: String::new(), short_description: description, time: chrono::Utc::now().into(), team_name: None, - }, - ) - .await + }) + .await { Ok(()) => Ok(serde_json::to_string(&Response { content: "Created!", @@ -652,8 +650,11 @@ async fn add_meta_notification( assert_eq!(description.pop(), Some(' ')); // pop trailing space Some(description) }; - let mut db = ctx.db.get().await; - match add_metadata(&mut db, gh_id, idx, description.as_deref()).await { + let mut connection = ctx.db.connection().await; + match connection + .add_metadata(gh_id, idx, description.as_deref()) + .await + { Ok(()) => Ok(serde_json::to_string(&Response { content: "Added metadata!", }) @@ -688,7 +689,8 @@ async fn move_notification( .context("to index")? .checked_sub(1) .ok_or_else(|| anyhow::anyhow!("1-based indexes"))?; - match move_indices(&mut *ctx.db.get().await, gh_id, from, to).await { + let mut connection = ctx.db.connection().await; + match connection.move_indices(gh_id, from, to).await { Ok(()) => Ok(serde_json::to_string(&Response { // to 1-base indices content: &format!("Moved {} to {}.", from + 1, to + 1), diff --git a/tests/db/issue_data.rs b/tests/db/issue_data.rs new file mode 100644 index 00000000..26e47099 --- /dev/null +++ b/tests/db/issue_data.rs @@ -0,0 +1,30 @@ +use super::run_test; +use serde::{Deserialize, Serialize}; +use triagebot::db::issue_data::IssueData; + +#[derive(Serialize, Deserialize, Default, Debug)] +struct MyData { + f1: String, + f2: u32, +} + +#[test] +fn issue_data() { + run_test(|mut connection| async move { + let repo = "rust-lang/rust".to_string(); + let mut id: IssueData = + IssueData::load(&mut *connection, repo.clone(), 1234, "test") + .await + .unwrap(); + assert_eq!(id.data.f1, ""); + assert_eq!(id.data.f2, 0); + id.data.f1 = "new data".to_string(); + id.data.f2 = 1; + id.save().await.unwrap(); + let id: IssueData = IssueData::load(&mut *connection, repo.clone(), 1234, "test") + .await + .unwrap(); + assert_eq!(id.data.f1, "new data"); + assert_eq!(id.data.f2, 1); + }); +} diff --git a/tests/db/jobs.rs b/tests/db/jobs.rs new file mode 100644 index 00000000..a2941063 --- /dev/null +++ b/tests/db/jobs.rs @@ -0,0 +1,113 @@ +use super::run_test; +use crate::assert_datetime_approx_equal; +use serde_json::json; + +#[test] +fn jobs() { + run_test(|mut connection| async move { + // Create some jobs and check that ones scheduled in the past are returned. + let past = chrono::Utc::now() - chrono::Duration::minutes(5); + let future = chrono::Utc::now() + chrono::Duration::hours(1); + connection + .insert_job("sample_job1", &past, &json! {{"foo": 123}}) + .await + .unwrap(); + connection + .insert_job("sample_job2", &past, &json! {{}}) + .await + .unwrap(); + connection + .insert_job("sample_job1", &future, &json! {{}}) + .await + .unwrap(); + let jobs = connection.get_jobs_to_execute().await.unwrap(); + assert_eq!(jobs.len(), 2); + assert_eq!(jobs[0].name, "sample_job1"); + assert_datetime_approx_equal(&jobs[0].scheduled_at, &past); + assert_eq!(jobs[0].metadata, json! {{"foo": 123}}); + assert_eq!(jobs[0].executed_at, None); + assert_eq!(jobs[0].error_message, None); + + assert_eq!(jobs[1].name, "sample_job2"); + assert_datetime_approx_equal(&jobs[1].scheduled_at, &past); + assert_eq!(jobs[1].metadata, json! {{}}); + assert_eq!(jobs[1].executed_at, None); + assert_eq!(jobs[1].error_message, None); + + // Get job by name + let job = connection + .get_job_by_name_and_scheduled_at("sample_job1", &future) + .await + .unwrap(); + assert_eq!(job.metadata, json! {{}}); + assert_eq!(job.error_message, None); + + // Update error message + connection + .update_job_error_message(&job.id, "an error") + .await + .unwrap(); + let job = connection + .get_job_by_name_and_scheduled_at("sample_job1", &future) + .await + .unwrap(); + assert_eq!(job.error_message.as_deref(), Some("an error")); + + // Delete job + let job = connection + .get_job_by_name_and_scheduled_at("sample_job1", &past) + .await + .unwrap(); + connection.delete_job(&job.id).await.unwrap(); + let jobs = connection.get_jobs_to_execute().await.unwrap(); + assert_eq!(jobs.len(), 1); + assert_eq!(jobs[0].name, "sample_job2"); + }); +} + +#[test] +fn on_conflict() { + // Verify that inserting a job with different data updates the data. + run_test(|mut connection| async move { + let past = chrono::Utc::now() - chrono::Duration::minutes(5); + connection + .insert_job("sample_job1", &past, &json! {{"foo": 123}}) + .await + .unwrap(); + connection + .insert_job("sample_job1", &past, &json! {{"foo": 456}}) + .await + .unwrap(); + let job = connection + .get_job_by_name_and_scheduled_at("sample_job1", &past) + .await + .unwrap(); + assert_eq!(job.metadata, json! {{"foo": 456}}); + }); +} + +#[test] +fn update_job_executed_at() { + run_test(|mut connection| async move { + let now = chrono::Utc::now(); + let past = now - chrono::Duration::minutes(5); + connection + .insert_job("sample_job1", &past, &json! {{"foo": 123}}) + .await + .unwrap(); + let jobs = connection.get_jobs_to_execute().await.unwrap(); + assert_eq!(jobs.len(), 1); + assert_eq!(jobs[0].executed_at, None); + connection + .update_job_executed_at(&jobs[0].id) + .await + .unwrap(); + let jobs = connection.get_jobs_to_execute().await.unwrap(); + assert_eq!(jobs.len(), 1); + let executed_at = jobs[0].executed_at.expect("executed_at should be set"); + // The timestamp should be approximately "now". + if executed_at - now > chrono::Duration::minutes(1) { + panic!("executed_at timestamp unexpected {executed_at:?} vs {now:?}"); + } + }); +} diff --git a/tests/db/mod.rs b/tests/db/mod.rs new file mode 100644 index 00000000..ef2dffd0 --- /dev/null +++ b/tests/db/mod.rs @@ -0,0 +1,208 @@ +//! Tests for the database API. +//! +//! These tests help verify the database interaction. The [`run_test`] +//! function helps set up the database and gives your callback a connection to +//! interact with. The general form of a test is: +//! +//! ```rust +//! #[test] +//! fn example() { +//! run_test(|mut connection| async move { +//! // Call methods on `connection` and verify its behavior. +//! }); +//! } +//! ``` +//! +//! The `run_test` function will run your test on both SQLite and Postgres (if +//! it is installed). + +use futures::Future; +use std::path::{Path, PathBuf}; +use std::process::Command; +use triagebot::db::{Connection, Pool}; + +mod issue_data; +mod jobs; +mod notification; +mod rustc_commits; + +struct PgContext { + db_dir: PathBuf, + pool: Pool, +} + +impl PgContext { + fn new(db_dir: PathBuf) -> PgContext { + let database_url = postgres_database_url(&db_dir); + let pool = Pool::open(&database_url); + PgContext { db_dir, pool } + } +} + +impl Drop for PgContext { + fn drop(&mut self) { + stop_postgres(&self.db_dir); + } +} + +struct SqliteContext { + pool: Pool, +} + +impl SqliteContext { + fn new() -> SqliteContext { + let db_path = super::test_dir().join("triagebot.sqlite3"); + let pool = Pool::open(db_path.to_str().unwrap()); + SqliteContext { pool } + } +} + +fn run_test(f: F) +where + F: Fn(Box) -> Fut + Send + Sync + 'static, + Fut: Future + Send, +{ + // Only run postgres if postgres can be found or on CI. + if let Some(db_dir) = setup_postgres() { + eprintln!("testing Postgres"); + let ctx = PgContext::new(db_dir); + tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap() + .block_on(async { f(ctx.pool.connection().await).await }); + } else if std::env::var_os("CI").is_some() { + panic!("postgres must be installed in CI"); + } + + eprintln!("\n\ntesting Sqlite"); + let ctx = SqliteContext::new(); + tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap() + .block_on(async { f(ctx.pool.connection().await).await }); +} + +pub fn postgres_database_url(db_dir: &PathBuf) -> String { + format!( + "postgres:///triagebot?user=triagebot&host={}", + db_dir.display() + ) +} + +pub fn setup_postgres() -> Option { + let pg_dir = find_postgres()?; + // Set up a directory where this test can store all its stuff. + let test_dir = super::test_dir(); + let db_dir = test_dir.join("db"); + + std::fs::create_dir(&db_dir).unwrap(); + let db_dir_str = db_dir.to_str().unwrap(); + run_command( + &pg_dir.join("initdb"), + &["--auth=trust", "--username=triagebot", "-D", db_dir_str], + &db_dir, + ); + run_command( + &pg_dir.join("pg_ctl"), + &[ + // -h '' tells it to not listen on TCP + // -k tells it where to place the unix-domain socket + "-o", + &format!("-h '' -k {db_dir_str}"), + // -D is the data dir where everything is stored + "-D", + db_dir_str, + // -l enables logging to a file instead of stdout + "-l", + db_dir.join("postgres.log").to_str().unwrap(), + "start", + ], + &db_dir, + ); + run_command( + &pg_dir.join("createdb"), + &["--user", "triagebot", "-h", db_dir_str, "triagebot"], + &db_dir, + ); + Some(db_dir) +} + +pub fn stop_postgres(db_dir: &Path) { + // Shut down postgres. + let pg_dir = find_postgres().unwrap(); + match Command::new(pg_dir.join("pg_ctl")) + .args(&["-D", db_dir.to_str().unwrap(), "stop"]) + .output() + { + Ok(output) => { + if !output.status.success() { + eprintln!( + "failed to stop postgres:\n\ + ---stdout\n\ + {}\n\ + ---stderr\n\ + {}\n\ + ", + std::str::from_utf8(&output.stdout).unwrap(), + std::str::from_utf8(&output.stderr).unwrap() + ); + } + } + Err(e) => eprintln!("could not run pg_ctl to stop: {e}"), + } +} + +/// Finds the root for PostgreSQL commands. +/// +/// For various reasons, some Linux distros hide some postgres commands and +/// don't put them on PATH, making them difficult to access. +fn find_postgres() -> Option { + // Check if on PATH first. + if let Ok(o) = Command::new("initdb").arg("-V").output() { + if o.status.success() { + return Some(PathBuf::new()); + } + } + if let Ok(dirs) = std::fs::read_dir("/usr/lib/postgresql") { + let mut versions: Vec<_> = dirs + .filter_map(|entry| { + let entry = entry.unwrap(); + // Versions are generally of the form 9.3 or 14, but this + // might be broken if other forms are used. + if let Ok(n) = entry.file_name().to_str().unwrap().parse::() { + Some((n, entry.path())) + } else { + None + } + }) + .collect(); + if !versions.is_empty() { + versions.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap()); + return Some(versions.last().unwrap().1.join("bin")); + } + } + None +} + +fn run_command(command: &Path, args: &[&str], cwd: &Path) { + eprintln!("running {command:?}: {args:?}"); + let output = Command::new(command) + .args(args) + .current_dir(cwd) + .output() + .unwrap_or_else(|e| panic!("`{command:?}` failed to run: {e}")); + if !output.status.success() { + panic!( + "{command:?} failed:\n\ + ---stdout\n\ + {}\n\ + ---stderr\n\ + {}\n\ + ", + std::str::from_utf8(&output.stdout).unwrap(), + std::str::from_utf8(&output.stderr).unwrap() + ); + } +} diff --git a/tests/db/notification.rs b/tests/db/notification.rs new file mode 100644 index 00000000..8edd986b --- /dev/null +++ b/tests/db/notification.rs @@ -0,0 +1,261 @@ +use super::run_test; +use crate::assert_datetime_approx_equal; +use std::num::NonZeroUsize; +use triagebot::db::notifications::{Identifier, Notification}; + +#[test] +fn notification() { + run_test(|mut connection| async move { + let now = chrono::Utc::now(); + connection + .record_username(43198, "ehuss".to_string()) + .await + .unwrap(); + connection + .record_username(14314532, "weihanglo".to_string()) + .await + .unwrap(); + connection + .record_ping(&Notification { + user_id: 43198, + origin_url: "https://github.com/rust-lang/rust/issues/1".to_string(), + origin_html: "This comment mentions @ehuss.".to_string(), + short_description: Some("Comment on some issue".to_string()), + time: now.into(), + team_name: None, + }) + .await + .unwrap(); + + connection + .record_ping(&Notification { + user_id: 43198, + origin_url: "https://github.com/rust-lang/rust/issues/2".to_string(), + origin_html: "This comment mentions @rust-lang/cargo.".to_string(), + short_description: Some("Comment on some issue".to_string()), + time: now.into(), + team_name: Some("cargo".to_string()), + }) + .await + .unwrap(); + connection + .record_ping(&Notification { + user_id: 14314532, + origin_url: "https://github.com/rust-lang/rust/issues/2".to_string(), + origin_html: "This comment mentions @rust-lang/cargo.".to_string(), + short_description: Some("Comment on some issue".to_string()), + time: now.into(), + team_name: Some("cargo".to_string()), + }) + .await + .unwrap(); + + let notifications = connection.get_notifications("ehuss").await.unwrap(); + assert_eq!(notifications.len(), 2); + assert_eq!( + notifications[0].origin_url, + "https://github.com/rust-lang/rust/issues/1" + ); + assert_eq!( + notifications[0].origin_text, + "This comment mentions @ehuss." + ); + assert_eq!( + notifications[0].short_description.as_deref(), + Some("Comment on some issue") + ); + assert_datetime_approx_equal(¬ifications[0].time, &now); + assert_eq!(notifications[0].metadata, None); + + assert_eq!( + notifications[1].origin_url, + "https://github.com/rust-lang/rust/issues/2" + ); + assert_eq!( + notifications[1].origin_text, + "This comment mentions @rust-lang/cargo." + ); + assert_eq!( + notifications[1].short_description.as_deref(), + Some("Comment on some issue") + ); + assert_datetime_approx_equal(¬ifications[1].time, &now); + assert_eq!(notifications[1].metadata, None); + + let notifications = connection.get_notifications("weihanglo").await.unwrap(); + assert_eq!(notifications.len(), 1); + assert_eq!( + notifications[0].origin_url, + "https://github.com/rust-lang/rust/issues/2" + ); + assert_eq!( + notifications[0].origin_text, + "This comment mentions @rust-lang/cargo." + ); + assert_eq!( + notifications[0].short_description.as_deref(), + Some("Comment on some issue") + ); + assert_datetime_approx_equal(¬ifications[0].time, &now); + assert_eq!(notifications[0].metadata, None); + + let notifications = connection.get_notifications("octocat").await.unwrap(); + assert_eq!(notifications.len(), 0); + }); +} + +#[test] +fn delete_ping() { + run_test(|mut connection| async move { + connection + .record_username(43198, "ehuss".to_string()) + .await + .unwrap(); + let now = chrono::Utc::now(); + for x in 1..4 { + connection + .record_ping(&Notification { + user_id: 43198, + origin_url: x.to_string(), + origin_html: "@ehuss {n}".to_string(), + short_description: Some("Comment on some issue".to_string()), + time: now.into(), + team_name: None, + }) + .await + .unwrap(); + } + + let notifications = connection.get_notifications("ehuss").await.unwrap(); + assert_eq!(notifications.len(), 3); + assert_eq!(notifications[0].origin_url, "1"); + assert_eq!(notifications[1].origin_url, "2"); + assert_eq!(notifications[2].origin_url, "3"); + + match connection + .delete_ping(43198, Identifier::Index(NonZeroUsize::new(5).unwrap())) + .await + { + Err(e) => assert_eq!(e.to_string(), "No such notification with index 5"), + Ok(deleted) => panic!("did not expect success {deleted:?}"), + } + + let deleted = connection + .delete_ping(43198, Identifier::Index(NonZeroUsize::new(2).unwrap())) + .await + .unwrap(); + assert_eq!(deleted.len(), 1); + assert_eq!(deleted[0].origin_url, "2"); + let notifications = connection.get_notifications("ehuss").await.unwrap(); + assert_eq!(notifications.len(), 2); + assert_eq!(notifications[0].origin_url, "1"); + assert_eq!(notifications[1].origin_url, "3"); + + let deleted = connection + .delete_ping(43198, Identifier::Url("1")) + .await + .unwrap(); + assert_eq!(deleted.len(), 1); + assert_eq!(deleted[0].origin_url, "1"); + let notifications = connection.get_notifications("ehuss").await.unwrap(); + assert_eq!(notifications.len(), 1); + assert_eq!(notifications[0].origin_url, "3"); + + for x in 4..6 { + connection + .record_ping(&Notification { + user_id: 43198, + origin_url: x.to_string(), + origin_html: "@ehuss {n}".to_string(), + short_description: Some("Comment on some issue".to_string()), + time: now.into(), + team_name: None, + }) + .await + .unwrap(); + } + + let notifications = connection.get_notifications("ehuss").await.unwrap(); + assert_eq!(notifications.len(), 3); + assert_eq!(notifications[0].origin_url, "3"); + assert_eq!(notifications[1].origin_url, "4"); + assert_eq!(notifications[2].origin_url, "5"); + + let deleted = connection + .delete_ping(43198, Identifier::Index(NonZeroUsize::new(2).unwrap())) + .await + .unwrap(); + assert_eq!(deleted.len(), 1); + assert_eq!(deleted[0].origin_url, "4"); + + let deleted = connection + .delete_ping(43198, Identifier::All) + .await + .unwrap(); + assert_eq!(deleted.len(), 2); + assert_eq!(deleted[0].origin_url, "3"); + assert_eq!(deleted[1].origin_url, "5"); + + let notifications = connection.get_notifications("ehuss").await.unwrap(); + assert_eq!(notifications.len(), 0); + }); +} + +#[test] +fn meta_notification() { + run_test(|mut connection| async move { + let now = chrono::Utc::now(); + connection + .record_username(43198, "ehuss".to_string()) + .await + .unwrap(); + connection + .record_ping(&Notification { + user_id: 43198, + origin_url: "1".to_string(), + origin_html: "This comment mentions @ehuss.".to_string(), + short_description: Some("Comment on some issue".to_string()), + time: now.into(), + team_name: None, + }) + .await + .unwrap(); + connection + .add_metadata(43198, 0, Some("metadata 1")) + .await + .unwrap(); + let notifications = connection.get_notifications("ehuss").await.unwrap(); + assert_eq!(notifications.len(), 1); + assert_eq!(notifications[0].metadata.as_deref(), Some("metadata 1")); + }); +} + +#[test] +fn move_indices() { + run_test(|mut connection| async move { + let now = chrono::Utc::now(); + connection + .record_username(43198, "ehuss".to_string()) + .await + .unwrap(); + for x in 1..4 { + connection + .record_ping(&Notification { + user_id: 43198, + origin_url: x.to_string(), + origin_html: "@ehuss {n}".to_string(), + short_description: Some("Comment on some issue".to_string()), + time: now.into(), + team_name: None, + }) + .await + .unwrap(); + } + connection.move_indices(43198, 1, 0).await.unwrap(); + let notifications = connection.get_notifications("ehuss").await.unwrap(); + assert_eq!(notifications.len(), 3); + assert_eq!(notifications[0].origin_url, "2"); + assert_eq!(notifications[1].origin_url, "1"); + assert_eq!(notifications[2].origin_url, "3"); + }); +} diff --git a/tests/db/rustc_commits.rs b/tests/db/rustc_commits.rs new file mode 100644 index 00000000..8c36c6fb --- /dev/null +++ b/tests/db/rustc_commits.rs @@ -0,0 +1,87 @@ +use super::run_test; +use crate::assert_datetime_approx_equal; +use triagebot::db::Commit; + +#[test] +fn rustc_commits() { + run_test(|mut connection| async move { + // Using current time since `get_commits_with_artifacts` is relative to the current time. + let now = chrono::offset::Utc::now(); + connection + .record_commit(&Commit { + sha: "eebdfb55fce148676c24555505aebf648123b2de".to_string(), + parent_sha: "73f40197ecabf77ed59028af61739404eb60dd2e".to_string(), + time: now.into(), + pr: Some(108228), + }) + .await + .unwrap(); + + // A little older to ensure sorting is consistent. + let now3 = now - chrono::Duration::hours(3); + connection + .record_commit(&Commit { + sha: "73f40197ecabf77ed59028af61739404eb60dd2e".to_string(), + parent_sha: "fcdbd1c07f0b6c8e7d8bbd727c6ca69a1af8c7e9".to_string(), + time: now3.into(), + pr: Some(107772), + }) + .await + .unwrap(); + + // In the distant past, won't show up in get_commits_with_artifacts. + connection + .record_commit(&Commit { + sha: "26904687275a55864f32f3a7ba87b7711d063fd5".to_string(), + parent_sha: "3b348d932aa5c9884310d025cf7c516023fd0d9a".to_string(), + time: "2022-02-19T23:25:06Z".parse().unwrap(), + pr: Some(92911), + }) + .await + .unwrap(); + + assert!(connection + .has_commit("eebdfb55fce148676c24555505aebf648123b2de") + .await + .unwrap()); + assert!(connection + .has_commit("73f40197ecabf77ed59028af61739404eb60dd2e") + .await + .unwrap()); + assert!(connection + .has_commit("26904687275a55864f32f3a7ba87b7711d063fd5") + .await + .unwrap()); + assert!(!connection + .has_commit("fcdbd1c07f0b6c8e7d8bbd727c6ca69a1af8c7e9") + .await + .unwrap()); + + let missing = connection.get_missing_commits().await.unwrap(); + assert_eq!( + &missing[..], + [ + "fcdbd1c07f0b6c8e7d8bbd727c6ca69a1af8c7e9", + "3b348d932aa5c9884310d025cf7c516023fd0d9a" + ] + ); + + let commits = connection.get_commits_with_artifacts().await.unwrap(); + assert_eq!(commits.len(), 2); + assert_eq!(commits[0].sha, "eebdfb55fce148676c24555505aebf648123b2de"); + assert_eq!( + commits[0].parent_sha, + "73f40197ecabf77ed59028af61739404eb60dd2e" + ); + assert_datetime_approx_equal(&commits[0].time, &now); + assert_eq!(commits[0].pr, Some(108228)); + + assert_eq!(commits[1].sha, "73f40197ecabf77ed59028af61739404eb60dd2e"); + assert_eq!( + commits[1].parent_sha, + "fcdbd1c07f0b6c8e7d8bbd727c6ca69a1af8c7e9" + ); + assert_datetime_approx_equal(&commits[1].time, &now3); + assert_eq!(commits[1].pr, Some(107772)); + }); +} diff --git a/tests/github_client/bors_commits/00-GET-repos_rust-lang_rust_commits.json b/tests/github_client/bors_commits/00-GET-repos_rust-lang_rust_commits.json new file mode 100644 index 00000000..b0658429 --- /dev/null +++ b/tests/github_client/bors_commits/00-GET-repos_rust-lang_rust_commits.json @@ -0,0 +1,2530 @@ +{ + "kind": "Request", + "method": "GET", + "path": "/repos/rust-lang/rust/commits", + "query": "author=bors", + "request_body": "", + "response_code": 200, + "response_body": [ + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/7f97aeaf73047268299ab55288b3dd886130be47/comments", + "commit": { + "author": { + "date": "2023-02-05T11:10:11Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-05T11:10:11Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107679 - est31:less_import_overhead, r=compiler-errors\n\nLess import overhead for errors\n\nThis removes huge (3+ lines) import lists found in files that had their error reporting migrated. These lists are bad for developer workflows as adding, removing, or editing a single error's name might cause a chain reaction that bloats the git diff. As the error struct names are long, the likelihood of such chain reactions is high.\n\nFollows the suggestion by `@Nilstrieb` in the [zulip thread](https://rust-lang.zulipchat.com/#narrow/stream/147480-t-compiler.2Fwg-diagnostics/topic/massive.20use.20statements) to replace the `use errors::{FooErr, BarErr};` with `use errors;` and then changing to `errors::FooErr` on the usage sites.\n\nI have used sed to do most of the changes, i.e. something like:\n\n```\nsed -i -E 's/(create_err|create_feature_err|emit_err|create_note|emit_fatal|emit_warning)\\(([[:alnum:]]+|[A-Z][[:alnum:]:]*)( \\{|\\))/\\1(errors::\\2\\3/' path/to/file.rs\n```\n\n& then I manually fixed the errors that occured. Most manual changes were required in `compiler/rustc_parse/src/parser/expr.rs`.\n\nr? `@compiler-errors`", + "tree": { + "sha": "28ef3869cb8034a8ab5e4ad389c139ec7dbd6df1", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/28ef3869cb8034a8ab5e4ad389c139ec7dbd6df1" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/7f97aeaf73047268299ab55288b3dd886130be47", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/7f97aeaf73047268299ab55288b3dd886130be47", + "node_id": "C_kwDOAAsO6NoAKDdmOTdhZWFmNzMwNDcyNjgyOTlhYjU1Mjg4YjNkZDg4NjEzMGJlNDc", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/2a6ff729233c62d1d991da5ed4d01aa29e59d637", + "sha": "2a6ff729233c62d1d991da5ed4d01aa29e59d637", + "url": "https://api.github.com/repos/rust-lang/rust/commits/2a6ff729233c62d1d991da5ed4d01aa29e59d637" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/580cc89e9c36a89d3cc13a352c96f874eaa76581", + "sha": "580cc89e9c36a89d3cc13a352c96f874eaa76581", + "url": "https://api.github.com/repos/rust-lang/rust/commits/580cc89e9c36a89d3cc13a352c96f874eaa76581" + } + ], + "sha": "7f97aeaf73047268299ab55288b3dd886130be47", + "url": "https://api.github.com/repos/rust-lang/rust/commits/7f97aeaf73047268299ab55288b3dd886130be47" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/2a6ff729233c62d1d991da5ed4d01aa29e59d637/comments", + "commit": { + "author": { + "date": "2023-02-05T07:36:37Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-05T07:36:37Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107434 - BoxyUwU:nll_const_equate, r=compiler-errors\n\nemit `ConstEquate` in `TypeRelating`\n\nemitting `ConstEquate` during mir typeck is useful since it can help catch bugs in hir typeck incase our impl of `ConstEquate` is wrong.\n\ndoing this did actually catch a bug, when relating `Expr::Call` we `==` the types of all the argument consts which spuriously returns false if the type contains const projections/aliases which causes us to fall through to the `expected_found` error arm.\nGenerally its an ICE if the `Const`'s `Ty`s arent equal but `ConstKind::Expr` is kind of special since they are sort of like const items that are `const CALL` though we dont actually explicitly represent the `F` type param explicitly in `Expr::Call` so I just made us relate the `Const`'s ty field to avoid getting ICEs from the tests I added and the following existing test:\n```rust\n// tests/ui/const-generics/generic_const_exprs/different-fn.rs\n#![feature(generic_const_exprs)]\n#![allow(incomplete_features)]\n\nuse std::mem::size_of;\nuse std::marker::PhantomData;\n\nstruct Foo(PhantomData);\n\nfn test() -> [u8; size_of::()] {\n [0; size_of::>()]\n //~^ ERROR unconstrained generic constant\n //~| ERROR mismatched types\n}\n\nfn main() {\n test::();\n}\n```\nwhich has us relate two `ConstKind::Value` one for the fn item of `size_of::>` and one for the fn item of `size_of::()`, these only differ by their `Ty` and if we don't relate the `Ty` we'll end up getting an ICE from the checks that ensure the `ty` fields always match.\n\nIn theory `Expr::UnOp` has the same problem so I added a call to `relate` for the ty's, although I was unable to create a repro test.", + "tree": { + "sha": "2304fe8c3bff131573b1cd5e6de1b3fb1c0ce7ad", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/2304fe8c3bff131573b1cd5e6de1b3fb1c0ce7ad" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/2a6ff729233c62d1d991da5ed4d01aa29e59d637", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/2a6ff729233c62d1d991da5ed4d01aa29e59d637", + "node_id": "C_kwDOAAsO6NoAKDJhNmZmNzI5MjMzYzYyZDFkOTkxZGE1ZWQ0ZDAxYWEyOWU1OWQ2Mzc", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/50d3ba5bcbf5c7e13d4ce068d3339710701dd603", + "sha": "50d3ba5bcbf5c7e13d4ce068d3339710701dd603", + "url": "https://api.github.com/repos/rust-lang/rust/commits/50d3ba5bcbf5c7e13d4ce068d3339710701dd603" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/d85d906f8c44dd98bf6bc0e4b753aa241839c323", + "sha": "d85d906f8c44dd98bf6bc0e4b753aa241839c323", + "url": "https://api.github.com/repos/rust-lang/rust/commits/d85d906f8c44dd98bf6bc0e4b753aa241839c323" + } + ], + "sha": "2a6ff729233c62d1d991da5ed4d01aa29e59d637", + "url": "https://api.github.com/repos/rust-lang/rust/commits/2a6ff729233c62d1d991da5ed4d01aa29e59d637" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/50d3ba5bcbf5c7e13d4ce068d3339710701dd603/comments", + "commit": { + "author": { + "date": "2023-02-04T21:07:10Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-04T21:07:10Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107672 - matthiaskrgr:rollup-7e6dbuk, r=matthiaskrgr\n\nRollup of 3 pull requests\n\nSuccessful merges:\n\n - #107116 (consolidate bootstrap docs)\n - #107646 (Provide structured suggestion for binding needing type on E0594)\n - #107661 (Remove Esteban from review queues for a while)\n\nFailed merges:\n\nr? `@ghost`\n`@rustbot` modify labels: rollup", + "tree": { + "sha": "932463b8bde694e38b6ed2bd27d772fc2ce0255f", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/932463b8bde694e38b6ed2bd27d772fc2ce0255f" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/50d3ba5bcbf5c7e13d4ce068d3339710701dd603", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/50d3ba5bcbf5c7e13d4ce068d3339710701dd603", + "node_id": "C_kwDOAAsO6NoAKDUwZDNiYTViY2JmNWM3ZTEzZDRjZTA2OGQzMzM5NzEwNzAxZGQ2MDM", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/3de7d7fb22a579a3d59ddb1c959d1b3da224aafa", + "sha": "3de7d7fb22a579a3d59ddb1c959d1b3da224aafa", + "url": "https://api.github.com/repos/rust-lang/rust/commits/3de7d7fb22a579a3d59ddb1c959d1b3da224aafa" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/47fc625a921aed430c08d6015246e65362256343", + "sha": "47fc625a921aed430c08d6015246e65362256343", + "url": "https://api.github.com/repos/rust-lang/rust/commits/47fc625a921aed430c08d6015246e65362256343" + } + ], + "sha": "50d3ba5bcbf5c7e13d4ce068d3339710701dd603", + "url": "https://api.github.com/repos/rust-lang/rust/commits/50d3ba5bcbf5c7e13d4ce068d3339710701dd603" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/3de7d7fb22a579a3d59ddb1c959d1b3da224aafa/comments", + "commit": { + "author": { + "date": "2023-02-04T18:11:02Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-04T18:11:02Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107549 - Zoxc:rustc-shared, r=jyn514\n\nMove code in `rustc_driver` out to a new `rustc_driver_impl` crate to allow pipelining\n\nThat adds a `rustc_shared` library which contains all the rustc library crates in a single dylib. It takes over this role from `rustc_driver`. This is done so that `rustc_driver` can be compiled in parallel with other crates. `rustc_shared` is intentionally left empty so it only does linking.\n\nAn alternative could be to move the code currently in `rustc_driver` into a new crate to avoid changing the name of the distributed library.", + "tree": { + "sha": "0d3e9447ea00657b717fbba42f6a854bc0b95355", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/0d3e9447ea00657b717fbba42f6a854bc0b95355" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/3de7d7fb22a579a3d59ddb1c959d1b3da224aafa", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/3de7d7fb22a579a3d59ddb1c959d1b3da224aafa", + "node_id": "C_kwDOAAsO6NoAKDNkZTdkN2ZiMjJhNTc5YTNkNTlkZGIxYzk1OWQxYjNkYTIyNGFhZmE", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/9dee4e4c42d23b0c5afd6d8fed025181f70fbe12", + "sha": "9dee4e4c42d23b0c5afd6d8fed025181f70fbe12", + "url": "https://api.github.com/repos/rust-lang/rust/commits/9dee4e4c42d23b0c5afd6d8fed025181f70fbe12" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/2b8f8922ee5852f97e92082b209c0f4d940a6edb", + "sha": "2b8f8922ee5852f97e92082b209c0f4d940a6edb", + "url": "https://api.github.com/repos/rust-lang/rust/commits/2b8f8922ee5852f97e92082b209c0f4d940a6edb" + } + ], + "sha": "3de7d7fb22a579a3d59ddb1c959d1b3da224aafa", + "url": "https://api.github.com/repos/rust-lang/rust/commits/3de7d7fb22a579a3d59ddb1c959d1b3da224aafa" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/9dee4e4c42d23b0c5afd6d8fed025181f70fbe12/comments", + "commit": { + "author": { + "date": "2023-02-04T15:17:32Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-04T15:17:32Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107267 - cjgillot:keep-aggregate, r=oli-obk\n\nDo not deaggregate MIR\n\nThis turns out to simplify a lot of things.\nI haven't checked the consequences for miri yet.\n\ncc `@JakobDegen`\nr? `@oli-obk`", + "tree": { + "sha": "9e854d084f562af0f8369eca144ad1fb044b248f", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/9e854d084f562af0f8369eca144ad1fb044b248f" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/9dee4e4c42d23b0c5afd6d8fed025181f70fbe12", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/9dee4e4c42d23b0c5afd6d8fed025181f70fbe12", + "node_id": "C_kwDOAAsO6NoAKDlkZWU0ZTRjNDJkMjNiMGM1YWZkNmQ4ZmVkMDI1MTgxZjcwZmJlMTI", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/4aa6afa7f8a418a7dae5dbe4c95371d4f3bcc0e1", + "sha": "4aa6afa7f8a418a7dae5dbe4c95371d4f3bcc0e1", + "url": "https://api.github.com/repos/rust-lang/rust/commits/4aa6afa7f8a418a7dae5dbe4c95371d4f3bcc0e1" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/5c39ba20279e338e2cd421bc799d4a5d3397c3b9", + "sha": "5c39ba20279e338e2cd421bc799d4a5d3397c3b9", + "url": "https://api.github.com/repos/rust-lang/rust/commits/5c39ba20279e338e2cd421bc799d4a5d3397c3b9" + } + ], + "sha": "9dee4e4c42d23b0c5afd6d8fed025181f70fbe12", + "url": "https://api.github.com/repos/rust-lang/rust/commits/9dee4e4c42d23b0c5afd6d8fed025181f70fbe12" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/4aa6afa7f8a418a7dae5dbe4c95371d4f3bcc0e1/comments", + "commit": { + "author": { + "date": "2023-02-04T11:22:31Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-04T11:22:31Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107618 - chriswailes:linker-arg, r=albertlarsan68\n\nAdd a linker argument back to boostrap.py\n\nIn https://github.com/rust-lang/rust/pull/101783 I accidentally removed a load-bearing linker argument. This PR adds it back in.\n\nr? jyn514", + "tree": { + "sha": "eac1bf39849eae33d4bb2b9bdb80304e8a03dd48", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/eac1bf39849eae33d4bb2b9bdb80304e8a03dd48" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/4aa6afa7f8a418a7dae5dbe4c95371d4f3bcc0e1", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/4aa6afa7f8a418a7dae5dbe4c95371d4f3bcc0e1", + "node_id": "C_kwDOAAsO6NoAKDRhYTZhZmE3ZjhhNDE4YTdkYWU1ZGJlNGM5NTM3MWQ0ZjNiY2MwZTE", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/91eb6f9acfcfde6832d547959ad2d95b1ac0b5dc", + "sha": "91eb6f9acfcfde6832d547959ad2d95b1ac0b5dc", + "url": "https://api.github.com/repos/rust-lang/rust/commits/91eb6f9acfcfde6832d547959ad2d95b1ac0b5dc" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/134a5aea52641715dd1ea1e4ad0e6a5693fbedc6", + "sha": "134a5aea52641715dd1ea1e4ad0e6a5693fbedc6", + "url": "https://api.github.com/repos/rust-lang/rust/commits/134a5aea52641715dd1ea1e4ad0e6a5693fbedc6" + } + ], + "sha": "4aa6afa7f8a418a7dae5dbe4c95371d4f3bcc0e1", + "url": "https://api.github.com/repos/rust-lang/rust/commits/4aa6afa7f8a418a7dae5dbe4c95371d4f3bcc0e1" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/91eb6f9acfcfde6832d547959ad2d95b1ac0b5dc/comments", + "commit": { + "author": { + "date": "2023-02-04T03:41:57Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-04T03:41:57Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107591 - krasimirgg:llvm-17-pgoopts, r=cuviper\n\nllvm-wrapper: adapt for LLVM API changes\n\nAdapts the wrapper for https://github.com/llvm/llvm-project/commit/516e301752560311d2cd8c2b549493eb0f98d01b, where the constructor of PGOOptions gained a new FileSystem argument. Adapted to use the real file system, similarly to the changes inside of LLVM:\nhttps://github.com/llvm/llvm-project/commit/516e301752560311d2cd8c2b549493eb0f98d01b#diff-f409934ba27ad86494f3012324e9a3995b56e0743609ded7a387ba62bbf5edb0R236\n\nFound via our experimental Rust + LLVM at HEAD bot: https://buildkite.com/llvm-project/rust-llvm-integrate-prototype/builds/16853#01860e2e-5eba-4f07-8359-0325913ff410/219-517", + "tree": { + "sha": "eac1bf39849eae33d4bb2b9bdb80304e8a03dd48", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/eac1bf39849eae33d4bb2b9bdb80304e8a03dd48" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/91eb6f9acfcfde6832d547959ad2d95b1ac0b5dc", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/91eb6f9acfcfde6832d547959ad2d95b1ac0b5dc", + "node_id": "C_kwDOAAsO6NoAKDkxZWI2ZjlhY2ZjZmRlNjgzMmQ1NDc5NTlhZDJkOTViMWFjMGI1ZGM", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/886b2c3e005b153b3c8263f48193e0df7de0f5b3", + "sha": "886b2c3e005b153b3c8263f48193e0df7de0f5b3", + "url": "https://api.github.com/repos/rust-lang/rust/commits/886b2c3e005b153b3c8263f48193e0df7de0f5b3" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/4614e5b5bf1331907bf3baf70cf0eb705f2959e9", + "sha": "4614e5b5bf1331907bf3baf70cf0eb705f2959e9", + "url": "https://api.github.com/repos/rust-lang/rust/commits/4614e5b5bf1331907bf3baf70cf0eb705f2959e9" + } + ], + "sha": "91eb6f9acfcfde6832d547959ad2d95b1ac0b5dc", + "url": "https://api.github.com/repos/rust-lang/rust/commits/91eb6f9acfcfde6832d547959ad2d95b1ac0b5dc" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/886b2c3e005b153b3c8263f48193e0df7de0f5b3/comments", + "commit": { + "author": { + "date": "2023-02-03T22:37:53Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-03T22:37:53Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107650 - compiler-errors:rollup-4pntchf, r=compiler-errors\n\nRollup of 8 pull requests\n\nSuccessful merges:\n\n - #106887 (Make const/fn return params more suggestable)\n - #107519 (Add type alias for raw OS errors)\n - #107551 ( Replace `ConstFnMutClosure` with const closures )\n - #107595 (Retry opening proc-macro DLLs a few times on Windows.)\n - #107615 (Replace nbsp in all rustdoc code blocks)\n - #107621 (Intern external constraints in new solver)\n - #107631 (loudly tell people when they change `Cargo.lock`)\n - #107632 (Clarifying that .map() returns None if None.)\n\nFailed merges:\n\nr? `@ghost`\n`@rustbot` modify labels: rollup", + "tree": { + "sha": "4bd560ab45691d951ce6a3b70229091e093a69b7", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/4bd560ab45691d951ce6a3b70229091e093a69b7" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/886b2c3e005b153b3c8263f48193e0df7de0f5b3", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/886b2c3e005b153b3c8263f48193e0df7de0f5b3", + "node_id": "C_kwDOAAsO6NoAKDg4NmIyYzNlMDA1YjE1M2IzYzgyNjNmNDgxOTNlMGRmN2RlMGY1YjM", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/658fad6c5506f41c35b64fb1a22ceb0992697ff3", + "sha": "658fad6c5506f41c35b64fb1a22ceb0992697ff3", + "url": "https://api.github.com/repos/rust-lang/rust/commits/658fad6c5506f41c35b64fb1a22ceb0992697ff3" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/13bd75f425f084d63817336db5ca433bc0655786", + "sha": "13bd75f425f084d63817336db5ca433bc0655786", + "url": "https://api.github.com/repos/rust-lang/rust/commits/13bd75f425f084d63817336db5ca433bc0655786" + } + ], + "sha": "886b2c3e005b153b3c8263f48193e0df7de0f5b3", + "url": "https://api.github.com/repos/rust-lang/rust/commits/886b2c3e005b153b3c8263f48193e0df7de0f5b3" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/658fad6c5506f41c35b64fb1a22ceb0992697ff3/comments", + "commit": { + "author": { + "date": "2023-02-03T17:53:49Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-03T17:53:49Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107642 - Dylan-DPC:rollup-edcqhm5, r=Dylan-DPC\n\nRollup of 6 pull requests\n\nSuccessful merges:\n\n - #107082 (Autotrait bounds on dyn-safe trait methods)\n - #107427 (Add candidates for DiscriminantKind builtin)\n - #107539 (Emit warnings on unused parens in index expressions)\n - #107544 (Improve `TokenCursor`.)\n - #107585 (Don't cause a cycle when formatting query description that references a FnDef)\n - #107633 (Fix suggestion for coercing Option<&String> to Option<&str>)\n\nFailed merges:\n\nr? `@ghost`\n`@rustbot` modify labels: rollup", + "tree": { + "sha": "d9beffb3e496848ea5acbe6d9caf2d102f473eab", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/d9beffb3e496848ea5acbe6d9caf2d102f473eab" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/658fad6c5506f41c35b64fb1a22ceb0992697ff3", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/658fad6c5506f41c35b64fb1a22ceb0992697ff3", + "node_id": "C_kwDOAAsO6NoAKDY1OGZhZDZjNTUwNmY0MWMzNWI2NGZiMWEyMmNlYjA5OTI2OTdmZjM", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/9545094994f1ab45cab5799d5b45980871a9e97b", + "sha": "9545094994f1ab45cab5799d5b45980871a9e97b", + "url": "https://api.github.com/repos/rust-lang/rust/commits/9545094994f1ab45cab5799d5b45980871a9e97b" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/c9270272df5bd7254b6ce1c7b69d41c75e443406", + "sha": "c9270272df5bd7254b6ce1c7b69d41c75e443406", + "url": "https://api.github.com/repos/rust-lang/rust/commits/c9270272df5bd7254b6ce1c7b69d41c75e443406" + } + ], + "sha": "658fad6c5506f41c35b64fb1a22ceb0992697ff3", + "url": "https://api.github.com/repos/rust-lang/rust/commits/658fad6c5506f41c35b64fb1a22ceb0992697ff3" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/9545094994f1ab45cab5799d5b45980871a9e97b/comments", + "commit": { + "author": { + "date": "2023-02-03T14:22:42Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-03T14:22:42Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107599 - clubby789:debug-less-ref, r=nnethercote\n\nDon't generate unecessary `&&self.field` in deriving Debug\n\nSince unsized fields may only be the last one in a struct, we only need to generate a double reference (`&&self.field`) for the final one.\n\ncc `@nnethercote`", + "tree": { + "sha": "f20e2d08b8836fe5498948b0863680019083975c", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/f20e2d08b8836fe5498948b0863680019083975c" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/9545094994f1ab45cab5799d5b45980871a9e97b", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/9545094994f1ab45cab5799d5b45980871a9e97b", + "node_id": "C_kwDOAAsO6NoAKDk1NDUwOTQ5OTRmMWFiNDVjYWI1Nzk5ZDViNDU5ODA4NzFhOWU5N2I", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/a94b9fd0ace1336a3dd93f51f1c0db6ca0fd7f92", + "sha": "a94b9fd0ace1336a3dd93f51f1c0db6ca0fd7f92", + "url": "https://api.github.com/repos/rust-lang/rust/commits/a94b9fd0ace1336a3dd93f51f1c0db6ca0fd7f92" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/d8651aae22d3b2251045647e7313fea37381362a", + "sha": "d8651aae22d3b2251045647e7313fea37381362a", + "url": "https://api.github.com/repos/rust-lang/rust/commits/d8651aae22d3b2251045647e7313fea37381362a" + } + ], + "sha": "9545094994f1ab45cab5799d5b45980871a9e97b", + "url": "https://api.github.com/repos/rust-lang/rust/commits/9545094994f1ab45cab5799d5b45980871a9e97b" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/a94b9fd0ace1336a3dd93f51f1c0db6ca0fd7f92/comments", + "commit": { + "author": { + "date": "2023-02-03T11:19:03Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-03T11:19:03Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107569 - petrochenkov:optattr, r=nnethercote\n\nast: Optimize list and value extraction primitives for attributes\n\nIt's not necessary to convert the whole attribute into a meta item to extract something specific.", + "tree": { + "sha": "a2064cce0219090bcdba2de58a84a62b78fc0270", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/a2064cce0219090bcdba2de58a84a62b78fc0270" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/a94b9fd0ace1336a3dd93f51f1c0db6ca0fd7f92", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/a94b9fd0ace1336a3dd93f51f1c0db6ca0fd7f92", + "node_id": "C_kwDOAAsO6NoAKGE5NGI5ZmQwYWNlMTMzNmEzZGQ5M2Y1MWYxYzBkYjZjYTBmZDdmOTI", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/7c46fb2111936ad21a8e3aa41e9128752357f5d8", + "sha": "7c46fb2111936ad21a8e3aa41e9128752357f5d8", + "url": "https://api.github.com/repos/rust-lang/rust/commits/7c46fb2111936ad21a8e3aa41e9128752357f5d8" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/a9c8a5c0255d056f78f1347c431fd88bc727febb", + "sha": "a9c8a5c0255d056f78f1347c431fd88bc727febb", + "url": "https://api.github.com/repos/rust-lang/rust/commits/a9c8a5c0255d056f78f1347c431fd88bc727febb" + } + ], + "sha": "a94b9fd0ace1336a3dd93f51f1c0db6ca0fd7f92", + "url": "https://api.github.com/repos/rust-lang/rust/commits/a94b9fd0ace1336a3dd93f51f1c0db6ca0fd7f92" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/7c46fb2111936ad21a8e3aa41e9128752357f5d8/comments", + "commit": { + "author": { + "date": "2023-02-03T08:07:47Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-03T08:07:47Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107625 - matthiaskrgr:rollup-xr9oldy, r=matthiaskrgr\n\nRollup of 6 pull requests\n\nSuccessful merges:\n\n - #106575 (Suggest `move` in nested closure when appropriate)\n - #106805 (Suggest `{var:?}` when finding `{?:var}` in inline format strings)\n - #107500 (Add tests to assert current behavior of large future sizes)\n - #107598 (Fix benchmarks in library/core with black_box)\n - #107602 (Parse and recover from type ascription in patterns)\n - #107608 (Use triple rather than arch for fuchsia test-runner)\n\nFailed merges:\n\nr? `@ghost`\n`@rustbot` modify labels: rollup", + "tree": { + "sha": "d3bdac647485a029e043f15ab0b46529058a437c", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/d3bdac647485a029e043f15ab0b46529058a437c" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/7c46fb2111936ad21a8e3aa41e9128752357f5d8", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/7c46fb2111936ad21a8e3aa41e9128752357f5d8", + "node_id": "C_kwDOAAsO6NoAKDdjNDZmYjIxMTE5MzZhZDIxYThlM2FhNDFlOTEyODc1MjM1N2Y1ZDg", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/5d32458343f34bd8de6d96cbaab2a9cf879dd1b8", + "sha": "5d32458343f34bd8de6d96cbaab2a9cf879dd1b8", + "url": "https://api.github.com/repos/rust-lang/rust/commits/5d32458343f34bd8de6d96cbaab2a9cf879dd1b8" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/b6e8ebf33b0203ab16bbb26eb95a6654ee00ac8e", + "sha": "b6e8ebf33b0203ab16bbb26eb95a6654ee00ac8e", + "url": "https://api.github.com/repos/rust-lang/rust/commits/b6e8ebf33b0203ab16bbb26eb95a6654ee00ac8e" + } + ], + "sha": "7c46fb2111936ad21a8e3aa41e9128752357f5d8", + "url": "https://api.github.com/repos/rust-lang/rust/commits/7c46fb2111936ad21a8e3aa41e9128752357f5d8" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/5d32458343f34bd8de6d96cbaab2a9cf879dd1b8/comments", + "commit": { + "author": { + "date": "2023-02-03T04:49:50Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-03T04:49:50Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107543 - ehuss:protocol-sparse, r=jyn514\n\nEnable Cargo's sparse protocol in CI\n\nThis enables the sparse protocol in CI in order to exercise and dogfood it. This is intended test the production server in a real-world situation.\n\nCloses #107342", + "tree": { + "sha": "9c2f45b42f042b5f78bfd1b8c491958f83dd1351", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/9c2f45b42f042b5f78bfd1b8c491958f83dd1351" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/5d32458343f34bd8de6d96cbaab2a9cf879dd1b8", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/5d32458343f34bd8de6d96cbaab2a9cf879dd1b8", + "node_id": "C_kwDOAAsO6NoAKDVkMzI0NTgzNDNmMzRiZDhkZTZkOTZjYmFhYjJhOWNmODc5ZGQxYjg", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/f02439dea78e5c2df42198c7a03e2db6002ff263", + "sha": "f02439dea78e5c2df42198c7a03e2db6002ff263", + "url": "https://api.github.com/repos/rust-lang/rust/commits/f02439dea78e5c2df42198c7a03e2db6002ff263" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/5e90940a4b742e7f1e86f21c26b56e99a8733458", + "sha": "5e90940a4b742e7f1e86f21c26b56e99a8733458", + "url": "https://api.github.com/repos/rust-lang/rust/commits/5e90940a4b742e7f1e86f21c26b56e99a8733458" + } + ], + "sha": "5d32458343f34bd8de6d96cbaab2a9cf879dd1b8", + "url": "https://api.github.com/repos/rust-lang/rust/commits/5d32458343f34bd8de6d96cbaab2a9cf879dd1b8" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/f02439dea78e5c2df42198c7a03e2db6002ff263/comments", + "commit": { + "author": { + "date": "2023-02-03T01:19:04Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-03T01:19:04Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107241 - clubby789:bootstrap-lto-off, r=simulacrum\n\nAdd `rust.lto=off` to bootstrap and set as compiler/library default\n\nCloses #107202\n\nThe issue mentions `embed-bitcode=on`, but here https://github.com/rust-lang/rust/blob/c8e6a9e8b6251bbc8276cb78cabe1998deecbed7/src/bootstrap/compile.rs#L379-L381\nit appears that this is always set for std stage 1+, so I'm unsure if changes are needed here.\n\n`@rustbot` label +A-bootstrap", + "tree": { + "sha": "ba934c044e040c794ecaf64c5d0ddea604210a5c", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/ba934c044e040c794ecaf64c5d0ddea604210a5c" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/f02439dea78e5c2df42198c7a03e2db6002ff263", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/f02439dea78e5c2df42198c7a03e2db6002ff263", + "node_id": "C_kwDOAAsO6NoAKGYwMjQzOWRlYTc4ZTVjMmRmNDIxOThjN2EwM2UyZGI2MDAyZmYyNjM", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/6c991b07403a3234dd1ec0ac973b8ef97055e605", + "sha": "6c991b07403a3234dd1ec0ac973b8ef97055e605", + "url": "https://api.github.com/repos/rust-lang/rust/commits/6c991b07403a3234dd1ec0ac973b8ef97055e605" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/2adf26fc72f354aabd65da176eb9f8806b0d2ef2", + "sha": "2adf26fc72f354aabd65da176eb9f8806b0d2ef2", + "url": "https://api.github.com/repos/rust-lang/rust/commits/2adf26fc72f354aabd65da176eb9f8806b0d2ef2" + } + ], + "sha": "f02439dea78e5c2df42198c7a03e2db6002ff263", + "url": "https://api.github.com/repos/rust-lang/rust/commits/f02439dea78e5c2df42198c7a03e2db6002ff263" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/6c991b07403a3234dd1ec0ac973b8ef97055e605/comments", + "commit": { + "author": { + "date": "2023-02-02T21:14:44Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-02T21:14:44Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107000 - GuillaumeGomez:fix-items-in-doc-hidden-block, r=notriddle,petrochenkov\n\nFix handling of items inside a `doc(hidden)` block\n\nFixes #106373.\n\ncc `@aDotInTheVoid`\nr? `@notriddle`", + "tree": { + "sha": "e9fd955533d898249d8602ae2e2cc9b6040b264b", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/e9fd955533d898249d8602ae2e2cc9b6040b264b" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/6c991b07403a3234dd1ec0ac973b8ef97055e605", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/6c991b07403a3234dd1ec0ac973b8ef97055e605", + "node_id": "C_kwDOAAsO6NoAKDZjOTkxYjA3NDAzYTMyMzRkZDFlYzBhYzk3M2I4ZWY5NzA1NWU2MDU", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/f3126500f25114ba4e0ac3e76694dd45a22de56d", + "sha": "f3126500f25114ba4e0ac3e76694dd45a22de56d", + "url": "https://api.github.com/repos/rust-lang/rust/commits/f3126500f25114ba4e0ac3e76694dd45a22de56d" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/ea844187b27fbcff521bcbcbe6615d51d0196fa2", + "sha": "ea844187b27fbcff521bcbcbe6615d51d0196fa2", + "url": "https://api.github.com/repos/rust-lang/rust/commits/ea844187b27fbcff521bcbcbe6615d51d0196fa2" + } + ], + "sha": "6c991b07403a3234dd1ec0ac973b8ef97055e605", + "url": "https://api.github.com/repos/rust-lang/rust/commits/6c991b07403a3234dd1ec0ac973b8ef97055e605" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/f3126500f25114ba4e0ac3e76694dd45a22de56d/comments", + "commit": { + "author": { + "date": "2023-02-02T17:56:53Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-02T17:56:53Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107601 - matthiaskrgr:rollup-07zaafe, r=matthiaskrgr\n\nRollup of 7 pull requests\n\nSuccessful merges:\n\n - #106919 (Recover `_` as `..` in field pattern)\n - #107493 (Improve diagnostic for missing space in range pattern)\n - #107515 (Improve pretty-printing of `HirIdValidator` errors)\n - #107524 (Remove both StorageLive and StorageDead in CopyProp.)\n - #107532 (Erase regions before doing uninhabited check in borrowck)\n - #107559 (Rename `rust_2015` → `is_rust_2015`)\n - #107577 (Reinstate the `hir-stats.rs` tests on stage 1.)\n\nFailed merges:\n\nr? `@ghost`\n`@rustbot` modify labels: rollup", + "tree": { + "sha": "ab016ef14231c6193f6a9d086fca0cda4a159f9a", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/ab016ef14231c6193f6a9d086fca0cda4a159f9a" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/f3126500f25114ba4e0ac3e76694dd45a22de56d", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/f3126500f25114ba4e0ac3e76694dd45a22de56d", + "node_id": "C_kwDOAAsO6NoAKGYzMTI2NTAwZjI1MTE0YmE0ZTBhYzNlNzY2OTRkZDQ1YTIyZGU1NmQ", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/97872b792c9dd6a9bc5c3f4e62a0bd5958b09cdc", + "sha": "97872b792c9dd6a9bc5c3f4e62a0bd5958b09cdc", + "url": "https://api.github.com/repos/rust-lang/rust/commits/97872b792c9dd6a9bc5c3f4e62a0bd5958b09cdc" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/08181eabfeb468e22e5ce179492979d57d0cdf85", + "sha": "08181eabfeb468e22e5ce179492979d57d0cdf85", + "url": "https://api.github.com/repos/rust-lang/rust/commits/08181eabfeb468e22e5ce179492979d57d0cdf85" + } + ], + "sha": "f3126500f25114ba4e0ac3e76694dd45a22de56d", + "url": "https://api.github.com/repos/rust-lang/rust/commits/f3126500f25114ba4e0ac3e76694dd45a22de56d" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/97872b792c9dd6a9bc5c3f4e62a0bd5958b09cdc/comments", + "commit": { + "author": { + "date": "2023-02-02T12:01:17Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-02T12:01:17Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107478 - compiler-errors:anon-enum-tys-are-ambiguous, r=estebank\n\nRevert \"Teach parser to understand fake anonymous enum syntax\" and related commits\n\nanonymous enum types are currently ambiguous in positions like:\n\n* `|` operator: `a as fn() -> B | C`\n* closure args: `|_: as fn() -> A | B`\n\nI first tried to thread around `RecoverAnonEnum` into all these positions, but the resulting complexity in the compiler is IMO not worth it, or at least worth a bit more thinking time. In the mean time, let's revert this syntax for now, so we can go back to the drawing board.\n\nFixes #107461\n\ncc: `@estebank` `@cjgillot` #106960\n\n---\n### Squashed revert commits:\n\nRevert \"review comment: Remove AST AnonTy\"\n\nThis reverts commit 020cca8d36cb678e3ddc2ead41364be314d19e93.\n\nRevert \"Ensure macros are not affected\"\n\nThis reverts commit 12d18e403139eeeeb339e8611b2bed4910864edb.\n\nRevert \"Emit fewer errors on patterns with possible type ascription\"\n\nThis reverts commit c847a01a3b1f620c4fdb98c75805033e768975d1.\n\nRevert \"Teach parser to understand fake anonymous enum syntax\"\n\nThis reverts commit 2d824206655bfb26cb5eed43490ee396542b153e.", + "tree": { + "sha": "ac382c6f916b98074fe5ce756d3778d5d3f0d407", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/ac382c6f916b98074fe5ce756d3778d5d3f0d407" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/97872b792c9dd6a9bc5c3f4e62a0bd5958b09cdc", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/97872b792c9dd6a9bc5c3f4e62a0bd5958b09cdc", + "node_id": "C_kwDOAAsO6NoAKDk3ODcyYjc5MmM5ZGQ2YTliYzVjM2Y0ZTYyYTBiZDU5NThiMDljZGM", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/a9985cf172e7cb8ab5c58ce2818752c3572754fc", + "sha": "a9985cf172e7cb8ab5c58ce2818752c3572754fc", + "url": "https://api.github.com/repos/rust-lang/rust/commits/a9985cf172e7cb8ab5c58ce2818752c3572754fc" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/39db65c526ae3b97f0ee90642242c8c07865707e", + "sha": "39db65c526ae3b97f0ee90642242c8c07865707e", + "url": "https://api.github.com/repos/rust-lang/rust/commits/39db65c526ae3b97f0ee90642242c8c07865707e" + } + ], + "sha": "97872b792c9dd6a9bc5c3f4e62a0bd5958b09cdc", + "url": "https://api.github.com/repos/rust-lang/rust/commits/97872b792c9dd6a9bc5c3f4e62a0bd5958b09cdc" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/a9985cf172e7cb8ab5c58ce2818752c3572754fc/comments", + "commit": { + "author": { + "date": "2023-02-02T09:05:18Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-02T09:05:18Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107584 - matthiaskrgr:rollup-vav4ljz, r=matthiaskrgr\n\nRollup of 5 pull requests\n\nSuccessful merges:\n\n - #107201 (Remove confusing 'while checking' note from opaque future type mismatches)\n - #107312 (Add Style Guide rules for let-else statements)\n - #107488 (Fix syntax in `-Zunpretty-expanded` output for derived `PartialEq`.)\n - #107531 (Inline CSS background images directly into the CSS)\n - #107576 (Add proc-macro boilerplate to crt-static test)\n\nFailed merges:\n\nr? `@ghost`\n`@rustbot` modify labels: rollup", + "tree": { + "sha": "dbb937247db20bbd75be7bde50d74213d674dbde", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/dbb937247db20bbd75be7bde50d74213d674dbde" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/a9985cf172e7cb8ab5c58ce2818752c3572754fc", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/a9985cf172e7cb8ab5c58ce2818752c3572754fc", + "node_id": "C_kwDOAAsO6NoAKGE5OTg1Y2YxNzJlN2NiOGFiNWM1OGNlMjgxODc1MmMzNTcyNzU0ZmM", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/821b2a8e39588fedda894d10b9b3abd7293f0383", + "sha": "821b2a8e39588fedda894d10b9b3abd7293f0383", + "url": "https://api.github.com/repos/rust-lang/rust/commits/821b2a8e39588fedda894d10b9b3abd7293f0383" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/643fc97fd3b3f4f34eb2d66af1deac9218835527", + "sha": "643fc97fd3b3f4f34eb2d66af1deac9218835527", + "url": "https://api.github.com/repos/rust-lang/rust/commits/643fc97fd3b3f4f34eb2d66af1deac9218835527" + } + ], + "sha": "a9985cf172e7cb8ab5c58ce2818752c3572754fc", + "url": "https://api.github.com/repos/rust-lang/rust/commits/a9985cf172e7cb8ab5c58ce2818752c3572754fc" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/821b2a8e39588fedda894d10b9b3abd7293f0383/comments", + "commit": { + "author": { + "date": "2023-02-02T05:26:09Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-02T05:26:09Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #106925 - imWildCat:imWildCat/remove-hardcoded-ios-macbi-target-version, r=wesleywiser\n\nRemove hardcoded iOS version of clang target for Mac Catalyst\n\n## Background\n\nFrom `clang` 13.x, `-target x86_64-apple-ios13.0-macabi` fails while linking:\n\n```\n = note: clang: error: invalid version number in '-target x86_64-apple-ios13.0-macabi'\n```\n\n\nVerbose output\n\n```\nerror: linking with `cc` failed: exit status: 1\n |\n = note: LC_ALL=\"C\" PATH=\"[removed]\" VSLANG=\"1033\" ZERO_AR_DATE=\"1\" \"cc\" \"-Wl,-exported_symbols_list,/var/folders/p8/qpmzbsdn07g5gxykwfxxw7y40000gn/T/rustci8tkvp/list\" \"-target\" \"x86_64-apple-ios13.0-macabi\" \"/var/folders/p8/qpmzbsdn07g5gxykwfxxw7y40000gn/T/rustci8tkvp/symbols.o\" \"/path/to/my/[project]/[user]/target/x86_64-apple-ios-macabi/release/deps/[user].[user].a2ccc648-cgu.0.rcgu.o\" \"-L\" \"/path/to/my/[project]/[user]/target/x86_64-apple-ios-macabi/release/deps\" \"-L\" \"/path/to/my/[project]/[user]/target/release/deps\" \"-L\" \"/path/to/my/[project]/[user]/target/x86_64-apple-ios-macabi/release/build/blake3-74e6ba91506ce712/out\" \"-L\" \"/path/to/my/[project]/[user]/target/x86_64-apple-ios-macabi/release/build/blake3-74e6ba91506ce712/out\" \"-L\" \"/Users/[user]/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/x86_64-apple-ios-macabi/lib\" \"/var/folders/p8/qpmzbsdn07g5gxykwfxxw7y40000gn/T/rustci8tkvp/libblake3-343c1616c8f62c66.rlib\" \"/path/to/my/[project]/[user]/target/x86_64-apple-ios-macabi/release/deps/libcompiler_builtins-15d4f20b641cf9ef.rlib\" \"-framework\" \"Security\" \"-framework\" \"CoreFoundation\" \"-framework\" \"Security\" \"-liconv\" \"-lSystem\" \"-lobjc\" \"-framework\" \"Security\" \"-framework\" \"Foundation\" \"-lc\" \"-lm\" \"-isysroot\" \"/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.1.sdk\" \"-Wl,-syslibroot\" \"/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.1.sdk\" \"-L\" \"/Users/[user]/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/x86_64-apple-ios-macabi/lib\" \"-o\" \"/path/to/my/[project]/[user]/target/x86_64-apple-ios-macabi/release/deps/lib[user].dylib\" \"-Wl,-dead_strip\" \"-dynamiclib\" \"-Wl,-dylib\" \"-nodefaultlibs\"\n = note: clang: error: invalid version number in '-target x86_64-apple-ios13.0-macabi'\n\nwarning: `[user]` (lib) generated 6 warnings\nerror: could not compile `[user]` due to previous error; 6 warnings emitted\n```\n\n\n### Minimal example\n\nC code:\n\n```c\n#include \nvoid main() {\n int a = 1;\n int b = 2;\n int c = a + b;\n printf(\"%d\", c);\n}\n```\n\n`clang` command sample:\n\n```\n➜ 202301 clang -target x86_64-apple-ios13.0-macabi main.c\nclang: error: invalid version number in '-target x86_64-apple-ios13.0-macabi'\n➜ 202301 clang -target x86_64-apple-ios14.0-macabi main.c\nmain.c:2:1: warning: return type of 'main' is not 'int' [-Wmain-return-type]\nvoid main() {\n^\nmain.c:2:1: note: change return type to 'int'\nvoid main() {\n^~~~\nint\n1 warning generated.\n➜ 202301 clang -target x86_64-apple-ios15.0-macabi main.c\nmain.c:2:1: warning: return type of 'main' is not 'int' [-Wmain-return-type]\nvoid main() {\n^\nmain.c:2:1: note: change return type to 'int'\nvoid main() {\n^~~~\nint\n1 warning generated.\n➜ 202301 clang -target x86_64-apple-ios-macabi main.c\nmain.c:2:1: warning: return type of 'main' is not 'int' [-Wmain-return-type]\nvoid main() {\n^\nmain.c:2:1: note: change return type to 'int'\nvoid main() {\n^~~~\nint\n1 warning generated.\n\n➜ 202301 clang --version\nApple clang version 14.0.0 (clang-1400.0.29.202)\nTarget: arm64-apple-darwin22.2.0\nThread model: posix\nInstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin\n```\n\nThis PR is a simplified version of #96392, inspired by https://github.com/rust-lang/cc-rs/pull/727", + "tree": { + "sha": "0f1eba14a5ae3fa1c9c700ec5d1b07c0dab8b554", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/0f1eba14a5ae3fa1c9c700ec5d1b07c0dab8b554" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/821b2a8e39588fedda894d10b9b3abd7293f0383", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/821b2a8e39588fedda894d10b9b3abd7293f0383", + "node_id": "C_kwDOAAsO6NoAKDgyMWIyYThlMzk1ODhmZWRkYTg5NGQxMGI5YjNhYmQ3MjkzZjAzODM", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/131f0c6df6777800aa884963bdba0739299cd31f", + "sha": "131f0c6df6777800aa884963bdba0739299cd31f", + "url": "https://api.github.com/repos/rust-lang/rust/commits/131f0c6df6777800aa884963bdba0739299cd31f" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/5209d6f5fdac2054666a15c64f78450d6cb99717", + "sha": "5209d6f5fdac2054666a15c64f78450d6cb99717", + "url": "https://api.github.com/repos/rust-lang/rust/commits/5209d6f5fdac2054666a15c64f78450d6cb99717" + } + ], + "sha": "821b2a8e39588fedda894d10b9b3abd7293f0383", + "url": "https://api.github.com/repos/rust-lang/rust/commits/821b2a8e39588fedda894d10b9b3abd7293f0383" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/131f0c6df6777800aa884963bdba0739299cd31f/comments", + "commit": { + "author": { + "date": "2023-02-02T02:23:31Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-02T02:23:31Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #105670 - Xiretza:rustc_parse-diagnostics-4, r=davidtwco\n\nrustc_parse: diagnostics migration, v4\n\nThis is all the `rustc_parse` migrations I have in store right now; unfortunately life is pretty busy right now, so I won't be able to do much more in the near future.\n\ncc #100717\n\nr? `@davidtwco`", + "tree": { + "sha": "44543518d5568584010021497a2e187328bf9b06", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/44543518d5568584010021497a2e187328bf9b06" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/131f0c6df6777800aa884963bdba0739299cd31f", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/131f0c6df6777800aa884963bdba0739299cd31f", + "node_id": "C_kwDOAAsO6NoAKDEzMWYwYzZkZjY3Nzc4MDBhYTg4NDk2M2JkYmEwNzM5Mjk5Y2QzMWY", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/8789e5392975203137765d7818fb23ad125782b3", + "sha": "8789e5392975203137765d7818fb23ad125782b3", + "url": "https://api.github.com/repos/rust-lang/rust/commits/8789e5392975203137765d7818fb23ad125782b3" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/0d0d36991599d230d4781432391608f9821765fa", + "sha": "0d0d36991599d230d4781432391608f9821765fa", + "url": "https://api.github.com/repos/rust-lang/rust/commits/0d0d36991599d230d4781432391608f9821765fa" + } + ], + "sha": "131f0c6df6777800aa884963bdba0739299cd31f", + "url": "https://api.github.com/repos/rust-lang/rust/commits/131f0c6df6777800aa884963bdba0739299cd31f" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/8789e5392975203137765d7818fb23ad125782b3/comments", + "commit": { + "author": { + "date": "2023-02-01T22:45:27Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-01T22:45:27Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107574 - compiler-errors:back-to-old-mac-builders-pls, r=pietroalbini\n\nRevert \"switch to the macos-12-xl builder\"\n\nThis reverts commit fcbae989ae790d5b9a0a23ceba242d0b0d4e6c5b.\n\nThis should fix the bors failures in https://rust-lang.zulipchat.com/#narrow/stream/242791-t-infra/topic/Every.20rust-lang.2Frust.20PR.20is.20failing.20bors", + "tree": { + "sha": "68f1f608bda41a90ec8a74295dbc3deb7e6c783c", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/68f1f608bda41a90ec8a74295dbc3deb7e6c783c" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/8789e5392975203137765d7818fb23ad125782b3", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/8789e5392975203137765d7818fb23ad125782b3", + "node_id": "C_kwDOAAsO6NoAKDg3ODllNTM5Mjk3NTIwMzEzNzc2NWQ3ODE4ZmIyM2FkMTI1NzgyYjM", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/11d96b59307b1702fffe871bfc2d0145d070881e", + "sha": "11d96b59307b1702fffe871bfc2d0145d070881e", + "url": "https://api.github.com/repos/rust-lang/rust/commits/11d96b59307b1702fffe871bfc2d0145d070881e" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/e63ec2e1402eaff949e5c53b8f6062b152010fcc", + "sha": "e63ec2e1402eaff949e5c53b8f6062b152010fcc", + "url": "https://api.github.com/repos/rust-lang/rust/commits/e63ec2e1402eaff949e5c53b8f6062b152010fcc" + } + ], + "sha": "8789e5392975203137765d7818fb23ad125782b3", + "url": "https://api.github.com/repos/rust-lang/rust/commits/8789e5392975203137765d7818fb23ad125782b3" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/11d96b59307b1702fffe871bfc2d0145d070881e/comments", + "commit": { + "author": { + "date": "2023-02-01T11:37:24Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-01T11:37:24Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107257 - inquisitivecrystal:ffi-attr, r=davidtwco\n\nStrengthen validation of FFI attributes\n\nPreviously, `codegen_attrs` validated the attributes `#[ffi_pure]`, `#[ffi_const]`, and `#[ffi_returns_twice]` to make sure that they were only used on foreign functions. However, this validation was insufficient in two ways:\n\n1. `codegen_attrs` only sees items for which code must be generated, so it was unable to raise errors when the attribute was incorrectly applied to macros and the like.\n2. the validation code only checked that the item with the attr was foreign, but not that it was a foreign function, allowing these attributes to be applied to foreign statics as well.\n\nThis PR moves the validation to `check_attr`, which sees all items. It additionally changes the validation to ensure that the attribute's target is `Target::ForeignFunction`, only allowing the attributes on foreign functions and not foreign statics. Because these attributes are unstable, there is no risk for backwards compatibility. The changes also ending up making the code much easier to read.\n\nThis PR is best reviewed commit by commit. Additionally, I was considering moving the tests to the `attribute` subdirectory, to get them out of the general UI directory. I could do that as part of this PR or a follow-up, as the reviewer prefers.\n\nCC: #58328, #58329", + "tree": { + "sha": "af26139253d2807f229208f8301714afc803c306", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/af26139253d2807f229208f8301714afc803c306" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/11d96b59307b1702fffe871bfc2d0145d070881e", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/11d96b59307b1702fffe871bfc2d0145d070881e", + "node_id": "C_kwDOAAsO6NoAKDExZDk2YjU5MzA3YjE3MDJmZmZlODcxYmZjMmQwMTQ1ZDA3MDg4MWU", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/3b639486c17e9144a9176382ecb2a0b801263935", + "sha": "3b639486c17e9144a9176382ecb2a0b801263935", + "url": "https://api.github.com/repos/rust-lang/rust/commits/3b639486c17e9144a9176382ecb2a0b801263935" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/bc23e9aa4c78066043be246a47627746341480dd", + "sha": "bc23e9aa4c78066043be246a47627746341480dd", + "url": "https://api.github.com/repos/rust-lang/rust/commits/bc23e9aa4c78066043be246a47627746341480dd" + } + ], + "sha": "11d96b59307b1702fffe871bfc2d0145d070881e", + "url": "https://api.github.com/repos/rust-lang/rust/commits/11d96b59307b1702fffe871bfc2d0145d070881e" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/3b639486c17e9144a9176382ecb2a0b801263935/comments", + "commit": { + "author": { + "date": "2023-02-01T07:47:29Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-01T07:47:29Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107546 - matthiaskrgr:rollup-9rgf2gx, r=matthiaskrgr\n\nRollup of 6 pull requests\n\nSuccessful merges:\n\n - #107389 (Fixing confusion between mod and remainder)\n - #107442 (improve panic message for slice windows and chunks)\n - #107470 (Small bootstrap improvements)\n - #107487 (Make the \"extra if in let...else block\" hint a suggestion)\n - #107499 (Do not depend on Generator trait when deducing closure signature)\n - #107533 (Extend `-Z print-type-sizes` to distinguish generator upvars+locals from \"normal\" fields.)\n\nFailed merges:\n\nr? `@ghost`\n`@rustbot` modify labels: rollup", + "tree": { + "sha": "7a062a4c43bf11d1fa11b1efdfd496d8a6f40d78", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/7a062a4c43bf11d1fa11b1efdfd496d8a6f40d78" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/3b639486c17e9144a9176382ecb2a0b801263935", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/3b639486c17e9144a9176382ecb2a0b801263935", + "node_id": "C_kwDOAAsO6NoAKDNiNjM5NDg2YzE3ZTkxNDRhOTE3NjM4MmVjYjJhMGI4MDEyNjM5MzU", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/0d32c8f2ce10710b6560dcb75f32f79c378410d0", + "sha": "0d32c8f2ce10710b6560dcb75f32f79c378410d0", + "url": "https://api.github.com/repos/rust-lang/rust/commits/0d32c8f2ce10710b6560dcb75f32f79c378410d0" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/f41f154dfbe2aa943e35a21c0e2a8de002443424", + "sha": "f41f154dfbe2aa943e35a21c0e2a8de002443424", + "url": "https://api.github.com/repos/rust-lang/rust/commits/f41f154dfbe2aa943e35a21c0e2a8de002443424" + } + ], + "sha": "3b639486c17e9144a9176382ecb2a0b801263935", + "url": "https://api.github.com/repos/rust-lang/rust/commits/3b639486c17e9144a9176382ecb2a0b801263935" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/0d32c8f2ce10710b6560dcb75f32f79c378410d0/comments", + "commit": { + "author": { + "date": "2023-02-01T04:53:29Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-01T04:53:29Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107541 - weihanglo:update-cargo, r=weihanglo\n\nUpdate cargo\n\n18 commits in 3c5af6bed9a1a243a693e8e22ee2486bd5b82a6c..e84a7928d93a31f284b497c214a2ece69b4d7719 2023-01-24 15:48:15 +0000 to 2023-01-31 22:18:09 +0000\n\n- chore: Add autolabel for `Command-*` labels (rust-lang/cargo#11664)\n- Update cross test instructions for aarch64-apple-darwin (rust-lang/cargo#11663)\n- Make cargo install report needed features (rust-lang/cargo#11647)\n- docs(contrib): Remove out-of-date process step (rust-lang/cargo#11662)\n- Do not error for `auth-required: true` without `-Z sparse-registry` (rust-lang/cargo#11661)\n- Warn on commits to non-default branches. (rust-lang/cargo#11655)\n- Avoid saving the same future_incompat warning multiple times (rust-lang/cargo#11648)\n- Mention current default value in `publish.timeout` docs (rust-lang/cargo#11652)\n- Make cargo aware of dwp files. (rust-lang/cargo#11572)\n- Reduce target info rustc query calls (rust-lang/cargo#11633)\n- Bump to 0.70.0; update changelog (rust-lang/cargo#11640)\n- Enable sparse protocol in CI (rust-lang/cargo#11632)\n- Fix split-debuginfo support detection (rust-lang/cargo#11347)\n- refactor(toml): Move `TomlWorkspaceDependency` out of `TomlDependency` (rust-lang/cargo#11565)\n- book: describe how the current resolver sometimes duplicates deps (rust-lang/cargo#11604)\n- `cargo add` check `[dependencies]` order without considering the dotted item (rust-lang/cargo#11612)\n- Link CoC to www.rust-lang.org/conduct.html (rust-lang/cargo#11622)\n- Add more labels to triagebot (rust-lang/cargo#11621)\n\nr? `@ghost`", + "tree": { + "sha": "9e08bab8c2e9b024e7ce120ed0c1fa7bbea9c463", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/9e08bab8c2e9b024e7ce120ed0c1fa7bbea9c463" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/0d32c8f2ce10710b6560dcb75f32f79c378410d0", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/0d32c8f2ce10710b6560dcb75f32f79c378410d0", + "node_id": "C_kwDOAAsO6NoAKDBkMzJjOGYyY2UxMDcxMGI2NTYwZGNiNzVmMzJmNzljMzc4NDEwZDA", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/ad8e1dc2863f63c35ef3ceef3064d0851a1d2582", + "sha": "ad8e1dc2863f63c35ef3ceef3064d0851a1d2582", + "url": "https://api.github.com/repos/rust-lang/rust/commits/ad8e1dc2863f63c35ef3ceef3064d0851a1d2582" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/bb2af4f28ca89b5088db433645f9e61f03c9ac2c", + "sha": "bb2af4f28ca89b5088db433645f9e61f03c9ac2c", + "url": "https://api.github.com/repos/rust-lang/rust/commits/bb2af4f28ca89b5088db433645f9e61f03c9ac2c" + } + ], + "sha": "0d32c8f2ce10710b6560dcb75f32f79c378410d0", + "url": "https://api.github.com/repos/rust-lang/rust/commits/0d32c8f2ce10710b6560dcb75f32f79c378410d0" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/ad8e1dc2863f63c35ef3ceef3064d0851a1d2582/comments", + "commit": { + "author": { + "date": "2023-02-01T01:15:02Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-02-01T01:15:02Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107536 - GuillaumeGomez:rollup-xv7dx2h, r=GuillaumeGomez\n\nRollup of 12 pull requests\n\nSuccessful merges:\n\n - #106898 (Include both md and yaml ICE ticket templates)\n - #107331 (Clean up eslint annotations and remove unused JS function)\n - #107348 (small refactor to new projection code)\n - #107354 (rustdoc: update Source Serif 4 from 4.004 to 4.005)\n - #107412 (avoid needless checks)\n - #107467 (Improve enum checks)\n - #107486 (Track bound types like bound regions)\n - #107491 (rustdoc: remove unused CSS from `.setting-check`)\n - #107508 (`Edition` micro refactor)\n - #107525 (PointeeInfo is advisory only)\n - #107527 (rustdoc: stop making unstable items transparent)\n - #107535 (Replace unwrap with ? in TcpListener doc)\n\nFailed merges:\n\nr? `@ghost`\n`@rustbot` modify labels: rollup", + "tree": { + "sha": "64d8db18dc8c8e118fd859c74061a34efbcae9d4", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/64d8db18dc8c8e118fd859c74061a34efbcae9d4" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/ad8e1dc2863f63c35ef3ceef3064d0851a1d2582", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/ad8e1dc2863f63c35ef3ceef3064d0851a1d2582", + "node_id": "C_kwDOAAsO6NoAKGFkOGUxZGMyODYzZjYzYzM1ZWYzY2VlZjMwNjRkMDg1MWExZDI1ODI", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/5b6ed253c42a69b93e7447fb0874a89ab6bc1cfb", + "sha": "5b6ed253c42a69b93e7447fb0874a89ab6bc1cfb", + "url": "https://api.github.com/repos/rust-lang/rust/commits/5b6ed253c42a69b93e7447fb0874a89ab6bc1cfb" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/adc3f8a44b943463577a5f8870da8fd18b749351", + "sha": "adc3f8a44b943463577a5f8870da8fd18b749351", + "url": "https://api.github.com/repos/rust-lang/rust/commits/adc3f8a44b943463577a5f8870da8fd18b749351" + } + ], + "sha": "ad8e1dc2863f63c35ef3ceef3064d0851a1d2582", + "url": "https://api.github.com/repos/rust-lang/rust/commits/ad8e1dc2863f63c35ef3ceef3064d0851a1d2582" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/5b6ed253c42a69b93e7447fb0874a89ab6bc1cfb/comments", + "commit": { + "author": { + "date": "2023-01-31T22:34:26Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-01-31T22:34:26Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #102513 - RalfJung:no-more-unaligned-reference, r=cjgillot,scottmcm\n\nmake unaligned_reference a hard error\n\nThe `unaligned_references` lint has been warn-by-default since Rust 1.53 (https://github.com/rust-lang/rust/pull/82525) and deny-by-default with mention in cargo future-incompat reports since Rust 1.62 (https://github.com/rust-lang/rust/pull/95372). Current nightly will become Rust 1.66, so (unless major surprises show up with crater) I think it is time we make this a hard error, and close this old soundness gap in the language.\n\nEDIT: Turns out this will only land for Rust 1.67, so there is another 6 weeks of time here for crates to adjust.\n\nFixes https://github.com/rust-lang/rust/issues/82523.", + "tree": { + "sha": "ba7e23c105713658431c3101d22977d8282e397f", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/ba7e23c105713658431c3101d22977d8282e397f" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/5b6ed253c42a69b93e7447fb0874a89ab6bc1cfb", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/5b6ed253c42a69b93e7447fb0874a89ab6bc1cfb", + "node_id": "C_kwDOAAsO6NoAKDViNmVkMjUzYzQyYTY5YjkzZTc0NDdmYjA4NzRhODlhYjZiYzFjZmI", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/dc1d9d50fba2f6a1ccab8748a0050cde38253f60", + "sha": "dc1d9d50fba2f6a1ccab8748a0050cde38253f60", + "url": "https://api.github.com/repos/rust-lang/rust/commits/dc1d9d50fba2f6a1ccab8748a0050cde38253f60" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/dfc4a7b2d02528f246e455f587605cce224bb99c", + "sha": "dfc4a7b2d02528f246e455f587605cce224bb99c", + "url": "https://api.github.com/repos/rust-lang/rust/commits/dfc4a7b2d02528f246e455f587605cce224bb99c" + } + ], + "sha": "5b6ed253c42a69b93e7447fb0874a89ab6bc1cfb", + "url": "https://api.github.com/repos/rust-lang/rust/commits/5b6ed253c42a69b93e7447fb0874a89ab6bc1cfb" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/dc1d9d50fba2f6a1ccab8748a0050cde38253f60/comments", + "commit": { + "author": { + "date": "2023-01-31T19:24:29Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-01-31T19:24:29Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107297 - Mark-Simulacrum:bump-bootstrap, r=pietroalbini\n\nBump bootstrap compiler to 1.68\n\nThis also changes our stage0.json to include the rustc component for the rustfmt pinned nightly toolchain, which is currently necessary due to rustfmt dynamically linking to that toolchain's librustc_driver and libstd.\n\nr? `@pietroalbini`", + "tree": { + "sha": "1497db582bb148e212d04fb4acc229d85aff2617", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/1497db582bb148e212d04fb4acc229d85aff2617" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/dc1d9d50fba2f6a1ccab8748a0050cde38253f60", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/dc1d9d50fba2f6a1ccab8748a0050cde38253f60", + "node_id": "C_kwDOAAsO6NoAKGRjMWQ5ZDUwZmJhMmY2YTFjY2FiODc0OGEwMDUwY2RlMzgyNTNmNjA", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/f361413cbf44ce2f144df59fc440cd484af4a56e", + "sha": "f361413cbf44ce2f144df59fc440cd484af4a56e", + "url": "https://api.github.com/repos/rust-lang/rust/commits/f361413cbf44ce2f144df59fc440cd484af4a56e" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/652f79e83543eab07c33840748cf5df37b42ac66", + "sha": "652f79e83543eab07c33840748cf5df37b42ac66", + "url": "https://api.github.com/repos/rust-lang/rust/commits/652f79e83543eab07c33840748cf5df37b42ac66" + } + ], + "sha": "dc1d9d50fba2f6a1ccab8748a0050cde38253f60", + "url": "https://api.github.com/repos/rust-lang/rust/commits/dc1d9d50fba2f6a1ccab8748a0050cde38253f60" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/f361413cbf44ce2f144df59fc440cd484af4a56e/comments", + "commit": { + "author": { + "date": "2023-01-31T13:53:40Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-01-31T13:53:40Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #106399 - estebank:type-err-span-label, r=nagisa\n\nModify primary span label for E0308\n\nLooking at the reactions to https://hachyderm.io/`@ekuber/109622160673605438,` a lot of people seem to have trouble understanding the current output, where the primary span label on type errors talks about the specific types that diverged, but these can be deeply nested type parameters. Because of that we could see \"expected i32, found u32\" in the label while the note said \"expected Vec, found Vec\". This understandably confuses people. I believe that once people learn to read these errors it starts to make more sense, but this PR changes the output to be more in line with what people might expect, without sacrificing terseness.\n\nFix #68220.", + "tree": { + "sha": "cecf91d94ee20df2d6bec7c88796b90fa34f9887", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/cecf91d94ee20df2d6bec7c88796b90fa34f9887" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/f361413cbf44ce2f144df59fc440cd484af4a56e", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/f361413cbf44ce2f144df59fc440cd484af4a56e", + "node_id": "C_kwDOAAsO6NoAKGYzNjE0MTNjYmY0NGNlMmYxNDRkZjU5ZmM0NDBjZDQ4NGFmNGE1NmU", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/a64ef7d07d0411315be85a646586cb85eeb9c136", + "sha": "a64ef7d07d0411315be85a646586cb85eeb9c136", + "url": "https://api.github.com/repos/rust-lang/rust/commits/a64ef7d07d0411315be85a646586cb85eeb9c136" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/449dfc64f0792f2320ef68bc08f238281199f53d", + "sha": "449dfc64f0792f2320ef68bc08f238281199f53d", + "url": "https://api.github.com/repos/rust-lang/rust/commits/449dfc64f0792f2320ef68bc08f238281199f53d" + } + ], + "sha": "f361413cbf44ce2f144df59fc440cd484af4a56e", + "url": "https://api.github.com/repos/rust-lang/rust/commits/f361413cbf44ce2f144df59fc440cd484af4a56e" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/a64ef7d07d0411315be85a646586cb85eeb9c136/comments", + "commit": { + "author": { + "date": "2023-01-31T10:20:58Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-01-31T10:20:58Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #100754 - davidtwco:translation-incremental, r=compiler-errors\n\nincremental: migrate diagnostics\n\n- Apply the diagnostic migration lints to more functions on `Session`, namely: `span_warn`, `span_warn_with_code`, `warn` `note_without_error`, `span_note_without_error`, `struct_note_without_error`.\n- Add impls of `IntoDiagnosticArg` for `std::io::Error`, `std::path::Path` and `std::path::PathBuf`.\n- Migrate the `rustc_incremental` crate's diagnostics to translatable diagnostic structs.\n\nr? `@compiler-errors`\ncc #100717", + "tree": { + "sha": "e4b006e2f97095541ee5ff8b1beab16675e5eb86", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/e4b006e2f97095541ee5ff8b1beab16675e5eb86" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/a64ef7d07d0411315be85a646586cb85eeb9c136", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/a64ef7d07d0411315be85a646586cb85eeb9c136", + "node_id": "C_kwDOAAsO6NoAKGE2NGVmN2QwN2QwNDExMzE1YmU4NWE2NDY1ODZjYjg1ZWViOWMxMzY", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/7c4a9a971ca6962533bed01ffbd0c1f6b5250abc", + "sha": "7c4a9a971ca6962533bed01ffbd0c1f6b5250abc", + "url": "https://api.github.com/repos/rust-lang/rust/commits/7c4a9a971ca6962533bed01ffbd0c1f6b5250abc" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/2ff46641a92c27a32db3e0dc94ae86295e6c3277", + "sha": "2ff46641a92c27a32db3e0dc94ae86295e6c3277", + "url": "https://api.github.com/repos/rust-lang/rust/commits/2ff46641a92c27a32db3e0dc94ae86295e6c3277" + } + ], + "sha": "a64ef7d07d0411315be85a646586cb85eeb9c136", + "url": "https://api.github.com/repos/rust-lang/rust/commits/a64ef7d07d0411315be85a646586cb85eeb9c136" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/7c4a9a971ca6962533bed01ffbd0c1f6b5250abc/comments", + "commit": { + "author": { + "date": "2023-01-31T06:25:30Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "comment_count": 0, + "committer": { + "date": "2023-01-31T06:25:30Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "message": "Auto merge of #107498 - JohnTitor:rollup-2i6g4uk, r=JohnTitor\n\nRollup of 8 pull requests\n\nSuccessful merges:\n\n - #107245 (Implement unsizing in the new trait solver)\n - #107445 (Remove `GenFuture` from core)\n - #107473 (Update books)\n - #107476 (rustdoc: remove unnecessary wrapper `div.item-decl` from HTML)\n - #107477 (Migrate last part of CSS themes to CSS variables)\n - #107479 (Use `ObligationCtxt::new_in_snapshot` in `satisfied_from_param_env`)\n - #107482 (rustdoc: remove meta keywords from HTML)\n - #107494 (fix link in std::path::Path::display())\n\nFailed merges:\n\nr? `@ghost`\n`@rustbot` modify labels: rollup", + "tree": { + "sha": "904e6bf143781822be126e176f256545da3767dd", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/904e6bf143781822be126e176f256545da3767dd" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/7c4a9a971ca6962533bed01ffbd0c1f6b5250abc", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/3372342?v=4", + "events_url": "https://api.github.com/users/bors/events{/privacy}", + "followers_url": "https://api.github.com/users/bors/followers", + "following_url": "https://api.github.com/users/bors/following{/other_user}", + "gists_url": "https://api.github.com/users/bors/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bors", + "id": 3372342, + "login": "bors", + "node_id": "MDQ6VXNlcjMzNzIzNDI=", + "organizations_url": "https://api.github.com/users/bors/orgs", + "received_events_url": "https://api.github.com/users/bors/received_events", + "repos_url": "https://api.github.com/users/bors/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bors/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/7c4a9a971ca6962533bed01ffbd0c1f6b5250abc", + "node_id": "C_kwDOAAsO6NoAKDdjNGE5YTk3MWNhNjk2MjUzM2JlZDAxZmZiZDBjMWY2YjUyNTBhYmM", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/dc3e59cb3fe05ebd752d3a2269f501c00327be22", + "sha": "dc3e59cb3fe05ebd752d3a2269f501c00327be22", + "url": "https://api.github.com/repos/rust-lang/rust/commits/dc3e59cb3fe05ebd752d3a2269f501c00327be22" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/150340bafdcd48becbe612a0d4d5631efe23621c", + "sha": "150340bafdcd48becbe612a0d4d5631efe23621c", + "url": "https://api.github.com/repos/rust-lang/rust/commits/150340bafdcd48becbe612a0d4d5631efe23621c" + } + ], + "sha": "7c4a9a971ca6962533bed01ffbd0c1f6b5250abc", + "url": "https://api.github.com/repos/rust-lang/rust/commits/7c4a9a971ca6962533bed01ffbd0c1f6b5250abc" + } + ] +} diff --git a/tests/github_client/create_commit/00-GET-repos_ehuss_rust.json b/tests/github_client/create_commit/00-GET-repos_ehuss_rust.json new file mode 100644 index 00000000..2e719ca7 --- /dev/null +++ b/tests/github_client/create_commit/00-GET-repos_ehuss_rust.json @@ -0,0 +1,365 @@ +{ + "kind": "Request", + "method": "GET", + "path": "/repos/ehuss/rust", + "query": null, + "request_body": "", + "response_code": 200, + "response_body": { + "allow_auto_merge": false, + "allow_forking": true, + "allow_merge_commit": true, + "allow_rebase_merge": true, + "allow_squash_merge": true, + "allow_update_branch": false, + "archive_url": "https://api.github.com/repos/ehuss/rust/{archive_format}{/ref}", + "archived": false, + "assignees_url": "https://api.github.com/repos/ehuss/rust/assignees{/user}", + "blobs_url": "https://api.github.com/repos/ehuss/rust/git/blobs{/sha}", + "branches_url": "https://api.github.com/repos/ehuss/rust/branches{/branch}", + "clone_url": "https://github.com/ehuss/rust.git", + "collaborators_url": "https://api.github.com/repos/ehuss/rust/collaborators{/collaborator}", + "comments_url": "https://api.github.com/repos/ehuss/rust/comments{/number}", + "commits_url": "https://api.github.com/repos/ehuss/rust/commits{/sha}", + "compare_url": "https://api.github.com/repos/ehuss/rust/compare/{base}...{head}", + "contents_url": "https://api.github.com/repos/ehuss/rust/contents/{+path}", + "contributors_url": "https://api.github.com/repos/ehuss/rust/contributors", + "created_at": "2018-01-14T20:35:48Z", + "default_branch": "master", + "delete_branch_on_merge": false, + "deployments_url": "https://api.github.com/repos/ehuss/rust/deployments", + "description": "A safe, concurrent, practical language.", + "disabled": false, + "downloads_url": "https://api.github.com/repos/ehuss/rust/downloads", + "events_url": "https://api.github.com/repos/ehuss/rust/events", + "fork": true, + "forks": 0, + "forks_count": 0, + "forks_url": "https://api.github.com/repos/ehuss/rust/forks", + "full_name": "ehuss/rust", + "git_commits_url": "https://api.github.com/repos/ehuss/rust/git/commits{/sha}", + "git_refs_url": "https://api.github.com/repos/ehuss/rust/git/refs{/sha}", + "git_tags_url": "https://api.github.com/repos/ehuss/rust/git/tags{/sha}", + "git_url": "git://github.com/ehuss/rust.git", + "has_discussions": false, + "has_downloads": true, + "has_issues": false, + "has_pages": false, + "has_projects": true, + "has_wiki": false, + "homepage": "https://www.rust-lang.org", + "hooks_url": "https://api.github.com/repos/ehuss/rust/hooks", + "html_url": "https://github.com/ehuss/rust", + "id": 117464625, + "is_template": false, + "issue_comment_url": "https://api.github.com/repos/ehuss/rust/issues/comments{/number}", + "issue_events_url": "https://api.github.com/repos/ehuss/rust/issues/events{/number}", + "issues_url": "https://api.github.com/repos/ehuss/rust/issues{/number}", + "keys_url": "https://api.github.com/repos/ehuss/rust/keys{/key_id}", + "labels_url": "https://api.github.com/repos/ehuss/rust/labels{/name}", + "language": "Rust", + "languages_url": "https://api.github.com/repos/ehuss/rust/languages", + "license": { + "key": "other", + "name": "Other", + "node_id": "MDc6TGljZW5zZTA=", + "spdx_id": "NOASSERTION", + "url": null + }, + "merge_commit_message": "PR_TITLE", + "merge_commit_title": "MERGE_MESSAGE", + "merges_url": "https://api.github.com/repos/ehuss/rust/merges", + "milestones_url": "https://api.github.com/repos/ehuss/rust/milestones{/number}", + "mirror_url": null, + "name": "rust", + "network_count": 10326, + "node_id": "MDEwOlJlcG9zaXRvcnkxMTc0NjQ2MjU=", + "notifications_url": "https://api.github.com/repos/ehuss/rust/notifications{?since,all,participating}", + "open_issues": 0, + "open_issues_count": 0, + "owner": { + "avatar_url": "https://avatars.githubusercontent.com/u/43198?v=4", + "events_url": "https://api.github.com/users/ehuss/events{/privacy}", + "followers_url": "https://api.github.com/users/ehuss/followers", + "following_url": "https://api.github.com/users/ehuss/following{/other_user}", + "gists_url": "https://api.github.com/users/ehuss/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/ehuss", + "id": 43198, + "login": "ehuss", + "node_id": "MDQ6VXNlcjQzMTk4", + "organizations_url": "https://api.github.com/users/ehuss/orgs", + "received_events_url": "https://api.github.com/users/ehuss/received_events", + "repos_url": "https://api.github.com/users/ehuss/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/ehuss/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ehuss/subscriptions", + "type": "User", + "url": "https://api.github.com/users/ehuss" + }, + "parent": { + "allow_forking": true, + "archive_url": "https://api.github.com/repos/rust-lang/rust/{archive_format}{/ref}", + "archived": false, + "assignees_url": "https://api.github.com/repos/rust-lang/rust/assignees{/user}", + "blobs_url": "https://api.github.com/repos/rust-lang/rust/git/blobs{/sha}", + "branches_url": "https://api.github.com/repos/rust-lang/rust/branches{/branch}", + "clone_url": "https://github.com/rust-lang/rust.git", + "collaborators_url": "https://api.github.com/repos/rust-lang/rust/collaborators{/collaborator}", + "comments_url": "https://api.github.com/repos/rust-lang/rust/comments{/number}", + "commits_url": "https://api.github.com/repos/rust-lang/rust/commits{/sha}", + "compare_url": "https://api.github.com/repos/rust-lang/rust/compare/{base}...{head}", + "contents_url": "https://api.github.com/repos/rust-lang/rust/contents/{+path}", + "contributors_url": "https://api.github.com/repos/rust-lang/rust/contributors", + "created_at": "2010-06-16T20:39:03Z", + "default_branch": "master", + "deployments_url": "https://api.github.com/repos/rust-lang/rust/deployments", + "description": "Empowering everyone to build reliable and efficient software.", + "disabled": false, + "downloads_url": "https://api.github.com/repos/rust-lang/rust/downloads", + "events_url": "https://api.github.com/repos/rust-lang/rust/events", + "fork": false, + "forks": 10326, + "forks_count": 10326, + "forks_url": "https://api.github.com/repos/rust-lang/rust/forks", + "full_name": "rust-lang/rust", + "git_commits_url": "https://api.github.com/repos/rust-lang/rust/git/commits{/sha}", + "git_refs_url": "https://api.github.com/repos/rust-lang/rust/git/refs{/sha}", + "git_tags_url": "https://api.github.com/repos/rust-lang/rust/git/tags{/sha}", + "git_url": "git://github.com/rust-lang/rust.git", + "has_discussions": false, + "has_downloads": true, + "has_issues": true, + "has_pages": false, + "has_projects": true, + "has_wiki": false, + "homepage": "https://www.rust-lang.org", + "hooks_url": "https://api.github.com/repos/rust-lang/rust/hooks", + "html_url": "https://github.com/rust-lang/rust", + "id": 724712, + "is_template": false, + "issue_comment_url": "https://api.github.com/repos/rust-lang/rust/issues/comments{/number}", + "issue_events_url": "https://api.github.com/repos/rust-lang/rust/issues/events{/number}", + "issues_url": "https://api.github.com/repos/rust-lang/rust/issues{/number}", + "keys_url": "https://api.github.com/repos/rust-lang/rust/keys{/key_id}", + "labels_url": "https://api.github.com/repos/rust-lang/rust/labels{/name}", + "language": "Rust", + "languages_url": "https://api.github.com/repos/rust-lang/rust/languages", + "license": { + "key": "other", + "name": "Other", + "node_id": "MDc6TGljZW5zZTA=", + "spdx_id": "NOASSERTION", + "url": null + }, + "merges_url": "https://api.github.com/repos/rust-lang/rust/merges", + "milestones_url": "https://api.github.com/repos/rust-lang/rust/milestones{/number}", + "mirror_url": null, + "name": "rust", + "node_id": "MDEwOlJlcG9zaXRvcnk3MjQ3MTI=", + "notifications_url": "https://api.github.com/repos/rust-lang/rust/notifications{?since,all,participating}", + "open_issues": 9513, + "open_issues_count": 9513, + "owner": { + "avatar_url": "https://avatars.githubusercontent.com/u/5430905?v=4", + "events_url": "https://api.github.com/users/rust-lang/events{/privacy}", + "followers_url": "https://api.github.com/users/rust-lang/followers", + "following_url": "https://api.github.com/users/rust-lang/following{/other_user}", + "gists_url": "https://api.github.com/users/rust-lang/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/rust-lang", + "id": 5430905, + "login": "rust-lang", + "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MzA5MDU=", + "organizations_url": "https://api.github.com/users/rust-lang/orgs", + "received_events_url": "https://api.github.com/users/rust-lang/received_events", + "repos_url": "https://api.github.com/users/rust-lang/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/rust-lang/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rust-lang/subscriptions", + "type": "Organization", + "url": "https://api.github.com/users/rust-lang" + }, + "private": false, + "pulls_url": "https://api.github.com/repos/rust-lang/rust/pulls{/number}", + "pushed_at": "2023-02-05T18:16:26Z", + "releases_url": "https://api.github.com/repos/rust-lang/rust/releases{/id}", + "size": 1066392, + "ssh_url": "git@github.com:rust-lang/rust.git", + "stargazers_count": 77401, + "stargazers_url": "https://api.github.com/repos/rust-lang/rust/stargazers", + "statuses_url": "https://api.github.com/repos/rust-lang/rust/statuses/{sha}", + "subscribers_url": "https://api.github.com/repos/rust-lang/rust/subscribers", + "subscription_url": "https://api.github.com/repos/rust-lang/rust/subscription", + "svn_url": "https://github.com/rust-lang/rust", + "tags_url": "https://api.github.com/repos/rust-lang/rust/tags", + "teams_url": "https://api.github.com/repos/rust-lang/rust/teams", + "topics": [ + "compiler", + "hacktoberfest", + "language", + "rust" + ], + "trees_url": "https://api.github.com/repos/rust-lang/rust/git/trees{/sha}", + "updated_at": "2023-02-05T17:54:34Z", + "url": "https://api.github.com/repos/rust-lang/rust", + "visibility": "public", + "watchers": 77401, + "watchers_count": 77401, + "web_commit_signoff_required": false + }, + "permissions": { + "admin": true, + "maintain": true, + "pull": true, + "push": true, + "triage": true + }, + "private": false, + "pulls_url": "https://api.github.com/repos/ehuss/rust/pulls{/number}", + "pushed_at": "2023-02-05T19:01:28Z", + "releases_url": "https://api.github.com/repos/ehuss/rust/releases{/id}", + "security_and_analysis": { + "secret_scanning": { + "status": "disabled" + }, + "secret_scanning_push_protection": { + "status": "disabled" + } + }, + "size": 1054343, + "source": { + "allow_forking": true, + "archive_url": "https://api.github.com/repos/rust-lang/rust/{archive_format}{/ref}", + "archived": false, + "assignees_url": "https://api.github.com/repos/rust-lang/rust/assignees{/user}", + "blobs_url": "https://api.github.com/repos/rust-lang/rust/git/blobs{/sha}", + "branches_url": "https://api.github.com/repos/rust-lang/rust/branches{/branch}", + "clone_url": "https://github.com/rust-lang/rust.git", + "collaborators_url": "https://api.github.com/repos/rust-lang/rust/collaborators{/collaborator}", + "comments_url": "https://api.github.com/repos/rust-lang/rust/comments{/number}", + "commits_url": "https://api.github.com/repos/rust-lang/rust/commits{/sha}", + "compare_url": "https://api.github.com/repos/rust-lang/rust/compare/{base}...{head}", + "contents_url": "https://api.github.com/repos/rust-lang/rust/contents/{+path}", + "contributors_url": "https://api.github.com/repos/rust-lang/rust/contributors", + "created_at": "2010-06-16T20:39:03Z", + "default_branch": "master", + "deployments_url": "https://api.github.com/repos/rust-lang/rust/deployments", + "description": "Empowering everyone to build reliable and efficient software.", + "disabled": false, + "downloads_url": "https://api.github.com/repos/rust-lang/rust/downloads", + "events_url": "https://api.github.com/repos/rust-lang/rust/events", + "fork": false, + "forks": 10326, + "forks_count": 10326, + "forks_url": "https://api.github.com/repos/rust-lang/rust/forks", + "full_name": "rust-lang/rust", + "git_commits_url": "https://api.github.com/repos/rust-lang/rust/git/commits{/sha}", + "git_refs_url": "https://api.github.com/repos/rust-lang/rust/git/refs{/sha}", + "git_tags_url": "https://api.github.com/repos/rust-lang/rust/git/tags{/sha}", + "git_url": "git://github.com/rust-lang/rust.git", + "has_discussions": false, + "has_downloads": true, + "has_issues": true, + "has_pages": false, + "has_projects": true, + "has_wiki": false, + "homepage": "https://www.rust-lang.org", + "hooks_url": "https://api.github.com/repos/rust-lang/rust/hooks", + "html_url": "https://github.com/rust-lang/rust", + "id": 724712, + "is_template": false, + "issue_comment_url": "https://api.github.com/repos/rust-lang/rust/issues/comments{/number}", + "issue_events_url": "https://api.github.com/repos/rust-lang/rust/issues/events{/number}", + "issues_url": "https://api.github.com/repos/rust-lang/rust/issues{/number}", + "keys_url": "https://api.github.com/repos/rust-lang/rust/keys{/key_id}", + "labels_url": "https://api.github.com/repos/rust-lang/rust/labels{/name}", + "language": "Rust", + "languages_url": "https://api.github.com/repos/rust-lang/rust/languages", + "license": { + "key": "other", + "name": "Other", + "node_id": "MDc6TGljZW5zZTA=", + "spdx_id": "NOASSERTION", + "url": null + }, + "merges_url": "https://api.github.com/repos/rust-lang/rust/merges", + "milestones_url": "https://api.github.com/repos/rust-lang/rust/milestones{/number}", + "mirror_url": null, + "name": "rust", + "node_id": "MDEwOlJlcG9zaXRvcnk3MjQ3MTI=", + "notifications_url": "https://api.github.com/repos/rust-lang/rust/notifications{?since,all,participating}", + "open_issues": 9513, + "open_issues_count": 9513, + "owner": { + "avatar_url": "https://avatars.githubusercontent.com/u/5430905?v=4", + "events_url": "https://api.github.com/users/rust-lang/events{/privacy}", + "followers_url": "https://api.github.com/users/rust-lang/followers", + "following_url": "https://api.github.com/users/rust-lang/following{/other_user}", + "gists_url": "https://api.github.com/users/rust-lang/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/rust-lang", + "id": 5430905, + "login": "rust-lang", + "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MzA5MDU=", + "organizations_url": "https://api.github.com/users/rust-lang/orgs", + "received_events_url": "https://api.github.com/users/rust-lang/received_events", + "repos_url": "https://api.github.com/users/rust-lang/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/rust-lang/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rust-lang/subscriptions", + "type": "Organization", + "url": "https://api.github.com/users/rust-lang" + }, + "private": false, + "pulls_url": "https://api.github.com/repos/rust-lang/rust/pulls{/number}", + "pushed_at": "2023-02-05T18:16:26Z", + "releases_url": "https://api.github.com/repos/rust-lang/rust/releases{/id}", + "size": 1066392, + "ssh_url": "git@github.com:rust-lang/rust.git", + "stargazers_count": 77401, + "stargazers_url": "https://api.github.com/repos/rust-lang/rust/stargazers", + "statuses_url": "https://api.github.com/repos/rust-lang/rust/statuses/{sha}", + "subscribers_url": "https://api.github.com/repos/rust-lang/rust/subscribers", + "subscription_url": "https://api.github.com/repos/rust-lang/rust/subscription", + "svn_url": "https://github.com/rust-lang/rust", + "tags_url": "https://api.github.com/repos/rust-lang/rust/tags", + "teams_url": "https://api.github.com/repos/rust-lang/rust/teams", + "topics": [ + "compiler", + "hacktoberfest", + "language", + "rust" + ], + "trees_url": "https://api.github.com/repos/rust-lang/rust/git/trees{/sha}", + "updated_at": "2023-02-05T17:54:34Z", + "url": "https://api.github.com/repos/rust-lang/rust", + "visibility": "public", + "watchers": 77401, + "watchers_count": 77401, + "web_commit_signoff_required": false + }, + "squash_merge_commit_message": "COMMIT_MESSAGES", + "squash_merge_commit_title": "COMMIT_OR_PR_TITLE", + "ssh_url": "git@github.com:ehuss/rust.git", + "stargazers_count": 0, + "stargazers_url": "https://api.github.com/repos/ehuss/rust/stargazers", + "statuses_url": "https://api.github.com/repos/ehuss/rust/statuses/{sha}", + "subscribers_count": 0, + "subscribers_url": "https://api.github.com/repos/ehuss/rust/subscribers", + "subscription_url": "https://api.github.com/repos/ehuss/rust/subscription", + "svn_url": "https://github.com/ehuss/rust", + "tags_url": "https://api.github.com/repos/ehuss/rust/tags", + "teams_url": "https://api.github.com/repos/ehuss/rust/teams", + "temp_clone_token": "", + "topics": [], + "trees_url": "https://api.github.com/repos/ehuss/rust/git/trees{/sha}", + "updated_at": "2021-11-03T23:44:04Z", + "url": "https://api.github.com/repos/ehuss/rust", + "use_squash_pr_title_as_default": false, + "visibility": "public", + "watchers": 0, + "watchers_count": 0, + "web_commit_signoff_required": false + } +} diff --git a/tests/github_client/create_commit/01-POST-repos_ehuss_rust_git_commits.json b/tests/github_client/create_commit/01-POST-repos_ehuss_rust_git_commits.json new file mode 100644 index 00000000..08cc813f --- /dev/null +++ b/tests/github_client/create_commit/01-POST-repos_ehuss_rust_git_commits.json @@ -0,0 +1,42 @@ +{ + "kind": "Request", + "method": "POST", + "path": "/repos/ehuss/rust/git/commits", + "query": null, + "request_body": "{\"message\":\"test reference commit\",\"parents\":[\"319b88c463fe6f51bb6badbbd3bb97252a60f3a5\"],\"tree\":\"45aae523b087e418f2778d4557489de38fede6a3\"}", + "response_code": 201, + "response_body": { + "author": { + "date": "2023-02-05T19:08:57Z", + "email": "eric@huss.org", + "name": "Eric Huss" + }, + "committer": { + "date": "2023-02-05T19:08:57Z", + "email": "eric@huss.org", + "name": "Eric Huss" + }, + "html_url": "https://github.com/ehuss/rust/commit/88a426017fa4635ba42203c3b1d1c19f6a028184", + "message": "test reference commit", + "node_id": "C_kwDOBwBeMdoAKDg4YTQyNjAxN2ZhNDYzNWJhNDIyMDNjM2IxZDFjMTlmNmEwMjgxODQ", + "parents": [ + { + "html_url": "https://github.com/ehuss/rust/commit/319b88c463fe6f51bb6badbbd3bb97252a60f3a5", + "sha": "319b88c463fe6f51bb6badbbd3bb97252a60f3a5", + "url": "https://api.github.com/repos/ehuss/rust/git/commits/319b88c463fe6f51bb6badbbd3bb97252a60f3a5" + } + ], + "sha": "88a426017fa4635ba42203c3b1d1c19f6a028184", + "tree": { + "sha": "45aae523b087e418f2778d4557489de38fede6a3", + "url": "https://api.github.com/repos/ehuss/rust/git/trees/45aae523b087e418f2778d4557489de38fede6a3" + }, + "url": "https://api.github.com/repos/ehuss/rust/git/commits/88a426017fa4635ba42203c3b1d1c19f6a028184", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + } +} diff --git a/tests/github_client/get_issues_no_search/00-GET-repos_rust-lang_rust.json b/tests/github_client/get_issues_no_search/00-GET-repos_rust-lang_rust.json new file mode 100644 index 00000000..3589a6e8 --- /dev/null +++ b/tests/github_client/get_issues_no_search/00-GET-repos_rust-lang_rust.json @@ -0,0 +1,160 @@ +{ + "kind": "Request", + "method": "GET", + "path": "/repos/rust-lang/rust", + "query": null, + "request_body": "", + "response_code": 200, + "response_body": { + "allow_auto_merge": false, + "allow_forking": true, + "allow_merge_commit": true, + "allow_rebase_merge": false, + "allow_squash_merge": false, + "allow_update_branch": false, + "archive_url": "https://api.github.com/repos/rust-lang/rust/{archive_format}{/ref}", + "archived": false, + "assignees_url": "https://api.github.com/repos/rust-lang/rust/assignees{/user}", + "blobs_url": "https://api.github.com/repos/rust-lang/rust/git/blobs{/sha}", + "branches_url": "https://api.github.com/repos/rust-lang/rust/branches{/branch}", + "clone_url": "https://github.com/rust-lang/rust.git", + "collaborators_url": "https://api.github.com/repos/rust-lang/rust/collaborators{/collaborator}", + "comments_url": "https://api.github.com/repos/rust-lang/rust/comments{/number}", + "commits_url": "https://api.github.com/repos/rust-lang/rust/commits{/sha}", + "compare_url": "https://api.github.com/repos/rust-lang/rust/compare/{base}...{head}", + "contents_url": "https://api.github.com/repos/rust-lang/rust/contents/{+path}", + "contributors_url": "https://api.github.com/repos/rust-lang/rust/contributors", + "created_at": "2010-06-16T20:39:03Z", + "default_branch": "master", + "delete_branch_on_merge": true, + "deployments_url": "https://api.github.com/repos/rust-lang/rust/deployments", + "description": "Empowering everyone to build reliable and efficient software.", + "disabled": false, + "downloads_url": "https://api.github.com/repos/rust-lang/rust/downloads", + "events_url": "https://api.github.com/repos/rust-lang/rust/events", + "fork": false, + "forks": 10326, + "forks_count": 10326, + "forks_url": "https://api.github.com/repos/rust-lang/rust/forks", + "full_name": "rust-lang/rust", + "git_commits_url": "https://api.github.com/repos/rust-lang/rust/git/commits{/sha}", + "git_refs_url": "https://api.github.com/repos/rust-lang/rust/git/refs{/sha}", + "git_tags_url": "https://api.github.com/repos/rust-lang/rust/git/tags{/sha}", + "git_url": "git://github.com/rust-lang/rust.git", + "has_discussions": false, + "has_downloads": true, + "has_issues": true, + "has_pages": false, + "has_projects": true, + "has_wiki": false, + "homepage": "https://www.rust-lang.org", + "hooks_url": "https://api.github.com/repos/rust-lang/rust/hooks", + "html_url": "https://github.com/rust-lang/rust", + "id": 724712, + "is_template": false, + "issue_comment_url": "https://api.github.com/repos/rust-lang/rust/issues/comments{/number}", + "issue_events_url": "https://api.github.com/repos/rust-lang/rust/issues/events{/number}", + "issues_url": "https://api.github.com/repos/rust-lang/rust/issues{/number}", + "keys_url": "https://api.github.com/repos/rust-lang/rust/keys{/key_id}", + "labels_url": "https://api.github.com/repos/rust-lang/rust/labels{/name}", + "language": "Rust", + "languages_url": "https://api.github.com/repos/rust-lang/rust/languages", + "license": { + "key": "other", + "name": "Other", + "node_id": "MDc6TGljZW5zZTA=", + "spdx_id": "NOASSERTION", + "url": null + }, + "merge_commit_message": "PR_TITLE", + "merge_commit_title": "MERGE_MESSAGE", + "merges_url": "https://api.github.com/repos/rust-lang/rust/merges", + "milestones_url": "https://api.github.com/repos/rust-lang/rust/milestones{/number}", + "mirror_url": null, + "name": "rust", + "network_count": 10326, + "node_id": "MDEwOlJlcG9zaXRvcnk3MjQ3MTI=", + "notifications_url": "https://api.github.com/repos/rust-lang/rust/notifications{?since,all,participating}", + "open_issues": 9513, + "open_issues_count": 9513, + "organization": { + "avatar_url": "https://avatars.githubusercontent.com/u/5430905?v=4", + "events_url": "https://api.github.com/users/rust-lang/events{/privacy}", + "followers_url": "https://api.github.com/users/rust-lang/followers", + "following_url": "https://api.github.com/users/rust-lang/following{/other_user}", + "gists_url": "https://api.github.com/users/rust-lang/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/rust-lang", + "id": 5430905, + "login": "rust-lang", + "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MzA5MDU=", + "organizations_url": "https://api.github.com/users/rust-lang/orgs", + "received_events_url": "https://api.github.com/users/rust-lang/received_events", + "repos_url": "https://api.github.com/users/rust-lang/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/rust-lang/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rust-lang/subscriptions", + "type": "Organization", + "url": "https://api.github.com/users/rust-lang" + }, + "owner": { + "avatar_url": "https://avatars.githubusercontent.com/u/5430905?v=4", + "events_url": "https://api.github.com/users/rust-lang/events{/privacy}", + "followers_url": "https://api.github.com/users/rust-lang/followers", + "following_url": "https://api.github.com/users/rust-lang/following{/other_user}", + "gists_url": "https://api.github.com/users/rust-lang/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/rust-lang", + "id": 5430905, + "login": "rust-lang", + "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MzA5MDU=", + "organizations_url": "https://api.github.com/users/rust-lang/orgs", + "received_events_url": "https://api.github.com/users/rust-lang/received_events", + "repos_url": "https://api.github.com/users/rust-lang/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/rust-lang/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rust-lang/subscriptions", + "type": "Organization", + "url": "https://api.github.com/users/rust-lang" + }, + "permissions": { + "admin": false, + "maintain": false, + "pull": true, + "push": true, + "triage": true + }, + "private": false, + "pulls_url": "https://api.github.com/repos/rust-lang/rust/pulls{/number}", + "pushed_at": "2023-02-05T18:16:26Z", + "releases_url": "https://api.github.com/repos/rust-lang/rust/releases{/id}", + "size": 1066392, + "squash_merge_commit_message": "COMMIT_MESSAGES", + "squash_merge_commit_title": "COMMIT_OR_PR_TITLE", + "ssh_url": "git@github.com:rust-lang/rust.git", + "stargazers_count": 77402, + "stargazers_url": "https://api.github.com/repos/rust-lang/rust/stargazers", + "statuses_url": "https://api.github.com/repos/rust-lang/rust/statuses/{sha}", + "subscribers_count": 1487, + "subscribers_url": "https://api.github.com/repos/rust-lang/rust/subscribers", + "subscription_url": "https://api.github.com/repos/rust-lang/rust/subscription", + "svn_url": "https://github.com/rust-lang/rust", + "tags_url": "https://api.github.com/repos/rust-lang/rust/tags", + "teams_url": "https://api.github.com/repos/rust-lang/rust/teams", + "temp_clone_token": "", + "topics": [ + "compiler", + "hacktoberfest", + "language", + "rust" + ], + "trees_url": "https://api.github.com/repos/rust-lang/rust/git/trees{/sha}", + "updated_at": "2023-02-05T19:09:47Z", + "url": "https://api.github.com/repos/rust-lang/rust", + "use_squash_pr_title_as_default": false, + "visibility": "public", + "watchers": 77402, + "watchers_count": 77402, + "web_commit_signoff_required": false + } +} diff --git a/tests/github_client/get_issues_no_search/01-GET-repos_rust-lang_rust_issues.json b/tests/github_client/get_issues_no_search/01-GET-repos_rust-lang_rust_issues.json new file mode 100644 index 00000000..d0a8d7d1 --- /dev/null +++ b/tests/github_client/get_issues_no_search/01-GET-repos_rust-lang_rust_issues.json @@ -0,0 +1,431 @@ +{ + "kind": "Request", + "method": "GET", + "path": "/repos/rust-lang/rust/issues", + "query": "labels=A-coherence&filter=all&sort=created&direction=asc&per_page=100", + "request_body": "", + "response_code": 200, + "response_body": [ + { + "active_lock_reason": null, + "assignee": { + "avatar_url": "https://avatars.githubusercontent.com/u/16256974?v=4", + "events_url": "https://api.github.com/users/atsuzaki/events{/privacy}", + "followers_url": "https://api.github.com/users/atsuzaki/followers", + "following_url": "https://api.github.com/users/atsuzaki/following{/other_user}", + "gists_url": "https://api.github.com/users/atsuzaki/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/atsuzaki", + "id": 16256974, + "login": "atsuzaki", + "node_id": "MDQ6VXNlcjE2MjU2OTc0", + "organizations_url": "https://api.github.com/users/atsuzaki/orgs", + "received_events_url": "https://api.github.com/users/atsuzaki/received_events", + "repos_url": "https://api.github.com/users/atsuzaki/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/atsuzaki/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/atsuzaki/subscriptions", + "type": "User", + "url": "https://api.github.com/users/atsuzaki" + }, + "assignees": [ + { + "avatar_url": "https://avatars.githubusercontent.com/u/16256974?v=4", + "events_url": "https://api.github.com/users/atsuzaki/events{/privacy}", + "followers_url": "https://api.github.com/users/atsuzaki/followers", + "following_url": "https://api.github.com/users/atsuzaki/following{/other_user}", + "gists_url": "https://api.github.com/users/atsuzaki/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/atsuzaki", + "id": 16256974, + "login": "atsuzaki", + "node_id": "MDQ6VXNlcjE2MjU2OTc0", + "organizations_url": "https://api.github.com/users/atsuzaki/orgs", + "received_events_url": "https://api.github.com/users/atsuzaki/received_events", + "repos_url": "https://api.github.com/users/atsuzaki/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/atsuzaki/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/atsuzaki/subscriptions", + "type": "User", + "url": "https://api.github.com/users/atsuzaki" + } + ], + "author_association": "MEMBER", + "body": "We consider projections to be foreign types during orphan check\n\nhttps://github.com/rust-lang/rust/blob/ceeb5ade201e4181c6d5df2ba96ae5fb2193aadc/compiler/rustc_trait_selection/src/traits/coherence.rs#L731\n\nbut do not consider them to be parameters when checking for uncovered types https://github.com/rust-lang/rust/blob/ceeb5ade201e4181c6d5df2ba96ae5fb2193aadc/compiler/rustc_trait_selection/src/traits/coherence.rs#L621\n\nThis is more obvious after #99552\n\nthis means that the following impl passes the orphan check even though it shouldn't\n```rust\n// crate a\npub trait Foreign {\n type Assoc;\n}\n\n// crate b\nuse a::Foreign;\n\ntrait Id {\n type Assoc;\n}\n\nimpl Id for T {\n type Assoc = T;\n}\n\npub struct B;\nimpl Foreign for ::Assoc {\n type Assoc = usize;\n}\n```\nThe impl in `b` overlaps with an impl `impl Foreign for LocalTy` in another crate `c` which passes the orphan check.\n\nWhile I wasn't able to cause runtime UB with this, I was able to get an ICE during `codegen_fulfill_obligation`: https://github.com/lcnr/orphan-check-ub\n\ncc @rust-lang/types \n\n\n\n\n\n\n\n\n", + "closed_at": null, + "comments": 5, + "comments_url": "https://api.github.com/repos/rust-lang/rust/issues/99554/comments", + "created_at": "2022-07-21T10:56:00Z", + "events_url": "https://api.github.com/repos/rust-lang/rust/issues/99554/events", + "html_url": "https://github.com/rust-lang/rust/issues/99554", + "id": 1313070635, + "labels": [ + { + "color": "f7e101", + "default": false, + "description": "Area: Trait system", + "id": 13836860, + "name": "A-traits", + "node_id": "MDU6TGFiZWwxMzgzNjg2MA==", + "url": "https://api.github.com/repos/rust-lang/rust/labels/A-traits" + }, + { + "color": "02E10C", + "default": false, + "description": "Call for participation: This issue has a mentor. Use RustcContributor::new on Zulip for discussion.", + "id": 67766349, + "name": "E-mentor", + "node_id": "MDU6TGFiZWw2Nzc2NjM0OQ==", + "url": "https://api.github.com/repos/rust-lang/rust/labels/E-mentor" + }, + { + "color": "f7e101", + "default": false, + "description": "Area: Associated items such as associated types and consts.", + "id": 149689562, + "name": "A-associated-items", + "node_id": "MDU6TGFiZWwxNDk2ODk1NjI=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/A-associated-items" + }, + { + "color": "eb6420", + "default": false, + "description": "High priority", + "id": 203429200, + "name": "P-high", + "node_id": "MDU6TGFiZWwyMDM0MjkyMDA=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/P-high" + }, + { + "color": "e11d21", + "default": false, + "description": "Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness", + "id": 267612997, + "name": "I-unsound", + "node_id": "MDU6TGFiZWwyNjc2MTI5OTc=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/I-unsound" + }, + { + "color": "02e10c", + "default": false, + "description": "Call for participation: Experience needed to fix: Medium / intermediate", + "id": 419557634, + "name": "E-medium", + "node_id": "MDU6TGFiZWw0MTk1NTc2MzQ=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/E-medium" + }, + { + "color": "f5f1fd", + "default": false, + "description": "Category: This is a bug.", + "id": 650731663, + "name": "C-bug", + "node_id": "MDU6TGFiZWw2NTA3MzE2NjM=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/C-bug" + }, + { + "color": "bfd4f2", + "default": false, + "description": "Relevant to the types team, which will review and decide on the PR/issue.", + "id": 4172483496, + "name": "T-types", + "node_id": "LA_kwDOAAsO6M74swuo", + "url": "https://api.github.com/repos/rust-lang/rust/labels/T-types" + }, + { + "color": "f7e101", + "default": false, + "description": "Area: Coherence", + "id": 4917350639, + "name": "A-coherence", + "node_id": "LA_kwDOAAsO6M8AAAABJRjQ7w", + "url": "https://api.github.com/repos/rust-lang/rust/labels/A-coherence" + } + ], + "labels_url": "https://api.github.com/repos/rust-lang/rust/issues/99554/labels{/name}", + "locked": false, + "milestone": null, + "node_id": "I_kwDOAAsO6M5OQ94r", + "number": 99554, + "performed_via_github_app": null, + "reactions": { + "+1": 0, + "-1": 0, + "confused": 0, + "eyes": 0, + "heart": 0, + "hooray": 0, + "laugh": 0, + "rocket": 0, + "total_count": 0, + "url": "https://api.github.com/repos/rust-lang/rust/issues/99554/reactions" + }, + "repository_url": "https://api.github.com/repos/rust-lang/rust", + "state": "open", + "state_reason": null, + "timeline_url": "https://api.github.com/repos/rust-lang/rust/issues/99554/timeline", + "title": "orphan check incorrectly handles projections", + "updated_at": "2023-01-27T17:08:45Z", + "url": "https://api.github.com/repos/rust-lang/rust/issues/99554", + "user": { + "avatar_url": "https://avatars.githubusercontent.com/u/29864074?v=4", + "events_url": "https://api.github.com/users/lcnr/events{/privacy}", + "followers_url": "https://api.github.com/users/lcnr/followers", + "following_url": "https://api.github.com/users/lcnr/following{/other_user}", + "gists_url": "https://api.github.com/users/lcnr/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/lcnr", + "id": 29864074, + "login": "lcnr", + "node_id": "MDQ6VXNlcjI5ODY0MDc0", + "organizations_url": "https://api.github.com/users/lcnr/orgs", + "received_events_url": "https://api.github.com/users/lcnr/received_events", + "repos_url": "https://api.github.com/users/lcnr/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/lcnr/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/lcnr/subscriptions", + "type": "User", + "url": "https://api.github.com/users/lcnr" + } + }, + { + "active_lock_reason": null, + "assignee": null, + "assignees": [], + "author_association": "MEMBER", + "body": "which is unsound during coherence, as coherence requires completeness\r\n```rust\r\n#![feature(specialization)]\r\n\r\ntrait Default {\r\n type Id;\r\n}\r\n\r\nimpl Default for T {\r\n default type Id = T;\r\n}\r\n\r\ntrait Overlap {\r\n type Assoc;\r\n}\r\n\r\nimpl Overlap for u32 {\r\n type Assoc = usize;\r\n}\r\n\r\nimpl Overlap for ::Id {\r\n type Assoc = Box;\r\n}\r\n```\r\n\r\nhttps://github.com/rust-lang/rust/blob/03770f0e2b60c02db8fcf52fed5fb36aac70cedc/compiler/rustc_trait_selection/src/traits/project.rs#L1526", + "closed_at": null, + "comments": 0, + "comments_url": "https://api.github.com/repos/rust-lang/rust/issues/105782/comments", + "created_at": "2022-12-16T15:11:15Z", + "events_url": "https://api.github.com/repos/rust-lang/rust/issues/105782/events", + "html_url": "https://github.com/rust-lang/rust/issues/105782", + "id": 1500394507, + "labels": [ + { + "color": "f7e101", + "default": false, + "description": "Area: Trait system", + "id": 13836860, + "name": "A-traits", + "node_id": "MDU6TGFiZWwxMzgzNjg2MA==", + "url": "https://api.github.com/repos/rust-lang/rust/labels/A-traits" + }, + { + "color": "e11d21", + "default": false, + "description": "Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness", + "id": 267612997, + "name": "I-unsound", + "node_id": "MDU6TGFiZWwyNjc2MTI5OTc=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/I-unsound" + }, + { + "color": "f7e101", + "default": false, + "description": "Area: Trait impl specialization", + "id": 347795552, + "name": "A-specialization", + "node_id": "MDU6TGFiZWwzNDc3OTU1NTI=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/A-specialization" + }, + { + "color": "f5f1fd", + "default": false, + "description": "Category: This is a bug.", + "id": 650731663, + "name": "C-bug", + "node_id": "MDU6TGFiZWw2NTA3MzE2NjM=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/C-bug" + }, + { + "color": "76dcde", + "default": false, + "description": "This issue requires a nightly compiler in some way.", + "id": 1472563007, + "name": "requires-nightly", + "node_id": "MDU6TGFiZWwxNDcyNTYzMDA3", + "url": "https://api.github.com/repos/rust-lang/rust/labels/requires-nightly" + }, + { + "color": "f9c0cc", + "default": false, + "description": "`#![feature(specialization)]`", + "id": 1472579062, + "name": "F-specialization", + "node_id": "MDU6TGFiZWwxNDcyNTc5MDYy", + "url": "https://api.github.com/repos/rust-lang/rust/labels/F-specialization" + }, + { + "color": "f7e101", + "default": false, + "description": "Area: Coherence", + "id": 4917350639, + "name": "A-coherence", + "node_id": "LA_kwDOAAsO6M8AAAABJRjQ7w", + "url": "https://api.github.com/repos/rust-lang/rust/labels/A-coherence" + } + ], + "labels_url": "https://api.github.com/repos/rust-lang/rust/issues/105782/labels{/name}", + "locked": false, + "milestone": null, + "node_id": "I_kwDOAAsO6M5ZbjQL", + "number": 105782, + "performed_via_github_app": null, + "reactions": { + "+1": 0, + "-1": 0, + "confused": 0, + "eyes": 0, + "heart": 0, + "hooray": 0, + "laugh": 0, + "rocket": 0, + "total_count": 0, + "url": "https://api.github.com/repos/rust-lang/rust/issues/105782/reactions" + }, + "repository_url": "https://api.github.com/repos/rust-lang/rust", + "state": "open", + "state_reason": null, + "timeline_url": "https://api.github.com/repos/rust-lang/rust/issues/105782/timeline", + "title": "specialization: default items completely drop candidates instead of ambiguity", + "updated_at": "2022-12-16T16:17:41Z", + "url": "https://api.github.com/repos/rust-lang/rust/issues/105782", + "user": { + "avatar_url": "https://avatars.githubusercontent.com/u/29864074?v=4", + "events_url": "https://api.github.com/users/lcnr/events{/privacy}", + "followers_url": "https://api.github.com/users/lcnr/followers", + "following_url": "https://api.github.com/users/lcnr/following{/other_user}", + "gists_url": "https://api.github.com/users/lcnr/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/lcnr", + "id": 29864074, + "login": "lcnr", + "node_id": "MDQ6VXNlcjI5ODY0MDc0", + "organizations_url": "https://api.github.com/users/lcnr/orgs", + "received_events_url": "https://api.github.com/users/lcnr/received_events", + "repos_url": "https://api.github.com/users/lcnr/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/lcnr/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/lcnr/subscriptions", + "type": "User", + "url": "https://api.github.com/users/lcnr" + } + }, + { + "active_lock_reason": null, + "assignee": null, + "assignees": [], + "author_association": "MEMBER", + "body": "```rust\r\n// Using the higher ranked projection hack to prevent us from replacing the projection\r\n// with an inference variable.\r\ntrait ToUnit<'a> {\r\n type Unit;\r\n}\r\n\r\nstruct LocalTy;\r\nimpl<'a> ToUnit<'a> for *const LocalTy {\r\n type Unit = ();\r\n}\r\n\r\nimpl<'a, T: Copy + ?Sized> ToUnit<'a> for *const T {\r\n type Unit = ();\r\n}\r\n\r\ntrait Overlap {\r\n type Assoc;\r\n}\r\n\r\ntype Assoc<'a, T> = <*const T as ToUnit<'a>>::Unit;\r\n\r\nimpl Overlap for T {\r\n type Assoc = usize;\r\n}\r\n\r\nimpl Overlap fn(&'a (), Assoc<'a, T>)> for T\r\nwhere\r\n for<'a> *const T: ToUnit<'a>,\r\n{\r\n type Assoc = Box;\r\n}\r\n\r\nfn foo, U>(x: T::Assoc) -> T::Assoc {\r\n x\r\n}\r\n\r\nfn main() {\r\n foo:: fn(&'a (), ()), for<'a> fn(&'a (), ())>(3usize);\r\n}\r\n```\r\n\r\n`for<'a> fn(&'a (), ())>: Overlap fn(&'a (), ())>>` can be satisfied using both impls, ignoring a deficiency of the current normalization routine which means that right now the second impl pretty much never applies.\r\n\r\nCurrently inference constraints from equating the self type are not used to normalize the trait argument so we fail when equating `()` with `Assoc<'a, for<'a> fn(&'a (), ())>` even those these two are the same type. This will change once deferred projection equality is implemented.\r\n\r\n## why this currently passes coherence\r\n\r\nCoherence does a pairwise check for all relevant impls. It starts by instantiating the impl parameters with inference vars and equating the impl headers. When we do that with `Overlap for T` and `Overlap fn(&'a (), Assoc<'a, T>)> for T` we have:\r\n\r\n- `eq(?0: Overflap0>, ?1: Overlap fn(&'a (), <*const ?1 as ToUnit<'a>>::Unit)>)`\r\n - `eq(?0, ?1)` constrains `?1` to be equal to `?0`\r\n - `eq(?0, for<'a> fn(&'a (), <*const ?0 as ToUnit<'a>>::Unit)>)`: this now fails the occurs check\r\n\r\nThe occurs check is necessary to prevent ourselves from creating infinitely large types, e.g. `?0 = Vec0>`. But it does mean that coherence considers these two impls to be disjoint. Because the inference var only occurs inside of a projection, there's a way to equate these two types without resulting in an infinitely large type by normalizing the projection.", + "closed_at": null, + "comments": 1, + "comments_url": "https://api.github.com/repos/rust-lang/rust/issues/105787/comments", + "created_at": "2022-12-16T16:16:11Z", + "events_url": "https://api.github.com/repos/rust-lang/rust/issues/105787/events", + "html_url": "https://github.com/rust-lang/rust/issues/105787", + "id": 1500501670, + "labels": [ + { + "color": "f7e101", + "default": false, + "description": "Area: Trait system", + "id": 13836860, + "name": "A-traits", + "node_id": "MDU6TGFiZWwxMzgzNjg2MA==", + "url": "https://api.github.com/repos/rust-lang/rust/labels/A-traits" + }, + { + "color": "eb6420", + "default": false, + "description": "Medium priority", + "id": 60344715, + "name": "P-medium", + "node_id": "MDU6TGFiZWw2MDM0NDcxNQ==", + "url": "https://api.github.com/repos/rust-lang/rust/labels/P-medium" + }, + { + "color": "e11d21", + "default": false, + "description": "Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness", + "id": 267612997, + "name": "I-unsound", + "node_id": "MDU6TGFiZWwyNjc2MTI5OTc=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/I-unsound" + }, + { + "color": "f5f1fd", + "default": false, + "description": "Category: This is a bug.", + "id": 650731663, + "name": "C-bug", + "node_id": "MDU6TGFiZWw2NTA3MzE2NjM=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/C-bug" + }, + { + "color": "bfd4f2", + "default": false, + "description": "Relevant to the types team, which will review and decide on the PR/issue.", + "id": 4172483496, + "name": "T-types", + "node_id": "LA_kwDOAAsO6M74swuo", + "url": "https://api.github.com/repos/rust-lang/rust/labels/T-types" + }, + { + "color": "f7e101", + "default": false, + "description": "Area: Coherence", + "id": 4917350639, + "name": "A-coherence", + "node_id": "LA_kwDOAAsO6M8AAAABJRjQ7w", + "url": "https://api.github.com/repos/rust-lang/rust/labels/A-coherence" + } + ], + "labels_url": "https://api.github.com/repos/rust-lang/rust/issues/105787/labels{/name}", + "locked": false, + "milestone": null, + "node_id": "I_kwDOAAsO6M5Zb9am", + "number": 105787, + "performed_via_github_app": null, + "reactions": { + "+1": 0, + "-1": 0, + "confused": 0, + "eyes": 0, + "heart": 0, + "hooray": 0, + "laugh": 0, + "rocket": 0, + "total_count": 0, + "url": "https://api.github.com/repos/rust-lang/rust/issues/105787/reactions" + }, + "repository_url": "https://api.github.com/repos/rust-lang/rust", + "state": "open", + "state_reason": null, + "timeline_url": "https://api.github.com/repos/rust-lang/rust/issues/105787/timeline", + "title": "occurs check with projections results in error, not ambiguity", + "updated_at": "2022-12-17T05:07:04Z", + "url": "https://api.github.com/repos/rust-lang/rust/issues/105787", + "user": { + "avatar_url": "https://avatars.githubusercontent.com/u/29864074?v=4", + "events_url": "https://api.github.com/users/lcnr/events{/privacy}", + "followers_url": "https://api.github.com/users/lcnr/followers", + "following_url": "https://api.github.com/users/lcnr/following{/other_user}", + "gists_url": "https://api.github.com/users/lcnr/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/lcnr", + "id": 29864074, + "login": "lcnr", + "node_id": "MDQ6VXNlcjI5ODY0MDc0", + "organizations_url": "https://api.github.com/users/lcnr/orgs", + "received_events_url": "https://api.github.com/users/lcnr/received_events", + "repos_url": "https://api.github.com/users/lcnr/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/lcnr/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/lcnr/subscriptions", + "type": "User", + "url": "https://api.github.com/users/lcnr" + } + } + ] +} diff --git a/tests/github_client/get_issues_with_search/00-GET-repos_rust-lang_rust.json b/tests/github_client/get_issues_with_search/00-GET-repos_rust-lang_rust.json new file mode 100644 index 00000000..fd9dcba7 --- /dev/null +++ b/tests/github_client/get_issues_with_search/00-GET-repos_rust-lang_rust.json @@ -0,0 +1,160 @@ +{ + "kind": "Request", + "method": "GET", + "path": "/repos/rust-lang/rust", + "query": null, + "request_body": "", + "response_code": 200, + "response_body": { + "allow_auto_merge": false, + "allow_forking": true, + "allow_merge_commit": true, + "allow_rebase_merge": false, + "allow_squash_merge": false, + "allow_update_branch": false, + "archive_url": "https://api.github.com/repos/rust-lang/rust/{archive_format}{/ref}", + "archived": false, + "assignees_url": "https://api.github.com/repos/rust-lang/rust/assignees{/user}", + "blobs_url": "https://api.github.com/repos/rust-lang/rust/git/blobs{/sha}", + "branches_url": "https://api.github.com/repos/rust-lang/rust/branches{/branch}", + "clone_url": "https://github.com/rust-lang/rust.git", + "collaborators_url": "https://api.github.com/repos/rust-lang/rust/collaborators{/collaborator}", + "comments_url": "https://api.github.com/repos/rust-lang/rust/comments{/number}", + "commits_url": "https://api.github.com/repos/rust-lang/rust/commits{/sha}", + "compare_url": "https://api.github.com/repos/rust-lang/rust/compare/{base}...{head}", + "contents_url": "https://api.github.com/repos/rust-lang/rust/contents/{+path}", + "contributors_url": "https://api.github.com/repos/rust-lang/rust/contributors", + "created_at": "2010-06-16T20:39:03Z", + "default_branch": "master", + "delete_branch_on_merge": true, + "deployments_url": "https://api.github.com/repos/rust-lang/rust/deployments", + "description": "Empowering everyone to build reliable and efficient software.", + "disabled": false, + "downloads_url": "https://api.github.com/repos/rust-lang/rust/downloads", + "events_url": "https://api.github.com/repos/rust-lang/rust/events", + "fork": false, + "forks": 10327, + "forks_count": 10327, + "forks_url": "https://api.github.com/repos/rust-lang/rust/forks", + "full_name": "rust-lang/rust", + "git_commits_url": "https://api.github.com/repos/rust-lang/rust/git/commits{/sha}", + "git_refs_url": "https://api.github.com/repos/rust-lang/rust/git/refs{/sha}", + "git_tags_url": "https://api.github.com/repos/rust-lang/rust/git/tags{/sha}", + "git_url": "git://github.com/rust-lang/rust.git", + "has_discussions": false, + "has_downloads": true, + "has_issues": true, + "has_pages": false, + "has_projects": true, + "has_wiki": false, + "homepage": "https://www.rust-lang.org", + "hooks_url": "https://api.github.com/repos/rust-lang/rust/hooks", + "html_url": "https://github.com/rust-lang/rust", + "id": 724712, + "is_template": false, + "issue_comment_url": "https://api.github.com/repos/rust-lang/rust/issues/comments{/number}", + "issue_events_url": "https://api.github.com/repos/rust-lang/rust/issues/events{/number}", + "issues_url": "https://api.github.com/repos/rust-lang/rust/issues{/number}", + "keys_url": "https://api.github.com/repos/rust-lang/rust/keys{/key_id}", + "labels_url": "https://api.github.com/repos/rust-lang/rust/labels{/name}", + "language": "Rust", + "languages_url": "https://api.github.com/repos/rust-lang/rust/languages", + "license": { + "key": "other", + "name": "Other", + "node_id": "MDc6TGljZW5zZTA=", + "spdx_id": "NOASSERTION", + "url": null + }, + "merge_commit_message": "PR_TITLE", + "merge_commit_title": "MERGE_MESSAGE", + "merges_url": "https://api.github.com/repos/rust-lang/rust/merges", + "milestones_url": "https://api.github.com/repos/rust-lang/rust/milestones{/number}", + "mirror_url": null, + "name": "rust", + "network_count": 10327, + "node_id": "MDEwOlJlcG9zaXRvcnk3MjQ3MTI=", + "notifications_url": "https://api.github.com/repos/rust-lang/rust/notifications{?since,all,participating}", + "open_issues": 9516, + "open_issues_count": 9516, + "organization": { + "avatar_url": "https://avatars.githubusercontent.com/u/5430905?v=4", + "events_url": "https://api.github.com/users/rust-lang/events{/privacy}", + "followers_url": "https://api.github.com/users/rust-lang/followers", + "following_url": "https://api.github.com/users/rust-lang/following{/other_user}", + "gists_url": "https://api.github.com/users/rust-lang/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/rust-lang", + "id": 5430905, + "login": "rust-lang", + "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MzA5MDU=", + "organizations_url": "https://api.github.com/users/rust-lang/orgs", + "received_events_url": "https://api.github.com/users/rust-lang/received_events", + "repos_url": "https://api.github.com/users/rust-lang/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/rust-lang/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rust-lang/subscriptions", + "type": "Organization", + "url": "https://api.github.com/users/rust-lang" + }, + "owner": { + "avatar_url": "https://avatars.githubusercontent.com/u/5430905?v=4", + "events_url": "https://api.github.com/users/rust-lang/events{/privacy}", + "followers_url": "https://api.github.com/users/rust-lang/followers", + "following_url": "https://api.github.com/users/rust-lang/following{/other_user}", + "gists_url": "https://api.github.com/users/rust-lang/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/rust-lang", + "id": 5430905, + "login": "rust-lang", + "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MzA5MDU=", + "organizations_url": "https://api.github.com/users/rust-lang/orgs", + "received_events_url": "https://api.github.com/users/rust-lang/received_events", + "repos_url": "https://api.github.com/users/rust-lang/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/rust-lang/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rust-lang/subscriptions", + "type": "Organization", + "url": "https://api.github.com/users/rust-lang" + }, + "permissions": { + "admin": false, + "maintain": false, + "pull": true, + "push": true, + "triage": true + }, + "private": false, + "pulls_url": "https://api.github.com/repos/rust-lang/rust/pulls{/number}", + "pushed_at": "2023-02-05T21:22:12Z", + "releases_url": "https://api.github.com/repos/rust-lang/rust/releases{/id}", + "size": 1066392, + "squash_merge_commit_message": "COMMIT_MESSAGES", + "squash_merge_commit_title": "COMMIT_OR_PR_TITLE", + "ssh_url": "git@github.com:rust-lang/rust.git", + "stargazers_count": 77405, + "stargazers_url": "https://api.github.com/repos/rust-lang/rust/stargazers", + "statuses_url": "https://api.github.com/repos/rust-lang/rust/statuses/{sha}", + "subscribers_count": 1487, + "subscribers_url": "https://api.github.com/repos/rust-lang/rust/subscribers", + "subscription_url": "https://api.github.com/repos/rust-lang/rust/subscription", + "svn_url": "https://github.com/rust-lang/rust", + "tags_url": "https://api.github.com/repos/rust-lang/rust/tags", + "teams_url": "https://api.github.com/repos/rust-lang/rust/teams", + "temp_clone_token": "", + "topics": [ + "compiler", + "hacktoberfest", + "language", + "rust" + ], + "trees_url": "https://api.github.com/repos/rust-lang/rust/git/trees{/sha}", + "updated_at": "2023-02-05T21:23:12Z", + "url": "https://api.github.com/repos/rust-lang/rust", + "use_squash_pr_title_as_default": false, + "visibility": "public", + "watchers": 77405, + "watchers_count": 77405, + "web_commit_signoff_required": false + } +} diff --git a/tests/github_client/get_issues_with_search/01-GET-search_issues.json b/tests/github_client/get_issues_with_search/01-GET-search_issues.json new file mode 100644 index 00000000..cbc12b0e --- /dev/null +++ b/tests/github_client/get_issues_with_search/01-GET-search_issues.json @@ -0,0 +1,614 @@ +{ + "kind": "Request", + "method": "GET", + "path": "/search/issues", + "query": "q=state:closed+is:pull-request+label:beta-nominated+label:beta-accepted+repo:rust-lang/rust&sort=created&order=asc&per_page=100&page=1", + "request_body": "", + "response_code": 200, + "response_body": { + "incomplete_results": false, + "items": [ + { + "active_lock_reason": null, + "assignee": { + "avatar_url": "https://avatars.githubusercontent.com/u/5047365?v=4", + "events_url": "https://api.github.com/users/Mark-Simulacrum/events{/privacy}", + "followers_url": "https://api.github.com/users/Mark-Simulacrum/followers", + "following_url": "https://api.github.com/users/Mark-Simulacrum/following{/other_user}", + "gists_url": "https://api.github.com/users/Mark-Simulacrum/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/Mark-Simulacrum", + "id": 5047365, + "login": "Mark-Simulacrum", + "node_id": "MDQ6VXNlcjUwNDczNjU=", + "organizations_url": "https://api.github.com/users/Mark-Simulacrum/orgs", + "received_events_url": "https://api.github.com/users/Mark-Simulacrum/received_events", + "repos_url": "https://api.github.com/users/Mark-Simulacrum/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/Mark-Simulacrum/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/Mark-Simulacrum/subscriptions", + "type": "User", + "url": "https://api.github.com/users/Mark-Simulacrum" + }, + "assignees": [ + { + "avatar_url": "https://avatars.githubusercontent.com/u/5047365?v=4", + "events_url": "https://api.github.com/users/Mark-Simulacrum/events{/privacy}", + "followers_url": "https://api.github.com/users/Mark-Simulacrum/followers", + "following_url": "https://api.github.com/users/Mark-Simulacrum/following{/other_user}", + "gists_url": "https://api.github.com/users/Mark-Simulacrum/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/Mark-Simulacrum", + "id": 5047365, + "login": "Mark-Simulacrum", + "node_id": "MDQ6VXNlcjUwNDczNjU=", + "organizations_url": "https://api.github.com/users/Mark-Simulacrum/orgs", + "received_events_url": "https://api.github.com/users/Mark-Simulacrum/received_events", + "repos_url": "https://api.github.com/users/Mark-Simulacrum/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/Mark-Simulacrum/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/Mark-Simulacrum/subscriptions", + "type": "User", + "url": "https://api.github.com/users/Mark-Simulacrum" + } + ], + "author_association": "MEMBER", + "body": "They were missing after recent move from src/test to tests.\r\n\r\ncc @albertlarsan68\r\n\r\nFixes #107081", + "closed_at": "2023-01-26T03:10:34Z", + "comments": 5, + "comments_url": "https://api.github.com/repos/rust-lang/rust/issues/107239/comments", + "created_at": "2023-01-23T20:54:12Z", + "draft": false, + "events_url": "https://api.github.com/repos/rust-lang/rust/issues/107239/events", + "html_url": "https://github.com/rust-lang/rust/pull/107239", + "id": 1553798773, + "labels": [ + { + "color": "1e76d9", + "default": false, + "description": "Nominated for backporting to the compiler in the beta channel.", + "id": 201991156, + "name": "beta-nominated", + "node_id": "MDU6TGFiZWwyMDE5OTExNTY=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/beta-nominated" + }, + { + "color": "1e76d9", + "default": false, + "description": "Accepted for backporting to the compiler in the beta channel.", + "id": 203428830, + "name": "beta-accepted", + "node_id": "MDU6TGFiZWwyMDM0Mjg4MzA=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/beta-accepted" + }, + { + "color": "bfd4f2", + "default": false, + "description": "Relevant to the bootstrap subteam: Rust's build system (x.py and src/bootstrap)", + "id": 325438536, + "name": "T-bootstrap", + "node_id": "MDU6TGFiZWwzMjU0Mzg1MzY=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/T-bootstrap" + }, + { + "color": "d3dddd", + "default": false, + "description": "Status: Waiting on bors to run and complete tests. Bors will change the label on completion.", + "id": 583437191, + "name": "S-waiting-on-bors", + "node_id": "MDU6TGFiZWw1ODM0MzcxOTE=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/S-waiting-on-bors" + }, + { + "color": "bfd4f2", + "default": false, + "description": "Relevant to the infrastructure team, which will review and decide on the PR/issue.", + "id": 593503757, + "name": "T-infra", + "node_id": "MDU6TGFiZWw1OTM1MDM3NTc=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/T-infra" + } + ], + "labels_url": "https://api.github.com/repos/rust-lang/rust/issues/107239/labels{/name}", + "locked": false, + "milestone": { + "closed_at": null, + "closed_issues": 270, + "created_at": "2023-01-22T13:22:36Z", + "creator": { + "avatar_url": "https://avatars.githubusercontent.com/u/47979223?v=4", + "events_url": "https://api.github.com/users/rustbot/events{/privacy}", + "followers_url": "https://api.github.com/users/rustbot/followers", + "following_url": "https://api.github.com/users/rustbot/following{/other_user}", + "gists_url": "https://api.github.com/users/rustbot/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/rustbot", + "id": 47979223, + "login": "rustbot", + "node_id": "MDQ6VXNlcjQ3OTc5MjIz", + "organizations_url": "https://api.github.com/users/rustbot/orgs", + "received_events_url": "https://api.github.com/users/rustbot/received_events", + "repos_url": "https://api.github.com/users/rustbot/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/rustbot/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rustbot/subscriptions", + "type": "User", + "url": "https://api.github.com/users/rustbot" + }, + "description": null, + "due_on": null, + "html_url": "https://github.com/rust-lang/rust/milestone/102", + "id": 8951616, + "labels_url": "https://api.github.com/repos/rust-lang/rust/milestones/102/labels", + "node_id": "MI_kwDOAAsO6M4AiJdA", + "number": 102, + "open_issues": 0, + "state": "open", + "title": "1.69.0", + "updated_at": "2023-02-05T20:33:07Z", + "url": "https://api.github.com/repos/rust-lang/rust/milestones/102" + }, + "node_id": "PR_kwDOAAsO6M5IXTOo", + "number": 107239, + "performed_via_github_app": null, + "pull_request": { + "diff_url": "https://github.com/rust-lang/rust/pull/107239.diff", + "html_url": "https://github.com/rust-lang/rust/pull/107239", + "merged_at": "2023-01-26T03:10:34Z", + "patch_url": "https://github.com/rust-lang/rust/pull/107239.patch", + "url": "https://api.github.com/repos/rust-lang/rust/pulls/107239" + }, + "reactions": { + "+1": 0, + "-1": 0, + "confused": 0, + "eyes": 0, + "heart": 0, + "hooray": 0, + "laugh": 0, + "rocket": 0, + "total_count": 0, + "url": "https://api.github.com/repos/rust-lang/rust/issues/107239/reactions" + }, + "repository_url": "https://api.github.com/repos/rust-lang/rust", + "score": 1.0, + "state": "closed", + "state_reason": null, + "timeline_url": "https://api.github.com/repos/rust-lang/rust/issues/107239/timeline", + "title": "Bring tests back into rustc source tarball", + "updated_at": "2023-01-26T09:15:41Z", + "url": "https://api.github.com/repos/rust-lang/rust/issues/107239", + "user": { + "avatar_url": "https://avatars.githubusercontent.com/u/51362316?v=4", + "events_url": "https://api.github.com/users/tmiasko/events{/privacy}", + "followers_url": "https://api.github.com/users/tmiasko/followers", + "following_url": "https://api.github.com/users/tmiasko/following{/other_user}", + "gists_url": "https://api.github.com/users/tmiasko/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/tmiasko", + "id": 51362316, + "login": "tmiasko", + "node_id": "MDQ6VXNlcjUxMzYyMzE2", + "organizations_url": "https://api.github.com/users/tmiasko/orgs", + "received_events_url": "https://api.github.com/users/tmiasko/received_events", + "repos_url": "https://api.github.com/users/tmiasko/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/tmiasko/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/tmiasko/subscriptions", + "type": "User", + "url": "https://api.github.com/users/tmiasko" + } + }, + { + "active_lock_reason": null, + "assignee": { + "avatar_url": "https://avatars.githubusercontent.com/u/1593513?v=4", + "events_url": "https://api.github.com/users/notriddle/events{/privacy}", + "followers_url": "https://api.github.com/users/notriddle/followers", + "following_url": "https://api.github.com/users/notriddle/following{/other_user}", + "gists_url": "https://api.github.com/users/notriddle/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/notriddle", + "id": 1593513, + "login": "notriddle", + "node_id": "MDQ6VXNlcjE1OTM1MTM=", + "organizations_url": "https://api.github.com/users/notriddle/orgs", + "received_events_url": "https://api.github.com/users/notriddle/received_events", + "repos_url": "https://api.github.com/users/notriddle/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/notriddle/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/notriddle/subscriptions", + "type": "User", + "url": "https://api.github.com/users/notriddle" + }, + "assignees": [ + { + "avatar_url": "https://avatars.githubusercontent.com/u/1593513?v=4", + "events_url": "https://api.github.com/users/notriddle/events{/privacy}", + "followers_url": "https://api.github.com/users/notriddle/followers", + "following_url": "https://api.github.com/users/notriddle/following{/other_user}", + "gists_url": "https://api.github.com/users/notriddle/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/notriddle", + "id": 1593513, + "login": "notriddle", + "node_id": "MDQ6VXNlcjE1OTM1MTM=", + "organizations_url": "https://api.github.com/users/notriddle/orgs", + "received_events_url": "https://api.github.com/users/notriddle/received_events", + "repos_url": "https://api.github.com/users/notriddle/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/notriddle/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/notriddle/subscriptions", + "type": "User", + "url": "https://api.github.com/users/notriddle" + } + ], + "author_association": "MEMBER", + "body": "Fixes https://github.com/rust-lang/rust/issues/107350.\r\n\r\nWe'll also need to backport this fix to beta.\r\n\r\nr? @notriddle ", + "closed_at": "2023-01-27T21:20:36Z", + "comments": 3, + "comments_url": "https://api.github.com/repos/rust-lang/rust/issues/107357/comments", + "created_at": "2023-01-27T11:11:41Z", + "draft": false, + "events_url": "https://api.github.com/repos/rust-lang/rust/issues/107357/events", + "html_url": "https://github.com/rust-lang/rust/pull/107357", + "id": 1559575358, + "labels": [ + { + "color": "bfd4f2", + "default": false, + "description": "Relevant to the rustdoc team, which will review and decide on the PR/issue.", + "id": 203738, + "name": "T-rustdoc", + "node_id": "MDU6TGFiZWwyMDM3Mzg=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/T-rustdoc" + }, + { + "color": "1e76d9", + "default": false, + "description": "Nominated for backporting to the compiler in the beta channel.", + "id": 201991156, + "name": "beta-nominated", + "node_id": "MDU6TGFiZWwyMDE5OTExNTY=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/beta-nominated" + }, + { + "color": "1e76d9", + "default": false, + "description": "Accepted for backporting to the compiler in the beta channel.", + "id": 203428830, + "name": "beta-accepted", + "node_id": "MDU6TGFiZWwyMDM0Mjg4MzA=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/beta-accepted" + }, + { + "color": "d3dddd", + "default": false, + "description": "Status: Waiting on bors to run and complete tests. Bors will change the label on completion.", + "id": 583437191, + "name": "S-waiting-on-bors", + "node_id": "MDU6TGFiZWw1ODM0MzcxOTE=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/S-waiting-on-bors" + } + ], + "labels_url": "https://api.github.com/repos/rust-lang/rust/issues/107357/labels{/name}", + "locked": false, + "milestone": { + "closed_at": null, + "closed_issues": 270, + "created_at": "2023-01-22T13:22:36Z", + "creator": { + "avatar_url": "https://avatars.githubusercontent.com/u/47979223?v=4", + "events_url": "https://api.github.com/users/rustbot/events{/privacy}", + "followers_url": "https://api.github.com/users/rustbot/followers", + "following_url": "https://api.github.com/users/rustbot/following{/other_user}", + "gists_url": "https://api.github.com/users/rustbot/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/rustbot", + "id": 47979223, + "login": "rustbot", + "node_id": "MDQ6VXNlcjQ3OTc5MjIz", + "organizations_url": "https://api.github.com/users/rustbot/orgs", + "received_events_url": "https://api.github.com/users/rustbot/received_events", + "repos_url": "https://api.github.com/users/rustbot/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/rustbot/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rustbot/subscriptions", + "type": "User", + "url": "https://api.github.com/users/rustbot" + }, + "description": null, + "due_on": null, + "html_url": "https://github.com/rust-lang/rust/milestone/102", + "id": 8951616, + "labels_url": "https://api.github.com/repos/rust-lang/rust/milestones/102/labels", + "node_id": "MI_kwDOAAsO6M4AiJdA", + "number": 102, + "open_issues": 0, + "state": "open", + "title": "1.69.0", + "updated_at": "2023-02-05T20:33:07Z", + "url": "https://api.github.com/repos/rust-lang/rust/milestones/102" + }, + "node_id": "PR_kwDOAAsO6M5Iqrzr", + "number": 107357, + "performed_via_github_app": null, + "pull_request": { + "diff_url": "https://github.com/rust-lang/rust/pull/107357.diff", + "html_url": "https://github.com/rust-lang/rust/pull/107357", + "merged_at": "2023-01-27T21:20:36Z", + "patch_url": "https://github.com/rust-lang/rust/pull/107357.patch", + "url": "https://api.github.com/repos/rust-lang/rust/pulls/107357" + }, + "reactions": { + "+1": 0, + "-1": 0, + "confused": 0, + "eyes": 0, + "heart": 0, + "hooray": 0, + "laugh": 0, + "rocket": 1, + "total_count": 1, + "url": "https://api.github.com/repos/rust-lang/rust/issues/107357/reactions" + }, + "repository_url": "https://api.github.com/repos/rust-lang/rust", + "score": 1.0, + "state": "closed", + "state_reason": null, + "timeline_url": "https://api.github.com/repos/rust-lang/rust/issues/107357/timeline", + "title": "Fix infinite loop in rustdoc get_all_import_attributes function", + "updated_at": "2023-02-01T22:14:14Z", + "url": "https://api.github.com/repos/rust-lang/rust/issues/107357", + "user": { + "avatar_url": "https://avatars.githubusercontent.com/u/3050060?v=4", + "events_url": "https://api.github.com/users/GuillaumeGomez/events{/privacy}", + "followers_url": "https://api.github.com/users/GuillaumeGomez/followers", + "following_url": "https://api.github.com/users/GuillaumeGomez/following{/other_user}", + "gists_url": "https://api.github.com/users/GuillaumeGomez/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/GuillaumeGomez", + "id": 3050060, + "login": "GuillaumeGomez", + "node_id": "MDQ6VXNlcjMwNTAwNjA=", + "organizations_url": "https://api.github.com/users/GuillaumeGomez/orgs", + "received_events_url": "https://api.github.com/users/GuillaumeGomez/received_events", + "repos_url": "https://api.github.com/users/GuillaumeGomez/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/GuillaumeGomez/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/GuillaumeGomez/subscriptions", + "type": "User", + "url": "https://api.github.com/users/GuillaumeGomez" + } + }, + { + "active_lock_reason": null, + "assignee": { + "avatar_url": "https://avatars.githubusercontent.com/u/1822483?v=4", + "events_url": "https://api.github.com/users/cjgillot/events{/privacy}", + "followers_url": "https://api.github.com/users/cjgillot/followers", + "following_url": "https://api.github.com/users/cjgillot/following{/other_user}", + "gists_url": "https://api.github.com/users/cjgillot/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/cjgillot", + "id": 1822483, + "login": "cjgillot", + "node_id": "MDQ6VXNlcjE4MjI0ODM=", + "organizations_url": "https://api.github.com/users/cjgillot/orgs", + "received_events_url": "https://api.github.com/users/cjgillot/received_events", + "repos_url": "https://api.github.com/users/cjgillot/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/cjgillot/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/cjgillot/subscriptions", + "type": "User", + "url": "https://api.github.com/users/cjgillot" + }, + "assignees": [ + { + "avatar_url": "https://avatars.githubusercontent.com/u/1822483?v=4", + "events_url": "https://api.github.com/users/cjgillot/events{/privacy}", + "followers_url": "https://api.github.com/users/cjgillot/followers", + "following_url": "https://api.github.com/users/cjgillot/following{/other_user}", + "gists_url": "https://api.github.com/users/cjgillot/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/cjgillot", + "id": 1822483, + "login": "cjgillot", + "node_id": "MDQ6VXNlcjE4MjI0ODM=", + "organizations_url": "https://api.github.com/users/cjgillot/orgs", + "received_events_url": "https://api.github.com/users/cjgillot/received_events", + "repos_url": "https://api.github.com/users/cjgillot/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/cjgillot/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/cjgillot/subscriptions", + "type": "User", + "url": "https://api.github.com/users/cjgillot" + } + ], + "author_association": "MEMBER", + "body": "This includes a revert of https://github.com/rust-lang/rust/pull/105221 to restore fat archive reading with LlvmArchiveBuilder.\r\n\r\nShould fix #107162, #107334 and https://github.com/google/shaderc-rs/issues/133", + "closed_at": "2023-01-28T06:46:40Z", + "comments": 18, + "comments_url": "https://api.github.com/repos/rust-lang/rust/issues/107360/comments", + "created_at": "2023-01-27T11:52:10Z", + "draft": false, + "events_url": "https://api.github.com/repos/rust-lang/rust/issues/107360/events", + "html_url": "https://github.com/rust-lang/rust/pull/107360", + "id": 1559626690, + "labels": [ + { + "color": "1e76d9", + "default": false, + "description": "Nominated for backporting to the compiler in the beta channel.", + "id": 201991156, + "name": "beta-nominated", + "node_id": "MDU6TGFiZWwyMDE5OTExNTY=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/beta-nominated" + }, + { + "color": "1e76d9", + "default": false, + "description": "Accepted for backporting to the compiler in the beta channel.", + "id": 203428830, + "name": "beta-accepted", + "node_id": "MDU6TGFiZWwyMDM0Mjg4MzA=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/beta-accepted" + }, + { + "color": "bfd4f2", + "default": false, + "description": "Relevant to the compiler team, which will review and decide on the PR/issue.", + "id": 211668100, + "name": "T-compiler", + "node_id": "MDU6TGFiZWwyMTE2NjgxMDA=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/T-compiler" + }, + { + "color": "d3dddd", + "default": false, + "description": "Status: Waiting on bors to run and complete tests. Bors will change the label on completion.", + "id": 583437191, + "name": "S-waiting-on-bors", + "node_id": "MDU6TGFiZWw1ODM0MzcxOTE=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/S-waiting-on-bors" + }, + { + "color": "00229c", + "default": false, + "description": "Nominated for backporting to the compiler in the stable channel.", + "id": 980125335, + "name": "stable-nominated", + "node_id": "MDU6TGFiZWw5ODAxMjUzMzU=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/stable-nominated" + }, + { + "color": "00229c", + "default": false, + "description": "Accepted for backporting to the compiler in the stable channel.", + "id": 980125489, + "name": "stable-accepted", + "node_id": "MDU6TGFiZWw5ODAxMjU0ODk=", + "url": "https://api.github.com/repos/rust-lang/rust/labels/stable-accepted" + }, + { + "color": "dae4e4", + "default": false, + "description": "This PR was explicitly merged by bors", + "id": 1223998418, + "name": "merged-by-bors", + "node_id": "MDU6TGFiZWwxMjIzOTk4NDE4", + "url": "https://api.github.com/repos/rust-lang/rust/labels/merged-by-bors" + }, + { + "color": "e4008a", + "default": false, + "description": "Performance regressions", + "id": 3116384996, + "name": "perf-regression", + "node_id": "MDU6TGFiZWwzMTE2Mzg0OTk2", + "url": "https://api.github.com/repos/rust-lang/rust/labels/perf-regression" + }, + { + "color": "e4008a", + "default": false, + "description": "The performance regression has been triaged.", + "id": 3145771546, + "name": "perf-regression-triaged", + "node_id": "MDU6TGFiZWwzMTQ1NzcxNTQ2", + "url": "https://api.github.com/repos/rust-lang/rust/labels/perf-regression-triaged" + } + ], + "labels_url": "https://api.github.com/repos/rust-lang/rust/issues/107360/labels{/name}", + "locked": false, + "milestone": { + "closed_at": null, + "closed_issues": 270, + "created_at": "2023-01-22T13:22:36Z", + "creator": { + "avatar_url": "https://avatars.githubusercontent.com/u/47979223?v=4", + "events_url": "https://api.github.com/users/rustbot/events{/privacy}", + "followers_url": "https://api.github.com/users/rustbot/followers", + "following_url": "https://api.github.com/users/rustbot/following{/other_user}", + "gists_url": "https://api.github.com/users/rustbot/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/rustbot", + "id": 47979223, + "login": "rustbot", + "node_id": "MDQ6VXNlcjQ3OTc5MjIz", + "organizations_url": "https://api.github.com/users/rustbot/orgs", + "received_events_url": "https://api.github.com/users/rustbot/received_events", + "repos_url": "https://api.github.com/users/rustbot/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/rustbot/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rustbot/subscriptions", + "type": "User", + "url": "https://api.github.com/users/rustbot" + }, + "description": null, + "due_on": null, + "html_url": "https://github.com/rust-lang/rust/milestone/102", + "id": 8951616, + "labels_url": "https://api.github.com/repos/rust-lang/rust/milestones/102/labels", + "node_id": "MI_kwDOAAsO6M4AiJdA", + "number": 102, + "open_issues": 0, + "state": "open", + "title": "1.69.0", + "updated_at": "2023-02-05T20:33:07Z", + "url": "https://api.github.com/repos/rust-lang/rust/milestones/102" + }, + "node_id": "PR_kwDOAAsO6M5Iq2_Z", + "number": 107360, + "performed_via_github_app": null, + "pull_request": { + "diff_url": "https://github.com/rust-lang/rust/pull/107360.diff", + "html_url": "https://github.com/rust-lang/rust/pull/107360", + "merged_at": "2023-01-28T06:46:40Z", + "patch_url": "https://github.com/rust-lang/rust/pull/107360.patch", + "url": "https://api.github.com/repos/rust-lang/rust/pulls/107360" + }, + "reactions": { + "+1": 0, + "-1": 0, + "confused": 0, + "eyes": 0, + "heart": 0, + "hooray": 0, + "laugh": 0, + "rocket": 0, + "total_count": 0, + "url": "https://api.github.com/repos/rust-lang/rust/issues/107360/reactions" + }, + "repository_url": "https://api.github.com/repos/rust-lang/rust", + "score": 1.0, + "state": "closed", + "state_reason": null, + "timeline_url": "https://api.github.com/repos/rust-lang/rust/issues/107360/timeline", + "title": "Fix thin archive reading", + "updated_at": "2023-02-02T20:35:26Z", + "url": "https://api.github.com/repos/rust-lang/rust/issues/107360", + "user": { + "avatar_url": "https://avatars.githubusercontent.com/u/17426603?v=4", + "events_url": "https://api.github.com/users/bjorn3/events{/privacy}", + "followers_url": "https://api.github.com/users/bjorn3/followers", + "following_url": "https://api.github.com/users/bjorn3/following{/other_user}", + "gists_url": "https://api.github.com/users/bjorn3/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/bjorn3", + "id": 17426603, + "login": "bjorn3", + "node_id": "MDQ6VXNlcjE3NDI2NjAz", + "organizations_url": "https://api.github.com/users/bjorn3/orgs", + "received_events_url": "https://api.github.com/users/bjorn3/received_events", + "repos_url": "https://api.github.com/users/bjorn3/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/bjorn3/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/bjorn3/subscriptions", + "type": "User", + "url": "https://api.github.com/users/bjorn3" + } + } + ], + "total_count": 3 + } +} diff --git a/tests/github_client/get_reference/00-GET-repos_rust-lang_rust.json b/tests/github_client/get_reference/00-GET-repos_rust-lang_rust.json new file mode 100644 index 00000000..3589a6e8 --- /dev/null +++ b/tests/github_client/get_reference/00-GET-repos_rust-lang_rust.json @@ -0,0 +1,160 @@ +{ + "kind": "Request", + "method": "GET", + "path": "/repos/rust-lang/rust", + "query": null, + "request_body": "", + "response_code": 200, + "response_body": { + "allow_auto_merge": false, + "allow_forking": true, + "allow_merge_commit": true, + "allow_rebase_merge": false, + "allow_squash_merge": false, + "allow_update_branch": false, + "archive_url": "https://api.github.com/repos/rust-lang/rust/{archive_format}{/ref}", + "archived": false, + "assignees_url": "https://api.github.com/repos/rust-lang/rust/assignees{/user}", + "blobs_url": "https://api.github.com/repos/rust-lang/rust/git/blobs{/sha}", + "branches_url": "https://api.github.com/repos/rust-lang/rust/branches{/branch}", + "clone_url": "https://github.com/rust-lang/rust.git", + "collaborators_url": "https://api.github.com/repos/rust-lang/rust/collaborators{/collaborator}", + "comments_url": "https://api.github.com/repos/rust-lang/rust/comments{/number}", + "commits_url": "https://api.github.com/repos/rust-lang/rust/commits{/sha}", + "compare_url": "https://api.github.com/repos/rust-lang/rust/compare/{base}...{head}", + "contents_url": "https://api.github.com/repos/rust-lang/rust/contents/{+path}", + "contributors_url": "https://api.github.com/repos/rust-lang/rust/contributors", + "created_at": "2010-06-16T20:39:03Z", + "default_branch": "master", + "delete_branch_on_merge": true, + "deployments_url": "https://api.github.com/repos/rust-lang/rust/deployments", + "description": "Empowering everyone to build reliable and efficient software.", + "disabled": false, + "downloads_url": "https://api.github.com/repos/rust-lang/rust/downloads", + "events_url": "https://api.github.com/repos/rust-lang/rust/events", + "fork": false, + "forks": 10326, + "forks_count": 10326, + "forks_url": "https://api.github.com/repos/rust-lang/rust/forks", + "full_name": "rust-lang/rust", + "git_commits_url": "https://api.github.com/repos/rust-lang/rust/git/commits{/sha}", + "git_refs_url": "https://api.github.com/repos/rust-lang/rust/git/refs{/sha}", + "git_tags_url": "https://api.github.com/repos/rust-lang/rust/git/tags{/sha}", + "git_url": "git://github.com/rust-lang/rust.git", + "has_discussions": false, + "has_downloads": true, + "has_issues": true, + "has_pages": false, + "has_projects": true, + "has_wiki": false, + "homepage": "https://www.rust-lang.org", + "hooks_url": "https://api.github.com/repos/rust-lang/rust/hooks", + "html_url": "https://github.com/rust-lang/rust", + "id": 724712, + "is_template": false, + "issue_comment_url": "https://api.github.com/repos/rust-lang/rust/issues/comments{/number}", + "issue_events_url": "https://api.github.com/repos/rust-lang/rust/issues/events{/number}", + "issues_url": "https://api.github.com/repos/rust-lang/rust/issues{/number}", + "keys_url": "https://api.github.com/repos/rust-lang/rust/keys{/key_id}", + "labels_url": "https://api.github.com/repos/rust-lang/rust/labels{/name}", + "language": "Rust", + "languages_url": "https://api.github.com/repos/rust-lang/rust/languages", + "license": { + "key": "other", + "name": "Other", + "node_id": "MDc6TGljZW5zZTA=", + "spdx_id": "NOASSERTION", + "url": null + }, + "merge_commit_message": "PR_TITLE", + "merge_commit_title": "MERGE_MESSAGE", + "merges_url": "https://api.github.com/repos/rust-lang/rust/merges", + "milestones_url": "https://api.github.com/repos/rust-lang/rust/milestones{/number}", + "mirror_url": null, + "name": "rust", + "network_count": 10326, + "node_id": "MDEwOlJlcG9zaXRvcnk3MjQ3MTI=", + "notifications_url": "https://api.github.com/repos/rust-lang/rust/notifications{?since,all,participating}", + "open_issues": 9513, + "open_issues_count": 9513, + "organization": { + "avatar_url": "https://avatars.githubusercontent.com/u/5430905?v=4", + "events_url": "https://api.github.com/users/rust-lang/events{/privacy}", + "followers_url": "https://api.github.com/users/rust-lang/followers", + "following_url": "https://api.github.com/users/rust-lang/following{/other_user}", + "gists_url": "https://api.github.com/users/rust-lang/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/rust-lang", + "id": 5430905, + "login": "rust-lang", + "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MzA5MDU=", + "organizations_url": "https://api.github.com/users/rust-lang/orgs", + "received_events_url": "https://api.github.com/users/rust-lang/received_events", + "repos_url": "https://api.github.com/users/rust-lang/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/rust-lang/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rust-lang/subscriptions", + "type": "Organization", + "url": "https://api.github.com/users/rust-lang" + }, + "owner": { + "avatar_url": "https://avatars.githubusercontent.com/u/5430905?v=4", + "events_url": "https://api.github.com/users/rust-lang/events{/privacy}", + "followers_url": "https://api.github.com/users/rust-lang/followers", + "following_url": "https://api.github.com/users/rust-lang/following{/other_user}", + "gists_url": "https://api.github.com/users/rust-lang/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/rust-lang", + "id": 5430905, + "login": "rust-lang", + "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MzA5MDU=", + "organizations_url": "https://api.github.com/users/rust-lang/orgs", + "received_events_url": "https://api.github.com/users/rust-lang/received_events", + "repos_url": "https://api.github.com/users/rust-lang/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/rust-lang/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rust-lang/subscriptions", + "type": "Organization", + "url": "https://api.github.com/users/rust-lang" + }, + "permissions": { + "admin": false, + "maintain": false, + "pull": true, + "push": true, + "triage": true + }, + "private": false, + "pulls_url": "https://api.github.com/repos/rust-lang/rust/pulls{/number}", + "pushed_at": "2023-02-05T18:16:26Z", + "releases_url": "https://api.github.com/repos/rust-lang/rust/releases{/id}", + "size": 1066392, + "squash_merge_commit_message": "COMMIT_MESSAGES", + "squash_merge_commit_title": "COMMIT_OR_PR_TITLE", + "ssh_url": "git@github.com:rust-lang/rust.git", + "stargazers_count": 77402, + "stargazers_url": "https://api.github.com/repos/rust-lang/rust/stargazers", + "statuses_url": "https://api.github.com/repos/rust-lang/rust/statuses/{sha}", + "subscribers_count": 1487, + "subscribers_url": "https://api.github.com/repos/rust-lang/rust/subscribers", + "subscription_url": "https://api.github.com/repos/rust-lang/rust/subscription", + "svn_url": "https://github.com/rust-lang/rust", + "tags_url": "https://api.github.com/repos/rust-lang/rust/tags", + "teams_url": "https://api.github.com/repos/rust-lang/rust/teams", + "temp_clone_token": "", + "topics": [ + "compiler", + "hacktoberfest", + "language", + "rust" + ], + "trees_url": "https://api.github.com/repos/rust-lang/rust/git/trees{/sha}", + "updated_at": "2023-02-05T19:09:47Z", + "url": "https://api.github.com/repos/rust-lang/rust", + "use_squash_pr_title_as_default": false, + "visibility": "public", + "watchers": 77402, + "watchers_count": 77402, + "web_commit_signoff_required": false + } +} diff --git a/tests/github_client/get_reference/01-GET-repos_rust-lang_rust_git_ref_heads_stable.json b/tests/github_client/get_reference/01-GET-repos_rust-lang_rust_git_ref_heads_stable.json new file mode 100644 index 00000000..b2a68fa9 --- /dev/null +++ b/tests/github_client/get_reference/01-GET-repos_rust-lang_rust_git_ref_heads_stable.json @@ -0,0 +1,18 @@ +{ + "kind": "Request", + "method": "GET", + "path": "/repos/rust-lang/rust/git/ref/heads/stable", + "query": null, + "request_body": "", + "response_code": 200, + "response_body": { + "node_id": "MDM6UmVmNzI0NzEyOnJlZnMvaGVhZHMvc3RhYmxl", + "object": { + "sha": "fc594f15669680fa70d255faec3ca3fb507c3405", + "type": "commit", + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/fc594f15669680fa70d255faec3ca3fb507c3405" + }, + "ref": "refs/heads/stable", + "url": "https://api.github.com/repos/rust-lang/rust/git/refs/heads/stable" + } +} diff --git a/tests/github_client/git_commit/00-GET-repos_rust-lang_rust.json b/tests/github_client/git_commit/00-GET-repos_rust-lang_rust.json new file mode 100644 index 00000000..a1ab4e0a --- /dev/null +++ b/tests/github_client/git_commit/00-GET-repos_rust-lang_rust.json @@ -0,0 +1,148 @@ +{ + "kind": "Request", + "method": "GET", + "path": "/repos/rust-lang/rust", + "query": null, + "request_body": "", + "response_code": 200, + "response_body": { + "allow_forking": true, + "archive_url": "https://api.github.com/repos/rust-lang/rust/{archive_format}{/ref}", + "archived": false, + "assignees_url": "https://api.github.com/repos/rust-lang/rust/assignees{/user}", + "blobs_url": "https://api.github.com/repos/rust-lang/rust/git/blobs{/sha}", + "branches_url": "https://api.github.com/repos/rust-lang/rust/branches{/branch}", + "clone_url": "https://github.com/rust-lang/rust.git", + "collaborators_url": "https://api.github.com/repos/rust-lang/rust/collaborators{/collaborator}", + "comments_url": "https://api.github.com/repos/rust-lang/rust/comments{/number}", + "commits_url": "https://api.github.com/repos/rust-lang/rust/commits{/sha}", + "compare_url": "https://api.github.com/repos/rust-lang/rust/compare/{base}...{head}", + "contents_url": "https://api.github.com/repos/rust-lang/rust/contents/{+path}", + "contributors_url": "https://api.github.com/repos/rust-lang/rust/contributors", + "created_at": "2010-06-16T20:39:03Z", + "default_branch": "master", + "deployments_url": "https://api.github.com/repos/rust-lang/rust/deployments", + "description": "Empowering everyone to build reliable and efficient software.", + "disabled": false, + "downloads_url": "https://api.github.com/repos/rust-lang/rust/downloads", + "events_url": "https://api.github.com/repos/rust-lang/rust/events", + "fork": false, + "forks": 10323, + "forks_count": 10323, + "forks_url": "https://api.github.com/repos/rust-lang/rust/forks", + "full_name": "rust-lang/rust", + "git_commits_url": "https://api.github.com/repos/rust-lang/rust/git/commits{/sha}", + "git_refs_url": "https://api.github.com/repos/rust-lang/rust/git/refs{/sha}", + "git_tags_url": "https://api.github.com/repos/rust-lang/rust/git/tags{/sha}", + "git_url": "git://github.com/rust-lang/rust.git", + "has_discussions": false, + "has_downloads": true, + "has_issues": true, + "has_pages": false, + "has_projects": true, + "has_wiki": false, + "homepage": "https://www.rust-lang.org", + "hooks_url": "https://api.github.com/repos/rust-lang/rust/hooks", + "html_url": "https://github.com/rust-lang/rust", + "id": 724712, + "is_template": false, + "issue_comment_url": "https://api.github.com/repos/rust-lang/rust/issues/comments{/number}", + "issue_events_url": "https://api.github.com/repos/rust-lang/rust/issues/events{/number}", + "issues_url": "https://api.github.com/repos/rust-lang/rust/issues{/number}", + "keys_url": "https://api.github.com/repos/rust-lang/rust/keys{/key_id}", + "labels_url": "https://api.github.com/repos/rust-lang/rust/labels{/name}", + "language": "Rust", + "languages_url": "https://api.github.com/repos/rust-lang/rust/languages", + "license": { + "key": "other", + "name": "Other", + "node_id": "MDc6TGljZW5zZTA=", + "spdx_id": "NOASSERTION", + "url": null + }, + "merges_url": "https://api.github.com/repos/rust-lang/rust/merges", + "milestones_url": "https://api.github.com/repos/rust-lang/rust/milestones{/number}", + "mirror_url": null, + "name": "rust", + "network_count": 10323, + "node_id": "MDEwOlJlcG9zaXRvcnk3MjQ3MTI=", + "notifications_url": "https://api.github.com/repos/rust-lang/rust/notifications{?since,all,participating}", + "open_issues": 9508, + "open_issues_count": 9508, + "organization": { + "avatar_url": "https://avatars.githubusercontent.com/u/5430905?v=4", + "events_url": "https://api.github.com/users/rust-lang/events{/privacy}", + "followers_url": "https://api.github.com/users/rust-lang/followers", + "following_url": "https://api.github.com/users/rust-lang/following{/other_user}", + "gists_url": "https://api.github.com/users/rust-lang/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/rust-lang", + "id": 5430905, + "login": "rust-lang", + "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MzA5MDU=", + "organizations_url": "https://api.github.com/users/rust-lang/orgs", + "received_events_url": "https://api.github.com/users/rust-lang/received_events", + "repos_url": "https://api.github.com/users/rust-lang/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/rust-lang/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rust-lang/subscriptions", + "type": "Organization", + "url": "https://api.github.com/users/rust-lang" + }, + "owner": { + "avatar_url": "https://avatars.githubusercontent.com/u/5430905?v=4", + "events_url": "https://api.github.com/users/rust-lang/events{/privacy}", + "followers_url": "https://api.github.com/users/rust-lang/followers", + "following_url": "https://api.github.com/users/rust-lang/following{/other_user}", + "gists_url": "https://api.github.com/users/rust-lang/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/rust-lang", + "id": 5430905, + "login": "rust-lang", + "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MzA5MDU=", + "organizations_url": "https://api.github.com/users/rust-lang/orgs", + "received_events_url": "https://api.github.com/users/rust-lang/received_events", + "repos_url": "https://api.github.com/users/rust-lang/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/rust-lang/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rust-lang/subscriptions", + "type": "Organization", + "url": "https://api.github.com/users/rust-lang" + }, + "permissions": { + "admin": false, + "maintain": false, + "pull": true, + "push": true, + "triage": true + }, + "private": false, + "pulls_url": "https://api.github.com/repos/rust-lang/rust/pulls{/number}", + "pushed_at": "2023-02-05T14:37:25Z", + "releases_url": "https://api.github.com/repos/rust-lang/rust/releases{/id}", + "size": 1066289, + "ssh_url": "git@github.com:rust-lang/rust.git", + "stargazers_count": 77396, + "stargazers_url": "https://api.github.com/repos/rust-lang/rust/stargazers", + "statuses_url": "https://api.github.com/repos/rust-lang/rust/statuses/{sha}", + "subscribers_count": 1488, + "subscribers_url": "https://api.github.com/repos/rust-lang/rust/subscribers", + "subscription_url": "https://api.github.com/repos/rust-lang/rust/subscription", + "svn_url": "https://github.com/rust-lang/rust", + "tags_url": "https://api.github.com/repos/rust-lang/rust/tags", + "teams_url": "https://api.github.com/repos/rust-lang/rust/teams", + "topics": [ + "compiler", + "hacktoberfest", + "language", + "rust" + ], + "trees_url": "https://api.github.com/repos/rust-lang/rust/git/trees{/sha}", + "updated_at": "2023-02-05T14:42:37Z", + "url": "https://api.github.com/repos/rust-lang/rust", + "visibility": "public", + "watchers": 77396, + "watchers_count": 77396, + "web_commit_signoff_required": false + } +} diff --git a/tests/github_client/git_commit/01-GET-repos_rust-lang_rust_git_commits_109cccbe4f345c0f0785ce860788580c3e2a29f5.json b/tests/github_client/git_commit/01-GET-repos_rust-lang_rust_git_commits_109cccbe4f345c0f0785ce860788580c3e2a29f5.json new file mode 100644 index 00000000..40cc3973 --- /dev/null +++ b/tests/github_client/git_commit/01-GET-repos_rust-lang_rust_git_commits_109cccbe4f345c0f0785ce860788580c3e2a29f5.json @@ -0,0 +1,47 @@ +{ + "kind": "Request", + "method": "GET", + "path": "/repos/rust-lang/rust/git/commits/109cccbe4f345c0f0785ce860788580c3e2a29f5", + "query": null, + "request_body": "", + "response_code": 200, + "response_body": { + "author": { + "date": "2022-12-13T07:10:53Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "committer": { + "date": "2022-12-13T07:10:53Z", + "email": "bors@rust-lang.org", + "name": "bors" + }, + "html_url": "https://github.com/rust-lang/rust/commit/109cccbe4f345c0f0785ce860788580c3e2a29f5", + "message": "Auto merge of #105350 - compiler-errors:faster-binder-relate, r=oli-obk\n\nFast-path some binder relations\n\nA simpler approach than #104598\n\nFixes #104583\n\nr? types", + "node_id": "C_kwDOAAsO6NoAKDEwOWNjY2JlNGYzNDVjMGYwNzg1Y2U4NjA3ODg1ODBjM2UyYTI5ZjU", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/71ec1457ee9868a838e4521a3510cdd416c0c295", + "sha": "71ec1457ee9868a838e4521a3510cdd416c0c295", + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/71ec1457ee9868a838e4521a3510cdd416c0c295" + }, + { + "html_url": "https://github.com/rust-lang/rust/commit/2025a96ee1a699722da73993995b6f0572374757", + "sha": "2025a96ee1a699722da73993995b6f0572374757", + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/2025a96ee1a699722da73993995b6f0572374757" + } + ], + "sha": "109cccbe4f345c0f0785ce860788580c3e2a29f5", + "tree": { + "sha": "e67d87c61892169977204cc2e3fd89b2a19e13bb", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/e67d87c61892169977204cc2e3fd89b2a19e13bb" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/109cccbe4f345c0f0785ce860788580c3e2a29f5", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + } +} diff --git a/tests/github_client/is_new_contributor/00-GET-repos_rust-lang_rust.json b/tests/github_client/is_new_contributor/00-GET-repos_rust-lang_rust.json new file mode 100644 index 00000000..2ec17b5e --- /dev/null +++ b/tests/github_client/is_new_contributor/00-GET-repos_rust-lang_rust.json @@ -0,0 +1,148 @@ +{ + "kind": "Request", + "method": "GET", + "path": "/repos/rust-lang/rust", + "query": null, + "request_body": "", + "response_code": 200, + "response_body": { + "allow_forking": true, + "archive_url": "https://api.github.com/repos/rust-lang/rust/{archive_format}{/ref}", + "archived": false, + "assignees_url": "https://api.github.com/repos/rust-lang/rust/assignees{/user}", + "blobs_url": "https://api.github.com/repos/rust-lang/rust/git/blobs{/sha}", + "branches_url": "https://api.github.com/repos/rust-lang/rust/branches{/branch}", + "clone_url": "https://github.com/rust-lang/rust.git", + "collaborators_url": "https://api.github.com/repos/rust-lang/rust/collaborators{/collaborator}", + "comments_url": "https://api.github.com/repos/rust-lang/rust/comments{/number}", + "commits_url": "https://api.github.com/repos/rust-lang/rust/commits{/sha}", + "compare_url": "https://api.github.com/repos/rust-lang/rust/compare/{base}...{head}", + "contents_url": "https://api.github.com/repos/rust-lang/rust/contents/{+path}", + "contributors_url": "https://api.github.com/repos/rust-lang/rust/contributors", + "created_at": "2010-06-16T20:39:03Z", + "default_branch": "master", + "deployments_url": "https://api.github.com/repos/rust-lang/rust/deployments", + "description": "Empowering everyone to build reliable and efficient software.", + "disabled": false, + "downloads_url": "https://api.github.com/repos/rust-lang/rust/downloads", + "events_url": "https://api.github.com/repos/rust-lang/rust/events", + "fork": false, + "forks": 10323, + "forks_count": 10323, + "forks_url": "https://api.github.com/repos/rust-lang/rust/forks", + "full_name": "rust-lang/rust", + "git_commits_url": "https://api.github.com/repos/rust-lang/rust/git/commits{/sha}", + "git_refs_url": "https://api.github.com/repos/rust-lang/rust/git/refs{/sha}", + "git_tags_url": "https://api.github.com/repos/rust-lang/rust/git/tags{/sha}", + "git_url": "git://github.com/rust-lang/rust.git", + "has_discussions": false, + "has_downloads": true, + "has_issues": true, + "has_pages": false, + "has_projects": true, + "has_wiki": false, + "homepage": "https://www.rust-lang.org", + "hooks_url": "https://api.github.com/repos/rust-lang/rust/hooks", + "html_url": "https://github.com/rust-lang/rust", + "id": 724712, + "is_template": false, + "issue_comment_url": "https://api.github.com/repos/rust-lang/rust/issues/comments{/number}", + "issue_events_url": "https://api.github.com/repos/rust-lang/rust/issues/events{/number}", + "issues_url": "https://api.github.com/repos/rust-lang/rust/issues{/number}", + "keys_url": "https://api.github.com/repos/rust-lang/rust/keys{/key_id}", + "labels_url": "https://api.github.com/repos/rust-lang/rust/labels{/name}", + "language": "Rust", + "languages_url": "https://api.github.com/repos/rust-lang/rust/languages", + "license": { + "key": "other", + "name": "Other", + "node_id": "MDc6TGljZW5zZTA=", + "spdx_id": "NOASSERTION", + "url": null + }, + "merges_url": "https://api.github.com/repos/rust-lang/rust/merges", + "milestones_url": "https://api.github.com/repos/rust-lang/rust/milestones{/number}", + "mirror_url": null, + "name": "rust", + "network_count": 10323, + "node_id": "MDEwOlJlcG9zaXRvcnk3MjQ3MTI=", + "notifications_url": "https://api.github.com/repos/rust-lang/rust/notifications{?since,all,participating}", + "open_issues": 9504, + "open_issues_count": 9504, + "organization": { + "avatar_url": "https://avatars.githubusercontent.com/u/5430905?v=4", + "events_url": "https://api.github.com/users/rust-lang/events{/privacy}", + "followers_url": "https://api.github.com/users/rust-lang/followers", + "following_url": "https://api.github.com/users/rust-lang/following{/other_user}", + "gists_url": "https://api.github.com/users/rust-lang/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/rust-lang", + "id": 5430905, + "login": "rust-lang", + "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MzA5MDU=", + "organizations_url": "https://api.github.com/users/rust-lang/orgs", + "received_events_url": "https://api.github.com/users/rust-lang/received_events", + "repos_url": "https://api.github.com/users/rust-lang/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/rust-lang/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rust-lang/subscriptions", + "type": "Organization", + "url": "https://api.github.com/users/rust-lang" + }, + "owner": { + "avatar_url": "https://avatars.githubusercontent.com/u/5430905?v=4", + "events_url": "https://api.github.com/users/rust-lang/events{/privacy}", + "followers_url": "https://api.github.com/users/rust-lang/followers", + "following_url": "https://api.github.com/users/rust-lang/following{/other_user}", + "gists_url": "https://api.github.com/users/rust-lang/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/rust-lang", + "id": 5430905, + "login": "rust-lang", + "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MzA5MDU=", + "organizations_url": "https://api.github.com/users/rust-lang/orgs", + "received_events_url": "https://api.github.com/users/rust-lang/received_events", + "repos_url": "https://api.github.com/users/rust-lang/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/rust-lang/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rust-lang/subscriptions", + "type": "Organization", + "url": "https://api.github.com/users/rust-lang" + }, + "permissions": { + "admin": false, + "maintain": false, + "pull": true, + "push": true, + "triage": true + }, + "private": false, + "pulls_url": "https://api.github.com/repos/rust-lang/rust/pulls{/number}", + "pushed_at": "2023-02-05T14:10:34Z", + "releases_url": "https://api.github.com/repos/rust-lang/rust/releases{/id}", + "size": 1066264, + "ssh_url": "git@github.com:rust-lang/rust.git", + "stargazers_count": 77394, + "stargazers_url": "https://api.github.com/repos/rust-lang/rust/stargazers", + "statuses_url": "https://api.github.com/repos/rust-lang/rust/statuses/{sha}", + "subscribers_count": 1488, + "subscribers_url": "https://api.github.com/repos/rust-lang/rust/subscribers", + "subscription_url": "https://api.github.com/repos/rust-lang/rust/subscription", + "svn_url": "https://github.com/rust-lang/rust", + "tags_url": "https://api.github.com/repos/rust-lang/rust/tags", + "teams_url": "https://api.github.com/repos/rust-lang/rust/teams", + "topics": [ + "compiler", + "hacktoberfest", + "language", + "rust" + ], + "trees_url": "https://api.github.com/repos/rust-lang/rust/git/trees{/sha}", + "updated_at": "2023-02-05T14:20:35Z", + "url": "https://api.github.com/repos/rust-lang/rust", + "visibility": "public", + "watchers": 77394, + "watchers_count": 77394, + "web_commit_signoff_required": false + } +} diff --git a/tests/github_client/is_new_contributor/01-GET-repos_rust-lang_rust_commits.json b/tests/github_client/is_new_contributor/01-GET-repos_rust-lang_rust_commits.json new file mode 100644 index 00000000..d7219399 --- /dev/null +++ b/tests/github_client/is_new_contributor/01-GET-repos_rust-lang_rust_commits.json @@ -0,0 +1,9 @@ +{ + "kind": "Request", + "method": "GET", + "path": "/repos/rust-lang/rust/commits", + "query": "author=octocat", + "request_body": "", + "response_code": 200, + "response_body": [] +} diff --git a/tests/github_client/is_new_contributor/02-GET-repos_rust-lang_rust_commits.json b/tests/github_client/is_new_contributor/02-GET-repos_rust-lang_rust_commits.json new file mode 100644 index 00000000..4fcaca4f --- /dev/null +++ b/tests/github_client/is_new_contributor/02-GET-repos_rust-lang_rust_commits.json @@ -0,0 +1,2380 @@ +{ + "kind": "Request", + "method": "GET", + "path": "/repos/rust-lang/rust/commits", + "query": "author=brson", + "request_body": "", + "response_code": 200, + "response_body": [ + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/147214?v=4", + "events_url": "https://api.github.com/users/brson/events{/privacy}", + "followers_url": "https://api.github.com/users/brson/followers", + "following_url": "https://api.github.com/users/brson/following{/other_user}", + "gists_url": "https://api.github.com/users/brson/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/brson", + "id": 147214, + "login": "brson", + "node_id": "MDQ6VXNlcjE0NzIxNA==", + "organizations_url": "https://api.github.com/users/brson/orgs", + "received_events_url": "https://api.github.com/users/brson/received_events", + "repos_url": "https://api.github.com/users/brson/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/brson/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/brson/subscriptions", + "type": "User", + "url": "https://api.github.com/users/brson" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/356848c9b9a3bd8226bbabd08611b1e519acc9c7/comments", + "commit": { + "author": { + "date": "2020-05-07T02:42:12Z", + "email": "andersrb@gmail.com", + "name": "Brian Anderson" + }, + "comment_count": 0, + "committer": { + "date": "2020-05-07T02:42:12Z", + "email": "andersrb@gmail.com", + "name": "Brian Anderson" + }, + "message": "Add two more TiKV bugs to trophy case", + "tree": { + "sha": "d1aae96f10ecb490d6caebc63de18f34885cb73d", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/d1aae96f10ecb490d6caebc63de18f34885cb73d" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/356848c9b9a3bd8226bbabd08611b1e519acc9c7", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/147214?v=4", + "events_url": "https://api.github.com/users/brson/events{/privacy}", + "followers_url": "https://api.github.com/users/brson/followers", + "following_url": "https://api.github.com/users/brson/following{/other_user}", + "gists_url": "https://api.github.com/users/brson/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/brson", + "id": 147214, + "login": "brson", + "node_id": "MDQ6VXNlcjE0NzIxNA==", + "organizations_url": "https://api.github.com/users/brson/orgs", + "received_events_url": "https://api.github.com/users/brson/received_events", + "repos_url": "https://api.github.com/users/brson/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/brson/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/brson/subscriptions", + "type": "User", + "url": "https://api.github.com/users/brson" + }, + "html_url": "https://github.com/rust-lang/rust/commit/356848c9b9a3bd8226bbabd08611b1e519acc9c7", + "node_id": "MDY6Q29tbWl0NzI0NzEyOjM1Njg0OGM5YjlhM2JkODIyNmJiYWJkMDg2MTFiMWU1MTlhY2M5Yzc=", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/308458a4ab210da24c8fd481d0f930e50f512886", + "sha": "308458a4ab210da24c8fd481d0f930e50f512886", + "url": "https://api.github.com/repos/rust-lang/rust/commits/308458a4ab210da24c8fd481d0f930e50f512886" + } + ], + "sha": "356848c9b9a3bd8226bbabd08611b1e519acc9c7", + "url": "https://api.github.com/repos/rust-lang/rust/commits/356848c9b9a3bd8226bbabd08611b1e519acc9c7" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/147214?v=4", + "events_url": "https://api.github.com/users/brson/events{/privacy}", + "followers_url": "https://api.github.com/users/brson/followers", + "following_url": "https://api.github.com/users/brson/following{/other_user}", + "gists_url": "https://api.github.com/users/brson/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/brson", + "id": 147214, + "login": "brson", + "node_id": "MDQ6VXNlcjE0NzIxNA==", + "organizations_url": "https://api.github.com/users/brson/orgs", + "received_events_url": "https://api.github.com/users/brson/received_events", + "repos_url": "https://api.github.com/users/brson/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/brson/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/brson/subscriptions", + "type": "User", + "url": "https://api.github.com/users/brson" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/5e25dfaef83d1a2855cc4e4a1aecca77ba0dc47a/comments", + "commit": { + "author": { + "date": "2020-05-01T21:34:16Z", + "email": "andersrb@gmail.com", + "name": "Brian Anderson" + }, + "comment_count": 0, + "committer": { + "date": "2020-05-01T21:34:16Z", + "email": "andersrb@gmail.com", + "name": "Brian Anderson" + }, + "message": "Add another tikv stacked borrowing error to trophy case", + "tree": { + "sha": "bbf63e95c9e9eac80d7f92875061c05352759cac", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/bbf63e95c9e9eac80d7f92875061c05352759cac" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/5e25dfaef83d1a2855cc4e4a1aecca77ba0dc47a", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/147214?v=4", + "events_url": "https://api.github.com/users/brson/events{/privacy}", + "followers_url": "https://api.github.com/users/brson/followers", + "following_url": "https://api.github.com/users/brson/following{/other_user}", + "gists_url": "https://api.github.com/users/brson/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/brson", + "id": 147214, + "login": "brson", + "node_id": "MDQ6VXNlcjE0NzIxNA==", + "organizations_url": "https://api.github.com/users/brson/orgs", + "received_events_url": "https://api.github.com/users/brson/received_events", + "repos_url": "https://api.github.com/users/brson/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/brson/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/brson/subscriptions", + "type": "User", + "url": "https://api.github.com/users/brson" + }, + "html_url": "https://github.com/rust-lang/rust/commit/5e25dfaef83d1a2855cc4e4a1aecca77ba0dc47a", + "node_id": "MDY6Q29tbWl0NzI0NzEyOjVlMjVkZmFlZjgzZDFhMjg1NWNjNGU0YTFhZWNjYTc3YmEwZGM0N2E=", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/d606172f32a4ca6c6ce73147760ee0ca1ed439b9", + "sha": "d606172f32a4ca6c6ce73147760ee0ca1ed439b9", + "url": "https://api.github.com/repos/rust-lang/rust/commits/d606172f32a4ca6c6ce73147760ee0ca1ed439b9" + } + ], + "sha": "5e25dfaef83d1a2855cc4e4a1aecca77ba0dc47a", + "url": "https://api.github.com/repos/rust-lang/rust/commits/5e25dfaef83d1a2855cc4e4a1aecca77ba0dc47a" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/147214?v=4", + "events_url": "https://api.github.com/users/brson/events{/privacy}", + "followers_url": "https://api.github.com/users/brson/followers", + "following_url": "https://api.github.com/users/brson/following{/other_user}", + "gists_url": "https://api.github.com/users/brson/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/brson", + "id": 147214, + "login": "brson", + "node_id": "MDQ6VXNlcjE0NzIxNA==", + "organizations_url": "https://api.github.com/users/brson/orgs", + "received_events_url": "https://api.github.com/users/brson/received_events", + "repos_url": "https://api.github.com/users/brson/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/brson/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/brson/subscriptions", + "type": "User", + "url": "https://api.github.com/users/brson" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/488f3801e2a22afb093d03cf176169d91212374c/comments", + "commit": { + "author": { + "date": "2020-04-30T00:03:43Z", + "email": "andersrb@gmail.com", + "name": "Brian Anderson" + }, + "comment_count": 0, + "committer": { + "date": "2020-04-30T00:03:43Z", + "email": "andersrb@gmail.com", + "name": "Brian Anderson" + }, + "message": "Add servo_arc to trophy case", + "tree": { + "sha": "bb1cf8cc877de4c14875aed208aca50321759c7f", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/bb1cf8cc877de4c14875aed208aca50321759c7f" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/488f3801e2a22afb093d03cf176169d91212374c", + "verification": { + "payload": null, + "reason": "unsigned", + "signature": null, + "verified": false + } + }, + "committer": { + "avatar_url": "https://avatars.githubusercontent.com/u/147214?v=4", + "events_url": "https://api.github.com/users/brson/events{/privacy}", + "followers_url": "https://api.github.com/users/brson/followers", + "following_url": "https://api.github.com/users/brson/following{/other_user}", + "gists_url": "https://api.github.com/users/brson/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/brson", + "id": 147214, + "login": "brson", + "node_id": "MDQ6VXNlcjE0NzIxNA==", + "organizations_url": "https://api.github.com/users/brson/orgs", + "received_events_url": "https://api.github.com/users/brson/received_events", + "repos_url": "https://api.github.com/users/brson/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/brson/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/brson/subscriptions", + "type": "User", + "url": "https://api.github.com/users/brson" + }, + "html_url": "https://github.com/rust-lang/rust/commit/488f3801e2a22afb093d03cf176169d91212374c", + "node_id": "MDY6Q29tbWl0NzI0NzEyOjQ4OGYzODAxZTJhMjJhZmIwOTNkMDNjZjE3NjE2OWQ5MTIxMjM3NGM=", + "parents": [ + { + "html_url": "https://github.com/rust-lang/rust/commit/dc91c172a469b51cf038d97e361458cd09b13fbd", + "sha": "dc91c172a469b51cf038d97e361458cd09b13fbd", + "url": "https://api.github.com/repos/rust-lang/rust/commits/dc91c172a469b51cf038d97e361458cd09b13fbd" + } + ], + "sha": "488f3801e2a22afb093d03cf176169d91212374c", + "url": "https://api.github.com/repos/rust-lang/rust/commits/488f3801e2a22afb093d03cf176169d91212374c" + }, + { + "author": { + "avatar_url": "https://avatars.githubusercontent.com/u/147214?v=4", + "events_url": "https://api.github.com/users/brson/events{/privacy}", + "followers_url": "https://api.github.com/users/brson/followers", + "following_url": "https://api.github.com/users/brson/following{/other_user}", + "gists_url": "https://api.github.com/users/brson/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/brson", + "id": 147214, + "login": "brson", + "node_id": "MDQ6VXNlcjE0NzIxNA==", + "organizations_url": "https://api.github.com/users/brson/orgs", + "received_events_url": "https://api.github.com/users/brson/received_events", + "repos_url": "https://api.github.com/users/brson/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/brson/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/brson/subscriptions", + "type": "User", + "url": "https://api.github.com/users/brson" + }, + "comments_url": "https://api.github.com/repos/rust-lang/rust/commits/f84aa4a424221a8b3739f6232fec8f419d176fba/comments", + "commit": { + "author": { + "date": "2020-04-23T08:46:36Z", + "email": "andersrb@gmail.com", + "name": "Brian Anderson" + }, + "comment_count": 0, + "committer": { + "date": "2020-04-23T08:46:36Z", + "email": "noreply@github.com", + "name": "GitHub" + }, + "message": "Update README.md\n\nCo-Authored-By: Ralf Jung ", + "tree": { + "sha": "9ad87c344ce2232649af262bad2e4b10d7b5cddc", + "url": "https://api.github.com/repos/rust-lang/rust/git/trees/9ad87c344ce2232649af262bad2e4b10d7b5cddc" + }, + "url": "https://api.github.com/repos/rust-lang/rust/git/commits/f84aa4a424221a8b3739f6232fec8f419d176fba", + "verification": { + "payload": "tree 9ad87c344ce2232649af262bad2e4b10d7b5cddc\nparent 5b60f0df2afba76fb6bd4cc3ae0c85ea2cfd484c\nauthor Brian Anderson 1587631596 -0600\ncommitter GitHub