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

common-workflow-language / cwlviewer / #1998

13 May 2026 06:03PM UTC coverage: 70.05% (-0.3%) from 70.334%
#1998

Pull #751

github

kinow
Remove custom implementations with native queries, now Hibernate + JPA works!
Pull Request #751: Bump org.springframework.boot:spring-boot-starter-parent from 3.1.4 to 4.1.0-RC1

117 of 194 new or added lines in 30 files covered. (60.31%)

20 existing lines in 4 files now uncovered.

1691 of 2414 relevant lines covered (70.05%)

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.ArrayList;
27
import java.util.Collections;
28
import java.util.HashMap;
29
import java.util.List;
30
import java.util.Map;
31
import org.commonwl.view.cwl.CWLValidationException;
32
import org.commonwl.view.git.GitDetails;
33
import org.springframework.beans.factory.annotation.Autowired;
34
import org.springframework.data.domain.Page;
35
import org.springframework.data.domain.Pageable;
36
import org.springframework.data.web.PageableDefault;
37
import org.springframework.http.HttpStatus;
38
import org.springframework.http.MediaType;
39
import org.springframework.http.ResponseEntity;
40
import org.springframework.ui.Model;
41
import org.springframework.validation.BeanPropertyBindingResult;
42
import org.springframework.web.bind.annotation.GetMapping;
43
import org.springframework.web.bind.annotation.PathVariable;
44
import org.springframework.web.bind.annotation.PostMapping;
45
import org.springframework.web.bind.annotation.RequestParam;
46
import org.springframework.web.bind.annotation.RestController;
47
import org.springframework.web.servlet.HandlerMapping;
48

49
/** JSON API Controller */
50
@RestController
51
public class WorkflowJSONController {
52

53
  private final WorkflowFormValidator workflowFormValidator;
54
  private final WorkflowService workflowService;
55

56
  /**
57
   * Autowired constructor to initialise objects used by the controller
58
   *
59
   * @param workflowFormValidator Validator to validate the workflow form
60
   * @param workflowService Builds new Workflow objects
61
   */
62
  @Autowired
63
  public WorkflowJSONController(
64
      WorkflowFormValidator workflowFormValidator, WorkflowService workflowService) {
1✔
65
    this.workflowFormValidator = workflowFormValidator;
1✔
66
    this.workflowService = workflowService;
1✔
67
  }
1✔
68

69
  /**
70
   * List all the workflows in the database, paginated
71
   *
72
   * @return A list of all the workflows
73
   */
74
  @GetMapping(value = "/workflows", produces = MediaType.APPLICATION_JSON_VALUE)
75
  public Page<Workflow> listWorkflowsJson(
76
      Model model, @PageableDefault(size = 10) Pageable pageable) {
77
    return workflowService.getPageOfWorkflows(pageable);
×
78
  }
79

80
  /**
81
   * Search all workflows for a string in the label or doc
82
   *
83
   * @return A list of all the workflows
84
   */
85
  @GetMapping(value = "/workflows", params = "search", produces = MediaType.APPLICATION_JSON_VALUE)
86
  public Page<Workflow> searchWorkflowsJson(
87
      Model model,
88
      @PageableDefault(size = 10) Pageable pageable,
89
      @RequestParam(value = "search") String search) {
90
    return workflowService.searchPageOfWorkflows(search, pageable);
×
91
  }
92

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

110
    // Run validator which checks the URL is valid
111
    WorkflowForm workflowForm = new WorkflowForm(url, branch, path, packedId);
1✔
112
    BeanPropertyBindingResult errors = new BeanPropertyBindingResult(workflowForm, "errors");
1✔
113
    GitDetails gitInfo = workflowFormValidator.validateAndParse(workflowForm, errors);
1✔
114

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

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

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

208
    // Get workflow
209
    Workflow workflowModel = workflowService.getWorkflow(gitDetails);
1✔
210
    if (workflowModel == null) {
1✔
211
      throw new WorkflowNotFoundException();
×
212
    } else {
213
      return workflowModel;
1✔
214
    }
215
  }
216

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

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

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

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

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