commit 607a89b90fb0215a7128bf30e3d3e5a0a110369a Author: john Date: Mon Nov 24 19:11:03 2025 -0700 chore: restore from backup restoring to gitea from backup diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8608cfb --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/.classpath +/.factorypath +/.project +/target +/.idea diff --git a/README.md b/README.md new file mode 100644 index 0000000..a3760bf --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +Placeholder. \ No newline at end of file diff --git a/manifest.yml b/manifest.yml new file mode 100644 index 0000000..780ccfc --- /dev/null +++ b/manifest.yml @@ -0,0 +1,7 @@ +--- +applications: + - name: GitHelp + memory: 768M + instances: 1 + buildpack: java_buildpack_offline + path: target/GitHelp-1.0.0-SNAPSHOT.jar \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..bbb17f3 --- /dev/null +++ b/pom.xml @@ -0,0 +1,83 @@ + + + 4.0.0 + + + John Groller + http://www.jkgroller.com + + + com.jkgroller.githelp + GitHelp + 1.0.0-SNAPSHOT + Translates GitLab terminology to scrum terminology and provides additional calculations. + jar + + + org.springframework.boot + spring-boot-starter-parent + 2.2.0.RELEASE + + + + UTF-8 + UTF-8 + 1.8 + + + + + jcenter + https://jcenter.bintray.com/ + + + + + + org.springframework.boot + spring-boot-starter-web + + + io.crnk + crnk-setup-spring-boot2 + 3.0.20190714142556 + + + org.projectlombok + lombok + + + org.springframework.boot + spring-boot-devtools + + + org.gitlab4j + gitlab4j-api + 4.12.15 + + + org.apache.commons + commons-lang3 + 3.8.1 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + + + \ No newline at end of file diff --git a/src/main/java/com/jkgroller/githelp/GitHelp.java b/src/main/java/com/jkgroller/githelp/GitHelp.java new file mode 100644 index 0000000..c69b69d --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/GitHelp.java @@ -0,0 +1,16 @@ +package com.jkgroller.githelp; + + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + + +@SpringBootApplication +public class GitHelp { + + public static void main(String[] args) { + SpringApplication.run(GitHelp.class, args); + } + +} + diff --git a/src/main/java/com/jkgroller/githelp/adapter/GitlabGroupAdapter.java b/src/main/java/com/jkgroller/githelp/adapter/GitlabGroupAdapter.java new file mode 100644 index 0000000..2b7384d --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/adapter/GitlabGroupAdapter.java @@ -0,0 +1,11 @@ +package com.jkgroller.githelp.adapter; + +import com.jkgroller.githelp.adapter.request.RetrieveGroupRequestTO; +import com.jkgroller.githelp.adapter.response.RetrieveGroupResponseTO; + +public interface GitlabGroupAdapter { + + RetrieveGroupResponseTO retrieveGroup( + RetrieveGroupRequestTO retrieveGroupRequestTO); + +} diff --git a/src/main/java/com/jkgroller/githelp/adapter/GitlabGroupAdapterImpl.java b/src/main/java/com/jkgroller/githelp/adapter/GitlabGroupAdapterImpl.java new file mode 100644 index 0000000..6cd6c8b --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/adapter/GitlabGroupAdapterImpl.java @@ -0,0 +1,33 @@ +package com.jkgroller.githelp.adapter; + +import com.jkgroller.githelp.adapter.request.RetrieveGroupRequestTO; +import com.jkgroller.githelp.adapter.response.RetrieveGroupResponseTO; +import org.gitlab4j.api.GitLabApiException; +import org.gitlab4j.api.GroupApi; +import org.gitlab4j.api.models.Group; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class GitlabGroupAdapterImpl implements GitlabGroupAdapter{ + + @Autowired + private GroupApi groupApi; + + @Override + public RetrieveGroupResponseTO retrieveGroup(RetrieveGroupRequestTO retrieveGroupRequestTO) { + + RetrieveGroupResponseTO retrieveGroupResponseTO = new RetrieveGroupResponseTO(); + + try { + Group group = groupApi.getGroup(retrieveGroupRequestTO.getGroupNumber()); + retrieveGroupResponseTO.setGroupName(group.getName()); + } catch (GitLabApiException e) { + return null; + } + + return retrieveGroupResponseTO; + + } + +} diff --git a/src/main/java/com/jkgroller/githelp/adapter/GitlabIssueAdapter.java b/src/main/java/com/jkgroller/githelp/adapter/GitlabIssueAdapter.java new file mode 100644 index 0000000..3c15600 --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/adapter/GitlabIssueAdapter.java @@ -0,0 +1,11 @@ +package com.jkgroller.githelp.adapter; + +import com.jkgroller.githelp.adapter.request.RetrieveMilestoneIssuesRequestTO; +import com.jkgroller.githelp.adapter.response.RetrieveMilestoneIssuesResponseTO; + +public interface GitlabIssueAdapter { + + RetrieveMilestoneIssuesResponseTO retrieveMilestoneIssues( + RetrieveMilestoneIssuesRequestTO retrieveMilestoneIssuesRequestTO); + +} diff --git a/src/main/java/com/jkgroller/githelp/adapter/GitlabIssueAdapterImpl.java b/src/main/java/com/jkgroller/githelp/adapter/GitlabIssueAdapterImpl.java new file mode 100644 index 0000000..32afa87 --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/adapter/GitlabIssueAdapterImpl.java @@ -0,0 +1,50 @@ +package com.jkgroller.githelp.adapter; + +import com.jkgroller.githelp.adapter.converter.IssueConverter; +import com.jkgroller.githelp.adapter.request.RetrieveMilestoneIssuesRequestTO; +import com.jkgroller.githelp.adapter.response.IssueTO; +import com.jkgroller.githelp.adapter.response.RetrieveMilestoneIssuesResponseTO; +import org.gitlab4j.api.GitLabApiException; +import org.gitlab4j.api.IssuesApi; +import org.gitlab4j.api.models.IssueFilter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import java.util.List; + +@Component +public class GitlabIssueAdapterImpl implements GitlabIssueAdapter { + + @Autowired + private IssuesApi issuesApi; + + @Autowired + private IssueConverter issueConverter; + + @Override + public RetrieveMilestoneIssuesResponseTO retrieveMilestoneIssues(RetrieveMilestoneIssuesRequestTO retrieveMilestoneIssuesRequestTO) { + + if (StringUtils.isEmpty(retrieveMilestoneIssuesRequestTO.getMilestoneTitle())) { + return null; + } + + RetrieveMilestoneIssuesResponseTO retrieveMilestoneIssuesResponseTO = new RetrieveMilestoneIssuesResponseTO(); + + try { + + IssueFilter issueFilter = new IssueFilter(); + issueFilter.setMilestone(retrieveMilestoneIssuesRequestTO.getMilestoneTitle()); + + List issueTOs = issueConverter.convert(issuesApi.getIssues(issueFilter)); + + retrieveMilestoneIssuesResponseTO.setIssueTOs(issueTOs); + + } catch (GitLabApiException e) { + return null; + } + + return retrieveMilestoneIssuesResponseTO; + + } +} diff --git a/src/main/java/com/jkgroller/githelp/adapter/GitlabMilestoneAdapter.java b/src/main/java/com/jkgroller/githelp/adapter/GitlabMilestoneAdapter.java new file mode 100644 index 0000000..e234fb8 --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/adapter/GitlabMilestoneAdapter.java @@ -0,0 +1,11 @@ +package com.jkgroller.githelp.adapter; + +import com.jkgroller.githelp.adapter.request.RetrieveMilestonesRequestTO; +import com.jkgroller.githelp.adapter.response.RetrieveMilestonesResponseTO; + +public interface GitlabMilestoneAdapter { + + RetrieveMilestonesResponseTO retrieveMilestones( + RetrieveMilestonesRequestTO retrieveMilestonesRequestTO); + +} \ No newline at end of file diff --git a/src/main/java/com/jkgroller/githelp/adapter/GitlabMilestoneAdapterImpl.java b/src/main/java/com/jkgroller/githelp/adapter/GitlabMilestoneAdapterImpl.java new file mode 100644 index 0000000..f4363f0 --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/adapter/GitlabMilestoneAdapterImpl.java @@ -0,0 +1,60 @@ +/** + * + */ +package com.jkgroller.githelp.adapter; + +import com.jkgroller.githelp.adapter.converter.MilestoneConverter; +import com.jkgroller.githelp.adapter.request.RetrieveMilestonesRequestTO; +import com.jkgroller.githelp.adapter.response.MilestoneTO; +import com.jkgroller.githelp.adapter.response.RetrieveMilestonesResponseTO; +import org.gitlab4j.api.GitLabApiException; +import org.gitlab4j.api.MilestonesApi; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * @author john@grollerfamily.com + * + */ + +@Component +public class GitlabMilestoneAdapterImpl implements GitlabMilestoneAdapter { + + @Autowired + private MilestonesApi milestonesApi; + + @Autowired + private MilestoneConverter milestoneConverter; + + @Override + public RetrieveMilestonesResponseTO retrieveMilestones( + RetrieveMilestonesRequestTO retrieveMilestonesRequestTO) { + + if (0 == retrieveMilestonesRequestTO.getGroupNumber()) { + return null; + } + + RetrieveMilestonesResponseTO retrieveMilestonesResponseTO = new RetrieveMilestonesResponseTO(); + + try { + + int subListStartIndex = 0; + int subListEndIndex = retrieveMilestonesRequestTO.getNumberOfMilestonesToReturn() - 1; + + List milestoneTOs = milestoneConverter.convert(milestonesApi + .getGroupMilestones(retrieveMilestonesRequestTO.getGroupNumber(), retrieveMilestonesRequestTO.getMilestoneState())).subList(subListStartIndex, + subListEndIndex); + + retrieveMilestonesResponseTO.setMilestoneTOs(milestoneTOs); + + } catch (GitLabApiException e) { + return null; + } + + return retrieveMilestonesResponseTO; + + } + +} diff --git a/src/main/java/com/jkgroller/githelp/adapter/converter/IssueConverter.java b/src/main/java/com/jkgroller/githelp/adapter/converter/IssueConverter.java new file mode 100644 index 0000000..0e2ea88 --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/adapter/converter/IssueConverter.java @@ -0,0 +1,26 @@ +package com.jkgroller.githelp.adapter.converter; + +import com.jkgroller.githelp.adapter.response.IssueTO; +import com.jkgroller.githelp.util.AbstractConverter; +import org.gitlab4j.api.models.Issue; +import org.springframework.stereotype.Component; + +@Component +public class IssueConverter extends AbstractConverter { + + @Override + public IssueTO convert(Issue from, Void context) { + + if (null == from) { + return null; + } + + IssueTO issueTO = new IssueTO(); + + issueTO.setTitle(from.getTitle()); + issueTO.setUrl(from.getWebUrl()); + issueTO.setWeight(from.getWeight()); + + return issueTO; + } +} diff --git a/src/main/java/com/jkgroller/githelp/adapter/converter/MilestoneConverter.java b/src/main/java/com/jkgroller/githelp/adapter/converter/MilestoneConverter.java new file mode 100644 index 0000000..eaadabb --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/adapter/converter/MilestoneConverter.java @@ -0,0 +1,25 @@ +package com.jkgroller.githelp.adapter.converter; + +import com.jkgroller.githelp.adapter.response.MilestoneTO; +import com.jkgroller.githelp.util.AbstractConverter; +import org.gitlab4j.api.models.Milestone; +import org.springframework.stereotype.Component; + +@Component +public class MilestoneConverter extends AbstractConverter { + + @Override + public MilestoneTO convert(Milestone from, Void context) { + + if (null == from) { + return null; + } + + MilestoneTO milestoneTO = new MilestoneTO(); + + milestoneTO.setTitle(from.getTitle()); + + return milestoneTO; + + } +} diff --git a/src/main/java/com/jkgroller/githelp/adapter/request/RetrieveGroupRequestTO.java b/src/main/java/com/jkgroller/githelp/adapter/request/RetrieveGroupRequestTO.java new file mode 100644 index 0000000..4fed536 --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/adapter/request/RetrieveGroupRequestTO.java @@ -0,0 +1,14 @@ +package com.jkgroller.githelp.adapter.request; + +public class RetrieveGroupRequestTO { + + private int groupNumber; + + public int getGroupNumber() { + return groupNumber; + } + + public void setGroupNumber(int groupNumber) { + this.groupNumber = groupNumber; + } +} diff --git a/src/main/java/com/jkgroller/githelp/adapter/request/RetrieveMilestoneIssuesRequestTO.java b/src/main/java/com/jkgroller/githelp/adapter/request/RetrieveMilestoneIssuesRequestTO.java new file mode 100644 index 0000000..4d3af8e --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/adapter/request/RetrieveMilestoneIssuesRequestTO.java @@ -0,0 +1,14 @@ +package com.jkgroller.githelp.adapter.request; + +public class RetrieveMilestoneIssuesRequestTO { + + private String milestoneTitle; + + public String getMilestoneTitle() { + return milestoneTitle; + } + + public void setMilestoneTitle(String milestoneTitle) { + this.milestoneTitle = milestoneTitle; + } +} diff --git a/src/main/java/com/jkgroller/githelp/adapter/request/RetrieveMilestonesRequestTO.java b/src/main/java/com/jkgroller/githelp/adapter/request/RetrieveMilestonesRequestTO.java new file mode 100644 index 0000000..31fe2b0 --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/adapter/request/RetrieveMilestonesRequestTO.java @@ -0,0 +1,37 @@ +package com.jkgroller.githelp.adapter.request; + +import org.gitlab4j.api.Constants; + +public class RetrieveMilestonesRequestTO { + + private int groupNumber; + + private int numberOfMilestonesToReturn; + + //Replace with internal enum later. + private Constants.MilestoneState milestoneState; + + public int getGroupNumber() { + return groupNumber; + } + + public void setGroupNumber(int groupNumber) { + this.groupNumber = groupNumber; + } + + public int getNumberOfMilestonesToReturn() { + return numberOfMilestonesToReturn; + } + + public void setNumberOfMilestonesToReturn(int numberOfMilestonesToReturn) { + this.numberOfMilestonesToReturn = numberOfMilestonesToReturn; + } + + public Constants.MilestoneState getMilestoneState() { + return milestoneState; + } + + public void setMilestoneState(Constants.MilestoneState milestoneState) { + this.milestoneState = milestoneState; + } +} diff --git a/src/main/java/com/jkgroller/githelp/adapter/response/IssueTO.java b/src/main/java/com/jkgroller/githelp/adapter/response/IssueTO.java new file mode 100644 index 0000000..2c08bc0 --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/adapter/response/IssueTO.java @@ -0,0 +1,41 @@ +/** + * + */ +package com.jkgroller.githelp.adapter.response; + +/** + * @author john@grollerfamily.com + * + */ +public class IssueTO { + + private String title; + + private String url; + + private int weight; + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public int getWeight() { + return weight; + } + + public void setWeight(int weight) { + this.weight = weight; + } +} diff --git a/src/main/java/com/jkgroller/githelp/adapter/response/MilestoneTO.java b/src/main/java/com/jkgroller/githelp/adapter/response/MilestoneTO.java new file mode 100644 index 0000000..7196142 --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/adapter/response/MilestoneTO.java @@ -0,0 +1,15 @@ +package com.jkgroller.githelp.adapter.response; + +public class MilestoneTO { + + private String title; + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + +} diff --git a/src/main/java/com/jkgroller/githelp/adapter/response/RetrieveGroupResponseTO.java b/src/main/java/com/jkgroller/githelp/adapter/response/RetrieveGroupResponseTO.java new file mode 100644 index 0000000..3fdbee9 --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/adapter/response/RetrieveGroupResponseTO.java @@ -0,0 +1,14 @@ +package com.jkgroller.githelp.adapter.response; + +public class RetrieveGroupResponseTO { + + private String groupName; + + public String getGroupName() { + return groupName; + } + + public void setGroupName(String groupName) { + this.groupName = groupName; + } +} diff --git a/src/main/java/com/jkgroller/githelp/adapter/response/RetrieveMilestoneIssuesResponseTO.java b/src/main/java/com/jkgroller/githelp/adapter/response/RetrieveMilestoneIssuesResponseTO.java new file mode 100644 index 0000000..af3b327 --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/adapter/response/RetrieveMilestoneIssuesResponseTO.java @@ -0,0 +1,16 @@ +package com.jkgroller.githelp.adapter.response; + +import java.util.List; + +public class RetrieveMilestoneIssuesResponseTO { + + private List issueTOs; + + public List getIssueTOs() { + return issueTOs; + } + + public void setIssueTOs(List issueTOs) { + this.issueTOs = issueTOs; + } +} diff --git a/src/main/java/com/jkgroller/githelp/adapter/response/RetrieveMilestonesResponseTO.java b/src/main/java/com/jkgroller/githelp/adapter/response/RetrieveMilestonesResponseTO.java new file mode 100644 index 0000000..e8516b4 --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/adapter/response/RetrieveMilestonesResponseTO.java @@ -0,0 +1,16 @@ +package com.jkgroller.githelp.adapter.response; + +import java.util.List; + +public class RetrieveMilestonesResponseTO { + + private List milestoneTOs; + + public List getMilestoneTOs() { + return milestoneTOs; + } + + public void setMilestoneTOs(List milestoneTOs) { + this.milestoneTOs = milestoneTOs; + } +} diff --git a/src/main/java/com/jkgroller/githelp/config/GitlabConfig.java b/src/main/java/com/jkgroller/githelp/config/GitlabConfig.java new file mode 100644 index 0000000..2f297d2 --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/config/GitlabConfig.java @@ -0,0 +1,44 @@ +package com.jkgroller.githelp.config; + +import org.gitlab4j.api.GitLabApi; +import org.gitlab4j.api.GroupApi; +import org.gitlab4j.api.IssuesApi; +import org.gitlab4j.api.MilestonesApi; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class GitlabConfig { + + @Value("${gitlab.url}") + private String gitlabUrl; + + @Value("${gitlab.apikey}") + private String gitlabApiKey; + + @Autowired + private GitLabApi gitlabApi; + + @Bean + public GitLabApi getGitlabApi() { + return new GitLabApi(gitlabUrl, gitlabApiKey); + } + + @Bean + public IssuesApi getIssuesApi() { + return gitlabApi.getIssuesApi(); + } + + @Bean + public GroupApi getGroupsApi() { + return gitlabApi.getGroupApi(); + } + + @Bean + public MilestonesApi getMilestonesApi() { + return gitlabApi.getMilestonesApi(); + } + +} diff --git a/src/main/java/com/jkgroller/githelp/resource/GroupResource.java b/src/main/java/com/jkgroller/githelp/resource/GroupResource.java new file mode 100644 index 0000000..c910392 --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/resource/GroupResource.java @@ -0,0 +1,54 @@ +package com.jkgroller.githelp.resource; + +import java.util.List; + +import com.jkgroller.githelp.resource.attribute.CompletedSprintsAttribute; + +import io.crnk.core.resource.annotations.JsonApiId; +import io.crnk.core.resource.annotations.JsonApiResource; + +@JsonApiResource(type = "group", resourcePath = "groups") +public class GroupResource { + + @JsonApiId + private int groupNumber; + + private String groupName; + + private int velocity; + + private List recentlyCompletedSprints; + + public int getGroupNumber() { + return groupNumber; + } + + public void setGroupNumber(int groupNumber) { + this.groupNumber = groupNumber; + } + + public String getGroupName() { + return groupName; + } + + public void setGroupName(String groupName) { + this.groupName = groupName; + } + + public int getVelocity() { + return velocity; + } + + public void setVelocity(int velocity) { + this.velocity = velocity; + } + + public List getRecentlyCompletedSprints() { + return recentlyCompletedSprints; + } + + public void setRecentlyCompletedSprints(List recentlyCompletedSprints) { + this.recentlyCompletedSprints = recentlyCompletedSprints; + } + +} diff --git a/src/main/java/com/jkgroller/githelp/resource/attribute/CompletedSprintsAttribute.java b/src/main/java/com/jkgroller/githelp/resource/attribute/CompletedSprintsAttribute.java new file mode 100644 index 0000000..fa7d3f6 --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/resource/attribute/CompletedSprintsAttribute.java @@ -0,0 +1,37 @@ +package com.jkgroller.githelp.resource.attribute; + +import java.util.List; + +public class CompletedSprintsAttribute { + + private String title; + + private List completedStories; + + private int storyPointsCompleted; + + public List getCompletedStories() { + return completedStories; + } + + public void setCompletedStories(List completedStories) { + this.completedStories = completedStories; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public int getStoryPointsCompleted() { + return storyPointsCompleted; + } + + public void setStoryPointsCompleted(int storyPointsCompleted) { + this.storyPointsCompleted = storyPointsCompleted; + } + +} diff --git a/src/main/java/com/jkgroller/githelp/resource/attribute/CompletedStoryAttribute.java b/src/main/java/com/jkgroller/githelp/resource/attribute/CompletedStoryAttribute.java new file mode 100644 index 0000000..b5185ab --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/resource/attribute/CompletedStoryAttribute.java @@ -0,0 +1,42 @@ +/** + * + */ +package com.jkgroller.githelp.resource.attribute; + +/** + * @author john@grollerfamily.com + * + */ +public class CompletedStoryAttribute { + + private String title; + + private String url; + + private int storyPoints; + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public int getStoryPoints() { + return storyPoints; + } + + public void setStoryPoints(int storyPoints) { + this.storyPoints = storyPoints; + } + +} diff --git a/src/main/java/com/jkgroller/githelp/resource/converter/RetrieveScrumInformationResponseTOConverter.java b/src/main/java/com/jkgroller/githelp/resource/converter/RetrieveScrumInformationResponseTOConverter.java new file mode 100644 index 0000000..ad4becc --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/resource/converter/RetrieveScrumInformationResponseTOConverter.java @@ -0,0 +1,34 @@ +package com.jkgroller.githelp.resource.converter; + +import com.jkgroller.githelp.resource.GroupResource; +import com.jkgroller.githelp.resource.attribute.CompletedStoryAttribute; +import com.jkgroller.githelp.service.response.RetrieveScrumInformationResponseTO; +import com.jkgroller.githelp.service.response.SprintTO; +import com.jkgroller.githelp.service.response.StoryTO; +import com.jkgroller.githelp.util.AbstractConverter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class RetrieveScrumInformationResponseTOConverter extends AbstractConverter { + + @Autowired + private SprintTOConverter sprintTOConverter; + + @Override + public GroupResource convert(RetrieveScrumInformationResponseTO from, Void context) { + + if(null == from){ + return null; + } + + GroupResource groupResource = new GroupResource(); + + groupResource.setGroupName(from.getGroupName()); + groupResource.setVelocity(from.getVelocity()); + groupResource.setRecentlyCompletedSprints(sprintTOConverter.convert(from.getCompletedSprintTOs())); + + return groupResource; + } + +} diff --git a/src/main/java/com/jkgroller/githelp/resource/converter/SprintTOConverter.java b/src/main/java/com/jkgroller/githelp/resource/converter/SprintTOConverter.java new file mode 100644 index 0000000..0febeae --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/resource/converter/SprintTOConverter.java @@ -0,0 +1,32 @@ +package com.jkgroller.githelp.resource.converter; + +import com.jkgroller.githelp.adapter.response.MilestoneTO; +import com.jkgroller.githelp.resource.attribute.CompletedSprintsAttribute; +import com.jkgroller.githelp.service.response.SprintTO; +import com.jkgroller.githelp.util.AbstractConverter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class SprintTOConverter extends AbstractConverter { + + @Autowired + private StoryTOConverter storyTOConverter; + + @Override + public CompletedSprintsAttribute convert(SprintTO from, Void context) { + + if(null == from){ + return null; + } + + CompletedSprintsAttribute completedSprintsAttribute = new CompletedSprintsAttribute(); + + completedSprintsAttribute.setTitle(from.getTitle()); + completedSprintsAttribute.setStoryPointsCompleted(from.getStoryPointsCompleted()); + completedSprintsAttribute.setCompletedStories(storyTOConverter.convert(from.getCompletedStories())); + + return completedSprintsAttribute; + } + +} diff --git a/src/main/java/com/jkgroller/githelp/resource/converter/StoryTOConverter.java b/src/main/java/com/jkgroller/githelp/resource/converter/StoryTOConverter.java new file mode 100644 index 0000000..9617fd5 --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/resource/converter/StoryTOConverter.java @@ -0,0 +1,29 @@ +package com.jkgroller.githelp.resource.converter; + +import com.jkgroller.githelp.resource.attribute.CompletedSprintsAttribute; +import com.jkgroller.githelp.resource.attribute.CompletedStoryAttribute; +import com.jkgroller.githelp.service.response.SprintTO; +import com.jkgroller.githelp.service.response.StoryTO; +import com.jkgroller.githelp.util.AbstractConverter; +import org.springframework.stereotype.Component; + +@Component +public class StoryTOConverter extends AbstractConverter { + + @Override + public CompletedStoryAttribute convert(StoryTO from, Void context) { + + if(null == from){ + return null; + } + + CompletedStoryAttribute completedStoryAttribute = new CompletedStoryAttribute(); + + completedStoryAttribute.setStoryPoints(from.getPoints()); + completedStoryAttribute.setTitle(from.getTitle()); + completedStoryAttribute.setUrl(from.getUrl()); + + return completedStoryAttribute; + } + +} diff --git a/src/main/java/com/jkgroller/githelp/resource/repository/GroupResourceRepository.java b/src/main/java/com/jkgroller/githelp/resource/repository/GroupResourceRepository.java new file mode 100644 index 0000000..c1b0990 --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/resource/repository/GroupResourceRepository.java @@ -0,0 +1,54 @@ +package com.jkgroller.githelp.resource.repository; + +import com.jkgroller.githelp.resource.GroupResource; +import com.jkgroller.githelp.resource.converter.RetrieveScrumInformationResponseTOConverter; +import com.jkgroller.githelp.service.ScrumService; +import com.jkgroller.githelp.service.request.RetrieveScrumInformationRequestTO; +import io.crnk.core.exception.MethodNotAllowedException; +import io.crnk.core.queryspec.QuerySpec; +import io.crnk.core.repository.ResourceRepositoryBase; +import io.crnk.core.resource.list.ResourceList; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class GroupResourceRepository extends ResourceRepositoryBase { + + @Autowired + private ScrumService scrumService; + + @Autowired + private RetrieveScrumInformationResponseTOConverter retrieveScrumInformationResponseTOConverter; + + @Value("${number.of.milestones}") + private int numberOfMilestones; + + public GroupResourceRepository() { + super(GroupResource.class); + } + + @Override + public GroupResource findOne(Integer id, QuerySpec querySpec) { + + RetrieveScrumInformationRequestTO retrieveScrumInformationRequestTO = new RetrieveScrumInformationRequestTO(); + + retrieveScrumInformationRequestTO.setGroupNumber(id); + retrieveScrumInformationRequestTO.setNumberOfMilestonesToReturn(numberOfMilestones); + + GroupResource groupResource = + retrieveScrumInformationResponseTOConverter.convert(scrumService.retrieveScrumInformation(retrieveScrumInformationRequestTO)); + + groupResource.setGroupNumber(id); + + return groupResource; + + } + + + @Override + public ResourceList findAll(QuerySpec querySpec) { + throw new MethodNotAllowedException("Only one group resource is allowed."); + } + +} diff --git a/src/main/java/com/jkgroller/githelp/service/ScrumService.java b/src/main/java/com/jkgroller/githelp/service/ScrumService.java new file mode 100644 index 0000000..04d3352 --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/service/ScrumService.java @@ -0,0 +1,10 @@ +package com.jkgroller.githelp.service; + +import com.jkgroller.githelp.service.request.RetrieveScrumInformationRequestTO; +import com.jkgroller.githelp.service.response.RetrieveScrumInformationResponseTO; + +public interface ScrumService { + + RetrieveScrumInformationResponseTO retrieveScrumInformation( + RetrieveScrumInformationRequestTO retrieveScrumInformationRequestTO); +} diff --git a/src/main/java/com/jkgroller/githelp/service/ScrumServiceImpl.java b/src/main/java/com/jkgroller/githelp/service/ScrumServiceImpl.java new file mode 100644 index 0000000..7fdeea1 --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/service/ScrumServiceImpl.java @@ -0,0 +1,131 @@ +/** + * + */ +package com.jkgroller.githelp.service; + +import com.jkgroller.githelp.adapter.GitlabGroupAdapter; +import com.jkgroller.githelp.adapter.GitlabIssueAdapter; +import com.jkgroller.githelp.adapter.GitlabMilestoneAdapter; +import com.jkgroller.githelp.adapter.request.RetrieveGroupRequestTO; +import com.jkgroller.githelp.adapter.request.RetrieveMilestoneIssuesRequestTO; +import com.jkgroller.githelp.adapter.request.RetrieveMilestonesRequestTO; +import com.jkgroller.githelp.adapter.response.IssueTO; +import com.jkgroller.githelp.adapter.response.MilestoneTO; +import com.jkgroller.githelp.adapter.response.RetrieveMilestonesResponseTO; +import com.jkgroller.githelp.service.converter.IssueTOConverter; +import com.jkgroller.githelp.service.converter.MilestoneTOConverter; +import com.jkgroller.githelp.service.request.RetrieveScrumInformationRequestTO; +import com.jkgroller.githelp.service.response.RetrieveScrumInformationResponseTO; +import com.jkgroller.githelp.service.response.SprintTO; +import com.jkgroller.githelp.service.response.StoryTO; +import org.gitlab4j.api.Constants; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * @author john@grollerfamily.com + * + */ +@Service +public class ScrumServiceImpl implements ScrumService { + + @Autowired + private GitlabMilestoneAdapter gitlabMilestoneAdapter; + + @Autowired + private GitlabIssueAdapter gitlabIssueAdapter; + + @Autowired + private GitlabGroupAdapter gitlabGroupAdapter; + + @Autowired + private MilestoneTOConverter milestoneTOConverter; + + @Autowired + private IssueTOConverter issueTOConverter; + + @Override + public RetrieveScrumInformationResponseTO retrieveScrumInformation( + RetrieveScrumInformationRequestTO retrieveGroupInformationRequestTO) { + + RetrieveScrumInformationResponseTO retrieveScrumInformationResponseTO = new RetrieveScrumInformationResponseTO(); + + //retrieve the group name + retrieveScrumInformationResponseTO.setGroupName(retrieveGroupName(retrieveGroupInformationRequestTO)); + + //retrieve closed sprints + List sprintTOs = retrieveSprints(retrieveGroupInformationRequestTO); + + //update closed sprints with closed stories and story points completed + for(SprintTO sprintTO : sprintTOs){ + sprintTO.setCompletedStories(retrieveSprintStories(sprintTO.getTitle())); + sprintTO.setStoryPointsCompleted(calculateStoryPointsCompleted(sprintTO)); + } + + //sprint stuff all done + retrieveScrumInformationResponseTO.setCompletedSprintTOs(sprintTOs); + + //calculate velocity + retrieveScrumInformationResponseTO.setVelocity(calculateVelocity(sprintTOs)); + + return retrieveScrumInformationResponseTO; + + } + + private int calculateStoryPointsCompleted(SprintTO sprintTO){ + + int totalStoryPointsCompleted = 0; + + for(StoryTO storyTO : sprintTO.getCompletedStories()){ + totalStoryPointsCompleted += storyTO.getPoints(); + } + + return totalStoryPointsCompleted; + + } + + private List retrieveSprints(RetrieveScrumInformationRequestTO retrieveGroupInformationRequestTO) { + + RetrieveMilestonesRequestTO retrieveMilestonesRequestTO = new RetrieveMilestonesRequestTO(); + retrieveMilestonesRequestTO.setGroupNumber(retrieveGroupInformationRequestTO.getGroupNumber()); + retrieveMilestonesRequestTO.setMilestoneState(Constants.MilestoneState.CLOSED); + retrieveMilestonesRequestTO.setNumberOfMilestonesToReturn(5); + + RetrieveMilestonesResponseTO retrieveMilestonesResponseTO = gitlabMilestoneAdapter.retrieveMilestones(retrieveMilestonesRequestTO); + + return milestoneTOConverter.convert(retrieveMilestonesResponseTO.getMilestoneTOs()); + } + + private List retrieveSprintStories(String sprintTitle) { + + RetrieveMilestoneIssuesRequestTO retrieveMilestoneIssuesRequestTO = new RetrieveMilestoneIssuesRequestTO(); + retrieveMilestoneIssuesRequestTO.setMilestoneTitle(sprintTitle); + + return issueTOConverter.convert(gitlabIssueAdapter.retrieveMilestoneIssues(retrieveMilestoneIssuesRequestTO).getIssueTOs()); + } + + + private String retrieveGroupName(RetrieveScrumInformationRequestTO retrieveScrumInformationRequestTO) { + + RetrieveGroupRequestTO retrieveGroupRequestTO = new RetrieveGroupRequestTO(); + retrieveGroupRequestTO.setGroupNumber(retrieveScrumInformationRequestTO.getGroupNumber()); + + return gitlabGroupAdapter.retrieveGroup(retrieveGroupRequestTO).getGroupName(); + + } + + private int calculateVelocity(List sprintTOs){ + + int totalStoryPointsCompleted = 0; + + for(SprintTO sprintTO : sprintTOs){ + totalStoryPointsCompleted += sprintTO.getStoryPointsCompleted(); + } + + return totalStoryPointsCompleted / sprintTOs.size(); + + } + +} diff --git a/src/main/java/com/jkgroller/githelp/service/converter/IssueTOConverter.java b/src/main/java/com/jkgroller/githelp/service/converter/IssueTOConverter.java new file mode 100644 index 0000000..13f10a3 --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/service/converter/IssueTOConverter.java @@ -0,0 +1,29 @@ +package com.jkgroller.githelp.service.converter; + +import com.jkgroller.githelp.adapter.response.IssueTO; +import com.jkgroller.githelp.adapter.response.MilestoneTO; +import com.jkgroller.githelp.service.response.SprintTO; +import com.jkgroller.githelp.service.response.StoryTO; +import com.jkgroller.githelp.util.AbstractConverter; +import org.springframework.stereotype.Component; + +@Component +public class IssueTOConverter extends AbstractConverter { + + @Override + public StoryTO convert(IssueTO from, Void context) { + + if(null == from){ + return null; + } + + StoryTO storyTO = new StoryTO(); + + storyTO.setTitle(from.getTitle()); + storyTO.setUrl(from.getUrl()); + storyTO.setPoints(from.getWeight()); + + return storyTO; + } + +} diff --git a/src/main/java/com/jkgroller/githelp/service/converter/MilestoneTOConverter.java b/src/main/java/com/jkgroller/githelp/service/converter/MilestoneTOConverter.java new file mode 100644 index 0000000..ae680f4 --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/service/converter/MilestoneTOConverter.java @@ -0,0 +1,24 @@ +package com.jkgroller.githelp.service.converter; + +import com.jkgroller.githelp.adapter.response.MilestoneTO; +import com.jkgroller.githelp.service.response.SprintTO; +import com.jkgroller.githelp.util.AbstractConverter; +import org.gitlab4j.api.models.Milestone; +import org.springframework.stereotype.Component; + +@Component +public class MilestoneTOConverter extends AbstractConverter { + + @Override + public SprintTO convert(MilestoneTO from, Void context) { + + if(null == from){ + return null; + } + + SprintTO sprintTO = new SprintTO(); + sprintTO.setTitle(from.getTitle()); + + return sprintTO; + } +} diff --git a/src/main/java/com/jkgroller/githelp/service/request/RetrieveScrumInformationRequestTO.java b/src/main/java/com/jkgroller/githelp/service/request/RetrieveScrumInformationRequestTO.java new file mode 100644 index 0000000..b651df5 --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/service/request/RetrieveScrumInformationRequestTO.java @@ -0,0 +1,24 @@ +package com.jkgroller.githelp.service.request; + +public class RetrieveScrumInformationRequestTO { + + private int groupNumber; + + private int numberOfMilestonesToReturn = 5; + + public int getGroupNumber() { + return groupNumber; + } + + public void setGroupNumber(int groupNumber) { + this.groupNumber = groupNumber; + } + + public int getNumberOfMilestonesToReturn() { + return numberOfMilestonesToReturn; + } + + public void setNumberOfMilestonesToReturn(int numberOfMilestonesToReturn) { + this.numberOfMilestonesToReturn = numberOfMilestonesToReturn; + } +} diff --git a/src/main/java/com/jkgroller/githelp/service/response/RetrieveScrumInformationResponseTO.java b/src/main/java/com/jkgroller/githelp/service/response/RetrieveScrumInformationResponseTO.java new file mode 100644 index 0000000..1ce3609 --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/service/response/RetrieveScrumInformationResponseTO.java @@ -0,0 +1,38 @@ +package com.jkgroller.githelp.service.response; + +import com.jkgroller.githelp.adapter.response.MilestoneTO; + +import java.util.List; + +public class RetrieveScrumInformationResponseTO { + + private String groupName; + + private int velocity; + + private List completedSprintTOs; + + public String getGroupName() { + return groupName; + } + + public void setGroupName(String groupName) { + this.groupName = groupName; + } + + public int getVelocity() { + return velocity; + } + + public void setVelocity(int velocity) { + this.velocity = velocity; + } + + public List getCompletedSprintTOs() { + return completedSprintTOs; + } + + public void setCompletedSprintTOs(List completedSprintTOs) { + this.completedSprintTOs = completedSprintTOs; + } +} diff --git a/src/main/java/com/jkgroller/githelp/service/response/SprintTO.java b/src/main/java/com/jkgroller/githelp/service/response/SprintTO.java new file mode 100644 index 0000000..7700582 --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/service/response/SprintTO.java @@ -0,0 +1,46 @@ +package com.jkgroller.githelp.service.response; + +import java.util.List; + +public class SprintTO { + + private String title; + + private int storyPointsCompleted; + + private int numberOfStoriesCompleted; + + private List completedStories; + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public int getStoryPointsCompleted() { + return storyPointsCompleted; + } + + public void setStoryPointsCompleted(int storyPointsCompleted) { + this.storyPointsCompleted = storyPointsCompleted; + } + + public int getNumberOfStoriesCompleted() { + return numberOfStoriesCompleted; + } + + public void setNumberOfStoriesCompleted(int numberOfStoriesCompleted) { + this.numberOfStoriesCompleted = numberOfStoriesCompleted; + } + + public List getCompletedStories() { + return completedStories; + } + + public void setCompletedStories(List completedStories) { + this.completedStories = completedStories; + } +} diff --git a/src/main/java/com/jkgroller/githelp/service/response/StoryTO.java b/src/main/java/com/jkgroller/githelp/service/response/StoryTO.java new file mode 100644 index 0000000..7210a66 --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/service/response/StoryTO.java @@ -0,0 +1,41 @@ +/** + * + */ +package com.jkgroller.githelp.service.response; + +/** + * @author john@grollerfamily.com + * + */ +public class StoryTO { + + private String title; + + private String url; + + private int points; + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public int getPoints() { + return points; + } + + public void setPoints(int points) { + this.points = points; + } +} diff --git a/src/main/java/com/jkgroller/githelp/util/AbstractConverter.java b/src/main/java/com/jkgroller/githelp/util/AbstractConverter.java new file mode 100644 index 0000000..f90ef71 --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/util/AbstractConverter.java @@ -0,0 +1,76 @@ +package com.jkgroller.githelp.util; + +/** + * Copyright (c) 2018 John Groller + */ + +import org.apache.commons.lang3.ArrayUtils; +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public abstract class AbstractConverter implements Converter { + + @Override + public List convert(List fromObjects, W context) { + + if (CollectionUtils.isEmpty(fromObjects)) { + return emptyList(); + } + + List output = new ArrayList(); + for (F from : fromObjects) { + if (null == from) { + continue; + } + + T value = convert(from, context); + if (null != value) { + output.add(value); + } + } + return output; + } + + @SuppressWarnings("unchecked") + private List emptyList() { + return Collections.EMPTY_LIST; + } + + @Override + public T convert(F from) { + return convert(from, null); + } + + @Override + public List convert(F[] fromObjects, W context) { + if (ArrayUtils.isEmpty(fromObjects)) { + return emptyList(); + } + + List output = new ArrayList(); + for (int idx = 0; fromObjects.length > idx; idx++) { + if (null != fromObjects[idx]) { + T value = convert(fromObjects[idx], context); + if (null != value) { + output.add(value); + } + } + } + + return output; + } + + @Override + public List convert(List fromObjects) { + return convert(fromObjects, null); + } + + @Override + public List convert(F[] fromObjects) { + return convert(fromObjects, null); + } + +} diff --git a/src/main/java/com/jkgroller/githelp/util/Converter.java b/src/main/java/com/jkgroller/githelp/util/Converter.java new file mode 100644 index 0000000..7dbadc3 --- /dev/null +++ b/src/main/java/com/jkgroller/githelp/util/Converter.java @@ -0,0 +1,19 @@ +package com.jkgroller.githelp.util; + +import java.util.List; + +public interface Converter { + + T convert(F from, C context); + + T convert(F from); + + List convert(List from, C context); + + List convert(List from); + + List convert(F[] from, C context); + + List convert(F[] from); + +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..fa90aef --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,12 @@ +#=============================== +# = CRNK +# =============================== +crnk.path-prefix=/v1 +crnk.return404-on-null=true + +#=============================== +# = Gitlab +# =============================== +gitlab.url=https://git.grollerfamily.com +gitlab.apikey=DUmjEJ4hQ2GW_Rkzq4L7 +number.of.milestones=5 \ No newline at end of file