Skip to content

Tree Closing and Opening #223

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions migrations/20250304172534_add_repository_model.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- Add down migration script here
DROP TABLE IF EXISTS repository;
9 changes: 9 additions & 0 deletions migrations/20250304172534_add_repository_model.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-- Add up migration script here
CREATE TABLE repository
(
id SERIAL PRIMARY KEY,
name TEXT NOT NULL UNIQUE,
tree_state INT NULL,
treeclosed_src TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
4 changes: 4 additions & 0 deletions src/bors/command/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,8 @@ pub enum BorsCommand {
Undelegate,
/// Set the rollup mode of a PRstatus.
SetRollupMode(RollupMode),
/// Open the repository tree for merging.
OpenTree,
/// Set the tree closed with a priority level.
TreeClosed(Priority),
}
65 changes: 64 additions & 1 deletion src/bors/command/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub enum CommandParseError<'a> {
}

/// Part of a command, either a bare string like `try` or a key value like `parent=<sha>`.
#[derive(PartialEq)]
#[derive(PartialEq, Copy, Clone)]
enum CommandPart<'a> {
Bare(&'a str),
KeyValue { key: &'a str, value: &'a str },
Expand Down Expand Up @@ -68,6 +68,7 @@ const PARSERS: &[for<'b> fn(&CommandPart<'b>, &[CommandPart<'b>]) -> ParseResult
parser_info,
parser_help,
parser_ping,
parser_tree_ops,
];

fn parse_command(input: &str) -> ParseResult {
Expand Down Expand Up @@ -313,6 +314,24 @@ fn parser_info<'a>(command: &CommandPart<'a>, _parts: &[CommandPart<'a>]) -> Par
}
}

/// Parses `@bors treeclosed-` and `@bors treeclosed=<priority>`
fn parser_tree_ops<'a>(command: &CommandPart<'a>, _parts: &[CommandPart<'a>]) -> ParseResult<'a> {
match command {
CommandPart::Bare("treeclosed-") => Some(Ok(BorsCommand::OpenTree)),
CommandPart::KeyValue {
key: "treeclosed",
value,
} => {
let priority = match parse_priority_value(value) {
Ok(p) => p,
Err(error) => return Some(Err(error)),
};
Some(Ok(BorsCommand::TreeClosed(priority)))
}
_ => None,
}
}

#[cfg(test)]
mod tests {
use crate::bors::command::parser::{CommandParseError, CommandParser};
Expand Down Expand Up @@ -1010,6 +1029,50 @@ line two
assert_eq!(cmds[0], Ok(BorsCommand::Delegate));
}

#[test]
fn parse_tree_closed() {
let cmds = parse_commands("@bors treeclosed=5");
assert_eq!(cmds.len(), 1);
assert_eq!(cmds[0], Ok(BorsCommand::TreeClosed(5)));
}

#[test]
fn parse_tree_closed_invalid() {
let cmds = parse_commands("@bors treeclosed=abc");
assert_eq!(cmds.len(), 1);
assert!(matches!(
cmds[0],
Err(CommandParseError::ValidationError(_))
));
}

#[test]
fn parse_tree_closed_empty() {
let cmds = parse_commands("@bors treeclosed=");
assert_eq!(cmds.len(), 1);
assert!(matches!(
cmds[0],
Err(CommandParseError::MissingArgValue { arg: "treeclosed" })
));
}

#[test]
fn parse_tree_closed_minus() {
let cmds = parse_commands("@bors treeclosed-");
assert_eq!(cmds.len(), 1);
assert_eq!(cmds[0], Ok(BorsCommand::OpenTree));
}

#[test]
fn parse_tree_closed_unknown_command() {
let cmds = parse_commands("@bors tree closed 5");
assert_eq!(cmds.len(), 1);
assert!(matches!(
cmds[0],
Err(CommandParseError::UnknownCommand("tree"))
));
}

fn parse_commands(text: &str) -> Vec<Result<BorsCommand, CommandParseError>> {
CommandParser::new("@bors".to_string()).parse_commands(text)
}
Expand Down
1 change: 1 addition & 0 deletions src/bors/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ pub struct PullRequestComment {
pub author: GithubUser,
pub pr_number: PullRequestNumber,
pub text: String,
pub html_url: String,
}

#[derive(Debug)]
Expand Down
11 changes: 10 additions & 1 deletion src/bors/handlers/help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ pub(super) async fn command_help(
BorsCommand::Info,
BorsCommand::Ping,
BorsCommand::Help,
BorsCommand::OpenTree,
BorsCommand::TreeClosed(0),
]
.into_iter()
.map(|help| format!("- {}", get_command_help(help)))
Expand Down Expand Up @@ -83,7 +85,12 @@ fn get_command_help(command: BorsCommand) -> String {
BorsCommand::Info => {
"`info`: Get information about the current PR including delegation, priority, merge status, and try build status"
}

BorsCommand::OpenTree => {
"`treeclosed-`: Open the repository tree for merging"
}
BorsCommand::TreeClosed(_) => {
"`treeclosed=<priority>`: Close the tree for PRs with priority less than `<priority>`"
}
};
help.to_string()
}
Expand All @@ -109,6 +116,8 @@ mod tests {
- `info`: Get information about the current PR including delegation, priority, merge status, and try build status
- `ping`: Check if the bot is alive
- `help`: Print this help message
- `treeclosed-`: Open the repository tree for merging
- `treeclosed=<priority>`: Close the tree for PRs with priority less than `<priority>`
");
Ok(tester)
})
Expand Down
24 changes: 22 additions & 2 deletions src/bors/handlers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ use crate::bors::handlers::help::command_help;
use crate::bors::handlers::info::command_info;
use crate::bors::handlers::ping::command_ping;
use crate::bors::handlers::refresh::refresh_repository;
use crate::bors::handlers::review::{command_approve, command_unapprove};
use crate::bors::handlers::review::{
command_approve, command_close_tree, command_open_tree, command_unapprove,
};
use crate::bors::handlers::trybuild::{command_try_build, command_try_cancel, TRY_BRANCH_NAME};
use crate::bors::handlers::workflow::{
handle_check_suite_completed, handle_workflow_completed, handle_workflow_started,
Expand Down Expand Up @@ -86,7 +88,6 @@ pub async fn handle_bors_repository_event(
return Err(error.context("Cannot perform command"));
}
}

BorsRepositoryEvent::WorkflowStarted(payload) => {
let span = tracing::info_span!(
"Workflow started",
Expand Down Expand Up @@ -227,6 +228,25 @@ async fn handle_comment(
.instrument(span)
.await
}
BorsCommand::OpenTree => {
let span = tracing::info_span!("TreeOpen");
command_open_tree(repo, database, &pull_request, &comment.author)
.instrument(span)
.await
}
BorsCommand::TreeClosed(priority) => {
let span = tracing::info_span!("TreeClosed");
command_close_tree(
repo,
database,
&pull_request,
&comment.author,
priority,
&comment.html_url,
)
.instrument(span)
.await
}
BorsCommand::Unapprove => {
let span = tracing::info_span!("Unapprove");
command_unapprove(repo, database, &pull_request, &comment.author)
Expand Down
Loading