Skip to content

Commit 68179a7

Browse files
authored
Merge pull request #62 from common-workflow-language/ro-properties
Add extra properties to Research Object manifests
2 parents e82bb18 + a77f4a4 commit 68179a7

File tree

4 files changed

+170
-27
lines changed

4 files changed

+170
-27
lines changed

pom.xml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@
2929
<id>jitpack.io</id>
3030
<url>https://jitpack.io</url>
3131
</repository>
32+
<repository>
33+
<id>apache.snapshots</id>
34+
<name>Apache Snapshot Repository</name>
35+
<url>http://repository.apache.org/snapshots</url>
36+
<releases>
37+
<enabled>false</enabled>
38+
</releases>
39+
</repository>
3240
</repositories>
3341

3442
<dependencies>
@@ -72,7 +80,7 @@
7280
<dependency>
7381
<groupId>org.apache.taverna.language</groupId>
7482
<artifactId>taverna-robundle</artifactId>
75-
<version>0.15.1-incubating</version>
83+
<version>0.16.0-incubating-SNAPSHOT</version>
7684
<exclusions>
7785
<exclusion>
7886
<groupId>org.slf4j</groupId>
@@ -90,6 +98,5 @@
9098
</plugin>
9199
</plugins>
92100
</build>
93-
94-
101+
95102
</project>
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package org.commonwl.viewer.domain;
2+
3+
import org.apache.taverna.robundle.manifest.Agent;
4+
5+
import java.net.URI;
6+
7+
/**
8+
* An implementation of Agent with added HashCode and Equals methods
9+
* for use in sets
10+
*/
11+
public class HashableAgent extends Agent {
12+
13+
private String name;
14+
private URI orcid;
15+
private URI uri;
16+
17+
@Override
18+
public String getName() {
19+
return name;
20+
}
21+
22+
@Override
23+
public void setName(String name) {
24+
this.name = name;
25+
}
26+
27+
@Override
28+
public URI getOrcid() {
29+
return orcid;
30+
}
31+
32+
@Override
33+
public void setOrcid(URI orcid) {
34+
this.orcid = orcid;
35+
}
36+
37+
@Override
38+
public URI getUri() {
39+
return uri;
40+
}
41+
42+
@Override
43+
public void setUri(URI uri) {
44+
this.uri = uri;
45+
}
46+
47+
@Override
48+
public boolean equals(Object o) {
49+
if (this == o) return true;
50+
if (o == null || getClass() != o.getClass() || super.getClass() != o.getClass()) return false;
51+
52+
HashableAgent that = (HashableAgent) o;
53+
54+
if (name != null ? !name.equals(that.name) : that.name != null) return false;
55+
if (orcid != null ? !orcid.equals(that.orcid) : that.orcid != null) return false;
56+
return uri != null ? uri.equals(that.uri) : that.uri == null;
57+
58+
}
59+
60+
@Override
61+
public int hashCode() {
62+
int result = name != null ? name.hashCode() : 0;
63+
result = 31 * result + (orcid != null ? orcid.hashCode() : 0);
64+
result = 31 * result + (uri != null ? uri.hashCode() : 0);
65+
return result;
66+
}
67+
68+
}

src/main/java/org/commonwl/viewer/domain/ROBundle.java

Lines changed: 51 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,14 @@
1919

2020
package org.commonwl.viewer.domain;
2121

22+
import org.apache.commons.io.FilenameUtils;
2223
import org.apache.taverna.robundle.Bundle;
2324
import org.apache.taverna.robundle.Bundles;
2425
import org.apache.taverna.robundle.manifest.Agent;
2526
import org.apache.taverna.robundle.manifest.Manifest;
27+
import org.apache.taverna.robundle.manifest.PathMetadata;
2628
import org.commonwl.viewer.services.GitHubService;
2729
import org.eclipse.egit.github.core.RepositoryContents;
28-
import org.eclipse.egit.github.core.User;
2930
import org.slf4j.Logger;
3031
import org.slf4j.LoggerFactory;
3132

@@ -35,7 +36,11 @@
3536
import java.nio.file.Files;
3637
import java.nio.file.Path;
3738
import java.util.ArrayList;
39+
import java.util.HashSet;
3840
import java.util.List;
41+
import java.util.Set;
42+
import java.util.regex.Matcher;
43+
import java.util.regex.Pattern;
3944

4045
/**
4146
* Represents a Workflow Research Object Bundle
@@ -49,6 +54,11 @@ public class ROBundle {
4954
private Bundle bundle;
5055
private GithubDetails githubInfo;
5156
private String commitSha;
57+
private Set<HashableAgent> authors = new HashSet<HashableAgent>();
58+
59+
// Pattern for extracting version from a cwl file
60+
private final String CWL_VERSION_REGEX = "cwlVersion:\\s*\"?(?:cwl:)?([^\\s\"]+)\"?";
61+
private final Pattern cwlVersionPattern = Pattern.compile(CWL_VERSION_REGEX);
5262

5363
/**
5464
* Creates a new research object bundle for a workflow from a Github repository
@@ -69,31 +79,19 @@ public ROBundle(GitHubService githubService, GithubDetails githubInfo, String co
6979

7080
// Simplified attribution for RO bundle
7181
try {
82+
// Tool attribution in createdBy
7283
Agent cwlViewer = new Agent(appName);
7384
cwlViewer.setUri(new URI(appURL));
7485
manifest.setCreatedBy(cwlViewer);
7586

76-
// Github author attribution
77-
// TODO: way to add all the contributors somehow
78-
// TODO: set the aggregates details according to the github information
79-
User authorDetails = githubService.getUser(githubInfo.getOwner());
80-
81-
List<Agent> authorList = new ArrayList<>(1);
82-
Agent author = new Agent(authorDetails.getName());
83-
author.setUri(new URI(authorDetails.getHtmlUrl()));
84-
85-
// This tool supports putting your ORCID in the blog field of github as a URL
86-
// eg http://orcid.org/0000-0000-0000-0000
87-
String authorBlog = authorDetails.getBlog();
88-
if (authorBlog != null && authorBlog.startsWith("http://orcid.org/")) {
89-
author.setOrcid(new URI(authorBlog));
90-
}
91-
92-
authorList.add(author);
93-
manifest.setAuthoredBy(authorList);
87+
// Retrieval Info
88+
manifest.setRetrievedBy(cwlViewer);
89+
manifest.setRetrievedOn(manifest.getCreatedOn());
90+
manifest.setRetrievedFrom(new URI("https://github.com/" + githubInfo.getOwner() + "/"
91+
+ githubInfo.getRepoName() + "/tree/" + commitSha + "/" + githubInfo.getPath()));
9492

9593
} catch (URISyntaxException ex) {
96-
logger.error(ex.getMessage());
94+
logger.error("Error creating URI for RO Bundle", ex);
9795
}
9896

9997
// Make a directory in the RO bundle to store the files
@@ -103,6 +101,9 @@ public ROBundle(GitHubService githubService, GithubDetails githubInfo, String co
103101
// Add the files from the Github repo to this workflow
104102
List<RepositoryContents> repoContents = githubService.getContents(githubInfo);
105103
addFiles(repoContents, bundleFiles);
104+
105+
// Add combined authors
106+
manifest.setAuthoredBy(new ArrayList<Agent>(authors));
106107
}
107108

108109
/**
@@ -130,7 +131,7 @@ private void addFiles(List<RepositoryContents> repoContents, Path path) throws I
130131
// Add the files in the subdirectory to this new folder
131132
addFiles(subdirectory, subdirPath);
132133

133-
// Otherwise this is a file so add to the bundle
134+
// Otherwise this is a file so add to the bundle
134135
} else if (repoContent.getType().equals("file")) {
135136

136137
// Get the content of this file from Github
@@ -142,6 +143,35 @@ private void addFiles(List<RepositoryContents> repoContents, Path path) throws I
142143
Path newFilePort = path.resolve(repoContent.getName());
143144
Bundles.setStringValue(newFilePort, fileContent);
144145

146+
// Manifest aggregation
147+
PathMetadata aggregation = bundle.getManifest().getAggregation(newFilePort);
148+
149+
try {
150+
// Special handling for cwl files
151+
if (FilenameUtils.getExtension(repoContent.getName()).equals("cwl")) {
152+
// Correct mime type (no official standard for yaml)
153+
aggregation.setMediatype("text/x-yaml");
154+
155+
// Add conformsTo for version extracted from regex
156+
// Lower overhead vs parsing entire file
157+
Matcher m = cwlVersionPattern.matcher(fileContent);
158+
if (m.find()) {
159+
aggregation.setConformsTo(new URI("https://w3id.org/cwl/" + m.group(1)));
160+
}
161+
}
162+
163+
// Add authors from github commits to the file
164+
Set<HashableAgent> fileAuthors = githubService.getContributors(githubFile, commitSha);
165+
authors.addAll(fileAuthors);
166+
aggregation.setAuthoredBy(new ArrayList<Agent>(fileAuthors));
167+
168+
// Set retrievedFrom information for this file in the manifest
169+
aggregation.setRetrievedFrom(new URI("https://github.com/" + githubFile.getOwner() + "/" +
170+
githubFile.getRepoName() + "/blob/" + commitSha + "/" + githubFile.getPath()));
171+
} catch (URISyntaxException ex) {
172+
logger.error("Error creating URI for RO Bundle", ex);
173+
}
174+
145175
}
146176
}
147177
}

src/main/java/org/commonwl/viewer/services/GitHubService.java

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,25 @@
2121

2222
import org.apache.commons.io.IOUtils;
2323
import org.commonwl.viewer.domain.GithubDetails;
24+
import org.commonwl.viewer.domain.HashableAgent;
2425
import org.eclipse.egit.github.core.*;
25-
import org.eclipse.egit.github.core.RepositoryContents;
26-
import org.eclipse.egit.github.core.RepositoryId;
27-
import org.eclipse.egit.github.core.User;
2826
import org.eclipse.egit.github.core.client.GitHubClient;
2927
import org.eclipse.egit.github.core.service.CommitService;
3028
import org.eclipse.egit.github.core.service.ContentsService;
29+
import org.eclipse.egit.github.core.service.RepositoryService;
3130
import org.eclipse.egit.github.core.service.UserService;
3231
import org.springframework.beans.factory.annotation.Autowired;
3332
import org.springframework.beans.factory.annotation.Value;
3433
import org.springframework.stereotype.Service;
3534

3635
import java.io.IOException;
3736
import java.io.InputStream;
37+
import java.net.URI;
38+
import java.net.URISyntaxException;
3839
import java.net.URL;
40+
import java.util.HashSet;
3941
import java.util.List;
42+
import java.util.Set;
4043
import java.util.regex.Matcher;
4144
import java.util.regex.Pattern;
4245

@@ -50,6 +53,7 @@ public class GitHubService {
5053
private final ContentsService contentsService;
5154
private final UserService userService;
5255
private final CommitService commitService;
56+
private final RepositoryService repoService;
5357

5458
// URL validation for directory links
5559
private final String GITHUB_DIR_REGEX = "^https:\\/\\/github\\.com\\/([A-Za-z0-9_.-]+)\\/([A-Za-z0-9_.-]+)\\/?(?:tree\\/([^/]+)\\/(.*))?$";
@@ -69,6 +73,7 @@ public GitHubService(@Value("${githubAPI.authentication}") String authSetting,
6973
this.contentsService = new ContentsService(client);
7074
this.userService = new UserService(client);
7175
this.commitService = new CommitService(client);
76+
this.repoService = new RepositoryService(client);
7277
}
7378

7479
/**
@@ -138,4 +143,37 @@ public String getCommitSha(GithubDetails githubInfo) throws IOException {
138143
RepositoryCommit currentCommit = commitService.getCommit(repo, githubInfo.getBranch());
139144
return currentCommit.getSha();
140145
}
146+
147+
/**
148+
*
149+
* Get the contributors to a specific file by their commits
150+
* @param githubInfo The information to access the repository
151+
* @return A list of unique contributors
152+
* @throws IOException Any API errors which may have occurred
153+
* @throws URISyntaxException Any error in the author's URI (should never occur)
154+
*/
155+
public Set<HashableAgent> getContributors(GithubDetails githubInfo, String sha)
156+
throws IOException, URISyntaxException {
157+
RepositoryId repo = new RepositoryId(githubInfo.getOwner(), githubInfo.getRepoName());
158+
Set<HashableAgent> authors = new HashSet<HashableAgent>();
159+
160+
for (RepositoryCommit commit : commitService.getCommits(repo, sha, githubInfo.getPath())) {
161+
User author = commit.getAuthor();
162+
CommitUser commitAuthor = commit.getCommit().getAuthor();
163+
164+
// If there is author information for this commit in some form
165+
if (author != null || commitAuthor != null) {
166+
// Create a new agent and add as much detail as possible
167+
HashableAgent newAgent = new HashableAgent();
168+
if (author != null) {
169+
newAgent.setUri(new URI(author.getHtmlUrl()));
170+
}
171+
if (commitAuthor != null) {
172+
newAgent.setName(commitAuthor.getName());
173+
}
174+
authors.add(newAgent);
175+
}
176+
}
177+
return authors;
178+
}
141179
}

0 commit comments

Comments
 (0)