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

common-workflow-language / cwlviewer / #1694

30 Sep 2024 10:51AM UTC coverage: 70.306% (-0.5%) from 70.811%
#1694

push

github

mr-c
detect non-Workflow CWL documents and give a better error message

2 of 19 new or added lines in 4 files covered. (10.53%)

106 existing lines in 4 files now uncovered.

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) {
UNCOV
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(
78
      value = "/workflows",
79
      params = "search",
80
      produces = MediaType.APPLICATION_JSON_VALUE)
81
  public Page<Workflow> searchWorkflowsJson(
UNCOV
82
      Model model,
×
83
      @PageableDefault(size = 10) Pageable pageable,
84
      @RequestParam(value = "search") String search) {
85
    return workflowService.searchPageOfWorkflows(search, pageable);
86
  }
87

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

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

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

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

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

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

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

×
UNCOV
228
    // Construct a GitDetails object to search for in the database
×
229
    GitDetails gitDetails = WorkflowController.getGitDetails(11, path, branch);
×
230

UNCOV
231
    // Get workflow
×
232
    Workflow workflowModel = workflowService.getWorkflow(gitDetails);
233
    if (workflowModel == null) {
234
      throw new WorkflowNotFoundException();
235
    } else {
236
      return workflowModel;
237
    }
238
  }
239

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

1✔
255
    if (queuedWorkflow.getCwltoolStatus() == SUCCESS) {
256
      GitDetails gitInfo = queuedWorkflow.getTempRepresentation().getRetrievedFrom();
1✔
257
      String resourceLocation = gitInfo.getInternalUrl();
258
      response.setHeader("Location", resourceLocation);
259
      response.setStatus(HttpServletResponse.SC_SEE_OTHER);
260
    }
261
    return queuedWorkflow;
262
  }
263
}
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

© 2026 Coveralls, Inc