From f4adfbed3ecdd1418880d017b70f3d11333d154e Mon Sep 17 00:00:00 2001 From: David Russell Date: Wed, 7 Sep 2016 14:11:29 +0800 Subject: [PATCH] Added support for GitLab and Bitbucket slideshow presentations. The GitPitch server has been updated with support for GitPitch slideshow presentations powered by PITCHME.md within GitHub, GitLab and Bitbucket public repos. The git.repo.services property in application.conf can be used to register and configure custom GRS (Git Repo Services) for any GitPitch server deployment. --- PITCHME.md | 16 +- README.md | 10 +- app/Module.java | 6 + .../gitpitch/controllers/PitchController.java | 58 ++++-- app/com/gitpitch/git/GRS.java | 104 +++++++++++ app/com/gitpitch/git/GRSManager.java | 170 ++++++++++++++++++ app/com/gitpitch/git/GRSService.java | 132 ++++++++++++++ app/com/gitpitch/git/vendors/BitBucket.java | 78 ++++++++ app/com/gitpitch/git/vendors/GitHub.java | 77 ++++++++ app/com/gitpitch/git/vendors/GitLab.java | 88 +++++++++ .../gitpitch/models/BitBucketRepoModel.java | 146 +++++++++++++++ app/com/gitpitch/models/GitHubRepoModel.java | 146 +++++++++++++++ app/com/gitpitch/models/GitLabRepoModel.java | 150 ++++++++++++++++ app/com/gitpitch/models/GitRepoModel.java | 162 +++++------------ app/com/gitpitch/models/MarkdownModel.java | 2 + app/com/gitpitch/models/SlideshowModel.java | 13 +- app/com/gitpitch/services/DiskService.java | 60 +++---- app/com/gitpitch/services/GitService.java | 121 +++++++------ app/com/gitpitch/services/OfflineService.java | 53 ++++-- app/com/gitpitch/services/PitchService.java | 1 + app/com/gitpitch/services/PrintService.java | 3 +- app/com/gitpitch/utils/GitHub.java | 99 ---------- app/com/gitpitch/utils/GitRepoRenderer.java | 157 +++++++++++++--- app/com/gitpitch/utils/MarkdownRenderer.java | 10 +- app/com/gitpitch/utils/PitchParams.java | 48 +++-- app/com/gitpitch/utils/RFE.java | 30 ++-- app/com/gitpitch/utils/YAMLOptions.java | 15 +- app/com/gitpitch/views/Landing.scala.html | 27 ++- app/com/gitpitch/views/Slideshow.scala.html | 19 +- .../views/frags/LandingFooter.scala.html | 19 +- .../views/frags/LandingHeader.scala.html | 39 ++-- .../views/frags/LandingStyle.scala.html | 2 +- build.sbt | 2 +- conf/application.conf | 41 ++++- conf/logback.xml | 3 + conf/routes | 12 +- images/gp-url.jpg | Bin 7697 -> 9721 bytes test/com/gitpitch/FunctionalTest.java | 8 +- 38 files changed, 1653 insertions(+), 474 deletions(-) create mode 100644 app/com/gitpitch/git/GRS.java create mode 100644 app/com/gitpitch/git/GRSManager.java create mode 100644 app/com/gitpitch/git/GRSService.java create mode 100644 app/com/gitpitch/git/vendors/BitBucket.java create mode 100644 app/com/gitpitch/git/vendors/GitHub.java create mode 100644 app/com/gitpitch/git/vendors/GitLab.java create mode 100644 app/com/gitpitch/models/BitBucketRepoModel.java create mode 100644 app/com/gitpitch/models/GitHubRepoModel.java create mode 100644 app/com/gitpitch/models/GitLabRepoModel.java delete mode 100644 app/com/gitpitch/utils/GitHub.java diff --git a/PITCHME.md b/PITCHME.md index a78e911..97c2ddd 100644 --- a/PITCHME.md +++ b/PITCHME.md @@ -3,9 +3,13 @@ ![LOGO](https://d1z75bzl1vljy2.cloudfront.net/img/gp-logo.png) -#### Get the word out! +#### Get the word out
-Slideshow Presentations For Your GitHub Projects +Slideshow Presentations For Developers +
+on +
+GitHub - GitLab - Bitbucket #HSLIDE @@ -35,7 +39,7 @@ Create GitPitch slideshow content using GitHub flavored Markdown in your favorit ![TERMINAL](https://d1z75bzl1vljy2.cloudfront.net/hello-world/terminal.png) -Git-commit on any repo branch and push your PITCHME.md to GitHub. +Git-commit on any branch and push your PITCHME.md to GitHub, GitLab or Bitbucket. #HSLIDE @@ -43,11 +47,11 @@ Git-commit on any repo branch and push your PITCHME.md to GitHub.
-https://gitpitch.com/user/repo +https://gitpitch.com/user/repo/branch
-Instantly use your GitPitch slideshow URL to promote, pitch or present your GitHub project. +Instantly use your GitPitch slideshow URL to promote, pitch or present absolutely anything. #HSLIDE @@ -75,7 +79,7 @@ Instantly use your GitPitch slideshow URL to promote, pitch or present your GitH - Multiple Themes And More - Plus... - Your Slideshow Is Part Of Your Project -- Under Git Version Control Within Your GitHub Repo +- Under Git Version Control Within Your Git Repo #HSLIDE diff --git a/README.md b/README.md index e5fa4db..19f366e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![GitPitch](https://gitpitch.com/assets/badge.svg)](https://gitpitch.com/gitpitch/gitpitch/master) [![Build Status](https://semaphoreci.com/api/v1/gitpitch/gitpitch/branches/master/shields_badge.svg)](https://semaphoreci.com/gitpitch/gitpitch) -# Slideshow Presentations For Your GitHub Projects +# Slideshow Presentations For Developers #### WEBSITE: [www.gitpitch.com](https://gitpitch.com) | HOW-TO : [GitPitch Wiki](https://github.com/gitpitch/gitpitch/wiki) | TWITTER: [@gitpitch](https://twitter.com/gitpitch) @@ -12,9 +12,9 @@ ## What is GitPitch? -GitPitch is a service that turns **[PITCHME.md](https://gitpitch.com/#gitpitch-pitchme-markdown)** markdown into online, interactive slideshows. You can use it to promote, pitch or present anything, including your own GitHub projects. +GitPitch is a service that turns **[PITCHME.md](https://gitpitch.com/#gitpitch-pitchme-markdown)** markdown into online and offline, interactive slideshows. You can use it to promote, pitch or present absolutely anything, including your own Git projects. -Each slideshow presentation is made instantly available online just as soon as you git-commit and push **PITCHME.md** on any branch within a public GitHub repo. +Each slideshow presentation is made instantly available online just as soon as you git-commit and push **PITCHME.md** on any branch within a public **GitHub**, **GitLab** or **Bitbucket** repo. ![URL](images/gp-url.jpg) @@ -27,13 +27,13 @@ If you ever find yourself needing to present a concept, design, library, integra - To colleagues, clients or customers - Or at meetups or conferences -Then GitPitch is for you. Simply capture your ideas in Markdown and let GitPitch automatically turn those ideas into compelling, responsive, online slideshow presentations. +Then GitPitch is for you. Simply capture your ideas in Markdown and let GitPitch automatically turn those ideas into compelling, responsive, online and offline slideshow presentations. ## How does GitPitch work? ![TERMINAL](images/gp-terminal.png) -No more Keynote. No more PowerPoint. Just Markdown. Then git-commit on any branch within a public GitHub repo. +No more Keynote. No more PowerPoint. Just Markdown. Then git-commit on any branch within a public GitHub, GitLab or Bitbucket repo. ## GitPitch slideshow presentations are compelling diff --git a/app/Module.java b/app/Module.java index 5e4a5f0..1e53609 100644 --- a/app/Module.java +++ b/app/Module.java @@ -23,6 +23,8 @@ */ import com.gitpitch.factory.MarkdownModelFactory; +import com.gitpitch.git.*; +import com.gitpitch.git.vendors.*; import com.gitpitch.models.Markdown; import com.gitpitch.models.MarkdownModel; import com.gitpitch.services.*; @@ -49,6 +51,10 @@ public class Module extends AbstractModule { bind(ImageService.class).asEagerSingleton(); bind(VideoService.class).asEagerSingleton(); bind(GISTService.class).asEagerSingleton(); + bind(GRSManager.class).asEagerSingleton(); + bind(GitHub.class).asEagerSingleton(); + bind(GitLab.class).asEagerSingleton(); + bind(BitBucket.class).asEagerSingleton(); bind(FrontEndThreads.class).asEagerSingleton(); bind(BackEndThreads.class).asEagerSingleton(); bind(Dependencies.class).asEagerSingleton(); diff --git a/app/com/gitpitch/controllers/PitchController.java b/app/com/gitpitch/controllers/PitchController.java index 0197c46..c4c1d56 100644 --- a/app/com/gitpitch/controllers/PitchController.java +++ b/app/com/gitpitch/controllers/PitchController.java @@ -23,6 +23,8 @@ */ package com.gitpitch.controllers; +import com.gitpitch.git.GRS; +import com.gitpitch.git.GRSManager; import com.gitpitch.models.GitRepoModel; import com.gitpitch.models.MarkdownModel; import com.gitpitch.executors.FrontEndThreads; @@ -56,6 +58,7 @@ public class PitchController extends Controller { private final PitchService pitchService; private final FrontEndThreads frontEndThreads; private final Dependencies deps; + private final GRSManager grsManager; private final Configuration cfg; private final WSClient ws; private final Environment env; @@ -65,6 +68,7 @@ public class PitchController extends Controller { public PitchController(PitchService pitchService, FrontEndThreads frontEndThreads, Dependencies deps, + GRSManager grsManager, Configuration cfg, WSClient ws, Environment env) { @@ -72,6 +76,7 @@ public class PitchController extends Controller { this.pitchService = pitchService; this.frontEndThreads = frontEndThreads; this.deps = deps; + this.grsManager = grsManager; this.cfg = cfg; this.ws = ws; this.env = env; @@ -117,11 +122,13 @@ public class PitchController extends Controller { public CompletionStage landing(String user, String repo, String branch, + String grs, String theme, String notes, String offline) { - PitchParams pp = PitchParams.build(user, repo, branch, theme, notes); + PitchParams pp = + PitchParams.build(grsOnCall(grs), user, repo, branch, theme, notes); boolean isOffline = (offline == null) ? false : Boolean.parseBoolean(offline); Optional grmo = pitchService.cachedRepo(pp); @@ -134,7 +141,8 @@ public class PitchController extends Controller { log.info("landing: [ cached, online ] {}", pp); GitRepoModel grm = grmo.get(); - GitRepoRenderer rndr = GitRepoRenderer.build(pp, grm, cfg); + GitRepoRenderer rndr = + GitRepoRenderer.build(pp, grm, cfg, grsManager.listGRS()); return CompletableFuture.completedFuture( ok(com.gitpitch.views.html.Landing.render(rndr, @@ -149,7 +157,9 @@ public class PitchController extends Controller { }, frontEndThreads.POOL) .thenApply(fetched -> { - GitRepoRenderer rndr = GitRepoRenderer.build(pp, fetched, cfg); + GitRepoRenderer rndr = + GitRepoRenderer.build(pp, fetched, cfg, + grsManager.listGRS()); if (rndr.isValid()) { if (isOffline) @@ -173,7 +183,8 @@ public class PitchController extends Controller { /* * Slideshow builds and renders a GitPitch slideshow page. */ - public CompletionStage slideshow(String user, + public CompletionStage slideshow(String grs, + String user, String repo, String branch, String theme, @@ -181,7 +192,8 @@ public class PitchController extends Controller { String fragments, String offline) { - PitchParams pp = PitchParams.build(user, repo, branch, theme, notes); + PitchParams pp = + PitchParams.build(grsOnCall(grs), user, repo, branch, theme, notes); boolean printing = (fragments == null) ? false : !Boolean.parseBoolean(fragments); boolean isOffline = @@ -234,11 +246,13 @@ public class PitchController extends Controller { /* * Markdown processes and renders PITCHME.md markdown. */ - public CompletionStage markdown(String user, + public CompletionStage markdown(String grs, + String user, String repo, String branch) { - PitchParams pp = PitchParams.build(user, repo, branch); + PitchParams pp = + PitchParams.build(grsOnCall(grs), user, repo, branch); Optional mdmo = pitchService.cachedMarkdown(pp); if (mdmo.isPresent()) { @@ -263,10 +277,12 @@ public class PitchController extends Controller { } if (pp.isMaster()) { log.info("markdown: [ notfnd, online ] {}", pp); - return ok(RFE.build(pp)).as("text/markdown"); + return ok(RFE.master(pp, grsManager.get(pp))) + .as("text/markdown"); } else { log.info("markdown: [ notfnd, online ] {}", pp); - return ok(RFE.PITCHME_NOT_FOUND_ON_BRANCH).as("text/markdown"); + return ok(RFE.branch(pp, grsManager.get(pp))) + .as("text/markdown"); } }); } @@ -276,13 +292,15 @@ public class PitchController extends Controller { /* * Print generates and renders PITCHME.pdf. */ - public CompletionStage print(String user, + public CompletionStage print(String grs, + String user, String repo, String branch, String theme, String notes) { - PitchParams pp = PitchParams.build(user, repo, branch, theme, notes); + PitchParams pp = + PitchParams.build(grsOnCall(grs), user, repo, branch, theme, notes); Optional pdfo = pitchService.cachedPDF(pp); if (pdfo.isPresent()) { @@ -316,14 +334,17 @@ public class PitchController extends Controller { /* * Offline generates and renders PITCHME.zip. */ - public CompletionStage offline(String user, + public CompletionStage offline(String grs, + String user, String repo, String branch, String theme, String notes) { + - PitchParams pp = PitchParams.build(user, repo, branch, theme, notes); - log.debug("print: pp={}", pp); + PitchParams pp = + PitchParams.build(grsOnCall(grs), user, repo, branch, theme, notes); + log.debug("offline: pp={}", pp); Optional zipo = pitchService.cachedZip(pp); @@ -353,7 +374,7 @@ public class PitchController extends Controller { }); } - } // print action + } // offline action /* * Gist generates and renders GitHub-Gist HTML for @@ -363,6 +384,13 @@ public class PitchController extends Controller { return ok(com.gitpitch.views.html.Gist.render(gid, deps)); } // gist action + /* + * Determine GRS on call, explicitly defined or default. + */ + private String grsOnCall(String grsParam) { + return grsManager.getType(grsParam); + } + private static final String PITCHME_PRINT_ERROR = "GitPitch Slideshow print service temporarily unavailable."; private static final String PITCHME_OFFLINE_ERROR = diff --git a/app/com/gitpitch/git/GRS.java b/app/com/gitpitch/git/GRS.java new file mode 100644 index 0000000..ec271e2 --- /dev/null +++ b/app/com/gitpitch/git/GRS.java @@ -0,0 +1,104 @@ +/* + * MIT License + * + * Copyright (c) 2016 David Russell + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.gitpitch.git; + +import com.gitpitch.utils.PitchParams; +import java.util.Map; +import java.util.HashMap; + +/* + * Git Respository Service model. + */ +public class GRS { + + private final String name; + private final String type; + private final String site; + private final String apiBase; + private final String apiToken; + private final String apiTokenHeader; + private final String rawBase; + private final boolean isDefault; + + private GRS(String name, + String type, + String site, + String apiBase, + String apiToken, + String apiTokenHeader, + String rawBase, + boolean isDefault) { + + this.name = name; + this.type = type; + this.site = site; + this.apiBase = apiBase; + this.apiToken = apiToken; + this.apiTokenHeader = apiTokenHeader; + this.rawBase = rawBase; + this.isDefault = isDefault; + } + + public static GRS build(Map grsCfg) { + + String name = grsCfg.get("name"); + String type = grsCfg.get("type"); + String site = grsCfg.get("site"); + String apiBase = grsCfg.get("apibase"); + String apiToken = grsCfg.get("apitoken"); + String apiTokenHeader = grsCfg.get("apitokenheader"); + String rawBase = grsCfg.get("rawbase"); + boolean isDefault = Boolean.parseBoolean(grsCfg.get("default")); + + if(name != null && type != null && site != null && + apiBase != null && rawBase != null) { + return new GRS(name, type, site, apiBase, apiToken, + apiTokenHeader, rawBase, isDefault); + } else { + return null; + } + } + + public String getName() { return name; } + public String getType() { return type; } + public String getSite() { return site; } + public String getApiBase() { return apiBase; } + public String getApiToken() { return apiToken; } + public String getApiTokenHeader() { return apiTokenHeader; } + public String getRawBase() { return rawBase; } + public boolean isDefault() { return isDefault; } + + public Map getHeaders() { + Map hdrs = new HashMap(); + if(getApiToken() != null && getApiTokenHeader() != null) { + hdrs.put(getApiTokenHeader(), getApiToken()); + } + return hdrs; + } + + public String toString() { + return "GRS[ " + name + " ][ " + type + " ]"; + } + +} diff --git a/app/com/gitpitch/git/GRSManager.java b/app/com/gitpitch/git/GRSManager.java new file mode 100644 index 0000000..091a446 --- /dev/null +++ b/app/com/gitpitch/git/GRSManager.java @@ -0,0 +1,170 @@ +/* + * MIT License + * + * Copyright (c) 2016 David Russell + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.gitpitch.git; + +import com.gitpitch.git.vendors.*; +import com.gitpitch.services.DiskService; +import com.gitpitch.utils.PitchParams; +import java.util.*; +import java.util.stream.Collectors; +import javax.inject.*; +import play.Configuration; +import play.Logger; +import play.Logger.ALogger; + +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; + +/* + * Git Repository Service manager. + */ +@Singleton +public class GRSManager { + + private final Logger.ALogger log = Logger.of(this.getClass()); + + private final DiskService diskService; + private final GitHub gitHubService; + private final GitLab gitLabService; + private final BitBucket bitBucketService; + private final Configuration cfg; + private final Map grsStore = new HashMap(); + private GRS grsDefault; + + @Inject + public GRSManager(DiskService diskService, + GitHub gitHubService, + GitLab gitLabService, + BitBucket bitBucketService, + Configuration cfg) { + + this.diskService = diskService; + + this.gitHubService = gitHubService; + this.gitHubService.init(this, diskService); + + this.gitLabService = gitLabService; + this.gitLabService.init(this, diskService); + + this.bitBucketService = bitBucketService; + this.bitBucketService.init(this, diskService); + + this.cfg = cfg; + + List grsCfg = cfg.getList("gitpitch.git.repo.services"); + List> grsCfgList = (List>) grsCfg; + + GRS fallback = GRS.build(GRS_FALLBACK); + + for(HashMap grsMap : grsCfgList) { + GRS grs = GRS.build(grsMap); + + if(grs != null) { + + grsStore.put(grs.getType(), grs); + if(grs.isDefault()) + grsDefault = grs; + + } else { + log.warn("rejecting: {}", grsMap); + } + } + + if(grsStore.isEmpty()) { + grsStore.put(fallback.getType(), fallback); + grsDefault = fallback; + log.info("fallback: {}, type={}, true", + grsDefault.getName(), grsDefault.getType()); + } + + if(grsDefault == null) { + grsDefault = fallback; + } + + grsStore.forEach((k,v) -> { + log.info("activating: {}, type={}, default={}", + v.getName(), k, v.isDefault()); + }); + } + + public GRS get(PitchParams pp) { + return get(pp.grs); + } + + public GRS get(String grsType) { + GRS grs = grsStore.get(grsType); + return (grs != null) ? grs : grsDefault; + } + + public String getType(String grsType) { + GRS grs = grsStore.get(grsType); + return (grs != null) ? grs.getType() : grsDefault.getType(); + } + + public GRSService getService(GRS grs) { + + GRSService service; + + switch(grs.getType()) { + + case GitHub.TYPE: + log.debug("getService: matching GitHub"); + service = gitHubService; + break; + case GitLab.TYPE: + log.debug("getService: matching GitLab"); + service = gitLabService; + break; + case BitBucket.TYPE: + log.debug("getService: matching BitBucket"); + service = bitBucketService; + break; + default: + log.debug("getService: defaulting GitHub"); + service = gitHubService; + } + + log.debug("getService: returning={}", service); + return service; + } + + public List listGRS() { + List services = grsStore.entrySet() + .stream() + .map(Map.Entry::getValue) + .collect(Collectors.toList()); + log.debug("listGRS: {}", services); + return services; + } + + static Map GRS_FALLBACK = new HashMap(); + static { + GRS_FALLBACK.put("name", "GitHub"); + GRS_FALLBACK.put("type", "github"); + GRS_FALLBACK.put("apibase", "https://api.github.com/"); + GRS_FALLBACK.put("apitoken", null); + GRS_FALLBACK.put("rawbase", "https://raw.githubusercontent.com/"); + GRS_FALLBACK.put("default", "true"); + } +} \ No newline at end of file diff --git a/app/com/gitpitch/git/GRSService.java b/app/com/gitpitch/git/GRSService.java new file mode 100644 index 0000000..12d8dd5 --- /dev/null +++ b/app/com/gitpitch/git/GRSService.java @@ -0,0 +1,132 @@ +/* + * MIT License + * + * Copyright (c) 2016 David Russell + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.gitpitch.git; + +import com.gitpitch.git.*; +import com.gitpitch.models.GitRepoModel; +import com.gitpitch.utils.PitchParams; +import com.gitpitch.services.DiskService; +import java.nio.file.Path; +import java.util.concurrent.atomic.AtomicInteger; +import com.fasterxml.jackson.databind.JsonNode; +import play.Logger; +import play.Logger.ALogger; + +/* + * Git Respository Service common interface. + */ +public abstract class GRSService { + + private final Logger.ALogger log = Logger.of(this.getClass()); + + protected final AtomicInteger cacheBypass = new AtomicInteger(); + protected GRSManager grsManager; + protected DiskService diskService; + + public void init(GRSManager grsManager, + DiskService diskService) { + this.grsManager = grsManager; + this.diskService = diskService; + } + + /* + * Return true if apiPath is a call on this GRSService instance. + */ + public boolean call(PitchParams pp, String apiPath) { + + if(apiPath != null) { + GRS grs = grsManager.get(pp); + return apiPath.startsWith(grs.getApiBase()) || + apiPath.startsWith(grs.getRawBase()); + } else { + return false; + } + } + + /* + * Return zero if file download completes successfully. + */ + public int download(PitchParams pp, String filename) { + + int status = 999; + + GRS grs = grsManager.get(pp); + GRSService grsService = grsManager.getService(grs); + Path branchPath = diskService.ensure(pp); + String grsLink = raw(pp, filename, true); + log.debug("download: grsLink={}", grsLink); + + if (grsService.call(pp, grsLink)) { + status = diskService.download(pp, + branchPath, + grsLink, + filename, + grs.getHeaders()); + } + + log.debug("download: returning status={}", status); + return status; + } + + /* + * Return model representing Git repository meta-data. + */ + public abstract GitRepoModel model(PitchParams pp, JsonNode json); + + /* + * Return Raw API path for /user/repo/branch. + */ + public abstract String raw(PitchParams pp); + + /* + * Return Raw API path for /user/repo/branch/filename. + */ + public String raw(PitchParams pp, String filename) { + return raw(pp, filename, false); + } + + /* + * Return Raw API path for /user/repo/branch/filename with + * optional query param used to bypass GRS API caching. + */ + public String raw(PitchParams pp, + String filename, + boolean bypassCache) { + + if (bypassCache) { + return raw(pp) + filename + + "?gp=" + cacheBypass.getAndIncrement(); + } else { + return raw(pp) + filename; + } + } + + /* + * Return API path for repository meta call for /user/repo. + */ + public abstract String repo(PitchParams pp); + + protected static final String SLASH = "/"; + +} diff --git a/app/com/gitpitch/git/vendors/BitBucket.java b/app/com/gitpitch/git/vendors/BitBucket.java new file mode 100644 index 0000000..ee392cf --- /dev/null +++ b/app/com/gitpitch/git/vendors/BitBucket.java @@ -0,0 +1,78 @@ +/* + * MIT License + * + * Copyright (c) 2016 David Russell + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.gitpitch.git.vendors; + +import com.gitpitch.git.*; +import com.gitpitch.models.*; +import com.gitpitch.utils.PitchParams; +import com.gitpitch.services.DiskService; +import com.fasterxml.jackson.databind.JsonNode; +import java.nio.file.Path; +import java.util.*; +import javax.inject.*; +import play.Logger; +import play.Logger.ALogger; + +/* + * BitBucket API Service. + */ +@Singleton +public class BitBucket extends GRSService { + + private final Logger.ALogger log = Logger.of(this.getClass()); + + public GitRepoModel model(PitchParams pp, JsonNode json) { + return BitBucketRepoModel.build(pp, json); + } + + public String raw(PitchParams pp) { + + GRS grs = grsManager.get(pp); + + return new StringBuffer(grs.getRawBase()) + .append(pp.user) + .append(SLASH) + .append(pp.repo) + .append(BITBUCKET_RAW) + .append(pp.branch) + .append(SLASH) + .toString(); + } + + public String repo(PitchParams pp) { + + GRS grs = grsManager.get(pp); + + return new StringBuffer(grs.getApiBase()) + .append(BITBUCKET_REPO_API) + .append(pp.user) + .append(SLASH) + .append(pp.repo) + .toString(); + } + + public static final String TYPE = "bitbucket"; + private static final String BITBUCKET_REPO_API = "repositories/"; + private static final String BITBUCKET_RAW = "/raw/"; +} diff --git a/app/com/gitpitch/git/vendors/GitHub.java b/app/com/gitpitch/git/vendors/GitHub.java new file mode 100644 index 0000000..3cbf54f --- /dev/null +++ b/app/com/gitpitch/git/vendors/GitHub.java @@ -0,0 +1,77 @@ +/* + * MIT License + * + * Copyright (c) 2016 David Russell + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.gitpitch.git.vendors; + +import com.gitpitch.git.*; +import com.gitpitch.models.*; +import com.gitpitch.services.DiskService; +import com.gitpitch.utils.PitchParams; +import com.fasterxml.jackson.databind.JsonNode; +import java.nio.file.Path; +import java.util.*; +import javax.inject.*; +import play.Logger; +import play.Logger.ALogger; + +/* + * GitHub API Service. + */ +@Singleton +public class GitHub extends GRSService { + + private final Logger.ALogger log = Logger.of(this.getClass()); + + public GitRepoModel model(PitchParams pp, JsonNode json) { + return GitHubRepoModel.build(pp, json); + } + + public String raw(PitchParams pp) { + + GRS grs = grsManager.get(pp); + + return new StringBuffer(grs.getRawBase()) + .append(pp.user) + .append(SLASH) + .append(pp.repo) + .append(SLASH) + .append(pp.branch) + .append(SLASH) + .toString(); + } + + public String repo(PitchParams pp) { + + GRS grs = grsManager.get(pp); + + return new StringBuffer(grs.getApiBase()) + .append(GITHUB_REPO_API) + .append(pp.user) + .append(SLASH) + .append(pp.repo) + .toString(); + } + + public static final String TYPE = "github"; + private static final String GITHUB_REPO_API = "repos/"; +} diff --git a/app/com/gitpitch/git/vendors/GitLab.java b/app/com/gitpitch/git/vendors/GitLab.java new file mode 100644 index 0000000..0bc4d32 --- /dev/null +++ b/app/com/gitpitch/git/vendors/GitLab.java @@ -0,0 +1,88 @@ +/* + * MIT License + * + * Copyright (c) 2016 David Russell + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.gitpitch.git.vendors; + +import com.gitpitch.git.*; +import com.gitpitch.models.*; +import com.gitpitch.services.DiskService; +import com.gitpitch.utils.PitchParams; +import com.fasterxml.jackson.databind.JsonNode; +import java.nio.file.Path; +import java.util.*; +import javax.inject.*; +import play.Logger; +import play.Logger.ALogger; + +/* + * GitLab API Service. + */ +@Singleton +public class GitLab extends GRSService { + + private final Logger.ALogger log = Logger.of(this.getClass()); + + public GitRepoModel model(PitchParams pp, JsonNode json) { + return GitLabRepoModel.build(pp, json); + } + + public String raw(PitchParams pp) { + + GRS grs = grsManager.get(pp); + + return new StringBuffer(grs.getRawBase()) + .append(pp.user) + .append(SLASH) + .append(pp.repo) + .append(GITLAB_RAW) + .append(pp.branch) + .append(SLASH) + .toString(); + } + + public String repo(PitchParams pp) { + + GRS grs = grsManager.get(pp); + + return new StringBuffer(grs.getApiBase()) + .append(GITLAB_PROJECTS_API) + .append(genProjectId(pp)) + .toString(); + } + + private String genProjectId(PitchParams pp) { + + String userRepo = + new StringBuffer(pp.user).append(SLASH) + .append(pp.repo) + .toString(); + + String pid = java.net.URLEncoder.encode(userRepo); + log.debug("genProjectId: pid={}", pid); + return pid; + } + + public static final String TYPE = "gitlab"; + private static final String GITLAB_PROJECTS_API = "projects/"; + private static final String GITLAB_RAW = "/raw/"; +} diff --git a/app/com/gitpitch/models/BitBucketRepoModel.java b/app/com/gitpitch/models/BitBucketRepoModel.java new file mode 100644 index 0000000..a39d77f --- /dev/null +++ b/app/com/gitpitch/models/BitBucketRepoModel.java @@ -0,0 +1,146 @@ +/* + * MIT License + * + * Copyright (c) 2016 David Russell + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.gitpitch.models; + +import com.fasterxml.jackson.databind.JsonNode; +import com.gitpitch.utils.PitchParams; +import play.Logger; +import play.Logger.ALogger; + +import java.util.*; + +/* + * Rendering model for views.Landing.scala.html. + */ +public class BitBucketRepoModel extends GitRepoModel { + + private final Logger.ALogger log = Logger.of(this.getClass()); + + /* + * Initialize instance of BitBucketRepoModel. + */ + private BitBucketRepoModel(PitchParams pp) { + this(pp, null); + } + + /* + * Initialize instance of BitBucketRepoModel. + */ + private BitBucketRepoModel(PitchParams pp, + JsonNode json) { + + this._pp = pp; + + this._pretty = new StringBuffer(SLASH) + .append(this._pp.user) + .append(SLASH) + .append(this._pp.repo) + .toString(); + + this._cacheKey = genKey(pp); + + /* + * Generate derived data on instance only if the BitBucket + * API JSON is available for processing. + */ + if (json != null) { + + JsonNode ownerNode = json.findPath("owner"); + this._type = ownerNode.findPath("type").textValue(); + + this._desc = json.findPath("description").textValue(); + this._created = json.findPath("created_on").textValue(); + this._updated = json.findPath("updated_on").textValue(); + this._lang = json.findPath("language").textValue(); + + this._stars = 0; + this._forks = 0; + this._issues = 0; + + this._hasWiki = json.findPath("has_wiki").asBoolean(); + this._hasPages = false; + + } else { + + this._type = null; + + this._desc = null; + this._created = null; + this._updated = null; + this._lang = null; + + this._stars = 0; + this._forks = 0; + this._issues = 0; + + this._hasWiki = false; + this._hasPages = false; + } + + } + + public static GitRepoModel build(PitchParams pp) { + return build(pp, null); + } + + public static GitRepoModel build(PitchParams pp, JsonNode json) { + return new BitBucketRepoModel(pp, json); + } + + public String owner() { + return _pp.user; + } + + public String name() { + return _pp.repo; + } + + public String description() { + return _desc; + } + + public String lang() { + return _lang; + } + + public boolean byOrg() { + return GIT_TYPE_ORG.equals(_type); + } + + public int stargazers() { + return _stars; + } + + public int forks() { + return _forks; + } + + public String toString() { + return _pretty; + } + + public String key() { + return _cacheKey; + } +} diff --git a/app/com/gitpitch/models/GitHubRepoModel.java b/app/com/gitpitch/models/GitHubRepoModel.java new file mode 100644 index 0000000..8a76ba1 --- /dev/null +++ b/app/com/gitpitch/models/GitHubRepoModel.java @@ -0,0 +1,146 @@ +/* + * MIT License + * + * Copyright (c) 2016 David Russell + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.gitpitch.models; + +import com.fasterxml.jackson.databind.JsonNode; +import com.gitpitch.utils.PitchParams; +import play.Logger; +import play.Logger.ALogger; + +import java.util.*; + +/* + * Rendering model for views.Landing.scala.html. + */ +public class GitHubRepoModel extends GitRepoModel { + + private final Logger.ALogger log = Logger.of(this.getClass()); + + /* + * Initialize instance of GitHubRepoModel. + */ + private GitHubRepoModel(PitchParams pp) { + this(pp, null); + } + + /* + * Initialize instance of GitHubRepoModel. + */ + private GitHubRepoModel(PitchParams pp, + JsonNode json) { + + this._pp = pp; + + this._pretty = new StringBuffer(SLASH) + .append(this._pp.user) + .append(SLASH) + .append(this._pp.repo) + .toString(); + + this._cacheKey = genKey(pp); + + /* + * Generate derived data on instance only if the GitHub + * API JSON is available for processing. + */ + if (json != null) { + + JsonNode ownerNode = json.findPath("owner"); + this._type = ownerNode.findPath("type").textValue(); + + this._desc = json.findPath("description").textValue(); + this._created = json.findPath("created_at").textValue(); + this._updated = json.findPath("updated_at").textValue(); + this._lang = json.findPath("language").textValue(); + + this._stars = json.findPath("stargazers_count").asInt(); + this._forks = json.findPath("forks_count").asInt(); + this._issues = json.findPath("open_issues").asInt(); + + this._hasWiki = json.findPath("has_wiki").asBoolean(); + this._hasPages = json.findPath("has_pages").asBoolean(); + + } else { + + this._type = null; + + this._desc = null; + this._created = null; + this._updated = null; + this._lang = null; + + this._stars = 0; + this._forks = 0; + this._issues = 0; + + this._hasWiki = false; + this._hasPages = false; + } + + } + + public static GitRepoModel build(PitchParams pp) { + return build(pp, null); + } + + public static GitRepoModel build(PitchParams pp, JsonNode json) { + return new GitHubRepoModel(pp, json); + } + + public String owner() { + return _pp.user; + } + + public String name() { + return _pp.repo; + } + + public String description() { + return _desc; + } + + public String lang() { + return _lang; + } + + public boolean byOrg() { + return GIT_TYPE_ORG.equals(_type); + } + + public int stargazers() { + return _stars; + } + + public int forks() { + return _forks; + } + + public String toString() { + return _pretty; + } + + public String key() { + return _cacheKey; + } +} diff --git a/app/com/gitpitch/models/GitLabRepoModel.java b/app/com/gitpitch/models/GitLabRepoModel.java new file mode 100644 index 0000000..7486032 --- /dev/null +++ b/app/com/gitpitch/models/GitLabRepoModel.java @@ -0,0 +1,150 @@ +/* + * MIT License + * + * Copyright (c) 2016 David Russell + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.gitpitch.models; + +import com.fasterxml.jackson.databind.JsonNode; +import com.gitpitch.utils.PitchParams; +import play.Logger; +import play.Logger.ALogger; + +import java.util.*; + +/* + * Rendering model for views.Landing.scala.html. + */ +public class GitLabRepoModel extends GitRepoModel { + + private final Logger.ALogger log = Logger.of(this.getClass()); + + /* + * Initialize instance of GitLabRepoModel. + */ + private GitLabRepoModel(PitchParams pp) { + this(pp, null); + } + + /* + * Initialize instance of GitLabRepoModel. + */ + private GitLabRepoModel(PitchParams pp, + JsonNode json) { + + this._pp = pp; + + this._pretty = new StringBuffer(SLASH) + .append(this._pp.user) + .append(SLASH) + .append(this._pp.repo) + .toString(); + + this._cacheKey = genKey(pp); + + /* + * Generate derived data on instance only if the GitLab + * API JSON is available for processing. + */ + if (json != null) { + + this._type = USER_TYPE; + this._desc = json.findPath("description").textValue(); + this._lang = null; + + JsonNode namespaceNode = json.findPath("namespace"); + if(namespaceNode != null) { + this._created = namespaceNode.findPath("created_at").textValue(); + this._updated = namespaceNode.findPath("updated_at").textValue(); + } + + this._stars = json.findPath("star_count").asInt(); + this._forks = json.findPath("forks_count").asInt(); + this._issues = json.findPath("open_issues_count").asInt(); + + this._hasWiki = json.findPath("wiki_enabled").asBoolean(); + this._hasPages = false; + + } else { + + this._type = null; + + this._desc = null; + this._created = null; + this._updated = null; + this._lang = null; + + this._stars = 0; + this._forks = 0; + this._issues = 0; + + this._hasWiki = false; + this._hasPages = false; + } + + } + + public static GitRepoModel build(PitchParams pp) { + return build(pp, null); + } + + public static GitRepoModel build(PitchParams pp, JsonNode json) { + return new GitLabRepoModel(pp, json); + } + + public String owner() { + return _pp.user; + } + + public String name() { + return _pp.repo; + } + + public String description() { + return _desc; + } + + public String lang() { + return _lang; + } + + public boolean byOrg() { + return GIT_TYPE_ORG.equals(_type); + } + + public int stargazers() { + return _stars; + } + + public int forks() { + return _forks; + } + + public String toString() { + return _pretty; + } + + public String key() { + return _cacheKey; + } + + private static final String USER_TYPE = "User"; +} diff --git a/app/com/gitpitch/models/GitRepoModel.java b/app/com/gitpitch/models/GitRepoModel.java index 6d59548..ad0f3d6 100644 --- a/app/com/gitpitch/models/GitRepoModel.java +++ b/app/com/gitpitch/models/GitRepoModel.java @@ -23,7 +23,6 @@ */ package com.gitpitch.models; -import com.fasterxml.jackson.databind.JsonNode; import com.gitpitch.utils.PitchParams; import play.Logger; import play.Logger.ALogger; @@ -33,124 +32,59 @@ import java.util.*; /* * Rendering model for views.Landing.scala.html. */ -public class GitRepoModel { +public abstract class GitRepoModel { private final Logger.ALogger log = Logger.of(this.getClass()); /* * PitchParams. */ - private final PitchParams _pp; + protected PitchParams _pp; /* - * GitHub repository owner type: User or Organization. + * Git repository owner type: User or Organization. */ - private final String _type; + protected String _type; /* - * GitHub repository description. + * Git repository description. */ - private final String _desc; + protected String _desc; /* - * GitHub repository creation date. + * Git repository creation date. */ - private final String _created; + protected String _created; /* - * GitHub repository last updated date. + * Git repository last updated date. */ - private final String _updated; + protected String _updated; /* - * GitHub repository language. + * Git repository language. */ - private final String _lang; + protected String _lang; /* - * GitHub repository stargazers_count. + * Git repository stargazers_count. */ - private final int _stars; + protected int _stars; /* - * GitHub repository forks_count. + * Git repository forks_count. */ - private final int _forks; + protected int _forks; /* - * GitHub repository open issues count. + * Git repository open issues count. */ - private final int _issues; + protected int _issues; /* - * GitHub repository has Wiki flag. + * Git repository has Wiki flag. */ - private final boolean _hasWiki; + protected boolean _hasWiki; /* - * GitHub repository has Pages (website) flag. + * Git repository has Pages (website) flag. */ - private final boolean _hasPages; + protected boolean _hasPages; /* * Derived immutable state. */ - private final String _pretty; - private final String _cacheKey; - - /* - * Initialize instance of GitRepoModel. - */ - public GitRepoModel(PitchParams pp) { - this(pp, null); - } - - /* - * Initialize instance of GitRepoModel. - */ - public GitRepoModel(PitchParams pp, - JsonNode json) { - - this._pp = pp; - - this._pretty = new StringBuffer(SLASH) - .append(this._pp.user) - .append(SLASH) - .append(this._pp.repo) - .toString(); - - this._cacheKey = new StringBuffer(MODEL_ID) - .append(this._pretty) - .toString(); - - /* - * Generate derived data on instance only if the GitHub - * API JSON is available for processing. - */ - if (json != null) { - - JsonNode ownerNode = json.findPath("owner"); - this._type = ownerNode.findPath("type").textValue(); - - this._desc = json.findPath("description").textValue(); - this._created = json.findPath("created_at").textValue(); - this._updated = json.findPath("updated_at").textValue(); - this._lang = json.findPath("language").textValue(); - - this._stars = json.findPath("stargazers_count").asInt(); - this._forks = json.findPath("forks_count").asInt(); - this._issues = json.findPath("open_issues").asInt(); - - this._hasWiki = json.findPath("has_wiki").asBoolean(); - this._hasPages = json.findPath("has_pages").asBoolean(); - - } else { - - this._type = null; - - this._desc = null; - this._created = null; - this._updated = null; - this._lang = null; - - this._stars = 0; - this._forks = 0; - this._issues = 0; - - this._hasWiki = false; - this._hasPages = false; - } - - } + protected String _pretty; + protected String _cacheKey; /* * Generate a key for querying the cache for matching GitRepoModel. @@ -158,6 +92,8 @@ public class GitRepoModel { public static String genKey(PitchParams pp) { return new StringBuffer(MODEL_ID).append(SLASH) + .append(pp.grs) + .append(SLASH) .append(pp.user) .append(SLASH) .append(pp.repo) @@ -165,53 +101,39 @@ public class GitRepoModel { } /* - * Return GitHub repository owner. + * Return Git repository owner. */ - public String owner() { - return _pp.user; - } + public abstract String owner(); /* - * Return GitHub repository name. + * Return Git repository name. */ - public String name() { - return _pp.repo; - } + public abstract String name(); /* - * Return GitHub repository description. + * Return Git repository description. */ - public String description() { - return _desc; - } + public abstract String description(); /* - * Return GitHub repository language. + * Return Git repository language. */ - public String lang() { - return _lang; - } + public abstract String lang(); /* - * Return true if GitHub repository owner is an organization. + * Return true if Git repository owner is an organization. */ - public boolean byOrg() { - return GIT_TYPE_ORG.equals(_type); - } + public abstract boolean byOrg(); /* - * Return number of GitHub repository stargazers. + * Return number of Git repository stargazers. */ - public int stargazers() { - return _stars; - } + public abstract int stargazers(); /* - * Return number of GitHub repository forks. + * Return number of Git repository forks. */ - public int forks() { - return _forks; - } + public abstract int forks(); public String toString() { return _pretty; @@ -221,8 +143,8 @@ public class GitRepoModel { return _cacheKey; } - private static final String GIT_TYPE_ORG = "Organization"; - private static final String SLASH = "/"; + protected static final String GIT_TYPE_ORG = "Organization"; + protected static final String SLASH = "/"; /* * Model prefix identifier for cache key generator. */ diff --git a/app/com/gitpitch/models/MarkdownModel.java b/app/com/gitpitch/models/MarkdownModel.java index a8d7a6f..31569e4 100644 --- a/app/com/gitpitch/models/MarkdownModel.java +++ b/app/com/gitpitch/models/MarkdownModel.java @@ -486,6 +486,8 @@ public class MarkdownModel implements Markdown { public static String genKey(PitchParams pp) { return new StringBuffer(MODEL_ID).append(SLASH) + .append(pp.grs) + .append(SLASH) .append(pp.user) .append(SLASH) .append(pp.repo) diff --git a/app/com/gitpitch/models/SlideshowModel.java b/app/com/gitpitch/models/SlideshowModel.java index fe7166e..571c455 100644 --- a/app/com/gitpitch/models/SlideshowModel.java +++ b/app/com/gitpitch/models/SlideshowModel.java @@ -24,6 +24,7 @@ package com.gitpitch.models; import com.gitpitch.models.MarkdownModel; +import com.gitpitch.git.GRSService; import com.gitpitch.services.DiskService; import com.gitpitch.utils.PitchParams; import com.gitpitch.utils.YAMLOptions; @@ -71,7 +72,8 @@ public class SlideshowModel { this._yOpts = yOpts; this._fetchMarkdown = - com.gitpitch.controllers.routes.PitchController.markdown(pp.user, + com.gitpitch.controllers.routes.PitchController.markdown(pp.grs, + pp.user, pp.repo, pp.branch).url(); @@ -83,17 +85,16 @@ public class SlideshowModel { .append(this._pp.branch) .toString(); - this._cacheKey = new StringBuffer(MODEL_ID) - .append(this._pretty) - .toString(); + this._cacheKey = genKey(pp); } public static SlideshowModel build(PitchParams pp, boolean yamlFound, + GRSService grsService, DiskService diskService) { YAMLOptions yOpts = - yamlFound ? YAMLOptions.build(pp, diskService) : null; + yamlFound ? YAMLOptions.build(pp, grsService, diskService) : null; return new SlideshowModel(pp, yOpts); } @@ -103,6 +104,8 @@ public class SlideshowModel { public static String genKey(PitchParams pp) { return new StringBuffer(MODEL_ID).append(SLASH) + .append(pp.grs) + .append(SLASH) .append(pp.user) .append(SLASH) .append(pp.repo) diff --git a/app/com/gitpitch/services/DiskService.java b/app/com/gitpitch/services/DiskService.java index 8ea70c4..b26d0f7 100644 --- a/app/com/gitpitch/services/DiskService.java +++ b/app/com/gitpitch/services/DiskService.java @@ -23,7 +23,9 @@ */ package com.gitpitch.services; -import com.gitpitch.utils.GitHub; +import com.gitpitch.git.GRS; +import com.gitpitch.git.GRSService; +import com.gitpitch.git.GRSManager; import com.gitpitch.utils.PitchParams; import org.apache.commons.io.FileUtils; import play.Configuration; @@ -36,6 +38,7 @@ import java.io.IOException; import java.net.HttpURLConnection; import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; +import java.util.Map; /* * File system storage service. @@ -45,30 +48,31 @@ public class DiskService { private final Logger.ALogger log = Logger.of(this.getClass()); - private final String _storage; - private final String _decktape; - private final String _rawAuthToken; - private Configuration configuration; - private ShellService shellService; - private WSClient ws; + private final String storage; + private final String decktape; + private final String rawAuthToken; + private final ShellService shellService; + private final Configuration configuration; + private final WSClient ws; @Inject - public DiskService(Configuration configuration, - ShellService shellService, + public DiskService(ShellService shellService, + Configuration configuration, WSClient ws) { - this.configuration = configuration; + this.shellService = shellService; + this.configuration = configuration; this.ws = ws; - this._storage = configuration.getString("gitpitch.storage.home"); - this._decktape = configuration.getString("gitpitch.decktape.home"); - this._rawAuthToken = configuration.getString("gitpitch.raw.auth.token"); + this.storage = configuration.getString("gitpitch.storage.home"); + this.decktape = configuration.getString("gitpitch.decktape.home"); + this.rawAuthToken = configuration.getString("gitpitch.raw.auth.token"); } /* * Return PitchParams branch working directory. */ public Path bwd(PitchParams pp) { - return Paths.get(storage(), pp.user, pp.repo, pp.branch); + return Paths.get(storage(), pp.grs, pp.user, pp.repo, pp.branch); } /* @@ -76,7 +80,7 @@ public class DiskService { */ public Path asPath(PitchParams pp, String filename) { - return Paths.get(storage(), pp.user, pp.repo, pp.branch, filename); + return Paths.get(storage(), pp.grs, pp.user, pp.repo, pp.branch, filename); } /* @@ -112,7 +116,8 @@ public class DiskService { public int download(PitchParams pp, Path wd, String source, - String dest) { + String dest, + Map headers) { int downloaded = 999; @@ -126,20 +131,13 @@ public class DiskService { final long start = System.currentTimeMillis(); - WSRequest downloadReq = ws.url(source); + final WSRequest downloadReq = ws.url(source); - if (GitHub.call(source)) { + downloadReq.setHeader(API_CACHE_CONTROL, API_NO_CACHE); - downloadReq = - downloadReq.setHeader(API_CACHE_CONTROL, API_NO_CACHE); - - if (rawAuthToken() != null) { - String tokenValue = API_HEADER_TOKEN + rawAuthToken(); - downloadReq = - downloadReq.setHeader(API_HEADER_AUTH, tokenValue); - } - - } + headers.forEach((k,v) -> { + downloadReq.setHeader(k, v); + }); WSResponse downloadResp = downloadReq.get().toCompletableFuture().get(); @@ -273,18 +271,18 @@ public class DiskService { * Return disk storage home directory. */ public String storage() { - return _storage; + return storage; } /* * Return DeckTape PDF Exporter home directory. */ public String decktape() { - return _decktape; + return decktape; } public String rawAuthToken() { - return _rawAuthToken; + return rawAuthToken; } private static final Integer STATUS_OK = 0; diff --git a/app/com/gitpitch/services/GitService.java b/app/com/gitpitch/services/GitService.java index 13f8e38..db1d6a9 100644 --- a/app/com/gitpitch/services/GitService.java +++ b/app/com/gitpitch/services/GitService.java @@ -25,6 +25,7 @@ package com.gitpitch.services; import com.fasterxml.jackson.databind.JsonNode; import com.gitpitch.factory.MarkdownModelFactory; +import com.gitpitch.git.*; import com.gitpitch.models.GitRepoModel; import com.gitpitch.models.MarkdownModel; import com.gitpitch.models.SlideshowModel; @@ -58,6 +59,7 @@ public class GitService { private final ConcurrentHashMap markdownLatchMap = new ConcurrentHashMap(); + private final GRSManager grsManager; private final DiskService diskService; private final PrintService printService; private final ShellService shellService; @@ -69,7 +71,8 @@ public class GitService { private final Configuration configuration; @Inject - public GitService(DiskService diskService, + public GitService(GRSManager grsManager, + DiskService diskService, PrintService printService, ShellService shellService, CacheTimeout cacheTimeout, @@ -79,6 +82,7 @@ public class GitService { CacheApi pitchCache, Configuration configuration) { + this.grsManager = grsManager; this.diskService = diskService; this.printService = printService; this.shellService = shellService; @@ -114,15 +118,18 @@ public class GitService { } else { - String apiCall = GitHub.repoAPI(pp); + GRS grs = grsManager.get(pp); + final GRSService grsService = grsManager.getService(grs); + String apiCall = grsService.repo(pp); + + log.debug("fetchRepo: apiCall={}", apiCall); final long start = System.currentTimeMillis(); WSRequest apiRequest = wsClient.url(apiCall); - if (githubApiToken() != null) { - String tokenValue = API_HEADER_TOKEN + githubApiToken(); - apiRequest = apiRequest.setHeader(API_HEADER_AUTH, tokenValue); - } + grs.getHeaders().forEach((k,v) -> { + apiRequest.setHeader(k, v); + }); CompletableFuture apiFuture = apiRequest.get().toCompletableFuture(); @@ -133,7 +140,8 @@ public class GitService { log.debug("fetchRepo: pp={}, fetch meta time-taken={}", pp, (System.currentTimeMillis() - start)); - log.info("GitHub: API Rate Limit Status [ {}, {} ]", + log.info("{}: API Rate Limit Status [ {}, {} ]", + grs.getName(), apiResp.getHeader(API_RATE_LIMIT), apiResp.getHeader(API_RATE_LIMIT_REMAINING)); @@ -144,19 +152,19 @@ public class GitService { try { JsonNode json = apiResp.asJson(); - GitRepoModel grm = new GitRepoModel(pp, json); + GitRepoModel grm = grsService.model(pp, json); - /* - * Update pitchCache with new GitRepoModel - * generated using GitHub API response data. - */ + /* + * Update pitchCache with new GitRepoModel + * generated using GitHub API response data. + */ pitchCache.set(grm.key(), grm, cacheTimeout.grm(pp)); } catch (Exception ex) { - /* - * Prevent any runtime errors, such as JSON parsing, - * from propogating to the front end. - */ + /* + * Prevent any runtime errors, such as JSON parsing, + * from propogating to the front end. + */ log.warn("fetchRepo: pp={}, unexpected ex={}", pp, ex); } @@ -173,7 +181,7 @@ public class GitService { Integer.parseInt(remainingHdr); if (rateLimitRemaining <= 0) { - log.warn("WARNING! GitHub API rate limit exceeded."); + log.warn("WARNING! {} API rate limit exceeded.", grs.getName()); } } catch (Exception rlex) { @@ -184,16 +192,16 @@ public class GitService { log.warn("fetchRepo: pp={}, unexpected runtime ex={}", pp, rex); } - /* - * Current operation completed, so remove latch associated - * with operation from repoLatchMap to permit future operations - * on this /{user}/{repo}. - */ + /* + * Current operation completed, so remove latch associated + * with operation from repoLatchMap to permit future operations + * on this /{user}/{repo}. + */ releaseCountDownLatch(repoLatchMap, grmKey); - /* - * Operation completed, valid result cached, no return required. - */ + /* + * Operation completed, valid result cached, no return required. + */ return null; }, backEndThreads.POOL) @@ -238,30 +246,29 @@ public class GitService { CompletableFuture syncFuture = CompletableFuture.supplyAsync(() -> { - Path branchPath = diskService.ensure(pp); - String yamlLink = GitHub.rawAPI(pp, PITCHME_YAML, true); - int downYAML = - diskService.download(pp, branchPath, yamlLink, PITCHME_YAML); + GRS grs = grsManager.get(pp); + GRSService grsService = grsManager.getService(grs); + int downYAML = grsService.download(pp, PITCHME_YAML); boolean downOk = downYAML == STATUS_OK; log.debug("fetchYAML: pp={}, downloaded YAML={}", pp, downYAML); - /* - * Update pitchCache with new SlideshowModel. - */ + /* + * Update pitchCache with new SlideshowModel. + */ SlideshowModel ssm = - SlideshowModel.build(pp, downOk, diskService); + SlideshowModel.build(pp, downOk, grsService, diskService); pitchCache.set(ssm.key(), ssm, cacheTimeout.ssm(pp)); - /* - * Current operation completed, so remove latch associated - * with operation from yamlLatchMap to permit future - * operations on this /{user}/{repo}?b={branch}. - */ + /* + * Current operation completed, so remove latch associated + * with operation from yamlLatchMap to permit future + * operations on this /{user}/{repo}?b={branch}. + */ releaseCountDownLatch(yamlLatchMap, ssmKey); - /* - * Operation completed, valid result cached, no return required. - */ + /* + * Operation completed, valid result cached, no return required. + */ return null; }, backEndThreads.POOL) @@ -307,18 +314,18 @@ public class GitService { CompletableFuture syncFuture = CompletableFuture.supplyAsync(() -> { - Path branchPath = diskService.ensure(pp); - String mdLink = GitHub.rawAPI(pp, PITCHME_MD, true); - int downStatus = - diskService.download(pp, branchPath, mdLink, PITCHME_MD); + GRS grs = grsManager.get(pp); + GRSService grsService = grsManager.getService(grs); + + int downStatus = grsService.download(pp, PITCHME_MD); if (downStatus == STATUS_OK) { String ssmKey = SlideshowModel.genKey(pp); Optional ssm = Optional.ofNullable(pitchCache.get(ssmKey)); - MarkdownRenderer mrndr = - MarkdownRenderer.build(pp, ssm, diskService); + MarkdownRenderer mrndr = MarkdownRenderer.build(pp, + ssm, grsService, diskService); // MarkdownModel mdm = MarkdownModel.consume(mrndr); MarkdownModel mdm = @@ -330,16 +337,16 @@ public class GitService { pp, downStatus); } - /* - * Current operation completed, so remove latch associated - * with operation from markdownLatchMap to permit future - * operations on this /{user}/{repo}?b={branch}. - */ + /* + * Current operation completed, so remove latch associated + * with operation from markdownLatchMap to permit future + * operations on this /{user}/{repo}?b={branch}. + */ releaseCountDownLatch(markdownLatchMap, mdmKey); - /* - * Operation completed, valid result cached, no return required. - */ + /* + * Operation completed, valid result cached, no return required. + */ return null; }, backEndThreads.POOL) @@ -378,10 +385,6 @@ public class GitService { } - public String githubApiToken() { - return configuration.getString("gitpitch.github.api.token"); - } - private static final String GHUB_REPO_META = "https://api.github.com/repos/"; private static final String GIT_MASTER = "master"; diff --git a/app/com/gitpitch/services/OfflineService.java b/app/com/gitpitch/services/OfflineService.java index 3dea674..240dabd 100644 --- a/app/com/gitpitch/services/OfflineService.java +++ b/app/com/gitpitch/services/OfflineService.java @@ -24,6 +24,7 @@ package com.gitpitch.services; import com.gitpitch.factory.MarkdownModelFactory; +import com.gitpitch.git.*; import com.gitpitch.models.MarkdownModel; import com.gitpitch.models.SlideshowModel; import com.gitpitch.executors.BackEndThreads; @@ -60,21 +61,24 @@ public class OfflineService { private final Logger.ALogger log = Logger.of(this.getClass()); - private DiskService diskService; - private ShellService shellService; - private MarkdownModelFactory markdownModelFactory; - private BackEndThreads backEndThreads; - private Configuration configuration; - private Environment env; + private final GRSManager grsManager; + private final DiskService diskService; + private final ShellService shellService; + private final MarkdownModelFactory markdownModelFactory; + private final BackEndThreads backEndThreads; + private final Configuration configuration; + private final Environment env; @Inject - public OfflineService(DiskService diskService, + public OfflineService(GRSManager grsManager, + DiskService diskService, ShellService shellService, MarkdownModelFactory markdownModelFactory, BackEndThreads backEndThreads, Configuration configuration, Environment env) { + this.grsManager = grsManager; this.diskService = diskService; this.shellService = shellService; this.markdownModelFactory = markdownModelFactory; @@ -230,14 +234,17 @@ public class OfflineService { private int fetchOnlineMarkdown(PitchParams pp) { String murl = - com.gitpitch.controllers.routes.PitchController.markdown(pp.user, + com.gitpitch.controllers.routes.PitchController.markdown(pp.grs, + pp.user, pp.repo, pp.branch) .absoluteURL(isEncrypted(), hostname()); Path zipMdPath = diskService.ensure(diskService.asPath(pp, ZIP_MD_DIR)); - return diskService.download(pp, zipMdPath, murl, PITCHME_ONLINE_MD); + return diskService.download(pp, + zipMdPath, murl, PITCHME_ONLINE_MD, + grsManager.get(pp).getHeaders()); } /* @@ -249,12 +256,14 @@ public class OfflineService { com.gitpitch.controllers.routes.PitchController.landing(pp.user, pp.repo, pp.branch, + pp.grs, pp.theme, pp.notes, ENABLED) .absoluteURL(isEncrypted(), hostname()); - return diskService.download(pp, zipRoot, lurl, INDEX_HTML); + return diskService.download(pp, zipRoot, + lurl, INDEX_HTML, grsManager.get(pp).getHeaders()); } /* @@ -263,7 +272,8 @@ public class OfflineService { private int fetchSlideshowHTML(PitchParams pp, Path zipRoot) { String surl = - com.gitpitch.controllers.routes.PitchController.slideshow(pp.user, + com.gitpitch.controllers.routes.PitchController.slideshow(pp.grs, + pp.user, pp.repo, pp.branch, pp.theme, @@ -272,7 +282,8 @@ public class OfflineService { ENABLED) .absoluteURL(isEncrypted(), hostname()); - return diskService.download(pp, zipRoot, surl, SLIDESHOW_HTML); + return diskService.download(pp, zipRoot, + surl, SLIDESHOW_HTML, grsManager.get(pp).getHeaders()); } /* @@ -322,8 +333,11 @@ public class OfflineService { if (mdOnlineFile.exists()) { + GRSService grsService = + grsManager.getService(grsManager.get(pp)); + MarkdownRenderer mrndr = - MarkdownRenderer.build(pp, ssmo, diskService); + MarkdownRenderer.build(pp, ssmo, grsService, diskService); MarkdownModel markdownModel = (MarkdownModel) markdownModelFactory.create(mrndr); @@ -384,9 +398,9 @@ public class OfflineService { for (String assetUrl : assetUrls) { if (assetUrl != null && !fetched.contains(assetUrl)) { - diskService.download(pp, zipMdAssetsPath, - assetUrl, - FilenameUtils.getName(assetUrl)); + diskService.download(pp, zipMdAssetsPath, assetUrl, + FilenameUtils.getName(assetUrl), + grsManager.get(pp).getHeaders()); fetched.add(assetUrl); } } @@ -405,7 +419,9 @@ public class OfflineService { */ private void fetchYAMLDependencies(PitchParams pp) { - YAMLOptions yOpts = YAMLOptions.build(pp, diskService); + GRSService grsService = + grsManager.getService(grsManager.get(pp)); + YAMLOptions yOpts = YAMLOptions.build(pp, grsService, diskService); log.debug("fetchYAMLDependencies: yOpts={}", yOpts); try { @@ -417,7 +433,8 @@ public class OfflineService { Path zipAssetsPath = diskService.ensure(diskService.asPath(pp, ZIP_ASSETS_DIR)); - diskService.download(pp, zipAssetsPath, logoUrl, logoName); + diskService.download(pp, zipAssetsPath, + logoUrl, logoName, grsManager.get(pp).getHeaders()); log.debug("fetchYAMLDependencies: downloaded logo={}", logoUrl); } diff --git a/app/com/gitpitch/services/PitchService.java b/app/com/gitpitch/services/PitchService.java index 4f258b7..75c2736 100644 --- a/app/com/gitpitch/services/PitchService.java +++ b/app/com/gitpitch/services/PitchService.java @@ -77,6 +77,7 @@ public class PitchService { public Optional cachedRepo(PitchParams pp) { String grmKey = GitRepoModel.genKey(pp); + log.debug("cachedRepo: grmKey={}", grmKey); return Optional.ofNullable(pitchCache.get(grmKey)); } diff --git a/app/com/gitpitch/services/PrintService.java b/app/com/gitpitch/services/PrintService.java index 035d7ba..775ea59 100644 --- a/app/com/gitpitch/services/PrintService.java +++ b/app/com/gitpitch/services/PrintService.java @@ -153,7 +153,8 @@ public class PrintService { String filePath = diskService.asFile(pp, PITCHME_PDF).toString(); String slideshowUrl = - com.gitpitch.controllers.routes.PitchController.slideshow(pp.user, + com.gitpitch.controllers.routes.PitchController.slideshow(pp.grs, + pp.user, pp.repo, pp.branch, pp.theme, diff --git a/app/com/gitpitch/utils/GitHub.java b/app/com/gitpitch/utils/GitHub.java deleted file mode 100644 index 52a4204..0000000 --- a/app/com/gitpitch/utils/GitHub.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2016 David Russell - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.gitpitch.utils; - -import com.gitpitch.utils.PitchParams; -import play.Logger; -import play.Logger.ALogger; - -import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; - -/* - * GitHub API endpoint utility. - */ -public final class GitHub { - - private final static Logger.ALogger log = - Logger.of("com.gitpitch.utils.GitHub"); - - private static AtomicInteger atomicInt = new AtomicInteger(); - - public static String rawAPI(PitchParams pp) { - - return new StringBuffer(GHUB_RAW_BASE) - .append(pp.user) - .append(SLASH) - .append(pp.repo) - .append(SLASH) - .append(pp.branch) - .append(SLASH) - .toString(); - } - - public static String rawAPI(PitchParams pp, - String filename) { - - return rawAPI(pp, filename, false); - } - - public static String rawAPI(PitchParams pp, - String filename, - boolean bypassCache) { - - if (bypassCache) { - /* - * Adding ?gp={rand} to the URL ensures that the - * GitHub cache does not return cached data. - */ - return rawAPI(pp) + filename + "?gp=" + atomicInt.getAndIncrement(); - } else { - return rawAPI(pp) + filename; - } - } - - public static String repoAPI(PitchParams pp) { - - return new StringBuffer(GHUB_REPO_META) - .append(pp.user) - .append(SLASH) - .append(pp.repo) - .toString(); - } - - public static boolean call(String url) { - - if (url != null) { - return url.startsWith(GHUB_API_BASE) || - url.startsWith(GHUB_RAW_BASE); - } else { - return false; - } - } - - private static final String SLASH = "/"; - private static final String GHUB_RAW_BASE = "https://raw.githubusercontent.com/"; - private static final String GHUB_API_BASE = "https://api.github.com"; - private static final String GHUB_REPO_META = GHUB_API_BASE + "/repos/"; -} diff --git a/app/com/gitpitch/utils/GitRepoRenderer.java b/app/com/gitpitch/utils/GitRepoRenderer.java index 0a8e079..0bea8df 100644 --- a/app/com/gitpitch/utils/GitRepoRenderer.java +++ b/app/com/gitpitch/utils/GitRepoRenderer.java @@ -23,14 +23,17 @@ */ package com.gitpitch.utils; +import com.gitpitch.git.GRS; +import com.gitpitch.git.vendors.*; import com.gitpitch.models.GitRepoModel; import com.gitpitch.utils.PitchParams; import play.Configuration; -import play.Logger; -import play.Logger.ALogger; - import java.util.Arrays; import java.util.List; +import java.util.Optional; + +import play.Logger; +import play.Logger.ALogger; /* * Rendering model for views.Landing.scala.html. @@ -42,6 +45,7 @@ public class GitRepoRenderer { private final PitchParams _pp; private final GitRepoModel _grm; private Configuration _cfg; + private List _grsServices; /* * Relative URLs for view components. */ @@ -57,17 +61,19 @@ public class GitRepoRenderer { private String _starHub; private String _forkHub; - private GitRepoRenderer(PitchParams pp) { - this(pp, null, null); + private GitRepoRenderer(PitchParams pp, List grsServices) { + this(pp, null, null, grsServices); } private GitRepoRenderer(PitchParams pp, GitRepoModel grm, - Configuration cfg) { + Configuration cfg, + List grsServices) { this._pp = pp; this._grm = grm; this._cfg = cfg; + this._grsServices = grsServices; if (grm != null) { @@ -77,25 +83,49 @@ public class GitRepoRenderer { */ this._landingURL = com.gitpitch.controllers.routes.PitchController - .landing(_grm.owner(), + .landing(_pp.grs, + _grm.owner(), _grm.name(), _pp.branch, _pp.theme, _pp.notes, null).toString(); this._slideshowURL = com.gitpitch.controllers.routes.PitchController - .slideshow(_grm.owner(), + .slideshow(_pp.grs, + _grm.owner(), _grm.name(), _pp.branch, _pp.theme, _pp.notes, null, null).toString(); this._markdownURL = com.gitpitch.controllers.routes.PitchController - .markdown(_grm.owner(), + .markdown(_pp.grs, + _grm.owner(), _grm.name(), _pp.branch).toString(); - this._orgHub = new StringBuffer(GIT_COM).append(_grm.owner()) + Optional grso = + this._grsServices.stream() + .filter(grs -> grs.getType().equals(_pp.grs)) + .findFirst(); + + Optional grsoDefault = + this._grsServices.stream() + .filter(grs -> grs.isDefault()) + .findFirst(); + + String grsSite = null; + + if(grso.isPresent()) { + grsSite = grso.get().getSite(); + } else { + if(grsoDefault.isPresent()) + grsSite = grsoDefault.get().getSite(); + else + grsSite = GRS_GITHUB_COM; + } + + this._orgHub = new StringBuffer(grsSite).append(_grm.owner()) .toString(); this._repoHub = @@ -103,14 +133,45 @@ public class GitRepoRenderer { .append(this._grm.name()) .toString(); + switch(_pp.grs) { - this._starHub = new StringBuffer(this._repoHub).append(SLASH) - .append(STARGAZERS) - .toString(); + case GitHub.TYPE: + this._starHub = + new StringBuffer(this._repoHub).append(SLASH) + .append(GRS_GITHUB_STARS) + .toString(); + this._forkHub = + new StringBuffer(this._repoHub).append(SLASH) + .append(GRS_GITHUB_FORKS) + .toString(); + break; + case GitLab.TYPE: + this._starHub = + new StringBuffer(this._repoHub).append(SLASH) + .append(GRS_GITLAB_STARS) + .toString(); + this._forkHub = + new StringBuffer(this._repoHub).append(SLASH) + .append(GRS_GITLAB_FORKS) + .append(_pp.branch) + .toString(); + break; + case BitBucket.TYPE: + this._starHub = + new StringBuffer(this._repoHub).append(SLASH) + .append(GRS_BITBUCKET_STARS) + .toString(); + this._forkHub = + new StringBuffer(this._repoHub).append(SLASH) + .append(GRS_BITBUCKET_FORKS) + .toString(); + break; - this._forkHub = new StringBuffer(this._repoHub).append(SLASH) - .append(FORKS) - .toString(); + default: + this._starHub = "#"; + this._forkHub = "#"; + break; + } } else { /* @@ -130,9 +191,10 @@ public class GitRepoRenderer { public static GitRepoRenderer build(PitchParams pp, GitRepoModel grm, - Configuration cfg) { + Configuration cfg, + List grsServices) { - return new GitRepoRenderer(pp, grm, cfg); + return new GitRepoRenderer(pp, grm, cfg, grsServices); } /* @@ -202,7 +264,8 @@ public class GitRepoRenderer { * Return relative URL to landing view. */ public String landingURL(String theme) { - return com.gitpitch.controllers.routes.PitchController.landing(_grm.owner(), + return com.gitpitch.controllers.routes.PitchController.landing(_pp.grs, + _grm.owner(), _grm.name(), _pp.branch, theme, @@ -269,7 +332,15 @@ public class GitRepoRenderer { * Return GitHub repository language. */ public String repoLang() { - return (_grm != null) ? _grm.lang() : null; + + String repoLang = null; + + if(_grm != null) { + if(_grm.lang() != null && _grm.lang().length() > 0) { + repoLang = _grm.lang(); + } + } + return repoLang; } /* @@ -300,19 +371,28 @@ public class GitRepoRenderer { } public String pageLink(boolean absolute) { + return pageLink(absolute, null); + } + + public String pageLink(boolean absolute, String grs) { + + grs = (grs != null) ? grs : _pp.grs; if (absolute) return com.gitpitch.controllers.routes.PitchController.landing(_pp.user, _pp.repo, _pp.branch, + grs, _pp.theme, - _pp.notes, null) + _pp.notes, + null) .absoluteURL(isEncrypted(), hostname()); else return com.gitpitch.controllers.routes.PitchController.landing(_pp.user, _pp.repo, _pp.branch, + grs, _pp.theme, _pp.notes, null).toString(); } @@ -322,13 +402,16 @@ public class GitRepoRenderer { return com.gitpitch.controllers.routes.PitchController.landing(_pp.user, _pp.repo, _pp.branch, + _pp.grs, theme, - _pp.notes, null).toString(); + _pp.notes, + null).toString(); } public String printLink() { - return com.gitpitch.controllers.routes.PitchController.print(_pp.user, + return com.gitpitch.controllers.routes.PitchController.print(_pp.grs, + _pp.user, _pp.repo, _pp.branch, _pp.theme, @@ -337,7 +420,8 @@ public class GitRepoRenderer { public String offlineLink() { - return com.gitpitch.controllers.routes.PitchController.offline(_pp.user, + return com.gitpitch.controllers.routes.PitchController.offline(_pp.grs, + _pp.user, _pp.repo, _pp.branch, _pp.theme, @@ -360,6 +444,20 @@ public class GitRepoRenderer { .toString(); } + public String getGRS(PitchParams pp) { + String grsName = null; + for(GRS grs : _grsServices) { + if(grs.getType().equals(pp.grs)) { + grsName = grs.getName(); + } + } + return grsName; + } + + public List listGRS() { + return _grsServices; + } + /* * Return string representation of ViewModel. */ @@ -382,9 +480,6 @@ public class GitRepoRenderer { private static final String SLASH = "/"; private static final String QMARK_BRANCH = "?b="; private static final String QMARK_THEME = "&t="; - private static final String GIT_COM = "https://github.com/"; - private static final String STARGAZERS = "stargazers"; - private static final String FORKS = "network"; private static final String HTTP_HASH = "#"; private static final String EMBED_OPEN = " } else {
- - GitHub repository not found - + Git repository not found on @rndr.getGRS(rndr.params()) +
} @@ -77,6 +74,18 @@
+ + @if(!offline) { @LandingSocialDependencies(deps, offline) } diff --git a/app/com/gitpitch/views/Slideshow.scala.html b/app/com/gitpitch/views/Slideshow.scala.html index e89e35d..0071eb1 100755 --- a/app/com/gitpitch/views/Slideshow.scala.html +++ b/app/com/gitpitch/views/Slideshow.scala.html @@ -6,11 +6,10 @@ - - - - GitPitch - Slideshow Presentations For Your GitHub Projects + + GitHub, GitLab, Bitbucket Slideshow Presentations For Developers - GitPitch + + @@ -19,6 +18,7 @@ } + @SlideshowStyle() @@ -39,15 +39,14 @@
}
- @if(ssm.params().darkTheme()) { + @if(ssm.params().grs.equals("github")) { - @ssm.params().asLogo() } else { - - @ssm.params().asLogo() + } + @ssm.params().asLogo()
diff --git a/app/com/gitpitch/views/frags/LandingFooter.scala.html b/app/com/gitpitch/views/frags/LandingFooter.scala.html index 6ea5948..71220ff 100644 --- a/app/com/gitpitch/views/frags/LandingFooter.scala.html +++ b/app/com/gitpitch/views/frags/LandingFooter.scala.html @@ -4,10 +4,23 @@