RepositoryService.java

1
package edu.ucsb.cs156.frontiers.services;
2
3
import com.fasterxml.jackson.core.JsonProcessingException;
4
import com.fasterxml.jackson.databind.ObjectMapper;
5
import edu.ucsb.cs156.frontiers.entities.Course;
6
import edu.ucsb.cs156.frontiers.entities.RosterStudent;
7
import edu.ucsb.cs156.frontiers.enums.RepositoryPermissions;
8
import java.security.NoSuchAlgorithmException;
9
import java.security.spec.InvalidKeySpecException;
10
import java.util.HashMap;
11
import java.util.Map;
12
import lombok.extern.slf4j.Slf4j;
13
import org.springframework.boot.web.client.RestTemplateBuilder;
14
import org.springframework.http.*;
15
import org.springframework.stereotype.Service;
16
import org.springframework.web.client.HttpClientErrorException;
17
import org.springframework.web.client.RestTemplate;
18
19
@Service
20
@Slf4j
21
public class RepositoryService {
22
  private final JwtService jwtService;
23
  private final RestTemplate restTemplate;
24
  private final ObjectMapper mapper;
25
26
  public RepositoryService(
27
      JwtService jwtService, RestTemplateBuilder restTemplateBuilder, ObjectMapper mapper) {
28
    this.jwtService = jwtService;
29
    this.restTemplate = restTemplateBuilder.build();
30
    this.mapper = mapper;
31
  }
32
33
  /**
34
   * Creates a single student repository if it doesn't already exist, and provisions access to the
35
   * repository by that student
36
   *
37
   * @param course The Course in question
38
   * @param student RosterStudent of the student the repository should be created for
39
   * @param repoPrefix Name of the project or assignment. Used to title the repository, in the
40
   *     format repoPrefix-githubLogin
41
   * @param isPrivate Whether the repository is private or not
42
   */
43
  public void createStudentRepository(
44
      Course course,
45
      RosterStudent student,
46
      String repoPrefix,
47
      Boolean isPrivate,
48
      RepositoryPermissions permissions)
49
      throws NoSuchAlgorithmException, InvalidKeySpecException, JsonProcessingException {
50
    String newRepoName = repoPrefix + "-" + student.getGithubLogin();
51
    String token = jwtService.getInstallationToken(course);
52
    String existenceEndpoint =
53
        "https://api.github.com/repos/" + course.getOrgName() + "/" + newRepoName;
54
    String createEndpoint = "https://api.github.com/orgs/" + course.getOrgName() + "/repos";
55
    String provisionEndpoint =
56
        "https://api.github.com/repos/"
57
            + course.getOrgName()
58
            + "/"
59
            + newRepoName
60
            + "/collaborators/"
61
            + student.getGithubLogin();
62
    HttpHeaders existenceHeaders = new HttpHeaders();
63 1 1. createStudentRepository : removed call to org/springframework/http/HttpHeaders::add → KILLED
    existenceHeaders.add("Authorization", "Bearer " + token);
64 1 1. createStudentRepository : removed call to org/springframework/http/HttpHeaders::add → KILLED
    existenceHeaders.add("Accept", "application/vnd.github+json");
65 1 1. createStudentRepository : removed call to org/springframework/http/HttpHeaders::add → KILLED
    existenceHeaders.add("X-GitHub-Api-Version", "2022-11-28");
66
67
    HttpEntity<String> existenceEntity = new HttpEntity<>(existenceHeaders);
68
69
    try {
70
      restTemplate.exchange(existenceEndpoint, HttpMethod.GET, existenceEntity, String.class);
71
    } catch (HttpClientErrorException e) {
72 1 1. createStudentRepository : negated conditional → KILLED
      if (e.getStatusCode().equals(HttpStatus.NOT_FOUND)) {
73
        HttpHeaders createHeaders = new HttpHeaders();
74 1 1. createStudentRepository : removed call to org/springframework/http/HttpHeaders::add → KILLED
        createHeaders.add("Authorization", "Bearer " + token);
75 1 1. createStudentRepository : removed call to org/springframework/http/HttpHeaders::add → KILLED
        createHeaders.add("Accept", "application/vnd.github+json");
76 1 1. createStudentRepository : removed call to org/springframework/http/HttpHeaders::add → KILLED
        createHeaders.add("X-GitHub-Api-Version", "2022-11-28");
77
78
        Map<String, Object> body = new HashMap<>();
79
        body.put("name", newRepoName);
80
        body.put("private", isPrivate);
81
        String bodyAsJson = mapper.writeValueAsString(body);
82
83
        HttpEntity<String> createEntity = new HttpEntity<>(bodyAsJson, createHeaders);
84
85
        restTemplate.exchange(createEndpoint, HttpMethod.POST, createEntity, String.class);
86
      } else {
87
        log.warn(
88
            "Unexpected response code {} when checking for existence of repository {}",
89
            e.getStatusCode(),
90
            newRepoName);
91
        return;
92
      }
93
    }
94
    try {
95
      Map<String, Object> provisionBody = new HashMap<>();
96
      provisionBody.put("permission", permissions.getApiName());
97
      String provisionAsJson = mapper.writeValueAsString(provisionBody);
98
99
      HttpEntity<String> provisionEntity = new HttpEntity<>(provisionAsJson, existenceHeaders);
100
      restTemplate.exchange(provisionEndpoint, HttpMethod.PUT, provisionEntity, String.class);
101
    } catch (HttpClientErrorException ignored) {
102
103
    }
104
  }
105
}

Mutations

63

1.1
Location : createStudentRepository
Killed by : edu.ucsb.cs156.frontiers.services.RepositoryServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.RepositoryServiceTests]/[method:exits_if_not_not_found()]
removed call to org/springframework/http/HttpHeaders::add → KILLED

64

1.1
Location : createStudentRepository
Killed by : edu.ucsb.cs156.frontiers.services.RepositoryServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.RepositoryServiceTests]/[method:exits_if_not_not_found()]
removed call to org/springframework/http/HttpHeaders::add → KILLED

65

1.1
Location : createStudentRepository
Killed by : edu.ucsb.cs156.frontiers.services.RepositoryServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.RepositoryServiceTests]/[method:exits_if_not_not_found()]
removed call to org/springframework/http/HttpHeaders::add → KILLED

72

1.1
Location : createStudentRepository
Killed by : edu.ucsb.cs156.frontiers.services.RepositoryServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.RepositoryServiceTests]/[method:exits_if_not_not_found()]
negated conditional → KILLED

74

1.1
Location : createStudentRepository
Killed by : edu.ucsb.cs156.frontiers.services.RepositoryServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.RepositoryServiceTests]/[method:successfully_creates_repo_private()]
removed call to org/springframework/http/HttpHeaders::add → KILLED

75

1.1
Location : createStudentRepository
Killed by : edu.ucsb.cs156.frontiers.services.RepositoryServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.RepositoryServiceTests]/[method:successfully_creates_repo_private()]
removed call to org/springframework/http/HttpHeaders::add → KILLED

76

1.1
Location : createStudentRepository
Killed by : edu.ucsb.cs156.frontiers.services.RepositoryServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.RepositoryServiceTests]/[method:successfully_creates_repo_private()]
removed call to org/springframework/http/HttpHeaders::add → KILLED

Active mutators

Tests examined


Report generated by PIT 1.17.0