gitlab-haskell 0.1.1 → 0.1.2
raw patch · 3 files changed
+230/−1 lines, 3 filesdep +gitlab-haskelldep +optparse-applicativenew-component:exe:gitlab-toolsPVP ok
version bump matches the API change (PVP)
Dependencies added: gitlab-haskell, optparse-applicative
API changes (from Hackage documentation)
Files
- README.md +60/−0
- app/Main.hs +156/−0
- gitlab-haskell.cabal +14/−1
README.md view
@@ -1,5 +1,7 @@ # A Haskell library for the GitLab web API +## gitlab-haskell library+ This library interacts with a GitLab server's API. It supports queries about and updates to: @@ -18,3 +20,61 @@ The library parses JSON results into Haskell data types in the `GitLab.Types` module.++## gitlab-tools executable++This package also includes a `gitlab-tools` executable.++```+> gitlab-tools --help+Program to execute bulk GitLab actions++Usage: gitlab-tools --host host [--token token] [--filename filename]+ [--group group] [--project project]+ [--add-reporters-to-group] [--share-projects-with-group]+ [--registered]+ Executes actions against a GitLab server++Available options:+ --host host URL of the GitLab server+ --token token GitLab access token+ --filename filename name of a CSV file+ --group group name of a group+ --project project name of a project+ --add-reporters-to-group Add users as reporters to a group+ --share-projects-with-group+ Share all projects with a given name to the specific+ group+ --registered prints 'yes' or 'no' depending on whether a user+ exists on the GitLab server+ -h,--help Show this help text+```++### Examples++Sharing projects with a group:++```+> gitlab-tools \+ --host <GitLab url> --token <token> \+ --share-projects-with-group --project my_project \+ --group my_group+```++This commands finds all projects called `my_project` then adds the+`my_group` group to all of those projects as a member with the+Reporter role.++Adding users to a group:++```+> gitlab-tools \+ --host <GitLab url> --token <token> \+ --filename <filename>.csv \+ --add-reporters-to-group \+ --group my_group+```++This command reads usernames from a comma separated file, and if they+are registered on the GitLab server it adds them to the `my_group`+group with the Reporter role.
+ app/Main.hs view
@@ -0,0 +1,156 @@+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE OverloadedStrings #-}+module Main where++import Control.Monad+import Control.Monad.IO.Class+import Data.Text (Text)+import qualified Data.Text as T+import qualified Data.Text.IO as T+import GitLab+import Network.HTTP.Types.Status+import Data.Semigroup ((<>))+import Options.Applicative++main :: IO ()+main = processOptions =<< execParser opts+ where+ opts = info (parser <**> helper)+ ( fullDesc+ <> progDesc "Executes actions against a GitLab server"+ <> header "Program to execute bulk GitLab actions" )++data Options =+ Options+ { gitlabUrl :: String+ , gitlabToken :: String+ , addUsersFilename :: String+ , group :: String+ , project :: String+ , addReportersToGroup :: Bool+ , addGroupToProject :: Bool+ , isRegistered :: Bool+ }+ deriving (Show)++parser :: Parser Options+parser = Options+ <$> strOption+ ( long "host"+ <> metavar "host"+ <> help "URL of the GitLab server" )+ <*> strOption+ ( long "token"+ <> metavar "token"+ <> value ""+ <> help "GitLab access token" )+ <*> strOption+ ( long "filename"+ <> metavar "filename"+ <> value ""+ <> help "name of a CSV file" )+ <*> strOption+ ( long "group"+ <> metavar "group"+ <> value ""+ <> help "name of a group" )+ <*> strOption+ ( long "project"+ <> metavar "project"+ <> value ""+ <> help "name of a project" )+ <*> switch+ ( long "add-reporters-to-group"+ <> help "Add users as reporters to a group" )+ <*> switch+ ( long "share-projects-with-group"+ <> help "Share all projects with a given name to the specific group" )+ <*> switch+ ( long "registered"+ <> help "prints 'yes' or 'no' depending on whether a user exists on the GitLab server" )++processOptions :: Options -> IO ()+processOptions (Options _url _tok "" _grp _proj True _addGroup _isRegistered) =+ return ()+processOptions (Options _url _tok _filename "" _proj True _addGroup _isRegistered) =+ putStrLn "you must specify a group name too"+processOptions (Options _gUrl _gToken _fname _groupName _ True True _isRegistered) =+ putStrLn "you can only choose one of adding users to group or adding group to projects"++-- add reporters to a group+processOptions (Options gUrl gToken fname groupName _ True False _isRegistered) = do+ text <- T.readFile fname+ let usernames = T.splitOn "," text+ runGitLab+ (defaultGitLabServer+ { url = T.pack gUrl+ , token = T.pack gToken+ })+ (addUsersToGroupDbg (T.pack groupName) Reporter usernames)+ +-- add group as a member to all projects with a given name, as Reporter+processOptions (Options gUrl gToken _ groupName projectName False True _isRegistered) = do+ when (null groupName || null projectName)+ (error "for --share-project you must specify a group name and a project name")+ runGitLab+ (defaultGitLabServer+ { url = T.pack gUrl+ , token = T.pack gToken+ })+ (do groups <- groupsWithName (T.pack groupName)+ void $ liftIO $ when (null groups)+ (error ("group not found: " ++ groupName))+ void $ liftIO $ when (length groups > 1)+ (error ("multiple groups found for: " ++ groupName))+ -- should only be 1 group with this head+ let grp = head groups+ projects <- projectsWithName (T.pack projectName)+ mapM_+ (\prj -> do+ result <- shareProjectWithGroup (group_id grp) (project_id prj) Reporter+ case result of+ Left st -> liftIO (putStrLn ("unable to share project " ++ show (project_id prj) ++ " with group " ++ show (group_id grp) ++ ". Reason: " ++ show st))+ Right _details -> liftIO (putStrLn ("Added group " ++ show (group_id grp) ++ " to project " ++ show (project_id prj) ++ " as a Reporter"))+ )+ projects+ )++-- ask if users are registered for a given GitLab server+processOptions (Options _gUrl _gToken "" __groupName _ False False True) =+ putStrLn "--registered needs a filename with --filename"+processOptions (Options gUrl gToken fname _groupName _ False False True) = do+ text <- T.readFile fname+ let usernames = T.splitOn "," text+ runGitLab+ (defaultGitLabServer+ { url = T.pack gUrl+ , token = T.pack gToken+ })+ (mapM_+ (\usrName ->+ do res <- searchUser usrName+ -- empty list of returned users+ if null res+ then liftIO $ putStrLn (T.unpack usrName ++ ": no")+ else liftIO $ putStrLn (T.unpack usrName ++ ": yes")+ )+ usernames+ )++processOptions Options{} =+ error "combination of flags not recognised"+ +addUsersToGroupDbg ::+ (MonadIO m) => Text -> AccessLevel -> [Text] -> GitLab m ()+addUsersToGroupDbg groupName access usernames = do+ (results :: [Either Status Member]) <-+ addUsersToGroup groupName access usernames+ liftIO $ mapM_+ (\(result :: Either Status Member) ->+ case result of+ Left errorStatus -> print errorStatus+ Right member ->+ putStrLn+ ("Added to " +++ show groupName ++ ": " ++ show (member_username member)))+ results
gitlab-haskell.cabal view
@@ -1,7 +1,7 @@ cabal-version: 2.4 name: gitlab-haskell category: Git-version: 0.1.1+version: 0.1.2 synopsis: A Haskell library for the GitLab web API description: This Haskell library queries and updates the database of a GitLab instance using the GitLab web API: <https://docs.gitlab.com/ee/api/>@@ -23,6 +23,19 @@ source-repository head type: git location: https://gitlab.com/robstewart57/gitlab-haskell++executable gitlab-tools+ main-is: Main.hs+ hs-source-dirs:+ app+ ghc-options: -threaded -rtsopts -with-rtsopts=-N+ build-depends:+ base >=4.7 && <5+ , gitlab-haskell+ , text+ , http-types+ , optparse-applicative+ default-language: Haskell2010 library exposed-modules: