forked from the-distro/ofborg
Merge pull request #53 from NixOS/review-comments-issue-49
Review comments issue 49
This commit is contained in:
commit
79f83cc206
|
@ -378,9 +378,9 @@ let kernel = buildPlatform.parsed.kernel.name;
|
|||
sha256 = "1y6qnd9r8ga6y8mvlabdrr73nc8cshjjlzbvnanzyj9b8zzkfwk2";
|
||||
inherit dependencies buildDependencies features;
|
||||
};
|
||||
ofborg_0_1_0_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate {
|
||||
ofborg_0_1_1_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate {
|
||||
crateName = "ofborg";
|
||||
version = "0.1.0";
|
||||
version = "0.1.1";
|
||||
authors = [ "Graham Christensen <graham@grahamc.com>" ];
|
||||
src = ./../ofborg;
|
||||
inherit dependencies buildDependencies features;
|
||||
|
@ -1048,24 +1048,24 @@ rec {
|
|||
dependencies = [ libc_0_2_36 ];
|
||||
};
|
||||
libc_0_2_36_features."default".from_num_cpus_1_8_0__default = true;
|
||||
ofborg_0_1_0 = ofborg_0_1_0_ rec {
|
||||
ofborg_0_1_1 = ofborg_0_1_1_ rec {
|
||||
dependencies = [ amqp_0_1_0 env_logger_0_4_3 fs2_0_4_3 hubcaps_0_3_16 hyper_0_10_13 hyper_native_tls_0_2_4 log_0_3_8 lru_cache_0_1_1 md5_0_3_6 serde_1_0_27 serde_derive_1_0_27 serde_json_1_0_9 tempfile_2_2_0 uuid_0_4_0 ];
|
||||
};
|
||||
amqp_0_1_0_features."default".from_ofborg_0_1_0__default = true;
|
||||
env_logger_0_4_3_features."default".from_ofborg_0_1_0__default = true;
|
||||
fs2_0_4_3_features."default".from_ofborg_0_1_0__default = true;
|
||||
hubcaps_0_3_16_features."default".from_ofborg_0_1_0__default = true;
|
||||
hyper_0_10_13_features."default".from_ofborg_0_1_0__default = true;
|
||||
hyper_native_tls_0_2_4_features."default".from_ofborg_0_1_0__default = true;
|
||||
log_0_3_8_features."default".from_ofborg_0_1_0__default = true;
|
||||
lru_cache_0_1_1_features."default".from_ofborg_0_1_0__default = true;
|
||||
md5_0_3_6_features."default".from_ofborg_0_1_0__default = true;
|
||||
serde_1_0_27_features."default".from_ofborg_0_1_0__default = true;
|
||||
serde_derive_1_0_27_features."default".from_ofborg_0_1_0__default = true;
|
||||
serde_json_1_0_9_features."default".from_ofborg_0_1_0__default = true;
|
||||
tempfile_2_2_0_features."default".from_ofborg_0_1_0__default = true;
|
||||
uuid_0_4_0_features."v4".from_ofborg_0_1_0 = true;
|
||||
uuid_0_4_0_features."default".from_ofborg_0_1_0__default = true;
|
||||
amqp_0_1_0_features."default".from_ofborg_0_1_1__default = true;
|
||||
env_logger_0_4_3_features."default".from_ofborg_0_1_1__default = true;
|
||||
fs2_0_4_3_features."default".from_ofborg_0_1_1__default = true;
|
||||
hubcaps_0_3_16_features."default".from_ofborg_0_1_1__default = true;
|
||||
hyper_0_10_13_features."default".from_ofborg_0_1_1__default = true;
|
||||
hyper_native_tls_0_2_4_features."default".from_ofborg_0_1_1__default = true;
|
||||
log_0_3_8_features."default".from_ofborg_0_1_1__default = true;
|
||||
lru_cache_0_1_1_features."default".from_ofborg_0_1_1__default = true;
|
||||
md5_0_3_6_features."default".from_ofborg_0_1_1__default = true;
|
||||
serde_1_0_27_features."default".from_ofborg_0_1_1__default = true;
|
||||
serde_derive_1_0_27_features."default".from_ofborg_0_1_1__default = true;
|
||||
serde_json_1_0_9_features."default".from_ofborg_0_1_1__default = true;
|
||||
tempfile_2_2_0_features."default".from_ofborg_0_1_1__default = true;
|
||||
uuid_0_4_0_features."v4".from_ofborg_0_1_1 = true;
|
||||
uuid_0_4_0_features."default".from_ofborg_0_1_1__default = true;
|
||||
openssl_0_9_23 = openssl_0_9_23_ rec {
|
||||
dependencies = [ bitflags_0_9_1 foreign_types_0_3_2 lazy_static_1_0_0 libc_0_2_36 openssl_sys_0_9_24 ];
|
||||
features = mkFeatures openssl_0_9_23_features;
|
||||
|
|
2
ofborg/Cargo.lock
generated
2
ofborg/Cargo.lock
generated
|
@ -374,7 +374,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ofborg"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
dependencies = [
|
||||
"amqp 0.1.0 (git+https://github.com/grahamc/rust-amqp.git)",
|
||||
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "ofborg"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
authors = ["Graham Christensen <graham@grahamc.com>"]
|
||||
|
||||
[dependencies]
|
||||
|
|
89
ofborg/src/bin/github-comment-poster.rs
Normal file
89
ofborg/src/bin/github-comment-poster.rs
Normal file
|
@ -0,0 +1,89 @@
|
|||
extern crate ofborg;
|
||||
extern crate amqp;
|
||||
extern crate env_logger;
|
||||
|
||||
extern crate hyper;
|
||||
extern crate hubcaps;
|
||||
extern crate hyper_native_tls;
|
||||
|
||||
|
||||
use std::env;
|
||||
|
||||
use amqp::Basic;
|
||||
|
||||
use ofborg::config;
|
||||
use ofborg::worker;
|
||||
use ofborg::tasks;
|
||||
use ofborg::easyamqp;
|
||||
use ofborg::easyamqp::TypedWrappers;
|
||||
|
||||
|
||||
fn main() {
|
||||
let cfg = config::load(env::args().nth(1).unwrap().as_ref());
|
||||
ofborg::setup_log();
|
||||
|
||||
let mut session = easyamqp::session_from_config(&cfg.rabbitmq).unwrap();
|
||||
let mut channel = session.open_channel(1).unwrap();
|
||||
|
||||
channel
|
||||
.declare_exchange(easyamqp::ExchangeConfig {
|
||||
exchange: "build-results".to_owned(),
|
||||
exchange_type: easyamqp::ExchangeType::Fanout,
|
||||
passive: false,
|
||||
durable: true,
|
||||
auto_delete: false,
|
||||
no_wait: false,
|
||||
internal: false,
|
||||
arguments: None,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
channel
|
||||
.declare_queue(easyamqp::QueueConfig {
|
||||
queue: "build-results".to_owned(),
|
||||
passive: false,
|
||||
durable: true,
|
||||
exclusive: false,
|
||||
auto_delete: false,
|
||||
no_wait: false,
|
||||
arguments: None,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
channel
|
||||
.bind_queue(easyamqp::BindQueueConfig {
|
||||
queue: "build-results".to_owned(),
|
||||
exchange: "build-results".to_owned(),
|
||||
routing_key: None,
|
||||
no_wait: false,
|
||||
arguments: None,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
channel.basic_prefetch(1).unwrap();
|
||||
channel
|
||||
.consume(
|
||||
worker::new(tasks::githubcommentposter::GitHubCommentPoster::new(
|
||||
cfg.github(),
|
||||
)),
|
||||
easyamqp::ConsumeConfig {
|
||||
queue: "build-results".to_owned(),
|
||||
consumer_tag: format!("{}-github-comment-poster", cfg.whoami()),
|
||||
no_local: false,
|
||||
no_ack: false,
|
||||
no_wait: false,
|
||||
exclusive: false,
|
||||
arguments: None,
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
channel.start_consuming();
|
||||
|
||||
println!("Finished consuming?");
|
||||
|
||||
channel.close(200, "Bye").unwrap();
|
||||
println!("Closed the channel");
|
||||
session.close(200, "Good Bye");
|
||||
println!("Closed the session... EOF");
|
||||
}
|
|
@ -48,6 +48,53 @@ pub struct ConsumeConfig {
|
|||
pub arguments: Option<amqp::Table>,
|
||||
}
|
||||
|
||||
pub struct BindQueueConfig {
|
||||
/// Specifies the name of the queue to bind.
|
||||
///
|
||||
/// The client MUST either specify a queue name or have previously
|
||||
/// declared a queue on the same channel Error code: not-found
|
||||
///
|
||||
/// The client MUST NOT attempt to bind a queue that does not
|
||||
/// exist. Error code: not-found
|
||||
pub queue: String,
|
||||
|
||||
/// Name of the exchange to bind to.
|
||||
///
|
||||
/// A client MUST NOT be allowed to bind a queue to a non-existent
|
||||
/// exchange. Error code: not-found
|
||||
///
|
||||
/// The server MUST accept a blank exchange name to mean the
|
||||
/// default exchange.
|
||||
pub exchange: String,
|
||||
|
||||
/// Specifies the routing key for the binding. The routing key is
|
||||
/// used for routing messages depending on the exchange
|
||||
/// configuration. Not all exchanges use a routing key - refer to
|
||||
/// the specific exchange documentation. If the queue name is
|
||||
/// empty, the server uses the last queue declared on the channel.
|
||||
/// If the routing key is also empty, the server uses this queue
|
||||
/// name for the routing key as well. If the queue name is
|
||||
/// provided but the routing key is empty, the server does the
|
||||
/// binding with that empty routing key. The meaning of empty
|
||||
/// routing keys depends on the exchange implementation.
|
||||
///
|
||||
/// If a message queue binds to a direct exchange using routing
|
||||
/// key K and a publisher sends the exchange a message with
|
||||
/// routing key R, then the message MUST be passed to the message
|
||||
/// queue if K = R.
|
||||
pub routing_key: Option<String>,
|
||||
|
||||
/// If set, the server will not respond to the method. The client
|
||||
/// should not wait for a reply method. If the server could not
|
||||
/// complete the method it will raise a channel or connection
|
||||
/// exception.
|
||||
pub no_wait: bool,
|
||||
|
||||
/// A set of arguments for the binding. The syntax and semantics
|
||||
/// of these arguments depends on the exchange class.
|
||||
pub arguments: Option<amqp::Table>,
|
||||
}
|
||||
|
||||
pub enum ExchangeType {
|
||||
Topic,
|
||||
Headers,
|
||||
|
@ -78,7 +125,7 @@ pub struct ExchangeConfig {
|
|||
/// The exchange name consists of a non-empty sequence of these
|
||||
/// characters: letters, digits, hyphen, underscore, period, or
|
||||
/// colon. Error code: precondition-failed
|
||||
exchange: String,
|
||||
pub exchange: String,
|
||||
|
||||
/// Each exchange belongs to one of a set of exchange types
|
||||
/// implemented by the server. The exchange types define the
|
||||
|
@ -93,7 +140,7 @@ pub struct ExchangeConfig {
|
|||
///
|
||||
/// The client MUST NOT attempt to declare an exchange with a type
|
||||
/// that the server does not support. Error code: command-invalid
|
||||
exchange_type: ExchangeType,
|
||||
pub exchange_type: ExchangeType,
|
||||
|
||||
/// If set, the server will reply with Declare-Ok if the exchange
|
||||
/// already exists with the same name, and raise an error if not.
|
||||
|
@ -112,7 +159,7 @@ pub struct ExchangeConfig {
|
|||
/// and arguments fields. The server MUST respond with Declare-Ok
|
||||
/// if the requested exchange matches these fields, and MUST raise
|
||||
/// a channel exception if not.
|
||||
passive: bool,
|
||||
pub passive: bool,
|
||||
|
||||
/// If set when creating a new exchange, the exchange will be
|
||||
/// marked as durable. Durable exchanges remain active when a
|
||||
|
@ -120,7 +167,7 @@ pub struct ExchangeConfig {
|
|||
/// are purged if/when a server restarts.
|
||||
///
|
||||
/// The server MUST support both durable and transient exchanges.
|
||||
durable: bool,
|
||||
pub durable: bool,
|
||||
|
||||
/// If set, the exchange is deleted when all queues have finished
|
||||
/// using it.
|
||||
|
@ -134,23 +181,105 @@ pub struct ExchangeConfig {
|
|||
///
|
||||
/// The server MUST ignore the auto-delete field if the exchange
|
||||
/// already exists.
|
||||
auto_delete: bool,
|
||||
pub auto_delete: bool,
|
||||
|
||||
/// If set, the exchange may not be used directly by publishers,
|
||||
/// but only when bound to other exchanges. Internal exchanges are
|
||||
/// used to construct wiring that is not visible to applications.
|
||||
internal: bool,
|
||||
pub internal: bool,
|
||||
|
||||
/// If set, the server will not respond to the method. The client
|
||||
/// should not wait for a reply method. If the server could not
|
||||
/// complete the method it will raise a channel or connection
|
||||
/// exception.
|
||||
nowait: bool,
|
||||
pub no_wait: bool,
|
||||
|
||||
/// A set of arguments for the declaration. The syntax and
|
||||
/// semantics of these arguments depends on the server
|
||||
/// implementation.
|
||||
arguments: Option<amqp::Table>,
|
||||
pub arguments: Option<amqp::Table>,
|
||||
}
|
||||
|
||||
pub struct QueueConfig {
|
||||
/// The queue name MAY be empty, in which case the server MUST
|
||||
/// create a new queue with a unique generated name and return
|
||||
/// this to the client in the Declare-Ok method.
|
||||
///
|
||||
/// Queue names starting with "amq." are reserved for pre-declared
|
||||
/// and standardised queues. The client MAY declare a queue
|
||||
/// starting with "amq." if the passive option is set, or the
|
||||
/// queue already exists. Error code: access-refused
|
||||
///
|
||||
/// The queue name can be empty, or a sequence of these
|
||||
/// characters: letters, digits, hyphen, underscore, period, or
|
||||
/// colon. Error code: precondition-failed
|
||||
pub queue: String,
|
||||
|
||||
/// If set, the server will reply with Declare-Ok if the queue
|
||||
/// already exists with the same name, and raise an error if not.
|
||||
/// The client can use this to check whether a queue exists
|
||||
/// without modifying the server state. When set, all other
|
||||
/// method fields except name and no-wait are ignored. A declare
|
||||
/// with both passive and no-wait has no effect. Arguments are
|
||||
/// compared for semantic equivalence.
|
||||
///
|
||||
/// The client MAY ask the server to assert that a queue exists
|
||||
/// without creating the queue if not. If the queue does not
|
||||
/// exist, the server treats this as a failure. Error code:
|
||||
/// not-found
|
||||
///
|
||||
/// If not set and the queue exists, the server MUST check that
|
||||
/// the existing queue has the same values for durable, exclusive,
|
||||
/// auto-delete, and arguments fields. The server MUST respond
|
||||
/// with Declare-Ok if the requested queue matches these fields,
|
||||
/// and MUST raise a channel exception if not.
|
||||
pub passive: bool,
|
||||
|
||||
/// If set when creating a new queue, the queue will be marked as
|
||||
/// durable. Durable queues remain active when a server restarts.
|
||||
/// Non-durable queues (transient queues) are purged if/when a
|
||||
/// server restarts. Note that durable queues do not necessarily
|
||||
/// hold persistent messages, although it does not make sense to
|
||||
/// send persistent messages to a transient queue.
|
||||
///
|
||||
/// The server MUST recreate the durable queue after a restart.
|
||||
///
|
||||
/// The server MUST support both durable and transient queues.
|
||||
pub durable: bool,
|
||||
|
||||
/// Exclusive queues may only be accessed by the current
|
||||
/// connection, and are deleted when that connection closes.
|
||||
/// Passive declaration of an exclusive queue by other connections
|
||||
/// are not allowed.
|
||||
///
|
||||
/// The server MUST support both exclusive (private) and
|
||||
/// non-exclusive (shared) queues.
|
||||
/// The client MAY NOT attempt to use a queue that was declared as
|
||||
/// exclusive by another still-open connection. Error code:
|
||||
/// resource-locked
|
||||
pub exclusive: bool,
|
||||
|
||||
/// If set, the queue is deleted when all consumers have finished
|
||||
/// using it. The last consumer can be cancelled either explicitly
|
||||
/// or because its channel is closed. If there was no consumer
|
||||
/// ever on the queue, it won't be deleted. Applications can
|
||||
/// explicitly delete auto-delete queues using the Delete method
|
||||
/// as normal.
|
||||
///
|
||||
/// The server MUST ignore the auto-delete field if the queue
|
||||
/// already exists.
|
||||
pub auto_delete: bool,
|
||||
|
||||
/// If set, the server will not respond to the method. The client
|
||||
/// should not wait for a reply method. If the server could not
|
||||
/// complete the method it will raise a channel or connection
|
||||
/// exception.
|
||||
pub no_wait: bool,
|
||||
|
||||
/// A set of arguments for the declaration. The syntax and
|
||||
/// semantics of these arguments depends on the server
|
||||
/// implementation.
|
||||
pub arguments: Option<amqp::Table>,
|
||||
}
|
||||
|
||||
pub fn session_from_config(config: &RabbitMQConfig) -> Result<amqp::Session, amqp::AMQPError> {
|
||||
|
@ -191,12 +320,20 @@ pub trait TypedWrappers {
|
|||
where
|
||||
T: amqp::Consumer + 'static;
|
||||
|
||||
fn declare_exchange<T>(
|
||||
fn declare_exchange(
|
||||
&mut self,
|
||||
config: ExchangeConfig,
|
||||
) -> Result<amqp::protocol::exchange::DeclareOk, amqp::AMQPError>
|
||||
where
|
||||
T: amqp::Consumer + 'static;
|
||||
) -> Result<amqp::protocol::exchange::DeclareOk, amqp::AMQPError>;
|
||||
|
||||
fn declare_queue(
|
||||
&mut self,
|
||||
config: QueueConfig,
|
||||
) -> Result<amqp::protocol::queue::DeclareOk, amqp::AMQPError>;
|
||||
|
||||
fn bind_queue(
|
||||
&mut self,
|
||||
config: BindQueueConfig,
|
||||
) -> Result<amqp::protocol::queue::BindOk, amqp::AMQPError>;
|
||||
}
|
||||
|
||||
impl TypedWrappers for amqp::Channel {
|
||||
|
@ -216,13 +353,10 @@ impl TypedWrappers for amqp::Channel {
|
|||
)
|
||||
}
|
||||
|
||||
fn declare_exchange<T>(
|
||||
fn declare_exchange(
|
||||
&mut self,
|
||||
config: ExchangeConfig,
|
||||
) -> Result<amqp::protocol::exchange::DeclareOk, amqp::AMQPError>
|
||||
where
|
||||
T: amqp::Consumer + 'static,
|
||||
{
|
||||
) -> Result<amqp::protocol::exchange::DeclareOk, amqp::AMQPError> {
|
||||
self.exchange_declare(
|
||||
config.exchange,
|
||||
config.exchange_type.into(),
|
||||
|
@ -230,7 +364,36 @@ impl TypedWrappers for amqp::Channel {
|
|||
config.durable,
|
||||
config.auto_delete,
|
||||
config.internal,
|
||||
config.nowait,
|
||||
config.no_wait,
|
||||
config.arguments.unwrap_or(amqp::Table::new()),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
fn declare_queue(
|
||||
&mut self,
|
||||
config: QueueConfig,
|
||||
) -> Result<amqp::protocol::queue::DeclareOk, amqp::AMQPError> {
|
||||
self.queue_declare(
|
||||
config.queue,
|
||||
config.passive,
|
||||
config.durable,
|
||||
config.exclusive,
|
||||
config.auto_delete,
|
||||
config.no_wait,
|
||||
config.arguments.unwrap_or(amqp::Table::new()),
|
||||
)
|
||||
}
|
||||
|
||||
fn bind_queue(
|
||||
&mut self,
|
||||
config: BindQueueConfig,
|
||||
) -> Result<amqp::protocol::queue::BindOk, amqp::AMQPError> {
|
||||
self.queue_bind(
|
||||
config.queue,
|
||||
config.exchange,
|
||||
config.routing_key.unwrap_or("".to_owned()),
|
||||
config.no_wait,
|
||||
config.arguments.unwrap_or(amqp::Table::new()),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -6,5 +6,6 @@ pub struct BuildResult {
|
|||
pub pr: Pr,
|
||||
pub system: String,
|
||||
pub output: Vec<String>,
|
||||
pub attempt_id: Option<String>,
|
||||
pub success: bool,
|
||||
}
|
||||
|
|
|
@ -111,7 +111,7 @@ impl<'a, 'b> JobActions<'a, 'b> {
|
|||
pr: self.job.pr.clone(),
|
||||
system: self.system.clone(),
|
||||
output: vec![String::from("Merge failed")],
|
||||
|
||||
attempt_id: Some(self.attempt_id.clone()),
|
||||
success: false,
|
||||
};
|
||||
|
||||
|
@ -171,6 +171,7 @@ impl<'a, 'b> JobActions<'a, 'b> {
|
|||
pr: self.job.pr.clone(),
|
||||
system: self.system.clone(),
|
||||
output: lines,
|
||||
attempt_id: Some(self.attempt_id.clone()),
|
||||
success: success,
|
||||
};
|
||||
|
||||
|
|
276
ofborg/src/tasks/githubcommentposter.rs
Normal file
276
ofborg/src/tasks/githubcommentposter.rs
Normal file
|
@ -0,0 +1,276 @@
|
|||
extern crate amqp;
|
||||
extern crate env_logger;
|
||||
|
||||
use serde_json;
|
||||
|
||||
use hubcaps;
|
||||
use ofborg::message::buildresult::BuildResult;
|
||||
use ofborg::worker;
|
||||
use amqp::protocol::basic::{Deliver, BasicProperties};
|
||||
|
||||
|
||||
pub struct GitHubCommentPoster {
|
||||
github: hubcaps::Github,
|
||||
}
|
||||
|
||||
impl GitHubCommentPoster {
|
||||
pub fn new(github: hubcaps::Github) -> GitHubCommentPoster {
|
||||
return GitHubCommentPoster { github: github };
|
||||
}
|
||||
}
|
||||
|
||||
impl worker::SimpleWorker for GitHubCommentPoster {
|
||||
type J = BuildResult;
|
||||
|
||||
fn msg_to_job(
|
||||
&mut self,
|
||||
_: &Deliver,
|
||||
_: &BasicProperties,
|
||||
body: &Vec<u8>,
|
||||
) -> Result<Self::J, String> {
|
||||
return match serde_json::from_slice(body) {
|
||||
Ok(e) => Ok(e),
|
||||
Err(e) => {
|
||||
Err(format!(
|
||||
"Failed to deserialize BuildResult: {:?}, err: {:}",
|
||||
String::from_utf8_lossy(&body.clone()),
|
||||
e
|
||||
))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn consumer(&mut self, job: &BuildResult) -> worker::Actions {
|
||||
let comment = hubcaps::comments::CommentOptions { body: result_to_comment(&job) };
|
||||
|
||||
let comment_attempt = self.github
|
||||
.repo(job.repo.owner.clone(), job.repo.name.clone())
|
||||
.pulls()
|
||||
.get(job.pr.number)
|
||||
.comments()
|
||||
.create(&comment);
|
||||
|
||||
match comment_attempt {
|
||||
Ok(comment) => {
|
||||
info!(
|
||||
"Successfully sent {:?} to {}",
|
||||
comment,
|
||||
job.pr.number,
|
||||
)
|
||||
}
|
||||
Err(err) => {
|
||||
info!(
|
||||
"Failed to send comment {:?} to {}",
|
||||
err,
|
||||
job.pr.number,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return vec![worker::Action::Ack];
|
||||
}
|
||||
}
|
||||
|
||||
fn result_to_comment(result: &BuildResult) -> String {
|
||||
let mut reply: Vec<String> = vec![];
|
||||
|
||||
reply.push(format!(
|
||||
"{} on {} [(full log)](https://logs.nix.gsc.io/?key={}/{}.{}&attempt_id={})",
|
||||
(match result.success {
|
||||
true => "Success",
|
||||
false => "Failure",
|
||||
}),
|
||||
result.system,
|
||||
&result.repo.owner.to_lowercase(),
|
||||
&result.repo.name.to_lowercase(),
|
||||
result.pr.number,
|
||||
(match result.attempt_id {
|
||||
Some(ref attempt_id) => &attempt_id,
|
||||
None => "none",
|
||||
})
|
||||
));
|
||||
reply.push("".to_owned());
|
||||
reply.push(
|
||||
"<details><summary>Partial log (click to expand)</summary><p>".to_owned(),
|
||||
);
|
||||
reply.push("".to_owned());
|
||||
reply.push("```".to_owned());
|
||||
reply.extend(result.output.clone());
|
||||
reply.push("```".to_owned());
|
||||
reply.push("</p></details>".to_owned());
|
||||
reply.push("".to_owned());
|
||||
reply.push("".to_owned());
|
||||
|
||||
reply.join("\n")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use message::{Pr, Repo};
|
||||
|
||||
#[test]
|
||||
pub fn test_passing_build() {
|
||||
let result = BuildResult {
|
||||
repo: Repo {
|
||||
clone_url: "https://github.com/nixos/nixpkgs.git".to_owned(),
|
||||
full_name: "NixOS/nixpkgs".to_owned(),
|
||||
owner: "NixOS".to_owned(),
|
||||
name: "nixpkgs".to_owned(),
|
||||
},
|
||||
pr: Pr {
|
||||
head_sha: "abc123".to_owned(),
|
||||
number: 2345,
|
||||
target_branch: Some("master".to_owned()),
|
||||
},
|
||||
output: vec![
|
||||
"make[2]: Entering directory '/private/tmp/nix-build-gdb-8.1.drv-0/gdb-8.1/readline'".to_owned(),
|
||||
"make[2]: Nothing to be done for 'install'.".to_owned(),
|
||||
"make[2]: Leaving directory '/private/tmp/nix-build-gdb-8.1.drv-0/gdb-8.1/readline'".to_owned(),
|
||||
"make[1]: Nothing to be done for 'install-target'.".to_owned(),
|
||||
"make[1]: Leaving directory '/private/tmp/nix-build-gdb-8.1.drv-0/gdb-8.1'".to_owned(),
|
||||
"removed '/nix/store/pcja75y9isdvgz5i00pkrpif9rxzxc29-gdb-8.1/share/info/bfd.info'".to_owned(),
|
||||
"post-installation fixup".to_owned(),
|
||||
"strip is /nix/store/5a88zk3jgimdmzg8rfhvm93kxib3njf9-cctools-binutils-darwin/bin/strip".to_owned(),
|
||||
"patching script interpreter paths in /nix/store/pcja75y9isdvgz5i00pkrpif9rxzxc29-gdb-8.1".to_owned(),
|
||||
"/nix/store/pcja75y9isdvgz5i00pkrpif9rxzxc29-gdb-8.1".to_owned(),
|
||||
],
|
||||
attempt_id: Some("neatattemptid".to_owned()),
|
||||
system: "x86_64-linux".to_owned(),
|
||||
success: true,
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
&result_to_comment(&result),
|
||||
"Success on x86_64-linux [(full log)](https://logs.nix.gsc.io/?key=nixos/nixpkgs.2345&attempt_id=neatattemptid)
|
||||
|
||||
<details><summary>Partial log (click to expand)</summary><p>
|
||||
|
||||
```
|
||||
make[2]: Entering directory '/private/tmp/nix-build-gdb-8.1.drv-0/gdb-8.1/readline'
|
||||
make[2]: Nothing to be done for 'install'.
|
||||
make[2]: Leaving directory '/private/tmp/nix-build-gdb-8.1.drv-0/gdb-8.1/readline'
|
||||
make[1]: Nothing to be done for 'install-target'.
|
||||
make[1]: Leaving directory '/private/tmp/nix-build-gdb-8.1.drv-0/gdb-8.1'
|
||||
removed '/nix/store/pcja75y9isdvgz5i00pkrpif9rxzxc29-gdb-8.1/share/info/bfd.info'
|
||||
post-installation fixup
|
||||
strip is /nix/store/5a88zk3jgimdmzg8rfhvm93kxib3njf9-cctools-binutils-darwin/bin/strip
|
||||
patching script interpreter paths in /nix/store/pcja75y9isdvgz5i00pkrpif9rxzxc29-gdb-8.1
|
||||
/nix/store/pcja75y9isdvgz5i00pkrpif9rxzxc29-gdb-8.1
|
||||
```
|
||||
</p></details>
|
||||
|
||||
"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_failing_build() {
|
||||
let result = BuildResult {
|
||||
repo: Repo {
|
||||
clone_url: "https://github.com/nixos/nixpkgs.git".to_owned(),
|
||||
full_name: "NixOS/nixpkgs".to_owned(),
|
||||
owner: "NixOS".to_owned(),
|
||||
name: "nixpkgs".to_owned(),
|
||||
},
|
||||
pr: Pr {
|
||||
head_sha: "abc123".to_owned(),
|
||||
number: 2345,
|
||||
target_branch: Some("master".to_owned()),
|
||||
},
|
||||
output: vec![
|
||||
"make[2]: Entering directory '/private/tmp/nix-build-gdb-8.1.drv-0/gdb-8.1/readline'".to_owned(),
|
||||
"make[2]: Nothing to be done for 'install'.".to_owned(),
|
||||
"make[2]: Leaving directory '/private/tmp/nix-build-gdb-8.1.drv-0/gdb-8.1/readline'".to_owned(),
|
||||
"make[1]: Nothing to be done for 'install-target'.".to_owned(),
|
||||
"make[1]: Leaving directory '/private/tmp/nix-build-gdb-8.1.drv-0/gdb-8.1'".to_owned(),
|
||||
"removed '/nix/store/pcja75y9isdvgz5i00pkrpif9rxzxc29-gdb-8.1/share/info/bfd.info'".to_owned(),
|
||||
"post-installation fixup".to_owned(),
|
||||
"strip is /nix/store/5a88zk3jgimdmzg8rfhvm93kxib3njf9-cctools-binutils-darwin/bin/strip".to_owned(),
|
||||
"patching script interpreter paths in /nix/store/pcja75y9isdvgz5i00pkrpif9rxzxc29-gdb-8.1".to_owned(),
|
||||
"/nix/store/pcja75y9isdvgz5i00pkrpif9rxzxc29-gdb-8.1".to_owned(),
|
||||
],
|
||||
attempt_id: Some("neatattemptid".to_owned()),
|
||||
system: "x86_64-linux".to_owned(),
|
||||
success: false,
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
&result_to_comment(&result),
|
||||
"Failure on x86_64-linux [(full log)](https://logs.nix.gsc.io/?key=nixos/nixpkgs.2345&attempt_id=neatattemptid)
|
||||
|
||||
<details><summary>Partial log (click to expand)</summary><p>
|
||||
|
||||
```
|
||||
make[2]: Entering directory '/private/tmp/nix-build-gdb-8.1.drv-0/gdb-8.1/readline'
|
||||
make[2]: Nothing to be done for 'install'.
|
||||
make[2]: Leaving directory '/private/tmp/nix-build-gdb-8.1.drv-0/gdb-8.1/readline'
|
||||
make[1]: Nothing to be done for 'install-target'.
|
||||
make[1]: Leaving directory '/private/tmp/nix-build-gdb-8.1.drv-0/gdb-8.1'
|
||||
removed '/nix/store/pcja75y9isdvgz5i00pkrpif9rxzxc29-gdb-8.1/share/info/bfd.info'
|
||||
post-installation fixup
|
||||
strip is /nix/store/5a88zk3jgimdmzg8rfhvm93kxib3njf9-cctools-binutils-darwin/bin/strip
|
||||
patching script interpreter paths in /nix/store/pcja75y9isdvgz5i00pkrpif9rxzxc29-gdb-8.1
|
||||
/nix/store/pcja75y9isdvgz5i00pkrpif9rxzxc29-gdb-8.1
|
||||
```
|
||||
</p></details>
|
||||
|
||||
"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_failing_build_no_attempt_id() {
|
||||
let result = BuildResult {
|
||||
repo: Repo {
|
||||
clone_url: "https://github.com/nixos/nixpkgs.git".to_owned(),
|
||||
full_name: "NixOS/nixpkgs".to_owned(),
|
||||
owner: "NixOS".to_owned(),
|
||||
name: "nixpkgs".to_owned(),
|
||||
},
|
||||
pr: Pr {
|
||||
head_sha: "abc123".to_owned(),
|
||||
number: 2345,
|
||||
target_branch: Some("master".to_owned()),
|
||||
},
|
||||
output: vec![
|
||||
"make[2]: Entering directory '/private/tmp/nix-build-gdb-8.1.drv-0/gdb-8.1/readline'".to_owned(),
|
||||
"make[2]: Nothing to be done for 'install'.".to_owned(),
|
||||
"make[2]: Leaving directory '/private/tmp/nix-build-gdb-8.1.drv-0/gdb-8.1/readline'".to_owned(),
|
||||
"make[1]: Nothing to be done for 'install-target'.".to_owned(),
|
||||
"make[1]: Leaving directory '/private/tmp/nix-build-gdb-8.1.drv-0/gdb-8.1'".to_owned(),
|
||||
"removed '/nix/store/pcja75y9isdvgz5i00pkrpif9rxzxc29-gdb-8.1/share/info/bfd.info'".to_owned(),
|
||||
"post-installation fixup".to_owned(),
|
||||
"strip is /nix/store/5a88zk3jgimdmzg8rfhvm93kxib3njf9-cctools-binutils-darwin/bin/strip".to_owned(),
|
||||
"patching script interpreter paths in /nix/store/pcja75y9isdvgz5i00pkrpif9rxzxc29-gdb-8.1".to_owned(),
|
||||
"/nix/store/pcja75y9isdvgz5i00pkrpif9rxzxc29-gdb-8.1".to_owned(),
|
||||
],
|
||||
attempt_id: None,
|
||||
system: "x86_64-linux".to_owned(),
|
||||
success: false,
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
&result_to_comment(&result),
|
||||
"Failure on x86_64-linux [(full log)](https://logs.nix.gsc.io/?key=nixos/nixpkgs.2345&attempt_id=none)
|
||||
|
||||
<details><summary>Partial log (click to expand)</summary><p>
|
||||
|
||||
```
|
||||
make[2]: Entering directory '/private/tmp/nix-build-gdb-8.1.drv-0/gdb-8.1/readline'
|
||||
make[2]: Nothing to be done for 'install'.
|
||||
make[2]: Leaving directory '/private/tmp/nix-build-gdb-8.1.drv-0/gdb-8.1/readline'
|
||||
make[1]: Nothing to be done for 'install-target'.
|
||||
make[1]: Leaving directory '/private/tmp/nix-build-gdb-8.1.drv-0/gdb-8.1'
|
||||
removed '/nix/store/pcja75y9isdvgz5i00pkrpif9rxzxc29-gdb-8.1/share/info/bfd.info'
|
||||
post-installation fixup
|
||||
strip is /nix/store/5a88zk3jgimdmzg8rfhvm93kxib3njf9-cctools-binutils-darwin/bin/strip
|
||||
patching script interpreter paths in /nix/store/pcja75y9isdvgz5i00pkrpif9rxzxc29-gdb-8.1
|
||||
/nix/store/pcja75y9isdvgz5i00pkrpif9rxzxc29-gdb-8.1
|
||||
```
|
||||
</p></details>
|
||||
|
||||
"
|
||||
);
|
||||
}
|
||||
}
|
|
@ -2,4 +2,5 @@
|
|||
pub mod build;
|
||||
pub mod massrebuilder;
|
||||
pub mod githubcommentfilter;
|
||||
pub mod githubcommentposter;
|
||||
pub mod log_message_collector;
|
||||
|
|
|
@ -1,93 +0,0 @@
|
|||
<?php
|
||||
|
||||
require __DIR__ . '/config.php';
|
||||
use PhpAmqpLib\Message\AMQPMessage;
|
||||
|
||||
# define('AMQP_DEBUG', true);
|
||||
$connection = rabbitmq_conn();
|
||||
$channel = $connection->channel();
|
||||
$channel->basic_qos(null, 1, true);
|
||||
|
||||
|
||||
$channel->exchange_declare('build-results', 'fanout', false, true, false);
|
||||
$channel->queue_bind('build-results', 'build-results', '');
|
||||
|
||||
list($queueName, , ) = $channel->queue_declare('build-results',
|
||||
false, true, false, false);
|
||||
|
||||
function runner($msg) {
|
||||
$body = json_decode($msg->body);
|
||||
|
||||
$num = $body->pr->number;
|
||||
if ($body->success) {
|
||||
echo "yay! $num passed!\n";
|
||||
} else {
|
||||
echo "Yikes, $num failed\n";
|
||||
}
|
||||
|
||||
reply_to_issue($body, implode("\n", $body->output), $body->success, $body->system);
|
||||
|
||||
var_dump($body->success);
|
||||
|
||||
$msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
|
||||
}
|
||||
|
||||
function reply_to_issue($body, $output, $success, $system) {
|
||||
$num = $body->pr->number;
|
||||
$owner = $body->repo->owner;
|
||||
$repo = $body->repo->name;
|
||||
$event = $success ? 'APPROVE' : 'COMMENT';
|
||||
$passfail = $success ? "Success" : "Failure";
|
||||
|
||||
echo "Sending $event to $owner/$repo#$num with " . $passfail . " on $system\n";
|
||||
|
||||
$client = gh_client();
|
||||
$pr = $client->api('pull_request')->show(
|
||||
$owner,
|
||||
$repo,
|
||||
$num
|
||||
);
|
||||
|
||||
if ($pr['state'] == 'closed') {
|
||||
$event = 'COMMENT';
|
||||
}
|
||||
|
||||
// With multiple archs, it is better to not approve at all, since
|
||||
// another arch may come in later with a failure.
|
||||
// - By request of Domen
|
||||
$event = 'COMMENT';
|
||||
|
||||
$sha = $body->pr->head_sha;
|
||||
echo "On sha: $sha\n";
|
||||
echo "Body:\n";
|
||||
echo $output;
|
||||
echo "\n\n";
|
||||
|
||||
$fullloglink = strtolower("https://logs.nix.gsc.io/?key=$owner/$repo.$num");
|
||||
|
||||
$client->api('pull_request')->reviews()->create(
|
||||
$owner,
|
||||
$repo,
|
||||
$num,
|
||||
array(
|
||||
'body' =>
|
||||
"$passfail on $system [(full log)]($fullloglink)\n\n".
|
||||
"<details><summary>Partial log (click to expand)</summary><p>\n\n".
|
||||
"```\n$output\n```\n".
|
||||
"</p></details>\n\n",
|
||||
'event' => $event,
|
||||
'commit_id' => $sha,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
function outrunner($msg) {
|
||||
return runner($msg);
|
||||
}
|
||||
|
||||
|
||||
$consumerTag = 'poster-' . getmypid();
|
||||
$channel->basic_consume($queueName, $consumerTag, false, false, false, false, 'outrunner');
|
||||
while(count($channel->callbacks)) {
|
||||
$channel->wait();
|
||||
}
|
Loading…
Reference in a new issue