Skip to content

Commit

Permalink
#959: Ensure multi-line string are enclosed in blockquotes
Browse files Browse the repository at this point in the history
The Github Cloud API now returns an error about the input message being
malformed, seemingly due to a change in how new lines in messages are
being handled. As the use of blockquotes around multi-line messages
appears to continue to work, the analysis messages are being wrapped in
blockquotes rather than double-quotes where they contain newline
characters. This requires an interim measure of cloning the InputObject
class from the nodes library to alter the String comparison and wrapping
since the library is no longer maintained.
  • Loading branch information
mc1arke committed Sep 6, 2024
1 parent 92f74f7 commit 6d32805
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2022 Michael Clarke
* Copyright (C) 2019-2024 Michael Clarke
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
Expand All @@ -20,7 +20,6 @@

import io.aexp.nodes.graphql.GraphQLRequestEntity;
import io.aexp.nodes.graphql.GraphQLTemplate;
import io.aexp.nodes.graphql.InputObject;
import org.sonar.api.ce.ComputeEngineSide;
import org.sonar.api.server.ServerSide;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020-2023 Michael Clarke
* Copyright (C) 2020-2024 Michael Clarke
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
Expand Down Expand Up @@ -29,7 +29,6 @@
import io.aexp.nodes.graphql.GraphQLRequestEntity;
import io.aexp.nodes.graphql.GraphQLResponseEntity;
import io.aexp.nodes.graphql.GraphQLTemplate;
import io.aexp.nodes.graphql.InputObject;
import io.aexp.nodes.graphql.internal.Error;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -90,6 +89,7 @@ public String createCheckRun(CheckRunDetails checkRunDetails, boolean postSummar
inputObjectArguments.put("completedAt", DATE_TIME_FORMATTER.format(checkRunDetails.getEndTime()));
inputObjectArguments.put("externalId", checkRunDetails.getExternalId());
inputObjectArguments.put("output", checkRunOutputContentBuilder.build());
inputObjectArguments.put("headSha", checkRunDetails.getCommitId());

InputObject.Builder<Object> repositoryInputObjectBuilder = graphqlProvider.createInputObject();
inputObjectArguments.forEach(repositoryInputObjectBuilder::put);
Expand All @@ -101,9 +101,7 @@ public String createCheckRun(CheckRunDetails checkRunDetails, boolean postSummar
.url(graphqlUrl)
.headers(headers)
.request(CreateCheckRun.class)
.arguments(new Arguments("createCheckRun", new Argument<>(INPUT, repositoryInputObjectBuilder
.put("headSha", checkRunDetails.getCommitId())
.build())))
.arguments(new Arguments("createCheckRun", new Argument<>(INPUT, repositoryInputObjectBuilder.build())))
.requestMethod(GraphQLTemplate.GraphQLMethod.MUTATE);

GraphQLRequestEntity graphQLRequestEntity = graphQLRequestEntityBuilder.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@

import io.aexp.nodes.graphql.GraphQLRequestEntity;
import io.aexp.nodes.graphql.GraphQLTemplate;
import io.aexp.nodes.graphql.InputObject;

public interface GraphqlProvider {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Copyright (c) 2018-2024 American Express Travel Related Services Company, Inc, Michael Clarke
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.github.mc1arke.sonarqube.plugin.almclient.github.v4;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public final class InputObject<T> {
private final Map<String, T> map;

InputObject(Builder<T> builder) {
this.map = builder.map;
}

String getMessage() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("{");
for (Map.Entry<String, T> entry : map.entrySet()) {
if (stringBuilder.length() != 1) stringBuilder.append(",");
stringBuilder.append(formatGraphQLParameter(entry.getKey(), entry.getValue()));
}
stringBuilder.append("}");
return stringBuilder.toString();
}

@Override
public String toString() {
return getMessage();
}

public Map<String, T> getMap() {
return this.map;
}

public static class Builder<T> {

private final Map<String, T> map = new HashMap<>();

public Builder<T> put(String key, T value) {
this.map.put(key, value);
return this;
}

public InputObject<T> build() {
return new InputObject<>(this);
}
}


private static <T> String formatGraphQLParameter(String key, T value) {
StringBuilder stringBuilder = new StringBuilder();
Pattern pattern = Pattern.compile("^\\$");
Matcher matcher = pattern.matcher("" + value);
if (value instanceof String && ((String) value).contains("\n")) {
stringBuilder.append(key).append(":\"\"\"").append(value).append("\"\"\"");
} else if (value instanceof String && !matcher.find()) {
stringBuilder.append(key).append(":\"").append(value).append("\"");
} else if (value instanceof List) {
stringBuilder.append(key).append(":").append(formatGraphQLArgumentList((List<?>)value));
} else if (value instanceof com.github.mc1arke.sonarqube.plugin.almclient.github.v4.InputObject) {
stringBuilder.append(key).append(":").append(((com.github.mc1arke.sonarqube.plugin.almclient.github.v4.InputObject<?>)value).getMessage());
} else {
stringBuilder.append(key).append(":").append(value);
}

return stringBuilder.toString();
}

private static String formatGraphQLArgumentList(List<?> values) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("[");
Pattern p = Pattern.compile("^\\$");
for (Object value: values) {
if (stringBuilder.length() != 1) stringBuilder.append(",");
Matcher m = p.matcher("" + value);
if (value instanceof String && !m.find()) {
stringBuilder.append("\"").append(value).append("\"");
} else if (value instanceof com.github.mc1arke.sonarqube.plugin.almclient.github.v4.InputObject) {
stringBuilder.append(((InputObject<?>) value).getMessage());
} else {
stringBuilder.append(value);
}
}
stringBuilder.append("]");
return stringBuilder.toString();
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020-2022 Michael Clarke
* Copyright (C) 2020-2024 Michael Clarke
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
Expand Down Expand Up @@ -31,7 +31,6 @@
import io.aexp.nodes.graphql.GraphQLRequestEntity;
import io.aexp.nodes.graphql.GraphQLResponseEntity;
import io.aexp.nodes.graphql.GraphQLTemplate;
import io.aexp.nodes.graphql.InputObject;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.sonar.api.issue.Issue;
Expand Down

0 comments on commit 6d32805

Please sign in to comment.