RepositoryService.java

1
package edu.ucsb.cs156.frontiers.services;
2
3
import com.fasterxml.jackson.core.JsonProcessingException;
4
import com.fasterxml.jackson.databind.JsonNode;
5
import com.fasterxml.jackson.databind.ObjectMapper;
6
import edu.ucsb.cs156.frontiers.entities.Course;
7
import edu.ucsb.cs156.frontiers.entities.CourseStaff;
8
import edu.ucsb.cs156.frontiers.entities.RosterStudent;
9
import edu.ucsb.cs156.frontiers.entities.Team;
10
import edu.ucsb.cs156.frontiers.enums.RepositoryPermissions;
11
import edu.ucsb.cs156.frontiers.repositories.TeamRepository;
12
import java.security.NoSuchAlgorithmException;
13
import java.security.spec.InvalidKeySpecException;
14
import java.util.ArrayList;
15
import java.util.HashMap;
16
import java.util.List;
17
import java.util.Map;
18
import lombok.extern.slf4j.Slf4j;
19
import org.springframework.boot.web.client.RestTemplateBuilder;
20
import org.springframework.http.*;
21
import org.springframework.stereotype.Service;
22
import org.springframework.web.client.HttpClientErrorException;
23
import org.springframework.web.client.RestTemplate;
24
25
@Service
26
@Slf4j
27
public class RepositoryService {
28
  private final JwtService jwtService;
29
  private final GithubTeamService githubTeamService;
30
  private final TeamRepository teamRepository;
31
  private final RestTemplate restTemplate;
32
  private final ObjectMapper mapper;
33
34
  public record GithubRepository(String name, String fullName) {}
35
36
  private HttpHeaders githubHeaders(String token) {
37
    HttpHeaders headers = new HttpHeaders();
38 1 1. githubHeaders : removed call to org/springframework/http/HttpHeaders::add → KILLED
    headers.add("Authorization", "Bearer " + token);
39 1 1. githubHeaders : removed call to org/springframework/http/HttpHeaders::add → KILLED
    headers.add("Accept", "application/vnd.github+json");
40 1 1. githubHeaders : removed call to org/springframework/http/HttpHeaders::add → KILLED
    headers.add("X-GitHub-Api-Version", "2022-11-28");
41 1 1. githubHeaders : replaced return value with null for edu/ucsb/cs156/frontiers/services/RepositoryService::githubHeaders → KILLED
    return headers;
42
  }
43
44
  /**
45
   * Creates a GitHub repository for a user (student or staff), given only their GitHub login.
46
   *
47
   * <p>This helper method contains the shared logic used by both {@link
48
   * #createStudentRepository(Course, RosterStudent, String, Boolean, RepositoryPermissions)} and
49
   * {@link #createStaffRepository(Course, CourseStaff, String, Boolean, RepositoryPermissions)}.
50
   *
51
   * <ul>
52
   *   <li>Checks whether the repository already exists.
53
   *   <li>If not, creates a new repository under the course's organization.
54
   *   <li>Adds the user as a collaborator with the given permission level.
55
   * </ul>
56
   *
57
   * @param course the course whose organization the repo belongs to
58
   * @param githubLogin GitHub username of the student or staff member
59
   * @param repoPrefix prefix for the repository name (repoPrefix-githubLogin)
60
   * @param isPrivate whether the created repository should be private
61
   * @param permissions collaborator permissions to grant the user
62
   * @throws NoSuchAlgorithmException if signing fails
63
   * @throws InvalidKeySpecException if signing fails
64
   * @throws JsonProcessingException if JSON serialization fails
65
   */
66
  private void createRepositoryForStudentOrStaff(
67
      Course course,
68
      String githubLogin,
69
      String repoPrefix,
70
      Boolean isPrivate,
71
      RepositoryPermissions permissions)
72
      throws NoSuchAlgorithmException, InvalidKeySpecException, JsonProcessingException {
73
74
    String newRepoName = repoPrefix + "-" + githubLogin;
75
    String token = jwtService.getInstallationToken(course);
76
77
    String existenceEndpoint =
78
        "https://api.github.com/repos/" + course.getOrgName() + "/" + newRepoName;
79
    String createEndpoint = "https://api.github.com/orgs/" + course.getOrgName() + "/repos";
80
    String provisionEndpoint =
81
        "https://api.github.com/repos/"
82
            + course.getOrgName()
83
            + "/"
84
            + newRepoName
85
            + "/collaborators/"
86
            + githubLogin;
87
88
    HttpHeaders existenceHeaders = githubHeaders(token);
89
90
    HttpEntity<String> existenceEntity = new HttpEntity<>(existenceHeaders);
91
92
    try {
93
      restTemplate.exchange(existenceEndpoint, HttpMethod.GET, existenceEntity, String.class);
94
    } catch (HttpClientErrorException e) {
95 1 1. createRepositoryForStudentOrStaff : negated conditional → KILLED
      if (e.getStatusCode().equals(HttpStatus.NOT_FOUND)) {
96
        HttpHeaders createHeaders = githubHeaders(token);
97
98
        Map<String, Object> body = new HashMap<>();
99
        body.put("name", newRepoName);
100
        body.put("private", isPrivate);
101
        String bodyAsJson = mapper.writeValueAsString(body);
102
103
        HttpEntity<String> createEntity = new HttpEntity<>(bodyAsJson, createHeaders);
104
105
        restTemplate.exchange(createEndpoint, HttpMethod.POST, createEntity, String.class);
106
      } else {
107
        log.warn(
108
            "Unexpected response code {} when checking for existence of repository {}",
109
            e.getStatusCode(),
110
            newRepoName);
111
        return;
112
      }
113
    }
114
115
    try {
116
      Map<String, Object> provisionBody = new HashMap<>();
117
      provisionBody.put("permission", permissions.getApiName());
118
      String provisionAsJson = mapper.writeValueAsString(provisionBody);
119
120
      HttpEntity<String> provisionEntity = new HttpEntity<>(provisionAsJson, existenceHeaders);
121
      restTemplate.exchange(provisionEndpoint, HttpMethod.PUT, provisionEntity, String.class);
122
    } catch (HttpClientErrorException ignored) {
123
      // silently ignore if provisioning fails (same as before)
124
    }
125
  }
126
127
  public RepositoryService(
128
      JwtService jwtService,
129
      GithubTeamService githubTeamService,
130
      TeamRepository teamRepository,
131
      RestTemplateBuilder restTemplateBuilder,
132
      ObjectMapper mapper) {
133
    this.jwtService = jwtService;
134
    this.githubTeamService = githubTeamService;
135
    this.teamRepository = teamRepository;
136
    this.restTemplate = restTemplateBuilder.build();
137
    this.mapper = mapper;
138
  }
139
140
  /**
141
   * Creates a single student repository if it doesn't already exist, and provisions access to the
142
   * repository by that student
143
   *
144
   * @param course The Course in question
145
   * @param student RosterStudent of the student the repository should be created for
146
   * @param repoPrefix Name of the project or assignment. Used to title the repository, in the
147
   *     format repoPrefix-githubLogin
148
   * @param isPrivate Whether the repository is private or not
149
   */
150
  public void createStudentRepository(
151
      Course course,
152
      RosterStudent student,
153
      String repoPrefix,
154
      Boolean isPrivate,
155
      RepositoryPermissions permissions)
156
      throws NoSuchAlgorithmException, InvalidKeySpecException, JsonProcessingException {
157 1 1. createStudentRepository : removed call to edu/ucsb/cs156/frontiers/services/RepositoryService::createRepositoryForStudentOrStaff → KILLED
    createRepositoryForStudentOrStaff(
158
        course, student.getGithubLogin(), repoPrefix, isPrivate, permissions);
159
  }
160
161
  /**
162
   * Creates a single staff repository if it doesn't already exist, and provisions access to the
163
   * repository by that staff member
164
   *
165
   * @param course The Course in question
166
   * @param staff CourseStaff of the staff the repository should be created for
167
   * @param repoPrefix Name of the project or assignment. Used to title the repository, in the
168
   *     format repoPrefix-githubLogin
169
   * @param isPrivate Whether the repository is private or not
170
   */
171
  public void createStaffRepository(
172
      Course course,
173
      CourseStaff staff,
174
      String repoPrefix,
175
      Boolean isPrivate,
176
      RepositoryPermissions permissions)
177
      throws NoSuchAlgorithmException, InvalidKeySpecException, JsonProcessingException {
178
179 1 1. createStaffRepository : removed call to edu/ucsb/cs156/frontiers/services/RepositoryService::createRepositoryForStudentOrStaff → KILLED
    createRepositoryForStudentOrStaff(
180
        course, staff.getGithubLogin(), repoPrefix, isPrivate, permissions);
181
  }
182
183
  /**
184
   * Lists repositories in the course GitHub organization whose names start with the provided
185
   * prefix.
186
   */
187
  public List<GithubRepository> getRepositoriesMatchingPrefix(Course course, String prefix)
188
      throws NoSuchAlgorithmException, InvalidKeySpecException, JsonProcessingException {
189
    String token = jwtService.getInstallationToken(course);
190
    String endpoint = "https://api.github.com/orgs/" + course.getOrgName() + "/repos?per_page=100";
191
192
    HttpEntity<String> entity = new HttpEntity<>(githubHeaders(token));
193
    ResponseEntity<String> response =
194
        restTemplate.exchange(endpoint, HttpMethod.GET, entity, String.class);
195
196
    JsonNode repos = mapper.readTree(response.getBody());
197
    List<GithubRepository> matchingRepos = new ArrayList<>();
198
    for (JsonNode repo : repos) {
199
      String name = repo.path("name").asText();
200 1 1. getRepositoriesMatchingPrefix : negated conditional → KILLED
      if (name.startsWith(prefix)) {
201
        matchingRepos.add(new GithubRepository(name, repo.path("full_name").asText()));
202
      }
203
    }
204 1 1. getRepositoriesMatchingPrefix : replaced return value with Collections.emptyList for edu/ucsb/cs156/frontiers/services/RepositoryService::getRepositoriesMatchingPrefix → KILLED
    return matchingRepos;
205
  }
206
207
  /** Returns true when the repository has no commits. */
208
  public boolean isRepositoryEmpty(Course course, String repositoryName)
209
      throws NoSuchAlgorithmException, InvalidKeySpecException, JsonProcessingException {
210
    String token = jwtService.getInstallationToken(course);
211
    String endpoint =
212
        "https://api.github.com/repos/"
213
            + course.getOrgName()
214
            + "/"
215
            + repositoryName
216
            + "/commits?per_page=1";
217
218
    HttpEntity<String> entity = new HttpEntity<>(githubHeaders(token));
219
    try {
220
      ResponseEntity<String> response =
221
          restTemplate.exchange(endpoint, HttpMethod.GET, entity, String.class);
222
      JsonNode commits = mapper.readTree(response.getBody());
223 3 1. isRepositoryEmpty : negated conditional → KILLED
2. isRepositoryEmpty : replaced boolean return with true for edu/ucsb/cs156/frontiers/services/RepositoryService::isRepositoryEmpty → KILLED
3. isRepositoryEmpty : negated conditional → KILLED
      return commits.isArray() && commits.isEmpty();
224
    } catch (HttpClientErrorException e) {
225 1 1. isRepositoryEmpty : negated conditional → KILLED
      if (e.getStatusCode().equals(HttpStatus.CONFLICT)) {
226 1 1. isRepositoryEmpty : replaced boolean return with false for edu/ucsb/cs156/frontiers/services/RepositoryService::isRepositoryEmpty → KILLED
        return true;
227
      }
228
      throw e;
229
    }
230
  }
231
232
  /** Deletes a repository only when it is empty. Returns true when a delete request was sent. */
233
  public boolean deleteRepositoryIfEmpty(Course course, String repositoryName)
234
      throws NoSuchAlgorithmException, InvalidKeySpecException, JsonProcessingException {
235 1 1. deleteRepositoryIfEmpty : negated conditional → KILLED
    if (!isRepositoryEmpty(course, repositoryName)) {
236 1 1. deleteRepositoryIfEmpty : replaced boolean return with true for edu/ucsb/cs156/frontiers/services/RepositoryService::deleteRepositoryIfEmpty → KILLED
      return false;
237
    }
238
239
    String token = jwtService.getInstallationToken(course);
240
    String endpoint = "https://api.github.com/repos/" + course.getOrgName() + "/" + repositoryName;
241
242
    HttpEntity<String> entity = new HttpEntity<>(githubHeaders(token));
243
    restTemplate.exchange(endpoint, HttpMethod.DELETE, entity, String.class);
244 1 1. deleteRepositoryIfEmpty : replaced boolean return with false for edu/ucsb/cs156/frontiers/services/RepositoryService::deleteRepositoryIfEmpty → KILLED
    return true;
245
  }
246
247
  /**
248
   * Creates a GitHub repository for a team (student or staff), given only their team name.
249
   *
250
   * <ul>
251
   *   <li>Checks whether the repository already exists.
252
   *   <li>If not, creates a new repository under the course's organization.
253
   *   <li>Adds all team members as collaborators with the given permission level.
254
   * </ul>
255
   *
256
   * @param course the course whose organization the repo belongs to
257
   * @param team the team for which the repo is being created
258
   * @param repoPrefix prefix for the repository name (repoPrefix-teamSlug)
259
   * @param isPrivate whether the created repository should be private
260
   * @param permissions collaborator permissions to grant the user
261
   * @param orgId GitHub organization ID used for team-based repo provisioning
262
   * @throws NoSuchAlgorithmException if signing fails
263
   * @throws InvalidKeySpecException if signing fails
264
   * @throws JsonProcessingException if JSON serialization fails
265
   */
266
  public void createTeamRepository(
267
      Course course,
268
      Team team,
269
      String repoPrefix,
270
      Boolean isPrivate,
271
      RepositoryPermissions permissions,
272
      Integer orgId)
273
      throws NoSuchAlgorithmException, InvalidKeySpecException, JsonProcessingException {
274
    String teamSlug = getOrFetchTeamSlug(course, team, orgId);
275
    String newRepoName = repoPrefix + "-" + teamSlug;
276
    String token = jwtService.getInstallationToken(course);
277
278
    String existenceEndpoint =
279
        "https://api.github.com/repos/" + course.getOrgName() + "/" + newRepoName;
280
    String createEndpoint = "https://api.github.com/orgs/" + course.getOrgName() + "/repos";
281
    String provisionEndpoint =
282
        "https://api.github.com/organizations/"
283
            + orgId
284
            + "/team/"
285
            + team.getGithubTeamId()
286
            + "/repos/"
287
            + course.getOrgName()
288
            + "/"
289
            + newRepoName;
290
291
    HttpHeaders existenceHeaders = githubHeaders(token);
292
293
    HttpEntity<String> existenceEntity = new HttpEntity<>(existenceHeaders);
294
295
    try {
296
      restTemplate.exchange(existenceEndpoint, HttpMethod.GET, existenceEntity, String.class);
297
    } catch (HttpClientErrorException e) {
298 1 1. createTeamRepository : negated conditional → KILLED
      if (e.getStatusCode().equals(HttpStatus.NOT_FOUND)) {
299
        HttpHeaders createHeaders = githubHeaders(token);
300
301
        Map<String, Object> body = new HashMap<>();
302
        body.put("name", newRepoName);
303
        body.put("private", isPrivate);
304
        String bodyAsJson = mapper.writeValueAsString(body);
305
306
        HttpEntity<String> createEntity = new HttpEntity<>(bodyAsJson, createHeaders);
307
308
        restTemplate.exchange(createEndpoint, HttpMethod.POST, createEntity, String.class);
309
      } else {
310
        log.warn(
311
            "Unexpected response code {} when checking for existence of repository {}",
312
            e.getStatusCode(),
313
            newRepoName);
314
        return;
315
      }
316
    }
317
    try {
318
      Map<String, Object> provisionBody = new HashMap<>();
319
      provisionBody.put("permission", permissions.getApiName());
320
      String provisionAsJson = mapper.writeValueAsString(provisionBody);
321
322
      HttpEntity<String> provisionEntity = new HttpEntity<>(provisionAsJson, existenceHeaders);
323
      restTemplate.exchange(provisionEndpoint, HttpMethod.PUT, provisionEntity, String.class);
324
    } catch (HttpClientErrorException ignored) {
325
      // silently ignore if provisioning fails (same as before)
326
    }
327
  }
328
329
  private String getOrFetchTeamSlug(Course course, Team team, Integer orgId)
330
      throws JsonProcessingException, NoSuchAlgorithmException, InvalidKeySpecException {
331 2 1. getOrFetchTeamSlug : negated conditional → KILLED
2. getOrFetchTeamSlug : negated conditional → KILLED
    if (team.getGithubTeamSlug() != null && !team.getGithubTeamSlug().isBlank()) {
332 1 1. getOrFetchTeamSlug : replaced return value with "" for edu/ucsb/cs156/frontiers/services/RepositoryService::getOrFetchTeamSlug → KILLED
      return team.getGithubTeamSlug();
333
    }
334
335 1 1. getOrFetchTeamSlug : negated conditional → KILLED
    if (team.getGithubTeamId() == null) {
336
      throw new IllegalStateException(
337
          "Cannot create team repository without a GitHub team ID for team '"
338
              + team.getName()
339
              + "'");
340
    }
341
342
    GithubTeamService.GithubTeamInfo teamInfo =
343
        githubTeamService.getTeamInfoById(orgId, team.getGithubTeamId(), course);
344
345 3 1. getOrFetchTeamSlug : negated conditional → KILLED
2. getOrFetchTeamSlug : negated conditional → KILLED
3. getOrFetchTeamSlug : negated conditional → KILLED
    if (teamInfo == null || teamInfo.slug() == null || teamInfo.slug().isBlank()) {
346
      throw new IllegalStateException(
347
          "Cannot determine GitHub team slug for team '" + team.getName() + "'");
348
    }
349
350 1 1. getOrFetchTeamSlug : removed call to edu/ucsb/cs156/frontiers/entities/Team::setGithubTeamSlug → KILLED
    team.setGithubTeamSlug(teamInfo.slug());
351
    teamRepository.save(team);
352 1 1. getOrFetchTeamSlug : replaced return value with "" for edu/ucsb/cs156/frontiers/services/RepositoryService::getOrFetchTeamSlug → KILLED
    return teamInfo.slug();
353
  }
354
}

Mutations

38

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

39

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

40

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

41

1.1
Location : githubHeaders
Killed by : edu.ucsb.cs156.frontiers.services.RepositoryServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.RepositoryServiceTests]/[method:isRepositoryEmpty_returns_false_when_commits_exist()]
replaced return value with null for edu/ucsb/cs156/frontiers/services/RepositoryService::githubHeaders → KILLED

95

1.1
Location : createRepositoryForStudentOrStaff
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

157

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 edu/ucsb/cs156/frontiers/services/RepositoryService::createRepositoryForStudentOrStaff → KILLED

179

1.1
Location : createStaffRepository
Killed by : edu.ucsb.cs156.frontiers.services.RepositoryServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.RepositoryServiceTests]/[method:successfully_creates_staff_repo_public()]
removed call to edu/ucsb/cs156/frontiers/services/RepositoryService::createRepositoryForStudentOrStaff → KILLED

200

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

204

1.1
Location : getRepositoriesMatchingPrefix
Killed by : edu.ucsb.cs156.frontiers.services.RepositoryServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.RepositoryServiceTests]/[method:getRepositoriesMatchingPrefix_filters_matching_repositories()]
replaced return value with Collections.emptyList for edu/ucsb/cs156/frontiers/services/RepositoryService::getRepositoriesMatchingPrefix → KILLED

223

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

2.2
Location : isRepositoryEmpty
Killed by : edu.ucsb.cs156.frontiers.services.RepositoryServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.RepositoryServiceTests]/[method:isRepositoryEmpty_returns_false_when_commits_exist()]
replaced boolean return with true for edu/ucsb/cs156/frontiers/services/RepositoryService::isRepositoryEmpty → KILLED

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

225

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

226

1.1
Location : isRepositoryEmpty
Killed by : edu.ucsb.cs156.frontiers.services.RepositoryServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.RepositoryServiceTests]/[method:isRepositoryEmpty_returns_true_when_github_reports_empty_repository()]
replaced boolean return with false for edu/ucsb/cs156/frontiers/services/RepositoryService::isRepositoryEmpty → KILLED

235

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

236

1.1
Location : deleteRepositoryIfEmpty
Killed by : edu.ucsb.cs156.frontiers.services.RepositoryServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.RepositoryServiceTests]/[method:deleteRepositoryIfEmpty_does_not_delete_non_empty_repository()]
replaced boolean return with true for edu/ucsb/cs156/frontiers/services/RepositoryService::deleteRepositoryIfEmpty → KILLED

244

1.1
Location : deleteRepositoryIfEmpty
Killed by : edu.ucsb.cs156.frontiers.services.RepositoryServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.RepositoryServiceTests]/[method:deleteRepositoryIfEmpty_deletes_empty_repository()]
replaced boolean return with false for edu/ucsb/cs156/frontiers/services/RepositoryService::deleteRepositoryIfEmpty → KILLED

298

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

331

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

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

332

1.1
Location : getOrFetchTeamSlug
Killed by : edu.ucsb.cs156.frontiers.services.RepositoryServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.RepositoryServiceTests]/[method:exits_if_team_repo_not_not_found()]
replaced return value with "" for edu/ucsb/cs156/frontiers/services/RepositoryService::getOrFetchTeamSlug → KILLED

335

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

345

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

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

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

350

1.1
Location : getOrFetchTeamSlug
Killed by : edu.ucsb.cs156.frontiers.services.RepositoryServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.RepositoryServiceTests]/[method:team_repo_fetches_and_persists_slug_when_missing()]
removed call to edu/ucsb/cs156/frontiers/entities/Team::setGithubTeamSlug → KILLED

352

1.1
Location : getOrFetchTeamSlug
Killed by : edu.ucsb.cs156.frontiers.services.RepositoryServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.RepositoryServiceTests]/[method:team_repo_fetches_and_persists_slug_when_missing()]
replaced return value with "" for edu/ucsb/cs156/frontiers/services/RepositoryService::getOrFetchTeamSlug → KILLED

Active mutators

Tests examined


Report generated by PIT 1.17.0