packages feed

gitlab-haskell 0.1.3 → 0.1.4

raw patch · 4 files changed

+5/−475 lines, 4 filesdep −directorydep −filepathdep −gitlab-haskellPVP ok

version bump matches the API change (PVP)

Dependencies removed: directory, filepath, gitlab-haskell, moss, optparse-applicative, temporary

API changes (from Hackage documentation)

+ GitLab.Types: CommitTodo :: Text -> Text -> Text -> Maybe [Text] -> CommitTodo
+ GitLab.Types: [todo_commit_created_at] :: CommitTodo -> Text
+ GitLab.Types: [todo_commit_id] :: CommitTodo -> Text
+ GitLab.Types: [todo_commit_short_id] :: CommitTodo -> Text
+ GitLab.Types: [todo_parent_ids] :: CommitTodo -> Maybe [Text]
+ GitLab.Types: data CommitTodo

Files

README.md view
@@ -1,7 +1,5 @@ # 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: @@ -21,60 +19,7 @@ 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-```+## Applications using this library -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.+* `gitlab-tools`: a command line tool for bulk transactions against a+  GitLab server. [link](https://gitlab.com/robstewart57/gitlab-tools)
− app/Main.hs
@@ -1,397 +0,0 @@-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE OverloadedStrings #-}-module Main where--import Control.Monad-import Control.Monad.IO.Class-import Control.Monad.IO.Unlift-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-import qualified Data.ByteString.Char8 as C-import Stanford.Moss-import Data.Maybe-import System.FilePath.Posix-import System.IO.Temp-import System.Directory--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-  , usersFilename :: String-  , group :: String-  , project :: String-  , addReportersToGroup :: Bool-  , addGroupToProject :: Bool-  , isRegistered :: Bool-  , plagiarism :: Bool-  , mossUserId :: String-  , mossLang :: String-  , plagiarismProject :: String-  , plagiarismFilePaths :: String-  , parentUser :: String-  , projectLinks :: 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 "userFilename"-    <> metavar "userFilename"-    <> value ""-    <> help "name of a CSV file with user IDs" )-  <*> 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" )-  <*> switch-  ( long "plagiarism"-    <> help "use MOSS to detect plagiarism" )-  <*> strOption-  ( long "mossUser"-    <> metavar "mossUser"-    <> value ""-    <> help "MOSS user ID" )-  <*> strOption-  ( long "mossLang"-    <> metavar "mossLang"-    <> value ""-    <> help "languge to pass to MOSS" )-  <*> strOption-  ( long "plagiarismProject"-    <> metavar "plagiarismProject"-    <> value ""-    <> help "project to detect plagiarism in" )-  <*> strOption-  ( long "plagiarismFiles"-    <> metavar "plagiarismFiles"-    <> value ""-    <> help "comma separated list of plagiarism files" )-  <*> strOption-  ( long "parent"-    <> metavar "parent"-    <> value ""-    <> help "parent username of skeleton code" )-  <*> switch-  ( long "projectLinks"-    <> help "get the URL links for searched for projects" )--processOptions :: Options -> IO ()-processOptions opts = go-  where-    go-      | addReportersToGroup opts && usersFilename opts == "" = return ()-      | addReportersToGroup opts && group opts == "" =-        putStrLn "you must specify a group name too"-      | addReportersToGroup opts && addGroupToProject opts =-        putStrLn-          "you can only choose one of adding users to group or adding group to projects"-         -- add reporters to a group-      | addReportersToGroup opts && usersFilename opts /= "" = do-        text <- T.readFile (usersFilename opts)-        let usernames = T.splitOn "," text-        runGitLab-          (defaultGitLabServer-           {url = T.pack (gitlabUrl opts), token = T.pack (gitlabToken opts)})-          (addUsersToGroupDbg (T.pack (group opts)) Reporter usernames)-      | not (addReportersToGroup opts) &&-          addGroupToProject opts && null (group opts) && null (project opts) =-        error-          "for --share-project you must specify a group name and a project name"-       -- add group as a member to all projects with a given name, as Reporter-      | not (addReportersToGroup opts) && addGroupToProject opts =-        runGitLab-          (defaultGitLabServer-           {url = T.pack (gitlabUrl opts), token = T.pack (gitlabToken opts)})-          (do groups <- groupsWithNameOrPath (T.pack (group opts))-              void $-                liftIO $-                when (null groups) (error ("group not found: " ++ group opts))-              void $-                liftIO $-                when-                  (length groups > 1)-                  (error ("multiple groups found for: " ++ group opts))-               -- should only be 1 group with this head-              let grp = head groups-              projects <- projectsWithName (T.pack (project opts))-              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-      | not (addReportersToGroup opts) &&-          not (addGroupToProject opts) && isRegistered opts =-        putStrLn "--registered needs a filename with --filename"-      | not (addReportersToGroup opts) &&-          not (addGroupToProject opts) &&-          isRegistered opts && usersFilename opts == "" =-        putStrLn "--registered needs a filename with --filename"-      | not (addReportersToGroup opts) &&-          not (addGroupToProject opts) && isRegistered opts = do-        text <- T.readFile (usersFilename opts)-        let usernames = T.splitOn "," text-        runGitLab-          (defaultGitLabServer-           {url = T.pack (gitlabUrl opts), token = T.pack (gitlabToken opts)})-          (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)-      | plagiarism opts &&-          ((mossUserId opts == "") ||-           (mossLang opts == "") ||-           (plagiarismFilePaths opts == "") ||-           (plagiarismProject opts == "") ||-           (parentUser opts == "") || (usersFilename opts == "")) =-        putStrLn-          "--plagiarism needs a MOSS user, MOSS language, filepath list and a parent user"-      | plagiarism opts = do-        usersData <- readFile (usersFilename opts)-        let usernames = T.splitOn "," (T.pack usersData)-        let files = T.splitOn "," (T.pack (plagiarismFilePaths opts))-        runGitLab-          (defaultGitLabServer-           {url = T.pack (gitlabUrl opts), token = T.pack (gitlabToken opts)})-          (do reports <--                runMoss-                  files-                  usernames-                  (T.pack (parentUser opts))-                  (T.pack (plagiarismProject opts))-                  (T.pack (mossUserId opts))-                  (T.pack (mossLang opts))-              liftIO (putStrLn "MOSS reports:")-              liftIO $ mapM_ T.putStr reports)-      | projectLinks opts && null (project opts) =-        error "--projectLinks must also be used with --project"-      | projectLinks opts = do-        usersData <- readFile (usersFilename opts)-        let usernames = T.splitOn "," (T.pack usersData)-        runGitLab-          (defaultGitLabServer-           {url = T.pack (gitlabUrl opts), token = T.pack (gitlabToken opts)})-          (mapM_-            (\username -> do-                projects <--                  projectsWithNameAndUser username (T.pack (project opts))-                case projects of-                  Nothing -> return ()-                  Just proj -> do-                    isPassing <- projectCISuccess proj-                    numCommits <- projectCommits proj-                    liftIO $-                      putStrLn-                      (T.unpack (project_web_url proj) <> " (" <>-                        (if isPassing-                         then "passing, "-                         else "failing, ")-                        <> show (length numCommits) <> " commits)"))-                usernames)-      | otherwise = error "combination of flags not recognised"--{- add users -}-  -addUsersToGroupDbg ::-  (MonadIO m, MonadUnliftIO m) => Text -> AccessLevel -> [Text] -> GitLab m ()-addUsersToGroupDbg groupName access usernames = do-  (users :: [User]) <--    catMaybes <$>-    mapM (\username ->-            do maybeUser <- searchUser username-               case maybeUser of-                 Nothing -> do-                   liftIO $ putStrLn $ T.unpack username <> " not found on server."-                   return Nothing-                 u -> return u-         ) usernames-  (results :: [Either Status Member]) <--    addUsersToGroup groupName access users-  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--{- plagiarism detection -}--runMoss :: (MonadIO m, MonadUnliftIO m) => [Text] -> [Text] -> Text -> Text -> Text -> Text -> GitLab m [Text]-runMoss filepaths usernames skeletonUser projectName mossUserKey lang =-  mapM-    (\fpath -> do-       liftIO $ putStrLn ("Processing file " ++ T.unpack fpath ++ "\n")-       liftIO $-         putStrLn-           ("getting handed out code " ++-            T.unpack skeletonUser ++ "/" ++ T.unpack projectName ++ "\n")-       skeletonCode <--         fromJust <$> getCode fpath "master" skeletonUser projectName-       userSubmissions <--         mapM-           (\usr -> do-              liftIO-                (putStrLn-                   ("getting " ++ T.unpack fpath ++ " from " ++-                    T.unpack usr ++ "/" ++ T.unpack projectName))-              maybe_userCode <- getCode fpath "master" usr projectName-              case maybe_userCode of-                Nothing -> return Nothing-                Just userCode -> return (Just (usr, userCode)))-           usernames-       liftIO (putStrLn "sending job to moss")-       result <- moss fpath skeletonCode (catMaybes userSubmissions) mossUserKey lang-       liftIO $ putStrLn ("File " ++ T.unpack fpath ++ " processed.\n")-       return result-    )-    filepaths--moss :: (MonadIO m, MonadUnliftIO m) => Text -> Text -> [(Text,Text)] -> Text -> Text -> GitLab m Text-moss skeletonFilename skeletonData studentCode mossUserKey lang = do-  let language =-        case T.unpack lang of-          "C" -> C-          "CPP" -> CPP-          "Java" -> Java-          "CSharp" -> CSharp-          "Python" -> Python-          "VisualBasic" -> VisualBasic-          "Javascript" -> Javascript-          "FORTRAN" -> FORTRAN-          "ML" -> ML-          "Haskell" -> Haskell-          "Lisp" -> Lisp-          "Scheme" -> Scheme-          "Pascal" -> Pascal-          "Modula2" -> Modula2-          "Ada" -> Ada-          "Perl" -> Perl-          "TCL" -> TCL-          "Matlab" -> Matlab-          "VHDL" -> VHDL-          "Verilog" -> Verilog-          _ -> error "unrecognised MOSS language name"-  let ext =-        case T.unpack lang of-          "C" -> ".c"-          "CPP" -> ".cpp"-          "Java" -> ".java"-          "CSharp" -> ".cs"-          "Python" -> ".py"-          "VisualBasic" -> ".vb"-          "Javascript" -> ".js"-          "FORTRAN" -> ".f"-          "ML" -> ".ml"-          "Haskell" -> ".hs"-          "Lisp" -> ".lisp"-          "Scheme" -> ".scm"-          "Pascal" -> ".pas"-          "Modula2" -> ".mod"-          "Ada" -> ".ada"-          "Perl" -> ".pl"-          "TCL" -> ".tcl"-          "Matlab" -> ".m"-          "VHDL" -> ".vhdl"-          "Verilog" -> ".v"-          _ -> error "unrecognised MOSS language name"        -  let cfg :: MossCfg-      cfg = defaultMossCfg {-        mossLanguage = language-        , mossUser = C.pack (T.unpack mossUserKey)-        }-  tmpSkelFile <- liftIO $ writeSystemTempFile (takeFileName (T.unpack skeletonFilename)) (T.unpack skeletonData)-  userFiles <- mapM (\(userId,code) -> do-                        userFile <- liftIO $ writeSystemTempFile (T.unpack userId <> ext) (T.unpack code)-                        return (userFile,userId)-                    )-               studentCode-  liftIO $ withMoss cfg $ do-    addBaseFile "Skeleton" tmpSkelFile-    mapM_ (\(userFile,userId) ->-           addFile (T.unpack userId) userFile-          ) userFiles-    res <- fromJust <$> query (C.pack ("moss-" <> takeFileName (T.unpack skeletonFilename)))--    -- remove temporary files-    liftIO $ removeFile tmpSkelFile-    liftIO $ mapM_ (\(fileName,_) -> removeFile fileName) userFiles-    -    return (T.pack (C.unpack res))--getCode :: (MonadIO m, MonadUnliftIO m) => Text -> Text -> Text -> Text -> GitLab m (Maybe Text)-getCode filepath branch username projectName = do-    maybe_proj <- projectsWithNameAndUser username projectName-    case maybe_proj of-      Nothing -> return Nothing-      Just proj -> do-        maybe_file <- repositoryFiles proj filepath branch-        case maybe_file of-          Nothing -> error "repo file not found"-          Just repoFile -> do-            let blobHash = blob_id repoFile-            contents <- repositoryFileBlob (project_id proj) blobHash-            return (Just (T.pack contents))
gitlab-haskell.cabal view
@@ -1,7 +1,7 @@ cabal-version: 2.4 name:           gitlab-haskell category:       Git-version:        0.1.3+version:        0.1.4 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,25 +23,6 @@ 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-              , bytestring-              , moss-              , filepath-              , unliftio-core-              , temporary-              , directory-  default-language: Haskell2010  library   exposed-modules:
src/GitLab/Types.hs view
@@ -30,6 +30,7 @@   , Issue(..)   , Pipeline(..)   , Commit(..)+  , CommitTodo(..)   , CommitStats(..)   , Diff(..)   , Repository(..)