Skip to content

Commit b1e9f5d

Browse files
committed
Set up permissions for local development
1 parent c7db500 commit b1e9f5d

File tree

6 files changed

+70
-28
lines changed

6 files changed

+70
-28
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ required.
2323
| `--client-secret` | `OAUTH_CLIENT_SECRET`| | GitHub OAuth client secret for rollup UI (optional). |
2424
| `--db` | `DATABASE_URL` | | Database connection string. Only PostgreSQL is supported. |
2525
| `--cmd-prefix` | `CMD_PREFIX` | @bors | Prefix used to invoke bors commands in PR comments. |
26+
| `--web_url` | `WEB_URL` | http://localhost:8080| Web URL where the bot's website is deployed (optional).|
27+
| `--permissions` | `PERMISSIONS` | Rust Team API url| List of users with permissions to perform try/review (optional).|
2628

2729
### Special branches
2830
The bot uses the following branch names for its operations.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"github_ids": []
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"github_ids": []
3+
}

docs/development.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ One-time setup:
5757
- Subscribe it to webhook events `Issue comment`, `Pull request`, `Pull request review`, `Pull request review comment` and `Workflow run`.
5858
- Install your GitHub app on some test repository where you want to test bors.
5959
- Don't forget to configure `rust-bors.toml` in the root of the repository, and also add some example CI workflows.
60+
- Create try/review permissions for Github users
61+
- Copy a review json file `cp data/permissions/bors.review.json.example data/permissions/bors.review.json`
62+
- Copy a try json file `cp data/permissions/bors.try.json.example data/permissions/bors.try.json`
63+
- Get your Github user `ID` `https://api.github.com/users/<your_github_user_name>`
64+
- Edit both `bors.review.json` and `bors.try.json` files to include your GitHub `ID`: `{ "github_ids": [12345678] }`
6065

6166
Everytime you want to run bors:
6267
- Run bors locally.
@@ -65,6 +70,7 @@ Everytime you want to run bors:
6570
- Set `PRIVATE_KEY` to the private key of the app.
6671
- (optional) Set `WEB_URL` to the public URL of the website of the app.
6772
- (optional) Set `CMD_PREFIX` to the command prefix used to control the bot (e.g. `@bors`).
73+
- (optional) Set `PERMISSIONS` `"data/permissions"` directory path to list users with permissions to perform try/review.
6874
- Set up some globally reachable URL/IP address for your computer, e.g. using [ngrok](https://ngrok.com/).
6975
- Configure the webhook URL for your app to point to `<address>/github`. You can use [gh webhook](https://docs.github.com/en/webhooks/testing-and-troubleshooting-webhooks/using-the-github-cli-to-forward-webhooks-for-testing) for that.
7076
- Try `@bors ping` on some PR on the test repository :)

src/bin/bors.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,14 @@ struct Opts {
7272
/// Web URL where the bot's website is deployed.
7373
#[arg(long, env = "WEB_URL", default_value = "http://localhost:8080")]
7474
web_url: String,
75+
76+
/// Source of list of users with permissions to perform try/review.
77+
#[arg(
78+
long,
79+
env = "PERMISSIONS",
80+
default_value = "https://team-api.infra.rust-lang.org"
81+
)]
82+
permissions: Option<String>,
7583
}
7684

7785
/// Starts a server that receives GitHub webhooks and generates events into a queue
@@ -117,7 +125,8 @@ fn try_main(opts: Opts) -> anyhow::Result<()> {
117125
let db = runtime
118126
.block_on(initialize_db(&opts.db))
119127
.context("Cannot initialize database")?;
120-
let team_api = TeamApiClient::default();
128+
// Unwrap will not panic due to default_value for the 'permissions' argument
129+
let team_api = TeamApiClient::new(opts.permissions.as_deref().unwrap());
121130
let (client, loaded_repos) = runtime.block_on(async {
122131
let client = create_github_client(
123132
opts.app_id.into(),

src/permissions.rs

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,24 @@ pub(crate) struct UserPermissionsResponse {
4848
github_ids: HashSet<UserId>,
4949
}
5050

51+
enum TeamSource {
52+
Url(String),
53+
Directory(String),
54+
}
55+
5156
pub struct TeamApiClient {
52-
base_url: String,
57+
team_source: TeamSource,
5358
}
5459

5560
impl TeamApiClient {
56-
pub(crate) fn new(base_url: impl Into<String>) -> Self {
57-
Self {
58-
base_url: base_url.into(),
59-
}
61+
pub fn new(source: impl Into<String>) -> Self {
62+
let source_str = source.into();
63+
let team_source = if source_str.starts_with("http") {
64+
TeamSource::Url(source_str)
65+
} else {
66+
TeamSource::Directory(source_str)
67+
};
68+
Self { team_source }
6069
}
6170

6271
pub(crate) async fn load_permissions(
@@ -81,7 +90,8 @@ impl TeamApiClient {
8190
})
8291
}
8392

84-
/// Loads users that are allowed to perform try/review from the Rust Team API.
93+
/// Loads users that are allowed to perform try/review from the Rust Team API
94+
/// or from directory for local environment.
8595
async fn load_users(
8696
&self,
8797
repository_name: &str,
@@ -92,26 +102,35 @@ impl TeamApiClient {
92102
PermissionType::Try => "try",
93103
};
94104

95-
let normalized_name = repository_name.replace('-', "_");
96-
let url = format!(
97-
"{}/v1/permissions/bors.{normalized_name}.{permission}.json",
98-
self.base_url
99-
);
100-
let users = reqwest::get(url)
101-
.await
102-
.and_then(|res| res.error_for_status())
103-
.map_err(|error| anyhow::anyhow!("Cannot load users from team API: {error:?}"))?
104-
.json::<UserPermissionsResponse>()
105-
.await
106-
.map_err(|error| {
107-
anyhow::anyhow!("Cannot deserialize users from team API: {error:?}")
108-
})?;
109-
Ok(users.github_ids)
110-
}
111-
}
112-
113-
impl Default for TeamApiClient {
114-
fn default() -> Self {
115-
Self::new("https://team-api.infra.rust-lang.org")
105+
match &self.team_source {
106+
TeamSource::Url(base_url) => {
107+
let normalized_name = repository_name.replace('-', "_");
108+
let url = format!(
109+
"{}/v1/permissions/bors.{normalized_name}.{permission}.json",
110+
base_url
111+
);
112+
let users = reqwest::get(url)
113+
.await
114+
.and_then(|res| res.error_for_status())
115+
.map_err(|error| anyhow::anyhow!("Cannot load users from team API: {error:?}"))?
116+
.json::<UserPermissionsResponse>()
117+
.await
118+
.map_err(|error| {
119+
anyhow::anyhow!("Cannot deserialize users from team API: {error:?}")
120+
})?;
121+
Ok(users.github_ids)
122+
}
123+
TeamSource::Directory(base_path) => {
124+
let path = format!("{base_path}/bors.{permission}.json");
125+
let data = std::fs::read_to_string(&path).map_err(|error| {
126+
anyhow::anyhow!("Could not read users from a file '{path}': {error:?}")
127+
})?;
128+
let users: UserPermissionsResponse =
129+
serde_json::from_str(&data).map_err(|error| {
130+
anyhow::anyhow!("Cannot deserialize users from a file '{path}': {error:?}")
131+
})?;
132+
Ok(users.github_ids)
133+
}
134+
}
116135
}
117136
}

0 commit comments

Comments
 (0)