diff options
| -rw-r--r-- | src/Config.hs | 21 | ||||
| -rw-r--r-- | src/Eval.hs | 20 | ||||
| -rw-r--r-- | src/Job.hs | 23 | ||||
| -rw-r--r-- | src/Job/Types.hs | 11 | ||||
| -rw-r--r-- | test/asset/publish/push.yaml | 7 | ||||
| -rw-r--r-- | test/script/publish.et | 77 |
6 files changed, 157 insertions, 2 deletions
diff --git a/src/Config.hs b/src/Config.hs index 40eb1e5..651b05c 100644 --- a/src/Config.hs +++ b/src/Config.hs @@ -27,6 +27,7 @@ import System.FilePath.Glob import System.Process import Destination +import Job import Job.Types import Repo @@ -101,6 +102,7 @@ parseJob name node = flip (withMap "Job") node $ \j -> do jobArtifacts <- parseArtifacts j jobUses <- maybe (return []) parseUses =<< j .:? "uses" jobPublish <- maybe (return []) (parsePublish jobName) =<< j .:? "publish" + jobPush <- maybe (return []) parsePush =<< j .:? "push" return Job {..} parseSingleCheckout :: Node Pos -> Parser [ JobCheckout Declared ] @@ -164,6 +166,25 @@ parsePublish ownName = withSeq "Publish list" $ mapM $ jpPath <- fmap T.unpack <$> m .:? "path" return JobPublish {..} +parsePush :: Node Pos -> Parser [ JobPush Declared ] +parsePush = withSeq "Push list" $ mapM $ + withMap "Push specification" $ \m -> do + source <- m .: "source" + jpushSource <- case T.split (== '.') source of + [ repo, sel ] + | sel == "commit" + -> return $ currentCommitExpr (RepoName repo) + _ -> mzero + destination <- m .: "destination" + jpushDestination <- case T.split (== '.') destination of + [ repo, sel ] + | [ fn, bname, fn' ] <- T.split (== '"') sel + , fn == "branch(" + , fn' == ")" + -> return $ branchExpr (RepoName repo) bname + _ -> mzero + return JobPush {..} + parseRepo :: Text -> Node Pos -> Parser DeclaredRepo parseRepo name node = choice diff --git a/src/Eval.hs b/src/Eval.hs index a918910..bd011cb 100644 --- a/src/Eval.hs +++ b/src/Eval.hs @@ -17,6 +17,7 @@ import Control.Monad.Catch import Control.Monad.Except import Control.Monad.Reader +import Data.Bifunctor import Data.Either import Data.List import Data.Maybe @@ -114,8 +115,9 @@ collectJobSetRepos revisionOverrides dset = do return ( rname, RepoRefCommit commit ) getJobExprDependencies :: DeclaredJob -> [ JobSetDep ] -getJobExprDependencies _ = concat - [ +getJobExprDependencies job = concat + [ concatMap (collectDependencies . jpushSource) $ jobPush job + , concatMap (collectDependencies . jpushDestination) $ jobPush job ] collectOtherRepos :: DeclaredJobSet -> DeclaredJob -> Eval [ ( Maybe ( RepoName, Maybe Text ), RepoDepLevel ) ] @@ -202,6 +204,11 @@ evalJobs (current : evaluating) evaluated repos dset reqs = do return $ Just ( idpart, repoRef' ) return $ fmap (\subtree -> ( mbrepo, subtree )) mbSubtree let otherRepoTrees = catMaybes otherRepoTreesMb + + let jscRepos = maybe id ((:) . ( Nothing, )) eiContainingRepo $ map (first Just) eiOtherRepos + let jscRepoRefs = map (\( repo, ( _, ref ) ) -> ( fst <$> repo, ref )) otherRepoTrees + let ctx = JobSetContext {..} + if all isJust otherRepoTreesMb then do let otherRepoIds = flip mapMaybe otherRepoTrees $ \case @@ -239,6 +246,14 @@ evalJobs (current : evaluating) evaluated repos dset reqs = do } Nothing -> throwError $ OtherEvalError $ "no url defined for destination ‘" <> textDestinationName (jpDestination dpublish) <> "’" + pushes <- forM (jobPush current) $ \JobPush {..} -> do + commit <- eval ctx jpushSource + branch <- eval ctx jpushDestination + return JobPush + { jpushSource = commit + , jpushDestination = branch + } + let job = Job { jobId = currentJobId , jobName = jobName current @@ -247,6 +262,7 @@ evalJobs (current : evaluating) evaluated repos dset reqs = do , jobArtifacts = jobArtifacts current , jobUses = uses , jobPublish = destinations + , jobPush = pushes } evalJobs evaluating (Right job : evaluated) repos dset reqs else do @@ -18,6 +18,9 @@ module Job ( copyRecursive, copyRecursiveForce, + + currentCommitExpr, + branchExpr, ) where import Control.Concurrent @@ -49,6 +52,7 @@ import System.Posix.Signals import System.Process import Destination +import Expr import Job.Types import Output import Repo @@ -477,6 +481,9 @@ runJob job uses checkoutPath jdir = do , aoutStorePath = target } + forM_ (jobPush job) $ \JobPush {..} -> do + pushToBranch jpushDestination jpushSource + forM_ (jobPublish job) $ \pub -> do Just aout <- return $ lookup (jpArtifact pub) $ map (\aout -> ( ( jobId job, aoutName aout ), aout )) artifacts ++ uses let ppath = case jpPath pub of @@ -489,3 +496,19 @@ runJob job uses checkoutPath jdir = do return JobOutput { outArtifacts = artifacts } + + + +currentCommitExpr :: RepoName -> Expr JobSetContext Commit +currentCommitExpr rname = + addDependency [ RepoDependency rname RepoDepCommit ] $ + (pure getCommit) <*> (lookup (Just rname) . jscRepoRefs <$> GetContext) + where + getCommit = \case + Nothing -> error $ "currentCommitExpr: repo ‘" <> showRepoName rname <> "’ not found" + Just (RepoRefTree _) -> error $ "currentCommitExpr: expected commit in ‘" <> showRepoName rname <> "’, but got a tree" + Just (RepoRefCommit commit) -> commit + Just (RepoRefTag commit _) -> commit + +branchExpr :: RepoName -> Text -> Expr JobSetContext Branch +branchExpr rname bname = pure ((\repo -> Branch repo bname) . fromJust) <*> (lookup (Just rname) . jscRepos <$> GetContext) diff --git a/src/Job/Types.hs b/src/Job/Types.hs index 682e056..50f550d 100644 --- a/src/Job/Types.hs +++ b/src/Job/Types.hs @@ -20,6 +20,11 @@ import Repo data Declared data Evaluated +type family ExprD d c a :: Type where + ExprD Declared c a = Expr c a + ExprD Evaluated c a = a + + data Job' d = Job { jobId :: JobId' d , jobName :: JobName @@ -28,6 +33,7 @@ data Job' d = Job , jobArtifacts :: [ ( ArtifactName, Pattern ) ] , jobUses :: [ ArtifactSpec d ] , jobPublish :: [ JobPublish d ] + , jobPush :: [ JobPush d ] } type Job = Job' Evaluated @@ -70,6 +76,11 @@ data JobPublish d = JobPublish , jpPath :: Maybe FilePath } +data JobPush d = JobPush + { jpushSource :: ExprD d JobSetContext Commit + , jpushDestination :: ExprD d JobSetContext Branch + } + data ArtifactName = ArtifactName Text deriving (Eq, Ord, Show) diff --git a/test/asset/publish/push.yaml b/test/asset/publish/push.yaml new file mode 100644 index 0000000..d82cd0b --- /dev/null +++ b/test/asset/publish/push.yaml @@ -0,0 +1,7 @@ +repo source_repo: +repo target_repo: + +job push_job: + push: + - source: source_repo.commit + destination: target_repo.branch("master") diff --git a/test/script/publish.et b/test/script/publish.et index 6cea2f2..29d0742 100644 --- a/test/script/publish.et +++ b/test/script/publish.et @@ -67,3 +67,80 @@ test PublishFromSelf: /.\/destination\/y/ /(.*)/ capture done guard (done == "DONE") + + +test PushRepo: + node n + shell on n as git_init: + cp ${scripts.path}/push.yaml minici.yaml + + mkdir workdir + git -C workdir -c init.defaultBranch=master init -q + git -C workdir -c user.name=test -c user.email=test commit -q --allow-empty -m 'initial commit' + git -C workdir rev-parse HEAD + + git clone --bare workdir target.git + + touch workdir/a + git -C workdir add a + git -C workdir -c user.name=test -c user.email=test commit -q -m a + git -C workdir rev-parse HEAD + git -C workdir rev-parse HEAD^{tree} + + touch workdir/b + git -C workdir add b + git -C workdir -c user.name=test -c user.email=test commit -q -m b + git -C workdir rev-parse HEAD + git -C workdir rev-parse HEAD^{tree} + + touch workdir/c + git -C workdir add c + git -C workdir -c user.name=test -c user.email=test commit -q -m c + git -C workdir rev-parse HEAD + git -C workdir rev-parse HEAD^{tree} + + touch workdir/d + git -C workdir add d + git -C workdir -c user.name=test -c user.email=test commit -q -m d + git -C workdir rev-parse HEAD + git -C workdir rev-parse HEAD^{tree} + + touch workdir/e + git -C workdir add e + git -C workdir -c user.name=test -c user.email=test commit -q -m e + git -C workdir rev-parse HEAD + git -C workdir rev-parse HEAD^{tree} + + git -C workdir reset --hard HEAD~5 + git -C workdir 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) + + let cmd_run = [ "--repo=source_repo:workdir", "--repo=target_repo:target.git", "run" ] + local: + spawn on n as p args (cmd_run ++ [ "push_job.$cb" ]) killwith SIGINT + expect from p: + /job-enqueue push_job.$cb/ + /job-start push_job.$cb/ + /job-finish push_job.$cb done/ + + expect /(.*)/ from p capture finish + guard (finish == "run-finish") + + shell on n as git_check: + git -C target.git rev-parse HEAD + expect /([0-9a-f]+)/ from git_check capture cur_target + guard (cur_target == cb) |