diff options
| -rw-r--r-- | README.md | 10 | ||||
| -rw-r--r-- | src/Expression.hs | 23 | ||||
| -rw-r--r-- | test/script/expression.et | 99 |
3 files changed, 128 insertions, 4 deletions
@@ -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/ |