summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md10
-rw-r--r--src/Expression.hs23
-rw-r--r--test/script/expression.et99
3 files changed, 128 insertions, 4 deletions
diff --git a/README.md b/README.md
index e56fec3..dc85086 100644
--- a/README.md
+++ b/README.md
@@ -70,7 +70,13 @@ To run jobs for commits that are in local `<branch>`, but not yet in its upstrea
minici run --since-upstream=<branch>
```
-For current branch, the name can be omitted:
+or equivalently:
+```
+minici run '<branch>..upstream(<branch>)'
+```
+
+This is the default action the `run` command will perform without any
+arguments, using the current branch as `<branch>` when executed as:
```
minici run
```
@@ -132,6 +138,8 @@ Where `<commit-expr>` can be:
* `lasttag(<pattern>)`, which from all the tags matching `<pattern>`, selects
the last created one (as given by the `tagger` date in tag object);
+* `upstream(<branch>)` refers to the upstream (remote) branch of the given `<branch>`;
+
* `watch(<commit-expr>)` is analogous to `watch` for `<range-expr>`.
And `<pattern>` is a shell glob pattern, as implemented
diff --git a/src/Expression.hs b/src/Expression.hs
index 49fb4c1..29b6ea0 100644
--- a/src/Expression.hs
+++ b/src/Expression.hs
@@ -47,6 +47,7 @@ import Repo
data DeclaredRef
= TextRef Text
+ | UpstreamRef Text
| TagRef Pattern (Tag Commit -> Tag Commit -> Tag Commit)
type family StaticRef' d :: Type where
@@ -131,6 +132,10 @@ textCommitRef (CommitRef suffix cid) = textCommitId cid <> suffix
evaluateDeclaredRevision :: (MonadIO m, MonadFail m, MonadOutput m) => Repo -> DeclaredRevisionExpression -> m RevisionExpression
evaluateDeclaredRevision repo = \case
StaticRef (TextRef ref) -> StaticRef <$> readCommit repo ref
+ StaticRef (UpstreamRef ref) ->
+ findUpstreamRef repo ref >>= \case
+ Just uref -> evaluateDeclaredRevision repo $ StaticRef (TextRef uref)
+ Nothing -> fail $ "no upstream ref found for ‘" <> T.unpack ref <> "’ in ‘" <> show repo <> "’"
StaticRef (TagRef pat sel) -> do
filter (Glob.match pat . T.unpack . tagTag) <$> listTags repo >>= \case
[] -> fail $ "no tag matching " <> show (decompile pat) <> " found"
@@ -145,6 +150,11 @@ evaluateDeclaredRevision repo = \case
Left commit -> do
return $ StaticRef commit
+ WatchedRef (UpstreamRef ref) ->
+ findUpstreamRef repo ref >>= \case
+ Just uref -> evaluateDeclaredRevision repo $ WatchedRef (TextRef uref)
+ Nothing -> fail $ "no upstream ref found for ‘" <> T.unpack ref <> "’ in ‘" <> show repo <> "’"
+
WatchedRef (TagRef wtPattern wtUpdate) -> do
wtChan <- watchTags repo
value <- filter (Glob.match wtPattern . T.unpack . tagTag) <$> listTags repo >>= \case
@@ -278,13 +288,17 @@ parseRangeExpression = bimap errorBundlePretty id . runParser parser ""
return range
]
- parseRevision :: ExprParser DeclaredRangeExpression
- parseRevision = do
- tok <- fmap T.concat $ some $ choice
+ parseTextRef :: ExprParser Text
+ parseTextRef = do
+ fmap T.concat $ some $ choice
[ takeWhile1P Nothing (\x -> isAlphaNum x || x `elem` [ '_', '-', '/' ])
, try $ string "." <* notFollowedBy (char '.')
]
+ parseRevision :: ExprParser DeclaredRangeExpression
+ parseRevision = do
+ tok <- parseTextRef
+
range <- choice
[ between (char '(') (char ')') $ do
case tok of
@@ -300,6 +314,9 @@ parseRangeExpression = bimap errorBundlePretty id . runParser parser ""
"lasttag" -> do
pat <- parseTagPattern
return $ SingleRevisionExpression $ StaticRef $ TagRef pat laterTag
+ "upstream" -> do
+ ref <- parseTextRef
+ return $ SingleRevisionExpression $ StaticRef $ UpstreamRef ref
_ -> unexpected $ Tokens $ NE.fromList $ chunkToTokens @Text Proxy tok
, do
diff --git a/test/script/expression.et b/test/script/expression.et
index 9896e7a..4c1fb0a 100644
--- a/test/script/expression.et
+++ b/test/script/expression.et
@@ -649,3 +649,102 @@ test WatchRemoteRepo:
/job-enqueue $td:single/
/job-start $td:single/
/job-finish $td:single done/
+
+
+test WatchUpstreamRef:
+ node n
+ shell on n as git_init:
+ mkdir a
+ cd a
+ git -c init.defaultBranch=master init -q
+ git -c user.name=test -c user.email=test commit -q --allow-empty -m 'initial commit'
+ cp "${scripts.path}/single.yaml" minici.yaml
+ git add minici.yaml
+ git -c user.name=test -c user.email=test commit -q -m 'minici.yaml'
+ git rev-parse HEAD
+
+ touch a
+ git add a
+ git -c user.name=test -c user.email=test commit -q -m a
+ git rev-parse HEAD
+ git rev-parse HEAD^{tree}
+
+ touch b
+ git add b
+ git -c user.name=test -c user.email=test commit -q -m b
+ git rev-parse HEAD
+ git rev-parse HEAD^{tree}
+
+ touch c
+ git add c
+ git -c user.name=test -c user.email=test commit -q -m c
+ git rev-parse HEAD
+ git rev-parse HEAD^{tree}
+
+ touch d
+ git add d
+ git -c user.name=test -c user.email=test commit -q -m d
+ git rev-parse HEAD
+ git rev-parse HEAD^{tree}
+
+ touch e
+ git add e
+ git -c user.name=test -c user.email=test commit -q -m e
+ git rev-parse HEAD
+ git rev-parse HEAD^{tree}
+
+ git reset --hard HEAD~5
+ git rev-parse HEAD
+
+ expect /([0-9a-f]+)/ from git_init capture c_init
+ expect /([0-9a-f]+)/ from git_init capture ca
+ expect /([0-9a-f]+)/ from git_init capture ta
+ expect /([0-9a-f]+)/ from git_init capture cb
+ expect /([0-9a-f]+)/ from git_init capture tb
+ expect /([0-9a-f]+)/ from git_init capture cc
+ expect /([0-9a-f]+)/ from git_init capture tc
+ expect /([0-9a-f]+)/ from git_init capture cd
+ expect /([0-9a-f]+)/ from git_init capture td
+ expect /([0-9a-f]+)/ from git_init capture ce
+ expect /([0-9a-f]+)/ from git_init capture te
+ expect /([0-9a-f]+)/ from git_init capture c_end
+
+ guard (c_init == c_end)
+
+ local:
+ shell on n:
+ git -C a checkout -q -b test $cb
+ git clone -q a b
+
+ local:
+ spawn on n as p args [ "./b", "run", "--rerun-all", "$ca..upstream(test)" ]
+ expect from p:
+ /job-enqueue $tb:single/
+ /job-start $tb:single/
+ /job-finish $tb:single done/
+ expect /(.*)/ from p capture finish
+ guard (finish == "run-finish")
+
+ local:
+ spawn on n as p args [ "./b", "run", "--rerun-all", "watch($ca..upstream(test))" ] killwith SIGINT
+ expect from p:
+ /watch-branch-started .*origin\/test/
+ /job-enqueue $tb:single/
+ /job-start $tb:single/
+ /job-finish $tb:single done/
+
+ local:
+ shell on n:
+ git -C a merge -q --ff-only $cd
+
+ local:
+ shell on n:
+ git -C b fetch -q origin
+
+ expect from p:
+ /job-enqueue $tc:single/
+ /job-start $tc:single/
+ /job-finish $tc:single done/
+ /job-enqueue $td:single/
+ /job-start $td:single/
+ /job-finish $td:single done/