2 | Enable users upload files into the readme resources attached to the API. SECURITY IMPORTANCE: This enables the user to specify any file inside their code repository.
3 |
2 | Enable users upload files into the changelog resources attached to the API. SECURITY IMPORTANCE: This enables the user to specify any file inside their code repository.
3 |
2 | A token is required if the API already existing in the catalog. If a new API is created the return value from this step includes the newly created token that is required in any future interaction.
3 |
--------------------------------------------------------------------------------
/Jenkinsfile:
--------------------------------------------------------------------------------
1 | def configurations = [
2 | [ platform: 'linux', jdk: '8', jenkins: '2.300' ],
3 | [ platform: 'linux', jdk: '11', jenkins: '2.300' ],
4 | [ platform: 'linux', jdk: '17', jenkins: '2.300' ]
5 | ]
6 |
7 | buildPlugin(
8 | tests: [ skip: true ],
9 | configurations: configurations
10 | )
--------------------------------------------------------------------------------
/src/main/resources/io/apimap/plugin/jenkins/ValidateStep/config.jelly:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.mvn/extensions.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | io.jenkins.tools.incrementals
4 | git-changelist-maven-extension
5 | 1.3
6 |
7 |
--------------------------------------------------------------------------------
/.github/workflows/cd.yaml:
--------------------------------------------------------------------------------
1 | # Note: additional setup is required, see https://www.jenkins.io/redirect/continuous-delivery-of-plugins
2 |
3 | name: cd
4 | on:
5 | workflow_dispatch:
6 | check_run:
7 | types:
8 | - completed
9 |
10 | jobs:
11 | maven-cd:
12 | uses: jenkins-infra/github-reusable-workflows/.github/workflows/maven-cd.yml@v1
13 | secrets:
14 | MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
15 | MAVEN_TOKEN: ${{ secrets.MAVEN_TOKEN }}
--------------------------------------------------------------------------------
/src/test/java/io/apimap/UrlRestrictionsTest.java:
--------------------------------------------------------------------------------
1 | package io.apimap;
2 |
3 | import io.apimap.plugin.jenkins.utils.RestClientUtil;
4 | import org.junit.Test;
5 |
6 | import static org.junit.Assert.assertFalse;
7 | import static org.junit.Assert.assertTrue;
8 |
9 | public class UrlRestrictionsTest {
10 | @Test
11 | public void urlWithArguments_didFail() {
12 | assertFalse(RestClientUtil.bareboneURL("https://www.google.com/search?channel=fs&client=ubuntu"));
13 | }
14 |
15 | @Test
16 | public void urlWithoutArguments_didSucceed() {
17 | assertTrue(RestClientUtil.bareboneURL("https://api.apimap.io/"));
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/resources/io/apimap/plugin/jenkins/PublishStep/config.jelly:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | Changelog
2 | ===
3 |
4 | ### 01.09.2022
5 | - Fixed repository url bug
6 |
7 | ### 19.08.2022
8 | - Added readme and changelog resource uploads
9 | - Using log levels FINER and FINE
10 | - Added default values to all parameters
11 | - Return token even on failure if a token is returned upon create a new API
12 | - Fixed enabling dry run bug
13 |
14 | ### 29.06.2022
15 | - Code added to the jenkins git repo
16 | - Added jar libraries to local repository
17 |
18 | ### 28.06.2022
19 | - Removed connection testing function
20 |
21 | ### 22.06.2022
22 | - Testing a URL now requires the user to be Administrator
23 | - Added description text if people use arguments in the apimap url
24 |
25 | ### 21.04.2022
26 | - Updated dependencies
27 |
28 | ### 29.10.2021
29 | - First public release
30 |
--------------------------------------------------------------------------------
/src/main/resources/io/apimap/plugin/jenkins/ApiMap/global.jelly:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/main/java/io/apimap/plugin/jenkins/exceptions/PublishErrorException.java:
--------------------------------------------------------------------------------
1 | /*
2 | Licensed to the Apache Software Foundation (ASF) under one
3 | or more contributor license agreements. See the NOTICE file
4 | distributed with this work for additional information
5 | regarding copyright ownership. The ASF licenses this file
6 | to you under the Apache License, Version 2.0 (the
7 | "License"); you may not use this file except in compliance
8 | with the License. You may obtain a copy of the License at
9 |
10 | http://www.apache.org/licenses/LICENSE-2.0
11 |
12 | Unless required by applicable law or agreed to in writing,
13 | software distributed under the License is distributed on an
14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | KIND, either express or implied. See the License for the
16 | specific language governing permissions and limitations
17 | under the License.
18 | */
19 |
20 | package io.apimap.plugin.jenkins.exceptions;
21 |
22 | public class PublishErrorException extends Exception {
23 | public PublishErrorException(String message) {
24 | super(message);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/io/apimap/plugin/jenkins/exceptions/FileUnreadableException.java:
--------------------------------------------------------------------------------
1 | /*
2 | Licensed to the Apache Software Foundation (ASF) under one
3 | or more contributor license agreements. See the NOTICE file
4 | distributed with this work for additional information
5 | regarding copyright ownership. The ASF licenses this file
6 | to you under the Apache License, Version 2.0 (the
7 | "License"); you may not use this file except in compliance
8 | with the License. You may obtain a copy of the License at
9 |
10 | http://www.apache.org/licenses/LICENSE-2.0
11 |
12 | Unless required by applicable law or agreed to in writing,
13 | software distributed under the License is distributed on an
14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | KIND, either express or implied. See the License for the
16 | specific language governing permissions and limitations
17 | under the License.
18 | */
19 |
20 | package io.apimap.plugin.jenkins.exceptions;
21 |
22 | public class FileUnreadableException extends Exception {
23 | public FileUnreadableException(String message) {
24 | super(message);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/io/apimap/plugin/jenkins/exceptions/IncorrectFileTypeException.java:
--------------------------------------------------------------------------------
1 | /*
2 | Licensed to the Apache Software Foundation (ASF) under one
3 | or more contributor license agreements. See the NOTICE file
4 | distributed with this work for additional information
5 | regarding copyright ownership. The ASF licenses this file
6 | to you under the Apache License, Version 2.0 (the
7 | "License"); you may not use this file except in compliance
8 | with the License. You may obtain a copy of the License at
9 |
10 | http://www.apache.org/licenses/LICENSE-2.0
11 |
12 | Unless required by applicable law or agreed to in writing,
13 | software distributed under the License is distributed on an
14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | KIND, either express or implied. See the License for the
16 | specific language governing permissions and limitations
17 | under the License.
18 | */
19 |
20 | package io.apimap.plugin.jenkins.exceptions;
21 |
22 | public class IncorrectFileTypeException extends Exception {
23 | public IncorrectFileTypeException(String message) {
24 | super(message);
25 | }
26 | }
--------------------------------------------------------------------------------
/lib/io/apimap/file/file-interface/1.0/file-interface-1.0.pom:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 | 4.0.0
10 | io.apimap.file
11 | file-interface
12 | 1.0
13 |
14 |
15 | com.fasterxml.jackson.core
16 | jackson-databind
17 | 2.13.0
18 | runtime
19 |
20 |
21 | com.fasterxml.jackson.core
22 | jackson-core
23 | 2.13.0
24 | runtime
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/lib/io/apimap/api/rest-interface/2.2.0/rest-interface-2.2.0.pom:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 | 4.0.0
10 | io.apimap.api
11 | rest-interface
12 | 2.2.0
13 |
14 |
15 | com.fasterxml.jackson.core
16 | jackson-databind
17 | 2.13.3
18 | runtime
19 |
20 |
21 | com.fasterxml.jackson.core
22 | jackson-annotations
23 | 2.13.3
24 | runtime
25 |
26 |
27 | io.swagger.core.v3
28 | swagger-annotations
29 | 2.2.0
30 | runtime
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/lib/io/apimap/client/rest-client/3.0.1/rest-client-3.0.1.pom:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 | 4.0.0
10 | io.apimap.client
11 | rest-client
12 | 3.0.1
13 |
14 |
15 | org.apache.httpcomponents.client5
16 | httpclient5
17 | 5.1.3
18 | compile
19 |
20 |
21 | io.apimap.api
22 | rest-interface
23 | 2.1.3
24 | compile
25 |
26 |
27 | com.fasterxml.jackson.core
28 | jackson-databind
29 | 2.13.3
30 | runtime
31 |
32 |
33 | com.fasterxml.jackson.core
34 | jackson-annotations
35 | 2.13.3
36 | runtime
37 |
38 |
39 | commons-io
40 | commons-io
41 | 2.11.0
42 | runtime
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/src/main/java/io/apimap/plugin/jenkins/output/ValidateResult.java:
--------------------------------------------------------------------------------
1 | /*
2 | Licensed to the Apache Software Foundation (ASF) under one
3 | or more contributor license agreements. See the NOTICE file
4 | distributed with this work for additional information
5 | regarding copyright ownership. The ASF licenses this file
6 | to you under the Apache License, Version 2.0 (the
7 | "License"); you may not use this file except in compliance
8 | with the License. You may obtain a copy of the License at
9 |
10 | http://www.apache.org/licenses/LICENSE-2.0
11 |
12 | Unless required by applicable law or agreed to in writing,
13 | software distributed under the License is distributed on an
14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | KIND, either express or implied. See the License for the
16 | specific language governing permissions and limitations
17 | under the License.
18 | */
19 |
20 | package io.apimap.plugin.jenkins.output;
21 |
22 | import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.Whitelisted;
23 |
24 | public class ValidateResult {
25 | public enum Status {
26 | VALID,
27 | MISSING,
28 | INVALID,
29 | ABORTED,
30 | FAILED,
31 | UNKNOWN
32 | }
33 |
34 | private final Status status;
35 | private final String description;
36 |
37 | public ValidateResult(final Status status,
38 | final String description) {
39 | this.status = status;
40 | this.description = description;
41 | }
42 |
43 | @Whitelisted
44 | public Status getStatus() {
45 | return status;
46 | }
47 |
48 | @Whitelisted
49 | public String getDescription() {
50 | return description;
51 | }
52 |
53 | @Override
54 | public String toString() {
55 | return "ValidateResult{" +
56 | "status=" + status +
57 | ", description='" + description + '\'' +
58 | '}';
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/io/apimap/plugin/jenkins/utils/RestClientUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | Licensed to the Apache Software Foundation (ASF) under one
3 | or more contributor license agreements. See the NOTICE file
4 | distributed with this work for additional information
5 | regarding copyright ownership. The ASF licenses this file
6 | to you under the Apache License, Version 2.0 (the
7 | "License"); you may not use this file except in compliance
8 | with the License. You may obtain a copy of the License at
9 |
10 | http://www.apache.org/licenses/LICENSE-2.0
11 |
12 | Unless required by applicable law or agreed to in writing,
13 | software distributed under the License is distributed on an
14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | KIND, either express or implied. See the License for the
16 | specific language governing permissions and limitations
17 | under the License.
18 | */
19 |
20 | package io.apimap.plugin.jenkins.utils;
21 |
22 | import io.apimap.client.RestClientConfiguration;
23 | import io.apimap.plugin.jenkins.ApiMap;
24 | import jenkins.model.Jenkins;
25 |
26 | import java.io.IOException;
27 |
28 | public class RestClientUtil {
29 | public static RestClientConfiguration configuration(String token) throws IOException {
30 | final Jenkins instance = Jenkins.getInstanceOrNull();
31 |
32 | if (instance == null) {
33 | throw new IOException("Unable to find Jenkins Instance");
34 | }
35 |
36 | final ApiMap.ApiMapDescriptorImpl descImpl = (ApiMap.ApiMapDescriptorImpl) instance.getDescriptorByName(ApiMap.class.getName());
37 |
38 | if (descImpl.getUrl() == null) {
39 | throw new IOException("Missing required root URL");
40 | }
41 |
42 | final RestClientConfiguration client = new RestClientConfiguration(
43 | token,
44 | descImpl.getUrl(),
45 | descImpl.isDebugMode()
46 | );
47 |
48 | client.setDryRunMode(descImpl.isDryRunMode());
49 |
50 | return client;
51 | }
52 |
53 | public static boolean bareboneURL(String url){
54 | return !url.matches(".*([&?]).*");
55 | }
56 | }
--------------------------------------------------------------------------------
/src/main/java/io/apimap/plugin/jenkins/output/PublishResult.java:
--------------------------------------------------------------------------------
1 | /*
2 | Licensed to the Apache Software Foundation (ASF) under one
3 | or more contributor license agreements. See the NOTICE file
4 | distributed with this work for additional information
5 | regarding copyright ownership. The ASF licenses this file
6 | to you under the Apache License, Version 2.0 (the
7 | "License"); you may not use this file except in compliance
8 | with the License. You may obtain a copy of the License at
9 |
10 | http://www.apache.org/licenses/LICENSE-2.0
11 |
12 | Unless required by applicable law or agreed to in writing,
13 | software distributed under the License is distributed on an
14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | KIND, either express or implied. See the License for the
16 | specific language governing permissions and limitations
17 | under the License.
18 | */
19 |
20 | package io.apimap.plugin.jenkins.output;
21 |
22 | import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.Whitelisted;
23 |
24 | public class PublishResult {
25 | public enum Status {
26 | CREATED,
27 | UPDATED,
28 | FAILED,
29 | ABORTED,
30 | UNKNOWN
31 | }
32 |
33 | private final Status status;
34 | private final String description;
35 | private final String token;
36 |
37 | public PublishResult(final Status status,
38 | final String description) {
39 | this.status = status;
40 | this.description = description;
41 | this.token = null;
42 | }
43 |
44 | public PublishResult(final Status status,
45 | final String description,
46 | final String token) {
47 | this.status = status;
48 | this.description = description;
49 | this.token = token;
50 | }
51 |
52 | @Whitelisted
53 | public Status getStatus() {
54 | return status;
55 | }
56 |
57 | @Whitelisted
58 | public String getDescription() {
59 | return description;
60 | }
61 |
62 | @Whitelisted
63 | public String getToken() {
64 | return token;
65 | }
66 |
67 | @Override
68 | public String toString() {
69 | return "PublishResult{" +
70 | "status=" + status +
71 | ", description='" + description + '\'' +
72 | ", token='" + token + '\'' +
73 | '}';
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/lib/io/apimap/file/file-interface/1.0/file-interface-1.0.module:
--------------------------------------------------------------------------------
1 | {
2 | "formatVersion": "1.1",
3 | "component": {
4 | "group": "io.apimap.file",
5 | "module": "file-interface",
6 | "version": "1.0",
7 | "attributes": {
8 | "org.gradle.status": "release"
9 | }
10 | },
11 | "createdBy": {
12 | "gradle": {
13 | "version": "7.1"
14 | }
15 | },
16 | "variants": [
17 | {
18 | "name": "apiElements",
19 | "attributes": {
20 | "org.gradle.category": "library",
21 | "org.gradle.dependency.bundling": "external",
22 | "org.gradle.jvm.version": 8,
23 | "org.gradle.libraryelements": "jar",
24 | "org.gradle.usage": "java-api"
25 | },
26 | "files": [
27 | {
28 | "name": "file-interface-1.0.jar",
29 | "url": "file-interface-1.0.jar",
30 | "size": 9054,
31 | "sha512": "c11981c37897542360a212474b28f581841be0ef37fae4fc8431f83957b56d75141fa752a457792f782c09306a295f3360145f6f2608a55343726bfbb776e525",
32 | "sha256": "12cb352883bf31a0327f99c71c33f8fcc2b5fc92fec9d2e6aba65bf6cb954198",
33 | "sha1": "904b90c2e92d7b90bcf945ecff533e617475fe44",
34 | "md5": "b1a83a8582fef1dbd09fcdb36ffb3507"
35 | }
36 | ]
37 | },
38 | {
39 | "name": "runtimeElements",
40 | "attributes": {
41 | "org.gradle.category": "library",
42 | "org.gradle.dependency.bundling": "external",
43 | "org.gradle.jvm.version": 8,
44 | "org.gradle.libraryelements": "jar",
45 | "org.gradle.usage": "java-runtime"
46 | },
47 | "dependencies": [
48 | {
49 | "group": "com.fasterxml.jackson.core",
50 | "module": "jackson-databind",
51 | "version": {
52 | "requires": "2.13.0"
53 | }
54 | },
55 | {
56 | "group": "com.fasterxml.jackson.core",
57 | "module": "jackson-core",
58 | "version": {
59 | "requires": "2.13.0"
60 | }
61 | }
62 | ],
63 | "files": [
64 | {
65 | "name": "file-interface-1.0.jar",
66 | "url": "file-interface-1.0.jar",
67 | "size": 9054,
68 | "sha512": "c11981c37897542360a212474b28f581841be0ef37fae4fc8431f83957b56d75141fa752a457792f782c09306a295f3360145f6f2608a55343726bfbb776e525",
69 | "sha256": "12cb352883bf31a0327f99c71c33f8fcc2b5fc92fec9d2e6aba65bf6cb954198",
70 | "sha1": "904b90c2e92d7b90bcf945ecff533e617475fe44",
71 | "md5": "b1a83a8582fef1dbd09fcdb36ffb3507"
72 | }
73 | ]
74 | }
75 | ]
76 | }
77 |
--------------------------------------------------------------------------------
/lib/io/apimap/api/rest-interface/2.2.0/rest-interface-2.2.0.module:
--------------------------------------------------------------------------------
1 | {
2 | "formatVersion": "1.1",
3 | "component": {
4 | "group": "io.apimap.api",
5 | "module": "rest-interface",
6 | "version": "2.2.0",
7 | "attributes": {
8 | "org.gradle.status": "release"
9 | }
10 | },
11 | "createdBy": {
12 | "gradle": {
13 | "version": "7.1"
14 | }
15 | },
16 | "variants": [
17 | {
18 | "name": "apiElements",
19 | "attributes": {
20 | "org.gradle.category": "library",
21 | "org.gradle.dependency.bundling": "external",
22 | "org.gradle.jvm.version": 8,
23 | "org.gradle.libraryelements": "jar",
24 | "org.gradle.usage": "java-api"
25 | },
26 | "files": [
27 | {
28 | "name": "rest-interface-2.2.0.jar",
29 | "url": "rest-interface-2.2.0.jar",
30 | "size": 72462,
31 | "sha512": "87b74572d8635bdae04c4bcfc107e368807a85946c8cd99a5a5c6058085aff827cc0e122a9b3f7ea55da84abcd210adca2996d6be05ea8d251d2f3015f3e6eb4",
32 | "sha256": "a0c233f539fa8f280e6b84e7b84d5ac70b8f6b586c10a30b8e9f115050f32793",
33 | "sha1": "e1ab48a4b5a6d9f2823fdbbe48816507220037ce",
34 | "md5": "fe083cd8f194da5a7ef47417e0f63f33"
35 | }
36 | ]
37 | },
38 | {
39 | "name": "runtimeElements",
40 | "attributes": {
41 | "org.gradle.category": "library",
42 | "org.gradle.dependency.bundling": "external",
43 | "org.gradle.jvm.version": 8,
44 | "org.gradle.libraryelements": "jar",
45 | "org.gradle.usage": "java-runtime"
46 | },
47 | "dependencies": [
48 | {
49 | "group": "com.fasterxml.jackson.core",
50 | "module": "jackson-databind",
51 | "version": {
52 | "requires": "2.13.3"
53 | }
54 | },
55 | {
56 | "group": "com.fasterxml.jackson.core",
57 | "module": "jackson-annotations",
58 | "version": {
59 | "requires": "2.13.3"
60 | }
61 | },
62 | {
63 | "group": "io.swagger.core.v3",
64 | "module": "swagger-annotations",
65 | "version": {
66 | "requires": "2.2.0"
67 | }
68 | }
69 | ],
70 | "files": [
71 | {
72 | "name": "rest-interface-2.2.0.jar",
73 | "url": "rest-interface-2.2.0.jar",
74 | "size": 72462,
75 | "sha512": "87b74572d8635bdae04c4bcfc107e368807a85946c8cd99a5a5c6058085aff827cc0e122a9b3f7ea55da84abcd210adca2996d6be05ea8d251d2f3015f3e6eb4",
76 | "sha256": "a0c233f539fa8f280e6b84e7b84d5ac70b8f6b586c10a30b8e9f115050f32793",
77 | "sha1": "e1ab48a4b5a6d9f2823fdbbe48816507220037ce",
78 | "md5": "fe083cd8f194da5a7ef47417e0f63f33"
79 | }
80 | ]
81 | }
82 | ]
83 | }
84 |
--------------------------------------------------------------------------------
/src/integrationTest/java/io/apimap/MetadataUploadTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | Licensed to the Apache Software Foundation (ASF) under one
3 | or more contributor license agreements. See the NOTICE file
4 | distributed with this work for additional information
5 | regarding copyright ownership. The ASF licenses this file
6 | to you under the Apache License, Version 2.0 (the
7 | "License"); you may not use this file except in compliance
8 | with the License. You may obtain a copy of the License at
9 |
10 | http://www.apache.org/licenses/LICENSE-2.0
11 |
12 | Unless required by applicable law or agreed to in writing,
13 | software distributed under the License is distributed on an
14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | KIND, either express or implied. See the License for the
16 | specific language governing permissions and limitations
17 | under the License.
18 | */
19 |
20 | package io.apimap;
21 |
22 | import io.apimap.client.RestClientConfiguration;
23 | import io.apimap.client.exception.IncorrectTokenException;
24 | import io.apimap.file.metadata.MetadataDataWrapper;
25 | import io.apimap.file.metadata.MetadataFile;
26 | import io.apimap.plugin.jenkins.exceptions.PublishErrorException;
27 | import io.apimap.plugin.jenkins.step.PublishStep;
28 | import org.apache.http.HttpEntity;
29 | import org.jenkinsci.plugins.workflow.steps.StepContext;
30 | import org.junit.Test;
31 |
32 | import java.io.IOException;
33 | import java.util.Arrays;
34 | import java.util.Locale;
35 |
36 | import static junit.framework.TestCase.assertTrue;
37 | import static org.mockito.Mockito.mock;
38 | import static org.mockito.Mockito.when;
39 |
40 |
41 | public class MetadataUploadTest {
42 | @Test
43 | public void uploadFile_didSucceed() throws IncorrectTokenException, IOException, PublishErrorException, InterruptedException {
44 | PublishStep publishStep = mock(PublishStep.class);
45 | when(publishStep.getRepositoryURL()).thenReturn("http://localhost:888");
46 |
47 | StepContext context = mock(StepContext.class);
48 |
49 | SurrogatePublishStepExecution publishStepExecution = new SurrogatePublishStepExecution(publishStep, context);
50 |
51 | MetadataDataWrapper data = new MetadataDataWrapper(
52 | "Hello World",
53 | "My first API",
54 | "Public",
55 | "1.0.0",
56 | "Design",
57 | "JSON:API v1.1",
58 | "OpenAPI Specification",
59 | "My department",
60 | "Apimap.io",
61 | "System1",
62 | Arrays.asList("http://localhost:8080")
63 | );
64 |
65 | MetadataFile metadataFile = new MetadataFile("1", data);
66 | RestClientConfiguration configuration = new RestClientConfiguration(null, "http://localhost:8080", true);
67 | publishStepExecution.uploadMetadata(metadataFile, configuration);
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/test/java/io/apimap/SurrogatePublishStepExecution.java:
--------------------------------------------------------------------------------
1 | /*
2 | Licensed to the Apache Software Foundation (ASF) under one
3 | or more contributor license agreements. See the NOTICE file
4 | distributed with this work for additional information
5 | regarding copyright ownership. The ASF licenses this file
6 | to you under the Apache License, Version 2.0 (the
7 | "License"); you may not use this file except in compliance
8 | with the License. You may obtain a copy of the License at
9 |
10 | http://www.apache.org/licenses/LICENSE-2.0
11 |
12 | Unless required by applicable law or agreed to in writing,
13 | software distributed under the License is distributed on an
14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | KIND, either express or implied. See the License for the
16 | specific language governing permissions and limitations
17 | under the License.
18 | */
19 |
20 | package io.apimap;
21 |
22 | import io.apimap.api.rest.ClassificationRootRestEntity;
23 | import io.apimap.api.rest.MetadataDataRestEntity;
24 | import io.apimap.client.RestClientConfiguration;
25 | import io.apimap.client.exception.IncorrectTokenException;
26 | import io.apimap.file.metadata.MetadataFile;
27 | import io.apimap.file.taxonomy.TaxonomyFile;
28 | import io.apimap.plugin.jenkins.exceptions.PublishErrorException;
29 | import io.apimap.plugin.jenkins.output.PublishResult;
30 | import io.apimap.plugin.jenkins.step.PublishStep;
31 | import io.apimap.plugin.jenkins.step.publish.PublishStepExecution;
32 | import org.apache.commons.lang.mutable.MutableBoolean;
33 | import org.jenkinsci.plugins.workflow.steps.StepContext;
34 |
35 | import java.io.IOException;
36 |
37 | public class SurrogatePublishStepExecution extends PublishStepExecution {
38 | public SurrogatePublishStepExecution(PublishStep step, StepContext context) {
39 | super(step, context);
40 | }
41 |
42 | public PublishResult failure(String description){
43 | return super.failure(description, null);
44 | }
45 |
46 | public PublishResult success(String description, String token, MutableBoolean isApiCreated){
47 | return super.success(description, token, isApiCreated);
48 | }
49 |
50 | public PublishResult run() throws Exception {
51 | return super.run();
52 | }
53 |
54 | public MetadataDataRestEntity uploadMetadata(MetadataFile metadataFile, RestClientConfiguration configuration, MutableBoolean isApiCreated) throws IOException, InterruptedException, IncorrectTokenException, PublishErrorException {
55 | return super.uploadMetadata(metadataFile, configuration, isApiCreated);
56 | }
57 |
58 | public ClassificationRootRestEntity uploadTaxonomy(String apiName, String apiVersion, TaxonomyFile taxonomyFile, RestClientConfiguration configuration) throws IOException, IncorrectTokenException, PublishErrorException {
59 | return super.uploadTaxonomy(apiName, apiVersion, taxonomyFile, configuration);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to make participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies within all project spaces, and it also applies when
49 | an individual is representing the project or its community in public spaces.
50 | Examples of representing a project or community include using an official
51 | project e-mail address, posting via an official social media account, or acting
52 | as an appointed representative at an online or offline event. Representation of
53 | a project may be further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at https://github.com/apimap. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
77 |
--------------------------------------------------------------------------------
/lib/io/apimap/client/rest-client/3.0.1/rest-client-3.0.1.module:
--------------------------------------------------------------------------------
1 | {
2 | "formatVersion": "1.1",
3 | "component": {
4 | "group": "io.apimap.client",
5 | "module": "rest-client",
6 | "version": "3.0.1",
7 | "attributes": {
8 | "org.gradle.status": "release"
9 | }
10 | },
11 | "createdBy": {
12 | "gradle": {
13 | "version": "7.5.1"
14 | }
15 | },
16 | "variants": [
17 | {
18 | "name": "apiElements",
19 | "attributes": {
20 | "org.gradle.category": "library",
21 | "org.gradle.dependency.bundling": "external",
22 | "org.gradle.jvm.version": 8,
23 | "org.gradle.libraryelements": "jar",
24 | "org.gradle.usage": "java-api"
25 | },
26 | "dependencies": [
27 | {
28 | "group": "org.apache.httpcomponents.client5",
29 | "module": "httpclient5",
30 | "version": {
31 | "requires": "5.1.3"
32 | }
33 | },
34 | {
35 | "group": "io.apimap.api",
36 | "module": "rest-interface",
37 | "version": {
38 | "requires": "2.1.3"
39 | }
40 | }
41 | ],
42 | "files": [
43 | {
44 | "name": "rest-client-3.0.1.jar",
45 | "url": "rest-client-3.0.1.jar",
46 | "size": 22590,
47 | "sha512": "5af289c73b7d5a50912f358f2bb149477e096ccb617093f2bea9555866283c6b0b1495910af24a52c52e0c1d9a59b8c911025e154e200aa9a39a41f8979a6b85",
48 | "sha256": "380b242bdaab0ec5a7b4392e756056da3c155954bdd39fc229ce8f0d507e7ae5",
49 | "sha1": "3ba06306c3616d770bf4b7db65d42e36ef9b621a",
50 | "md5": "800f499242191d36d29e697b858c7336"
51 | }
52 | ]
53 | },
54 | {
55 | "name": "runtimeElements",
56 | "attributes": {
57 | "org.gradle.category": "library",
58 | "org.gradle.dependency.bundling": "external",
59 | "org.gradle.jvm.version": 8,
60 | "org.gradle.libraryelements": "jar",
61 | "org.gradle.usage": "java-runtime"
62 | },
63 | "dependencies": [
64 | {
65 | "group": "com.fasterxml.jackson.core",
66 | "module": "jackson-databind",
67 | "version": {
68 | "requires": "2.13.3"
69 | }
70 | },
71 | {
72 | "group": "com.fasterxml.jackson.core",
73 | "module": "jackson-annotations",
74 | "version": {
75 | "requires": "2.13.3"
76 | }
77 | },
78 | {
79 | "group": "commons-io",
80 | "module": "commons-io",
81 | "version": {
82 | "requires": "2.11.0"
83 | }
84 | },
85 | {
86 | "group": "org.apache.httpcomponents.client5",
87 | "module": "httpclient5",
88 | "version": {
89 | "requires": "5.1.3"
90 | }
91 | },
92 | {
93 | "group": "io.apimap.api",
94 | "module": "rest-interface",
95 | "version": {
96 | "requires": "2.1.3"
97 | }
98 | }
99 | ],
100 | "files": [
101 | {
102 | "name": "rest-client-3.0.1.jar",
103 | "url": "rest-client-3.0.1.jar",
104 | "size": 22590,
105 | "sha512": "5af289c73b7d5a50912f358f2bb149477e096ccb617093f2bea9555866283c6b0b1495910af24a52c52e0c1d9a59b8c911025e154e200aa9a39a41f8979a6b85",
106 | "sha256": "380b242bdaab0ec5a7b4392e756056da3c155954bdd39fc229ce8f0d507e7ae5",
107 | "sha1": "3ba06306c3616d770bf4b7db65d42e36ef9b621a",
108 | "md5": "800f499242191d36d29e697b858c7336"
109 | }
110 | ]
111 | }
112 | ]
113 | }
114 |
--------------------------------------------------------------------------------
/src/main/java/io/apimap/plugin/jenkins/step/ValidateStep.java:
--------------------------------------------------------------------------------
1 | /*
2 | Licensed to the Apache Software Foundation (ASF) under one
3 | or more contributor license agreements. See the NOTICE file
4 | distributed with this work for additional information
5 | regarding copyright ownership. The ASF licenses this file
6 | to you under the Apache License, Version 2.0 (the
7 | "License"); you may not use this file except in compliance
8 | with the License. You may obtain a copy of the License at
9 |
10 | http://www.apache.org/licenses/LICENSE-2.0
11 |
12 | Unless required by applicable law or agreed to in writing,
13 | software distributed under the License is distributed on an
14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | KIND, either express or implied. See the License for the
16 | specific language governing permissions and limitations
17 | under the License.
18 | */
19 |
20 | package io.apimap.plugin.jenkins.step;
21 |
22 | import edu.umd.cs.findbugs.annotations.NonNull;
23 | import hudson.Extension;
24 | import hudson.model.Run;
25 | import hudson.model.TaskListener;
26 | import io.apimap.plugin.jenkins.step.validate.ValidateStepExecution;
27 | import org.jenkinsci.Symbol;
28 | import org.jenkinsci.plugins.workflow.steps.Step;
29 | import org.jenkinsci.plugins.workflow.steps.StepContext;
30 | import org.jenkinsci.plugins.workflow.steps.StepDescriptor;
31 | import org.jenkinsci.plugins.workflow.steps.StepExecution;
32 | import org.kohsuke.stapler.DataBoundConstructor;
33 | import org.kohsuke.stapler.DataBoundSetter;
34 |
35 | import java.io.Serializable;
36 | import java.util.HashSet;
37 | import java.util.Set;
38 | import java.util.logging.Logger;
39 |
40 | public class ValidateStep extends Step implements Serializable {
41 | public static final String BUILD_STEP_DISPLAY_NAME = "File content validation";
42 | public static final String BUILD_STEP_FUNCTION_NAME = "validateAPI";
43 |
44 | public static final String DEFAULT_METADATA_FILE_VALUE = "apimap/metadata.apimap";
45 | public static final String DEFAULT_TAXONOMY_FILE_VALUE = "apimap/taxonomy.apimap";
46 |
47 | public String metadataFile;
48 | public String taxonomyFile;
49 |
50 | @DataBoundConstructor
51 | public ValidateStep(final String metadataFile,
52 | final String taxonomyFile) {
53 | this.metadataFile = metadataFile;
54 | this.taxonomyFile = taxonomyFile;
55 | }
56 |
57 | public String getMetadataFile() {
58 | if(metadataFile == null) return DEFAULT_METADATA_FILE_VALUE;
59 | return metadataFile;
60 | }
61 |
62 | @DataBoundSetter
63 | public void setMetadataFile(final String metadataFile) {
64 | this.metadataFile = metadataFile;
65 | }
66 |
67 | public String getTaxonomyFile() {
68 | if(taxonomyFile == null) return DEFAULT_TAXONOMY_FILE_VALUE;
69 | return taxonomyFile;
70 | }
71 |
72 | @DataBoundSetter
73 | public void setTaxonomyFile(final String taxonomyFile) {
74 | this.taxonomyFile = taxonomyFile;
75 | }
76 |
77 | @Override
78 | public StepExecution start(final StepContext stepContext) throws Exception {
79 | return new ValidateStepExecution(this, stepContext);
80 | }
81 |
82 | @Symbol(BUILD_STEP_FUNCTION_NAME)
83 | @Extension
84 | public static final class DescriptorImpl extends StepDescriptor {
85 | @Override
86 | public Set extends Class>> getRequiredContext() {
87 | Set> contexts = new HashSet<>();
88 | contexts.add(TaskListener.class);
89 | contexts.add(Run.class);
90 | return contexts;
91 | }
92 |
93 | @Override
94 | public String getFunctionName() {
95 | return BUILD_STEP_FUNCTION_NAME;
96 | }
97 |
98 | @NonNull
99 | @Override
100 | public String getDisplayName() {
101 | return BUILD_STEP_DISPLAY_NAME;
102 | }
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Contributing to the Project
2 | =====
3 |
4 | 🥳 **Happy Coding** 🥳
5 |
6 | The following is a set of guidelines for contributing to the Apimap.io project. Although the project consists of
7 | multiple components they all share the same "way of working".
8 |
9 | Remember, these are mostly guidelines and not strict rules. Feel free to propose changes to this document.
10 |
11 | ## Table of Contents
12 |
13 | * [Code of Conduct](#code-of-conduct)
14 | * [Report a Bug](#report-a-bug)
15 | * [Request a Feature](#request-a-feature)
16 | * [Code and Asset Contributions](#code-and-asset-contributions)
17 | * [Where can I ask for help?](#where-can-i-ask-for-help)
18 |
19 | ## Code of Conduct
20 | ___
21 |
22 | This project and everyone that participates in it is governed by our [Code of Conduct](CODE_OF_CONDUCT.md).
23 | By participating, we expect you to uphold this code.
24 |
25 | ## How Can I Contribute?
26 | ___
27 |
28 | **We love contributions** 🎉
29 |
30 | Remember, it is better to report a bug to many than not reporting at all. If in doubt report a bug or create a feature
31 | request ️🧙 Future features depends on community feedback.
32 |
33 | > **Note:** Please don't file an issue to ask a question, you will get a faster answer by using
34 | > other means of contact
35 |
36 | > **Note:** We try to list questions we get in our [FAQ](FAQ.md), please read there first
37 |
38 | ### Report a Bug
39 | ___
40 |
41 | 🎉 **We love bug reports** 🎉
42 |
43 | #### Before Submitting
44 |
45 | - **Check** the [FAQ](FAQ.md)
46 | - **Perform a search** to see if an equal problem has already been reported. If so, please add a comment to the reported issue
47 | - **Already have a fix?** If you want to fix the bug please make a note in the description
48 | - **Determine** the correct Apimap.io component, it might be relevant to multiple components
49 |
50 | #### Howto Submit A Report
51 |
52 | [We use GitHub to track our bugs and features.](https://github.com/jenkinsci/apimap-plugin)
53 |
54 | ##### A Good Bug Report Should Contain
55 |
56 | - **A clear and descriptive title**
57 | - **Step by step** description on how to reproduce the results
58 | - A clear and **"to the point"** description of the problem
59 | - **Stack traces**, system outputs or any other information that might be relevant
60 |
61 | ### Request a Feature
62 | ___
63 |
64 | 🎉 **We love feature request** 🎉
65 |
66 | #### Before Submitting
67 |
68 | - **Determine** the correct component. We read everything, although the correct component could help us understand the
69 | context of the feature
70 |
71 | ##### A Good Feature Request Should Contain
72 |
73 | - **A clear and descriptive title**
74 | - **Use case examples**. We don't need features just to have features, they have to give value
75 | - **Examples from other software products** if the feature is implemented by others
76 | - A clear and **"to the point"** description of the feature
77 |
78 | ### Code and Asset Contributions
79 | ___
80 |
81 | 🎉 **We love code contributions** 🎉
82 |
83 | ##### Setting up your environment
84 |
85 | This is a Java based solution
86 |
87 | You will need
88 | - Java version 8 or newer
89 |
90 | ##### Creating a Pull Request
91 |
92 | 1. Be up-to-date with our development branch
93 | 2. Squash your commits (git merge --squash)
94 | 3. Create a pull request on GitHub
95 |
96 | We strive to include contributions without too much delay. If the diff between your commit and the development branch
97 | becomes to great, we will ask you to rebase.
98 |
99 | ##### A Good Pull Request Should Contain
100 |
101 | - **A clear and descriptive branch name** that starts with feature/ or bugfix/
102 | - A clear and **"to the point"** summary of the changes within
103 | - A **up-to-date** code merge with our development branch
104 |
105 | **Remember**: No change is too small
106 |
107 | ### Where can I ask for help?
108 | ___
109 |
110 | Didn't find what you where looking for? I want to contribute but still have questions? Please [contact us](SUPPORT.md) after reading our [FAQ](FAQ.md).
--------------------------------------------------------------------------------
/src/main/java/io/apimap/plugin/jenkins/utils/FileReader.java:
--------------------------------------------------------------------------------
1 | /*
2 | Licensed to the Apache Software Foundation (ASF) under one
3 | or more contributor license agreements. See the NOTICE file
4 | distributed with this work for additional information
5 | regarding copyright ownership. The ASF licenses this file
6 | to you under the Apache License, Version 2.0 (the
7 | "License"); you may not use this file except in compliance
8 | with the License. You may obtain a copy of the License at
9 |
10 | http://www.apache.org/licenses/LICENSE-2.0
11 |
12 | Unless required by applicable law or agreed to in writing,
13 | software distributed under the License is distributed on an
14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | KIND, either express or implied. See the License for the
16 | specific language governing permissions and limitations
17 | under the License.
18 | */
19 |
20 | package io.apimap.plugin.jenkins.utils;
21 |
22 | import hudson.FilePath;
23 | import io.apimap.file.FileFactory;
24 | import io.apimap.file.exceptions.MissingRequiredFieldException;
25 | import io.apimap.file.exceptions.UnsupportedVersionException;
26 | import io.apimap.file.metadata.MetadataFile;
27 | import io.apimap.file.taxonomy.TaxonomyFile;
28 | import io.apimap.plugin.jenkins.exceptions.FileUnreadableException;
29 | import io.apimap.plugin.jenkins.exceptions.IncorrectFileTypeException;
30 |
31 | import java.io.*;
32 | import java.nio.charset.StandardCharsets;
33 | import java.util.stream.Collectors;
34 |
35 | public class FileReader {
36 | public static MetadataFile metadataFile(final FilePath filePath) throws InterruptedException, MissingRequiredFieldException, UnsupportedVersionException, IOException, FileUnreadableException {
37 | if (filePath == null) throw new FileNotFoundException("[ERROR] Empty metadata file path");
38 |
39 | try (final InputStream fileReader = FileReader.readFileInDirectory(filePath)) {
40 | return FileFactory.metadataFromInputStream(fileReader);
41 | } catch (IOException | InterruptedException ignored) {
42 | throw new FileUnreadableException("Unable to read file");
43 | }
44 | }
45 |
46 | public static TaxonomyFile taxonomyFile(final FilePath filePath) throws IOException, InterruptedException, FileUnreadableException {
47 | if (filePath == null) throw new FileNotFoundException("[ERROR] Empty taxonomy file path");
48 |
49 | try (final InputStream fileReader = FileReader.readFileInDirectory(filePath)) {
50 | return FileFactory.taxonomyFromInputStream(fileReader);
51 | } catch (IOException | InterruptedException ignored) {
52 | throw new FileUnreadableException("Unable to read file");
53 | }
54 | }
55 |
56 | public static String readDocument(final FilePath filePath) throws IncorrectFileTypeException, FileUnreadableException {
57 | if(!filePath.getName().endsWith(".md")){
58 | throw new IncorrectFileTypeException("File must be of type markdown, ending with .md");
59 | }
60 |
61 | try (final InputStream fileReader = FileReader.readFileInDirectory(filePath);
62 | final InputStreamReader reader = new InputStreamReader(fileReader, StandardCharsets.UTF_8);
63 | final BufferedReader bufferedReader = new BufferedReader(reader)) {
64 |
65 | return bufferedReader
66 | .lines()
67 | .collect(Collectors.joining("\n"));
68 | } catch (IOException | InterruptedException ignored) {
69 | throw new FileUnreadableException("Unable to read file");
70 | }
71 | }
72 |
73 | public static InputStream readFileInDirectory(final FilePath file) throws IOException, InterruptedException {
74 | if (file == null) throw new IOException();
75 | if (!file.exists()) throw new FileNotFoundException();
76 | return file.read();
77 | }
78 |
79 | public static FilePath filePath(final FilePath basePath, final String additionalFilePath) {
80 | FilePath filePath = basePath;
81 | if (additionalFilePath != null) filePath = new FilePath(basePath, additionalFilePath);
82 | return filePath;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target*
2 |
3 | # General
4 | .DS_Store
5 | .AppleDouble
6 | .LSOverride
7 |
8 | # Icon must end with two \r
9 | Icon
10 |
11 | # Thumbnails
12 | ._*
13 |
14 | # Files that might appear in the root of a volume
15 | .DocumentRevisions-V100
16 | .fseventsd
17 | .Spotlight-V100
18 | .TemporaryItems
19 | .Trashes
20 | .VolumeIcon.icns
21 | .com.apple.timemachine.donotpresent
22 |
23 | # Directories potentially created on remote AFP share
24 | .AppleDB
25 | .AppleDesktop
26 | Network Trash Folder
27 | Temporary Items
28 | .apdisk
29 |
30 | *~
31 |
32 | # temporary files which can be created if a process still has a handle open of a deleted file
33 | .fuse_hidden*
34 |
35 | # KDE directory preferences
36 | .directory
37 |
38 | # Linux trash folder which might appear on any partition or disk
39 | .Trash-*
40 |
41 | # .nfs files are created when an open file is removed but is still being accessed
42 | .nfs*
43 |
44 | Cache files for Sublime Text
45 | *.tmlanguage.cache
46 | *.tmPreferences.cache
47 | *.stTheme.cache
48 |
49 | # Workspace files are user-specific
50 | *.sublime-workspace
51 |
52 | # Project files should be checked into the repository, unless a significant
53 | # proportion of contributors will probably not be using Sublime Text
54 | # *.sublime-project
55 |
56 | # SFTP configuration file
57 | sftp-config.json
58 |
59 | # Package control specific files
60 | Package Control.last-run
61 | Package Control.ca-list
62 | Package Control.ca-bundle
63 | Package Control.system-ca-bundle
64 | Package Control.cache/
65 | Package Control.ca-certs/
66 | Package Control.merged-ca-bundle
67 | Package Control.user-ca-bundle
68 | oscrypto-ca-bundle.crt
69 | bh_unicode_properties.cache
70 |
71 | # Sublime-github package stores a github token in this file
72 | # https://packagecontrol.io/packages/sublime-github
73 | GitHub.sublime-settings
74 |
75 | # Windows thumbnail cache files
76 | Thumbs.db
77 | Thumbs.db:encryptable
78 | ehthumbs.db
79 | ehthumbs_vista.db
80 |
81 | # Dump file
82 | *.stackdump
83 |
84 | # Folder config file
85 | [Dd]esktop.ini
86 |
87 | # Recycle Bin used on file shares
88 | $RECYCLE.BIN/
89 |
90 | # Windows Installer files
91 | *.cab
92 | *.msi
93 | *.msix
94 | *.msm
95 | *.msp
96 |
97 | # Windows shortcuts
98 | *.lnk
99 |
100 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
101 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
102 |
103 | .idea/*
104 |
105 | # User-specific stuff
106 | .idea/**/workspace.xml
107 | .idea/**/tasks.xml
108 | .idea/**/usage.statistics.xml
109 | .idea/**/dictionaries
110 | .idea/**/shelf
111 |
112 | # Generated files
113 | .idea/**/contentModel.xml
114 |
115 | # Sensitive or high-churn files
116 | .idea/**/dataSources/
117 | .idea/**/dataSources.ids
118 | .idea/**/dataSources.local.xml
119 | .idea/**/sqlDataSources.xml
120 | .idea/**/dynamic.xml
121 | .idea/**/uiDesigner.xml
122 | .idea/**/dbnavigator.xml
123 |
124 | # Gradle
125 | .idea/**/gradle.xml
126 | .idea/**/libraries
127 |
128 | # Gradle and Maven with auto-import
129 | # When using Gradle or Maven with auto-import, you should exclude module files,
130 | # since they will be recreated, and may cause churn. Uncomment if using
131 | # auto-import.
132 | # .idea/modules.xml
133 | # .idea/*.iml
134 | # .idea/modules
135 | # *.iml
136 | # *.ipr
137 |
138 | # CMake
139 | cmake-build-*/
140 |
141 | # Mongo Explorer plugin
142 | .idea/**/mongoSettings.xml
143 |
144 | # File-based project format
145 | *.iws
146 |
147 | # IntelliJ
148 | out/
149 |
150 | # mpeltonen/sbt-idea plugin
151 | .idea_modules/
152 |
153 | # JIRA plugin
154 | atlassian-ide-plugin.xml
155 |
156 | # Cursive Clojure plugin
157 | .idea/replstate.xml
158 | .idea/
159 |
160 | # Crashlytics plugin (for Android Studio and IntelliJ)
161 | com_crashlytics_export_strings.xml
162 | crashlytics.properties
163 | crashlytics-build.properties
164 | fabric.properties
165 |
166 | # Editor-based Rest Client
167 | .idea/httpRequests
168 |
169 | # Android studio 3.1+ serialized cache file
170 | .idea/caches/build_file_checksums.ser
171 |
172 | .gradle
173 | /build/
174 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Apimap.io Jenkins Plugin
2 | ===
3 |
4 | 🎉 **Welcome** 🎉
5 |
6 | This is a part of the Apimap.io project https://github.com/apimap, a freestanding solution to keep track of all functionality a company
7 | provides through an API. It is a push based system, connected with your build pipeline or manually updated using our CLI.
8 |
9 | > **Application programming interface (API)**: Point of functional integration between two or more systems connected
10 | > through commonly known standards
11 |
12 | **Why is this project useful?** Lost track of all the API functionality provided inside your organization? Don't want
13 | to be tied to an API proxy or management solution? The Apimap.io project uploads, indexes and enables discoverability of all
14 | your organizations APIs. We care about the source code, removing the limitation of where the API is hosted and how your
15 | network is constructed.
16 |
17 |
18 | ## Table of Contents
19 |
20 | * [Project Components](#project-components)
21 | * [Build and Run](#build-and-run)
22 | * [Contributing](#contributing)
23 |
24 | I want to know more of the technical details and implementation guides: [DEVELOPER.md](DEVELOPER.md)
25 |
26 | ## Project Components
27 | ___
28 | This is a complete software solution consisting of a collection of freestanding components. Use only the components you
29 | find useful, create the rest to custom fit your organization.
30 |
31 | - A **Developer Portal** with wizards and implementation information
32 | - A **Discovery Portal** to display APIs and filter search results
33 | - An **API** to accommodate all the information
34 | - A **Jenkins plugin** to automate information parsing and upload
35 | - A **CLI** to enable manual information uploads
36 |
37 | ## Build and Run
38 | ___
39 |
40 | This is the Jenkins plugin, created to automatically upload metadata and taxonomy files.
41 |
42 |
43 | ### Jenkinsfile
44 |
45 | The following is an example of how to use the plugin inside a Jenkinsfile
46 |
47 | #### Default values (used if not overwritten when used)
48 |
49 | The plugin is configured by default with the following values. If a value is not overwritten with another value the defaults will be used.
50 |
51 | | Argument | Default Value |
52 | |----------------|--------------------------|
53 | | metadataFile | "apimap/metadata.apimap" |
54 | | taxonomyFile | "apimap/taxonomy.apimap" |
55 | | readmeFile | "README.md" |
56 | | changelogFile | "CHANGELOG.md" |
57 | | repositoryURL | empty |
58 |
59 | #### Pipeline as Code
60 |
61 | The following example show how to use the plugin in a Pipeline as Code environment.
62 |
63 | ```groovy
64 | pipeline {
65 | agent any
66 | stages{
67 | stage('Get source'){
68 | steps{
69 | git 'https://....'
70 | }
71 | }
72 | stage('Validate'){
73 | steps{
74 | script{
75 | def result = validateAPI metadataFile: 'apimap/metadata.apimap',
76 | taxonomyFile: 'apimap/taxonomy.apimap'
77 |
78 | echo result.getDescription()
79 | }
80 | }
81 | }
82 | stage('Publish'){
83 | steps{
84 | script{
85 | def result = publishAPI metadataFile: 'apimap/metadata.apimap',
86 | taxonomyFile: 'apimap/taxonomy.apimap',
87 | readmeFile: 'README.md',
88 | changelogFile: 'CHANGELOG.md',
89 | repositoryURL: scm.getUserRemoteConfigs()[0].getUrl()
90 |
91 | echo result.getStatus().toString()
92 | echo result.getDescription()
93 | echo result.getToken()
94 | }
95 | }
96 | }
97 | }
98 | }
99 | ```
100 |
101 | #### Build JAR
102 |
103 | Based on Java the easiest way to build the artifact is using **package**
104 |
105 | > mvnw package
106 |
107 | If you build this component on anything newer than Java 8, please add the following parameter. This is due to a limitation in one of the jenkins dependencies.
108 |
109 | > -Dmaven.test.skip
110 |
111 | #### Requirements
112 |
113 | Java version 8 or newer.
114 |
115 |
116 | ## Contributing
117 | ___
118 |
119 | Read [howto contribute](CONTRIBUTING.md) to this project.
--------------------------------------------------------------------------------
/src/main/java/io/apimap/plugin/jenkins/ApiMap.java:
--------------------------------------------------------------------------------
1 | /*
2 | Licensed to the Apache Software Foundation (ASF) under one
3 | or more contributor license agreements. See the NOTICE file
4 | distributed with this work for additional information
5 | regarding copyright ownership. The ASF licenses this file
6 | to you under the Apache License, Version 2.0 (the
7 | "License"); you may not use this file except in compliance
8 | with the License. You may obtain a copy of the License at
9 |
10 | http://www.apache.org/licenses/LICENSE-2.0
11 |
12 | Unless required by applicable law or agreed to in writing,
13 | software distributed under the License is distributed on an
14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | KIND, either express or implied. See the License for the
16 | specific language governing permissions and limitations
17 | under the License.
18 | */
19 |
20 | package io.apimap.plugin.jenkins;
21 |
22 | import hudson.Extension;
23 | import hudson.Util;
24 | import hudson.model.AbstractProject;
25 | import hudson.model.Job;
26 | import hudson.model.JobProperty;
27 | import hudson.model.JobPropertyDescriptor;
28 | import hudson.util.FormValidation;
29 | import io.apimap.api.rest.ApiCollectionRootRestEntity;
30 | import io.apimap.api.rest.jsonapi.JsonApiRestResponseWrapper;
31 | import io.apimap.client.IRestClient;
32 | import io.apimap.client.RestClientConfiguration;
33 | import io.apimap.plugin.jenkins.utils.RestClientUtil;
34 | import jenkins.model.Jenkins;
35 | import net.sf.json.JSONObject;
36 | import org.kohsuke.stapler.QueryParameter;
37 | import org.kohsuke.stapler.StaplerRequest;
38 |
39 | public class ApiMap extends JobProperty> {
40 |
41 | @Extension
42 | public static final ApiMapDescriptorImpl DESCRIPTOR = new ApiMapDescriptorImpl();
43 |
44 | @Override
45 | public JobPropertyDescriptor getDescriptor() {
46 | return DESCRIPTOR;
47 | }
48 |
49 | public static final class ApiMapDescriptorImpl extends JobPropertyDescriptor {
50 | public static final String BUILD_STEP_DISPLAY_NAME = "ApiMap.io";
51 |
52 | private String url;
53 | private boolean updateBuildStatus;
54 | private boolean dryRunMode;
55 | private boolean debugMode;
56 | private boolean allowReadmeUpload;
57 | private boolean allowChangelogUpload;
58 |
59 | public ApiMapDescriptorImpl() {
60 | super(ApiMap.class);
61 | load();
62 | }
63 |
64 | @Override
65 | public boolean isApplicable(Class extends Job> aClass) {
66 | return true; //Supports all types of projects
67 | }
68 |
69 | @Override
70 | public String getDisplayName() {
71 | return BUILD_STEP_DISPLAY_NAME;
72 | }
73 |
74 | @Override
75 | public boolean configure(StaplerRequest req, JSONObject formData) throws FormException {
76 | req.bindJSON(this, formData);
77 | save();
78 | return super.configure(req, formData);
79 | }
80 |
81 | public String getUrl() {
82 | return url;
83 | }
84 |
85 | public void setUrl(String url) {
86 | this.url = url;
87 | }
88 |
89 | public boolean updateBuildStatus() {
90 | return updateBuildStatus;
91 | }
92 |
93 | public void setUpdateBuildStatus(boolean updateBuildStatus) {
94 | this.updateBuildStatus = updateBuildStatus;
95 | }
96 |
97 | public boolean isDryRunMode() {
98 | return dryRunMode;
99 | }
100 |
101 | public void setDryRunMode(boolean dryRunMode) {
102 | this.dryRunMode = dryRunMode;
103 | }
104 |
105 | public boolean isDebugMode() {
106 | return debugMode;
107 | }
108 |
109 | public void setDebugMode(boolean debugMode) {
110 | this.debugMode = debugMode;
111 | }
112 |
113 | public boolean isUpdateBuildStatus() {
114 | return updateBuildStatus;
115 | }
116 |
117 | public boolean isAllowReadmeUpload() {
118 | return allowReadmeUpload;
119 | }
120 |
121 | public void setAllowReadmeUpload(boolean allowReadmeUpload) {
122 | this.allowReadmeUpload = allowReadmeUpload;
123 | }
124 |
125 | public boolean isAllowChangelogUpload() {
126 | return allowChangelogUpload;
127 | }
128 |
129 | public void setAllowChangelogUpload(boolean allowChangelogUpload) {
130 | this.allowChangelogUpload = allowChangelogUpload;
131 | }
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/DEVELOPER.md:
--------------------------------------------------------------------------------
1 | Apimap.io Jenkins Plugin
2 | =====
3 |
4 | 🥳 **Happy Coding** 🥳
5 |
6 | This section is targeted to developers that want to use the Jenkins Plugin provided by the project.
7 |
8 | ## Table of Contents
9 |
10 | * [Introduction](#introduction)
11 | * [Getting Started](#getting-started)
12 | * [Other Resources](#other-resources)
13 |
14 | ## Introduction
15 |
16 | ### Global Configuration
17 |
18 | #### Debug Mode
19 |
20 | More extensive logging. Please note that the output is generated using System.out.println and will be printed to STDOUT.
21 |
22 | #### Dryrun Mode
23 |
24 | Does not communicate to any APIs on any actions and returns a default object from create resources.
25 |
26 | #### Configuration Options
27 |
28 | ##### Update Global Build Status
29 |
30 | | Status | Description |
31 | |-----------------|------------------------------------------------------|
32 | | Enabled | Updated the global build status to match step result |
33 | | Disabled | Only returns the validation result as a object |
34 |
35 | #### ApiMap.io instance URL
36 |
37 | Complete URL to the API instance the build system should connect to.
38 |
39 | > E.g. http://127.0.0.1:8080
40 |
41 | ## Getting Started
42 |
43 | This plugin is created to be used with Pipeline-as-Code and returns a result object depending on the step activated.
44 |
45 | ### Results from the Validate Step
46 |
47 | The following Java-object is returned from the validate step:
48 |
49 | | Variable | Description |
50 | |-------------|----------------------------------------------------------------------------------------------|
51 | | status | The status of the action. If the API was created, updated, something failed or if it crashed |
52 | | description | An explanation to the status |
53 |
54 | ```java
55 | public class ValidateResult {
56 | public enum Status {
57 | VALID,
58 | MISSING,
59 | INVALID,
60 | ABORTED,
61 | FAILED,
62 | UNKNOWN
63 | }
64 |
65 | private final Status status;
66 | private final String description;
67 |
68 | public ValidateResult(Status status, String description) {
69 | this.status = status;
70 | this.description = description;
71 | }
72 |
73 | @Whitelisted
74 | public Status getStatus() {
75 | return status;
76 | }
77 |
78 | @Whitelisted
79 | public String getDescription() {
80 | return description;
81 | }
82 | }
83 | ```
84 |
85 | ### Results from the Publish Step
86 |
87 | The following Java-object is returned from the publish step:
88 |
89 | | Variable | Description |
90 | |-------------|-------------------------------------------------------------------------------------------------------------------------|
91 | | status | The status of the action. If the API was created, updated, something failed or if it crashed |
92 | | description | An explanation to the status |
93 | | token | If the status is created theres is also a token returned with the result. This token must be used in any future updates |
94 |
95 | > Note: Do not use the token or description to test if the API is created or updated. Use the status ENUM to determine the status.
96 |
97 | ```java
98 | public class PublishResult {
99 | public enum Status {
100 | CREATED,
101 | UPDATED,
102 | FAILED,
103 | ABORTED,
104 | UNKNOWN
105 | }
106 |
107 | private final Status status;
108 | private final String description;
109 | private final String token;
110 |
111 | public PublishResult(Status status, String description) {
112 | this.status = status;
113 | this.description = description;
114 | this.token = null;
115 | }
116 |
117 | public PublishResult(Status status, String description, String token) {
118 | this.status = status;
119 | this.description = description;
120 | this.token = token;
121 | }
122 |
123 | @Whitelisted
124 | public Status getStatus() {
125 | return status;
126 | }
127 |
128 | @Whitelisted
129 | public String getDescription() {
130 | return description;
131 | }
132 |
133 | @Whitelisted
134 | public String getToken() {
135 | return token;
136 | }
137 | }
138 | ```
139 |
140 | ## Other Resources
141 | ___
142 |
143 | - [Hypermedia as the Engine of Application State (HATEOAS) ](https://en.wikipedia.org/wiki/HATEOAS)
144 | - [JSON:API — A specification for building APIs in JSON](https://jsonapi.org/)
145 | - [Jenkins Plugin development](https://www.jenkins.io/doc/developer/plugin-development/)
146 |
--------------------------------------------------------------------------------
/mvnw.cmd:
--------------------------------------------------------------------------------
1 | @REM ----------------------------------------------------------------------------
2 | @REM Licensed to the Apache Software Foundation (ASF) under one
3 | @REM or more contributor license agreements. See the NOTICE file
4 | @REM distributed with this work for additional information
5 | @REM regarding copyright ownership. The ASF licenses this file
6 | @REM to you under the Apache License, Version 2.0 (the
7 | @REM "License"); you may not use this file except in compliance
8 | @REM with the License. You may obtain a copy of the License at
9 | @REM
10 | @REM http://www.apache.org/licenses/LICENSE-2.0
11 | @REM
12 | @REM Unless required by applicable law or agreed to in writing,
13 | @REM software distributed under the License is distributed on an
14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | @REM KIND, either express or implied. See the License for the
16 | @REM specific language governing permissions and limitations
17 | @REM under the License.
18 | @REM ----------------------------------------------------------------------------
19 |
20 | @REM ----------------------------------------------------------------------------
21 | @REM Maven2 Start Up Batch script
22 | @REM
23 | @REM Required ENV vars:
24 | @REM JAVA_HOME - location of a JDK home dir
25 | @REM
26 | @REM Optional ENV vars
27 | @REM M2_HOME - location of maven2's installed home dir
28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
31 | @REM e.g. to debug Maven itself, use
32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
34 | @REM ----------------------------------------------------------------------------
35 |
36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
37 | @echo off
38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
40 |
41 | @REM set %HOME% to equivalent of $HOME
42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
43 |
44 | @REM Execute a user defined script before this one
45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending
47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
49 | :skipRcPre
50 |
51 | @setlocal
52 |
53 | set ERROR_CODE=0
54 |
55 | @REM To isolate internal variables from possible post scripts, we use another setlocal
56 | @setlocal
57 |
58 | @REM ==== START VALIDATION ====
59 | if not "%JAVA_HOME%" == "" goto OkJHome
60 |
61 | echo.
62 | echo Error: JAVA_HOME not found in your environment. >&2
63 | echo Please set the JAVA_HOME variable in your environment to match the >&2
64 | echo location of your Java installation. >&2
65 | echo.
66 | goto error
67 |
68 | :OkJHome
69 | if exist "%JAVA_HOME%\bin\java.exe" goto init
70 |
71 | echo.
72 | echo Error: JAVA_HOME is set to an invalid directory. >&2
73 | echo JAVA_HOME = "%JAVA_HOME%" >&2
74 | echo Please set the JAVA_HOME variable in your environment to match the >&2
75 | echo location of your Java installation. >&2
76 | echo.
77 | goto error
78 |
79 | @REM ==== END VALIDATION ====
80 |
81 | :init
82 |
83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
84 | @REM Fallback to current working directory if not found.
85 |
86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
88 |
89 | set EXEC_DIR=%CD%
90 | set WDIR=%EXEC_DIR%
91 | :findBaseDir
92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound
93 | cd ..
94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound
95 | set WDIR=%CD%
96 | goto findBaseDir
97 |
98 | :baseDirFound
99 | set MAVEN_PROJECTBASEDIR=%WDIR%
100 | cd "%EXEC_DIR%"
101 | goto endDetectBaseDir
102 |
103 | :baseDirNotFound
104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
105 | cd "%EXEC_DIR%"
106 |
107 | :endDetectBaseDir
108 |
109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
110 |
111 | @setlocal EnableExtensions EnableDelayedExpansion
112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
114 |
115 | :endReadAdditionalConfig
116 |
117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
118 |
119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
121 |
122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
123 | if ERRORLEVEL 1 goto error
124 | goto end
125 |
126 | :error
127 | set ERROR_CODE=1
128 |
129 | :end
130 | @endlocal & set ERROR_CODE=%ERROR_CODE%
131 |
132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending
134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
136 | :skipRcPost
137 |
138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause
140 |
141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
142 |
143 | exit /B %ERROR_CODE%
144 |
--------------------------------------------------------------------------------
/src/main/java/io/apimap/plugin/jenkins/step/PublishStep.java:
--------------------------------------------------------------------------------
1 | /*
2 | Licensed to the Apache Software Foundation (ASF) under one
3 | or more contributor license agreements. See the NOTICE file
4 | distributed with this work for additional information
5 | regarding copyright ownership. The ASF licenses this file
6 | to you under the Apache License, Version 2.0 (the
7 | "License"); you may not use this file except in compliance
8 | with the License. You may obtain a copy of the License at
9 |
10 | http://www.apache.org/licenses/LICENSE-2.0
11 |
12 | Unless required by applicable law or agreed to in writing,
13 | software distributed under the License is distributed on an
14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | KIND, either express or implied. See the License for the
16 | specific language governing permissions and limitations
17 | under the License.
18 | */
19 |
20 | package io.apimap.plugin.jenkins.step;
21 |
22 | import edu.umd.cs.findbugs.annotations.NonNull;
23 | import hudson.Extension;
24 | import hudson.model.Run;
25 | import hudson.model.TaskListener;
26 | import io.apimap.plugin.jenkins.step.publish.PublishStepExecution;
27 | import org.jenkinsci.Symbol;
28 | import org.jenkinsci.plugins.workflow.steps.Step;
29 | import org.jenkinsci.plugins.workflow.steps.StepContext;
30 | import org.jenkinsci.plugins.workflow.steps.StepDescriptor;
31 | import org.jenkinsci.plugins.workflow.steps.StepExecution;
32 | import org.kohsuke.stapler.DataBoundConstructor;
33 | import org.kohsuke.stapler.DataBoundSetter;
34 |
35 | import java.io.Serializable;
36 | import java.util.HashSet;
37 | import java.util.Set;
38 |
39 | public class PublishStep extends Step implements Serializable {
40 |
41 | public static final String BUILD_STEP_DISPLAY_NAME = "File content publishing";
42 | public static final String BUILD_STEP_FUNCTION_NAME = "publishAPI";
43 |
44 | public static final String DEFAULT_METADATA_FILE_VALUE = "apimap/metadata.apimap";
45 | public static final String DEFAULT_TAXONOMY_FILE_VALUE = "apimap/taxonomy.apimap";
46 | public static final String DEFAULT_README_FILE_VALUE = "README.md";
47 | public static final String DEFAULT_CHANGELOG_FILE_VALUE = "CHANGELOG.md";
48 |
49 | public String metadataFile;
50 | public String taxonomyFile;
51 | public String readmeFile;
52 | public String changelogFile;
53 | public String repositoryURL;
54 | public String token;
55 |
56 | @DataBoundSetter
57 | public void setMetadataFile(final String metadataFile) {
58 | this.metadataFile = metadataFile;
59 | }
60 |
61 | public String getMetadataFile() {
62 | if(metadataFile == null) return DEFAULT_METADATA_FILE_VALUE;
63 | return metadataFile;
64 | }
65 |
66 | @DataBoundSetter
67 | public void setTaxonomyFile(final String taxonomyFile) {
68 | this.taxonomyFile = taxonomyFile;
69 | }
70 |
71 | public String getTaxonomyFile() {
72 | if(taxonomyFile == null) return DEFAULT_TAXONOMY_FILE_VALUE;
73 | return taxonomyFile;
74 | }
75 |
76 | @DataBoundSetter
77 | public void setRepositoryURL(final String repositoryURL) {
78 | this.repositoryURL = repositoryURL;
79 | }
80 |
81 | public String getRepositoryURL() {
82 | return repositoryURL;
83 | }
84 |
85 | @DataBoundSetter
86 | public void setToken(final String token) {
87 | this.token = token;
88 | }
89 |
90 | public String getToken() {
91 | return token;
92 | }
93 |
94 | @DataBoundSetter
95 | public void setReadmeFile(final String readmeFile) {
96 | this.readmeFile = readmeFile;
97 | }
98 |
99 | public String getReadmeFile() {
100 | if(readmeFile == null) return DEFAULT_README_FILE_VALUE;
101 | return readmeFile;
102 | }
103 |
104 | @DataBoundSetter
105 | public void setChangelogFile(final String changelogFile) {
106 | this.changelogFile = changelogFile;
107 | }
108 |
109 | public String getChangelogFile() {
110 | if(changelogFile == null) return DEFAULT_CHANGELOG_FILE_VALUE;
111 | return changelogFile;
112 | }
113 |
114 | @DataBoundConstructor
115 | public PublishStep(final String metadataFile,
116 | final String taxonomyFile,
117 | final String readmeFile,
118 | final String changelogFile,
119 | final String token,
120 | final String repositoryURL) {
121 | this.metadataFile = metadataFile;
122 | this.taxonomyFile = taxonomyFile;
123 | this.readmeFile = readmeFile;
124 | this.changelogFile = changelogFile;
125 | this.token = token;
126 | this.repositoryURL = repositoryURL;
127 | }
128 |
129 | @Override
130 | public StepExecution start(final StepContext stepContext) throws Exception {
131 | return new PublishStepExecution(this, stepContext);
132 | }
133 |
134 | @Symbol(BUILD_STEP_FUNCTION_NAME)
135 | @Extension
136 | public static final class DescriptorImpl extends StepDescriptor {
137 | @Override
138 | public Set extends Class>> getRequiredContext() {
139 | Set> contexts = new HashSet<>();
140 | contexts.add(TaskListener.class);
141 | contexts.add(Run.class);
142 | return contexts;
143 | }
144 |
145 | @Override
146 | public String getFunctionName() {
147 | return BUILD_STEP_FUNCTION_NAME;
148 | }
149 |
150 | @NonNull
151 | @Override
152 | public String getDisplayName() {
153 | return BUILD_STEP_DISPLAY_NAME;
154 | }
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/src/main/java/io/apimap/plugin/jenkins/step/validate/ValidateStepExecution.java:
--------------------------------------------------------------------------------
1 | /*
2 | Licensed to the Apache Software Foundation (ASF) under one
3 | or more contributor license agreements. See the NOTICE file
4 | distributed with this work for additional information
5 | regarding copyright ownership. The ASF licenses this file
6 | to you under the Apache License, Version 2.0 (the
7 | "License"); you may not use this file except in compliance
8 | with the License. You may obtain a copy of the License at
9 |
10 | http://www.apache.org/licenses/LICENSE-2.0
11 |
12 | Unless required by applicable law or agreed to in writing,
13 | software distributed under the License is distributed on an
14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | KIND, either express or implied. See the License for the
16 | specific language governing permissions and limitations
17 | under the License.
18 | */
19 |
20 | package io.apimap.plugin.jenkins.step.validate;
21 |
22 | import com.fasterxml.jackson.core.JsonParseException;
23 | import com.fasterxml.jackson.databind.JsonMappingException;
24 | import hudson.FilePath;
25 | import hudson.model.Result;
26 | import io.apimap.file.metadata.MetadataFile;
27 | import io.apimap.file.taxonomy.TaxonomyFile;
28 | import io.apimap.plugin.jenkins.ApiMap;
29 | import io.apimap.plugin.jenkins.output.ValidateResult;
30 | import io.apimap.plugin.jenkins.step.ValidateStep;
31 | import io.apimap.plugin.jenkins.utils.FileReader;
32 | import jenkins.model.Jenkins;
33 | import org.jenkinsci.plugins.workflow.steps.StepContext;
34 | import org.jenkinsci.plugins.workflow.steps.SynchronousStepExecution;
35 |
36 | import java.io.IOException;
37 | import java.util.logging.Level;
38 | import java.util.logging.Logger;
39 |
40 | public class ValidateStepExecution extends SynchronousStepExecution {
41 | private static final Logger LOGGER = Logger.getLogger(ValidateStepExecution.class.getName());
42 |
43 | public static final String FILEPATH_IS_A_NULL_OBJECT = "Filepath returned as a null object";
44 | public static final String UNABLE_TO_READ_METADATA_ERROR_MESSAGE = "Unable read metadata content";
45 | public static final String METADATA_FILE_NOT_FOUND = "Unable to read metadata file";
46 | public static final String UNABLE_TO_PARSE_METADATA_ERROR_MESSAGE = "Unable to map metadata file values";
47 | public static final String TAXONOMY_FILE_NOT_FOUND = "Unable to read taxonomy file";
48 | public static final String UNABLE_TO_READ_TAXONOMY_ERROR_MESSAGE = "Unable read taxonomy content";
49 | public static final String UNABLE_TO_PARSE_TAXONOMY_ERROR_MESSAGE = "Unable to map taxonomy file values";
50 | public static final String STEP_COMPLETED_SUCCESSFULLY = "Successfully validated information";
51 |
52 | private static final long serialVersionUID = 1L;
53 |
54 | private final ValidateStep step;
55 |
56 | public ValidateStepExecution(final ValidateStep step,
57 | final StepContext context){
58 | super(context);
59 | this.step = step;
60 | }
61 |
62 | protected ValidateResult failure(final String description,
63 | final ValidateResult.Status result){
64 | final ApiMap.ApiMapDescriptorImpl descImpl = (ApiMap.ApiMapDescriptorImpl) Jenkins.getInstance().getDescriptorByName(ApiMap.class.getName());
65 |
66 | if (descImpl.updateBuildStatus()) {
67 | getContext().setResult(Result.FAILURE);
68 | getContext().onFailure(new IOException(description));
69 | }
70 |
71 | return new ValidateResult(result, description);
72 | }
73 |
74 | protected ValidateResult success(final String description){
75 | final ApiMap.ApiMapDescriptorImpl descImpl = (ApiMap.ApiMapDescriptorImpl) Jenkins.getInstance().getDescriptorByName(ApiMap.class.getName());
76 |
77 | final ValidateResult returnValue = new ValidateResult(ValidateResult.Status.VALID, description);
78 |
79 | if(descImpl.updateBuildStatus()) {
80 | getContext().setResult(Result.SUCCESS);
81 | getContext().onSuccess(returnValue);
82 | }
83 |
84 | return returnValue;
85 | }
86 |
87 | @Override
88 | protected ValidateResult run() throws Exception {
89 | final FilePath path = getContext().get(FilePath.class);
90 | if(path == null) { return failure(FILEPATH_IS_A_NULL_OBJECT, ValidateResult.Status.MISSING); }
91 |
92 | LOGGER.log(Level.FINER, "Reading metadata file");
93 | try {
94 | final MetadataFile metadataFile = FileReader.metadataFile(FileReader.filePath(path, this.step.getMetadataFile()));
95 | if (metadataFile == null) {
96 | return failure(UNABLE_TO_READ_METADATA_ERROR_MESSAGE, ValidateResult.Status.MISSING);
97 | }
98 | } catch (JsonMappingException e) {
99 | return failure(UNABLE_TO_PARSE_METADATA_ERROR_MESSAGE, ValidateResult.Status.INVALID);
100 | } catch (JsonParseException e) {
101 | return failure(UNABLE_TO_READ_METADATA_ERROR_MESSAGE, ValidateResult.Status.FAILED);
102 | } catch (IOException e) {
103 | return failure(METADATA_FILE_NOT_FOUND, ValidateResult.Status.MISSING);
104 | }
105 |
106 | LOGGER.log(Level.INFO, "Reading taxonomy file");
107 | try {
108 | final TaxonomyFile taxonomyFile = FileReader.taxonomyFile(FileReader.filePath(path, this.step.getTaxonomyFile()));
109 | if (taxonomyFile == null) {
110 | return failure(UNABLE_TO_READ_TAXONOMY_ERROR_MESSAGE, ValidateResult.Status.MISSING);
111 | }
112 | } catch (JsonMappingException e) {
113 | return failure(UNABLE_TO_PARSE_TAXONOMY_ERROR_MESSAGE, ValidateResult.Status.INVALID);
114 | } catch (JsonParseException e) {
115 | return failure(UNABLE_TO_READ_TAXONOMY_ERROR_MESSAGE, ValidateResult.Status.FAILED);
116 | } catch (IOException e) {
117 | return failure(TAXONOMY_FILE_NOT_FOUND, ValidateResult.Status.MISSING);
118 | }
119 |
120 | return success(STEP_COMPLETED_SUCCESSFULLY);
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/src/test/java/io/apimap/FileReaderTest.java:
--------------------------------------------------------------------------------
1 | package io.apimap;
2 |
3 | import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
4 | import hudson.FilePath;
5 | import io.apimap.api.rest.ApiDataRestEntity;
6 | import io.apimap.file.exceptions.MissingRequiredFieldException;
7 | import io.apimap.file.exceptions.UnsupportedVersionException;
8 | import io.apimap.file.metadata.MetadataFile;
9 | import io.apimap.file.taxonomy.TaxonomyFile;
10 | import io.apimap.plugin.jenkins.exceptions.FileUnreadableException;
11 | import io.apimap.plugin.jenkins.utils.FileReader;
12 | import org.apache.tools.ant.filters.StringInputStream;
13 | import org.junit.Assert;
14 | import org.junit.Test;
15 | import org.mockito.ArgumentMatchers;
16 | import org.mockito.MockedStatic;
17 | import org.mockito.Mockito;
18 |
19 | import java.io.FileNotFoundException;
20 | import java.io.IOException;
21 | import java.io.InputStream;
22 |
23 | import static org.junit.Assert.assertEquals;
24 | import static org.mockito.ArgumentMatchers.any;
25 |
26 | public class FileReaderTest {
27 | @Test
28 | public void readMetadataFile_didFailWithNotFound() throws MissingRequiredFieldException, IOException, InterruptedException, UnsupportedVersionException {
29 | Assert.assertThrows(FileNotFoundException.class,
30 | ()->{
31 | FileReader.metadataFile(null);
32 | });
33 | }
34 |
35 | @Test
36 | public void readTaxonomyFile_didFailWithNotFound() throws MissingRequiredFieldException, IOException, InterruptedException, UnsupportedVersionException {
37 | Assert.assertThrows(FileNotFoundException.class,
38 | ()->{
39 | FileReader.taxonomyFile(null);
40 | });
41 | }
42 |
43 | @Test
44 | public void readMetadataFile_didFailWithJsonParsing() {
45 | FilePath filePath = Mockito.mock(FilePath.class);
46 |
47 | MockedStatic fileReader = Mockito.mockStatic(FileReader.class, Mockito.CALLS_REAL_METHODS);
48 | StringInputStream inputStream = new StringInputStream("{" +
49 | "\"api catalog version\": 1," +
50 | "\"failure\":" +
51 | "{\"name\":\"name\"," +
52 | "\"visibility\":\"visibility\"," +
53 | "\"description\":\"description\"," +
54 | "\"api version\":\"apiVersion\"," +
55 | "\"release status\":\"releaseStatus\"," +
56 | "\"system identifier\":\"systemIdentifier\"," +
57 | "\"documentation\":[\"url1\",\"url2\"]," +
58 | "\"interface specification\":\"interfaceSpecification\"," +
59 | "\"interface description language\":\"interfaceDescriptionLanguage\"," +
60 | "\"architecture layer\":\"architectureLayer\"," +
61 | "\"business unit\":\"businessUnit\"}}}"
62 | );
63 | fileReader.when(() -> FileReader.readFileInDirectory(any())).thenReturn(inputStream);
64 |
65 | Assert.assertThrows(io.apimap.plugin.jenkins.exceptions.FileUnreadableException.class,
66 | ()->{
67 | MetadataFile object = FileReader.metadataFile(filePath);
68 | fileReader.close();
69 |
70 | });
71 | }
72 |
73 | @Test
74 | public void readMetadataFile_didSucceed() throws MissingRequiredFieldException, IOException, InterruptedException, UnsupportedVersionException, FileUnreadableException {
75 | FilePath filePath = Mockito.mock(FilePath.class);
76 |
77 | MockedStatic fileReader = Mockito.mockStatic(FileReader.class, Mockito.CALLS_REAL_METHODS);
78 | StringInputStream inputStream = new StringInputStream("{" +
79 | "\"api catalog version\": 1," +
80 | "\"data\":" +
81 | "{\"name\":\"name\"," +
82 | "\"visibility\":\"visibility\"," +
83 | "\"description\":\"description\"," +
84 | "\"api version\":\"apiVersion\"," +
85 | "\"release status\":\"releaseStatus\"," +
86 | "\"system identifier\":\"systemIdentifier\"," +
87 | "\"documentation\":[\"url1\",\"url2\"]," +
88 | "\"interface specification\":\"interfaceSpecification\"," +
89 | "\"interface description language\":\"interfaceDescriptionLanguage\"," +
90 | "\"architecture layer\":\"architectureLayer\"," +
91 | "\"business unit\":\"businessUnit\"}}}"
92 | );
93 | fileReader.when(() -> FileReader.readFileInDirectory(any())).thenReturn(inputStream);
94 |
95 | MetadataFile object = FileReader.metadataFile(filePath);
96 | fileReader.close();
97 |
98 | assertEquals("name", object.getData().getName());
99 | assertEquals("visibility", object.getData().getVisibility());
100 | assertEquals("description", object.getData().getDescription());
101 | assertEquals("apiVersion", object.getData().getApiVersion());
102 | assertEquals("releaseStatus", object.getData().getReleaseStatus());
103 | assertEquals("systemIdentifier", object.getData().getSystemIdentifier());
104 | assertEquals("interfaceSpecification", object.getData().getInterfaceSpecification());
105 | assertEquals("interfaceDescriptionLanguage", object.getData().getInterfaceDescriptionLanguage());
106 | assertEquals("architectureLayer", object.getData().getArchitectureLayer());
107 | assertEquals("businessUnit", object.getData().getBusinessUnit());
108 | }
109 |
110 | //-
111 | @Test
112 | public void readTaxonomyFile_didFailWithJsonParsing() {
113 | FilePath filePath = Mockito.mock(FilePath.class);
114 |
115 | MockedStatic fileReader = Mockito.mockStatic(FileReader.class, Mockito.CALLS_REAL_METHODS);
116 | StringInputStream inputStream = new StringInputStream("{" +
117 | "\"api catalog version\": 1," +
118 | "\"failure\":" +
119 | "{\"taxonomy\": \"apimap\"," +
120 | "\"classifications\": [\"urn:apimap:1\"]}}}"
121 | );
122 | fileReader.when(() -> FileReader.readFileInDirectory(any())).thenReturn(inputStream);
123 | fileReader.close();
124 |
125 | Assert.assertThrows(io.apimap.plugin.jenkins.exceptions.FileUnreadableException.class,
126 | ()->{
127 | TaxonomyFile object = FileReader.taxonomyFile(filePath);
128 | fileReader.close();
129 |
130 | });
131 | }
132 |
133 | @Test
134 | public void readTaxonomyFile_didSucceed() throws MissingRequiredFieldException, IOException, InterruptedException, UnsupportedVersionException, FileUnreadableException {
135 | FilePath filePath = Mockito.mock(FilePath.class);
136 |
137 | MockedStatic fileReader = Mockito.mockStatic(FileReader.class, Mockito.CALLS_REAL_METHODS);
138 | StringInputStream inputStream = new StringInputStream("{" +
139 | "\"api catalog version\": 1," +
140 | "\"data\":" +
141 | "{\"taxonomy\": \"apimap\", \"classifications\": [\"urn:apimap:1\"]}}}"
142 | );
143 | fileReader.when(() -> FileReader.readFileInDirectory(any())).thenReturn(inputStream);
144 |
145 | TaxonomyFile object = FileReader.taxonomyFile(filePath);
146 | fileReader.close();
147 |
148 | assertEquals("apimap", object.getData().getTaxonomy());
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 |
7 | org.jenkins-ci.plugins
8 | plugin
9 | 4.41
10 |
11 |
12 |
13 |
14 |
15 | Apache License, Version 2.0
16 | http://www.apache.org/licenses/LICENSE-2.0.txt
17 | repo
18 |
19 |
20 |
21 |
22 |
23 | msulland
24 | Magnus Sulland
25 | magnus@apperiet.no
26 |
27 | maintainer
28 |
29 |
30 |
31 |
32 | io.jenkins.plugins
33 | apimap
34 | Apimap.io
35 | ${revision}${changelist}
36 | hpi
37 | Enables automated publishing of API metadata to your Apimap.io instance
38 | https://github.com/jenkinsci/apimap-plugin
39 |
40 |
41 | 1
42 | -SNAPSHOT
43 | 2.300
44 | UTF-8
45 | 3.0.5
46 | true
47 |
48 |
49 |
50 |
51 |
52 | org.jenkins-ci.tools
53 | maven-hpi-plugin
54 |
55 | true
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | org.jenkins-ci.plugins.workflow
64 | workflow-step-api
65 | 2.24
66 |
67 |
68 | org.jenkins-ci.plugins
69 | script-security
70 | 1.78
71 |
72 |
73 | org.apache.httpcomponents.client5
74 | httpclient5
75 | 5.1.3
76 |
77 |
78 | org.mockito
79 | mockito-core
80 | 4.6.1
81 | test
82 |
83 |
84 | com.fasterxml.jackson.core
85 | jackson-databind
86 | 2.13.2.1
87 |
88 |
89 | javax.json.bind
90 | javax.json.bind-api
91 | 1.0
92 |
93 |
94 | javax.json
95 | javax.json-api
96 | 1.1.4
97 |
98 |
99 | javax.servlet
100 | javax.servlet-api
101 | 4.0.1
102 |
103 |
104 | commons-io
105 | commons-io
106 | 2.11.0
107 |
108 |
109 | io.jenkins.tools.bom
110 | bom-2.303.x
111 | 950.v396cb834de1e
112 | pom
113 |
114 |
115 | io.apimap.client
116 | rest-client
117 | 3.0.1
118 |
119 |
120 | io.apimap.file
121 | file-interface
122 | 1.0
123 |
124 |
125 | io.apimap.api
126 | rest-interface
127 | 2.2.0
128 |
129 |
130 | org.jenkins-ci.main
131 | jenkins-core
132 | 2.319.2
133 |
134 |
135 | org.mockito
136 | mockito-inline
137 | 4.0.0
138 | test
139 |
140 |
141 |
142 |
143 |
144 | lib-rest-client
145 | REST Client
146 | file:///${project.basedir}/lib
147 | default
148 |
149 | true
150 | always
151 |
152 |
153 | true
154 | never
155 |
156 |
157 |
158 | lib-file-interface
159 | File Interface
160 | file:///${project.basedir}/lib
161 | default
162 |
163 | true
164 | always
165 |
166 |
167 | true
168 | never
169 |
170 |
171 |
172 | lib-rest-interface
173 | REST Interface
174 | file:///${project.basedir}/lib
175 | default
176 |
177 | true
178 | always
179 |
180 |
181 | true
182 | never
183 |
184 |
185 |
186 | repo.jenkins-ci.org
187 | Jenkins CI
188 | https://repo.jenkins-ci.org/public/
189 | default
190 |
191 |
192 | repo.maven.apache.org
193 | Central Repository
194 | https://repo.maven.apache.org/maven2/
195 | default
196 |
197 |
198 |
199 |
200 |
201 | repo.jenkins-ci.org
202 | https://repo.jenkins-ci.org/public/
203 |
204 |
205 |
206 |
207 |
--------------------------------------------------------------------------------
/mvnw:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # ----------------------------------------------------------------------------
3 | # Licensed to the Apache Software Foundation (ASF) under one
4 | # or more contributor license agreements. See the NOTICE file
5 | # distributed with this work for additional information
6 | # regarding copyright ownership. The ASF licenses this file
7 | # to you under the Apache License, Version 2.0 (the
8 | # "License"); you may not use this file except in compliance
9 | # with the License. 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,
14 | # software distributed under the License is distributed on an
15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | # KIND, either express or implied. See the License for the
17 | # specific language governing permissions and limitations
18 | # under the License.
19 | # ----------------------------------------------------------------------------
20 |
21 | # ----------------------------------------------------------------------------
22 | # Maven2 Start Up Batch script
23 | #
24 | # Required ENV vars:
25 | # ------------------
26 | # JAVA_HOME - location of a JDK home dir
27 | #
28 | # Optional ENV vars
29 | # -----------------
30 | # M2_HOME - location of maven2's installed home dir
31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven
32 | # e.g. to debug Maven itself, use
33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files
35 | # ----------------------------------------------------------------------------
36 |
37 | if [ -z "$MAVEN_SKIP_RC" ] ; then
38 |
39 | if [ -f /etc/mavenrc ] ; then
40 | . /etc/mavenrc
41 | fi
42 |
43 | if [ -f "$HOME/.mavenrc" ] ; then
44 | . "$HOME/.mavenrc"
45 | fi
46 |
47 | fi
48 |
49 | # OS specific support. $var _must_ be set to either true or false.
50 | cygwin=false;
51 | darwin=false;
52 | mingw=false
53 | case "`uname`" in
54 | CYGWIN*) cygwin=true ;;
55 | MINGW*) mingw=true;;
56 | Darwin*) darwin=true
57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
59 | if [ -z "$JAVA_HOME" ]; then
60 | if [ -x "/usr/libexec/java_home" ]; then
61 | export JAVA_HOME="`/usr/libexec/java_home`"
62 | else
63 | export JAVA_HOME="/Library/Java/Home"
64 | fi
65 | fi
66 | ;;
67 | esac
68 |
69 | if [ -z "$JAVA_HOME" ] ; then
70 | if [ -r /etc/gentoo-release ] ; then
71 | JAVA_HOME=`java-config --jre-home`
72 | fi
73 | fi
74 |
75 | if [ -z "$M2_HOME" ] ; then
76 | ## resolve links - $0 may be a link to maven's home
77 | PRG="$0"
78 |
79 | # need this for relative symlinks
80 | while [ -h "$PRG" ] ; do
81 | ls=`ls -ld "$PRG"`
82 | link=`expr "$ls" : '.*-> \(.*\)$'`
83 | if expr "$link" : '/.*' > /dev/null; then
84 | PRG="$link"
85 | else
86 | PRG="`dirname "$PRG"`/$link"
87 | fi
88 | done
89 |
90 | saveddir=`pwd`
91 |
92 | M2_HOME=`dirname "$PRG"`/..
93 |
94 | # make it fully qualified
95 | M2_HOME=`cd "$M2_HOME" && pwd`
96 |
97 | cd "$saveddir"
98 | # echo Using m2 at $M2_HOME
99 | fi
100 |
101 | # For Cygwin, ensure paths are in UNIX format before anything is touched
102 | if $cygwin ; then
103 | [ -n "$M2_HOME" ] &&
104 | M2_HOME=`cygpath --unix "$M2_HOME"`
105 | [ -n "$JAVA_HOME" ] &&
106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
107 | [ -n "$CLASSPATH" ] &&
108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
109 | fi
110 |
111 | # For Mingw, ensure paths are in UNIX format before anything is touched
112 | if $mingw ; then
113 | [ -n "$M2_HOME" ] &&
114 | M2_HOME="`(cd "$M2_HOME"; pwd)`"
115 | [ -n "$JAVA_HOME" ] &&
116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
117 | # TODO classpath?
118 | fi
119 |
120 | if [ -z "$JAVA_HOME" ]; then
121 | javaExecutable="`which javac`"
122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
123 | # readlink(1) is not available as standard on Solaris 10.
124 | readLink=`which readlink`
125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
126 | if $darwin ; then
127 | javaHome="`dirname \"$javaExecutable\"`"
128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
129 | else
130 | javaExecutable="`readlink -f \"$javaExecutable\"`"
131 | fi
132 | javaHome="`dirname \"$javaExecutable\"`"
133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'`
134 | JAVA_HOME="$javaHome"
135 | export JAVA_HOME
136 | fi
137 | fi
138 | fi
139 |
140 | if [ -z "$JAVACMD" ] ; then
141 | if [ -n "$JAVA_HOME" ] ; then
142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
143 | # IBM's JDK on AIX uses strange locations for the executables
144 | JAVACMD="$JAVA_HOME/jre/sh/java"
145 | else
146 | JAVACMD="$JAVA_HOME/bin/java"
147 | fi
148 | else
149 | JAVACMD="`which java`"
150 | fi
151 | fi
152 |
153 | if [ ! -x "$JAVACMD" ] ; then
154 | echo "Error: JAVA_HOME is not defined correctly." >&2
155 | echo " We cannot execute $JAVACMD" >&2
156 | exit 1
157 | fi
158 |
159 | if [ -z "$JAVA_HOME" ] ; then
160 | echo "Warning: JAVA_HOME environment variable is not set."
161 | fi
162 |
163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
164 |
165 | # traverses directory structure from process work directory to filesystem root
166 | # first directory with .mvn subdirectory is considered project base directory
167 | find_maven_basedir() {
168 |
169 | if [ -z "$1" ]
170 | then
171 | echo "Path not specified to find_maven_basedir"
172 | return 1
173 | fi
174 |
175 | basedir="$1"
176 | wdir="$1"
177 | while [ "$wdir" != '/' ] ; do
178 | if [ -d "$wdir"/.mvn ] ; then
179 | basedir=$wdir
180 | break
181 | fi
182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc)
183 | if [ -d "${wdir}" ]; then
184 | wdir=`cd "$wdir/.."; pwd`
185 | fi
186 | # end of workaround
187 | done
188 | echo "${basedir}"
189 | }
190 |
191 | # concatenates all lines of a file
192 | concat_lines() {
193 | if [ -f "$1" ]; then
194 | echo "$(tr -s '\n' ' ' < "$1")"
195 | fi
196 | }
197 |
198 | BASE_DIR=`find_maven_basedir "$(pwd)"`
199 | if [ -z "$BASE_DIR" ]; then
200 | exit 1;
201 | fi
202 |
203 | ##########################################################################################
204 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
205 | # This allows using the maven wrapper in projects that prohibit checking in binary data.
206 | ##########################################################################################
207 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
208 | if [ "$MVNW_VERBOSE" = true ]; then
209 | echo "Found .mvn/wrapper/maven-wrapper.jar"
210 | fi
211 | else
212 | if [ "$MVNW_VERBOSE" = true ]; then
213 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
214 | fi
215 | jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
216 | while IFS="=" read key value; do
217 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
218 | esac
219 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
220 | if [ "$MVNW_VERBOSE" = true ]; then
221 | echo "Downloading from: $jarUrl"
222 | fi
223 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
224 |
225 | if command -v wget > /dev/null; then
226 | if [ "$MVNW_VERBOSE" = true ]; then
227 | echo "Found wget ... using wget"
228 | fi
229 | wget "$jarUrl" -O "$wrapperJarPath"
230 | elif command -v curl > /dev/null; then
231 | if [ "$MVNW_VERBOSE" = true ]; then
232 | echo "Found curl ... using curl"
233 | fi
234 | curl -o "$wrapperJarPath" "$jarUrl"
235 | else
236 | if [ "$MVNW_VERBOSE" = true ]; then
237 | echo "Falling back to using Java to download"
238 | fi
239 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
240 | if [ -e "$javaClass" ]; then
241 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
242 | if [ "$MVNW_VERBOSE" = true ]; then
243 | echo " - Compiling MavenWrapperDownloader.java ..."
244 | fi
245 | # Compiling the Java class
246 | ("$JAVA_HOME/bin/javac" "$javaClass")
247 | fi
248 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
249 | # Running the downloader
250 | if [ "$MVNW_VERBOSE" = true ]; then
251 | echo " - Running MavenWrapperDownloader.java ..."
252 | fi
253 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
254 | fi
255 | fi
256 | fi
257 | fi
258 | ##########################################################################################
259 | # End of extension
260 | ##########################################################################################
261 |
262 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
263 | if [ "$MVNW_VERBOSE" = true ]; then
264 | echo $MAVEN_PROJECTBASEDIR
265 | fi
266 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
267 |
268 | # For Cygwin, switch paths to Windows format before running java
269 | if $cygwin; then
270 | [ -n "$M2_HOME" ] &&
271 | M2_HOME=`cygpath --path --windows "$M2_HOME"`
272 | [ -n "$JAVA_HOME" ] &&
273 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
274 | [ -n "$CLASSPATH" ] &&
275 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
276 | [ -n "$MAVEN_PROJECTBASEDIR" ] &&
277 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
278 | fi
279 |
280 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
281 |
282 | exec "$JAVACMD" \
283 | $MAVEN_OPTS \
284 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
285 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
286 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
287 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright 2020 TELENOR NORGE AS
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/src/main/java/io/apimap/plugin/jenkins/step/publish/PublishStepExecution.java:
--------------------------------------------------------------------------------
1 | /*
2 | Licensed to the Apache Software Foundation (ASF) under one
3 | or more contributor license agreements. See the NOTICE file
4 | distributed with this work for additional information
5 | regarding copyright ownership. The ASF licenses this file
6 | to you under the Apache License, Version 2.0 (the
7 | "License"); you may not use this file except in compliance
8 | with the License. You may obtain a copy of the License at
9 |
10 | http://www.apache.org/licenses/LICENSE-2.0
11 |
12 | Unless required by applicable law or agreed to in writing,
13 | software distributed under the License is distributed on an
14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | KIND, either express or implied. See the License for the
16 | specific language governing permissions and limitations
17 | under the License.
18 | */
19 |
20 | package io.apimap.plugin.jenkins.step.publish;
21 |
22 | import hudson.FilePath;
23 | import hudson.model.Result;
24 | import io.apimap.api.rest.ApiDataRestEntity;
25 | import io.apimap.api.rest.ApiVersionDataRestEntity;
26 | import io.apimap.api.rest.ClassificationDataRestEntity;
27 | import io.apimap.api.rest.ClassificationRootRestEntity;
28 | import io.apimap.api.rest.MetadataDataRestEntity;
29 | import io.apimap.api.rest.jsonapi.JsonApiRestResponseWrapper;
30 | import io.apimap.client.IRestClient;
31 | import io.apimap.client.RestClientConfiguration;
32 | import io.apimap.client.exception.IncorrectTokenException;
33 | import io.apimap.file.metadata.MetadataFile;
34 | import io.apimap.file.taxonomy.TaxonomyFile;
35 | import io.apimap.plugin.jenkins.ApiMap;
36 | import io.apimap.plugin.jenkins.exceptions.IncorrectFileTypeException;
37 | import io.apimap.plugin.jenkins.exceptions.PublishErrorException;
38 | import io.apimap.plugin.jenkins.output.PublishResult;
39 | import io.apimap.plugin.jenkins.step.PublishStep;
40 | import io.apimap.plugin.jenkins.utils.FileReader;
41 | import io.apimap.plugin.jenkins.utils.RestClientUtil;
42 | import jenkins.model.Jenkins;
43 | import org.apache.commons.lang.mutable.MutableBoolean;
44 | import org.apache.hc.core5.http.ContentType;
45 | import org.jenkinsci.plugins.workflow.steps.StepContext;
46 | import org.jenkinsci.plugins.workflow.steps.SynchronousStepExecution;
47 |
48 | import java.io.FileNotFoundException;
49 | import java.io.IOException;
50 | import java.util.ArrayList;
51 | import java.util.concurrent.atomic.AtomicReference;
52 | import java.util.function.Consumer;
53 | import java.util.logging.Level;
54 | import java.util.logging.Logger;
55 | import java.util.stream.Collectors;
56 |
57 | public class PublishStepExecution extends SynchronousStepExecution {
58 | private static final Logger LOGGER = Logger.getLogger(PublishStepExecution.class.getName());
59 |
60 | public static final String FILEPATH_IS_A_NULL_OBJECT = "Filepath returned as a null object";
61 | public static final String METADATA_FILE_MISSING_ERROR = "Unable to read metadata file";
62 | public static final String TAXONOMY_FILE_MISSING_ERROR = "Unable to read taxonomy file";
63 | public static final String README_FILE_MISSING_ERROR = "Unable to read README.md file";
64 | public static final String CHANGELOG_FILE_MISSING_ERROR = "Unable to read CHANGELOG.md file";
65 | public static final String UNABLE_TO_UPLOAD_METADATA_ERROR_MESSAGE = "Unable to upload metadata. Please contact your system administrator";
66 | public static final String UNABLE_TO_UPLOAD_TAXONOMY_ERROR_MESSAGE = "Unable to upload taxonomy classifications. Please contact your system administrator";
67 | public static final String UNABLE_TO_UPLOAD_README_ERROR_MESSAGE = "Unable to upload README.md classifications. Please contact your system administrator";
68 | public static final String UNABLE_TO_UPLOAD_CHANGELOG_ERROR_MESSAGE = "Unable to upload CHANGELOG.md classifications. Please contact your system administrator";
69 | public static final String MISSING_OR_INVALID_API_TOKEN_ERROR_MESSAGE = "Unable to find correct API token";
70 | public static final String STEP_COMPLETED_SUCCESSFULLY = "Successfully published information";
71 | public static final String MARKDOWN_FILE_FORMAT_REQUIRED = "File must be of type markdown, ending with .md";
72 |
73 |
74 | private static final long serialVersionUID = 1L;
75 |
76 | private final PublishStep step;
77 |
78 | public PublishStepExecution(final PublishStep step,
79 | final StepContext context){
80 | super(context);
81 | this.step = step;
82 | }
83 |
84 | protected PublishResult failure(final String description,
85 | final String token){
86 | final ApiMap.ApiMapDescriptorImpl descImpl = (ApiMap.ApiMapDescriptorImpl) Jenkins.getInstance().getDescriptorByName(ApiMap.class.getName());
87 |
88 | if (descImpl.updateBuildStatus()) {
89 | getContext().setResult(Result.FAILURE);
90 | getContext().onFailure(new IOException(description));
91 | }
92 |
93 | return new PublishResult(PublishResult.Status.FAILED, description, token);
94 | }
95 |
96 | protected PublishResult success(final String description,
97 | final String token,
98 | final MutableBoolean isApiCreate){
99 | final ApiMap.ApiMapDescriptorImpl descImpl = (ApiMap.ApiMapDescriptorImpl) Jenkins.getInstance().getDescriptorByName(ApiMap.class.getName());
100 |
101 | PublishResult returnValue;
102 |
103 | if(isApiCreate.isTrue()) {
104 | returnValue = new PublishResult(PublishResult.Status.CREATED, description, token);
105 | }else{
106 | returnValue = new PublishResult(PublishResult.Status.UPDATED, description);
107 | }
108 |
109 | if(descImpl.updateBuildStatus()) {
110 | getContext().setResult(Result.SUCCESS);
111 | getContext().onSuccess(returnValue);
112 | }
113 |
114 | return returnValue;
115 | }
116 |
117 | @Override
118 | protected PublishResult run() throws Exception {
119 | /*
120 | * Global
121 | */
122 | final ApiMap.ApiMapDescriptorImpl descImpl = (ApiMap.ApiMapDescriptorImpl) Jenkins.getInstance().getDescriptorByName(ApiMap.class.getName());
123 |
124 | final FilePath path = getContext().get(FilePath.class);
125 | if(path == null) { return failure(FILEPATH_IS_A_NULL_OBJECT, null); }
126 |
127 | final RestClientConfiguration configuration;
128 |
129 | LOGGER.log(Level.FINER, "Reading metadata file");
130 |
131 | final MutableBoolean isApiCreated = new MutableBoolean(false);
132 |
133 | LOGGER.log(Level.FINER, "Creating rest client configuration");
134 | configuration = RestClientUtil.configuration(this.step.getToken());
135 |
136 | /*
137 | * Metadata
138 | */
139 |
140 | final MetadataFile metadataFile;
141 |
142 | try {
143 | metadataFile = FileReader.metadataFile(FileReader.filePath(path, this.step.getMetadataFile()));
144 | if (metadataFile == null) {
145 | return failure(METADATA_FILE_MISSING_ERROR, configuration.getToken());
146 | }
147 |
148 | LOGGER.log(Level.FINER, "Uploading metadata content");
149 | final MetadataDataRestEntity metadataReturnObject = uploadMetadata(metadataFile, configuration, isApiCreated);
150 | if (metadataReturnObject == null) {
151 | return failure(UNABLE_TO_UPLOAD_METADATA_ERROR_MESSAGE, configuration.getToken());
152 | }
153 | } catch (FileNotFoundException e){
154 | LOGGER.log(Level.FINE, e.getMessage());
155 | return failure(METADATA_FILE_MISSING_ERROR, configuration.getToken());
156 | } catch (IOException e) {
157 | LOGGER.log(Level.FINE, e.getMessage());
158 | return failure(UNABLE_TO_UPLOAD_METADATA_ERROR_MESSAGE, configuration.getToken());
159 | } catch (IncorrectTokenException e) {
160 | LOGGER.log(Level.FINE, e.getMessage());
161 | return failure(MISSING_OR_INVALID_API_TOKEN_ERROR_MESSAGE, configuration.getToken());
162 | } catch (PublishErrorException e){
163 | LOGGER.log(Level.FINE, e.getMessage());
164 | return failure(e.getMessage(), configuration.getToken());
165 | }
166 |
167 | /*
168 | * Taxonomy
169 | */
170 |
171 | LOGGER.log(Level.FINER, "Reading taxonomy file");
172 |
173 | try {
174 | final TaxonomyFile taxonomyFile = FileReader.taxonomyFile(FileReader.filePath(path, this.step.getTaxonomyFile()));
175 | if (taxonomyFile == null) { return failure(TAXONOMY_FILE_MISSING_ERROR, configuration.getToken()); }
176 |
177 | LOGGER.log(Level.FINER, "Uploading taxonomy content");
178 | final ClassificationRootRestEntity classificationReturnObject = uploadTaxonomy(
179 | metadataFile.getData().getName(),
180 | metadataFile.getData().getApiVersion(),
181 | taxonomyFile,
182 | configuration
183 | );
184 | if (classificationReturnObject == null) { return failure(UNABLE_TO_UPLOAD_TAXONOMY_ERROR_MESSAGE, configuration.getToken()); }
185 | } catch (FileNotFoundException e){
186 | LOGGER.log(Level.FINE, e.getMessage());
187 | return failure(TAXONOMY_FILE_MISSING_ERROR, configuration.getToken());
188 | } catch (IncorrectTokenException e) {
189 | LOGGER.log(Level.FINE, e.getMessage());
190 | return failure(MISSING_OR_INVALID_API_TOKEN_ERROR_MESSAGE, configuration.getToken());
191 | } catch (Exception e) {
192 | LOGGER.log(Level.FINE, e.getMessage());
193 | return failure(UNABLE_TO_UPLOAD_TAXONOMY_ERROR_MESSAGE, configuration.getToken());
194 | }
195 |
196 | /*
197 | * Readme.md
198 | */
199 |
200 | if(descImpl.isAllowReadmeUpload() && this.step.getReadmeFile() != null && !this.step.getReadmeFile().isEmpty()){
201 | try{
202 | final String readme = FileReader.readDocument(FileReader.filePath(path, this.step.getReadmeFile()));
203 | if (readme == null) { return failure(README_FILE_MISSING_ERROR, configuration.getToken()); }
204 |
205 | LOGGER.log(Level.FINER, "Uploading README.md content");
206 | final String readmeReturnObject = uploadReadme(
207 | metadataFile.getData().getName(),
208 | metadataFile.getData().getApiVersion(),
209 | readme,
210 | configuration
211 | );
212 | if (readmeReturnObject == null) { return failure(UNABLE_TO_UPLOAD_README_ERROR_MESSAGE, configuration.getToken()); }
213 | } catch (IncorrectFileTypeException e){
214 | LOGGER.log(Level.FINE, e.getMessage());
215 | return failure(MARKDOWN_FILE_FORMAT_REQUIRED, configuration.getToken());
216 | } catch (FileNotFoundException e){
217 | LOGGER.log(Level.FINE, e.getMessage());
218 | return failure(README_FILE_MISSING_ERROR, configuration.getToken());
219 | } catch (IncorrectTokenException e) {
220 | LOGGER.log(Level.FINE, e.getMessage());
221 | return failure(MISSING_OR_INVALID_API_TOKEN_ERROR_MESSAGE, configuration.getToken());
222 | } catch (Exception e) {
223 | LOGGER.log(Level.FINE, e.getMessage());
224 | return failure(UNABLE_TO_UPLOAD_README_ERROR_MESSAGE, configuration.getToken());
225 | }
226 | }
227 |
228 | /*
229 | * Changelog.md
230 | */
231 |
232 | if(descImpl.isAllowChangelogUpload() && this.step.getChangelogFile() != null && !this.step.getChangelogFile().isEmpty()){
233 | try{
234 | final String changelog = FileReader.readDocument(FileReader.filePath(path, this.step.getChangelogFile()));
235 | if (changelog == null) { return failure(README_FILE_MISSING_ERROR, configuration.getToken()); }
236 |
237 | LOGGER.log(Level.FINER, "Uploading CHANGELOG.md content");
238 | final String readmeReturnObject = uploadChangelog(
239 | metadataFile.getData().getName(),
240 | metadataFile.getData().getApiVersion(),
241 | changelog,
242 | configuration
243 | );
244 | if (readmeReturnObject == null) { return failure(UNABLE_TO_UPLOAD_CHANGELOG_ERROR_MESSAGE, configuration.getToken()); }
245 | } catch (IncorrectFileTypeException e){
246 | LOGGER.log(Level.FINE, e.getMessage());
247 | return failure(MARKDOWN_FILE_FORMAT_REQUIRED, configuration.getToken());
248 | } catch (FileNotFoundException e){
249 | LOGGER.log(Level.FINE, e.getMessage());
250 | return failure(CHANGELOG_FILE_MISSING_ERROR, configuration.getToken());
251 | } catch (IncorrectTokenException e) {
252 | LOGGER.log(Level.FINE, e.getMessage());
253 | return failure(MISSING_OR_INVALID_API_TOKEN_ERROR_MESSAGE, configuration.getToken());
254 | } catch (Exception e) {
255 | LOGGER.log(Level.FINE, e.getMessage());
256 | return failure(UNABLE_TO_UPLOAD_CHANGELOG_ERROR_MESSAGE, configuration.getToken());
257 | }
258 | }
259 |
260 | return success(STEP_COMPLETED_SUCCESSFULLY, configuration.getToken(), isApiCreated);
261 | }
262 |
263 | protected MetadataDataRestEntity uploadMetadata(final MetadataFile metadataFile,
264 | final RestClientConfiguration configuration,
265 | final MutableBoolean isApiCreated) throws IOException, InterruptedException, IncorrectTokenException, PublishErrorException {
266 | /* Assemble REST entities */
267 | LOGGER.log(Level.FINER, "Assembling REST entities");
268 |
269 | final MetadataDataRestEntity metadataDataApiEntity = new MetadataDataRestEntity(
270 | metadataFile.getData().getName(),
271 | metadataFile.getData().getDescription(),
272 | metadataFile.getData().getVisibility(),
273 | metadataFile.getData().getApiVersion(),
274 | metadataFile.getData().getReleaseStatus(),
275 | metadataFile.getData().getInterfaceSpecification(),
276 | metadataFile.getData().getInterfaceDescriptionLanguage(),
277 | metadataFile.getData().getArchitectureLayer(),
278 | metadataFile.getData().getBusinessUnit(),
279 | metadataFile.getData().getSystemIdentifier(),
280 | metadataFile.getData().getDocumentation()
281 | );
282 |
283 | final ApiDataRestEntity apiDataApiEntity = new ApiDataRestEntity(
284 | metadataFile.getData().getName(),
285 | this.step.getRepositoryURL()
286 | );
287 |
288 | final ApiVersionDataRestEntity apiVersionDataApiEntity = new ApiVersionDataRestEntity(
289 | metadataDataApiEntity.getApiVersion()
290 | );
291 |
292 | /* Setup callback methods */
293 | LOGGER.log(Level.FINER, "Creating callback methods");
294 |
295 | final Consumer