• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ethlo / zally-maven-plugin / 47

pending completion
47

Pull #9

travis-ci-com

web-flow
Merge d242a4eb1 into 8c4830a27
Pull Request #9: Upgrade to latest Zally libraries.

171 of 531 relevant lines covered (32.2%)

0.32 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

30.56
/src/main/java/com/ethlo/zally/ZallyRunner.java
1
package com.ethlo.zally;/*-
2
 * #%L
3
 * zally-maven-plugin
4
 * %%
5
 * Copyright (C) 2021 Morten Haraldsen (ethlo)
6
 * %%
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *      http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 * #L%
19
 */
20

21
import java.io.IOException;
22
import java.lang.reflect.Constructor;
23
import java.lang.reflect.InvocationTargetException;
24
import java.lang.reflect.Method;
25
import java.nio.file.Files;
26
import java.nio.file.Paths;
27
import java.util.ArrayList;
28
import java.util.Collections;
29
import java.util.LinkedHashMap;
30
import java.util.LinkedList;
31
import java.util.List;
32
import java.util.Map;
33
import java.util.Set;
34
import java.util.stream.Collectors;
35

36
import org.apache.maven.plugin.logging.Log;
37
import org.jetbrains.annotations.NotNull;
38
import org.zalando.zally.core.CheckDetails;
39
import org.zalando.zally.core.DefaultContext;
40
import org.zalando.zally.core.JsonPointerLocator;
41
import org.zalando.zally.core.Result;
42
import org.zalando.zally.core.RuleDetails;
43
import org.zalando.zally.rule.api.Check;
44
import org.zalando.zally.rule.api.Context;
45
import org.zalando.zally.rule.api.Rule;
46
import org.zalando.zally.rule.api.RuleSet;
47
import org.zalando.zally.rule.api.Violation;
48

49
import com.typesafe.config.Config;
50
import com.typesafe.config.ConfigFactory;
51
import io.github.classgraph.ClassGraph;
52
import io.github.classgraph.ClassInfo;
53
import io.github.classgraph.ClassInfoList;
54
import io.github.classgraph.ScanResult;
55
import io.swagger.v3.oas.models.OpenAPI;
56

57
public class ZallyRunner
58
{
59
    private final List<RuleDetails> rules;
60

61
    private final Log logger;
62

63
    public ZallyRunner(final Config ruleConfigs, final Log logger)
64
    {
1✔
65
        this.rules = new LinkedList<>();
1✔
66
        this.logger = logger;
1✔
67
        final List<Class<?>> ruleClasses = loadRuleClasses();
1✔
68
        for (Class<?> ruleClass : ruleClasses)
1✔
69
        {
70
            final String simpleName = ruleClass.getSimpleName();
1✔
71
            logger.debug("Loading rule " + simpleName);
1✔
72
            final Object instance = createRuleInstance(ruleClass, ruleConfigs);
1✔
73
            final Rule ruleAnnotation = ruleClass.getAnnotation(Rule.class);
1✔
74
            this.rules.add(new RuleDetails((RuleSet) createInstance(ruleAnnotation.ruleSet()), ruleAnnotation, instance));
1✔
75
        }
1✔
76
    }
1✔
77

78
    public Map<CheckDetails, List<Result>> validate(String url, final Set<String> skipped) throws IOException
79
    {
80
        final OpenAPI openApi = new OpenApiParser().parseInlined(url);
×
81
        final Context context = new DefaultContext("", openApi, null);
×
82

83
        final Map<CheckDetails, List<Result>> returnValue = new LinkedHashMap<>();
×
84
        for (RuleDetails ruleDetails : rules)
×
85
        {
86
            if (!skipped.contains(ruleDetails.getInstance().getClass().getSimpleName()))
×
87
            {
88
                final Object instance = ruleDetails.getInstance();
×
89
                for (Method method : instance.getClass().getDeclaredMethods())
×
90
                {
91
                    final Check checkAnnotation = method.getAnnotation(Check.class);
×
92

93
                    if (checkAnnotation != null && method.getParameterTypes().length == 1 && method.getParameterTypes()[0] == Context.class)
×
94
                    {
95
                        final List<Result> violationList = new ArrayList<>();
×
96
                        final CheckDetails checkDetails = performCheck(context, violationList, instance, ruleDetails.getRule(), ruleDetails.getRuleSet(), method, checkAnnotation, url);
×
97
                        returnValue.put(checkDetails, violationList);
×
98
                    }
99
                }
100
            }
101
        }
×
102

103
        return returnValue;
×
104
    }
105

106
    @NotNull
107
    private CheckDetails performCheck(Context context, List<Result> violationList, Object instance, Rule ruleAnnotation, RuleSet ruleSet, Method method, Check checkAnnotation, String url)
108
    {
109
        final CheckDetails checkDetails = new CheckDetails(ruleSet, ruleAnnotation, instance, checkAnnotation, method);
×
110

111
        final Object result;
112
        try
113
        {
114
            result = method.invoke(instance, context);
×
115
        }
116
        catch (IllegalAccessException | InvocationTargetException e)
×
117
        {
118
            throw new RuntimeException(e);
×
119
        }
×
120
        if (result != null)
×
121
        {
122
            if (result instanceof Iterable)
×
123
            {
124
                //noinspection unchecked
125
                for (Violation violation : (Iterable<? extends Violation>) result)
×
126
                {
127
                    // Ignore violations if there are x-zally-ignore markers.
128
                    if (context.isIgnored(violation.getPointer(), checkDetails.getRule().id())
×
129
                            || context.isIgnored(violation.getPointer(), "*"))
×
130
                    {
131
                        logger.info(String.format("Ignore violation, rule = %s, at %s", checkDetails.getRule().id(), violation.getPointer()));
×
132
                        continue;
×
133
                    }
134
                    violationList.add(handleViolation(url, checkDetails, violation));
×
135
                }
×
136
            }
137
            else if (result instanceof Violation)
×
138
            {
139
                violationList.add(handleViolation(url, checkDetails, (Violation) result));
×
140
            }
141
        }
142
        return checkDetails;
×
143
    }
144

145
    private List<Class<?>> loadRuleClasses()
146
    {
147
        try (ScanResult result = new ClassGraph().enableClassInfo().enableAnnotationInfo().scan())
1✔
148
        {
149
            final ClassInfoList classInfos = result.getClassesWithAnnotation(Rule.class.getName());
1✔
150
            return classInfos.stream().map(ClassInfo::loadClass).collect(Collectors.toList());
1✔
151
        }
152
    }
153

154
    private Object createRuleInstance(Class<?> ruleClass, Config ruleConfig)
155
    {
156
        try
157
        {
158
            for (Constructor<?> constructor : ruleClass.getConstructors())
1✔
159
            {
160
                final Class<?>[] paramTypes = constructor.getParameterTypes();
1✔
161
                if (paramTypes.length == 1 && paramTypes[0].equals(Config.class))
1✔
162
                {
163
                    return constructor.newInstance(ruleConfig.withFallback(ConfigFactory.parseMap(Collections.emptyMap())));
1✔
164
                }
165
            }
166
            return ruleClass.getConstructor().newInstance();
1✔
167
        }
168
        catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e)
×
169
        {
170
            throw new RuntimeException("Cannot instantiate rule " + ruleClass, e);
×
171
        }
172
    }
173

174
    private Object createInstance(Class<?> type)
175
    {
176
        try
177
        {
178
            final Constructor<?> constructor = type.getConstructor();
1✔
179
            return constructor.newInstance();
1✔
180
        }
181
        catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e)
×
182
        {
183
            throw new RuntimeException("Cannot instantiate class " + type, e);
×
184
        }
185
    }
186

187
    private Result handleViolation(String url, final CheckDetails details, Violation violation)
188
    {
189
        JsonPointerLocator locator = new JsonPointerLocator("");
×
190
        try {
191
            // throw new IOException();
192
            locator = new JsonPointerLocator(Files.readString(Paths.get(url)));
×
193
        } catch (IOException e) {
×
194
            logger.warn("Could not read File");;
×
195
            e.printStackTrace();
×
196
        }
×
197

198
        return new Result(
×
199
                details.getRule().id(),
×
200
                details.getRuleSet().url(details.getRule()),
×
201
                details.getRule().title(),
×
202
                violation.getDescription(),
×
203
                details.getCheck().severity(),
×
204
                violation.getPointer(),
×
205
                locator.locate(violation.getPointer())
×
206
        );
207
    }
208

209
    public List<RuleDetails> getRules()
210
    {
211
        return rules;
×
212
    }
213
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc