Skip to content

Commit 75174c5

Browse files
committed
Bitbucket raw URL support
1 parent b405e9a commit 75174c5

File tree

7 files changed

+110
-68
lines changed

7 files changed

+110
-68
lines changed

src/main/java/org/commonwl/view/cwl/CWLToolRunner.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ public void createWorkflowFromQueued(QueuedWorkflow queuedWorkflow, File workflo
8080
newWorkflow.setRetrievedFrom(tempWorkflow.getRetrievedFrom());
8181
newWorkflow.setRetrievedOn(new Date());
8282
newWorkflow.setLastCommit(tempWorkflow.getLastCommit());
83+
newWorkflow.setGitRepoPath(tempWorkflow.getGitRepoPath());
8384
newWorkflow.setCwltoolVersion(cwlToolVersion);
8485
workflowRepository.save(newWorkflow);
8586

src/main/java/org/commonwl/view/git/GitDetails.java

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ public GitType getType() {
9292
return GitType.GITHUB;
9393
case "gitlab.com":
9494
return GitType.GITLAB;
95+
case "bitbucket.org":
96+
return GitType.BITBUCKET;
9597
default:
9698
return GitType.GENERIC;
9799
}
@@ -107,13 +109,15 @@ public GitType getType() {
107109
*/
108110
public String getUrl(String branchOverride) {
109111
switch (getType()) {
110-
case GENERIC:
111-
return repoUrl;
112112
case GITHUB:
113113
case GITLAB:
114-
return "https://" + normaliseUrl(repoUrl).replace(".git", "") + "/blob/" + branchOverride + "/" + path;
114+
return "https://" + normaliseUrl(repoUrl).replace(".git", "")
115+
+ "/blob/" + branchOverride + "/" + path;
116+
case BITBUCKET:
117+
return "https://" + normaliseUrl(repoUrl).replace(".git", "")
118+
+ "/src/" + branchOverride + "/" + path;
115119
default:
116-
return null;
120+
return repoUrl;
117121
}
118122
}
119123

@@ -131,13 +135,11 @@ public String getUrl() {
131135
*/
132136
public String getInternalUrl() {
133137
switch (getType()) {
134-
case GENERIC:
135-
return "/workflows/" + normaliseUrl(repoUrl) + "/" + branch + "/" + path;
136138
case GITHUB:
137139
case GITLAB:
138140
return "/workflows/" + normaliseUrl(repoUrl).replace(".git", "") + "/blob/" + branch + "/" + path;
139141
default:
140-
return null;
142+
return "/workflows/" + normaliseUrl(repoUrl) + "/" + branch + "/" + path;
141143
}
142144
}
143145

@@ -147,16 +149,16 @@ public String getInternalUrl() {
147149
*/
148150
public String getRawUrl() {
149151
switch (getType()) {
150-
case GENERIC:
151-
return repoUrl;
152152
case GITHUB:
153153
return "https://raw.githubusercontent.com/" +
154154
normaliseUrl(repoUrl).replace("github.com/", "").replace(".git", "") +
155155
"/" + branch + "/" + path;
156156
case GITLAB:
157-
return "https://whatever/gitlab/uses";
157+
case BITBUCKET:
158+
return "https://" + normaliseUrl(repoUrl).replace(".git", "")
159+
+ "/raw/" + branch + "/" + path;
158160
default:
159-
return null;
161+
return repoUrl;
160162
}
161163
}
162164

src/main/java/org/commonwl/view/git/GitType.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,6 @@
2626
public enum GitType {
2727
GITHUB,
2828
GITLAB,
29+
BITBUCKET,
2930
GENERIC
3031
}

src/main/java/org/commonwl/view/workflow/WorkflowController.java

Lines changed: 83 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -147,13 +147,13 @@ public ModelAndView newWorkflowFromGithubURL(@Valid WorkflowForm workflowForm, B
147147
*/
148148
@GetMapping(value={"/workflows/{domain}.com/{owner}/{repoName}/tree/{branch}/**",
149149
"/workflows/{domain}.com/{owner}/{repoName}/blob/{branch}/**"})
150-
public ModelAndView getWorkflowByGithubDetails(@Value("${applicationURL}") String applicationURL,
151-
@PathVariable("domain") String domain,
152-
@PathVariable("owner") String owner,
153-
@PathVariable("repoName") String repoName,
154-
@PathVariable("branch") String branch,
155-
HttpServletRequest request,
156-
RedirectAttributes redirectAttrs) {
150+
public ModelAndView getWorkflowByGitSiteDetails(@Value("${applicationURL}") String applicationURL,
151+
@PathVariable("domain") String domain,
152+
@PathVariable("owner") String owner,
153+
@PathVariable("repoName") String repoName,
154+
@PathVariable("branch") String branch,
155+
HttpServletRequest request,
156+
RedirectAttributes redirectAttrs) {
157157

158158
// The wildcard end of the URL is the path
159159
String path = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
@@ -163,49 +163,38 @@ public ModelAndView getWorkflowByGithubDetails(@Value("${applicationURL}") Strin
163163
GitDetails gitDetails = getGitDetails(domain, owner, repoName, branch, path);
164164

165165
// Get workflow
166-
QueuedWorkflow queued = null;
167-
Workflow workflowModel = workflowService.getWorkflow(gitDetails);
168-
if (workflowModel == null) {
169-
// Check if already queued
170-
queued = workflowService.getQueuedWorkflow(gitDetails);
171-
if (queued == null) {
172-
// Validation
173-
WorkflowForm workflowForm = new WorkflowForm(gitDetails.getUrl());
174-
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(workflowForm, "errors");
175-
workflowFormValidator.validateAndParse(workflowForm, errors);
176-
if (!errors.hasErrors()) {
177-
try {
178-
queued = workflowService.createQueuedWorkflow(gitDetails);
179-
} catch (GitAPIException ex) {
180-
errors.rejectValue("url", "git.retrievalError", ex.getMessage());
181-
} catch (CWLValidationException ex) {
182-
errors.rejectValue("url", "cwltool.validationError", ex.getMessage());
183-
} catch (IOException ex) {
184-
errors.rejectValue("url", "githubURL.parsingError", "The workflow could not be parsed from the given URL");
185-
}
186-
}
187-
// Redirect to main page with errors if they occurred
188-
if (errors.hasErrors()) {
189-
redirectAttrs.addFlashAttribute("errors", errors);
190-
return new ModelAndView("redirect:/?url=" + gitDetails.getUrl());
191-
}
192-
}
166+
ModelAndView modelAndView = getWorkflow(gitDetails, redirectAttrs);
167+
return modelAndView.addObject("appURL", applicationURL);
168+
169+
}
170+
171+
@GetMapping(value="/workflows/**/*.git/{branch}/**")
172+
public ModelAndView getWorkflowByGitDetails(@Value("${applicationURL}") String applicationURL,
173+
@PathVariable("branch") String branch,
174+
HttpServletRequest request,
175+
RedirectAttributes redirectAttrs) {
176+
String path = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
177+
178+
// The repository URL is the part after /workflows/ and up to and including .git
179+
String repoUrl = path.substring(11);
180+
int extensionIndex = repoUrl.indexOf(".git");
181+
if (extensionIndex == -1) {
182+
throw new WorkflowNotFoundException();
193183
}
184+
repoUrl = "https://" + repoUrl.substring(0, extensionIndex + 4);
194185

195-
// Display this model along with the view
196-
ModelAndView modelAndView;
197-
if (queued != null) {
198-
// Retry creation if there has been an error in cwltool parsing
199-
if (queued.getCwltoolStatus() == CWLToolStatus.ERROR) {
200-
workflowService.retryCwltool(queued);
201-
}
202-
modelAndView = new ModelAndView("loading", "queued", queued);
203-
} else {
204-
modelAndView = new ModelAndView("workflow", "workflow", workflowModel);
186+
// The path is after the branch
187+
int slashAfterBranch = path.indexOf("/", path.indexOf(branch));
188+
if (slashAfterBranch == -1 || slashAfterBranch == path.length()) {
189+
throw new WorkflowNotFoundException();
205190
}
191+
path = path.substring(slashAfterBranch + 1);
206192

207-
return modelAndView.addObject("appURL", applicationURL);
193+
// Construct GitDetails object for this workflow
194+
GitDetails gitDetails = new GitDetails(repoUrl, branch, path);
208195

196+
ModelAndView modelAndView = getWorkflow(gitDetails, redirectAttrs);
197+
return modelAndView.addObject("appURL", applicationURL);
209198
}
210199

211200
/**
@@ -381,4 +370,53 @@ public static GitDetails getGitDetails(String domain, String owner, String repoN
381370
}
382371
return new GitDetails(repoUrl, branch, path);
383372
}
373+
374+
/**
375+
* Get a workflow from Git Details
376+
* @param gitDetails The details of the Git repository
377+
* @param redirectAttrs Error attributes for redirect
378+
* @return The model and view to be returned by the controller
379+
*/
380+
private ModelAndView getWorkflow(GitDetails gitDetails, RedirectAttributes redirectAttrs) {
381+
// Get workflow
382+
QueuedWorkflow queued = null;
383+
Workflow workflowModel = workflowService.getWorkflow(gitDetails);
384+
if (workflowModel == null) {
385+
// Check if already queued
386+
queued = workflowService.getQueuedWorkflow(gitDetails);
387+
if (queued == null) {
388+
// Validation
389+
WorkflowForm workflowForm = new WorkflowForm(gitDetails.getUrl());
390+
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(workflowForm, "errors");
391+
workflowFormValidator.validateAndParse(workflowForm, errors);
392+
if (!errors.hasErrors()) {
393+
try {
394+
queued = workflowService.createQueuedWorkflow(gitDetails);
395+
} catch (GitAPIException ex) {
396+
errors.rejectValue("url", "git.retrievalError", ex.getMessage());
397+
} catch (CWLValidationException ex) {
398+
errors.rejectValue("url", "cwltool.validationError", ex.getMessage());
399+
} catch (IOException ex) {
400+
errors.rejectValue("url", "githubURL.parsingError", "The workflow could not be parsed from the given URL");
401+
}
402+
}
403+
// Redirect to main page with errors if they occurred
404+
if (errors.hasErrors()) {
405+
redirectAttrs.addFlashAttribute("errors", errors);
406+
return new ModelAndView("redirect:/?url=" + gitDetails.getUrl());
407+
}
408+
}
409+
}
410+
411+
// Display this model along with the view
412+
if (queued != null) {
413+
// Retry creation if there has been an error in cwltool parsing
414+
if (queued.getCwltoolStatus() == CWLToolStatus.ERROR) {
415+
workflowService.retryCwltool(queued);
416+
}
417+
return new ModelAndView("loading", "queued", queued);
418+
} else {
419+
return new ModelAndView("workflow", "workflow", workflowModel);
420+
}
421+
}
384422
}

src/main/resources/static/js/main.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ require(['jquery'],
7676
* Validate form before submit
7777
*/
7878
$('#add').submit(function() {
79-
var pathPattern = new RegExp("^\\/?(\\w+\\/)*\\w+\\.cwl$");
79+
var pathPattern = new RegExp("^\\/?([^\\/]*\\/)*[^\\/]+\\.cwl$");
8080
var input = $("#url").val();
8181
if (gitPattern.test(input)) {
8282
var success = true;

src/main/resources/templates/workflow.html

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
<link rel="stylesheet" th:href="@{/bower_components/bootstrap/dist/css/bootstrap.min.css}" href="../static/bower_components/bootstrap/dist/css/bootstrap.min.css" />
3232
<link rel="stylesheet" type="text/css" th:href="@{/css/main-20170616.css}" href="../static/css/main-20170616.css" />
3333
</head>
34-
<body th:with="githubURLPart=${workflow.retrievedFrom.getUrl().replace('https://', '')}">
34+
<body>
3535

3636
<nav th:replace="fragments/header :: navbar"></nav>
3737

@@ -113,8 +113,8 @@ <h4 class="modal-title" id="fullScreenGraphLabel">Workflow Graph</h4>
113113
</div>
114114
<div class="modal-body">
115115
<span id="fullscreen-close" data-dismiss="modal" class="close glyphicon glyphicon-resize-small graphControl" data-tooltip="true" title="Close"></span>
116-
<object id="graphFullscreen" th:data="@{'/graph/svg/' + ${githubURLPart}}" type="image/svg+xml">
117-
<img th:src="@{'/graph/png/' + ${githubURLPart}}" alt="fullscreen" />
116+
<object id="graphFullscreen" th:data="@{${workflow.getVisualisationSvg()}}" type="image/svg+xml">
117+
<img th:src="@{${workflow.getVisualisationPng()}}" alt="fullscreen" />
118118
</object>
119119
</div>
120120
</div>
@@ -136,7 +136,7 @@ <h2>Workflow: <span th:text="${workflow.label}">Workflow Name</span></h2>
136136
<span th:if="${workflow.roBundlePath == null}" id="ajaxRequired"></span>
137137
<span th:class="${workflow.roBundlePath != null} ? hide : ''" id="generating"> - Generating download link <img alt="loading" src="../static/img/loading.svg" th:src="@{/img/loading.svg}" width="20" height="20" /></span>
138138
<span th:class="${workflow.roBundlePath == null} ? hide : ''" id="generated">
139-
- <a th:href="@{'/robundle/' + ${githubURLPart}}" id="download" href="#" download="bundle.zip">Download as Research Object Bundle</a>
139+
- <a th:href="@{${workflow.getROBundle()}}" id="download" href="#" download="bundle.zip">Download as Research Object Bundle</a>
140140
<a href="http://www.researchobject.org/" rel="noopener" target="_blank">[?]</a>
141141
</span>
142142
</div>
@@ -154,8 +154,8 @@ <h2>Workflow: <span th:text="${workflow.label}">Workflow Name</span></h2>
154154
Download Image <span class="caret"></span>
155155
</button>
156156
<ul class="dropdown-menu">
157-
<li><a id="download-graph" th:href="@{'/graph/svg/' + ${githubURLPart}}" download="graph.svg">As .svg</a></li>
158-
<li><a id="download-graph" th:href="@{'/graph/png/' + ${githubURLPart}}" download="graph.png">As .png</a></li>
157+
<li><a id="download-graph" th:href="@{${workflow.getVisualisationSvg()}}" download="graph.svg">As .svg</a></li>
158+
<li><a id="download-graph" th:href="@{${workflow.getVisualisationPng()}}" download="graph.png">As .png</a></li>
159159
</ul>
160160
</div>
161161
</div>
@@ -167,7 +167,7 @@ <h2>Workflow: <span th:text="${workflow.label}">Workflow Name</span></h2>
167167
<span id="fullscreen-open" data-toggle="modal" data-target="#fullScreenGraphModal" data-tooltip="true" class="glyphicon glyphicon-resize-full graphControl" title="Expand"></span>
168168
<img id="selectChildren" class="graphControl" th:src="@{/img/children-logo.svg}" src="../static/img/children-logo.svg" alt="children" data-tooltip="true" title="Select All Children" />
169169
<img id="selectParents" class="graphControl" th:src="@{/img/parents-logo.svg}" src="../static/img/parents-logo.svg" alt="parents" data-tooltip="true" title="Select All Parents" />
170-
<div id="graph" data-th-attr="data-svgurl=@{'/graph/svg/' + ${githubURLPart}}"></div>
170+
<div id="graph" data-th-attr="data-svgurl=@{${workflow.getVisualisationSvg()}}"></div>
171171
</div>
172172
<ul class="legend">
173173
<li><span class="selectednode"></span> Selected</li>

src/main/resources/templates/workflows.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,10 @@ <h3>Showing results for "<span th:text="${search}">query</span>" <a href="/workf
5959
</tr>
6060
</thead>
6161
<tbody>
62-
<tr th:each="workflow : ${workflows}" th:with="githubURLPart=${workflow.retrievedFrom.getUrl().replace('https://', '')}">
62+
<tr th:each="workflow : ${workflows}">
6363
<td>
64-
<a th:href="@{${workflow.retrievedFrom.getUrl()}}">
65-
<img class="workflow-thumb" th:src="@{'/graph/svg/' + ${githubURLPart}}" alt="workflow graph" />
64+
<a th:href="@{${workflow.retrievedFrom.getInternalUrl()}}">
65+
<img class="workflow-thumb" th:src="@{${workflow.getVisualisationSvg()}}" alt="workflow graph" />
6666
</a>
6767
</td>
6868
<td>
@@ -78,7 +78,7 @@ <h3>Showing results for "<span th:text="${search}">query</span>" <a href="/workf
7878
<p th:if="${workflow.retrievedFrom.path != null}">Path: <i th:text="${workflow.retrievedFrom.path}">/path/to/workflow.cwl</i></p>
7979
<p>Branch/Commit ID: <i th:text="${workflow.retrievedFrom.branch}">master</i></p>
8080
</td>
81-
<td><a th:href="@{'/workflows/' + ${githubURLPart}}"><span class="icon-view glyphicon glyphicon-chevron-right"></span></a></td>
81+
<td><a th:href="@{${workflow.retrievedFrom.getInternalUrl()}}"><span class="icon-view glyphicon glyphicon-chevron-right"></span></a></td>
8282
</tr>
8383
</tbody>
8484
</table>

0 commit comments

Comments
 (0)