Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Lukas Wiest
unified-ticketing
Commits
25207b24
Verified
Commit
25207b24
authored
Dec 20, 2020
by
Lukas Wiest
🚂
Browse files
feat(systems): add implementation for GitHub
parent
42f19bc5
Changes
7
Hide whitespace changes
Inline
Side-by-side
src/main/java/de/hftstuttgart/unifiedticketing/systems/github/GithubFilter.java
0 → 100644
View file @
25207b24
package
de.hftstuttgart.unifiedticketing.systems.github
;
import
com.fasterxml.jackson.core.type.TypeReference
;
import
com.fasterxml.jackson.databind.DeserializationFeature
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
de.hftstuttgart.unifiedticketing.core.Filter
;
import
de.hftstuttgart.unifiedticketing.core.Logging
;
import
de.hftstuttgart.unifiedticketing.core.TicketSystem
;
import
de.hftstuttgart.unifiedticketing.exceptions.*
;
import
okhttp3.*
;
import
java.io.IOException
;
import
java.util.*
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
import
java.util.stream.Collectors
;
import
java.util.stream.Stream
;
public
class
GithubFilter
extends
Filter
<
GithubTicket
,
GithubFilter
>
{
private
final
static
Logger
logger
=
Logging
.
getLogger
(
GithubFilter
.
class
.
getName
());
protected
final
GithubTicketSystem
parent
;
protected
GithubFilter
(
GithubTicketSystem
parent
)
{
this
.
parent
=
parent
;
}
protected
OkHttpClient
getHttpClient
()
{
return
new
OkHttpClient
();
}
@Override
public
List
<
GithubTicket
>
get
()
{
ObjectMapper
mapper
=
new
ObjectMapper
()
.
configure
(
DeserializationFeature
.
FAIL_ON_UNKNOWN_PROPERTIES
,
false
);
Request
.
Builder
requestBuilder
=
new
Request
.
Builder
()
.
url
(
parent
.
baseUrl
)
.
addHeader
(
"accept"
,
parent
.
acceptHeader
)
.
get
();
if
(
parent
.
username
!=
null
&&
parent
.
apiKey
!=
null
)
{
requestBuilder
.
addHeader
(
"Authorization"
,
Credentials
.
basic
(
parent
.
username
,
parent
.
apiKey
));
logger
.
log
(
Level
.
FINEST
,
"added token authentication header"
);
}
HttpUrl
.
Builder
urlBuilder
=
requestBuilder
.
build
().
url
().
newBuilder
();
for
(
Map
.
Entry
<
String
,
Object
>
mapEntry
:
setFilters
.
entrySet
())
{
String
f
=
mapEntry
.
getKey
();
Object
v
=
mapEntry
.
getValue
();
try
{
if
(
f
.
equals
(
FilterNames
.
ASSIGNEEID
.
name
()))
{
logger
.
log
(
Level
.
WARNING
,
"assignee-id check only possible after request |"
+
" Filter: "
+
FilterNames
.
ASSIGNEEID
.
name
());
}
else
if
(
f
.
equals
(
FilterNames
.
ASSIGNEENAME
.
name
()))
{
Set
<
String
>
names
=
(
Set
<
String
>)
v
;
if
(
names
.
size
()
>
0
)
{
urlBuilder
.
addQueryParameter
(
"assignee"
,
names
.
stream
()
.
findFirst
()
.
get
());
if
(
names
.
size
()
>
1
)
{
logger
.
log
(
Level
.
WARNING
,
"assignee-name filter natively only for one name supported"
);
}
}
}
else
if
(
f
.
equals
(
FilterNames
.
DESCRIPTION_CONTAIN
.
name
()))
{
logger
.
log
(
Level
.
FINE
,
"Description contain check only possible after request |"
+
" Filter: "
+
FilterNames
.
DESCRIPTION_CONTAIN
.
name
());
}
else
if
(
f
.
equals
(
FilterNames
.
DESCRIPTION_MATCH
.
name
()))
{
logger
.
log
(
Level
.
FINE
,
"Regex matching only possible after request |"
+
" Filter: "
+
FilterNames
.
DESCRIPTION_MATCH
.
name
());
}
else
if
(
f
.
equals
(
FilterNames
.
IDS
.
name
()))
{
logger
.
log
(
Level
.
FINE
,
"Ticket id matching only possible after request |"
+
" Filter: "
+
FilterNames
.
IDS
.
name
());
}
else
if
(
f
.
equals
(
FilterNames
.
LABELS
.
name
()))
{
urlBuilder
.
addQueryParameter
(
"labels"
,
((
Set
<
String
>)
v
).
stream
()
.
reduce
((
l1
,
l2
)
->
l1
+
","
+
l2
)
.
orElse
(
""
));
}
else
if
(
f
.
equals
(
FilterNames
.
PAGE
.
name
()))
{
urlBuilder
.
addQueryParameter
(
"page"
,
String
.
valueOf
(
v
));
}
else
if
(
f
.
equals
(
FilterNames
.
PAGINATION
.
name
()))
{
urlBuilder
.
addQueryParameter
(
"per_page"
,
String
.
valueOf
(
v
));
}
else
if
(
f
.
equals
(
FilterNames
.
OPEN
.
name
()))
{
urlBuilder
.
addQueryParameter
(
"state"
,
((
boolean
)
v
)
?
"open"
:
"closed"
);
}
else
if
(
f
.
equals
(
FilterNames
.
TITLE_CONTAINS
.
name
()))
{
logger
.
log
(
Level
.
FINE
,
"title contain check only possible after request |"
+
" Filter: "
+
FilterNames
.
TITLE_CONTAINS
.
name
());
}
else
if
(
f
.
equals
(
FilterNames
.
TITLE_MATCH
.
name
()))
{
logger
.
log
(
Level
.
FINE
,
"Regex matching only possible after request |"
+
" Filter: "
+
FilterNames
.
TITLE_MATCH
.
name
());
}
else
{
logger
.
log
(
Level
.
WARNING
,
String
.
format
(
"unrecognized filter key: %s"
,
f
));
}
}
catch
(
ClassCastException
e
)
{
logger
.
log
(
Level
.
SEVERE
,
"Filter with key "
+
f
+
" unexpectedly had type "
+
v
.
getClass
().
getName
());
if
(!
this
.
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
{
throw
new
AssertionException
(
e
);
}
}
}
requestBuilder
.
url
(
urlBuilder
.
build
());
OkHttpClient
client
=
getHttpClient
();
Response
response
;
try
{
Request
request
=
requestBuilder
.
build
();
logger
.
log
(
Level
.
FINEST
,
String
.
format
(
"created request:\n%s"
,
(
this
.
parent
.
apiKey
!=
null
)
?
request
.
toString
().
replace
(
this
.
parent
.
apiKey
,
"SECRET"
)
:
request
.
toString
()
));
response
=
client
.
newCall
(
request
).
execute
();
}
catch
(
IOException
e
)
{
logger
.
log
(
Level
.
SEVERE
,
String
.
format
(
"get request FAILED with: %s"
,
e
.
getMessage
()));
if
(
this
.
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
null
;
else
throw
new
HttpReqeustException
(
e
);
}
if
(
response
.
code
()
>=
400
)
{
logger
.
log
(
Level
.
SEVERE
,
String
.
format
(
"request failed with response code %d"
,
response
.
code
()
));
if
(
this
.
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
null
;
else
throw
new
HttpResponseException
(
String
.
format
(
"ticket query failed, error response code: %d"
,
response
.
code
()),
response
.
code
());
}
logger
.
log
(
Level
.
FINEST
,
"response received\n"
);
ResponseBody
responseBody
;
responseBody
=
response
.
body
();
if
(
responseBody
==
null
)
{
logger
.
log
(
Level
.
SEVERE
,
"query didn't deliver a body in response"
);
if
(
this
.
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
null
;
else
throw
new
HttpResponseException
(
"ticket query failed, no response body"
,
response
.
code
());
}
List
<
GithubTicketResponse
>
tr
;
try
{
tr
=
mapper
.
readValue
(
responseBody
.
bytes
(),
new
TypeReference
<
List
<
GithubTicketResponse
>>(){});
logger
.
log
(
Level
.
FINER
,
"parsed response body to ticketResponse list instance"
);
logger
.
log
(
Level
.
FINEST
,
String
.
format
(
"found %d items pre post-filter"
,
tr
.
size
()));
}
catch
(
IOException
e
)
{
logger
.
log
(
Level
.
SEVERE
,
String
.
format
(
"parsing query response FAILED with: %s"
,
e
.
getMessage
()));
if
(
this
.
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
null
;
else
throw
new
DeserializationException
(
e
);
}
logger
.
log
(
Level
.
FINER
,
"starting query post filter"
);
Stream
<
GithubTicketResponse
>
ticketStream
=
tr
.
stream
();
for
(
Map
.
Entry
<
String
,
Object
>
entry
:
setFilters
.
entrySet
())
{
String
f
=
entry
.
getKey
();
Object
v
=
entry
.
getValue
();
try
{
if
(
f
.
equals
(
FilterNames
.
ASSIGNEEID
.
name
()))
{
ticketStream
=
ticketStream
.
filter
(
t
->
t
.
assignees
.
stream
()
.
map
(
a
->
String
.
valueOf
(
a
.
id
))
.
collect
(
Collectors
.
toSet
())
.
equals
((
Set
<
String
>)
v
));
}
else
if
(
f
.
equals
(
FilterNames
.
ASSIGNEENAME
.
name
())
&&
((
Set
)
v
).
size
()
>
1
)
{
ticketStream
=
ticketStream
.
filter
(
t
->
t
.
assignees
.
stream
()
.
map
(
a
->
a
.
login
)
.
collect
(
Collectors
.
toSet
())
.
equals
((
Set
<
String
>)
v
));
}
else
if
(
f
.
equals
(
FilterNames
.
DESCRIPTION_CONTAIN
))
{
ticketStream
=
ticketStream
.
filter
(
t
->
t
.
body
.
toLowerCase
()
.
contains
(((
String
)
v
).
toLowerCase
()));
}
else
if
(
f
.
equals
(
FilterNames
.
DESCRIPTION_MATCH
.
name
()))
{
ticketStream
=
ticketStream
.
filter
(
t
->
t
.
body
.
matches
((
String
)
v
));
}
else
if
(
f
.
equals
(
FilterNames
.
TITLE_CONTAINS
.
name
()))
{
ticketStream
=
ticketStream
.
filter
(
t
->
t
.
title
.
toLowerCase
()
.
contains
(((
String
)
v
).
toLowerCase
()));
}
else
if
(
f
.
equals
(
FilterNames
.
TITLE_MATCH
.
name
()))
{
ticketStream
=
ticketStream
.
filter
(
t
->
t
.
title
.
matches
((
String
)
v
));
}
}
catch
(
ClassCastException
e
)
{
logger
.
log
(
Level
.
SEVERE
,
"Filter with key "
+
f
+
" unexpectedly had type "
+
v
.
getClass
().
getName
());
}
}
logger
.
log
(
Level
.
FINER
,
"post-filter finished"
);
List
<
GithubTicket
>
ret
=
ticketStream
.
map
(
t
->
GithubTicket
.
fromTicketResponse
(
parent
,
t
))
.
collect
(
Collectors
.
toList
());
logger
.
log
(
Level
.
FINEST
,
String
.
format
(
"remaining items: %d"
,
ret
.
size
()));
return
ret
;
}
}
src/main/java/de/hftstuttgart/unifiedticketing/systems/github/GithubTicket.java
0 → 100644
View file @
25207b24
package
de.hftstuttgart.unifiedticketing.systems.github
;
import
com.fasterxml.jackson.core.JsonProcessingException
;
import
com.fasterxml.jackson.databind.DeserializationFeature
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
com.fasterxml.jackson.databind.node.ArrayNode
;
import
com.fasterxml.jackson.databind.node.ObjectNode
;
import
de.hftstuttgart.unifiedticketing.core.Logging
;
import
de.hftstuttgart.unifiedticketing.core.Ticket
;
import
de.hftstuttgart.unifiedticketing.core.TicketSystem
;
import
de.hftstuttgart.unifiedticketing.exceptions.DeserializationException
;
import
de.hftstuttgart.unifiedticketing.exceptions.HttpReqeustException
;
import
de.hftstuttgart.unifiedticketing.exceptions.HttpResponseException
;
import
de.hftstuttgart.unifiedticketing.exceptions.SerializationException
;
import
okhttp3.*
;
import
java.io.IOException
;
import
java.util.Objects
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
import
java.util.stream.Collectors
;
public
class
GithubTicket
extends
Ticket
<
GithubTicketSystem
,
GithubTicket
>
{
private
final
static
Logger
logger
=
Logging
.
getLogger
(
GithubTicket
.
class
.
getName
());
protected
static
GithubTicket
fromTicketResponse
(
GithubTicketSystem
parent
,
GithubTicketResponse
response
)
{
GithubTicket
ret
=
new
GithubTicket
(
parent
);
ret
.
description
=
response
.
body
;
ret
.
id
=
String
.
valueOf
(
response
.
number
);
ret
.
open
=
response
.
state
.
equalsIgnoreCase
(
"open"
);
ret
.
title
=
response
.
title
;
if
(
response
.
assignees
!=
null
)
{
ret
.
assignees
=
response
.
assignees
.
stream
()
.
map
(
a
->
new
GithubTicketAssignee
(
a
.
id
,
a
.
login
))
.
collect
(
Collectors
.
toSet
());
}
if
(
response
.
labels
!=
null
)
{
ret
.
labels
=
response
.
labels
.
stream
()
.
map
(
l
->
l
.
name
)
.
collect
(
Collectors
.
toSet
());
}
return
ret
;
}
protected
GithubTicket
(
GithubTicketSystem
parent
)
{
super
(
parent
);
}
@Override
public
GithubTicket
addAssignee
(
String
identifier
)
{
this
.
assignees
.
add
(
new
GithubTicketAssignee
(
0
,
identifier
));
this
.
updatedFields
.
add
(
FieldNames
.
ASSIGNEES
.
name
());
return
this
;
}
@Override
public
GithubTicket
removeAssignee
(
String
identifier
)
{
this
.
assignees
.
removeIf
(
a
->
Objects
.
equals
(
a
.
username
,
identifier
));
this
.
updatedFields
.
add
(
FieldNames
.
ASSIGNEES
.
name
());
return
null
;
}
protected
OkHttpClient
getHttpClient
()
{
return
new
OkHttpClient
();
}
@Override
public
GithubTicket
save
()
{
if
(
updatedFields
.
size
()
==
0
)
{
logger
.
info
(
"No changed fields, no save required"
);
return
this
;
}
OkHttpClient
client
=
this
.
getHttpClient
();
ObjectMapper
mapper
=
new
ObjectMapper
()
.
configure
(
DeserializationFeature
.
FAIL_ON_UNKNOWN_PROPERTIES
,
false
);
logger
.
log
(
Level
.
FINEST
,
String
.
format
(
"[Ticket %s] preparing body for update request"
,
this
.
id
));
ObjectNode
body
=
mapper
.
createObjectNode
();
for
(
String
name
:
this
.
updatedFields
)
{
if
(
FieldNames
.
ASSIGNEES
.
name
().
equals
(
name
))
{
ArrayNode
arrayNode
=
body
.
putArray
(
"assignees"
);
this
.
assignees
.
forEach
(
a
->
arrayNode
.
add
(
a
.
username
));
}
else
if
(
FieldNames
.
DESCRIPTION
.
name
().
equals
(
name
))
{
body
.
put
(
"body"
,
this
.
description
);
}
else
if
(
FieldNames
.
LABELS
.
name
().
equals
(
name
))
{
ArrayNode
arrayNode
=
body
.
putArray
(
"labels"
);
this
.
labels
.
forEach
(
arrayNode:
:
add
);
}
else
if
(
FieldNames
.
OPEN
.
name
().
equals
(
name
))
{
body
.
put
(
"state"
,
(
this
.
open
)
?
"open"
:
"closed"
);
}
else
if
(
FieldNames
.
TITLE
.
name
().
equals
(
name
))
{
body
.
put
(
"title"
,
this
.
title
);
}
else
{
logger
.
log
(
Level
.
WARNING
,
String
.
format
(
"[Ticket %s] unknown field %s will be ignored from update"
,
this
.
id
,
name
));
continue
;
}
logger
.
log
(
Level
.
FINEST
,
String
.
format
(
"[Ticket %s] %s added to update"
,
this
.
id
,
name
));
}
logger
.
log
(
Level
.
FINEST
,
String
.
format
(
"[Ticket %s] request body for update prepared"
,
this
.
id
));
Request
.
Builder
builder
=
new
Request
.
Builder
()
.
url
(
String
.
format
(
"%s/%s"
,
this
.
parent
.
baseUrl
,
this
.
id
))
.
addHeader
(
"accept"
,
parent
.
acceptHeader
);
try
{
logger
.
log
(
Level
.
FINEST
,
String
.
format
(
"[Ticket %s] serializing update request body"
,
this
.
id
));
String
bodyJson
=
mapper
.
writeValueAsString
(
body
);
logger
.
log
(
Level
.
FINEST
,
String
.
format
(
"[Ticket %s] serialized JSON:\n%s"
,
this
.
id
,
bodyJson
));
builder
.
patch
(
RequestBody
.
create
(
bodyJson
,
MediaType
.
get
(
"application/json"
)));
}
catch
(
JsonProcessingException
e
)
{
logger
.
log
(
Level
.
SEVERE
,
String
.
format
(
"[Ticket %s] serializing update request body FAILED!"
,
this
.
id
));
if
(
this
.
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
null
;
else
throw
new
SerializationException
(
e
);
}
if
(
parent
.
username
!=
null
&&
parent
.
apiKey
!=
null
)
{
builder
.
addHeader
(
"Authorization"
,
Credentials
.
basic
(
parent
.
username
,
parent
.
apiKey
));
logger
.
log
(
Level
.
FINEST
,
String
.
format
(
"[Ticket %s] added token authentication header"
,
this
.
id
));
}
Response
response
;
try
{
Request
request
=
builder
.
build
();
logger
.
log
(
Level
.
FINEST
,
String
.
format
(
"[Ticket %s] created request:\n%s"
,
this
.
id
,
(
this
.
parent
.
apiKey
!=
null
)
?
request
.
toString
().
replace
(
this
.
parent
.
apiKey
,
"SECRET"
)
:
request
.
toString
()
));
response
=
client
.
newCall
(
request
).
execute
();
}
catch
(
IOException
e
)
{
logger
.
log
(
Level
.
SEVERE
,
String
.
format
(
"[Ticket %s] update request FAILED"
,
this
.
id
));
if
(
this
.
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
null
;
else
throw
new
HttpReqeustException
(
e
);
}
if
(
response
.
code
()
>=
400
)
{
logger
.
log
(
Level
.
SEVERE
,
String
.
format
(
"[Ticket %s] update request failed with response code %d"
,
this
.
id
,
response
.
code
()
));
if
(
this
.
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
null
;
else
throw
new
HttpResponseException
(
String
.
format
(
"ticket save failed, error response code: %d"
,
response
.
code
()),
response
.
code
());
}
logger
.
log
(
Level
.
FINEST
,
String
.
format
(
"[Ticket %s] response received"
,
this
.
id
));
ResponseBody
responseBody
;
responseBody
=
response
.
body
();
if
(
responseBody
==
null
)
{
logger
.
log
(
Level
.
SEVERE
,
String
.
format
(
"[Ticket %s] update request didn't deliver a body in response"
,
this
.
id
));
if
(
this
.
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
null
;
else
throw
new
HttpResponseException
(
"ticket save failed, no response body"
,
response
.
code
());
}
GithubTicketResponse
ticketResponse
;
try
{
ticketResponse
=
mapper
.
readValue
(
responseBody
.
bytes
(),
GithubTicketResponse
.
class
);
logger
.
log
(
Level
.
FINEST
,
String
.
format
(
"[Ticket %s] parsed response body to ticketResponse instance"
,
this
.
id
));
}
catch
(
IOException
e
)
{
logger
.
log
(
Level
.
SEVERE
,
String
.
format
(
"parsing update response FAILED with: %s"
,
e
.
getMessage
()));
if
(
this
.
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
null
;
else
throw
new
DeserializationException
(
e
);
}
this
.
updatedFields
.
clear
();
logger
.
log
(
Level
.
FINEST
,
String
.
format
(
"[Ticket %s] update mark state reset"
,
this
.
id
));
return
GithubTicket
.
fromTicketResponse
(
this
.
parent
,
ticketResponse
);
}
}
src/main/java/de/hftstuttgart/unifiedticketing/systems/github/GithubTicketAssignee.java
0 → 100644
View file @
25207b24
package
de.hftstuttgart.unifiedticketing.systems.github
;
import
de.hftstuttgart.unifiedticketing.core.TicketAssignee
;
public
class
GithubTicketAssignee
extends
TicketAssignee
{
protected
GithubTicketAssignee
(
int
id
,
String
username
)
{
super
(
null
,
String
.
valueOf
(
id
),
username
,
null
);
}
}
src/main/java/de/hftstuttgart/unifiedticketing/systems/github/GithubTicketBuilder.java
0 → 100644
View file @
25207b24
package
de.hftstuttgart.unifiedticketing.systems.github
;
import
com.fasterxml.jackson.core.JsonProcessingException
;
import
com.fasterxml.jackson.databind.DeserializationFeature
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
com.fasterxml.jackson.databind.node.ArrayNode
;
import
com.fasterxml.jackson.databind.node.ObjectNode
;
import
de.hftstuttgart.unifiedticketing.core.Logging
;
import
de.hftstuttgart.unifiedticketing.core.TicketBuilder
;
import
de.hftstuttgart.unifiedticketing.core.TicketSystem
;
import
de.hftstuttgart.unifiedticketing.exceptions.*
;
import
okhttp3.*
;
import
java.io.IOException
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
public
class
GithubTicketBuilder
extends
TicketBuilder
<
GithubTicketBuilder
,
GithubTicket
,
GithubTicketSystem
>
{
private
final
static
Logger
logger
=
Logging
.
getLogger
(
GithubTicketBuilder
.
class
.
getName
());
protected
GithubTicketBuilder
(
GithubTicketSystem
parent
)
{
super
(
parent
);
}
protected
OkHttpClient
getHttpClient
()
{
return
new
OkHttpClient
();
}
@Override
public
GithubTicket
create
()
{
logger
.
log
(
Level
.
FINEST
,
"starting Ticket creation from builder data"
);
ObjectMapper
mapper
=
new
ObjectMapper
()
.
configure
(
DeserializationFeature
.
FAIL_ON_UNKNOWN_PROPERTIES
,
false
);
ObjectNode
body
=
mapper
.
createObjectNode
();
// title is mandatory field
if
(
this
.
title
==
null
)
{
String
msg
=
"mandatory field title not set before building ticket"
;
logger
.
log
(
Level
.
SEVERE
,
msg
);
if
(
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
null
;
else
throw
new
AssertionException
(
msg
);
}
if
(
this
.
description
!=
null
)
{
body
.
put
(
"body"
,
this
.
description
);
logger
.
log
(
Level
.
FINEST
,
"description set"
);
}
body
.
put
(
"title"
,
this
.
title
);
logger
.
log
(
Level
.
FINEST
,
"title set"
);
if
(
this
.
assignees
!=
null
)
{
ArrayNode
arrayNode
=
body
.
putArray
(
"assignees"
);
assignees
.
forEach
(
arrayNode:
:
add
);
logger
.
log
(
Level
.
FINEST
,
"assignees set"
);
}
if
(
this
.
labels
!=
null
)
{
ArrayNode
arrayNode
=
body
.
putArray
(
"labels"
);
this
.
labels
.
forEach
(
arrayNode:
:
add
);
logger
.
log
(
Level
.
FINEST
,
"labels set"
);
}
String
jsonBody
;
try
{
jsonBody
=
mapper
.
writeValueAsString
(
body
);
}
catch
(
JsonProcessingException
e
)
{
String
msg
=
"json serialization FAILED"
;
logger
.
log
(
Level
.
SEVERE
,
msg
);
if
(
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
null
;
else
throw
new
SerializationException
(
e
);
}
OkHttpClient
client
=
getHttpClient
();
Request
.
Builder
builder
=
new
Request
.
Builder
()
.
url
(
parent
.
baseUrl
)
.
addHeader
(
"accept"
,
parent
.
acceptHeader
)
.
post
(
RequestBody
.
create
(
jsonBody
,
MediaType
.
get
(
"application/json"
)));
if
(
this
.
parent
.
username
!=
null
&&
this
.
parent
.
apiKey
!=
null
)
{
builder
.
addHeader
(
"Authorization"
,
Credentials
.
basic
(
this
.
parent
.
username
,
this
.
parent
.
apiKey
));
logger
.
log
(
Level
.
FINEST
,
"added basic auth header with api token"
);
}
Response
response
;
try
{
Request
request
=
builder
.
build
();
logger
.
log
(
Level
.
FINEST
,
String
.
format
(
"created request:\n%s"
,
(
this
.
parent
.
apiKey
!=
null
)
?
request
.
toString
().
replace
(
this
.
parent
.
apiKey
,
"SECRET"
)
:
request
.
toString
()
));
response
=
client
.
newCall
(
request
).
execute
();
}
catch
(
IOException
e
)
{
logger
.
log
(
Level
.
SEVERE
,
"create request FAILED"
);
if
(
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
null
;
else
throw
new
HttpReqeustException
(
e
);
}
if
(
response
.
code
()
>=
400
)
{
logger
.
log
(
Level
.
SEVERE
,
String
.
format
(
"create request failed with response code %d"
,
response
.
code
()
));
if
(
this
.
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
null
;
else
throw
new
HttpResponseException
(
String
.
format
(
"ticket creation failed, error response code %d"
,
response
.
code
()),
response
.
code
());
}
logger
.
log
(
Level
.
FINEST
,
"response received\n"
);
ResponseBody
responseBody
;
responseBody
=
response
.
body
();
if
(
responseBody
==
null
)
{
logger
.
log
(
Level
.
SEVERE
,
"create request didn't deliver a body in response"
);
if
(
this
.
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
null
;
else
throw
new
HttpResponseException
(
"ticket creation failed, no response body"
,
response
.
code
());
}
GithubTicketResponse
ticketResponse
;
try
{
ticketResponse
=
mapper
.
readValue
(
responseBody
.
bytes
(),
GithubTicketResponse
.
class
);
logger
.
log
(
Level
.
FINEST
,
"parsed response to ticketResponse instance"
);
}
catch
(
IOException
e
)
{
logger
.
severe
(
String
.
format
(
"parsing create response FAILED with: %s"
,
e
.
getMessage
()));
if
(
parent
.
getConfigTrue
(
TicketSystem
.
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
null
;
else
throw
new
DeserializationException
(
e
);
}
return
GithubTicket
.
fromTicketResponse
(
parent
,
ticketResponse
);
}
}
src/main/java/de/hftstuttgart/unifiedticketing/systems/github/GithubTicketResponse.java
0 → 100644
View file @
25207b24
package
de.hftstuttgart.unifiedticketing.systems.github
;
import
java.util.Set
;
public
class
GithubTicketResponse
{
public
Set
<
Assignee
>
assignees
;
public
String
body
;
public
int
number
;
public
Set
<
Label
>
labels
;
public
String
state
;
public
String
title
;
protected
static
class
Label
{
public
String
name
;
}
protected
static
class
Assignee
{
public
int
id
;
public
String
login
;
}
}
src/main/java/de/hftstuttgart/unifiedticketing/systems/github/GithubTicketSystem.java
0 → 100644
View file @
25207b24
package
de.hftstuttgart.unifiedticketing.systems.github
;
import
de.hftstuttgart.unifiedticketing.core.*
;
import
de.hftstuttgart.unifiedticketing.exceptions.AssertionException
;
import
de.hftstuttgart.unifiedticketing.exceptions.UnifiedticketingException
;
import
java.util.List
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
import
java.util.regex.Matcher
;
import
java.util.regex.Pattern
;
public
class
GithubTicketSystem
extends
TicketSystem
<
GithubTicket
,
GithubTicketSystem
,
GithubTicketBuilder
,
GithubFilter
>
{
private
final
static
Logger
logger
=
Logging
.
getLogger
(
GithubTicketSystem
.
class
.
getName
());
protected
final
String
acceptHeader
;
protected
final
String
apiKey
;
protected
final
String
username
;
/**
* creates a new instance of this class from an uri.<br>
* <br>
* <b>Attention:</b> This method should not be called from the enduser!<br>
* Instead call the same method from {@link TicketSystem}.<br>
* To call this method directly, the uri has to be shortend by the {@code "unifiedticketing:github:"} part.
* @param uri gitlab specific part of full uri
* @return new github ticket system instance
*/
public
static
GithubTicketSystem
fromUri
(
String
uri
)
{
Matcher
matcher
=
Pattern
.
compile
(
"^((http|https):\\/\\/)?(.*?(:[0-9]+.*?)?)::(.*?):(.*?)(:(.*?):(.*?))?$"
).
matcher
(
uri
);
if
(!
matcher
.
matches
())
{
String
msg
=
"uri didn't match regex"
;
logger
.
log
(
Level
.
SEVERE
,
msg
);
throw
new
AssertionException
(
msg
);
}
GithubTicketSystemBuilder
builder
=
new
GithubTicketSystemBuilder
();
if
(
matcher
.
group
(
2
)
!=
null
&&
matcher
.
group
(
2
).
length
()
>
0
)
{
if
(
matcher
.
group
(
2
).
equalsIgnoreCase
(
"http"
))
builder
.
withHttp
();
else
builder
.
withHttps
();
}
if
(
matcher
.
group
(
3
)
==
null
||
matcher
.
group
(
3
).
length
()
==
0
)
{
String
msg
=
"no base url identified in uri"
;
throw
new
AssertionException
(
msg
);
}
builder
.
withBaseUrl
(
matcher
.
group
(
3
));
if
(
matcher
.
group
(
5
)
==
null
||
matcher
.
group
(
5
).
length
()
==
0
)
{
String
msg
=
"no owner identified in uri"
;
throw
new
AssertionException
(
msg
);
}
builder
.
withOwner
(
matcher
.
group
(
5
));
if
(
matcher
.
group
(
6
)
==
null
||
matcher
.
group
(
6
).
length
()
==
0
)
{
String
msg
=
"no repo identified in uri"
;
throw
new
AssertionException
(
msg
);
}
builder
.
withRepo
(
matcher
.
group
(
6
));
if
(
matcher
.
group
(
8
)
!=
null
&&
matcher
.
group
(
9
)
!=
null
)
{
builder
.
withAuthentication
(
matcher
.
group
(
8
),
matcher
.
group
(
9
));
}
else
logger
.
log
(
Level
.
INFO
,
"no authentication given, creating anonymous instance"
);
return
builder
.
build
();
}
protected
GithubTicketSystem
(
String
acceptHeader
,
String
baseUrl
)
{
this
(
acceptHeader
,
baseUrl
,
null
,
null
);
}
protected
GithubTicketSystem
(
String
acceptHeader
,
String
baseUrl
,
String
username
,
String
apiKey
)
{
super
();
this
.
acceptHeader
=
acceptHeader
;
this
.
apiKey
=
apiKey
;
this
.
baseUrl
=
baseUrl
;
this
.
username
=
username
;
}
/**
* starts builder process for new github ticket
*/
@Override
public
GithubTicketBuilder
createTicket
()
{
return
new
GithubTicketBuilder
(
this
);
}
@Override
public
GithubFilter
find
()
{
return
new
GithubFilter
(
this
);
}
@Override
public
GithubTicket
getTicketById
(
String
id
)
{
logger
.
log
(
Level
.
FINER
,
"redirecting request to find method"
);
List
<
GithubTicket
>
ret
=
this
.
find
()
.
withId
(
id
)
.
get
();
if
(
ret
==
null
)
return
null
;
else
if
(
ret
.
size
()
!=
1
)
{
if
(
getConfigTrue
(
ConfigurationOptions
.
RETURN_NULL_ON_ERROR
))
return
null
;
else
throw
new
UnifiedticketingException
(
"more or less than 1 dedicated ticket found"
);
}
else
return
ret
.
get
(
0
);
}
@Override
public
boolean
hasAssigneeSupport
()
{
return
true
;
}
@Override
public
boolean
hasDefaultPagination
()
{
return
true
;
}
@Override
public
boolean
hasLabelSupport
()
{
return
true
;
}
@Override
public
boolean
hasPaginationSupport
()
{
return
true
;
}
@Override
public
boolean
hasReturnNullOnErrorSupport
()
{
return
true
;
}
}
src/main/java/de/hftstuttgart/unifiedticketing/systems/github/GithubTicketSystemBuilder.java
0 → 100644
View file @
25207b24
package
de.hftstuttgart.unifiedticketing.systems.github
;
import
de.hftstuttgart.unifiedticketing.core.Logging
;
import
de.hftstuttgart.unifiedticketing.core.TicketSystemBuilder
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
public
class
GithubTicketSystemBuilder
extends
TicketSystemBuilder
<
GithubTicketSystemBuilder
,
GithubTicketSystem
>
{
private
static
final
Logger
logger
=
Logging
.
getLogger
(
GithubTicketSystemBuilder
.
class
.
getName
());
protected
String
acceptHeader
;
protected
String
apiKey
;
protected
boolean
https
;
protected
String
owner
;
protected
String
repo
;
protected
String
username
;
/**
* starts builder process for a {@link GithubTicketSystem} instance
*/
public
GithubTicketSystemBuilder
()
{
super
();
acceptHeader
=
"application/vnd.github.v3+json"
;
https
=
true
;
logger
.
log
(
Level
.
FINEST
,
"Builder for Github System instance started"
);
}
public
GithubTicketSystemBuilder
withAuthentication
(
String
username
,
String
apiKey
)
{
this
.
username
=
username
;
this
.
apiKey
=
apiKey
;
logger
.
log
(
Level
.
FINEST
,
"set authentication values"
);
return
this
;
}
public
GithubTicketSystemBuilder
withHttp
()
{
this
.
https
=
false
;
logger
.
log
(
Level
.
FINEST
,
"set http"
);
return
this
;
}
public
GithubTicketSystemBuilder
withHttps
()
{
this
.
https
=
true
;
logger
.
log
(
Level
.
FINEST
,
"set https"
);
return
this
;
}
public
GithubTicketSystemBuilder
withOwner
(
String
owner
)
{
this
.
owner
=
owner
;
logger
.
log
(
Level
.
FINEST
,
String
.
format
(
"set owner to %s"
,
this
.
owner
));
return
this
;
}
public
GithubTicketSystemBuilder
withRepo
(
String
repo
)
{
this
.
repo
=
repo
;
logger
.
log
(
Level
.
FINEST
,
String
.
format
(
"set repo to %s"
,
this
.
repo
));
return
this
;
}
@Override
public
GithubTicketSystem
build
()
{
return
new
GithubTicketSystem
(
acceptHeader
,
String
.
format
(
"%s://%s/repos/%s/%s/issues"
,
(
https
)
?
"https"
:
"http"
,
baseUrl
,
owner
,
repo
),
username
,
apiKey
);
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment