packages feed

libjenkins-0.1.0.0: examples/Rename.hs

{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
-- | Rename jobs matching supplied pattern
module Main where

import           Control.Lens                      -- lens
import           Control.Lens.Aeson                -- lens-aeson
import           Control.Monad (when)              -- base
import qualified Data.ByteString.Char8 as B        -- bytestring
import           Data.Foldable (for_)              -- base
import           Data.Function (fix)               -- base
import           Data.Text (Text)                  -- text
import qualified Data.Text as T                    -- text
import qualified Data.Text.IO as T                 -- text
import           Jenkins.REST                      -- libjenkins
import           Options.Applicative               -- optparse-applicative
import           System.Exit (exitFailure)         -- base

{-# ANN module ("HLint: Use camelCase" :: String) #-}


main :: IO ()
main = do
  -- more useful help on error
  opts <- customExecParser (prefs showHelpOnError) options
  res  <- rename opts
  case res of
    Right () -> T.putStrLn "Done."
    -- something bad happened, show it!
    Left  e  -> do
      print e
      exitFailure

-- | Prompt to rename all jobs matching pattern
rename :: Options -> IO (Either Disconnect ())
rename (Options { settings, old, new }) = runJenkins settings $ do
  -- get jobs names from jenkins "root" API
  res <- get (json -?- "tree" -=- "jobs[name]")
  let jobs = res ^.. key "jobs"._Array.each.key "name"._String
  for_ jobs rename_job
 where
  rename_job :: Text -> Jenkins ()
  rename_job name = when (old `T.isInfixOf` name) $ do
    let name' = (old `T.replace` new) name
    -- prompt for every matching job
    yes <- prompt $ T.unwords ["Rename", name, "to", name', "? [y/n]"]
    when yes $
      -- if user agrees then voodoo comes
      post_ (job name -/- "doRename" -?- "newName" -=- name')

  -- asks user until she enters 'y' or 'n'
  prompt message = io . fix $ \loop -> do
    T.putStrLn message
    res <- T.getLine
    case T.toUpper res of
      "Y" -> return True
      "N" -> return False
      _   -> loop


-- | Program options
data Options = Options
  { settings :: Settings
  , old      :: Text
  , new      :: Text
  }

-- | Quite a trivial options parser
options :: ParserInfo Options
options = info (helper <*> parser) fullDesc
 where
  parser = Options
    <$> parse_settings
    <*> nullOption (reader (return . T.pack) <> long "old")
    <*> nullOption (reader (return . T.pack) <> long "new")

  parse_settings = Settings
    <$> (Host <$> strOption (long "host"))
    <*> (Port <$> option (long "port"))
    <*> (User . B.pack <$> strOption (long "user"))
    <*> (APIToken . B.pack <$> strOption (long "token" <> long "password"))