Implement tunable preservation of remote branches
diff mbox series

Message ID 20191028230923.11613-1-ajd@linux.ibm.com
State Superseded
Headers show
Series
  • Implement tunable preservation of remote branches
Related show

Commit Message

Andrew Donnellan Oct. 28, 2019, 11:09 p.m. UTC
From: Russell Currey <ruscur@russell.cc>

A new parameter, branch_preserve_policy, allows users to specify whether
they want to preserve all remote branches, just full series or
standalone patches, or none (default, current behaviour).  In addition,
users can specify a separate remote to push to, allowing branches to be
preserved while still deleting them from the main remote used for
testing.

Signed-off-by: Russell Currey <ruscur@russell.cc>
[ajd: rebase on master]
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
---
 docs/configuration.md   | 18 ++++++++++++++++--
 examples/openpower.toml |  2 ++
 src/main.rs             | 25 +++++++++++++++++++++++--
 src/settings.rs         | 27 +++++++++++++++++++++++++++
 4 files changed, 68 insertions(+), 4 deletions(-)

Patch
diff mbox series

diff --git a/docs/configuration.md b/docs/configuration.md
index d4c383fefe9e..0a49b00ed502 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -147,7 +147,21 @@  Example:
 - `base_remote_name`: the name of the remote where base branches are retrieved
   from (Optional, defaults to value of remote_name)
 
-- `push_results`: whether test results should be pushed to Patchwork for this project
+- `push_results`: whether test results should be pushed to Patchwork for this
+  project
+
+- `branch_preserve_policy`: set the policy for how snowpatch will handle
+  branches on git remotes after tests have run.
+
+  "ALL": preserves all branches on the remote.
+  "SERIES": only preserves full series or standalone patches.
+  "NONE": deletes branches on the remote after testing.
+
+  (Optional, defaults to NONE)
+
+- `branch_preserve_remote`: only valid if `branch_preserve_policy` is not NONE.
+  Specify the name of a git remote that will only be used for branch
+  preservation.  If set, branches will be deleted on the main remote. (Optional)
 
 Individual jobs contain the following:
 
@@ -172,4 +186,4 @@  Individual jobs contain the following:
 - `warn_on_fail`: if true, this job will return a warning rather than a failure
   if it fails (Optional, defaults to false)
 
-- Any further parameters will be passed to Jenkins as build parameters
\ No newline at end of file
+- Any further parameters will be passed to Jenkins as build parameters
diff --git a/examples/openpower.toml b/examples/openpower.toml
index d72d47ad7c69..a85f9f916981 100644
--- a/examples/openpower.toml
+++ b/examples/openpower.toml
@@ -43,6 +43,8 @@  token = "33333333333333333333333333333333"
     remote_uri = "git@github.com:ruscur/skiboot.git"
     base_remote_name = "origin"
     push_results = false
+    branch_preserve_policy = "SERIES" # defaults to NONE
+    branch_preserve_remote = "gitlab" # branch to push to, but not delete from
 
         [[projects.skiboot.jobs]]
         job = "skiboot-compile-test-snowpatch"
diff --git a/src/main.rs b/src/main.rs
index 999b16cbdabe..ad1733a23a95 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -65,7 +65,7 @@  mod jenkins;
 use jenkins::JenkinsBackend;
 
 mod settings;
-use settings::{Config, Job, Project};
+use settings::{BranchPreservePolicy, Config, Job, Project};
 
 mod git;
 
@@ -194,6 +194,9 @@  fn test_patch(
     hefty_tests: bool,
 ) -> Vec<TestResult> {
     let repo = project.get_repo().unwrap();
+    let preserve_policy = project
+        .branch_preserve_policy
+        .unwrap_or(BranchPreservePolicy::None);
     let mut results: Vec<TestResult> = Vec::new();
     if !path.is_file() {
         return results;
@@ -206,6 +209,7 @@  fn test_patch(
             _ => &project.remote_name,
         })
         .unwrap();
+    let preserve_remote = &project.branch_preserve_remote;
 
     let mut push_callbacks = RemoteCallbacks::new();
     push_callbacks.credentials(|_, _, _| git::cred_from_settings(&settings.git));
@@ -244,6 +248,18 @@  fn test_patch(
 
         if output.is_ok() {
             git::push_to_remote(&mut remote, &branch, false, &mut push_opts).unwrap();
+            if preserve_remote.is_some()
+                && (preserve_policy == BranchPreservePolicy::All
+                    || (preserve_policy == BranchPreservePolicy::Series && hefty_tests))
+            {
+                git::push_to_remote(
+                    &mut repo.find_remote(preserve_remote.as_ref().unwrap()).unwrap(),
+                    &branch,
+                    false,
+                    &mut push_opts,
+                )
+                .unwrap();
+            }
         }
 
         git::delete_branch(&repo, &tag).unwrap_or_else(|err| {
@@ -323,7 +339,12 @@  fn test_patch(
         results.append(&mut thread.join().unwrap());
 
         // Delete the remote branch now it's not needed any more
-        git::push_to_remote(&mut remote, &branch, true, &mut push_opts).unwrap();
+        if preserve_remote.is_some()
+            || preserve_policy == BranchPreservePolicy::None
+            || (preserve_policy == BranchPreservePolicy::Series && !hefty_tests)
+        {
+            git::push_to_remote(&mut remote, &branch, true, &mut push_opts).unwrap();
+        }
     }
 
     if !successfully_applied {
diff --git a/src/settings.rs b/src/settings.rs
index e20d2e856834..b3b82894a876 100644
--- a/src/settings.rs
+++ b/src/settings.rs
@@ -29,6 +29,13 @@  use std::io::Read;
 
 // TODO: Give more informative error messages when we fail to parse.
 
+#[derive(Deserialize, Clone, PartialEq, Copy)]
+pub enum BranchPreservePolicy {
+    All,
+    Series,
+    None,
+}
+
 #[derive(Deserialize, Clone)]
 pub struct Git {
     pub user: String,
@@ -68,6 +75,10 @@  pub struct Project {
     pub base_remote_name: Option<String>,
     pub jobs: Vec<Job>,
     pub push_results: bool,
+    #[serde(default)] // necessary for serde to treat as optional
+    #[serde(deserialize_with = "parse_preserve_policy")]
+    pub branch_preserve_policy: Option<BranchPreservePolicy>,
+    pub branch_preserve_remote: Option<String>,
     pub category: Option<String>,
 }
 
@@ -89,6 +100,22 @@  pub struct Job {
     pub parameters: BTreeMap<String, String>,
 }
 
+fn parse_preserve_policy<'de, D>(deserializer: D) -> Result<Option<BranchPreservePolicy>, D::Error>
+where
+    D: Deserializer<'de>,
+{
+    let s = String::deserialize(deserializer)?;
+
+    match s.as_ref() {
+        "ALL" => Ok(Some(BranchPreservePolicy::All)),
+        "SERIES" => Ok(Some(BranchPreservePolicy::Series)),
+        "NONE" => Ok(Some(BranchPreservePolicy::None)),
+        _ => Err(serde::de::Error::custom(
+            "branch_preserve_policy not one of ALL, SERIES, NONE",
+        )),
+    }
+}
+
 impl<'de> Deserialize<'de> for Job {
     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
     where