Merge pull request #53 from NixOS/review-comments-issue-49

Review comments issue 49
This commit is contained in:
Graham Christensen 2018-01-31 20:06:21 -05:00 committed by GitHub
commit 79f83cc206
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 570 additions and 132 deletions

View file

@ -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
View file

@ -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)",

View file

@ -1,6 +1,6 @@
[package]
name = "ofborg"
version = "0.1.0"
version = "0.1.1"
authors = ["Graham Christensen <graham@grahamc.com>"]
[dependencies]

View 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");
}

View file

@ -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()),
)
}

View file

@ -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,
}

View file

@ -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,
};

View 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>
"
);
}
}

View file

@ -2,4 +2,5 @@
pub mod build;
pub mod massrebuilder;
pub mod githubcommentfilter;
pub mod githubcommentposter;
pub mod log_message_collector;

View file

@ -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();
}