Skip to content

Commit a21d7b6

Browse files
authored
Merge pull request #1125 from salesforce/W-14174147
Add a debug flag that enables wire logging for git http requests
2 parents 53f6340 + 4fa8723 commit a21d7b6

File tree

6 files changed

+191
-28
lines changed

6 files changed

+191
-28
lines changed

dockerfile-image-update/pom.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,16 @@
144144
<artifactId>bucket4j-core</artifactId>
145145
<version>8.1.1</version>
146146
</dependency>
147+
<dependency>
148+
<groupId>com.squareup.okhttp3</groupId>
149+
<artifactId>okhttp</artifactId>
150+
<version>4.9.1</version>
151+
</dependency>
152+
<dependency>
153+
<groupId>com.squareup.okhttp3</groupId>
154+
<artifactId>logging-interceptor</artifactId>
155+
<version>4.9.1</version>
156+
</dependency>
147157
</dependencies>
148158

149159
<build>

dockerfile-image-update/src/main/java/com/salesforce/dockerfileimageupdate/CommandLine.java

Lines changed: 77 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,29 @@
1010

1111
import com.google.common.reflect.ClassPath;
1212
import com.salesforce.dockerfileimageupdate.subcommands.ExecutableWithNamespace;
13-
import com.salesforce.dockerfileimageupdate.utils.Constants;
1413
import com.salesforce.dockerfileimageupdate.utils.DockerfileGitHubUtil;
1514
import com.salesforce.dockerfileimageupdate.utils.GitHubUtil;
1615
import net.sourceforge.argparse4j.ArgumentParsers;
1716
import net.sourceforge.argparse4j.impl.Arguments;
1817
import net.sourceforge.argparse4j.inf.*;
18+
import okhttp3.OkHttpClient;
19+
import okhttp3.logging.HttpLoggingInterceptor;
20+
1921
import org.kohsuke.github.GitHub;
2022
import org.kohsuke.github.GitHubBuilder;
23+
import org.kohsuke.github.extras.okhttp3.OkHttpGitHubConnector;
2124
import org.slf4j.Logger;
2225
import org.slf4j.LoggerFactory;
2326

2427
import java.io.IOException;
2528
import java.util.Comparator;
29+
import java.util.Objects;
30+
import java.util.Optional;
2631
import java.util.Set;
2732
import java.util.TreeSet;
33+
import java.util.function.Consumer;
34+
import java.util.function.Function;
35+
import java.util.function.Supplier;
2836
import java.util.stream.Collectors;
2937
import static com.salesforce.dockerfileimageupdate.utils.Constants.*;
3038

@@ -45,8 +53,8 @@ public static void main(String[] args)
4553
Namespace ns = handleArguments(parser, args);
4654
if (ns == null)
4755
System.exit(1);
48-
Class<?> runClass = loadCommand(allClasses, ns.get(Constants.COMMAND));
49-
DockerfileGitHubUtil dockerfileGitHubUtil = initializeDockerfileGithubUtil(ns.get(Constants.GIT_API));
56+
Class<?> runClass = loadCommand(allClasses, ns.get(COMMAND));
57+
DockerfileGitHubUtil dockerfileGitHubUtil = initializeDockerfileGithubUtil(gitApiUrl(ns), gitApiToken(), ns.getBoolean(DEBUG));
5058

5159
/* Execute given command. */
5260
((ExecutableWithNamespace)runClass.getDeclaredConstructor().newInstance()).execute(ns, dockerfileGitHubUtil);
@@ -57,30 +65,30 @@ static ArgumentParser getArgumentParser() {
5765
ArgumentParsers.newFor("dockerfile-image-update").addHelp(true).build()
5866
.description("Image Updates through Pull Request Automator");
5967

60-
parser.addArgument("-l", "--" + Constants.GIT_API_SEARCH_LIMIT)
68+
parser.addArgument("-l", "--" + GIT_API_SEARCH_LIMIT)
6169
.type(Integer.class)
6270
.setDefault(1000)
6371
.help("limit the search results for github api (default: 1000)");
64-
parser.addArgument("-o", "--" + Constants.GIT_ORG)
72+
parser.addArgument("-o", "--" + GIT_ORG)
6573
.help("search within specific organization (default: all of github)");
6674
/* Currently, because of argument passing reasons, you can only specify one branch. */
67-
parser.addArgument("-b", "--" + Constants.GIT_BRANCH)
75+
parser.addArgument("-b", "--" + GIT_BRANCH)
6876
.help("make pull requests for given branch name (default: main)");
69-
parser.addArgument("-g", "--" + Constants.GIT_API)
77+
parser.addArgument("-g", "--" + GIT_API)
7078
.help("link to github api; overrides environment variable");
7179
parser.addArgument("-f", "--auto-merge").action(Arguments.storeTrue())
7280
.help("NOT IMPLEMENTED / set to automatically merge pull requests if available");
7381
parser.addArgument("-m")
7482
.help("message to provide for pull requests");
7583
parser.addArgument("-c")
7684
.help("additional commit message for the commits in pull requests");
77-
parser.addArgument("-e", "--" + Constants.GIT_REPO_EXCLUDES)
85+
parser.addArgument("-e", "--" + GIT_REPO_EXCLUDES)
7886
.help("regex of repository names to exclude from pull request generation");
7987
parser.addArgument("-B")
8088
.help("additional body text to include in pull requests");
81-
parser.addArgument("-s", "--" + Constants.SKIP_PR_CREATION)
89+
parser.addArgument("-s", "--" + SKIP_PR_CREATION)
8290
.type(Boolean.class)
83-
.setDefault(false)
91+
.setDefault(false) //To prevent null from being returned by the argument
8492
.help("Only update image tag store. Skip creating PRs");
8593
parser.addArgument("-x")
8694
.help("comment snippet mentioned in line just before 'FROM' instruction(Dockerfile)" +
@@ -95,14 +103,19 @@ static ArgumentParser getArgumentParser() {
95103
.type(String.class)
96104
.required(false)
97105
.help("Use RateLimiting when sending PRs. RateLimiting is enabled only if this value is set it's disabled by default.");
106+
parser.addArgument("-d", "--" + DEBUG)
107+
.type(Boolean.class)
108+
.setDefault(false) //To prevent null from being returned by the argument
109+
.required(false)
110+
.help("Enable debug logging, including git wire logs.");
98111
return parser;
99112
}
100113

101114
/* Adding subcommands to the subcommands list.
102115
argparse4j allows commands to be truncated, so users can type the first letter (a,c,p) for commands */
103116
public static Set<ClassPath.ClassInfo> findSubcommands(ArgumentParser parser) throws IOException {
104117
Subparsers subparsers = parser.addSubparsers()
105-
.dest(Constants.COMMAND)
118+
.dest(COMMAND)
106119
.help("FEATURE")
107120
.title("subcommands")
108121
.description("Specify which feature to perform")
@@ -181,27 +194,65 @@ public static Class<?> loadCommand(Set<ClassPath.ClassInfo> allClasses, String c
181194
return runClass;
182195
}
183196

197+
public static String gitApiToken() {
198+
return gitApiToken(System::getenv, System::exit);
199+
}
200+
201+
public static String gitApiToken(final Function<String, String> envFunc, final Consumer<Integer> exitFunc) {
202+
final String token = envFunc.apply("git_api_token");
203+
if (Objects.isNull(token)) {
204+
log.error("Please provide GitHub token in environment variables.");
205+
exitFunc.accept(3);
206+
}
207+
return token;
208+
}
209+
210+
public static String gitApiUrl(final Namespace ns) throws IOException {
211+
return gitApiUrl(ns, System::getenv);
212+
}
213+
214+
public static String gitApiUrl(final Namespace ns, final Function<String, String> envFunc) throws IOException {
215+
return Optional.ofNullable(
216+
Optional.ofNullable(ns.getString(GIT_API))
217+
.orElse(envFunc.apply("git_api_url"))
218+
)
219+
.orElseThrow(() -> new IOException("No Git API URL in environment variables nor on the commmand line."));
220+
}
221+
222+
public static DockerfileGitHubUtil initializeDockerfileGithubUtil(
223+
final String gitApiUrl,
224+
final String token,
225+
final boolean debug) throws IOException
226+
{
227+
return initializeDockerfileGithubUtil(gitApiUrl, token, () -> new GitHubBuilder(), debug);
228+
}
229+
184230
/* Validate API URL and connect to the API using credentials. */
185-
public static DockerfileGitHubUtil initializeDockerfileGithubUtil(String gitApiUrl) throws IOException {
186-
if (gitApiUrl == null) {
187-
gitApiUrl = System.getenv("git_api_url");
188-
if (gitApiUrl == null) {
189-
throw new IOException("No Git API URL in environment variables.");
190-
}
191-
}
192-
String token = System.getenv("git_api_token");
193-
if (token == null) {
194-
log.error("Please provide GitHub token in environment variables.");
195-
System.exit(3);
196-
}
231+
public static DockerfileGitHubUtil initializeDockerfileGithubUtil(
232+
final String gitApiUrl,
233+
final String token,
234+
final Supplier<GitHubBuilder> builderFunc,
235+
final boolean debug) throws IOException {
197236

198-
GitHub github = new GitHubBuilder().withEndpoint(gitApiUrl)
237+
GitHub github = shouldAddWireLogger(builderFunc.get(), debug)
238+
.withEndpoint(gitApiUrl)
199239
.withOAuthToken(token)
200240
.build();
201241
github.checkApiUrlValidity();
202242

203-
GitHubUtil gitHubUtil = new GitHubUtil(github);
243+
return new DockerfileGitHubUtil(new GitHubUtil(github));
244+
}
245+
246+
public static GitHubBuilder shouldAddWireLogger(final GitHubBuilder builder, final boolean debug) {
247+
if (debug) {
248+
HttpLoggingInterceptor logger = new HttpLoggingInterceptor();
249+
logger.setLevel(HttpLoggingInterceptor.Level.HEADERS);
250+
logger.redactHeader("Authorization");
204251

205-
return new DockerfileGitHubUtil(gitHubUtil);
252+
builder.withConnector(new OkHttpGitHubConnector(new OkHttpClient.Builder()
253+
.addInterceptor(logger)
254+
.build()));
255+
}
256+
return builder;
206257
}
207258
}

dockerfile-image-update/src/main/java/com/salesforce/dockerfileimageupdate/subcommands/impl/Parent.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public void execute(final Namespace ns, DockerfileGitHubUtil dockerfileGitHubUti
5454
log.error("Could not initialize the Image tage store. Exception: ", e);
5555
}
5656

57-
if (ns.get(Constants.SKIP_PR_CREATION)) {
57+
if (ns.getBoolean(Constants.SKIP_PR_CREATION)) {
5858
log.info("Since the flag {} is set to True, the PR creation steps will "
5959
+ "be skipped.", Constants.SKIP_PR_CREATION);
6060
return;

dockerfile-image-update/src/main/java/com/salesforce/dockerfileimageupdate/utils/Constants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ private Constants() {
4141
public static final String IGNORE_IMAGE_STRING = "x";
4242
public static final String FILE_NAMES_TO_SEARCH = "filenamestosearch";
4343
public static final String RATE_LIMIT_PR_CREATION = "rate_limit_pr_creations";
44+
public static final String DEBUG = "debug";
4445
//max number of PRs to be sent (or tokens to be added) per DEFAULT_RATE_LIMIT_DURATION(per hour in this case)
4546
public static final long DEFAULT_RATE_LIMIT = 60;
4647

dockerfile-image-update/src/main/java/com/salesforce/dockerfileimageupdate/utils/DockerfileGitHubUtil.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public DockerfileGitHubUtil(GitHubUtil gitHubUtil) {
3939
this.gitHubUtil = gitHubUtil;
4040
}
4141

42-
protected GitHubUtil getGitHubUtil() { return gitHubUtil; }
42+
public GitHubUtil getGitHubUtil() { return gitHubUtil; }
4343

4444
/**
4545
* Return an existing fork in the current user's org or create one if it does not exist

dockerfile-image-update/src/test/java/com/salesforce/dockerfileimageupdate/CommandLineTest.java

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,28 @@
99
package com.salesforce.dockerfileimageupdate;
1010

1111
import com.google.common.reflect.ClassPath;
12+
import com.salesforce.dockerfileimageupdate.utils.DockerfileGitHubUtil;
13+
14+
import org.kohsuke.github.GitHub;
15+
import org.kohsuke.github.GitHubBuilder;
16+
import org.kohsuke.github.extras.okhttp3.OkHttpGitHubConnector;
17+
import org.mockito.Mockito;
1218
import org.testng.annotations.Test;
1319

20+
import net.sourceforge.argparse4j.inf.Namespace;
21+
22+
import java.io.IOException;
1423
import java.util.Arrays;
1524
import java.util.List;
1625
import java.util.Set;
26+
import java.util.function.Consumer;
27+
import java.util.function.Function;
1728

29+
import static com.salesforce.dockerfileimageupdate.utils.Constants.GIT_API;
1830
import static org.assertj.core.api.Assertions.assertThat;
31+
import static org.mockito.Mockito.never;
1932
import static org.testng.Assert.assertEquals;
33+
import static org.testng.Assert.assertSame;
2034

2135
/**
2236
* Created by afalko on 10/25/17.
@@ -31,4 +45,91 @@ public void testLoadSubcommands() throws Exception {
3145
classInfo -> assertThat(expectedSubCommands).contains(classInfo.getSimpleName())
3246
);
3347
}
48+
49+
@Test
50+
public void testShouldAddWireLoggerDisabled() {
51+
GitHubBuilder builder = Mockito.spy(new GitHubBuilder());
52+
CommandLine.shouldAddWireLogger(builder, false);
53+
54+
Mockito.verify(builder, never()).withConnector(Mockito.any(OkHttpGitHubConnector.class));
55+
}
56+
57+
@Test
58+
public void testShouldAddWireLoggerEnabled() {
59+
GitHubBuilder builder = Mockito.spy(new GitHubBuilder());
60+
CommandLine.shouldAddWireLogger(builder, true);
61+
62+
Mockito.verify(builder).withConnector(Mockito.any(OkHttpGitHubConnector.class));
63+
}
64+
65+
@Test
66+
public void testInitializeDockerfileGithubUtil() throws IOException {
67+
GitHubBuilder builder = Mockito.spy(new GitHubBuilder());
68+
GitHub github = Mockito.mock(GitHub.class);
69+
70+
Mockito.doReturn(github).when(builder).build();
71+
72+
DockerfileGitHubUtil retval = CommandLine.initializeDockerfileGithubUtil("someUrl", "someToken", () -> builder, true);
73+
74+
Mockito.verify(builder).withEndpoint(Mockito.eq("someUrl"));
75+
Mockito.verify(builder).withOAuthToken(Mockito.eq("someToken"));
76+
Mockito.verify(builder).withConnector(Mockito.any(OkHttpGitHubConnector.class));
77+
Mockito.verify(github).checkApiUrlValidity();
78+
assertSame(retval.getGitHubUtil().getGithub(), github);
79+
}
80+
81+
@Test
82+
public void testGitApiUrlNonNullNamespace() throws IOException {
83+
Namespace ns = Mockito.mock(Namespace.class);
84+
Mockito.doReturn("someUrl").when(ns).getString(GIT_API);
85+
86+
String retval = CommandLine.gitApiUrl(ns, x -> null);
87+
assertEquals(retval, "someUrl");
88+
}
89+
90+
@Test
91+
public void testGitApiUrlNullNamespace() throws IOException {
92+
Namespace ns = Mockito.mock(Namespace.class);
93+
Mockito.doReturn(null).when(ns).getString(GIT_API);
94+
95+
String retval = CommandLine.gitApiUrl(ns, x -> "anotherUrl");
96+
assertEquals(retval, "anotherUrl");
97+
}
98+
99+
@Test(expectedExceptions = { IOException.class } )
100+
public void testGitApiUrlNamespaceAndEnvNull() throws IOException {
101+
Namespace ns = Mockito.mock(Namespace.class);
102+
Mockito.doReturn(null).when(ns).getString(GIT_API);
103+
104+
String retval = CommandLine.gitApiUrl(ns, x -> null);
105+
assertEquals(retval, "anotherUrl");
106+
}
107+
108+
@Test
109+
public void gitApiTokenAvailable() {
110+
Function<String, String> envFunc = x -> {
111+
assertEquals(x, "git_api_token");
112+
return "token";
113+
};
114+
115+
Consumer<Integer> exitFunc = new Consumer<Integer>() {
116+
@Override
117+
public void accept(Integer t) {}
118+
};
119+
120+
final String retval = CommandLine.gitApiToken(envFunc, exitFunc);
121+
assertEquals(retval, "token");
122+
}
123+
124+
@Test
125+
public void gitApiTokenNull() {
126+
Function<String, String> envFunc = x -> {
127+
assertEquals(x, "git_api_token");
128+
return null;
129+
};
130+
131+
Consumer<Integer> exitFunc = x -> assertEquals(x, 3);
132+
133+
CommandLine.gitApiToken(envFunc, exitFunc);
134+
}
34135
}

0 commit comments

Comments
 (0)