diff --git a/SPEC.md b/SPEC.md index 6bc06f5..3a0f4fc 100644 --- a/SPEC.md +++ b/SPEC.md @@ -15,3 +15,4 @@ ## Supports configurable log levels (debug, info, warn, error) ## Supports logging to a file instead of stderr via --log-file or log_file config +## Can notify on pull: per-repo notify_on_pull setting sends a desktop notification when new commits are pulled from the remote diff --git a/converge.example.yaml b/converge.example.yaml index e91fc8a..9e46efb 100644 --- a/converge.example.yaml +++ b/converge.example.yaml @@ -6,6 +6,7 @@ repos: - path: /home/jbrechtel/org remote: origin branch: main + # notify_on_pull: true # send a notification when new commits are pulled - path: /work/personal/hawat # remote defaults to "origin" # branch defaults to "main" diff --git a/src/Converge.hs b/src/Converge.hs index bf4b3dd..692d66e 100644 --- a/src/Converge.hs +++ b/src/Converge.hs @@ -64,6 +64,8 @@ data RepoConfig = RepoConfig -- ^ Remote name to pull from. , rcBranch :: !Text -- ^ Branch to pull. + , rcNotifyOnPull :: !Bool + -- ^ Send a notification when new commits are pulled from the remote. } deriving (Show, Eq) @@ -105,6 +107,7 @@ defaultRepoConfig = { rcPath = "." , rcRemote = "origin" , rcBranch = "main" + , rcNotifyOnPull = False } -- | Sensible defaults for options. @@ -167,6 +170,7 @@ instance FromJSON RepoConfig where <$> o .: "path" <*> (fromMaybe "origin" <$> o .:? "remote") <*> (fromMaybe "main" <$> o .:? "branch") + <*> (fromMaybe False <$> o .:? "notify_on_pull") -- | Load a YAML config file. loadConfig :: FilePath -> IO Config @@ -341,6 +345,8 @@ syncRepo opts logger repo = do ("Commit failed in " <> rcPath repo <> " (exit " <> show commitCode <> ")") -- Pull logRepo logger repo ("pulling " <> rcRemote repo <> "/" <> rcBranch repo) + (_, headBefore, _) <- runGitIn (rcPath repo) ["rev-parse", "HEAD"] + let headBefore' = T.strip headBefore (pullCode, pullOut, pullErr) <- gitPull logger repo case pullCode of ExitSuccess -> do @@ -348,6 +354,22 @@ syncRepo opts logger repo = do if T.null trimmed then logRepo logger repo "pull: already up to date" else logRepo logger repo ("pull succeeded:\n" <> trimmed) + -- Notify on new commits pulled, if configured + when (rcNotifyOnPull repo) $ do + (_, headAfter, _) <- runGitIn (rcPath repo) ["rev-parse", "HEAD"] + let headAfter' = T.strip headAfter + when (headBefore' /= headAfter') $ do + let range = T.unpack headBefore' <> ".." <> T.unpack headAfter' + (_, logOut, _) <- runGitIn (rcPath repo) ["log", "--oneline", range] + let newCommits = filter (not . T.null) (T.lines logOut) + count = length newCommits + summary = T.unlines (take 5 newCommits) + more = if count > 5 then "\n... and " <> T.pack (show (count - 5)) <> " more" else "" + logRepo logger repo ("pulled " <> T.pack (show count) <> " new commit(s)") + notifyUser + opts + ("Converge: " <> show count <> " New Commit(s) in " <> rcPath repo) + ("Pulled " <> show count <> " new commit(s):\n" <> T.unpack summary <> T.unpack more) _ -> do logRepoAt logger Error repo ("pull FAILED (exit " <> T.pack (show pullCode) <> "): " <> T.strip (pullOut <> pullErr)) notifyUser