Skip to content

Commit a485c56

Browse files
committed
Add LabelGraphQLScript
1 parent ccebbbe commit a485c56

File tree

1 file changed

+221
-0
lines changed

1 file changed

+221
-0
lines changed

gitlab4j-test/LabelGraphQLScript.java

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
///usr/bin/env jbang "$0" "$@" ; exit $?
2+
3+
//DEPS info.picocli:picocli:4.6.3
4+
//DEPS https://github.com/unblu/gitlab-workitem-graphql-client/commit/f36726404b311bab0d5df41eff8072950fb9f97c
5+
//DEPS io.smallrye:smallrye-graphql-client-implementation-vertx:2.11.0
6+
//DEPS org.jboss.logmanager:jboss-logmanager:3.1.1.Final
7+
//JAVA 17
8+
//RUNTIME_OPTIONS -Djava.util.logging.manager=org.jboss.logmanager.LogManager
9+
//FILES logging.properties
10+
11+
import java.io.FileInputStream;
12+
import java.io.IOException;
13+
import java.io.InputStream;
14+
import java.nio.file.Files;
15+
import java.nio.file.Path;
16+
import java.nio.file.Paths;
17+
import java.util.ArrayList;
18+
import java.util.Arrays;
19+
import java.util.List;
20+
import java.util.Properties;
21+
import java.util.concurrent.Callable;
22+
import java.util.function.Function;
23+
import java.util.stream.Collectors;
24+
25+
import graphql.gitlab.api.WorkitemClientApi;
26+
import graphql.gitlab.model.Group;
27+
import graphql.gitlab.model.Label;
28+
import graphql.gitlab.model.LabelConnection;
29+
import graphql.gitlab.model.Project;
30+
import io.smallrye.graphql.client.typesafe.api.TypesafeGraphQLClientBuilder;
31+
import picocli.CommandLine;
32+
import picocli.CommandLine.Command;
33+
import picocli.CommandLine.Option;
34+
import picocli.CommandLine.Parameters;
35+
36+
@Command(name = "LabelGraphQLScript", mixinStandardHelpOptions = true, version = "LabelGraphQLScript 0.1", description = "Tests with GraphQL")
37+
public class LabelGraphQLScript implements Callable<Integer> {
38+
39+
private static final String CONFIG_FILE_INITIAL_CONTENT = """
40+
GITLAB_URL=https://gitlab.com
41+
GITLAB_AUTH_VALUE=
42+
""";
43+
44+
@Parameters(index = "0", description = "action to execute", defaultValue = "LIST_LABELS")
45+
private Action action;
46+
47+
@Option(names = { "-p", "--project" }, description = "project")
48+
private String project;
49+
50+
@Option(names = { "-g", "--group" }, description = "group")
51+
private String group;
52+
53+
@Option(names = { "-a", "--includeAncestorGroups" }, description = "include ancestor groups when fetching labels")
54+
private boolean includeAncestorGroups;
55+
56+
@Option(names = { "-c", "--config" }, description = "configuration file location")
57+
String configFile;
58+
59+
private static enum Action {
60+
LIST_LABELS
61+
}
62+
63+
@Override
64+
public Integer call() throws Exception {
65+
Path file;
66+
if (configFile != null) {
67+
file = Paths.get(configFile);
68+
} else {
69+
file = configFile(Paths.get(""));
70+
}
71+
System.out.println("Reading config: " + file.toAbsolutePath());
72+
final Properties prop = configProperties(file);
73+
final String gitLabUrl = readProperty(prop, "GITLAB_URL", "https://gitlab.com");
74+
final String gitLabAuthValue = readProperty(prop, "GITLAB_AUTH_VALUE");
75+
76+
WorkitemClientApi api = createGraphQLWorkitemClientApi(gitLabUrl, gitLabAuthValue);
77+
switch (action) {
78+
case LIST_LABELS:
79+
listLabels(api);
80+
break;
81+
default:
82+
throw new IllegalArgumentException("Unexpected value: " + action);
83+
}
84+
85+
return 0;
86+
}
87+
88+
private void listLabels(WorkitemClientApi api) {
89+
ensureNamespace();
90+
List<Label> labels;
91+
if (project != null) {
92+
System.out.println("Reading gitlab labels and metadata from project " + project);
93+
Function<String, Project> apiCall = (from) -> api.project(project, includeAncestorGroups, from);
94+
Function<Project, LabelConnection> lGetter = Project::getLabels;
95+
labels = getLabels(apiCall, lGetter);
96+
} else if (group != null) {
97+
System.out.println("Reading gitlab labels and metadata from group " + group);
98+
Function<String, Group> apiCall = (from) -> api.group(group, includeAncestorGroups, from);
99+
Function<Group, LabelConnection> lGetter = Group::getLabels;
100+
labels = getLabels(apiCall, lGetter);
101+
} else {
102+
throw new IllegalStateException("Unexpected");
103+
}
104+
105+
for (Label label : labels) {
106+
System.out.println(label.getId() + " " + label.getTitle());
107+
}
108+
}
109+
110+
private static <R> ArrayList<Label> getLabels(Function<String, R> apiCall, Function<R, LabelConnection> labelsGetter) {
111+
ArrayList<Label> result = new ArrayList<Label>();
112+
R response = apiCall.apply(null);
113+
LabelConnection labels = labelsGetter.apply(response);
114+
result.addAll(labels.getNodes());
115+
while (labels.getPageInfo()
116+
.getHasNextPage()) {
117+
response = apiCall.apply(labels.getPageInfo()
118+
.getEndCursor());
119+
labels = labelsGetter.apply(response);
120+
result.addAll(labels.getNodes());
121+
}
122+
return result;
123+
}
124+
125+
private void ensureNamespace() {
126+
ensureOneExists(Holder.of(project, "project"), Holder.of(group, "group"));
127+
}
128+
129+
static WorkitemClientApi createGraphQLWorkitemClientApi(String gitLabUrl, String gitlabToken) {
130+
WorkitemClientApi gqlApi = TypesafeGraphQLClientBuilder.newBuilder()
131+
.endpoint(gitLabUrl + "/api/graphql")
132+
.header("Authorization", "Bearer " + gitlabToken)
133+
.allowUnexpectedResponseFields(true)
134+
.build(WorkitemClientApi.class);
135+
return gqlApi;
136+
}
137+
138+
private void ensureExists(Object value, String optionName) {
139+
if (value == null) {
140+
throw new IllegalStateException("--" + optionName + " must be set");
141+
}
142+
}
143+
144+
private void ensureOneExists(Holder... values) {
145+
List<Holder> list = Arrays.stream(values)
146+
.filter(h -> h.value != null)
147+
.toList();
148+
if (list.isEmpty()) {
149+
String names = Arrays.stream(values)
150+
.map(h -> "--" + h.name)
151+
.collect(Collectors.joining(", "));
152+
throw new IllegalStateException("One of " + names + " must be set");
153+
}
154+
if (list.size() > 1) {
155+
String names = list.stream()
156+
.map(h -> "--" + h.name)
157+
.collect(Collectors.joining(", "));
158+
throw new IllegalStateException("Not all of " + names + " can be set at the same time");
159+
160+
}
161+
}
162+
163+
public static Properties configProperties(final Path configFile) {
164+
try (InputStream is = new FileInputStream(configFile.toFile())) {
165+
final Properties properties = new Properties();
166+
properties.load(is);
167+
return properties;
168+
} catch (final IOException e) {
169+
throw new IllegalStateException("Can not read config file", e);
170+
}
171+
}
172+
173+
public static Path configFile(final Path root) {
174+
final Path configFile = root.toAbsolutePath()
175+
.resolve("gitlab-config.properties");
176+
if (!Files.isRegularFile(configFile)) {
177+
try {
178+
Files.writeString(configFile, CONFIG_FILE_INITIAL_CONTENT);
179+
throw new IllegalStateException(String.format("Configuration file '%s' does not exist. An empty configuration file was created", configFile.toAbsolutePath()));
180+
} catch (final IOException e) {
181+
throw new IllegalStateException("Can not write initial config file", e);
182+
}
183+
}
184+
return configFile;
185+
}
186+
187+
public static String readProperty(final Properties p, final String key) {
188+
if (!p.containsKey(key)) {
189+
throw new IllegalStateException(String.format("Configuration file does not contains key '%s'", key));
190+
}
191+
final String value = p.getProperty(key);
192+
if (value == null || value.isBlank()) {
193+
throw new IllegalStateException(String.format("Key '%s' is not defined in configuration file", key));
194+
}
195+
return value;
196+
}
197+
198+
public static String readProperty(final Properties p, final String key, final String defaultValue) {
199+
return p.getProperty(key, defaultValue);
200+
}
201+
202+
public static void main(final String... args) {
203+
final int exitCode = new CommandLine(new LabelGraphQLScript()).execute(args);
204+
System.exit(exitCode);
205+
}
206+
207+
public static class Holder {
208+
private Object value;
209+
private String name;
210+
211+
public Holder(Object value, String name) {
212+
super();
213+
this.value = value;
214+
this.name = name;
215+
}
216+
217+
public static Holder of(Object value, String name) {
218+
return new Holder(value, name);
219+
}
220+
}
221+
}

0 commit comments

Comments
 (0)