gerrit 0.1.0.0 → 0.1.1.0
raw patch · 13 files changed
+1909/−684 lines, 13 filesdep +aeson-casingdep +http-client-openssldep +timedep −http-client-tlsPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: aeson-casing, http-client-openssl, time
Dependencies removed: http-client-tls
API changes (from Hackage documentation)
- Gerrit: hasLabel :: Text -> Int -> GerritChange -> Bool
- Gerrit.Data: ABANDONED :: GerritChangeStatus
- Gerrit.Data: APPROVED :: GerritLabelVote
- Gerrit.Data: ChangeId :: Text -> GerritQuery
- Gerrit.Data: CommitMessage :: Text -> GerritQuery
- Gerrit.Data: DISLIKED :: GerritLabelVote
- Gerrit.Data: DRAFT :: GerritChangeStatus
- Gerrit.Data: GerritAccount :: Int -> GerritAccount
- Gerrit.Data: GerritChange :: Text -> Text -> Text -> Text -> GerritChangeStatus -> Maybe Bool -> Map Text (Maybe GerritRevision) -> Maybe Text -> Int -> Map Text GerritDetailedLabel -> GerritChange
- Gerrit.Data: GerritDetailedLabel :: [GerritDetailedLabelVote] -> Int -> GerritDetailedLabel
- Gerrit.Data: GerritDetailedLabelVote :: Maybe Int -> Int -> GerritDetailedLabelVote
- Gerrit.Data: GerritLabel :: Map GerritLabelVote GerritAccount -> GerritLabel
- Gerrit.Data: GerritRevision :: Text -> GerritRevisionKind -> GerritRevision
- Gerrit.Data: GerritVersion :: Text -> GerritVersion
- Gerrit.Data: MERGED :: GerritChangeStatus
- Gerrit.Data: NEW :: GerritChangeStatus
- Gerrit.Data: Owner :: Text -> GerritQuery
- Gerrit.Data: Project :: Text -> GerritQuery
- Gerrit.Data: RECOMMENDED :: GerritLabelVote
- Gerrit.Data: REJECTED :: GerritLabelVote
- Gerrit.Data: ReviewInput :: Maybe Text -> Maybe (Map Text Int) -> ReviewInput
- Gerrit.Data: ReviewResult :: Maybe (Map Text Int) -> Maybe Int -> ReviewResult
- Gerrit.Data: Status :: GerritChangeStatus -> GerritQuery
- Gerrit.Data: [account_id] :: GerritDetailedLabelVote -> Int
- Gerrit.Data: [all] :: GerritDetailedLabel -> [GerritDetailedLabelVote]
- Gerrit.Data: [branch] :: GerritChange -> Text
- Gerrit.Data: [current_revision] :: GerritChange -> Maybe Text
- Gerrit.Data: [default_value] :: GerritDetailedLabel -> Int
- Gerrit.Data: [id] :: GerritChange -> Text
- Gerrit.Data: [kind] :: GerritRevision -> GerritRevisionKind
- Gerrit.Data: [labels] :: GerritChange -> Map Text GerritDetailedLabel
- Gerrit.Data: [mergeable] :: GerritChange -> Maybe Bool
- Gerrit.Data: [number] :: GerritChange -> Int
- Gerrit.Data: [project] :: GerritChange -> Text
- Gerrit.Data: [ref] :: GerritRevision -> Text
- Gerrit.Data: [revisions] :: GerritChange -> Map Text (Maybe GerritRevision)
- Gerrit.Data: [riLabels] :: ReviewInput -> Maybe (Map Text Int)
- Gerrit.Data: [riMessage] :: ReviewInput -> Maybe Text
- Gerrit.Data: [rrLabels] :: ReviewResult -> Maybe (Map Text Int)
- Gerrit.Data: [rrReady] :: ReviewResult -> Maybe Int
- Gerrit.Data: [status] :: GerritChange -> GerritChangeStatus
- Gerrit.Data: [subject] :: GerritChange -> Text
- Gerrit.Data: [unused_account_id] :: GerritAccount -> Int
- Gerrit.Data: [value] :: GerritDetailedLabelVote -> Maybe Int
- Gerrit.Data: data GerritChange
- Gerrit.Data: data GerritChangeStatus
- Gerrit.Data: data GerritDetailedLabel
- Gerrit.Data: data GerritDetailedLabelVote
- Gerrit.Data: data GerritLabelVote
- Gerrit.Data: data GerritQuery
- Gerrit.Data: data GerritRevision
- Gerrit.Data: data ReviewInput
- Gerrit.Data: data ReviewResult
- Gerrit.Data: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.GerritAccount
- Gerrit.Data: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.GerritChange
- Gerrit.Data: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.GerritChangeStatus
- Gerrit.Data: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.GerritDetailedLabel
- Gerrit.Data: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.GerritDetailedLabelVote
- Gerrit.Data: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.GerritLabel
- Gerrit.Data: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.GerritLabelVote
- Gerrit.Data: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.GerritRevision
- Gerrit.Data: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.GerritRevisionKind
- Gerrit.Data: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.GerritVersion
- Gerrit.Data: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.ReviewInput
- Gerrit.Data: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.ReviewResult
- Gerrit.Data: instance Data.Aeson.Types.FromJSON.FromJSONKey Gerrit.Data.GerritLabelVote
- Gerrit.Data: instance Data.Aeson.Types.ToJSON.ToJSON Gerrit.Data.ReviewInput
- Gerrit.Data: instance Data.Aeson.Types.ToJSON.ToJSON Gerrit.Data.ReviewResult
- Gerrit.Data: instance GHC.Classes.Eq Gerrit.Data.GerritChangeStatus
- Gerrit.Data: instance GHC.Classes.Eq Gerrit.Data.GerritLabelVote
- Gerrit.Data: instance GHC.Classes.Eq Gerrit.Data.GerritRevisionKind
- Gerrit.Data: instance GHC.Classes.Eq Gerrit.Data.ReviewInput
- Gerrit.Data: instance GHC.Classes.Eq Gerrit.Data.ReviewResult
- Gerrit.Data: instance GHC.Classes.Ord Gerrit.Data.GerritLabelVote
- Gerrit.Data: instance GHC.Classes.Ord Gerrit.Data.ReviewInput
- Gerrit.Data: instance GHC.Classes.Ord Gerrit.Data.ReviewResult
- Gerrit.Data: instance GHC.Generics.Generic Gerrit.Data.GerritAccount
- Gerrit.Data: instance GHC.Generics.Generic Gerrit.Data.GerritChange
- Gerrit.Data: instance GHC.Generics.Generic Gerrit.Data.GerritChangeStatus
- Gerrit.Data: instance GHC.Generics.Generic Gerrit.Data.GerritDetailedLabel
- Gerrit.Data: instance GHC.Generics.Generic Gerrit.Data.GerritDetailedLabelVote
- Gerrit.Data: instance GHC.Generics.Generic Gerrit.Data.GerritLabel
- Gerrit.Data: instance GHC.Generics.Generic Gerrit.Data.GerritLabelVote
- Gerrit.Data: instance GHC.Generics.Generic Gerrit.Data.GerritRevision
- Gerrit.Data: instance GHC.Generics.Generic Gerrit.Data.GerritRevisionKind
- Gerrit.Data: instance GHC.Generics.Generic Gerrit.Data.GerritVersion
- Gerrit.Data: instance GHC.Generics.Generic Gerrit.Data.ReviewInput
- Gerrit.Data: instance GHC.Generics.Generic Gerrit.Data.ReviewResult
- Gerrit.Data: instance GHC.Show.Show Gerrit.Data.GerritAccount
- Gerrit.Data: instance GHC.Show.Show Gerrit.Data.GerritChange
- Gerrit.Data: instance GHC.Show.Show Gerrit.Data.GerritChangeStatus
- Gerrit.Data: instance GHC.Show.Show Gerrit.Data.GerritDetailedLabel
- Gerrit.Data: instance GHC.Show.Show Gerrit.Data.GerritDetailedLabelVote
- Gerrit.Data: instance GHC.Show.Show Gerrit.Data.GerritLabel
- Gerrit.Data: instance GHC.Show.Show Gerrit.Data.GerritLabelVote
- Gerrit.Data: instance GHC.Show.Show Gerrit.Data.GerritRevision
- Gerrit.Data: instance GHC.Show.Show Gerrit.Data.GerritRevisionKind
- Gerrit.Data: instance GHC.Show.Show Gerrit.Data.GerritVersion
- Gerrit.Data: instance GHC.Show.Show Gerrit.Data.ReviewInput
- Gerrit.Data: instance GHC.Show.Show Gerrit.Data.ReviewResult
- Gerrit.Data: newtype GerritAccount
- Gerrit.Data: newtype GerritLabel
- Gerrit.Data: newtype GerritVersion
- Gerrit.Data: queryText :: GerritQuery -> Text
- Gerrit.Event: AssigneeChanged :: Change -> User -> AssigneeChanged
- Gerrit.Event: AssigneeChangedEvent :: EventType
- Gerrit.Event: Change :: Text -> Text -> Text -> Text -> User -> Change
- Gerrit.Event: ChangeAbandoned :: Text -> User -> Change -> PatchSet -> ChangeAbandoned
- Gerrit.Event: ChangeAbandonedEvent :: EventType
- Gerrit.Event: ChangeDeleted :: Change -> User -> ChangeDeleted
- Gerrit.Event: ChangeDeletedEvent :: EventType
- Gerrit.Event: ChangeMerged :: Text -> User -> Change -> PatchSet -> ChangeMerged
- Gerrit.Event: ChangeMergedEvent :: EventType
- Gerrit.Event: ChangeRestored :: Change -> PatchSet -> User -> Text -> ChangeRestored
- Gerrit.Event: ChangeRestoredEvent :: EventType
- Gerrit.Event: CommentAdded :: Change -> PatchSet -> User -> CommentAdded
- Gerrit.Event: CommentAddedEvent :: EventType
- Gerrit.Event: DroppedOutputEvent :: EventType
- Gerrit.Event: EventAssigneeChanged :: AssigneeChanged -> Event
- Gerrit.Event: EventChangeAbandoned :: ChangeAbandoned -> Event
- Gerrit.Event: EventChangeDeleted :: ChangeDeleted -> Event
- Gerrit.Event: EventChangeMerged :: ChangeMerged -> Event
- Gerrit.Event: EventChangeRestored :: ChangeRestored -> Event
- Gerrit.Event: EventCommentAdded :: CommentAdded -> Event
- Gerrit.Event: EventDroppedOutput :: Event
- Gerrit.Event: EventHashtagsChanged :: HashtagsChanged -> Event
- Gerrit.Event: EventPatchsetCreated :: PatchsetCreated -> Event
- Gerrit.Event: EventPrivateStateChanged :: PrivateStateChanged -> Event
- Gerrit.Event: EventProjectCreated :: ProjectCreated -> Event
- Gerrit.Event: EventRefUpdated :: RefUpdated -> Event
- Gerrit.Event: EventReviewerAdded :: ReviewerAdded -> Event
- Gerrit.Event: EventReviewerDeleted :: ReviewerDeleted -> Event
- Gerrit.Event: EventTopicChanged :: TopicChanged -> Event
- Gerrit.Event: EventVoteDeleted :: VoteDeleted -> Event
- Gerrit.Event: EventWorkInProgressStateChanged :: WorkInProgressStateChanged -> Event
- Gerrit.Event: HashtagsChanged :: Change -> User -> HashtagsChanged
- Gerrit.Event: HashtagsChangedEvent :: EventType
- Gerrit.Event: PatchSet :: Int -> Text -> User -> User -> PatchSet
- Gerrit.Event: PatchsetCreated :: User -> Change -> PatchSet -> PatchsetCreated
- Gerrit.Event: PatchsetCreatedEvent :: EventType
- Gerrit.Event: PrivateStateChanged :: Change -> PatchSet -> User -> PrivateStateChanged
- Gerrit.Event: PrivateStateChangedEvent :: EventType
- Gerrit.Event: ProjectCreated :: Text -> Text -> ProjectCreated
- Gerrit.Event: ProjectCreatedEvent :: EventType
- Gerrit.Event: Ref :: Text -> Text -> Text -> Text -> Ref
- Gerrit.Event: RefUpdated :: User -> Ref -> RefUpdated
- Gerrit.Event: RefUpdatedEvent :: EventType
- Gerrit.Event: ReviewerAdded :: Change -> PatchSet -> User -> ReviewerAdded
- Gerrit.Event: ReviewerAddedEvent :: EventType
- Gerrit.Event: ReviewerDeleted :: Change -> PatchSet -> User -> ReviewerDeleted
- Gerrit.Event: ReviewerDeletedEvent :: EventType
- Gerrit.Event: TopicChanged :: Change -> User -> Text -> TopicChanged
- Gerrit.Event: TopicChangedEvent :: EventType
- Gerrit.Event: User :: Maybe Text -> Maybe Text -> Maybe Text -> User
- Gerrit.Event: VoteDeleted :: Change -> PatchSet -> User -> VoteDeleted
- Gerrit.Event: VoteDeletedEvent :: EventType
- Gerrit.Event: WorkInProgressStateChanged :: Change -> PatchSet -> User -> WorkInProgressStateChanged
- Gerrit.Event: WorkInProgressStateChangedEvent :: EventType
- Gerrit.Event: [assigneeChangedChange] :: AssigneeChanged -> Change
- Gerrit.Event: [assigneeChangedChanger] :: AssigneeChanged -> User
- Gerrit.Event: [changeAbandonedAbandoner] :: ChangeAbandoned -> User
- Gerrit.Event: [changeAbandonedChange] :: ChangeAbandoned -> Change
- Gerrit.Event: [changeAbandonedPatchSet] :: ChangeAbandoned -> PatchSet
- Gerrit.Event: [changeAbandonedProject] :: ChangeAbandoned -> Text
- Gerrit.Event: [changeBranch] :: Change -> Text
- Gerrit.Event: [changeDeletedChange] :: ChangeDeleted -> Change
- Gerrit.Event: [changeDeletedDeleter] :: ChangeDeleted -> User
- Gerrit.Event: [changeMergedChange] :: ChangeMerged -> Change
- Gerrit.Event: [changeMergedPatchSet] :: ChangeMerged -> PatchSet
- Gerrit.Event: [changeMergedProject] :: ChangeMerged -> Text
- Gerrit.Event: [changeMergedSubmitter] :: ChangeMerged -> User
- Gerrit.Event: [changeOwner] :: Change -> User
- Gerrit.Event: [changeProject] :: Change -> Text
- Gerrit.Event: [changeRestoredChange] :: ChangeRestored -> Change
- Gerrit.Event: [changeRestoredPatchSet] :: ChangeRestored -> PatchSet
- Gerrit.Event: [changeRestoredReason] :: ChangeRestored -> Text
- Gerrit.Event: [changeRestoredRestorer] :: ChangeRestored -> User
- Gerrit.Event: [changeSubject] :: Change -> Text
- Gerrit.Event: [changeUrl] :: Change -> Text
- Gerrit.Event: [commentAddedAuthor] :: CommentAdded -> User
- Gerrit.Event: [commentAddedChange] :: CommentAdded -> Change
- Gerrit.Event: [commentAddedPatchSet] :: CommentAdded -> PatchSet
- Gerrit.Event: [hashtagsChangedChange] :: HashtagsChanged -> Change
- Gerrit.Event: [hashtagsChangedEditor] :: HashtagsChanged -> User
- Gerrit.Event: [patchSetNumber] :: PatchSet -> Int
- Gerrit.Event: [patchSetRef] :: PatchSet -> Text
- Gerrit.Event: [patchSetUploader] :: PatchSet -> User
- Gerrit.Event: [patchsetAuthor] :: PatchSet -> User
- Gerrit.Event: [patchsetCreatedChange] :: PatchsetCreated -> Change
- Gerrit.Event: [patchsetCreatedPatchSet] :: PatchsetCreated -> PatchSet
- Gerrit.Event: [patchsetCreatedUploader] :: PatchsetCreated -> User
- Gerrit.Event: [privateStateChangedChange] :: PrivateStateChanged -> Change
- Gerrit.Event: [privateStateChangedChanger] :: PrivateStateChanged -> User
- Gerrit.Event: [privateStateChangedPatchSet] :: PrivateStateChanged -> PatchSet
- Gerrit.Event: [projectCreatedHeadName] :: ProjectCreated -> Text
- Gerrit.Event: [projectCreatedProjectName] :: ProjectCreated -> Text
- Gerrit.Event: [refNewRev] :: Ref -> Text
- Gerrit.Event: [refOldRev] :: Ref -> Text
- Gerrit.Event: [refProject] :: Ref -> Text
- Gerrit.Event: [refRefName] :: Ref -> Text
- Gerrit.Event: [refUpdatedRefUpdate] :: RefUpdated -> Ref
- Gerrit.Event: [refUpdatedSubmitter] :: RefUpdated -> User
- Gerrit.Event: [reviewerAddedAdder] :: ReviewerAdded -> User
- Gerrit.Event: [reviewerAddedChange] :: ReviewerAdded -> Change
- Gerrit.Event: [reviewerAddedPatchSet] :: ReviewerAdded -> PatchSet
- Gerrit.Event: [reviewerDeletedChange] :: ReviewerDeleted -> Change
- Gerrit.Event: [reviewerDeletedPatchSet] :: ReviewerDeleted -> PatchSet
- Gerrit.Event: [reviewerDeletedRemover] :: ReviewerDeleted -> User
- Gerrit.Event: [topicChangedChange] :: TopicChanged -> Change
- Gerrit.Event: [topicChangedChanger] :: TopicChanged -> User
- Gerrit.Event: [topicChangedOldTopic] :: TopicChanged -> Text
- Gerrit.Event: [userEmail] :: User -> Maybe Text
- Gerrit.Event: [userName] :: User -> Maybe Text
- Gerrit.Event: [userUsername] :: User -> Maybe Text
- Gerrit.Event: [voteDeletedChange] :: VoteDeleted -> Change
- Gerrit.Event: [voteDeletedPatchSet] :: VoteDeleted -> PatchSet
- Gerrit.Event: [voteDeletedRemover] :: VoteDeleted -> User
- Gerrit.Event: [workInProgressStateChangedChange] :: WorkInProgressStateChanged -> Change
- Gerrit.Event: [workInProgressStateChangedChanger] :: WorkInProgressStateChanged -> User
- Gerrit.Event: [workInProgressStateChangedPatchSet] :: WorkInProgressStateChanged -> PatchSet
- Gerrit.Event: data AssigneeChanged
- Gerrit.Event: data Change
- Gerrit.Event: data ChangeAbandoned
- Gerrit.Event: data ChangeDeleted
- Gerrit.Event: data ChangeMerged
- Gerrit.Event: data ChangeRestored
- Gerrit.Event: data CommentAdded
- Gerrit.Event: data Event
- Gerrit.Event: data EventType
- Gerrit.Event: data HashtagsChanged
- Gerrit.Event: data PatchSet
- Gerrit.Event: data PatchsetCreated
- Gerrit.Event: data PrivateStateChanged
- Gerrit.Event: data ProjectCreated
- Gerrit.Event: data Ref
- Gerrit.Event: data RefUpdated
- Gerrit.Event: data ReviewerAdded
- Gerrit.Event: data ReviewerDeleted
- Gerrit.Event: data TopicChanged
- Gerrit.Event: data User
- Gerrit.Event: data VoteDeleted
- Gerrit.Event: data WorkInProgressStateChanged
- Gerrit.Event: eventName :: EventType -> Text
- Gerrit.Event: getChange :: Event -> Maybe Change
- Gerrit.Event: getEventType :: Event -> EventType
- Gerrit.Event: getUser :: Event -> Maybe User
- Gerrit.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Event.AssigneeChanged
- Gerrit.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Event.Change
- Gerrit.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Event.ChangeAbandoned
- Gerrit.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Event.ChangeDeleted
- Gerrit.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Event.ChangeMerged
- Gerrit.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Event.ChangeRestored
- Gerrit.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Event.CommentAdded
- Gerrit.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Event.Event
- Gerrit.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Event.EventType
- Gerrit.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Event.HashtagsChanged
- Gerrit.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Event.PatchSet
- Gerrit.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Event.PatchsetCreated
- Gerrit.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Event.PrivateStateChanged
- Gerrit.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Event.ProjectCreated
- Gerrit.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Event.Ref
- Gerrit.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Event.RefUpdated
- Gerrit.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Event.ReviewerAdded
- Gerrit.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Event.ReviewerDeleted
- Gerrit.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Event.TopicChanged
- Gerrit.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Event.User
- Gerrit.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Event.VoteDeleted
- Gerrit.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Event.WorkInProgressStateChanged
- Gerrit.Event: instance GHC.Classes.Eq Gerrit.Event.AssigneeChanged
- Gerrit.Event: instance GHC.Classes.Eq Gerrit.Event.Change
- Gerrit.Event: instance GHC.Classes.Eq Gerrit.Event.ChangeAbandoned
- Gerrit.Event: instance GHC.Classes.Eq Gerrit.Event.ChangeDeleted
- Gerrit.Event: instance GHC.Classes.Eq Gerrit.Event.ChangeMerged
- Gerrit.Event: instance GHC.Classes.Eq Gerrit.Event.ChangeRestored
- Gerrit.Event: instance GHC.Classes.Eq Gerrit.Event.CommentAdded
- Gerrit.Event: instance GHC.Classes.Eq Gerrit.Event.Event
- Gerrit.Event: instance GHC.Classes.Eq Gerrit.Event.EventType
- Gerrit.Event: instance GHC.Classes.Eq Gerrit.Event.HashtagsChanged
- Gerrit.Event: instance GHC.Classes.Eq Gerrit.Event.PatchSet
- Gerrit.Event: instance GHC.Classes.Eq Gerrit.Event.PatchsetCreated
- Gerrit.Event: instance GHC.Classes.Eq Gerrit.Event.PrivateStateChanged
- Gerrit.Event: instance GHC.Classes.Eq Gerrit.Event.ProjectCreated
- Gerrit.Event: instance GHC.Classes.Eq Gerrit.Event.Ref
- Gerrit.Event: instance GHC.Classes.Eq Gerrit.Event.RefUpdated
- Gerrit.Event: instance GHC.Classes.Eq Gerrit.Event.ReviewerAdded
- Gerrit.Event: instance GHC.Classes.Eq Gerrit.Event.ReviewerDeleted
- Gerrit.Event: instance GHC.Classes.Eq Gerrit.Event.TopicChanged
- Gerrit.Event: instance GHC.Classes.Eq Gerrit.Event.User
- Gerrit.Event: instance GHC.Classes.Eq Gerrit.Event.VoteDeleted
- Gerrit.Event: instance GHC.Classes.Eq Gerrit.Event.WorkInProgressStateChanged
- Gerrit.Event: instance GHC.Generics.Generic Gerrit.Event.AssigneeChanged
- Gerrit.Event: instance GHC.Generics.Generic Gerrit.Event.Change
- Gerrit.Event: instance GHC.Generics.Generic Gerrit.Event.ChangeAbandoned
- Gerrit.Event: instance GHC.Generics.Generic Gerrit.Event.ChangeDeleted
- Gerrit.Event: instance GHC.Generics.Generic Gerrit.Event.ChangeMerged
- Gerrit.Event: instance GHC.Generics.Generic Gerrit.Event.ChangeRestored
- Gerrit.Event: instance GHC.Generics.Generic Gerrit.Event.CommentAdded
- Gerrit.Event: instance GHC.Generics.Generic Gerrit.Event.HashtagsChanged
- Gerrit.Event: instance GHC.Generics.Generic Gerrit.Event.PatchSet
- Gerrit.Event: instance GHC.Generics.Generic Gerrit.Event.PatchsetCreated
- Gerrit.Event: instance GHC.Generics.Generic Gerrit.Event.PrivateStateChanged
- Gerrit.Event: instance GHC.Generics.Generic Gerrit.Event.ProjectCreated
- Gerrit.Event: instance GHC.Generics.Generic Gerrit.Event.Ref
- Gerrit.Event: instance GHC.Generics.Generic Gerrit.Event.RefUpdated
- Gerrit.Event: instance GHC.Generics.Generic Gerrit.Event.ReviewerAdded
- Gerrit.Event: instance GHC.Generics.Generic Gerrit.Event.ReviewerDeleted
- Gerrit.Event: instance GHC.Generics.Generic Gerrit.Event.TopicChanged
- Gerrit.Event: instance GHC.Generics.Generic Gerrit.Event.User
- Gerrit.Event: instance GHC.Generics.Generic Gerrit.Event.VoteDeleted
- Gerrit.Event: instance GHC.Generics.Generic Gerrit.Event.WorkInProgressStateChanged
- Gerrit.Event: instance GHC.Show.Show Gerrit.Event.AssigneeChanged
- Gerrit.Event: instance GHC.Show.Show Gerrit.Event.Change
- Gerrit.Event: instance GHC.Show.Show Gerrit.Event.ChangeAbandoned
- Gerrit.Event: instance GHC.Show.Show Gerrit.Event.ChangeDeleted
- Gerrit.Event: instance GHC.Show.Show Gerrit.Event.ChangeMerged
- Gerrit.Event: instance GHC.Show.Show Gerrit.Event.ChangeRestored
- Gerrit.Event: instance GHC.Show.Show Gerrit.Event.CommentAdded
- Gerrit.Event: instance GHC.Show.Show Gerrit.Event.Event
- Gerrit.Event: instance GHC.Show.Show Gerrit.Event.EventType
- Gerrit.Event: instance GHC.Show.Show Gerrit.Event.HashtagsChanged
- Gerrit.Event: instance GHC.Show.Show Gerrit.Event.PatchSet
- Gerrit.Event: instance GHC.Show.Show Gerrit.Event.PatchsetCreated
- Gerrit.Event: instance GHC.Show.Show Gerrit.Event.PrivateStateChanged
- Gerrit.Event: instance GHC.Show.Show Gerrit.Event.ProjectCreated
- Gerrit.Event: instance GHC.Show.Show Gerrit.Event.Ref
- Gerrit.Event: instance GHC.Show.Show Gerrit.Event.RefUpdated
- Gerrit.Event: instance GHC.Show.Show Gerrit.Event.ReviewerAdded
- Gerrit.Event: instance GHC.Show.Show Gerrit.Event.ReviewerDeleted
- Gerrit.Event: instance GHC.Show.Show Gerrit.Event.TopicChanged
- Gerrit.Event: instance GHC.Show.Show Gerrit.Event.User
- Gerrit.Event: instance GHC.Show.Show Gerrit.Event.VoteDeleted
- Gerrit.Event: instance GHC.Show.Show Gerrit.Event.WorkInProgressStateChanged
+ Gerrit: After :: UTCTime -> GerritQuery
+ Gerrit: CanSee :: Text -> GerritAccountQuery
+ Gerrit: Email :: Text -> GerritAccountQuery
+ Gerrit: GerritAccount :: Int -> Text -> Maybe Text -> Maybe Text -> Maybe Bool -> GerritAccount
+ Gerrit: IsActive :: GerritAccountQuery
+ Gerrit: IsInactive :: GerritAccountQuery
+ Gerrit: Name :: Text -> GerritAccountQuery
+ Gerrit: Prefix :: Text -> GerritProjectQuery
+ Gerrit: Regexp :: Text -> GerritProjectQuery
+ Gerrit: Username :: Text -> GerritAccountQuery
+ Gerrit: [created] :: GerritChange -> GerritTime
+ Gerrit: [deletions] :: GerritChange -> Int
+ Gerrit: [gerritAccountEmail] :: GerritAccount -> Maybe Text
+ Gerrit: [gerritAccountHasMore] :: GerritAccount -> Maybe Bool
+ Gerrit: [gerritAccountId] :: GerritAccount -> Int
+ Gerrit: [gerritAccountName] :: GerritAccount -> Text
+ Gerrit: [gerritAccountUsername] :: GerritAccount -> Maybe Text
+ Gerrit: [insertions] :: GerritChange -> Int
+ Gerrit: [messages] :: GerritChange -> [GerritChangeMessage]
+ Gerrit: [more_changes] :: GerritChange -> Maybe Bool
+ Gerrit: [owner] :: GerritChange -> GerritAuthor
+ Gerrit: [submitted] :: GerritChange -> Maybe GerritTime
+ Gerrit: [submitter] :: GerritChange -> Maybe GerritAuthor
+ Gerrit: [updated] :: GerritChange -> GerritTime
+ Gerrit: data GerritAccount
+ Gerrit: data GerritAccountQuery
+ Gerrit: data GerritProjectQuery
+ Gerrit: getAccount :: Int -> NonEmpty GerritAccountQuery -> GerritClient -> IO [GerritAccount]
+ Gerrit: getAccountId :: Int -> NonEmpty GerritAccountQuery -> GerritClient -> IO [GerritAccountId]
+ Gerrit: getClient :: Text -> Maybe (Text, Text) -> IO GerritClient
+ Gerrit: getProjects :: Int -> GerritProjectQuery -> Maybe Int -> GerritClient -> IO GerritProjectsMessage
+ Gerrit: serverUrl :: GerritClient -> Text
+ Gerrit.Data.Account: CanSee :: Text -> GerritAccountQuery
+ Gerrit.Data.Account: Email :: Text -> GerritAccountQuery
+ Gerrit.Data.Account: GerritAccount :: Int -> Text -> Maybe Text -> Maybe Text -> Maybe Bool -> GerritAccount
+ Gerrit.Data.Account: GerritAccountId :: Int -> Maybe Bool -> GerritAccountId
+ Gerrit.Data.Account: IsActive :: GerritAccountQuery
+ Gerrit.Data.Account: IsInactive :: GerritAccountQuery
+ Gerrit.Data.Account: Name :: Text -> GerritAccountQuery
+ Gerrit.Data.Account: Username :: Text -> GerritAccountQuery
+ Gerrit.Data.Account: [gerritAccountEmail] :: GerritAccount -> Maybe Text
+ Gerrit.Data.Account: [gerritAccountHasMore'] :: GerritAccountId -> Maybe Bool
+ Gerrit.Data.Account: [gerritAccountHasMore] :: GerritAccount -> Maybe Bool
+ Gerrit.Data.Account: [gerritAccountId'] :: GerritAccountId -> Int
+ Gerrit.Data.Account: [gerritAccountId] :: GerritAccount -> Int
+ Gerrit.Data.Account: [gerritAccountName] :: GerritAccount -> Text
+ Gerrit.Data.Account: [gerritAccountUsername] :: GerritAccount -> Maybe Text
+ Gerrit.Data.Account: accountQs :: Int -> NonEmpty GerritAccountQuery -> Text
+ Gerrit.Data.Account: data GerritAccount
+ Gerrit.Data.Account: data GerritAccountId
+ Gerrit.Data.Account: data GerritAccountQuery
+ Gerrit.Data.Account: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Account.GerritAccount
+ Gerrit.Data.Account: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Account.GerritAccountId
+ Gerrit.Data.Account: instance GHC.Classes.Eq Gerrit.Data.Account.GerritAccount
+ Gerrit.Data.Account: instance GHC.Classes.Eq Gerrit.Data.Account.GerritAccountId
+ Gerrit.Data.Account: instance GHC.Show.Show Gerrit.Data.Account.GerritAccount
+ Gerrit.Data.Account: instance GHC.Show.Show Gerrit.Data.Account.GerritAccountId
+ Gerrit.Data.Account: userQueryText :: GerritAccountQuery -> Text
+ Gerrit.Data.Change: ABANDONED :: GerritChangeStatus
+ Gerrit.Data.Change: After :: UTCTime -> GerritQuery
+ Gerrit.Data.Change: ChangeId :: Text -> GerritQuery
+ Gerrit.Data.Change: CommitMessage :: Text -> GerritQuery
+ Gerrit.Data.Change: DRAFT :: GerritChangeStatus
+ Gerrit.Data.Change: GerritAuthor :: Int -> Text -> Maybe Text -> Maybe Text -> GerritAuthor
+ Gerrit.Data.Change: GerritChange :: Text -> Text -> Text -> Text -> GerritChangeStatus -> Maybe Bool -> Map Text (Maybe GerritRevision) -> Maybe Text -> Int -> Map Text GerritDetailedLabel -> [GerritChangeMessage] -> GerritAuthor -> GerritTime -> GerritTime -> Maybe GerritTime -> Maybe GerritAuthor -> Int -> Int -> Maybe Bool -> GerritChange
+ Gerrit.Data.Change: GerritChangeMessage :: Text -> Maybe GerritAuthor -> GerritTime -> Text -> GerritChangeMessage
+ Gerrit.Data.Change: GerritCommit :: GerritCommitAuthor -> GerritCommitAuthor -> Text -> Text -> GerritCommit
+ Gerrit.Data.Change: GerritCommitAuthor :: Text -> Maybe Text -> GerritTime -> GerritCommitAuthor
+ Gerrit.Data.Change: GerritDetailedLabel :: Maybe [GerritDetailedLabelVote] -> Int -> GerritDetailedLabel
+ Gerrit.Data.Change: GerritDetailedLabelVote :: Maybe Int -> Int -> GerritDetailedLabelVote
+ Gerrit.Data.Change: GerritFile :: Maybe Text -> Maybe Int -> Maybe Int -> Maybe Int -> Maybe Int -> GerritFile
+ Gerrit.Data.Change: GerritRevision :: Text -> GerritRevisionKind -> Map Text GerritFile -> GerritCommit -> GerritAuthor -> GerritRevision
+ Gerrit.Data.Change: GerritTime :: UTCTime -> GerritTime
+ Gerrit.Data.Change: MERGED :: GerritChangeStatus
+ Gerrit.Data.Change: MERGE_FIRST_PARENT_UPDATE :: GerritRevisionKind
+ Gerrit.Data.Change: NEW :: GerritChangeStatus
+ Gerrit.Data.Change: NO_CHANGE :: GerritRevisionKind
+ Gerrit.Data.Change: NO_CODE_CHANGE :: GerritRevisionKind
+ Gerrit.Data.Change: Owner :: Text -> GerritQuery
+ Gerrit.Data.Change: Project :: Text -> GerritQuery
+ Gerrit.Data.Change: REWORK :: GerritRevisionKind
+ Gerrit.Data.Change: Status :: GerritChangeStatus -> GerritQuery
+ Gerrit.Data.Change: TRIVIAL_REBASE :: GerritRevisionKind
+ Gerrit.Data.Change: [aAccountId] :: GerritAuthor -> Int
+ Gerrit.Data.Change: [aEmail] :: GerritAuthor -> Maybe Text
+ Gerrit.Data.Change: [aName] :: GerritAuthor -> Text
+ Gerrit.Data.Change: [aUsername] :: GerritAuthor -> Maybe Text
+ Gerrit.Data.Change: [account_id] :: GerritDetailedLabelVote -> Int
+ Gerrit.Data.Change: [all] :: GerritDetailedLabel -> Maybe [GerritDetailedLabelVote]
+ Gerrit.Data.Change: [branch] :: GerritChange -> Text
+ Gerrit.Data.Change: [cAuthor] :: GerritCommit -> GerritCommitAuthor
+ Gerrit.Data.Change: [cCommitter] :: GerritCommit -> GerritCommitAuthor
+ Gerrit.Data.Change: [cMessage] :: GerritCommit -> Text
+ Gerrit.Data.Change: [cSubject] :: GerritCommit -> Text
+ Gerrit.Data.Change: [caDate] :: GerritCommitAuthor -> GerritTime
+ Gerrit.Data.Change: [caEmail] :: GerritCommitAuthor -> Maybe Text
+ Gerrit.Data.Change: [caName] :: GerritCommitAuthor -> Text
+ Gerrit.Data.Change: [created] :: GerritChange -> GerritTime
+ Gerrit.Data.Change: [current_revision] :: GerritChange -> Maybe Text
+ Gerrit.Data.Change: [default_value] :: GerritDetailedLabel -> Int
+ Gerrit.Data.Change: [deletions] :: GerritChange -> Int
+ Gerrit.Data.Change: [gfLinesDeleted] :: GerritFile -> Maybe Int
+ Gerrit.Data.Change: [gfLinesInserted] :: GerritFile -> Maybe Int
+ Gerrit.Data.Change: [gfSizeDelta] :: GerritFile -> Maybe Int
+ Gerrit.Data.Change: [gfSize] :: GerritFile -> Maybe Int
+ Gerrit.Data.Change: [gfStatus] :: GerritFile -> Maybe Text
+ Gerrit.Data.Change: [grCommit] :: GerritRevision -> GerritCommit
+ Gerrit.Data.Change: [grFiles] :: GerritRevision -> Map Text GerritFile
+ Gerrit.Data.Change: [grKind] :: GerritRevision -> GerritRevisionKind
+ Gerrit.Data.Change: [grRef] :: GerritRevision -> Text
+ Gerrit.Data.Change: [grUploader] :: GerritRevision -> GerritAuthor
+ Gerrit.Data.Change: [id] :: GerritChange -> Text
+ Gerrit.Data.Change: [insertions] :: GerritChange -> Int
+ Gerrit.Data.Change: [labels] :: GerritChange -> Map Text GerritDetailedLabel
+ Gerrit.Data.Change: [mAuthor] :: GerritChangeMessage -> Maybe GerritAuthor
+ Gerrit.Data.Change: [mDate] :: GerritChangeMessage -> GerritTime
+ Gerrit.Data.Change: [mId] :: GerritChangeMessage -> Text
+ Gerrit.Data.Change: [mMessage] :: GerritChangeMessage -> Text
+ Gerrit.Data.Change: [mergeable] :: GerritChange -> Maybe Bool
+ Gerrit.Data.Change: [messages] :: GerritChange -> [GerritChangeMessage]
+ Gerrit.Data.Change: [more_changes] :: GerritChange -> Maybe Bool
+ Gerrit.Data.Change: [number] :: GerritChange -> Int
+ Gerrit.Data.Change: [owner] :: GerritChange -> GerritAuthor
+ Gerrit.Data.Change: [project] :: GerritChange -> Text
+ Gerrit.Data.Change: [revisions] :: GerritChange -> Map Text (Maybe GerritRevision)
+ Gerrit.Data.Change: [status] :: GerritChange -> GerritChangeStatus
+ Gerrit.Data.Change: [subject] :: GerritChange -> Text
+ Gerrit.Data.Change: [submitted] :: GerritChange -> Maybe GerritTime
+ Gerrit.Data.Change: [submitter] :: GerritChange -> Maybe GerritAuthor
+ Gerrit.Data.Change: [unGerritTime] :: GerritTime -> UTCTime
+ Gerrit.Data.Change: [updated] :: GerritChange -> GerritTime
+ Gerrit.Data.Change: [value] :: GerritDetailedLabelVote -> Maybe Int
+ Gerrit.Data.Change: changeQS :: Int -> [GerritQuery] -> Maybe Int -> Text
+ Gerrit.Data.Change: data GerritAuthor
+ Gerrit.Data.Change: data GerritChange
+ Gerrit.Data.Change: data GerritChangeMessage
+ Gerrit.Data.Change: data GerritChangeStatus
+ Gerrit.Data.Change: data GerritCommit
+ Gerrit.Data.Change: data GerritCommitAuthor
+ Gerrit.Data.Change: data GerritDetailedLabel
+ Gerrit.Data.Change: data GerritDetailedLabelVote
+ Gerrit.Data.Change: data GerritFile
+ Gerrit.Data.Change: data GerritQuery
+ Gerrit.Data.Change: data GerritRevision
+ Gerrit.Data.Change: data GerritRevisionKind
+ Gerrit.Data.Change: defaultQueryChangeOptions :: Text
+ Gerrit.Data.Change: hasLabel :: Text -> Int -> GerritChange -> Bool
+ Gerrit.Data.Change: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Change.GerritAuthor
+ Gerrit.Data.Change: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Change.GerritChange
+ Gerrit.Data.Change: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Change.GerritChangeMessage
+ Gerrit.Data.Change: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Change.GerritChangeStatus
+ Gerrit.Data.Change: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Change.GerritCommit
+ Gerrit.Data.Change: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Change.GerritCommitAuthor
+ Gerrit.Data.Change: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Change.GerritDetailedLabel
+ Gerrit.Data.Change: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Change.GerritDetailedLabelVote
+ Gerrit.Data.Change: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Change.GerritFile
+ Gerrit.Data.Change: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Change.GerritRevision
+ Gerrit.Data.Change: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Change.GerritRevisionKind
+ Gerrit.Data.Change: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Change.GerritTime
+ Gerrit.Data.Change: instance GHC.Classes.Eq Gerrit.Data.Change.GerritChangeStatus
+ Gerrit.Data.Change: instance GHC.Classes.Eq Gerrit.Data.Change.GerritRevisionKind
+ Gerrit.Data.Change: instance GHC.Generics.Generic Gerrit.Data.Change.GerritAuthor
+ Gerrit.Data.Change: instance GHC.Generics.Generic Gerrit.Data.Change.GerritChange
+ Gerrit.Data.Change: instance GHC.Generics.Generic Gerrit.Data.Change.GerritChangeMessage
+ Gerrit.Data.Change: instance GHC.Generics.Generic Gerrit.Data.Change.GerritChangeStatus
+ Gerrit.Data.Change: instance GHC.Generics.Generic Gerrit.Data.Change.GerritCommit
+ Gerrit.Data.Change: instance GHC.Generics.Generic Gerrit.Data.Change.GerritCommitAuthor
+ Gerrit.Data.Change: instance GHC.Generics.Generic Gerrit.Data.Change.GerritDetailedLabel
+ Gerrit.Data.Change: instance GHC.Generics.Generic Gerrit.Data.Change.GerritDetailedLabelVote
+ Gerrit.Data.Change: instance GHC.Generics.Generic Gerrit.Data.Change.GerritFile
+ Gerrit.Data.Change: instance GHC.Generics.Generic Gerrit.Data.Change.GerritRevision
+ Gerrit.Data.Change: instance GHC.Generics.Generic Gerrit.Data.Change.GerritRevisionKind
+ Gerrit.Data.Change: instance GHC.Show.Show Gerrit.Data.Change.GerritAuthor
+ Gerrit.Data.Change: instance GHC.Show.Show Gerrit.Data.Change.GerritChange
+ Gerrit.Data.Change: instance GHC.Show.Show Gerrit.Data.Change.GerritChangeMessage
+ Gerrit.Data.Change: instance GHC.Show.Show Gerrit.Data.Change.GerritChangeStatus
+ Gerrit.Data.Change: instance GHC.Show.Show Gerrit.Data.Change.GerritCommit
+ Gerrit.Data.Change: instance GHC.Show.Show Gerrit.Data.Change.GerritCommitAuthor
+ Gerrit.Data.Change: instance GHC.Show.Show Gerrit.Data.Change.GerritDetailedLabel
+ Gerrit.Data.Change: instance GHC.Show.Show Gerrit.Data.Change.GerritDetailedLabelVote
+ Gerrit.Data.Change: instance GHC.Show.Show Gerrit.Data.Change.GerritFile
+ Gerrit.Data.Change: instance GHC.Show.Show Gerrit.Data.Change.GerritRevision
+ Gerrit.Data.Change: instance GHC.Show.Show Gerrit.Data.Change.GerritRevisionKind
+ Gerrit.Data.Change: instance GHC.Show.Show Gerrit.Data.Change.GerritTime
+ Gerrit.Data.Change: newtype GerritTime
+ Gerrit.Data.Change: queryText :: GerritQuery -> Text
+ Gerrit.Data.Event: AssigneeChanged :: Change -> User -> Int64 -> AssigneeChanged
+ Gerrit.Data.Event: AssigneeChangedEvent :: EventType
+ Gerrit.Data.Event: Change :: Text -> Text -> Text -> Int -> Text -> User -> Change
+ Gerrit.Data.Event: ChangeAbandoned :: Text -> User -> Change -> PatchSet -> Maybe Text -> Int64 -> ChangeAbandoned
+ Gerrit.Data.Event: ChangeAbandonedEvent :: EventType
+ Gerrit.Data.Event: ChangeDeleted :: Change -> User -> ChangeDeleted
+ Gerrit.Data.Event: ChangeDeletedEvent :: EventType
+ Gerrit.Data.Event: ChangeMerged :: Text -> User -> Change -> PatchSet -> Int64 -> ChangeMerged
+ Gerrit.Data.Event: ChangeMergedEvent :: EventType
+ Gerrit.Data.Event: ChangeRestored :: Change -> PatchSet -> User -> Maybe Text -> Int64 -> ChangeRestored
+ Gerrit.Data.Event: ChangeRestoredEvent :: EventType
+ Gerrit.Data.Event: CommentAdded :: Change -> PatchSet -> User -> Int64 -> CommentAdded
+ Gerrit.Data.Event: CommentAddedEvent :: EventType
+ Gerrit.Data.Event: DroppedOutputEvent :: EventType
+ Gerrit.Data.Event: EventAssigneeChanged :: AssigneeChanged -> Event
+ Gerrit.Data.Event: EventChangeAbandoned :: ChangeAbandoned -> Event
+ Gerrit.Data.Event: EventChangeDeleted :: ChangeDeleted -> Event
+ Gerrit.Data.Event: EventChangeMerged :: ChangeMerged -> Event
+ Gerrit.Data.Event: EventChangeRestored :: ChangeRestored -> Event
+ Gerrit.Data.Event: EventCommentAdded :: CommentAdded -> Event
+ Gerrit.Data.Event: EventDroppedOutput :: Event
+ Gerrit.Data.Event: EventHashtagsChanged :: HashtagsChanged -> Event
+ Gerrit.Data.Event: EventPatchsetCreated :: PatchsetCreated -> Event
+ Gerrit.Data.Event: EventPrivateStateChanged :: PrivateStateChanged -> Event
+ Gerrit.Data.Event: EventProjectCreated :: ProjectCreated -> Event
+ Gerrit.Data.Event: EventRefUpdated :: RefUpdated -> Event
+ Gerrit.Data.Event: EventReviewerAdded :: ReviewerAdded -> Event
+ Gerrit.Data.Event: EventReviewerDeleted :: ReviewerDeleted -> Event
+ Gerrit.Data.Event: EventTopicChanged :: TopicChanged -> Event
+ Gerrit.Data.Event: EventVoteDeleted :: VoteDeleted -> Event
+ Gerrit.Data.Event: EventWorkInProgressStateChanged :: WorkInProgressStateChanged -> Event
+ Gerrit.Data.Event: HashtagsChanged :: Change -> User -> Int64 -> HashtagsChanged
+ Gerrit.Data.Event: HashtagsChangedEvent :: EventType
+ Gerrit.Data.Event: PatchSet :: Int -> Text -> User -> User -> PatchSet
+ Gerrit.Data.Event: PatchsetCreated :: User -> Change -> PatchSet -> Int64 -> PatchsetCreated
+ Gerrit.Data.Event: PatchsetCreatedEvent :: EventType
+ Gerrit.Data.Event: PrivateStateChanged :: Change -> PatchSet -> User -> Int64 -> PrivateStateChanged
+ Gerrit.Data.Event: PrivateStateChangedEvent :: EventType
+ Gerrit.Data.Event: ProjectCreated :: Text -> Text -> Int64 -> ProjectCreated
+ Gerrit.Data.Event: ProjectCreatedEvent :: EventType
+ Gerrit.Data.Event: Ref :: Text -> Text -> Text -> Text -> Ref
+ Gerrit.Data.Event: RefUpdated :: User -> Ref -> Int64 -> RefUpdated
+ Gerrit.Data.Event: RefUpdatedEvent :: EventType
+ Gerrit.Data.Event: ReviewerAdded :: Change -> PatchSet -> User -> Int64 -> ReviewerAdded
+ Gerrit.Data.Event: ReviewerAddedEvent :: EventType
+ Gerrit.Data.Event: ReviewerDeleted :: Change -> PatchSet -> User -> Int64 -> ReviewerDeleted
+ Gerrit.Data.Event: ReviewerDeletedEvent :: EventType
+ Gerrit.Data.Event: TopicChanged :: Change -> User -> Text -> Int64 -> TopicChanged
+ Gerrit.Data.Event: TopicChangedEvent :: EventType
+ Gerrit.Data.Event: User :: Maybe Text -> Maybe Text -> Maybe Text -> User
+ Gerrit.Data.Event: VoteDeleted :: Change -> PatchSet -> User -> VoteDeleted
+ Gerrit.Data.Event: VoteDeletedEvent :: EventType
+ Gerrit.Data.Event: WorkInProgressStateChanged :: Change -> PatchSet -> User -> Int64 -> WorkInProgressStateChanged
+ Gerrit.Data.Event: WorkInProgressStateChangedEvent :: EventType
+ Gerrit.Data.Event: [assigneeChangedChange] :: AssigneeChanged -> Change
+ Gerrit.Data.Event: [assigneeChangedChanger] :: AssigneeChanged -> User
+ Gerrit.Data.Event: [assigneeChangedEventCreatedOn] :: AssigneeChanged -> Int64
+ Gerrit.Data.Event: [changeAbandonedAbandoner] :: ChangeAbandoned -> User
+ Gerrit.Data.Event: [changeAbandonedChange] :: ChangeAbandoned -> Change
+ Gerrit.Data.Event: [changeAbandonedEventCreatedOn] :: ChangeAbandoned -> Int64
+ Gerrit.Data.Event: [changeAbandonedPatchSet] :: ChangeAbandoned -> PatchSet
+ Gerrit.Data.Event: [changeAbandonedProject] :: ChangeAbandoned -> Text
+ Gerrit.Data.Event: [changeAbandonedReason] :: ChangeAbandoned -> Maybe Text
+ Gerrit.Data.Event: [changeBranch] :: Change -> Text
+ Gerrit.Data.Event: [changeDeletedChange] :: ChangeDeleted -> Change
+ Gerrit.Data.Event: [changeDeletedDeleter] :: ChangeDeleted -> User
+ Gerrit.Data.Event: [changeMergedChange] :: ChangeMerged -> Change
+ Gerrit.Data.Event: [changeMergedEventCreatedOn] :: ChangeMerged -> Int64
+ Gerrit.Data.Event: [changeMergedPatchSet] :: ChangeMerged -> PatchSet
+ Gerrit.Data.Event: [changeMergedProject] :: ChangeMerged -> Text
+ Gerrit.Data.Event: [changeMergedSubmitter] :: ChangeMerged -> User
+ Gerrit.Data.Event: [changeNumber] :: Change -> Int
+ Gerrit.Data.Event: [changeOwner] :: Change -> User
+ Gerrit.Data.Event: [changeProject] :: Change -> Text
+ Gerrit.Data.Event: [changeRestoredChange] :: ChangeRestored -> Change
+ Gerrit.Data.Event: [changeRestoredEventCreatedOn] :: ChangeRestored -> Int64
+ Gerrit.Data.Event: [changeRestoredPatchSet] :: ChangeRestored -> PatchSet
+ Gerrit.Data.Event: [changeRestoredReason] :: ChangeRestored -> Maybe Text
+ Gerrit.Data.Event: [changeRestoredRestorer] :: ChangeRestored -> User
+ Gerrit.Data.Event: [changeSubject] :: Change -> Text
+ Gerrit.Data.Event: [changeUrl] :: Change -> Text
+ Gerrit.Data.Event: [commentAddedAuthor] :: CommentAdded -> User
+ Gerrit.Data.Event: [commentAddedChange] :: CommentAdded -> Change
+ Gerrit.Data.Event: [commentAddedEventCreatedOn] :: CommentAdded -> Int64
+ Gerrit.Data.Event: [commentAddedPatchSet] :: CommentAdded -> PatchSet
+ Gerrit.Data.Event: [hashtagsChangedChange] :: HashtagsChanged -> Change
+ Gerrit.Data.Event: [hashtagsChangedEditor] :: HashtagsChanged -> User
+ Gerrit.Data.Event: [hashtagsChangedEventCreatedOn] :: HashtagsChanged -> Int64
+ Gerrit.Data.Event: [patchSetNumber] :: PatchSet -> Int
+ Gerrit.Data.Event: [patchSetRef] :: PatchSet -> Text
+ Gerrit.Data.Event: [patchSetUploader] :: PatchSet -> User
+ Gerrit.Data.Event: [patchsetAuthor] :: PatchSet -> User
+ Gerrit.Data.Event: [patchsetCreatedChange] :: PatchsetCreated -> Change
+ Gerrit.Data.Event: [patchsetCreatedEventCreatedOn] :: PatchsetCreated -> Int64
+ Gerrit.Data.Event: [patchsetCreatedPatchSet] :: PatchsetCreated -> PatchSet
+ Gerrit.Data.Event: [patchsetCreatedUploader] :: PatchsetCreated -> User
+ Gerrit.Data.Event: [privateStateChangedChange] :: PrivateStateChanged -> Change
+ Gerrit.Data.Event: [privateStateChangedChangedEventCreatedOn] :: PrivateStateChanged -> Int64
+ Gerrit.Data.Event: [privateStateChangedChanger] :: PrivateStateChanged -> User
+ Gerrit.Data.Event: [privateStateChangedPatchSet] :: PrivateStateChanged -> PatchSet
+ Gerrit.Data.Event: [projectCreatedEventCreatedOn] :: ProjectCreated -> Int64
+ Gerrit.Data.Event: [projectCreatedHeadName] :: ProjectCreated -> Text
+ Gerrit.Data.Event: [projectCreatedProjectName] :: ProjectCreated -> Text
+ Gerrit.Data.Event: [refNewRev] :: Ref -> Text
+ Gerrit.Data.Event: [refOldRev] :: Ref -> Text
+ Gerrit.Data.Event: [refProject] :: Ref -> Text
+ Gerrit.Data.Event: [refRefName] :: Ref -> Text
+ Gerrit.Data.Event: [refUpdatedEventCreatedOn] :: RefUpdated -> Int64
+ Gerrit.Data.Event: [refUpdatedRefUpdate] :: RefUpdated -> Ref
+ Gerrit.Data.Event: [refUpdatedSubmitter] :: RefUpdated -> User
+ Gerrit.Data.Event: [reviewerAddedAdder] :: ReviewerAdded -> User
+ Gerrit.Data.Event: [reviewerAddedChange] :: ReviewerAdded -> Change
+ Gerrit.Data.Event: [reviewerAddedEventCreatedOn] :: ReviewerAdded -> Int64
+ Gerrit.Data.Event: [reviewerAddedPatchSet] :: ReviewerAdded -> PatchSet
+ Gerrit.Data.Event: [reviewerDeletedChange] :: ReviewerDeleted -> Change
+ Gerrit.Data.Event: [reviewerDeletedEventCreatedOn] :: ReviewerDeleted -> Int64
+ Gerrit.Data.Event: [reviewerDeletedPatchSet] :: ReviewerDeleted -> PatchSet
+ Gerrit.Data.Event: [reviewerDeletedRemover] :: ReviewerDeleted -> User
+ Gerrit.Data.Event: [topicChangedChange] :: TopicChanged -> Change
+ Gerrit.Data.Event: [topicChangedChanger] :: TopicChanged -> User
+ Gerrit.Data.Event: [topicChangedEventCreatedOn] :: TopicChanged -> Int64
+ Gerrit.Data.Event: [topicChangedOldTopic] :: TopicChanged -> Text
+ Gerrit.Data.Event: [userEmail] :: User -> Maybe Text
+ Gerrit.Data.Event: [userName] :: User -> Maybe Text
+ Gerrit.Data.Event: [userUsername] :: User -> Maybe Text
+ Gerrit.Data.Event: [voteDeletedChange] :: VoteDeleted -> Change
+ Gerrit.Data.Event: [voteDeletedPatchSet] :: VoteDeleted -> PatchSet
+ Gerrit.Data.Event: [voteDeletedRemover] :: VoteDeleted -> User
+ Gerrit.Data.Event: [workInProgressStateChangedChange] :: WorkInProgressStateChanged -> Change
+ Gerrit.Data.Event: [workInProgressStateChangedChanger] :: WorkInProgressStateChanged -> User
+ Gerrit.Data.Event: [workInProgressStateChangedEventCreatedOn] :: WorkInProgressStateChanged -> Int64
+ Gerrit.Data.Event: [workInProgressStateChangedPatchSet] :: WorkInProgressStateChanged -> PatchSet
+ Gerrit.Data.Event: data AssigneeChanged
+ Gerrit.Data.Event: data Change
+ Gerrit.Data.Event: data ChangeAbandoned
+ Gerrit.Data.Event: data ChangeDeleted
+ Gerrit.Data.Event: data ChangeMerged
+ Gerrit.Data.Event: data ChangeRestored
+ Gerrit.Data.Event: data CommentAdded
+ Gerrit.Data.Event: data Event
+ Gerrit.Data.Event: data EventType
+ Gerrit.Data.Event: data HashtagsChanged
+ Gerrit.Data.Event: data PatchSet
+ Gerrit.Data.Event: data PatchsetCreated
+ Gerrit.Data.Event: data PrivateStateChanged
+ Gerrit.Data.Event: data ProjectCreated
+ Gerrit.Data.Event: data Ref
+ Gerrit.Data.Event: data RefUpdated
+ Gerrit.Data.Event: data ReviewerAdded
+ Gerrit.Data.Event: data ReviewerDeleted
+ Gerrit.Data.Event: data TopicChanged
+ Gerrit.Data.Event: data User
+ Gerrit.Data.Event: data VoteDeleted
+ Gerrit.Data.Event: data WorkInProgressStateChanged
+ Gerrit.Data.Event: eventName :: EventType -> Text
+ Gerrit.Data.Event: getChange :: Event -> Maybe Change
+ Gerrit.Data.Event: getCreatedOn :: Event -> Maybe Int64
+ Gerrit.Data.Event: getEventType :: Event -> EventType
+ Gerrit.Data.Event: getPatchSet :: Event -> Maybe PatchSet
+ Gerrit.Data.Event: getUser :: Event -> Maybe User
+ Gerrit.Data.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Event.AssigneeChanged
+ Gerrit.Data.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Event.Change
+ Gerrit.Data.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Event.ChangeAbandoned
+ Gerrit.Data.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Event.ChangeDeleted
+ Gerrit.Data.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Event.ChangeMerged
+ Gerrit.Data.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Event.ChangeRestored
+ Gerrit.Data.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Event.CommentAdded
+ Gerrit.Data.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Event.Event
+ Gerrit.Data.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Event.EventType
+ Gerrit.Data.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Event.HashtagsChanged
+ Gerrit.Data.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Event.PatchSet
+ Gerrit.Data.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Event.PatchsetCreated
+ Gerrit.Data.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Event.PrivateStateChanged
+ Gerrit.Data.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Event.ProjectCreated
+ Gerrit.Data.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Event.Ref
+ Gerrit.Data.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Event.RefUpdated
+ Gerrit.Data.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Event.ReviewerAdded
+ Gerrit.Data.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Event.ReviewerDeleted
+ Gerrit.Data.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Event.TopicChanged
+ Gerrit.Data.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Event.User
+ Gerrit.Data.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Event.VoteDeleted
+ Gerrit.Data.Event: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Event.WorkInProgressStateChanged
+ Gerrit.Data.Event: instance GHC.Classes.Eq Gerrit.Data.Event.AssigneeChanged
+ Gerrit.Data.Event: instance GHC.Classes.Eq Gerrit.Data.Event.Change
+ Gerrit.Data.Event: instance GHC.Classes.Eq Gerrit.Data.Event.ChangeAbandoned
+ Gerrit.Data.Event: instance GHC.Classes.Eq Gerrit.Data.Event.ChangeDeleted
+ Gerrit.Data.Event: instance GHC.Classes.Eq Gerrit.Data.Event.ChangeMerged
+ Gerrit.Data.Event: instance GHC.Classes.Eq Gerrit.Data.Event.ChangeRestored
+ Gerrit.Data.Event: instance GHC.Classes.Eq Gerrit.Data.Event.CommentAdded
+ Gerrit.Data.Event: instance GHC.Classes.Eq Gerrit.Data.Event.Event
+ Gerrit.Data.Event: instance GHC.Classes.Eq Gerrit.Data.Event.EventType
+ Gerrit.Data.Event: instance GHC.Classes.Eq Gerrit.Data.Event.HashtagsChanged
+ Gerrit.Data.Event: instance GHC.Classes.Eq Gerrit.Data.Event.PatchSet
+ Gerrit.Data.Event: instance GHC.Classes.Eq Gerrit.Data.Event.PatchsetCreated
+ Gerrit.Data.Event: instance GHC.Classes.Eq Gerrit.Data.Event.PrivateStateChanged
+ Gerrit.Data.Event: instance GHC.Classes.Eq Gerrit.Data.Event.ProjectCreated
+ Gerrit.Data.Event: instance GHC.Classes.Eq Gerrit.Data.Event.Ref
+ Gerrit.Data.Event: instance GHC.Classes.Eq Gerrit.Data.Event.RefUpdated
+ Gerrit.Data.Event: instance GHC.Classes.Eq Gerrit.Data.Event.ReviewerAdded
+ Gerrit.Data.Event: instance GHC.Classes.Eq Gerrit.Data.Event.ReviewerDeleted
+ Gerrit.Data.Event: instance GHC.Classes.Eq Gerrit.Data.Event.TopicChanged
+ Gerrit.Data.Event: instance GHC.Classes.Eq Gerrit.Data.Event.User
+ Gerrit.Data.Event: instance GHC.Classes.Eq Gerrit.Data.Event.VoteDeleted
+ Gerrit.Data.Event: instance GHC.Classes.Eq Gerrit.Data.Event.WorkInProgressStateChanged
+ Gerrit.Data.Event: instance GHC.Generics.Generic Gerrit.Data.Event.AssigneeChanged
+ Gerrit.Data.Event: instance GHC.Generics.Generic Gerrit.Data.Event.Change
+ Gerrit.Data.Event: instance GHC.Generics.Generic Gerrit.Data.Event.ChangeAbandoned
+ Gerrit.Data.Event: instance GHC.Generics.Generic Gerrit.Data.Event.ChangeDeleted
+ Gerrit.Data.Event: instance GHC.Generics.Generic Gerrit.Data.Event.ChangeMerged
+ Gerrit.Data.Event: instance GHC.Generics.Generic Gerrit.Data.Event.ChangeRestored
+ Gerrit.Data.Event: instance GHC.Generics.Generic Gerrit.Data.Event.CommentAdded
+ Gerrit.Data.Event: instance GHC.Generics.Generic Gerrit.Data.Event.HashtagsChanged
+ Gerrit.Data.Event: instance GHC.Generics.Generic Gerrit.Data.Event.PatchSet
+ Gerrit.Data.Event: instance GHC.Generics.Generic Gerrit.Data.Event.PatchsetCreated
+ Gerrit.Data.Event: instance GHC.Generics.Generic Gerrit.Data.Event.PrivateStateChanged
+ Gerrit.Data.Event: instance GHC.Generics.Generic Gerrit.Data.Event.ProjectCreated
+ Gerrit.Data.Event: instance GHC.Generics.Generic Gerrit.Data.Event.Ref
+ Gerrit.Data.Event: instance GHC.Generics.Generic Gerrit.Data.Event.RefUpdated
+ Gerrit.Data.Event: instance GHC.Generics.Generic Gerrit.Data.Event.ReviewerAdded
+ Gerrit.Data.Event: instance GHC.Generics.Generic Gerrit.Data.Event.ReviewerDeleted
+ Gerrit.Data.Event: instance GHC.Generics.Generic Gerrit.Data.Event.TopicChanged
+ Gerrit.Data.Event: instance GHC.Generics.Generic Gerrit.Data.Event.User
+ Gerrit.Data.Event: instance GHC.Generics.Generic Gerrit.Data.Event.VoteDeleted
+ Gerrit.Data.Event: instance GHC.Generics.Generic Gerrit.Data.Event.WorkInProgressStateChanged
+ Gerrit.Data.Event: instance GHC.Show.Show Gerrit.Data.Event.AssigneeChanged
+ Gerrit.Data.Event: instance GHC.Show.Show Gerrit.Data.Event.Change
+ Gerrit.Data.Event: instance GHC.Show.Show Gerrit.Data.Event.ChangeAbandoned
+ Gerrit.Data.Event: instance GHC.Show.Show Gerrit.Data.Event.ChangeDeleted
+ Gerrit.Data.Event: instance GHC.Show.Show Gerrit.Data.Event.ChangeMerged
+ Gerrit.Data.Event: instance GHC.Show.Show Gerrit.Data.Event.ChangeRestored
+ Gerrit.Data.Event: instance GHC.Show.Show Gerrit.Data.Event.CommentAdded
+ Gerrit.Data.Event: instance GHC.Show.Show Gerrit.Data.Event.Event
+ Gerrit.Data.Event: instance GHC.Show.Show Gerrit.Data.Event.EventType
+ Gerrit.Data.Event: instance GHC.Show.Show Gerrit.Data.Event.HashtagsChanged
+ Gerrit.Data.Event: instance GHC.Show.Show Gerrit.Data.Event.PatchSet
+ Gerrit.Data.Event: instance GHC.Show.Show Gerrit.Data.Event.PatchsetCreated
+ Gerrit.Data.Event: instance GHC.Show.Show Gerrit.Data.Event.PrivateStateChanged
+ Gerrit.Data.Event: instance GHC.Show.Show Gerrit.Data.Event.ProjectCreated
+ Gerrit.Data.Event: instance GHC.Show.Show Gerrit.Data.Event.Ref
+ Gerrit.Data.Event: instance GHC.Show.Show Gerrit.Data.Event.RefUpdated
+ Gerrit.Data.Event: instance GHC.Show.Show Gerrit.Data.Event.ReviewerAdded
+ Gerrit.Data.Event: instance GHC.Show.Show Gerrit.Data.Event.ReviewerDeleted
+ Gerrit.Data.Event: instance GHC.Show.Show Gerrit.Data.Event.TopicChanged
+ Gerrit.Data.Event: instance GHC.Show.Show Gerrit.Data.Event.User
+ Gerrit.Data.Event: instance GHC.Show.Show Gerrit.Data.Event.VoteDeleted
+ Gerrit.Data.Event: instance GHC.Show.Show Gerrit.Data.Event.WorkInProgressStateChanged
+ Gerrit.Data.Project: GerritProjectInfo :: Text -> GerritProjectInfo
+ Gerrit.Data.Project: Prefix :: Text -> GerritProjectQuery
+ Gerrit.Data.Project: Regexp :: Text -> GerritProjectQuery
+ Gerrit.Data.Project: [gerritprojectinfoId] :: GerritProjectInfo -> Text
+ Gerrit.Data.Project: data GerritProjectQuery
+ Gerrit.Data.Project: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Project.GerritProjectInfo
+ Gerrit.Data.Project: instance GHC.Classes.Eq Gerrit.Data.Project.GerritProjectInfo
+ Gerrit.Data.Project: instance GHC.Generics.Generic Gerrit.Data.Project.GerritProjectInfo
+ Gerrit.Data.Project: instance GHC.Show.Show Gerrit.Data.Project.GerritProjectInfo
+ Gerrit.Data.Project: newtype GerritProjectInfo
+ Gerrit.Data.Project: projectQS :: Int -> GerritProjectQuery -> Maybe Int -> Text
+ Gerrit.Data.Project: type GerritProjectsMessage = Map Text GerritProjectInfo
+ Gerrit.Data.Review: APPROVED :: GerritLabelVote
+ Gerrit.Data.Review: DISLIKED :: GerritLabelVote
+ Gerrit.Data.Review: GerritLabel :: Map GerritLabelVote GerritReviewAccount -> GerritLabel
+ Gerrit.Data.Review: GerritReviewAccount :: Int -> GerritReviewAccount
+ Gerrit.Data.Review: GerritVersion :: Text -> GerritVersion
+ Gerrit.Data.Review: RECOMMENDED :: GerritLabelVote
+ Gerrit.Data.Review: REJECTED :: GerritLabelVote
+ Gerrit.Data.Review: ReviewInput :: Maybe Text -> Maybe (Map Text Int) -> ReviewInput
+ Gerrit.Data.Review: ReviewResult :: Maybe (Map Text Int) -> Maybe Int -> ReviewResult
+ Gerrit.Data.Review: [riLabels] :: ReviewInput -> Maybe (Map Text Int)
+ Gerrit.Data.Review: [riMessage] :: ReviewInput -> Maybe Text
+ Gerrit.Data.Review: [rrLabels] :: ReviewResult -> Maybe (Map Text Int)
+ Gerrit.Data.Review: [rrReady] :: ReviewResult -> Maybe Int
+ Gerrit.Data.Review: [unused_account_id] :: GerritReviewAccount -> Int
+ Gerrit.Data.Review: data GerritLabelVote
+ Gerrit.Data.Review: data ReviewInput
+ Gerrit.Data.Review: data ReviewResult
+ Gerrit.Data.Review: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Review.GerritLabel
+ Gerrit.Data.Review: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Review.GerritLabelVote
+ Gerrit.Data.Review: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Review.GerritReviewAccount
+ Gerrit.Data.Review: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Review.GerritVersion
+ Gerrit.Data.Review: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Review.ReviewInput
+ Gerrit.Data.Review: instance Data.Aeson.Types.FromJSON.FromJSON Gerrit.Data.Review.ReviewResult
+ Gerrit.Data.Review: instance Data.Aeson.Types.FromJSON.FromJSONKey Gerrit.Data.Review.GerritLabelVote
+ Gerrit.Data.Review: instance Data.Aeson.Types.ToJSON.ToJSON Gerrit.Data.Review.ReviewInput
+ Gerrit.Data.Review: instance Data.Aeson.Types.ToJSON.ToJSON Gerrit.Data.Review.ReviewResult
+ Gerrit.Data.Review: instance GHC.Classes.Eq Gerrit.Data.Review.GerritLabelVote
+ Gerrit.Data.Review: instance GHC.Classes.Eq Gerrit.Data.Review.ReviewInput
+ Gerrit.Data.Review: instance GHC.Classes.Eq Gerrit.Data.Review.ReviewResult
+ Gerrit.Data.Review: instance GHC.Classes.Ord Gerrit.Data.Review.GerritLabelVote
+ Gerrit.Data.Review: instance GHC.Classes.Ord Gerrit.Data.Review.ReviewInput
+ Gerrit.Data.Review: instance GHC.Classes.Ord Gerrit.Data.Review.ReviewResult
+ Gerrit.Data.Review: instance GHC.Generics.Generic Gerrit.Data.Review.GerritLabel
+ Gerrit.Data.Review: instance GHC.Generics.Generic Gerrit.Data.Review.GerritLabelVote
+ Gerrit.Data.Review: instance GHC.Generics.Generic Gerrit.Data.Review.GerritReviewAccount
+ Gerrit.Data.Review: instance GHC.Generics.Generic Gerrit.Data.Review.GerritVersion
+ Gerrit.Data.Review: instance GHC.Generics.Generic Gerrit.Data.Review.ReviewInput
+ Gerrit.Data.Review: instance GHC.Generics.Generic Gerrit.Data.Review.ReviewResult
+ Gerrit.Data.Review: instance GHC.Show.Show Gerrit.Data.Review.GerritLabel
+ Gerrit.Data.Review: instance GHC.Show.Show Gerrit.Data.Review.GerritLabelVote
+ Gerrit.Data.Review: instance GHC.Show.Show Gerrit.Data.Review.GerritReviewAccount
+ Gerrit.Data.Review: instance GHC.Show.Show Gerrit.Data.Review.GerritVersion
+ Gerrit.Data.Review: instance GHC.Show.Show Gerrit.Data.Review.ReviewInput
+ Gerrit.Data.Review: instance GHC.Show.Show Gerrit.Data.Review.ReviewResult
+ Gerrit.Data.Review: newtype GerritLabel
+ Gerrit.Data.Review: newtype GerritReviewAccount
+ Gerrit.Data.Review: newtype GerritVersion
- Gerrit: GerritChange :: Text -> Text -> Text -> Text -> GerritChangeStatus -> Maybe Bool -> Map Text (Maybe GerritRevision) -> Maybe Text -> Int -> Map Text GerritDetailedLabel -> GerritChange
+ Gerrit: GerritChange :: Text -> Text -> Text -> Text -> GerritChangeStatus -> Maybe Bool -> Map Text (Maybe GerritRevision) -> Maybe Text -> Int -> Map Text GerritDetailedLabel -> [GerritChangeMessage] -> GerritAuthor -> GerritTime -> GerritTime -> Maybe GerritTime -> Maybe GerritAuthor -> Int -> Int -> Maybe Bool -> GerritChange
- Gerrit: queryChanges :: Int -> [GerritQuery] -> GerritClient -> IO [GerritChange]
+ Gerrit: queryChanges :: Int -> [GerritQuery] -> Maybe Int -> GerritClient -> IO [GerritChange]
- Gerrit: withClient :: Text -> Maybe Text -> (GerritClient -> IO ()) -> IO ()
+ Gerrit: withClient :: Text -> Maybe (Text, Text) -> (GerritClient -> IO a) -> IO a
Files
- CHANGELOG.md +8/−0
- gerrit.cabal +9/−4
- src/Gerrit.hs +52/−19
- src/Gerrit/Client.hs +18/−19
- src/Gerrit/Data.hs +0/−168
- src/Gerrit/Data/Account.hs +72/−0
- src/Gerrit/Data/Change.hs +235/−0
- src/Gerrit/Data/Event.hs +509/−0
- src/Gerrit/Data/Project.hs +42/−0
- src/Gerrit/Data/Review.hs +87/−0
- src/Gerrit/Event.hs +0/−448
- test/Spec.hs +16/−8
- test/data/GerritChange.json +861/−18
CHANGELOG.md view
@@ -1,5 +1,13 @@ # Changelog +## 0.1.1.0 (2021-10-13)++- Add EventCreatedOn Event attribute+- Split Data module into specialized modules+- Support more fields for GerritChange+- Add the getProjects function+- withClient takes optional credentials+ ## 0.1.0.0 (2021-05-30) - Basic Gerrit API data types.
gerrit.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: gerrit-version: 0.1.0.0+version: 0.1.1.0 synopsis: A gerrit client library description: Gerrit is a client library to interface with https://www.gerritcodereview.com/@@ -29,6 +29,7 @@ build-depends: base >= 4.11.0.0 && < 5 , aeson >= 1.0.0.0 && < 1.6 , bytestring < 0.11+ , time >= 1.9.3 && < 2.0 ghc-options: -Wall -Wcompat -Widentities@@ -49,13 +50,17 @@ import: common-options build-depends: containers >= 0.5.8.0 && < 0.7 , http-client >= 0.5.0 && < 0.8- , http-client-tls >= 0.2.0 && < 0.4+ , http-client-openssl >= 0.3.0 && < 0.4 , text >= 0.11.1.0 && < 1.3+ , aeson-casing >= 0.2.0.0 && < 0.3.0.0 hs-source-dirs: src exposed-modules: Gerrit- , Gerrit.Data- , Gerrit.Event+ , Gerrit.Data.Review+ , Gerrit.Data.Change+ , Gerrit.Data.Account+ , Gerrit.Data.Event+ , Gerrit.Data.Project other-modules: Gerrit.Client test-suite gerrit-test
src/Gerrit.hs view
@@ -5,12 +5,16 @@ ( -- * Client GerritClient, withClient,+ getClient, -- * Api getVersion, getChange, queryChanges, postReview,+ getAccountId,+ getAccount,+ getProjects, -- * Main data types GerritVersion (..),@@ -18,22 +22,33 @@ GerritChange (..), GerritChangeStatus (..), ReviewResult (..),+ GerritAccount (..),+ GerritAccountQuery (..),+ GerritProjectQuery (..), -- * Convenient functions changeUrl,- hasLabel,+ serverUrl, ) where import Control.Exception (try)+import Data.List.NonEmpty (NonEmpty) import qualified Data.Map as M import Data.Maybe (fromMaybe) import Data.Text (Text) import qualified Data.Text as T import Gerrit.Client-import Gerrit.Data+import Gerrit.Data.Account+import Gerrit.Data.Change+import Gerrit.Data.Project+import Gerrit.Data.Review import Network.HTTP.Client (HttpException) +-- | Return the base url of the 'GerritClient'+serverUrl :: GerritClient -> T.Text+serverUrl = baseUrl+ -- | Return the url of a 'GerritChange' changeUrl :: GerritClient -> GerritChange -> T.Text changeUrl client change = baseUrl client <> T.pack (show (number change))@@ -42,20 +57,38 @@ getVersion :: GerritClient -> IO GerritVersion getVersion = gerritGet "config/server/version" +-- | Get projects+getProjects ::+ -- | Count of projects to get back+ Int ->+ -- | The project query type+ GerritProjectQuery ->+ -- | Whether or not to ask result from offset+ Maybe Int ->+ -- | The client+ GerritClient ->+ IO GerritProjectsMessage+getProjects count query startM = gerritGet ("projects/?" <> projectQS count query startM)+ -- | Search for changes-queryChanges :: Int -> [GerritQuery] -> GerritClient -> IO [GerritChange]-queryChanges count queries = gerritGet ("changes/?" <> queryString)- where- queryString = T.intercalate "&" [changeString, countString, option]- changeString = "q=" <> T.intercalate "+" (map queryText queries)- countString = "n=" <> T.pack (show count)- option = "o=CURRENT_REVISION&o=DETAILED_LABELS"+queryChanges ::+ -- | Count of changes to get back+ Int ->+ -- | The change query+ [GerritQuery] ->+ -- | Whether or not to ask result from offset+ Maybe Int ->+ -- | The client+ GerritClient ->+ IO [GerritChange]+queryChanges count queries startM = gerritGet ("changes/?" <> changeQS count queries startM) +-- | Get a change by change Id getChange :: Int -> GerritClient -> IO (Maybe GerritChange) getChange changeNumber client = do res <- try- ( gerritGet ("changes/" <> T.pack (show changeNumber) <> "?o=CURRENT_REVISION&o=DETAILED_LABELS") client+ ( gerritGet ("changes/" <> T.pack (show changeNumber) <> "?" <> defaultQueryChangeOptions) client ) :: IO (Either HttpException GerritChange) pure $ case res of@@ -79,18 +112,18 @@ postReview change message label value' = gerritPost urlPath review where urlPath = "changes/" <> changeId <> "/revisions/" <> revHash <> "/review"- changeId = Gerrit.Data.id change- revHash = fromMaybe "" (Gerrit.Data.current_revision change)+ changeId = Gerrit.Data.Change.id change+ revHash = fromMaybe "" (Gerrit.Data.Change.current_revision change) review = ReviewInput { riMessage = Just message, riLabels = Just (M.fromList [(label, value')]) } --- | Check if a gerrit change as a label-hasLabel :: T.Text -> Int -> GerritChange -> Bool-hasLabel label labelValue change = case M.lookup label (labels change) of- Just gerritLabel ->- (> 0) $- length $ filter (\vote -> fromMaybe 0 (value vote) == labelValue) (Gerrit.Data.all gerritLabel)- _ -> False+-- | Get user account id+getAccountId :: Int -> NonEmpty GerritAccountQuery -> GerritClient -> IO [GerritAccountId]+getAccountId count queries = gerritGet ("accounts/?" <> accountQs count queries)++-- | Get user account details+getAccount :: Int -> NonEmpty GerritAccountQuery -> GerritClient -> IO [GerritAccount]+getAccount count queries = gerritGet ("accounts/?" <> accountQs count queries <> "&o=DETAILS")
src/Gerrit/Client.hs view
@@ -7,18 +7,17 @@ withClient, gerritGet, gerritPost,+ getClient, ) where import Data.Aeson (FromJSON, ToJSON, eitherDecode, encode) import qualified Data.ByteString.Lazy as BSL-import Data.Maybe (fromMaybe) import Data.Text (Text, unpack) import qualified Data.Text as T import qualified Data.Text.Encoding as T import Network.HTTP.Client-import Network.HTTP.Client.TLS (tlsManagerSettings)-import System.Environment (lookupEnv)+import Network.HTTP.Client.OpenSSL (newOpenSSLManager, withOpenSSL) -- | The GerritClient record, use 'withClient' to create data GerritClient = GerritClient@@ -27,27 +26,26 @@ auth :: Maybe (Text, Text) } +-- | Need to be call through withOpenSSL+getClient :: Text -> Maybe (Text, Text) -> IO GerritClient+getClient url auth = do+ let baseUrl = T.dropWhileEnd (== '/') url <> "/"+ manager <- newOpenSSLManager+ pure $ GerritClient {..}+ -- | Create the 'GerritClient' withClient :: -- | The gerrit api url Text ->- -- | A username (password is read from GERRIT_PASSWORD environment)- Maybe Text ->+ -- | Credentials (login, password) [Optional]+ Maybe (Text, Text) -> -- | The callback- (GerritClient -> IO ()) ->+ (GerritClient -> IO a) -> -- | withClient performs the IO- IO ()-withClient url username callBack =- do- manager <- newManager tlsManagerSettings- auth <- case username of- Just user -> do- pass <- lookupEnv "GERRIT_PASSWORD"- pure $ Just (user, T.pack $ fromMaybe "" pass)- _ -> pure Nothing- callBack (GerritClient {..})- where- baseUrl = T.dropWhileEnd (== '/') url <> "/"+ IO a+withClient url creds callBack = withOpenSSL $ do+ client <- getClient url creds+ callBack client gerritDecode :: (FromJSON a, Applicative f) => Response BSL.ByteString -> f a gerritDecode response = case eitherDecode $ BSL.drop 5 $ responseBody response of@@ -74,6 +72,7 @@ gerritGet :: (FromJSON a) => Text -> GerritClient -> IO a gerritGet path GerritClient {..} = do- request <- parseUrlThrow (unpack $ baseUrl <> path)+ let url = baseUrl <> path+ request <- parseUrlThrow (unpack url) response <- httpLbs request manager gerritDecode response
− src/Gerrit/Data.hs
@@ -1,168 +0,0 @@-{-# LANGUAGE DeriveAnyClass #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE DerivingStrategies #-}-{-# LANGUAGE OverloadedStrings #-}---- | This module contains the gerrit data type-module Gerrit.Data- ( -- * Main data types- GerritVersion (..),- GerritQuery (..),- GerritChangeStatus (..),- GerritChange (..),- GerritRevision (..),- GerritLabel (..),- GerritAccount (..),- GerritLabelVote (..),- GerritDetailedLabelVote (..),- GerritDetailedLabel (..),- ReviewResult (..),- ReviewInput (..),-- -- * Convenient functions- queryText,- )-where--import Data.Aeson-import Data.Char (isUpper, toLower)-import qualified Data.Map as M-import Data.Text (Text)-import qualified Data.Text as T-import GHC.Generics (Generic)--newtype GerritVersion = GerritVersion Text- deriving (Show, Generic)- deriving anyclass (FromJSON)---- https://gerrit-review.googlesource.com/Documentation/json.html-data GerritRevisionKind = REWORK | TRIVIAL_REBASE | MERGE_FIRST_PARENT_UPDATE | NO_CODE_CHANGE | NO_CHANGE- deriving (Eq, Show, Generic, FromJSON)--data GerritChangeStatus = NEW | MERGED | ABANDONED | DRAFT- deriving (Eq, Show, Generic, FromJSON)--data GerritLabelVote = REJECTED | APPROVED | DISLIKED | RECOMMENDED- deriving (Eq, Show, Ord, Generic)---- We use a custom parseJSON to decode Label Vote as lowercase-instance FromJSON GerritLabelVote where- parseJSON = genericParseJSON defaultOptions {fieldLabelModifier = map toLower}--instance FromJSONKey GerritLabelVote where- fromJSONKey = genericFromJSONKey defaultJSONKeyOptions {keyModifier = map toLower}---- | Modify record attribute to match json schema--- Remove the prefix and use snakecase-customParseJSON :: String -> Options-customParseJSON prefix = defaultOptions {fieldLabelModifier = recordToJson}- where- recordToJson = updateCase . drop (length prefix)- updateCase [] = []- updateCase (x : xs) = toLower x : updateCase' xs- updateCase' [] = []- updateCase' (x : xs)- | isUpper x = '_' : toLower x : updateCase' xs- | otherwise = x : updateCase' xs---- https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html-data ReviewResult = ReviewResult- { rrLabels :: Maybe (M.Map Text Int),- rrReady :: Maybe Int- }- deriving (Eq, Show, Ord, Generic)--instance FromJSON ReviewResult where- parseJSON = genericParseJSON $ customParseJSON "rr"--instance ToJSON ReviewResult where- toJSON = genericToJSON $ customParseJSON "rr"--data ReviewInput = ReviewInput- { riMessage :: Maybe Text,- riLabels :: Maybe (M.Map Text Int)- }- deriving (Eq, Show, Ord, Generic)--instance FromJSON ReviewInput where- parseJSON = genericParseJSON $ customParseJSON "ri"--instance ToJSON ReviewInput where- toJSON = genericToJSON $ (customParseJSON "ri") {omitNothingFields = True}---- https://gerrit-review.googlesource.com/Documentation/user-search.html-data GerritQuery- = Status GerritChangeStatus- | Owner Text- | CommitMessage Text- | Project Text- | ChangeId Text---- | Convert a GerritQuery object to the search terms-queryText :: GerritQuery -> Text-queryText (Status stat) = "status:" <> T.toLower (T.pack $ show stat)-queryText (Owner owner) = "owner:" <> owner-queryText (CommitMessage message) = "message:" <> message-queryText (Project project') = "project:" <> project'-queryText (ChangeId changeId) = "change:" <> changeId--data GerritRevision = GerritRevision- { ref :: Text,- kind :: GerritRevisionKind- }- deriving (Show, Generic, FromJSON)--newtype GerritAccount = GerritAccount- { unused_account_id :: Int- }- deriving (Show, Generic)---- We use a cusom parseJSON to decode `_account_id` as `account_id`-instance FromJSON GerritAccount where- parseJSON = genericParseJSON aesonOptions--newtype GerritLabel- = GerritLabel (M.Map GerritLabelVote GerritAccount)- deriving (Show, Generic)- deriving anyclass (FromJSON)--data GerritDetailedLabelVote = GerritDetailedLabelVote- { value :: Maybe Int,- account_id :: Int- }- deriving (Show, Generic)---- We use a cusom parseJSON to decode record field properly-instance FromJSON GerritDetailedLabelVote where- parseJSON = genericParseJSON aesonOptions--data GerritDetailedLabel = GerritDetailedLabel- { all :: [GerritDetailedLabelVote],- default_value :: Int- }- deriving (Show, Generic, FromJSON)--data GerritChange = GerritChange- { id :: Text,- project :: Text,- branch :: Text,- subject :: Text,- status :: GerritChangeStatus,- mergeable :: Maybe Bool,- revisions :: M.Map Text (Maybe GerritRevision),- current_revision :: Maybe Text,- number :: Int,- labels :: M.Map Text GerritDetailedLabel- }- deriving (Show, Generic)---- We use a cusom parseJSON to decode `_number` as `number`-instance FromJSON GerritChange where- parseJSON = genericParseJSON aesonOptions--aesonOptions :: Options-aesonOptions = defaultOptions {fieldLabelModifier = recordToJson}- where- recordToJson "number" = "_number"- recordToJson "account_id" = "_account_id"- recordToJson n = n
+ src/Gerrit/Data/Account.hs view
@@ -0,0 +1,72 @@+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE OverloadedStrings #-}++module Gerrit.Data.Account+ ( GerritAccountId (..),+ GerritAccount (..),+ GerritAccountQuery (..),+ userQueryText,+ accountQs,+ )+where++import Control.Monad (mzero)+import Data.Aeson+import Data.List.NonEmpty (NonEmpty, toList)+import Data.Text (Text)+import qualified Data.Text as T++-- https://gerrit-review.googlesource.com/Documentation/user-search-accounts.html#_search_operators+data GerritAccountQuery+ = CanSee Text+ | Email Text+ | Name Text+ | Username Text+ | IsActive+ | IsInactive++userQueryText :: GerritAccountQuery -> Text+userQueryText guq = case guq of+ CanSee change -> "cansee:" <> change+ Email email -> "email:" <> email+ Name name -> "name:" <> escapeChar name+ Username username -> "username:" <> username+ IsActive -> "is:active"+ IsInactive -> "is:inactive"+ where+ escapeChar = T.replace "'" " "++accountQs :: Int -> NonEmpty GerritAccountQuery -> Text+accountQs count queries = T.intercalate "&" [searchString, countString]+ where+ searchString = "q=" <> T.intercalate "+" (map userQueryText $ toList queries)+ countString = "n=" <> T.pack (show count)++data GerritAccountId = GerritAccountId+ { gerritAccountId' :: Int,+ gerritAccountHasMore' :: Maybe Bool+ }+ deriving (Eq, Show)++instance FromJSON GerritAccountId where+ parseJSON (Object v) = GerritAccountId <$> v .: "_account_id" <*> v .:? "_more_accounts"+ parseJSON _ = mzero++data GerritAccount = GerritAccount+ { gerritAccountId :: Int,+ gerritAccountName :: Text,+ gerritAccountUsername :: Maybe Text,+ gerritAccountEmail :: Maybe Text,+ gerritAccountHasMore :: Maybe Bool+ }+ deriving (Eq, Show)++instance FromJSON GerritAccount where+ parseJSON (Object v) =+ GerritAccount+ <$> v .: "_account_id"+ <*> v .: "name"+ <*> v .:? "username"+ <*> v .:? "email"+ <*> v .:? "_more_accounts"+ parseJSON _ = mzero
+ src/Gerrit/Data/Change.hs view
@@ -0,0 +1,235 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE OverloadedStrings #-}++module Gerrit.Data.Change+ ( GerritQuery (..),+ GerritChangeStatus (..),+ GerritRevisionKind (..),+ GerritFile (..),+ GerritCommit (..),+ GerritRevision (..),+ GerritDetailedLabelVote (..),+ GerritDetailedLabel (..),+ GerritAuthor (..),+ GerritCommitAuthor (..),+ GerritChangeMessage (..),+ GerritChange (..),+ GerritTime (..),+ changeQS,+ queryText,+ defaultQueryChangeOptions,+ hasLabel,+ )+where++import Data.Aeson+import Data.Aeson.Casing (aesonPrefix, snakeCase)+import qualified Data.Map as M+import Data.Maybe (fromMaybe)+import Data.Text (Text)+import qualified Data.Text as T+import Data.Time.Clock+import Data.Time.Format (defaultTimeLocale, formatTime, parseTimeM)+import GHC.Generics (Generic)++aesonOptions :: Options+aesonOptions = defaultOptions {fieldLabelModifier = recordToJson}+ where+ recordToJson "number" = "_number"+ recordToJson "account_id" = "_account_id"+ recordToJson "aAccountId" = "_account_id"+ recordToJson "aName" = "name"+ recordToJson "aEmail" = "email"+ recordToJson "aUsername" = "username"+ recordToJson "more_changes" = "_more_changes"+ recordToJson n = n++-- https://gerrit-review.googlesource.com/Documentation/user-search.html+data GerritQuery+ = Status GerritChangeStatus+ | Owner Text+ | CommitMessage Text+ | Project Text+ | ChangeId Text+ | After UTCTime++-- | Convert a GerritQuery object to the search terms+queryText :: GerritQuery -> Text+queryText (Status stat) = "status:" <> T.toLower (T.pack $ show stat)+queryText (Owner owner') = "owner:" <> owner'+queryText (CommitMessage message) = "message:" <> message+queryText (Project project') = "project:" <> project'+queryText (ChangeId changeId) = "change:" <> changeId+queryText (After date') = "after:" <> T.pack formatedDate+ where+ formatedDate = formatTime defaultTimeLocale "%F" date'++defaultQueryChangeOptions :: Text+defaultQueryChangeOptions =+ "o="+ <> T.intercalate+ "&o="+ [ "MESSAGES",+ "DETAILED_ACCOUNTS",+ "DETAILED_LABELS",+ "CURRENT_REVISION",+ "CURRENT_FILES",+ "CURRENT_COMMIT"+ ]++-- | Build the Query String for the changes endpoint+-- >>> changeQS 10 [Project "software-factory/gerrit-haskell"] Nothing+-- "q=project:software-factory/gerrit-haskell&n=10&o=MESSAGES&o=DETAILED_ACCOUNTS&o=DETAILED_LABELS&o=CURRENT_REVISION&o=CURRENT_FILES&o=CURRENT_COMMIT"+-- >>> changeQS 10 [Project "software-factory/gerrit-haskell"] $ Just 100+-- "q=project:software-factory/gerrit-haskell&n=10&o=MESSAGES&o=DETAILED_ACCOUNTS&o=DETAILED_LABELS&o=CURRENT_REVISION&o=CURRENT_FILES&o=CURRENT_COMMIT&start=100"+changeQS :: Int -> [GerritQuery] -> Maybe Int -> Text+changeQS count queries startM =+ let base =+ T.intercalate+ "&"+ [ changeString,+ countString,+ defaultQueryChangeOptions+ ]+ in base <> startString+ where+ changeString = "q=" <> T.intercalate "+" (map queryText queries)+ countString = "n=" <> T.pack (show count)+ startString = maybe mempty (\s -> "&start=" <> T.pack (show s)) startM++-- | Check if a gerrit change as a label+hasLabel :: T.Text -> Int -> GerritChange -> Bool+hasLabel label labelValue change = case M.lookup label (labels change) of+ Just gerritLabel ->+ (> 0) $+ length $+ filter+ (\vote -> fromMaybe 0 (value vote) == labelValue)+ (fromMaybe [] (Gerrit.Data.Change.all gerritLabel))+ _ -> False++data GerritChangeStatus = NEW | MERGED | ABANDONED | DRAFT+ deriving (Eq, Show, Generic, FromJSON)++-- https://gerrit-review.googlesource.com/Documentation/json.html+data GerritRevisionKind = REWORK | TRIVIAL_REBASE | MERGE_FIRST_PARENT_UPDATE | NO_CODE_CHANGE | NO_CHANGE+ deriving (Eq, Show, Generic, FromJSON)++data GerritFile = GerritFile+ { gfStatus :: Maybe Text,+ gfLinesInserted :: Maybe Int,+ gfLinesDeleted :: Maybe Int,+ gfSizeDelta :: Maybe Int,+ gfSize :: Maybe Int+ }+ deriving (Show, Generic)++instance FromJSON GerritFile where+ parseJSON = genericParseJSON $ aesonPrefix snakeCase++data GerritCommit = GerritCommit+ { cAuthor :: GerritCommitAuthor,+ cCommitter :: GerritCommitAuthor,+ cSubject :: Text,+ cMessage :: Text+ }+ deriving (Show, Generic)++instance FromJSON GerritCommit where+ parseJSON = genericParseJSON $ aesonPrefix snakeCase++data GerritRevision = GerritRevision+ { grRef :: Text,+ grKind :: GerritRevisionKind,+ grFiles :: M.Map Text GerritFile,+ grCommit :: GerritCommit,+ grUploader :: GerritAuthor+ }+ deriving (Show, Generic)++instance FromJSON GerritRevision where+ parseJSON = genericParseJSON $ aesonPrefix snakeCase++data GerritDetailedLabelVote = GerritDetailedLabelVote+ { value :: Maybe Int,+ account_id :: Int+ }+ deriving (Show, Generic)++instance FromJSON GerritDetailedLabelVote where+ parseJSON = genericParseJSON aesonOptions++data GerritDetailedLabel = GerritDetailedLabel+ { all :: Maybe [GerritDetailedLabelVote],+ default_value :: Int+ }+ deriving (Show, Generic, FromJSON)++data GerritAuthor = GerritAuthor+ { aAccountId :: Int,+ aName :: Text,+ aEmail :: Maybe Text,+ aUsername :: Maybe Text+ }+ deriving (Show, Generic)++instance FromJSON GerritAuthor where+ parseJSON = genericParseJSON aesonOptions++data GerritCommitAuthor = GerritCommitAuthor+ { caName :: Text,+ caEmail :: Maybe Text,+ caDate :: GerritTime+ }+ deriving (Show, Generic)++instance FromJSON GerritCommitAuthor where+ parseJSON = genericParseJSON $ aesonPrefix snakeCase++newtype GerritTime = GerritTime {unGerritTime :: UTCTime} deriving (Show)++instance FromJSON GerritTime where+ parseJSON = withText "UTCTimePlus" (parse . T.unpack)+ where+ format = "%F %T.000000000"+ tryParse f s = parseTimeM False defaultTimeLocale f s+ parse s = GerritTime <$> tryParse format s++data GerritChangeMessage = GerritChangeMessage+ { mId :: Text,+ mAuthor :: Maybe GerritAuthor,+ mDate :: GerritTime,+ mMessage :: Text+ }+ deriving (Show, Generic)++instance FromJSON GerritChangeMessage where+ parseJSON = genericParseJSON $ aesonPrefix snakeCase++data GerritChange = GerritChange+ { id :: Text,+ project :: Text,+ branch :: Text,+ subject :: Text,+ status :: GerritChangeStatus,+ mergeable :: Maybe Bool,+ revisions :: M.Map Text (Maybe GerritRevision),+ current_revision :: Maybe Text,+ number :: Int,+ labels :: M.Map Text GerritDetailedLabel,+ messages :: [GerritChangeMessage],+ owner :: GerritAuthor,+ created :: GerritTime,+ updated :: GerritTime,+ submitted :: Maybe GerritTime,+ submitter :: Maybe GerritAuthor,+ insertions :: Int,+ deletions :: Int,+ more_changes :: Maybe Bool+ }+ deriving (Show, Generic)++instance FromJSON GerritChange where+ parseJSON = genericParseJSON aesonOptions
+ src/Gerrit/Data/Event.hs view
@@ -0,0 +1,509 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}++-- | Gerrit stream event data type+module Gerrit.Data.Event+ ( -- * Main event data types+ EventType (..),+ Event (..),++ -- * Common data types+ User (..),+ PatchSet (..),+ Change (..),+ Ref (..),++ -- * Individual event data types+ AssigneeChanged (..),+ ChangeAbandoned (..),+ ChangeDeleted (..),+ ChangeMerged (..),+ ChangeRestored (..),+ CommentAdded (..),+ HashtagsChanged (..),+ ProjectCreated (..),+ PatchsetCreated (..),+ RefUpdated (..),+ ReviewerAdded (..),+ ReviewerDeleted (..),+ TopicChanged (..),+ WorkInProgressStateChanged (..),+ PrivateStateChanged (..),+ VoteDeleted (..),++ -- * Convenient functions+ getChange,+ getPatchSet,+ getUser,+ getCreatedOn,+ getEventType,+ eventName,+ )+where++import Control.Monad (mzero)+import Data.Aeson+ ( FromJSON (..),+ Options (fieldLabelModifier),+ Value (Object, String),+ defaultOptions,+ genericParseJSON,+ (.:),+ )+import Data.Char (toLower)+import Data.Text (Text)+import qualified Data.Text as Text+import GHC.Generics (Generic)+import GHC.Int (Int64)++aesonOption :: Text -> Options+aesonOption prefix = defaultOptions {fieldLabelModifier = recordToJson}+ where+ recordToJson = updateCase . drop (Text.length prefix)+ updateCase [] = []+ updateCase (x : xs) = toLower x : xs++-------------------------------------------------------------------------------+-- Shared types+-------------------------------------------------------------------------------+data User = User+ { userName :: Maybe Text,+ userEmail :: Maybe Text,+ userUsername :: Maybe Text+ }+ deriving (Show, Eq, Generic)++instance FromJSON User where+ parseJSON = genericParseJSON $ aesonOption "user"++data PatchSet = PatchSet+ { patchSetNumber :: Int,+ patchSetRef :: Text,+ patchSetUploader :: User,+ patchsetAuthor :: User+ }+ deriving (Show, Eq, Generic)++instance FromJSON PatchSet where+ parseJSON = genericParseJSON $ aesonOption "patchSet"++data Change = Change+ { changeProject :: Text,+ changeBranch :: Text,+ changeSubject :: Text,+ changeNumber :: Int,+ changeUrl :: Text,+ changeOwner :: User+ }+ deriving (Show, Eq, Generic)++instance FromJSON Change where+ parseJSON = genericParseJSON $ aesonOption "change"++data Ref = Ref+ { refOldRev :: Text,+ refNewRev :: Text,+ refRefName :: Text,+ refProject :: Text+ }+ deriving (Show, Eq, Generic)++instance FromJSON Ref where+ parseJSON = genericParseJSON $ aesonOption "ref"++-------------------------------------------------------------------------------+-- Individual Event data types+-------------------------------------------------------------------------------+data AssigneeChanged = AssigneeChanged+ { assigneeChangedChange :: Change,+ assigneeChangedChanger :: User,+ assigneeChangedEventCreatedOn :: Int64+ }+ deriving (Show, Eq, Generic)++data ChangeAbandoned = ChangeAbandoned+ { changeAbandonedProject :: Text,+ changeAbandonedAbandoner :: User,+ changeAbandonedChange :: Change,+ changeAbandonedPatchSet :: PatchSet,+ changeAbandonedReason :: Maybe Text,+ changeAbandonedEventCreatedOn :: Int64+ }+ deriving (Show, Eq, Generic)++data ChangeDeleted = ChangeDeleted+ { changeDeletedChange :: Change,+ changeDeletedDeleter :: User+ }+ deriving (Show, Eq, Generic)++data ChangeMerged = ChangeMerged+ { changeMergedProject :: Text,+ changeMergedSubmitter :: User,+ changeMergedChange :: Change,+ changeMergedPatchSet :: PatchSet,+ changeMergedEventCreatedOn :: Int64+ }+ deriving (Show, Eq, Generic)++data ChangeRestored = ChangeRestored+ { changeRestoredChange :: Change,+ changeRestoredPatchSet :: PatchSet,+ changeRestoredRestorer :: User,+ changeRestoredReason :: Maybe Text,+ changeRestoredEventCreatedOn :: Int64+ }+ deriving (Show, Eq, Generic)++data CommentAdded = CommentAdded+ { commentAddedChange :: Change,+ commentAddedPatchSet :: PatchSet,+ commentAddedAuthor :: User,+ commentAddedEventCreatedOn :: Int64+ }+ deriving (Show, Eq, Generic)++data HashtagsChanged = HashtagsChanged+ { hashtagsChangedChange :: Change,+ hashtagsChangedEditor :: User,+ hashtagsChangedEventCreatedOn :: Int64+ }+ deriving (Show, Eq, Generic)++data ProjectCreated = ProjectCreated+ { projectCreatedProjectName :: Text,+ projectCreatedHeadName :: Text,+ projectCreatedEventCreatedOn :: Int64+ }+ deriving (Show, Eq, Generic)++data PatchsetCreated = PatchsetCreated+ { patchsetCreatedUploader :: User,+ patchsetCreatedChange :: Change,+ patchsetCreatedPatchSet :: PatchSet,+ patchsetCreatedEventCreatedOn :: Int64+ }+ deriving (Show, Eq, Generic)++data RefUpdated = RefUpdated+ { refUpdatedSubmitter :: User,+ refUpdatedRefUpdate :: Ref,+ refUpdatedEventCreatedOn :: Int64+ }+ deriving (Show, Eq, Generic)++data ReviewerAdded = ReviewerAdded+ { reviewerAddedChange :: Change,+ reviewerAddedPatchSet :: PatchSet,+ reviewerAddedAdder :: User,+ reviewerAddedEventCreatedOn :: Int64+ }+ deriving (Show, Eq, Generic)++data ReviewerDeleted = ReviewerDeleted+ { reviewerDeletedChange :: Change,+ reviewerDeletedPatchSet :: PatchSet,+ reviewerDeletedRemover :: User,+ reviewerDeletedEventCreatedOn :: Int64+ }+ deriving (Show, Eq, Generic)++data TopicChanged = TopicChanged+ { topicChangedChange :: Change,+ topicChangedChanger :: User,+ topicChangedOldTopic :: Text,+ topicChangedEventCreatedOn :: Int64+ }+ deriving (Show, Eq, Generic)++data WorkInProgressStateChanged = WorkInProgressStateChanged+ { workInProgressStateChangedChange :: Change,+ workInProgressStateChangedPatchSet :: PatchSet,+ workInProgressStateChangedChanger :: User,+ workInProgressStateChangedEventCreatedOn :: Int64+ }+ deriving (Show, Eq, Generic)++data PrivateStateChanged = PrivateStateChanged+ { privateStateChangedChange :: Change,+ privateStateChangedPatchSet :: PatchSet,+ privateStateChangedChanger :: User,+ privateStateChangedChangedEventCreatedOn :: Int64+ }+ deriving (Show, Eq, Generic)++data VoteDeleted = VoteDeleted+ { voteDeletedChange :: Change,+ voteDeletedPatchSet :: PatchSet,+ voteDeletedRemover :: User+ }+ deriving (Show, Eq, Generic)++-------------------------------------------------------------------------------+-- Events FromJSON instances+-------------------------------------------------------------------------------+instance FromJSON AssigneeChanged where+ parseJSON = genericParseJSON $ aesonOption "assigneeChanged"++instance FromJSON ChangeAbandoned where+ parseJSON = genericParseJSON $ aesonOption "changeAbandoned"++instance FromJSON ChangeDeleted where+ parseJSON = genericParseJSON $ aesonOption "changeDeleted"++instance FromJSON ChangeMerged where+ parseJSON = genericParseJSON $ aesonOption "changeMerged"++instance FromJSON ChangeRestored where+ parseJSON = genericParseJSON $ aesonOption "changeRestored"++instance FromJSON CommentAdded where+ parseJSON = genericParseJSON $ aesonOption "commentAdded"++instance FromJSON HashtagsChanged where+ parseJSON = genericParseJSON $ aesonOption "hashtagsChanged"++instance FromJSON ProjectCreated where+ parseJSON = genericParseJSON $ aesonOption "projectCreated"++instance FromJSON PatchsetCreated where+ parseJSON = genericParseJSON $ aesonOption "patchsetCreated"++instance FromJSON RefUpdated where+ parseJSON = genericParseJSON $ aesonOption "refUpdated"++instance FromJSON ReviewerAdded where+ parseJSON = genericParseJSON $ aesonOption "reviewerAdded"++instance FromJSON ReviewerDeleted where+ parseJSON = genericParseJSON $ aesonOption "reviewerDeleted"++instance FromJSON TopicChanged where+ parseJSON = genericParseJSON $ aesonOption "topicChanged"++instance FromJSON WorkInProgressStateChanged where+ parseJSON = genericParseJSON $ aesonOption "workInProgressStateChanged"++instance FromJSON PrivateStateChanged where+ parseJSON = genericParseJSON $ aesonOption "privateStateChanged"++instance FromJSON VoteDeleted where+ parseJSON = genericParseJSON $ aesonOption "voteDeleted"++-- | The event "type" data type+data EventType+ = AssigneeChangedEvent+ | ChangeAbandonedEvent+ | ChangeDeletedEvent+ | ChangeMergedEvent+ | ChangeRestoredEvent+ | CommentAddedEvent+ | DroppedOutputEvent+ | HashtagsChangedEvent+ | ProjectCreatedEvent+ | PatchsetCreatedEvent+ | RefUpdatedEvent+ | ReviewerAddedEvent+ | ReviewerDeletedEvent+ | TopicChangedEvent+ | WorkInProgressStateChangedEvent+ | PrivateStateChangedEvent+ | VoteDeletedEvent+ deriving (Show, Eq)++instance FromJSON EventType where+ parseJSON (String v) = case v of+ "assignee-changed" -> pure AssigneeChangedEvent+ "change-abandoned" -> pure ChangeAbandonedEvent+ "change-deleted" -> pure ChangeDeletedEvent+ "change-merged" -> pure ChangeMergedEvent+ "change-restored" -> pure ChangeRestoredEvent+ "comment-added" -> pure CommentAddedEvent+ "dropped-output" -> pure DroppedOutputEvent+ "hashtags-changed" -> pure HashtagsChangedEvent+ "project-created" -> pure ProjectCreatedEvent+ "patchset-created" -> pure PatchsetCreatedEvent+ "ref-updated" -> pure RefUpdatedEvent+ "reviewer-added" -> pure ReviewerAddedEvent+ "reviewer-deleted" -> pure ReviewerDeletedEvent+ "topic-changed" -> pure TopicChangedEvent+ "wip-state-changed" -> pure WorkInProgressStateChangedEvent+ "private-state-changed" -> pure PrivateStateChangedEvent+ "vote-deleted" -> pure VoteDeletedEvent+ _ -> mzero+ parseJSON _ = mzero++-- | The main event union data type+data Event+ = EventAssigneeChanged AssigneeChanged+ | EventChangeAbandoned ChangeAbandoned+ | EventChangeDeleted ChangeDeleted+ | EventChangeMerged ChangeMerged+ | EventChangeRestored ChangeRestored+ | EventCommentAdded CommentAdded+ | EventDroppedOutput+ | EventHashtagsChanged HashtagsChanged+ | EventProjectCreated ProjectCreated+ | EventPatchsetCreated PatchsetCreated+ | EventRefUpdated RefUpdated+ | EventReviewerAdded ReviewerAdded+ | EventReviewerDeleted ReviewerDeleted+ | EventTopicChanged TopicChanged+ | EventWorkInProgressStateChanged WorkInProgressStateChanged+ | EventPrivateStateChanged PrivateStateChanged+ | EventVoteDeleted VoteDeleted+ deriving (Show, Eq)++instance FromJSON Event where+ parseJSON o@(Object v) = do+ eType <- v .: "type"+ case eType of+ AssigneeChangedEvent -> EventAssigneeChanged <$> parseJSON o+ ChangeAbandonedEvent -> EventChangeAbandoned <$> parseJSON o+ ChangeDeletedEvent -> EventChangeDeleted <$> parseJSON o+ ChangeMergedEvent -> EventChangeMerged <$> parseJSON o+ ChangeRestoredEvent -> EventChangeRestored <$> parseJSON o+ CommentAddedEvent -> EventCommentAdded <$> parseJSON o+ DroppedOutputEvent -> pure EventDroppedOutput+ HashtagsChangedEvent -> EventHashtagsChanged <$> parseJSON o+ ProjectCreatedEvent -> EventProjectCreated <$> parseJSON o+ PatchsetCreatedEvent -> EventPatchsetCreated <$> parseJSON o+ RefUpdatedEvent -> EventRefUpdated <$> parseJSON o+ ReviewerAddedEvent -> EventReviewerAdded <$> parseJSON o+ ReviewerDeletedEvent -> EventReviewerDeleted <$> parseJSON o+ TopicChangedEvent -> EventTopicChanged <$> parseJSON o+ WorkInProgressStateChangedEvent -> EventWorkInProgressStateChanged <$> parseJSON o+ PrivateStateChangedEvent -> EventPrivateStateChanged <$> parseJSON o+ VoteDeletedEvent -> EventVoteDeleted <$> parseJSON o+ parseJSON _ = mzero++-------------------------------------------------------------------------------+-- Utilities function+-------------------------------------------------------------------------------++-- | Get the associated change+getChange :: Event -> Maybe Change+getChange event = case event of+ EventAssigneeChanged AssigneeChanged {..} -> Just assigneeChangedChange+ EventChangeAbandoned ChangeAbandoned {..} -> Just changeAbandonedChange+ EventChangeDeleted ChangeDeleted {..} -> Just changeDeletedChange+ EventChangeMerged ChangeMerged {..} -> Just changeMergedChange+ EventChangeRestored ChangeRestored {..} -> Just changeRestoredChange+ EventCommentAdded CommentAdded {..} -> Just commentAddedChange+ EventDroppedOutput -> Nothing+ EventHashtagsChanged HashtagsChanged {..} -> Just hashtagsChangedChange+ EventProjectCreated _ -> Nothing+ EventPatchsetCreated PatchsetCreated {..} -> Just patchsetCreatedChange+ EventRefUpdated _ -> Nothing+ EventReviewerAdded ReviewerAdded {..} -> Just reviewerAddedChange+ EventReviewerDeleted ReviewerDeleted {..} -> Just reviewerDeletedChange+ EventTopicChanged TopicChanged {..} -> Just topicChangedChange+ EventWorkInProgressStateChanged WorkInProgressStateChanged {..} -> Just workInProgressStateChangedChange+ EventPrivateStateChanged PrivateStateChanged {..} -> Just privateStateChangedChange+ EventVoteDeleted VoteDeleted {..} -> Just voteDeletedChange++-- | Get the associated patchset+getPatchSet :: Event -> Maybe PatchSet+getPatchSet event = case event of+ EventAssigneeChanged _ -> Nothing+ EventChangeAbandoned ChangeAbandoned {..} -> Just changeAbandonedPatchSet+ EventChangeDeleted _ -> Nothing+ EventChangeMerged ChangeMerged {..} -> Just changeMergedPatchSet+ EventChangeRestored ChangeRestored {..} -> Just changeRestoredPatchSet+ EventCommentAdded CommentAdded {..} -> Just commentAddedPatchSet+ EventDroppedOutput -> Nothing+ EventHashtagsChanged _ -> Nothing+ EventProjectCreated _ -> Nothing+ EventPatchsetCreated PatchsetCreated {..} -> Just patchsetCreatedPatchSet+ EventRefUpdated _ -> Nothing+ EventReviewerAdded ReviewerAdded {..} -> Just reviewerAddedPatchSet+ EventReviewerDeleted ReviewerDeleted {..} -> Just reviewerDeletedPatchSet+ EventTopicChanged _ -> Nothing+ EventWorkInProgressStateChanged WorkInProgressStateChanged {..} -> Just workInProgressStateChangedPatchSet+ EventPrivateStateChanged PrivateStateChanged {..} -> Just privateStateChangedPatchSet+ EventVoteDeleted VoteDeleted {..} -> Just voteDeletedPatchSet++-- | Get the associated author+getUser :: Event -> Maybe User+getUser event = case event of+ EventAssigneeChanged AssigneeChanged {..} -> Just assigneeChangedChanger+ EventChangeAbandoned ChangeAbandoned {..} -> Just changeAbandonedAbandoner+ EventChangeDeleted ChangeDeleted {..} -> Just changeDeletedDeleter+ EventChangeMerged ChangeMerged {..} -> Just changeMergedSubmitter+ EventChangeRestored ChangeRestored {..} -> Just changeRestoredRestorer+ EventCommentAdded CommentAdded {..} -> Just commentAddedAuthor+ EventDroppedOutput -> Nothing+ EventHashtagsChanged HashtagsChanged {..} -> Just hashtagsChangedEditor+ EventProjectCreated _ -> Nothing+ EventPatchsetCreated PatchsetCreated {..} -> Just patchsetCreatedUploader+ EventRefUpdated _ -> Nothing+ EventReviewerAdded ReviewerAdded {..} -> Just reviewerAddedAdder+ EventReviewerDeleted ReviewerDeleted {..} -> Just reviewerDeletedRemover+ EventTopicChanged TopicChanged {..} -> Just topicChangedChanger+ EventWorkInProgressStateChanged WorkInProgressStateChanged {..} -> Just workInProgressStateChangedChanger+ EventPrivateStateChanged PrivateStateChanged {..} -> Just privateStateChangedChanger+ EventVoteDeleted VoteDeleted {..} -> Just voteDeletedRemover++-- | Get the creation timestamp+getCreatedOn :: Event -> Maybe Int64+getCreatedOn event = case event of+ EventAssigneeChanged AssigneeChanged {..} -> Just assigneeChangedEventCreatedOn+ EventChangeAbandoned ChangeAbandoned {..} -> Just changeAbandonedEventCreatedOn+ EventChangeDeleted _ -> Nothing+ EventChangeMerged ChangeMerged {..} -> Just changeMergedEventCreatedOn+ EventChangeRestored ChangeRestored {..} -> Just changeRestoredEventCreatedOn+ EventCommentAdded CommentAdded {..} -> Just commentAddedEventCreatedOn+ EventDroppedOutput -> Nothing+ EventHashtagsChanged HashtagsChanged {..} -> Just hashtagsChangedEventCreatedOn+ EventProjectCreated ProjectCreated {..} -> Just projectCreatedEventCreatedOn+ EventPatchsetCreated PatchsetCreated {..} -> Just patchsetCreatedEventCreatedOn+ EventRefUpdated RefUpdated {..} -> Just refUpdatedEventCreatedOn+ EventReviewerAdded ReviewerAdded {..} -> Just reviewerAddedEventCreatedOn+ EventReviewerDeleted ReviewerDeleted {..} -> Just reviewerDeletedEventCreatedOn+ EventTopicChanged TopicChanged {..} -> Just topicChangedEventCreatedOn+ EventWorkInProgressStateChanged WorkInProgressStateChanged {..} -> Just workInProgressStateChangedEventCreatedOn+ EventPrivateStateChanged PrivateStateChanged {..} -> Just privateStateChangedChangedEventCreatedOn+ EventVoteDeleted _ -> Nothing++-- | Get the 'EventType' back from an 'Event'+getEventType :: Event -> EventType+getEventType event = case event of+ EventAssigneeChanged _ -> AssigneeChangedEvent+ EventChangeAbandoned _ -> ChangeAbandonedEvent+ EventChangeDeleted _ -> ChangeDeletedEvent+ EventChangeMerged _ -> ChangeMergedEvent+ EventChangeRestored _ -> ChangeRestoredEvent+ EventCommentAdded _ -> CommentAddedEvent+ EventDroppedOutput -> DroppedOutputEvent+ EventHashtagsChanged _ -> HashtagsChangedEvent+ EventProjectCreated _ -> ProjectCreatedEvent+ EventPatchsetCreated _ -> PatchsetCreatedEvent+ EventRefUpdated _ -> RefUpdatedEvent+ EventReviewerAdded _ -> ReviewerAddedEvent+ EventReviewerDeleted _ -> ReviewerDeletedEvent+ EventTopicChanged _ -> TopicChangedEvent+ EventWorkInProgressStateChanged _ -> WorkInProgressStateChangedEvent+ EventPrivateStateChanged _ -> PrivateStateChangedEvent+ EventVoteDeleted _ -> VoteDeletedEvent++-- | Get the text representation suitable for event subscription.+eventName :: EventType -> Text+eventName eventType = case eventType of+ AssigneeChangedEvent -> "assignee-changed"+ ChangeAbandonedEvent -> "change-abandoned"+ ChangeDeletedEvent -> "change-deleted"+ ChangeMergedEvent -> "change-merged"+ ChangeRestoredEvent -> "change-restored"+ CommentAddedEvent -> "comment-added"+ DroppedOutputEvent -> "dropped-output"+ HashtagsChangedEvent -> "hashtags-changed"+ ProjectCreatedEvent -> "project-created"+ PatchsetCreatedEvent -> "patchset-created"+ RefUpdatedEvent -> "ref-updated"+ ReviewerAddedEvent -> "reviewer-added"+ ReviewerDeletedEvent -> "reviewer-deleted"+ TopicChangedEvent -> "topic-changed"+ WorkInProgressStateChangedEvent -> "wip-state-changed"+ PrivateStateChangedEvent -> "private-state-changed"+ VoteDeletedEvent -> "vote-deleted"
+ src/Gerrit/Data/Project.hs view
@@ -0,0 +1,42 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE OverloadedStrings #-}++module Gerrit.Data.Project+ ( GerritProjectInfo (..),+ GerritProjectQuery (..),+ projectQS,+ GerritProjectsMessage,+ )+where++import Data.Aeson+import Data.Aeson.Casing (aesonPrefix, snakeCase)+import Data.Map+import Data.Text (Text, intercalate, pack)+import GHC.Generics (Generic)++data GerritProjectQuery = Regexp Text | Prefix Text++queryText :: GerritProjectQuery -> Text+queryText (Regexp re) = "r=" <> re+queryText (Prefix prefix) = "p=" <> prefix++-- >>> projectQS 10 (Regexp "test/.*|rpms/.*") Nothing+-- "r:test/.*|rpms/.*&n=10"+projectQS :: Int -> GerritProjectQuery -> Maybe Int -> Text+projectQS count query startM =+ intercalate "&" [qtString, countString] <> startString+ where+ qtString = queryText query+ countString = "n=" <> pack (show count)+ startString = maybe mempty (\s -> "&S=" <> pack (show s)) startM++newtype GerritProjectInfo = GerritProjectInfo+ {gerritprojectinfoId :: Text}+ deriving (Eq, Show, Generic)++type GerritProjectsMessage = Map Text GerritProjectInfo++instance FromJSON GerritProjectInfo where+ parseJSON = genericParseJSON $ aesonPrefix snakeCase
+ src/Gerrit/Data/Review.hs view
@@ -0,0 +1,87 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE OverloadedStrings #-}++-- | This module contains the gerrit data type+module Gerrit.Data.Review+ ( GerritVersion (..),+ GerritLabel (..),+ GerritReviewAccount (..),+ GerritLabelVote (..),+ ReviewResult (..),+ ReviewInput (..),+ )+where++import Data.Aeson+import Data.Char (isUpper, toLower)+import qualified Data.Map as M+import Data.Text (Text)+import GHC.Generics (Generic)++newtype GerritVersion = GerritVersion Text+ deriving (Show, Generic)+ deriving anyclass (FromJSON)++data GerritLabelVote = REJECTED | APPROVED | DISLIKED | RECOMMENDED+ deriving (Eq, Show, Ord, Generic)++-- We use a custom parseJSON to decode Label Vote as lowercase+instance FromJSON GerritLabelVote where+ parseJSON = genericParseJSON defaultOptions {fieldLabelModifier = map toLower}++instance FromJSONKey GerritLabelVote where+ fromJSONKey = genericFromJSONKey defaultJSONKeyOptions {keyModifier = map toLower}++-- | Modify record attribute to match json schema+-- Remove the prefix and use snakecase+customParseJSON :: String -> Options+customParseJSON prefix = defaultOptions {fieldLabelModifier = recordToJson}+ where+ recordToJson = updateCase . drop (length prefix)+ updateCase [] = []+ updateCase (x : xs) = toLower x : updateCase' xs+ updateCase' [] = []+ updateCase' (x : xs)+ | isUpper x = '_' : toLower x : updateCase' xs+ | otherwise = x : updateCase' xs++-- https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html+data ReviewResult = ReviewResult+ { rrLabels :: Maybe (M.Map Text Int),+ rrReady :: Maybe Int+ }+ deriving (Eq, Show, Ord, Generic)++instance FromJSON ReviewResult where+ parseJSON = genericParseJSON $ customParseJSON "rr"++instance ToJSON ReviewResult where+ toJSON = genericToJSON $ customParseJSON "rr"++data ReviewInput = ReviewInput+ { riMessage :: Maybe Text,+ riLabels :: Maybe (M.Map Text Int)+ }+ deriving (Eq, Show, Ord, Generic)++instance FromJSON ReviewInput where+ parseJSON = genericParseJSON $ customParseJSON "ri"++instance ToJSON ReviewInput where+ toJSON = genericToJSON $ (customParseJSON "ri") {omitNothingFields = True}++newtype GerritReviewAccount = GerritReviewAccount+ { unused_account_id :: Int+ }+ deriving (Show, Generic)++-- We use a cusom parseJSON to decode `_account_id` as `account_id`+instance FromJSON GerritReviewAccount where+ parseJSON = genericParseJSON defaultOptions++newtype GerritLabel+ = GerritLabel (M.Map GerritLabelVote GerritReviewAccount)+ deriving (Show, Generic)+ deriving anyclass (FromJSON)
− src/Gerrit/Event.hs
@@ -1,448 +0,0 @@-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RecordWildCards #-}---- | Gerrit stream event data type-module Gerrit.Event- ( -- * Main event data types- EventType (..),- Event (..),-- -- * Common data types- User (..),- PatchSet (..),- Change (..),- Ref (..),-- -- * Individual event data types- AssigneeChanged (..),- ChangeAbandoned (..),- ChangeDeleted (..),- ChangeMerged (..),- ChangeRestored (..),- CommentAdded (..),- HashtagsChanged (..),- ProjectCreated (..),- PatchsetCreated (..),- RefUpdated (..),- ReviewerAdded (..),- ReviewerDeleted (..),- TopicChanged (..),- WorkInProgressStateChanged (..),- PrivateStateChanged (..),- VoteDeleted (..),-- -- * Convenient functions- getChange,- getUser,- getEventType,- eventName,- )-where--import Control.Monad (mzero)-import Data.Aeson- ( FromJSON (..),- Options (fieldLabelModifier),- Value (Object, String),- defaultOptions,- genericParseJSON,- (.:),- )-import Data.Char (toLower)-import Data.Text (Text)-import qualified Data.Text as Text-import GHC.Generics (Generic)--aesonOption :: Text -> Options-aesonOption prefix = defaultOptions {fieldLabelModifier = recordToJson}- where- recordToJson = updateCase . drop (Text.length prefix)- updateCase [] = []- updateCase (x : xs) = toLower x : xs------------------------------------------------------------------------------------ Shared types---------------------------------------------------------------------------------data User = User- { userName :: Maybe Text,- userEmail :: Maybe Text,- userUsername :: Maybe Text- }- deriving (Show, Eq, Generic)--instance FromJSON User where- parseJSON = genericParseJSON $ aesonOption "user"--data PatchSet = PatchSet- { patchSetNumber :: Int,- patchSetRef :: Text,- patchSetUploader :: User,- patchsetAuthor :: User- }- deriving (Show, Eq, Generic)--instance FromJSON PatchSet where- parseJSON = genericParseJSON $ aesonOption "patchSet"--data Change = Change- { changeProject :: Text,- changeBranch :: Text,- changeSubject :: Text,- changeUrl :: Text,- changeOwner :: User- }- deriving (Show, Eq, Generic)--instance FromJSON Change where- parseJSON = genericParseJSON $ aesonOption "change"--data Ref = Ref- { refOldRev :: Text,- refNewRev :: Text,- refRefName :: Text,- refProject :: Text- }- deriving (Show, Eq, Generic)--instance FromJSON Ref where- parseJSON = genericParseJSON $ aesonOption "ref"------------------------------------------------------------------------------------ Individual Event data types---------------------------------------------------------------------------------data AssigneeChanged = AssigneeChanged- { assigneeChangedChange :: Change,- assigneeChangedChanger :: User- }- deriving (Show, Eq, Generic)--data ChangeAbandoned = ChangeAbandoned- { changeAbandonedProject :: Text,- changeAbandonedAbandoner :: User,- changeAbandonedChange :: Change,- changeAbandonedPatchSet :: PatchSet- }- deriving (Show, Eq, Generic)--data ChangeDeleted = ChangeDeleted- { changeDeletedChange :: Change,- changeDeletedDeleter :: User- }- deriving (Show, Eq, Generic)--data ChangeMerged = ChangeMerged- { changeMergedProject :: Text,- changeMergedSubmitter :: User,- changeMergedChange :: Change,- changeMergedPatchSet :: PatchSet- }- deriving (Show, Eq, Generic)--data ChangeRestored = ChangeRestored- { changeRestoredChange :: Change,- changeRestoredPatchSet :: PatchSet,- changeRestoredRestorer :: User,- changeRestoredReason :: Text- }- deriving (Show, Eq, Generic)--data CommentAdded = CommentAdded- { commentAddedChange :: Change,- commentAddedPatchSet :: PatchSet,- commentAddedAuthor :: User- }- deriving (Show, Eq, Generic)--data HashtagsChanged = HashtagsChanged- { hashtagsChangedChange :: Change,- hashtagsChangedEditor :: User- }- deriving (Show, Eq, Generic)--data ProjectCreated = ProjectCreated- { projectCreatedProjectName :: Text,- projectCreatedHeadName :: Text- }- deriving (Show, Eq, Generic)--data PatchsetCreated = PatchsetCreated- { patchsetCreatedUploader :: User,- patchsetCreatedChange :: Change,- patchsetCreatedPatchSet :: PatchSet- }- deriving (Show, Eq, Generic)--data RefUpdated = RefUpdated- { refUpdatedSubmitter :: User,- refUpdatedRefUpdate :: Ref- }- deriving (Show, Eq, Generic)--data ReviewerAdded = ReviewerAdded- { reviewerAddedChange :: Change,- reviewerAddedPatchSet :: PatchSet,- reviewerAddedAdder :: User- }- deriving (Show, Eq, Generic)--data ReviewerDeleted = ReviewerDeleted- { reviewerDeletedChange :: Change,- reviewerDeletedPatchSet :: PatchSet,- reviewerDeletedRemover :: User- }- deriving (Show, Eq, Generic)--data TopicChanged = TopicChanged- { topicChangedChange :: Change,- topicChangedChanger :: User,- topicChangedOldTopic :: Text- }- deriving (Show, Eq, Generic)--data WorkInProgressStateChanged = WorkInProgressStateChanged- { workInProgressStateChangedChange :: Change,- workInProgressStateChangedPatchSet :: PatchSet,- workInProgressStateChangedChanger :: User- }- deriving (Show, Eq, Generic)--data PrivateStateChanged = PrivateStateChanged- { privateStateChangedChange :: Change,- privateStateChangedPatchSet :: PatchSet,- privateStateChangedChanger :: User- }- deriving (Show, Eq, Generic)--data VoteDeleted = VoteDeleted- { voteDeletedChange :: Change,- voteDeletedPatchSet :: PatchSet,- voteDeletedRemover :: User- }- deriving (Show, Eq, Generic)------------------------------------------------------------------------------------ Events FromJSON instances---------------------------------------------------------------------------------instance FromJSON AssigneeChanged where- parseJSON = genericParseJSON $ aesonOption "assigneeChanged"--instance FromJSON ChangeAbandoned where- parseJSON = genericParseJSON $ aesonOption "changeAbandoned"--instance FromJSON ChangeDeleted where- parseJSON = genericParseJSON $ aesonOption "changeDeleted"--instance FromJSON ChangeMerged where- parseJSON = genericParseJSON $ aesonOption "changeMerged"--instance FromJSON ChangeRestored where- parseJSON = genericParseJSON $ aesonOption "changeRestored"--instance FromJSON CommentAdded where- parseJSON = genericParseJSON $ aesonOption "commentAdded"--instance FromJSON HashtagsChanged where- parseJSON = genericParseJSON $ aesonOption "hashtagsChanged"--instance FromJSON ProjectCreated where- parseJSON = genericParseJSON $ aesonOption "projectCreated"--instance FromJSON PatchsetCreated where- parseJSON = genericParseJSON $ aesonOption "patchsetCreated"--instance FromJSON RefUpdated where- parseJSON = genericParseJSON $ aesonOption "refUpdated"--instance FromJSON ReviewerAdded where- parseJSON = genericParseJSON $ aesonOption "reviewerAdded"--instance FromJSON ReviewerDeleted where- parseJSON = genericParseJSON $ aesonOption "reviewerDeleted"--instance FromJSON TopicChanged where- parseJSON = genericParseJSON $ aesonOption "topicChanged"--instance FromJSON WorkInProgressStateChanged where- parseJSON = genericParseJSON $ aesonOption "workInProgressStateChanged"--instance FromJSON PrivateStateChanged where- parseJSON = genericParseJSON $ aesonOption "privateStateChanged"--instance FromJSON VoteDeleted where- parseJSON = genericParseJSON $ aesonOption "voteDeleted"---- | The event "type" data type-data EventType- = AssigneeChangedEvent- | ChangeAbandonedEvent- | ChangeDeletedEvent- | ChangeMergedEvent- | ChangeRestoredEvent- | CommentAddedEvent- | DroppedOutputEvent- | HashtagsChangedEvent- | ProjectCreatedEvent- | PatchsetCreatedEvent- | RefUpdatedEvent- | ReviewerAddedEvent- | ReviewerDeletedEvent- | TopicChangedEvent- | WorkInProgressStateChangedEvent- | PrivateStateChangedEvent- | VoteDeletedEvent- deriving (Show, Eq)--instance FromJSON EventType where- parseJSON (String v) = case v of- "assignee-changed" -> pure AssigneeChangedEvent- "change-abandoned" -> pure ChangeAbandonedEvent- "change-deleted" -> pure ChangeDeletedEvent- "change-merged" -> pure ChangeMergedEvent- "change-restored" -> pure ChangeRestoredEvent- "comment-added" -> pure CommentAddedEvent- "dropped-output" -> pure DroppedOutputEvent- "hashtags-changed" -> pure HashtagsChangedEvent- "project-created" -> pure ProjectCreatedEvent- "patchset-created" -> pure PatchsetCreatedEvent- "ref-updated" -> pure RefUpdatedEvent- "reviewer-added" -> pure ReviewerAddedEvent- "reviewer-deleted" -> pure ReviewerDeletedEvent- "topic-changed" -> pure TopicChangedEvent- "wip-state-changed" -> pure WorkInProgressStateChangedEvent- "private-state-changed" -> pure PrivateStateChangedEvent- "vote-deleted" -> pure VoteDeletedEvent- _ -> mzero- parseJSON _ = mzero---- | The main event union data type-data Event- = EventAssigneeChanged AssigneeChanged- | EventChangeAbandoned ChangeAbandoned- | EventChangeDeleted ChangeDeleted- | EventChangeMerged ChangeMerged- | EventChangeRestored ChangeRestored- | EventCommentAdded CommentAdded- | EventDroppedOutput- | EventHashtagsChanged HashtagsChanged- | EventProjectCreated ProjectCreated- | EventPatchsetCreated PatchsetCreated- | EventRefUpdated RefUpdated- | EventReviewerAdded ReviewerAdded- | EventReviewerDeleted ReviewerDeleted- | EventTopicChanged TopicChanged- | EventWorkInProgressStateChanged WorkInProgressStateChanged- | EventPrivateStateChanged PrivateStateChanged- | EventVoteDeleted VoteDeleted- deriving (Show, Eq)--instance FromJSON Event where- parseJSON o@(Object v) = do- eType <- v .: "type"- case eType of- AssigneeChangedEvent -> EventAssigneeChanged <$> parseJSON o- ChangeAbandonedEvent -> EventChangeAbandoned <$> parseJSON o- ChangeDeletedEvent -> EventChangeDeleted <$> parseJSON o- ChangeMergedEvent -> EventChangeMerged <$> parseJSON o- ChangeRestoredEvent -> EventChangeRestored <$> parseJSON o- CommentAddedEvent -> EventCommentAdded <$> parseJSON o- DroppedOutputEvent -> pure EventDroppedOutput- HashtagsChangedEvent -> EventHashtagsChanged <$> parseJSON o- ProjectCreatedEvent -> EventProjectCreated <$> parseJSON o- PatchsetCreatedEvent -> EventPatchsetCreated <$> parseJSON o- RefUpdatedEvent -> EventRefUpdated <$> parseJSON o- ReviewerAddedEvent -> EventReviewerAdded <$> parseJSON o- ReviewerDeletedEvent -> EventReviewerDeleted <$> parseJSON o- TopicChangedEvent -> EventTopicChanged <$> parseJSON o- WorkInProgressStateChangedEvent -> EventWorkInProgressStateChanged <$> parseJSON o- PrivateStateChangedEvent -> EventPrivateStateChanged <$> parseJSON o- VoteDeletedEvent -> EventVoteDeleted <$> parseJSON o- parseJSON _ = mzero------------------------------------------------------------------------------------ Utilities function------------------------------------------------------------------------------------ | Get the associated change-getChange :: Event -> Maybe Change-getChange event = case event of- EventAssigneeChanged AssigneeChanged {..} -> Just assigneeChangedChange- EventChangeAbandoned ChangeAbandoned {..} -> Just changeAbandonedChange- EventChangeDeleted ChangeDeleted {..} -> Just changeDeletedChange- EventChangeMerged ChangeMerged {..} -> Just changeMergedChange- EventChangeRestored ChangeRestored {..} -> Just changeRestoredChange- EventCommentAdded CommentAdded {..} -> Just commentAddedChange- EventDroppedOutput -> Nothing- EventHashtagsChanged HashtagsChanged {..} -> Just hashtagsChangedChange- EventProjectCreated _ -> Nothing- EventPatchsetCreated PatchsetCreated {..} -> Just patchsetCreatedChange- EventRefUpdated _ -> Nothing- EventReviewerAdded ReviewerAdded {..} -> Just reviewerAddedChange- EventReviewerDeleted ReviewerDeleted {..} -> Just reviewerDeletedChange- EventTopicChanged TopicChanged {..} -> Just topicChangedChange- EventWorkInProgressStateChanged WorkInProgressStateChanged {..} -> Just workInProgressStateChangedChange- EventPrivateStateChanged PrivateStateChanged {..} -> Just privateStateChangedChange- EventVoteDeleted VoteDeleted {..} -> Just voteDeletedChange---- | Get the associated author-getUser :: Event -> Maybe User-getUser event = case event of- EventAssigneeChanged AssigneeChanged {..} -> Just assigneeChangedChanger- EventChangeAbandoned ChangeAbandoned {..} -> Just changeAbandonedAbandoner- EventChangeDeleted ChangeDeleted {..} -> Just changeDeletedDeleter- EventChangeMerged ChangeMerged {..} -> Just changeMergedSubmitter- EventChangeRestored ChangeRestored {..} -> Just changeRestoredRestorer- EventCommentAdded CommentAdded {..} -> Just commentAddedAuthor- EventDroppedOutput -> Nothing- EventHashtagsChanged HashtagsChanged {..} -> Just hashtagsChangedEditor- EventProjectCreated _ -> Nothing- EventPatchsetCreated PatchsetCreated {..} -> Just patchsetCreatedUploader- EventRefUpdated _ -> Nothing- EventReviewerAdded ReviewerAdded {..} -> Just reviewerAddedAdder- EventReviewerDeleted ReviewerDeleted {..} -> Just reviewerDeletedRemover- EventTopicChanged TopicChanged {..} -> Just topicChangedChanger- EventWorkInProgressStateChanged WorkInProgressStateChanged {..} -> Just workInProgressStateChangedChanger- EventPrivateStateChanged PrivateStateChanged {..} -> Just privateStateChangedChanger- EventVoteDeleted VoteDeleted {..} -> Just voteDeletedRemover---- | Get the 'EventType' back from an 'Event'-getEventType :: Event -> EventType-getEventType event = case event of- EventAssigneeChanged _ -> AssigneeChangedEvent- EventChangeAbandoned _ -> ChangeAbandonedEvent- EventChangeDeleted _ -> ChangeDeletedEvent- EventChangeMerged _ -> ChangeMergedEvent- EventChangeRestored _ -> ChangeRestoredEvent- EventCommentAdded _ -> CommentAddedEvent- EventDroppedOutput -> DroppedOutputEvent- EventHashtagsChanged _ -> HashtagsChangedEvent- EventProjectCreated _ -> ProjectCreatedEvent- EventPatchsetCreated _ -> PatchsetCreatedEvent- EventRefUpdated _ -> RefUpdatedEvent- EventReviewerAdded _ -> ReviewerAddedEvent- EventReviewerDeleted _ -> ReviewerDeletedEvent- EventTopicChanged _ -> TopicChangedEvent- EventWorkInProgressStateChanged _ -> WorkInProgressStateChangedEvent- EventPrivateStateChanged _ -> PrivateStateChangedEvent- EventVoteDeleted _ -> VoteDeletedEvent---- | Get the text representation suitable for event subscription.-eventName :: EventType -> Text-eventName eventType = case eventType of- AssigneeChangedEvent -> "assignee-changed"- ChangeAbandonedEvent -> "change-abandoned"- ChangeDeletedEvent -> "change-deleted"- ChangeMergedEvent -> "change-merged"- ChangeRestoredEvent -> "change-restored"- CommentAddedEvent -> "comment-added"- DroppedOutputEvent -> "dropped-output"- HashtagsChangedEvent -> "hashtags-changed"- ProjectCreatedEvent -> "project-created"- PatchsetCreatedEvent -> "patchset-created"- RefUpdatedEvent -> "ref-updated"- ReviewerAddedEvent -> "reviewer-added"- ReviewerDeletedEvent -> "reviewer-deleted"- TopicChangedEvent -> "topic-changed"- WorkInProgressStateChangedEvent -> "wip-state-changed"- PrivateStateChangedEvent -> "private-state-changed"- VoteDeletedEvent -> "vote-deleted"
test/Spec.hs view
@@ -8,8 +8,9 @@ import qualified Data.ByteString.Lazy as BSL import Data.Maybe (fromJust) import Gerrit-import Gerrit.Data as Gerrit-import qualified Gerrit.Event as Event+import Gerrit.Data.Change+import qualified Gerrit.Data.Event as Event+import Gerrit.Data.Review import System.Directory (listDirectory) import Test.Tasty import Test.Tasty.HUnit@@ -17,10 +18,10 @@ main :: IO () main = do- files <- listDirectory "./test/data"- dataFiles <- traverse (BSL.readFile . ("./test/data/" <>)) files+ files' <- listDirectory "./test/data"+ dataFiles <- traverse (BSL.readFile . ("./test/data/" <>)) files' withClient "http://example.com/r" Nothing $ \client ->- defaultMain (tests (zip files dataFiles) client)+ defaultMain (tests (zip files' dataFiles) client) tests :: [(FilePath, ByteString)] -> GerritClient -> TestTree tests dataFiles client = testGroup "Tests" $ [unitTests] <> encodingTests dataFiles client@@ -30,8 +31,15 @@ testGroup "unitTests" [ testCase "queryString status" $- assertEqual "Query string is valid" "status:new" (queryText (Status NEW))+ assertEqual "Query string is valid" "status:new" (queryText (Status NEW)),+ testCase "changeQS w/o start" $+ assertEqual "Change query is valid" expected1 (changeQS 10 [Project "gerrit-haskell"] Nothing),+ testCase "changeQS with start" $+ assertEqual "Change query is valid" expected2 (changeQS 10 [Project "gerrit-haskell"] (Just 100)) ]+ where+ expected1 = "q=project:gerrit-haskell&n=10&o=MESSAGES&o=DETAILED_ACCOUNTS&o=DETAILED_LABELS&o=CURRENT_REVISION&o=CURRENT_FILES&o=CURRENT_COMMIT"+ expected2 = "q=project:gerrit-haskell&n=10&o=MESSAGES&o=DETAILED_ACCOUNTS&o=DETAILED_LABELS&o=CURRENT_REVISION&o=CURRENT_FILES&o=CURRENT_COMMIT&start=100" encodingTests :: [(FilePath, ByteString)] -> GerritClient -> [TestTree] encodingTests dataFiles client =@@ -74,7 +82,7 @@ ] where prettyEncode obj = encode obj <> "\n"- reviewInput = Gerrit.ReviewInput (Just "Thanks!") Nothing+ reviewInput = ReviewInput (Just "Thanks!") Nothing getRaw :: FilePath -> ByteString getRaw fp = fromJust $ lookup fp dataFiles isReviewResult :: Maybe ReviewResult -> Bool@@ -104,7 +112,7 @@ Just _ -> True Nothing -> False testIsApproved = case decode (getRaw "GerritChange.json") of- Just change -> hasLabel "Code-Review" 1 change+ Just change -> hasLabel "Code-Review" 2 change Nothing -> False testGetUrl = case decode (getRaw "GerritChange.json") of Just change -> changeUrl client change
test/data/GerritChange.json view
@@ -5,33 +5,127 @@ "hashtags": [], "change_id": "Ic6add806c49bccaf6e15d4ef1c62522d56eb9384", "subject": "Initial summon",- "status": "NEW",+ "status": "MERGED", "created": "2020-07-15 19:39:55.000000000",- "updated": "2020-07-15 23:01:14.000000000",- "submit_type": "MERGE_IF_NECESSARY",- "mergeable": true,+ "updated": "2020-07-16 18:08:59.000000000",+ "submitted": "2020-07-16 18:08:59.000000000",+ "submitter": {+ "_account_id": 458,+ "name": "Zuul CI",+ "email": "zuul@softwarefactory-project.io",+ "username": "zuul",+ "avatars": [+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32",+ "height": 32+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56",+ "height": 56+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100",+ "height": 100+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120",+ "height": 120+ }+ ]+ }, "insertions": 295, "deletions": 0,+ "total_comment_count": 0, "unresolved_comment_count": 0,+ "has_review_started": true,+ "submission_id": "18839-1594922939722-7c5a83e2", "_number": 18839, "owner": {- "_account_id": 7+ "_account_id": 7,+ "name": "Tristan de Cacqueray",+ "email": "tdecacqu@redhat.com",+ "username": "TristanCacqueray",+ "avatars": [+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32",+ "height": 32+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56",+ "height": 56+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100",+ "height": 100+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120",+ "height": 120+ }+ ] }, "labels": { "Code-Review": { "all": [ {- "value": 1,+ "value": 0,+ "_account_id": 458,+ "name": "Zuul CI",+ "email": "zuul@softwarefactory-project.io",+ "username": "zuul",+ "avatars": [+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32",+ "height": 32+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56",+ "height": 56+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100",+ "height": 100+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120",+ "height": 120+ }+ ]+ },+ {+ "value": 2,+ "date": "2020-07-16 18:08:48.000000000", "permitted_voting_range": {- "min": -1,- "max": 1+ "min": 2,+ "max": 2 },- "_account_id": 458+ "_account_id": 7,+ "name": "Tristan de Cacqueray",+ "email": "tdecacqu@redhat.com",+ "username": "TristanCacqueray",+ "avatars": [+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32",+ "height": 32+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56",+ "height": 56+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100",+ "height": 100+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120",+ "height": 120+ }+ ] } ], "values": { "-2": "Do not submit",- "-1": "I would prefer that you didn't submit this",+ "-1": "I would prefer that you didn\u0027t submit this", " 0": "No score", "+1": "Looks good to me, but someone else must approve", "+2": "Looks good to me (core reviewer)"@@ -41,28 +135,683 @@ "Verified": { "all": [ {- "value": 1,- "date": "2020-07-17 13:02:15.000000000",+ "value": 2,+ "date": "2020-07-16 18:08:59.000000000",+ "post_submit": true, "permitted_voting_range": {- "min": -2,+ "min": 2, "max": 2 },- "_account_id": 458+ "_account_id": 458,+ "name": "Zuul CI",+ "email": "zuul@softwarefactory-project.io",+ "username": "zuul",+ "avatars": [+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32",+ "height": 32+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56",+ "height": 56+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100",+ "height": 100+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120",+ "height": 120+ }+ ] }, {- "_account_id": 42+ "value": 0,+ "_account_id": 7,+ "name": "Tristan de Cacqueray",+ "email": "tdecacqu@redhat.com",+ "username": "TristanCacqueray",+ "avatars": [+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32",+ "height": 32+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56",+ "height": 56+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100",+ "height": 100+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120",+ "height": 120+ }+ ] } ], "values": { "-2": "Fails",- "-1": "Doesn't seem to work",+ "-1": "Doesn\u0027t seem to work", " 0": "No score", "+1": "Works for me", "+2": "Verified" }, "default_value": 0+ },+ "Workflow": {+ "all": [+ {+ "value": 0,+ "_account_id": 458,+ "name": "Zuul CI",+ "email": "zuul@softwarefactory-project.io",+ "username": "zuul",+ "avatars": [+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32",+ "height": 32+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56",+ "height": 56+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100",+ "height": 100+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120",+ "height": 120+ }+ ]+ },+ {+ "value": 1,+ "date": "2020-07-16 18:08:48.000000000",+ "permitted_voting_range": {+ "min": 1,+ "max": 1+ },+ "_account_id": 7,+ "name": "Tristan de Cacqueray",+ "email": "tdecacqu@redhat.com",+ "username": "TristanCacqueray",+ "avatars": [+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32",+ "height": 32+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56",+ "height": 56+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100",+ "height": 100+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120",+ "height": 120+ }+ ]+ }+ ],+ "values": {+ "-1": "Work in progress",+ " 0": "Ready for reviews",+ "+1": "Approved"+ },+ "default_value": 0 } },+ "removable_reviewers": [],+ "reviewers": {+ "REVIEWER": [+ {+ "_account_id": 7,+ "name": "Tristan de Cacqueray",+ "email": "tdecacqu@redhat.com",+ "username": "TristanCacqueray",+ "avatars": [+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32",+ "height": 32+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56",+ "height": 56+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100",+ "height": 100+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120",+ "height": 120+ }+ ]+ },+ {+ "_account_id": 458,+ "name": "Zuul CI",+ "email": "zuul@softwarefactory-project.io",+ "username": "zuul",+ "avatars": [+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32",+ "height": 32+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56",+ "height": 56+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100",+ "height": 100+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120",+ "height": 120+ }+ ]+ }+ ]+ },+ "pending_reviewers": {},+ "messages": [+ {+ "id": "ee2e77b6628d5a007029fab6ed7a6f6132c031c9",+ "tag": "autogenerated:gerrit:newPatchSet",+ "author": {+ "_account_id": 7,+ "name": "Tristan de Cacqueray",+ "email": "tdecacqu@redhat.com",+ "username": "TristanCacqueray",+ "avatars": [+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32",+ "height": 32+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56",+ "height": 56+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100",+ "height": 100+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120",+ "height": 120+ }+ ]+ },+ "real_author": {+ "_account_id": 7,+ "name": "Tristan de Cacqueray",+ "email": "tdecacqu@redhat.com",+ "username": "TristanCacqueray",+ "avatars": [+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32",+ "height": 32+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56",+ "height": 56+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100",+ "height": 100+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120",+ "height": 120+ }+ ]+ },+ "date": "2020-07-15 19:39:55.000000000",+ "message": "Uploaded patch set 1.",+ "_revision_number": 1+ },+ {+ "id": "3e1eb0ecb29947dda8ef79bbe67c193e9465db7a",+ "tag": "autogenerated:gerrit:newPatchSet",+ "author": {+ "_account_id": 7,+ "name": "Tristan de Cacqueray",+ "email": "tdecacqu@redhat.com",+ "username": "TristanCacqueray",+ "avatars": [+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32",+ "height": 32+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56",+ "height": 56+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100",+ "height": 100+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120",+ "height": 120+ }+ ]+ },+ "real_author": {+ "_account_id": 7,+ "name": "Tristan de Cacqueray",+ "email": "tdecacqu@redhat.com",+ "username": "TristanCacqueray",+ "avatars": [+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32",+ "height": 32+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56",+ "height": 56+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100",+ "height": 100+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120",+ "height": 120+ }+ ]+ },+ "date": "2020-07-15 21:03:21.000000000",+ "message": "Uploaded patch set 2.",+ "_revision_number": 2+ },+ {+ "id": "ba03042aa7252f4ff133d31f66b75c60f80c067f",+ "tag": "autogenerated:gerrit:newPatchSet",+ "author": {+ "_account_id": 7,+ "name": "Tristan de Cacqueray",+ "email": "tdecacqu@redhat.com",+ "username": "TristanCacqueray",+ "avatars": [+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32",+ "height": 32+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56",+ "height": 56+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100",+ "height": 100+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120",+ "height": 120+ }+ ]+ },+ "real_author": {+ "_account_id": 7,+ "name": "Tristan de Cacqueray",+ "email": "tdecacqu@redhat.com",+ "username": "TristanCacqueray",+ "avatars": [+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32",+ "height": 32+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56",+ "height": 56+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100",+ "height": 100+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120",+ "height": 120+ }+ ]+ },+ "date": "2020-07-15 23:01:02.000000000",+ "message": "Uploaded patch set 3.",+ "_revision_number": 3+ },+ {+ "id": "dc3ddbc6022f57505b3924d4c42df19ea0d2d527",+ "author": {+ "_account_id": 458,+ "name": "Zuul CI",+ "email": "zuul@softwarefactory-project.io",+ "username": "zuul",+ "avatars": [+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32",+ "height": 32+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56",+ "height": 56+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100",+ "height": 100+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120",+ "height": 120+ }+ ]+ },+ "real_author": {+ "_account_id": 458,+ "name": "Zuul CI",+ "email": "zuul@softwarefactory-project.io",+ "username": "zuul",+ "avatars": [+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32",+ "height": 32+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56",+ "height": 56+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100",+ "height": 100+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120",+ "height": 120+ }+ ]+ },+ "date": "2020-07-15 23:01:13.000000000",+ "message": "Patch Set 3:\n\nStarting check jobs. Status at",+ "_revision_number": 3+ },+ {+ "id": "f053926475b8fd9da58d55ae47d8f7eef3a3a727",+ "author": {+ "_account_id": 458,+ "name": "Zuul CI",+ "email": "zuul@softwarefactory-project.io",+ "username": "zuul",+ "avatars": [+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32",+ "height": 32+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56",+ "height": 56+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100",+ "height": 100+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120",+ "height": 120+ }+ ]+ },+ "real_author": {+ "_account_id": 458,+ "name": "Zuul CI",+ "email": "zuul@softwarefactory-project.io",+ "username": "zuul",+ "avatars": [+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32",+ "height": 32+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56",+ "height": 56+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100",+ "height": 100+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120",+ "height": 120+ }+ ]+ },+ "date": "2020-07-15 23:01:14.000000000",+ "message": "Patch Set 3: Verified+1\n\nBuild succeeded.\n\n- noop https://softwarefactory-project.io/zuul/t/local/build/c6511d87e5f644e7b566b73741600392 : SUCCESS in 0s",+ "_revision_number": 3+ },+ {+ "id": "9d688628218ba8972d8ecf51669bec9c83d3a18f",+ "author": {+ "_account_id": 7,+ "name": "Tristan de Cacqueray",+ "email": "tdecacqu@redhat.com",+ "username": "TristanCacqueray",+ "avatars": [+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32",+ "height": 32+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56",+ "height": 56+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100",+ "height": 100+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120",+ "height": 120+ }+ ]+ },+ "real_author": {+ "_account_id": 7,+ "name": "Tristan de Cacqueray",+ "email": "tdecacqu@redhat.com",+ "username": "TristanCacqueray",+ "avatars": [+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32",+ "height": 32+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56",+ "height": 56+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100",+ "height": 100+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120",+ "height": 120+ }+ ]+ },+ "date": "2020-07-16 18:08:48.000000000",+ "message": "Patch Set 3: Code-Review+2 Workflow+1",+ "_revision_number": 3+ },+ {+ "id": "f2dcf8b15417b0057b2e7384c51d194cce7a0491",+ "tag": "autogenerated:gerrit:merged",+ "author": {+ "_account_id": 458,+ "name": "Zuul CI",+ "email": "zuul@softwarefactory-project.io",+ "username": "zuul",+ "avatars": [+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32",+ "height": 32+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56",+ "height": 56+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100",+ "height": 100+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120",+ "height": 120+ }+ ]+ },+ "real_author": {+ "_account_id": 458,+ "name": "Zuul CI",+ "email": "zuul@softwarefactory-project.io",+ "username": "zuul",+ "avatars": [+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32",+ "height": 32+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56",+ "height": 56+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100",+ "height": 100+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120",+ "height": 120+ }+ ]+ },+ "date": "2020-07-16 18:08:59.000000000",+ "message": "Change has been successfully merged by Zuul CI",+ "_revision_number": 3+ },+ {+ "id": "10a3e0eeee03627b1d57a9e932a479545a2f2ade",+ "author": {+ "_account_id": 458,+ "name": "Zuul CI",+ "email": "zuul@softwarefactory-project.io",+ "username": "zuul",+ "avatars": [+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32",+ "height": 32+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56",+ "height": 56+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100",+ "height": 100+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120",+ "height": 120+ }+ ]+ },+ "real_author": {+ "_account_id": 458,+ "name": "Zuul CI",+ "email": "zuul@softwarefactory-project.io",+ "username": "zuul",+ "avatars": [+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32",+ "height": 32+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56",+ "height": 56+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100",+ "height": 100+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120",+ "height": 120+ }+ ]+ },+ "date": "2020-07-16 18:08:59.000000000",+ "message": "Patch Set 3: -Verified\n\nStarting gate jobs.",+ "_revision_number": 3+ },+ {+ "id": "b3d3d3639dc32a9ee80d7b65a82ab57615925d6d",+ "author": {+ "_account_id": 458,+ "name": "Zuul CI",+ "email": "zuul@softwarefactory-project.io",+ "username": "zuul",+ "avatars": [+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32",+ "height": 32+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56",+ "height": 56+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100",+ "height": 100+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120",+ "height": 120+ }+ ]+ },+ "real_author": {+ "_account_id": 458,+ "name": "Zuul CI",+ "email": "zuul@softwarefactory-project.io",+ "username": "zuul",+ "avatars": [+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32",+ "height": 32+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56",+ "height": 56+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100",+ "height": 100+ },+ {+ "url": "https://www.gravatar.com/avatar/72ca689f16f3f13bf36869ea655c488e.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120",+ "height": 120+ }+ ]+ },+ "date": "2020-07-16 18:08:59.000000000",+ "message": "Patch Set 3: Verified+2\n\nBuild succeeded (gate pipeline).\n\n- noop https://softwarefactory-project.io/zuul/t/local/build/261409bf24ea4b20a8a4304bcbed343a : SUCCESS in 0s",+ "_revision_number": 3+ }+ ], "current_revision": "155658085799464e8d198edb7c8bd62de9ec9ae6", "revisions": { "155658085799464e8d198edb7c8bd62de9ec9ae6": {@@ -70,7 +819,28 @@ "_number": 3, "created": "2020-07-15 23:01:02.000000000", "uploader": {- "_account_id": 7+ "_account_id": 7,+ "name": "Tristan de Cacqueray",+ "email": "tdecacqu@redhat.com",+ "username": "TristanCacqueray",+ "avatars": [+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32",+ "height": 32+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56",+ "height": 56+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100",+ "height": 100+ },+ {+ "url": "https://www.gravatar.com/avatar/921d0ed12095380e7b79d606bb037261.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120",+ "height": 120+ }+ ] }, "ref": "refs/changes/39/18839/3", "fetch": {@@ -78,7 +848,80 @@ "url": "https://softwarefactory-project.io/r/software-factory/gerrit-haskell", "ref": "refs/changes/39/18839/3" }+ },+ "commit": {+ "parents": [+ {+ "commit": "fda786eda9e53208ede9b571174b85e4be39a44d",+ "subject": "ManageSF commit"+ }+ ],+ "author": {+ "name": "Tristan Cacqueray",+ "email": "tdecacqu@redhat.com",+ "date": "2020-07-15 19:38:27.000000000",+ "tz": 0+ },+ "committer": {+ "name": "Tristan Cacqueray",+ "email": "tdecacqu@redhat.com",+ "date": "2020-07-15 23:00:30.000000000",+ "tz": 0+ },+ "subject": "Initial summon",+ "message": "Initial summon\n\nChange-Id: Ic6add806c49bccaf6e15d4ef1c62522d56eb9384\n"+ },+ "files": {+ ".zuul.yaml": {+ "status": "A",+ "lines_inserted": 5,+ "size_delta": 71,+ "size": 71+ },+ "LICENSE": {+ "status": "A",+ "lines_inserted": 201,+ "size_delta": 11357,+ "size": 11357+ },+ "README.md": {+ "status": "A",+ "lines_inserted": 3,+ "size_delta": 34,+ "size": 34+ },+ "app/Main.hs": {+ "status": "A",+ "lines_inserted": 6,+ "size_delta": 82,+ "size": 82+ },+ "gerrit-haskell.cabal": {+ "status": "A",+ "lines_inserted": 61,+ "size_delta": 1863,+ "size": 1863+ },+ "src/Gerrit.hs": {+ "status": "A",+ "lines_inserted": 13,+ "size_delta": 279,+ "size": 279+ },+ "stack.yaml": {+ "status": "A",+ "lines_inserted": 1,+ "size_delta": 19,+ "size": 19+ },+ "test/Spec.hs": {+ "status": "A",+ "lines_inserted": 5,+ "size_delta": 101,+ "size": 101+ } } }- }+ },+ "requirements": [] }