Skip to content
This repository has been archived by the owner on Jan 31, 2023. It is now read-only.

WFLOW-577 - integrate releases with GitHub #9

Merged
merged 7 commits into from
Nov 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/main/java/dev/vernite/vernite/integration/git/Branch.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package dev.vernite.vernite.integration.git;

public class Branch {
private String name;

public Branch(String name) {
this.name = name;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

import dev.vernite.vernite.integration.git.github.GitHubService;
import dev.vernite.vernite.project.Project;
import dev.vernite.vernite.release.Release;
import dev.vernite.vernite.task.Task;

import org.springframework.beans.factory.annotation.Autowired;
Expand Down Expand Up @@ -171,4 +172,12 @@ public Mono<PullRequest> connectPullRequest(Task task, PullRequest pullRequest)
public void deletePullRequest(Task task) {
gitHubService.deletePullRequest(task);
}

public Mono<Long> publishRelease(Release release, String branch) {
return gitHubService.publishRelease(release, branch);
}

public Flux<Branch> getBranches(Project project) {
return Flux.concat(List.of(gitHubService.getBranches(project)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,15 @@
import java.util.List;
import java.util.Optional;

import dev.vernite.vernite.integration.git.Branch;
import dev.vernite.vernite.integration.git.Issue;
import dev.vernite.vernite.integration.git.PullRequest;
import dev.vernite.vernite.integration.git.github.data.GitHubBranchRead;
import dev.vernite.vernite.integration.git.github.data.GitHubInstallationApi;
import dev.vernite.vernite.integration.git.github.data.GitHubIssue;
import dev.vernite.vernite.integration.git.github.data.GitHubMergeInfo;
import dev.vernite.vernite.integration.git.github.data.GitHubPullRequest;
import dev.vernite.vernite.integration.git.github.data.GitHubRelease;
import dev.vernite.vernite.integration.git.github.data.GitHubRepository;
import dev.vernite.vernite.integration.git.github.data.GitHubUser;
import dev.vernite.vernite.integration.git.github.data.GitHubInstallationRepositories;
Expand All @@ -58,6 +61,7 @@
import dev.vernite.vernite.integration.git.github.entity.task.GitHubTaskPull;
import dev.vernite.vernite.integration.git.github.entity.task.GitHubTaskPullRepository;
import dev.vernite.vernite.project.Project;
import dev.vernite.vernite.release.Release;
import dev.vernite.vernite.task.Task;
import dev.vernite.vernite.user.User;
import dev.vernite.vernite.utils.ExternalApiException;
Expand Down Expand Up @@ -659,6 +663,32 @@ private Flux<GitHubUser> apiGetRepositoryCollaborators(GitHubInstallation instal
.onErrorMap(error -> new ExternalApiException(GITHUB, error.getMessage()));
}

private Mono<Long> apiCreateRelease(GitHubInstallation installation,
GitHubIntegration integration, GitHubRelease release) {
return client.post()
.uri("/repos/{owner}/{repo}/releases", integration.getRepositoryOwner(),
integration.getRepositoryName())
.header(AUTHORIZATION, BEARER + installation.getToken())
.header(ACCEPT, APPLICATION_JSON_GITHUB)
.bodyValue(release)
.retrieve()
.bodyToMono(GitHubRelease.class)
.onErrorMap(error -> new ExternalApiException(GITHUB, error.getMessage()))
.map(GitHubRelease::getId);
}

private Flux<GitHubBranchRead> apiGetBranches(GitHubInstallation installation,
GitHubIntegration integration) {
return client.get()
.uri("/repos/{owner}/{repo}/branches", integration.getRepositoryOwner(),
integration.getRepositoryName())
.header(AUTHORIZATION, BEARER + installation.getToken())
.header(ACCEPT, APPLICATION_JSON_GITHUB)
.retrieve()
.bodyToFlux(GitHubBranchRead.class)
.onErrorMap(error -> new ExternalApiException(GITHUB, error.getMessage()));
}

/**
* Creates Json Web Token from file with private key. Token created with this
* method lasts 10 minutes.
Expand All @@ -681,4 +711,27 @@ private static String createJWT() {
throw new ResponseStatusException(HttpStatus.SERVICE_UNAVAILABLE, "Unable to create JWT");
}
}

public Mono<Long> publishRelease(Release release, String branch) {
GitHubIntegration integration = release.getProject().getGitHubIntegrationEntity();
if (integration == null) {
return Mono.empty();
}
GitHubRelease gitHubRelease = new GitHubRelease(release);
if (branch != null) {
gitHubRelease.setTargetCommitish(branch);
}
return refreshToken(integration.getInstallation())
.flatMap(installation -> apiCreateRelease(installation, integration, gitHubRelease));
}

public Flux<Branch> getBranches(Project project) {
GitHubIntegration integration = project.getGitHubIntegrationEntity();
if (integration == null) {
return Flux.empty();
}
return refreshToken(integration.getInstallation())
.flatMapMany(installation -> apiGetBranches(installation, integration))
.map(branch -> new Branch(branch.getName()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* BSD 2-Clause License
*
* Copyright (c) 2022, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak]
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package dev.vernite.vernite.integration.git.github.data;

/**
* Object to represent a GitHub Rest api branch.
*/
public class GitHubBranchRead {
private String name;

public GitHubBranchRead() {
}

public GitHubBranchRead(String name) {
this.name = name;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package dev.vernite.vernite.integration.git.github.data;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;

import dev.vernite.vernite.release.Release;

@JsonInclude(JsonInclude.Include.NON_NULL)
public class GitHubRelease {

@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private Long id;
@JsonProperty("tag_name")
private String tagName;
private String body;
@JsonProperty("generate_release_notes")
private boolean generateReleaseNotes;
@JsonProperty("target_commitish")
private String targetCommitish;

public GitHubRelease() {
}

public GitHubRelease(Release release) {
this.tagName = release.getName().replace(" ", "-");
this.body = release.getDescription();
this.generateReleaseNotes = true;
}

public String getBody() {
return body;
}

public void setBody(String body) {
this.body = body;
}

public String getTagName() {
return tagName;
}

public void setGenerateReleaseNotes(boolean generateReleaseNotes) {
this.generateReleaseNotes = generateReleaseNotes;
}

public boolean getGenerateReleaseNotes() {
return generateReleaseNotes;
}

public void setTagName(String tagName) {
this.tagName = tagName;
}

public String getTargetCommitish() {
return targetCommitish;
}

public void setTargetCommitish(String targetCommitish) {
this.targetCommitish = targetCommitish;
}

public long getId() {
return id;
}

public void setId(long id) {
this.id = id;
}
}
5 changes: 5 additions & 0 deletions src/main/java/dev/vernite/vernite/project/Project.java
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,11 @@ public String getGitHubIntegration() {
: null;
}

@JsonIgnore
public GitHubIntegration getGitHubIntegrationEntity() {
return gitHubIntegration;
}

public void setGitHubIntegration(GitHubIntegration gitHubIntegration) {
this.gitHubIntegration = gitHubIntegration;
}
Expand Down
14 changes: 14 additions & 0 deletions src/main/java/dev/vernite/vernite/project/ProjectController.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
import dev.vernite.vernite.event.EventService;
import dev.vernite.vernite.integration.calendar.CalendarIntegration;
import dev.vernite.vernite.integration.calendar.CalendarIntegrationRepository;
import dev.vernite.vernite.integration.git.Branch;
import dev.vernite.vernite.integration.git.GitTaskService;
import dev.vernite.vernite.integration.git.Issue;
import dev.vernite.vernite.integration.git.PullRequest;
Expand Down Expand Up @@ -303,6 +304,19 @@ public Flux<PullRequest> getPullRequests(@NotNull @Parameter(hidden = true) User
return service.getPullRequests(project);
}

@Operation(summary = "Retrieve git branches for project", description = "Retrieves all branches from all integrated git services for project.")
@ApiResponse(description = "List of branches.", responseCode = "200", content = @Content(schema = @Schema(implementation = Branch.class)))
@ApiResponse(description = "No user logged in.", responseCode = "401", content = @Content(schema = @Schema(implementation = ErrorType.class)))
@ApiResponse(description = "Project not found.", responseCode = "404", content = @Content(schema = @Schema(implementation = ErrorType.class)))
@GetMapping("/{id}/integration/git/branch")
public Flux<Branch> getBranches(@NotNull @Parameter(hidden = true) User user, @PathVariable long id) {
Project project = projectRepository.findByIdOrThrow(id);
if (project.member(user) == -1) {
throw new ObjectNotFoundException();
}
return service.getBranches(project);
}

@Operation(summary = "Retrieve events for project", description = "Retrieves events from specified timestamp for project.")
@ApiResponse(description = "List of events.", responseCode = "200")
@ApiResponse(description = "No user logged in.", responseCode = "401", content = @Content(schema = @Schema(implementation = ErrorType.class)))
Expand Down
28 changes: 13 additions & 15 deletions src/main/java/dev/vernite/vernite/release/Release.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@

import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
import org.springframework.http.HttpStatus;
import org.springframework.web.server.ResponseStatusException;

import com.fasterxml.jackson.annotation.JsonIgnore;

import dev.vernite.vernite.project.Project;
import dev.vernite.vernite.task.Task;
Expand Down Expand Up @@ -72,6 +72,9 @@ public class Release extends SoftDeleteEntity {
@OneToMany(mappedBy = "release")
private List<Task> tasks;

@JsonIgnore
private long gitReleaseId = 0;

public Release() {
}

Expand All @@ -90,19 +93,6 @@ public void update(@NotNull ReleaseRequest request) {
request.getName().ifPresent(this::setName);
request.getDescription().ifPresent(this::setDescription);
request.getDeadline().ifPresent(this::setDeadline);
request.getReleased().ifPresent(aReleased -> {
if (Boolean.TRUE.equals(aReleased)) {
for (Task task : getTasks()) {
if (!task.getStatus().isFinal()) {
throw new ResponseStatusException(HttpStatus.CONFLICT,
"Cannot release release with non-final tasks");
}
}
this.setReleased(true);
} else {
this.setReleased(false);
}
});
}

public long getId() {
Expand Down Expand Up @@ -160,4 +150,12 @@ public List<Task> getTasks() {
public void setTasks(List<Task> tasks) {
this.tasks = tasks;
}

public long getGitReleaseId() {
return gitReleaseId;
}

public void setGitReleaseId(long gitReleaseI) {
this.gitReleaseId = gitReleaseI;
}
}
Loading