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

common-workflow-language / cwlviewer / #1790

29 Mar 2025 08:39PM UTC coverage: 70.306%. Remained the same
#1790

push

github

kinow
Add org.apache.commons:commons-lang3, 3.17.0 as it's now required by liquibase 4.30.0+

1700 of 2418 relevant lines covered (70.31%)

0.7 hits per line

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

73.97
/src/main/java/org/commonwl/view/workflow/WorkflowJSONController.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 org.commonwl.view.workflow;
21

22
import static org.commonwl.view.cwl.CWLToolStatus.SUCCESS;
23

24
import jakarta.servlet.http.HttpServletRequest;
25
import jakarta.servlet.http.HttpServletResponse;
26
import java.util.*;
27
import org.commonwl.view.cwl.CWLValidationException;
28
import org.commonwl.view.git.GitDetails;
29
import org.springframework.beans.factory.annotation.Autowired;
30
import org.springframework.data.domain.Page;
31
import org.springframework.data.domain.Pageable;
32
import org.springframework.data.web.PageableDefault;
33
import org.springframework.http.HttpStatus;
34
import org.springframework.http.MediaType;
35
import org.springframework.http.ResponseEntity;
36
import org.springframework.ui.Model;
37
import org.springframework.validation.BeanPropertyBindingResult;
38
import org.springframework.web.bind.annotation.*;
39
import org.springframework.web.servlet.HandlerMapping;
40

41
/** JSON API Controller */
42
@RestController
43
public class WorkflowJSONController {
44

45
  private final WorkflowFormValidator workflowFormValidator;
46
  private final WorkflowService workflowService;
47

48
  /**
49
   * Autowired constructor to initialise objects used by the controller
50
   *
51
   * @param workflowFormValidator Validator to validate the workflow form
52
   * @param workflowService Builds new Workflow objects
53
   */
54
  @Autowired
55
  public WorkflowJSONController(
56
      WorkflowFormValidator workflowFormValidator, WorkflowService workflowService) {
1✔
57
    this.workflowFormValidator = workflowFormValidator;
1✔
58
    this.workflowService = workflowService;
1✔
59
  }
1✔
60

61
  /**
62
   * List all the workflows in the database, paginated
63
   *
64
   * @return A list of all the workflows
65
   */
66
  @GetMapping(value = "/workflows", produces = MediaType.APPLICATION_JSON_VALUE)
67
  public Page<Workflow> listWorkflowsJson(
68
      Model model, @PageableDefault(size = 10) Pageable pageable) {
69
    return workflowService.getPageOfWorkflows(pageable);
×
70
  }
71

72
  /**
73
   * Search all workflows for a string in the label or doc
74
   *
75
   * @return A list of all the workflows
76
   */
77
  @GetMapping(value = "/workflows", params = "search", produces = MediaType.APPLICATION_JSON_VALUE)
78
  public Page<Workflow> searchWorkflowsJson(
79
      Model model,
80
      @PageableDefault(size = 10) Pageable pageable,
81
      @RequestParam(value = "search") String search) {
82
    return workflowService.searchPageOfWorkflows(search, pageable);
×
83
  }
84

85
  /**
86
   * Create a new workflow from the given URL
87
   *
88
   * @param url The URL of the workflow
89
   * @param branch The branch where the workflow can be found
90
   * @param path The path within the repository to the workflow file
91
   * @param packedId The ID of the workflow if the file is packed
92
   * @return Appropriate response code and optional JSON string with message
93
   */
94
  @PostMapping(value = "/workflows", produces = MediaType.APPLICATION_JSON_VALUE)
95
  public ResponseEntity<?> newWorkflowFromGitURLJson(
96
      @RequestParam(value = "url") String url,
97
      @RequestParam(value = "branch", required = false) String branch,
98
      @RequestParam(value = "path", required = false) String path,
99
      @RequestParam(value = "packedId", required = false) String packedId,
100
      HttpServletResponse response) {
101

102
    // Run validator which checks the URL is valid
103
    WorkflowForm workflowForm = new WorkflowForm(url, branch, path, packedId);
1✔
104
    BeanPropertyBindingResult errors = new BeanPropertyBindingResult(workflowForm, "errors");
1✔
105
    GitDetails gitInfo = workflowFormValidator.validateAndParse(workflowForm, errors);
1✔
106

107
    if (errors.hasErrors() || gitInfo == null) {
1✔
108
      String error;
109
      if (errors.hasErrors()) {
1✔
110
        error = errors.getAllErrors().get(0).getDefaultMessage();
×
111
      } else {
112
        error = "Could not parse workflow details from URL";
1✔
113
      }
114
      Map<String, String> message = Collections.singletonMap("message", "Error: " + error);
1✔
115
      return new ResponseEntity<Map<String, String>>(message, HttpStatus.BAD_REQUEST);
1✔
116
    } else {
117
      // Get workflow or create if does not exist
118
      Workflow workflow = workflowService.getWorkflow(gitInfo);
1✔
119
      if (workflow == null) {
1✔
120
        // Check if already queued
121
        QueuedWorkflow queued = workflowService.getQueuedWorkflow(gitInfo);
1✔
122
        if (queued == null) {
1✔
123
          try {
124
            queued = workflowService.createQueuedWorkflow(gitInfo);
1✔
125
            if (queued.getWorkflowList() != null) {
1✔
126
              if (queued.getWorkflowList().size() == 1) {
1✔
127
                // Parse the packed workflow within automatically if there is only one
128
                gitInfo.setPackedId(queued.getWorkflowList().get(0).getFileName());
×
129
                queued = workflowService.getQueuedWorkflow(gitInfo);
×
130
                if (queued == null) {
×
131
                  queued = workflowService.createQueuedWorkflow(gitInfo);
×
132
                }
133
              } else {
134
                // Error with alternatives suggested
135
                List<String> workflowUris = new ArrayList<>();
1✔
136
                for (WorkflowOverview overview : queued.getWorkflowList()) {
1✔
137
                  workflowUris.add(overview.getFileName().substring(1));
1✔
138
                }
1✔
139
                Map<String, Object> responseMap = new HashMap<>();
1✔
140
                responseMap.put(
1✔
141
                    "message",
142
                    "This workflow file is packed and contains multiple workflow "
143
                        + "descriptions. Please provide a packedId parameter with one of the following");
144
                responseMap.put("packedId", workflowUris);
1✔
145
                return new ResponseEntity<Map<String, Object>>(
1✔
146
                    responseMap, HttpStatus.UNPROCESSABLE_ENTITY);
147
              }
148
            }
149
          } catch (CWLValidationException ex) {
1✔
150
            Map<String, String> message =
1✔
151
                Collections.singletonMap("message", "Error:" + ex.getMessage());
1✔
152
            return new ResponseEntity<Map<String, String>>(message, HttpStatus.BAD_REQUEST);
1✔
153
          } catch (Exception ex) {
×
154
            Map<String, String> message =
×
155
                Collections.singletonMap(
×
156
                    "message", "Error: Workflow could not be created from the provided cwl file");
157
            return new ResponseEntity<Map<String, String>>(message, HttpStatus.BAD_REQUEST);
×
158
          }
1✔
159
        }
160
        response.setHeader("Location", "/queue/" + queued.getId());
1✔
161
        response.setStatus(HttpServletResponse.SC_ACCEPTED);
1✔
162
        return null;
1✔
163
      } else {
164
        // Workflow already exists and is equivalent
165
        response.setStatus(HttpServletResponse.SC_SEE_OTHER);
1✔
166
        response.setHeader("Location", gitInfo.getInternalUrl());
1✔
167
        return null;
1✔
168
      }
169
    }
170
  }
171

172
  /**
173
   * Get the JSON representation of a workflow from github.com or gitlab.com details
174
   *
175
   * @param domain The domain of the hosting site, github.com or gitlab.com
176
   * @param owner The owner of the Github repository
177
   * @param repoName The name of the repository
178
   * @param branch The branch of repository
179
   * @return The JSON representation of the workflow
180
   */
181
  @GetMapping(
182
      value = {
183
        "/workflows/{domain}.com/{owner}/{repoName}/tree/{branch}/**",
184
        "/workflows/{domain}.com/{owner}/{repoName}/blob/{branch}/**"
185
      },
186
      produces = MediaType.APPLICATION_JSON_VALUE)
187
  public Workflow getWorkflowJson(
188
      @PathVariable("domain") String domain,
189
      @PathVariable("owner") String owner,
190
      @PathVariable("repoName") String repoName,
191
      @PathVariable("branch") String branch,
192
      HttpServletRequest request) {
193
    // The wildcard end of the URL is the path
194
    String path =
1✔
195
        (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
1✔
196
    path = WorkflowController.extractPath(path, 7);
1✔
197

198
    // Construct a GitDetails object to search for in the database
199
    GitDetails gitDetails = WorkflowController.getGitDetails(domain, owner, repoName, branch, path);
1✔
200

201
    // Get workflow
202
    Workflow workflowModel = workflowService.getWorkflow(gitDetails);
1✔
203
    if (workflowModel == null) {
1✔
204
      throw new WorkflowNotFoundException();
×
205
    } else {
206
      return workflowModel;
1✔
207
    }
208
  }
209

210
  /**
211
   * Get JSON representation of a workflow from generic git details
212
   *
213
   * @param branch The branch of the repository
214
   * @return The JSON representation of the workflow
215
   */
216
  @GetMapping(value = "/workflows/*/*.git/{branch}/**", produces = MediaType.APPLICATION_JSON_VALUE)
217
  public Workflow getWorkflowJsonGeneric(
218
      @PathVariable("branch") String branch, HttpServletRequest request) {
219
    // The wildcard end of the URL is the path
220
    String path =
×
221
        (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
×
222

223
    // Construct a GitDetails object to search for in the database
224
    GitDetails gitDetails = WorkflowController.getGitDetails(11, path, branch);
×
225

226
    // Get workflow
227
    Workflow workflowModel = workflowService.getWorkflow(gitDetails);
×
228
    if (workflowModel == null) {
×
229
      throw new WorkflowNotFoundException();
×
230
    } else {
231
      return workflowModel;
×
232
    }
233
  }
234

235
  /**
236
   * Query progress of a queued workflow
237
   *
238
   * @param queueID The queued workflow ID to check
239
   * @return 303 see other status w/ location header if success, otherwise JSON representation of
240
   *     object
241
   */
242
  @GetMapping(value = "/queue/{queueID}", produces = MediaType.APPLICATION_JSON_VALUE)
243
  public QueuedWorkflow checkQueueJson(
244
      @PathVariable("queueID") String queueID, HttpServletResponse response) {
245
    QueuedWorkflow queuedWorkflow = workflowService.getQueuedWorkflow(queueID);
1✔
246
    if (queuedWorkflow == null) {
1✔
247
      throw new WorkflowNotFoundException();
1✔
248
    }
249

250
    if (queuedWorkflow.getCwltoolStatus() == SUCCESS) {
1✔
251
      GitDetails gitInfo = queuedWorkflow.getTempRepresentation().getRetrievedFrom();
1✔
252
      String resourceLocation = gitInfo.getInternalUrl();
1✔
253
      response.setHeader("Location", resourceLocation);
1✔
254
      response.setStatus(HttpServletResponse.SC_SEE_OTHER);
1✔
255
    }
256
    return queuedWorkflow;
1✔
257
  }
258
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc