2121package com .spotify .github .v3 .repos ;
2222
2323import com .fasterxml .jackson .annotation .JsonProperty ;
24+ import com .fasterxml .jackson .core .JsonParser ;
25+ import com .fasterxml .jackson .databind .DeserializationContext ;
26+ import com .fasterxml .jackson .databind .JsonDeserializer ;
27+ import com .fasterxml .jackson .databind .JsonNode ;
2428import com .fasterxml .jackson .databind .annotation .JsonDeserialize ;
2529import com .fasterxml .jackson .databind .annotation .JsonSerialize ;
2630import com .spotify .github .GithubStyle ;
31+ import com .spotify .github .v3 .git .ImmutableShaLink ;
2732import com .spotify .github .v3 .git .ShaLink ;
33+ import java .io .IOException ;
2834import java .net .URI ;
35+ import java .net .URISyntaxException ;
36+ import java .net .URLEncoder ;
37+ import java .nio .charset .StandardCharsets ;
2938import java .util .Optional ;
3039import javax .annotation .Nullable ;
3140import org .immutables .value .Value ;
3443@ Value .Immutable
3544@ GithubStyle
3645@ JsonSerialize (as = ImmutableBranch .class )
37- @ JsonDeserialize (as = ImmutableBranch .class )
46+ @ JsonDeserialize (as = ImmutableBranch .class , using = BranchDeserializer . class )
3847public interface Branch {
3948
4049 /** Branch name */
@@ -52,3 +61,46 @@ public interface Branch {
5261 /** Branch protection API URL */
5362 Optional <URI > protectionUrl ();
5463}
64+
65+ class BranchDeserializer extends JsonDeserializer <ImmutableBranch > {
66+
67+ private URI fixInvalidGithubUrl (final String invalidUrl ) throws IOException {
68+ // There's a bug in github where it gives you back non-url-encoded characters
69+ // in the protection_url field. For example if your branch has a single "%" in its name.
70+ // As of this writing, the protection URL looks something like this
71+ // https://github-server.tld/api/v3/repos/owner/repo-name/branches/branch-name/protection
72+ final String [] schemaAndPath = invalidUrl .split ("//" );
73+ String [] pathParts = schemaAndPath [1 ].split ("/" );
74+ for (int i = 0 ; i < pathParts .length ; i ++) {
75+ pathParts [i ] = URLEncoder .encode (pathParts [i ], StandardCharsets .UTF_8 );
76+ }
77+ String fixedUrlString = schemaAndPath [0 ] + "//" + String .join ("/" , pathParts );
78+ return URI .create (fixedUrlString );
79+ }
80+
81+ @ Override
82+ public ImmutableBranch deserialize (final JsonParser jsonParser , final DeserializationContext deserializationContext )
83+ throws IOException {
84+ JsonNode node = jsonParser .getCodec ().readTree (jsonParser );
85+ URI protectionUrl ;
86+ var immutableBranchBuilder = ImmutableBranch .builder ();
87+ if (node .has ("protected" )) {
88+ immutableBranchBuilder .isProtected (node .get ("protected" ).asBoolean ());
89+ String protectionUrlString = node .get ("protection_url" ).asText ();
90+ try {
91+ protectionUrl = new URI (protectionUrlString );
92+ } catch (URISyntaxException e ) {
93+ protectionUrl = fixInvalidGithubUrl (protectionUrlString );
94+ }
95+ immutableBranchBuilder .protectionUrl (protectionUrl );
96+ }
97+ ImmutableShaLink shaLink = ImmutableShaLink .builder ()
98+ .sha (node .get ("commit" ).get ("sha" ).asText ())
99+ .url (URI .create (node .at ("/commit/url" ).asText ()))
100+ .build ();
101+ return immutableBranchBuilder
102+ .name (node .get ("name" ).textValue ())
103+ .commit (shaLink )
104+ .build ();
105+ }
106+ }
0 commit comments