Radish alpha
r
Radicle CI broker
Radicle
Git (anonymous pull)
Log in to clone via SSH
feat: generate RSS feeds for all, failed CI runs
Lars Wirzenius committed 1 year ago
commit 4caab2118c56ad6b4794aba5cab3be5b94ae9f30
parent dc61d2bbbbb9aecae59cf74c7089ce093056ea3b
4 files changed +218 -1
modified Cargo.lock
@@ -212,6 +212,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16"

[[package]]
+
name = "atom_syndication"
+
version = "0.12.4"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "2a3a5ed3201df5658d1aa45060c5a57dc9dba8a8ada20d696d67cb0c479ee043"
+
dependencies = [
+
 "chrono",
+
 "derive_builder",
+
 "diligent-date-parser",
+
 "never",
+
 "quick-xml",
+
]
+

+
[[package]]
name = "autocfg"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -597,6 +610,41 @@ dependencies = [
]

[[package]]
+
name = "darling"
+
version = "0.20.10"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
+
dependencies = [
+
 "darling_core",
+
 "darling_macro",
+
]
+

+
[[package]]
+
name = "darling_core"
+
version = "0.20.10"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
+
dependencies = [
+
 "fnv",
+
 "ident_case",
+
 "proc-macro2",
+
 "quote",
+
 "strsim",
+
 "syn 2.0.87",
+
]
+

+
[[package]]
+
name = "darling_macro"
+
version = "0.20.10"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
+
dependencies = [
+
 "darling_core",
+
 "quote",
+
 "syn 2.0.87",
+
]
+

+
[[package]]
name = "data-encoding"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -642,6 +690,37 @@ dependencies = [
]

[[package]]
+
name = "derive_builder"
+
version = "0.20.2"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947"
+
dependencies = [
+
 "derive_builder_macro",
+
]
+

+
[[package]]
+
name = "derive_builder_core"
+
version = "0.20.2"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8"
+
dependencies = [
+
 "darling",
+
 "proc-macro2",
+
 "quote",
+
 "syn 2.0.87",
+
]
+

+
[[package]]
+
name = "derive_builder_macro"
+
version = "0.20.2"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
+
dependencies = [
+
 "derive_builder_core",
+
 "syn 2.0.87",
+
]
+

+
[[package]]
name = "deunicode"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -660,6 +739,15 @@ dependencies = [
]

[[package]]
+
name = "diligent-date-parser"
+
version = "0.1.4"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "f6cf7fe294274a222363f84bcb63cdea762979a0443b4cf1f4f8fd17c86b1182"
+
dependencies = [
+
 "chrono",
+
]
+

+
[[package]]
name = "displaydoc"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -836,6 +924,12 @@ dependencies = [
]

[[package]]
+
name = "fnv"
+
version = "1.0.7"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+

+
[[package]]
name = "form_urlencoded"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1231,6 +1325,12 @@ dependencies = [
]

[[package]]
+
name = "ident_case"
+
version = "1.0.1"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
+

+
[[package]]
name = "idna"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1476,6 +1576,12 @@ dependencies = [
]

[[package]]
+
name = "never"
+
version = "0.1.0"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "c96aba5aa877601bb3f6dd6a63a969e1f82e60646e81e71b14496995e9853c91"
+

+
[[package]]
name = "nix"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1845,6 +1951,16 @@ dependencies = [
]

[[package]]
+
name = "quick-xml"
+
version = "0.36.2"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe"
+
dependencies = [
+
 "encoding_rs",
+
 "memchr",
+
]
+

+
[[package]]
name = "quote"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1899,6 +2015,7 @@ dependencies = [
 "radicle-git-ext",
 "radicle-surf",
 "regex",
+
 "rss",
 "serde",
 "serde_json",
 "serde_yml",
@@ -2160,6 +2277,18 @@ dependencies = [
]

[[package]]
+
name = "rss"
+
version = "2.0.9"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "27e92048f840d98c6d6dd870af9101610ea9ff413f11f1bcebf4f4c31d96d957"
+
dependencies = [
+
 "atom_syndication",
+
 "derive_builder",
+
 "never",
+
 "quick-xml",
+
]
+

+
[[package]]
name = "rust_decimal"
version = "1.36.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
modified Cargo.toml
@@ -18,6 +18,7 @@ html-page = "0.4.0"
radicle-git-ext = "0.8.0"
radicle-surf = { version = "0.22.0", default-features = false, features = ["serde"] }
regex = "1.10.5"
+
rss = "2.0.9"
serde = { version = "1.0.204", features = ["derive"] }
serde_json = "1.0.121"
serde_yml = "0.0.11"
modified ci-broker.md
@@ -262,6 +262,8 @@ then stderr contains "loaded configuration"
then stderr contains "CI broker ends successfully"
then file reports/index.html exists
then file reports/status.json exists
+
then file reports/index.rss exists
+
when I run tidy -xml -indent -quiet reports/index.rss

when I run cibtool --db ci-broker.db event list
then stdout is empty
modified src/pages.rs
@@ -17,6 +17,7 @@ use std::{
};

use html_page::{Element, HtmlPage, Tag};
+
use rss::{Channel, ChannelBuilder, Guid, Item, ItemBuilder};
use serde::Serialize;
use time::{macros::format_description, OffsetDateTime};

@@ -31,11 +32,13 @@ use crate::{
    ci_event::{CiEvent, CiEventV1},
    db::{Db, DbError, QueuedCiEvent},
    logger,
-
    msg::RunId,
+
    msg::{RunId, RunResult},
    notif::NotificationReceiver,
    run::{Run, RunState, Whence},
};

+
const BROKER_RSS: &str = "index.rss";
+
const FAILURE_RSS: &str = "failed.rss";
const CSS: &str = include_str!("radicle-ci.css");
const REFERESH_INTERVAL: &str = "300";
const UPDATE_INTERVAL: Duration = Duration::from_secs(60);
@@ -97,6 +100,22 @@ impl PageData {

        doc.push_to_body(Element::new(Tag::H1).with_text(&title));

+
        doc.push_to_body(
+
            Element::new(Tag::P)
+
                .with_text("RSS feeds: ")
+
                .with_child(
+
                    Element::new(Tag::A)
+
                        .with_text("all")
+
                        .with_attribute("href", BROKER_RSS),
+
                )
+
                .with_text(" ")
+
                .with_child(
+
                    Element::new(Tag::A)
+
                        .with_text("failed")
+
                        .with_attribute("href", FAILURE_RSS),
+
                ),
+
        );
+

        Self::h1(&mut doc, "Broker status");
        doc.push_to_body(
            Element::new(Tag::P)
@@ -512,6 +531,62 @@ impl PageData {
        }
        value
    }
+

+
    fn status_as_rss(&self) -> Result<Channel, PageError> {
+
        let mut channel = ChannelBuilder::default();
+
        channel
+
            .title("Radicle CI broker run information")
+
            .description("All CI runs known to this instance of the Radicle CI broker.")
+
            .link("FIXME:link");
+
        for (_alias, repo_id) in self.repos() {
+
            for run in self.runs(repo_id) {
+
                channel.item(Self::rss_item_from_run(run));
+
            }
+
        }
+
        Ok(channel.build())
+
    }
+

+
    fn failed_as_rss(&self) -> Result<Channel, PageError> {
+
        let mut channel = ChannelBuilder::default();
+
        channel
+
            .title("Radicle CI broker run information")
+
            .description("All CI runs known to this instance of the Radicle CI broker.")
+
            .link("FIXME:link");
+
        for (_alias, repo_id) in self.repos() {
+
            for run in self.runs(repo_id) {
+
                if run.state() == RunState::Finished && run.result() == Some(&RunResult::Failure) {
+
                    channel.item(Self::rss_item_from_run(run));
+
                }
+
            }
+
        }
+
        Ok(channel.build())
+
    }
+

+
    fn rss_item_from_run(run: &Run) -> Item {
+
        let mut guid = Guid::default();
+
        guid.set_value(run.broker_run_id().to_string());
+

+
        let state = if run.state() == RunState::Finished {
+
            match run.result() {
+
                Some(result) => result.to_string(),
+
                None => "unknown".to_string(),
+
            }
+
        } else {
+
            run.state().to_string()
+
        };
+
        let title = format!("{state}: {} run {}", run.repo_alias(), run.broker_run_id());
+

+
        let mut item = ItemBuilder::default()
+
            .title(Some(title))
+
            .guid(Some(guid))
+
            .build();
+

+
        if let Some(url) = run.adapter_info_url() {
+
            item.set_link(Some(url.into()));
+
        };
+

+
        item
+
    }
}

/// Data for status pages for CI broker.
@@ -647,6 +722,16 @@ impl StatusPage {
            let filename = dirname.join(STATUS_JSON);
            let json = data.status_page_as_json()?;
            Self::write_file(&filename, &json)?;
+

+
            let filename = dirname.join(BROKER_RSS);
+
            let channel = data.status_as_rss()?;
+
            let rss = channel.to_string();
+
            Self::write_file(&filename, &rss)?;
+

+
            let filename = dirname.join(FAILURE_RSS);
+
            let channel = data.failed_as_rss()?;
+
            let rss = channel.to_string();
+
            Self::write_file(&filename, &rss)?;
        }
        Ok(())
    }