feat: implement --new flag
The new `--new` or `-n` flag allows to create a new revision after the single revision being described. Running `jj-cz --new` is the equivalent of running `jj-cz @ && jj new`. Running `jj-cz --new xs` is the equivalent of running `jj-cz xs && jj new xs`. Passing several revisions to `jj-cz` with the `--new` flag will result in an error. Refs: #6
This commit is contained in:
+88
-5
@@ -11,18 +11,22 @@ use std::sync::{Mutex, atomic::AtomicBool};
|
||||
/// Mock implementation of JjExecutor for testing
|
||||
#[derive(Debug)]
|
||||
pub struct MockJjExecutor {
|
||||
/// Response to return from is_repository()
|
||||
/// Response to return from `is_repository()`
|
||||
is_repo_response: Result<bool, Error>,
|
||||
/// Response to return from describe()
|
||||
/// Response to return from `describe()`
|
||||
describe_response: Result<(), Error>,
|
||||
/// Track described revsets
|
||||
described_revsets: Mutex<Vec<String>>,
|
||||
/// Track response to return from get_description()
|
||||
/// Track response to return from `get_description()`
|
||||
get_description_response: Result<String, Error>,
|
||||
/// Track calls to is_repository()
|
||||
/// Track calls to `is_repository()`
|
||||
is_repo_called: AtomicBool,
|
||||
/// Track calls to describe() with the message passed
|
||||
/// Track calls to `describe()` with the message passed
|
||||
describe_calls: Mutex<Vec<String>>,
|
||||
/// Track response to return from `new_revision()`
|
||||
new_revision_response: Result<(), Error>,
|
||||
/// Track calls to `new_revision()`
|
||||
new_revision_calls: Mutex<Vec<String>>,
|
||||
}
|
||||
|
||||
impl Default for MockJjExecutor {
|
||||
@@ -34,6 +38,8 @@ impl Default for MockJjExecutor {
|
||||
get_description_response: Ok(String::new()),
|
||||
is_repo_called: AtomicBool::new(false),
|
||||
describe_calls: Mutex::new(Vec::new()),
|
||||
new_revision_response: Ok(()),
|
||||
new_revision_calls: Mutex::new(Vec::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,6 +72,15 @@ impl MockJjExecutor {
|
||||
pub fn describe_messages(&self) -> Vec<String> {
|
||||
self.describe_calls.lock().unwrap().clone()
|
||||
}
|
||||
|
||||
pub fn with_new_revision_response(mut self, response: Result<(), Error>) -> Self {
|
||||
self.new_revision_response = response;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn new_revision_calls(&self) -> Vec<String> {
|
||||
self.new_revision_calls.lock().unwrap().clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
@@ -97,6 +112,17 @@ impl JjExecutor for MockJjExecutor {
|
||||
async fn get_description(&self, _revset: &str) -> Result<String, Error> {
|
||||
self.get_description_response.clone()
|
||||
}
|
||||
|
||||
async fn new_revision(&self, revset: &str) -> Result<(), Error> {
|
||||
self.new_revision_calls
|
||||
.lock()
|
||||
.unwrap()
|
||||
.push(revset.to_string());
|
||||
match &self.new_revision_response {
|
||||
Ok(()) => Ok(()),
|
||||
Err(e) => Err(e.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -245,4 +271,61 @@ mod tests {
|
||||
mock.is_repository().await.unwrap();
|
||||
assert!(mock.was_is_repo_called());
|
||||
}
|
||||
|
||||
/// Test mock new_revision() records the revset
|
||||
#[tokio::test]
|
||||
async fn mock_new_revision_records_revset() {
|
||||
let mock = MockJjExecutor::new();
|
||||
let result = mock.new_revision("@").await;
|
||||
assert!(result.is_ok());
|
||||
let calls = mock.new_revision_calls();
|
||||
assert_eq!(calls.len(), 1);
|
||||
assert_eq!(calls[0], "@");
|
||||
}
|
||||
|
||||
/// Test mock new_revision() records multiple calls
|
||||
#[tokio::test]
|
||||
async fn mock_new_revision_records_multiple_calls() {
|
||||
let mock = MockJjExecutor::new();
|
||||
mock.new_revision("@").await.unwrap();
|
||||
mock.new_revision("abc").await.unwrap();
|
||||
mock.new_revision("xyz").await.unwrap();
|
||||
let calls = mock.new_revision_calls();
|
||||
assert_eq!(calls.len(), 3);
|
||||
assert_eq!(calls[0], "@");
|
||||
assert_eq!(calls[1], "abc");
|
||||
assert_eq!(calls[2], "xyz");
|
||||
}
|
||||
|
||||
/// Test mock new_revision() returns configured error
|
||||
#[tokio::test]
|
||||
async fn mock_new_revision_returns_error() {
|
||||
let mock = MockJjExecutor::new().with_new_revision_response(Err(Error::RepositoryLocked));
|
||||
let result = mock.new_revision("@").await;
|
||||
assert!(result.is_err());
|
||||
assert!(matches!(result.unwrap_err(), Error::RepositoryLocked));
|
||||
}
|
||||
|
||||
/// Test mock new_revision() records revset even on error
|
||||
#[tokio::test]
|
||||
async fn mock_new_revision_records_revset_on_error() {
|
||||
let mock = MockJjExecutor::new().with_new_revision_response(Err(Error::JjOperation {
|
||||
context: "failed".to_string(),
|
||||
}));
|
||||
let result = mock.new_revision("abc").await;
|
||||
assert!(result.is_err());
|
||||
let calls = mock.new_revision_calls();
|
||||
assert_eq!(calls.len(), 1);
|
||||
assert_eq!(calls[0], "abc");
|
||||
}
|
||||
|
||||
/// Test mock new_revision() can be inspected after success
|
||||
#[tokio::test]
|
||||
async fn mock_new_revision_returns_ok_and_tracks_revset() {
|
||||
let mock = MockJjExecutor::new();
|
||||
let result = mock.new_revision("my-feature").await;
|
||||
assert!(result.is_ok());
|
||||
let calls = mock.new_revision_calls();
|
||||
assert_eq!(calls, vec!["my-feature"]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user