PullTeamsFromGithubJob.java

1
package edu.ucsb.cs156.frontiers.jobs;
2
3
import edu.ucsb.cs156.frontiers.entities.Course;
4
import edu.ucsb.cs156.frontiers.entities.RosterStudent;
5
import edu.ucsb.cs156.frontiers.entities.Team;
6
import edu.ucsb.cs156.frontiers.entities.TeamMember;
7
import edu.ucsb.cs156.frontiers.enums.TeamStatus;
8
import edu.ucsb.cs156.frontiers.repositories.CourseRepository;
9
import edu.ucsb.cs156.frontiers.repositories.TeamMemberRepository;
10
import edu.ucsb.cs156.frontiers.repositories.TeamRepository;
11
import edu.ucsb.cs156.frontiers.services.GithubTeamService;
12
import edu.ucsb.cs156.frontiers.services.GithubTeamService.GithubTeamInfo;
13
import edu.ucsb.cs156.frontiers.services.jobs.JobContext;
14
import edu.ucsb.cs156.frontiers.services.jobs.JobContextConsumer;
15
import java.util.HashMap;
16
import java.util.List;
17
import java.util.Map;
18
import java.util.Optional;
19
import java.util.concurrent.atomic.AtomicBoolean;
20
import lombok.Builder;
21
22
@Builder
23
public class PullTeamsFromGithubJob implements JobContextConsumer {
24
  Long courseId;
25
  CourseRepository courseRepository;
26
  TeamRepository teamRepository;
27
  TeamMemberRepository teamMemberRepository;
28
  GithubTeamService githubTeamService;
29
30
  @Override
31
  public Course getCourse() {
32
    Optional<Course> courseOpt = courseRepository.findById(courseId);
33 1 1. getCourse : replaced return value with null for edu/ucsb/cs156/frontiers/jobs/PullTeamsFromGithubJob::getCourse → KILLED
    return courseOpt.orElse(null);
34
  }
35
36
  @Override
37
  public void accept(JobContext ctx) throws Exception {
38
    ctx.log(String.format("Starting pull teams from GitHub job for course ID: %s", courseId));
39
40
    Optional<Course> courseOpt = courseRepository.findById(courseId);
41 1 1. accept : negated conditional → KILLED
    if (courseOpt.isEmpty()) {
42
      ctx.log(String.format("ERROR: Course with ID %s not found", courseId));
43
      return;
44
    }
45
    Course course = courseOpt.get();
46
    ctx.log(
47
        String.format(
48
            "Processing course: %s (org: %s)", course.getCourseName(), course.getOrgName()));
49
50 2 1. accept : negated conditional → KILLED
2. accept : negated conditional → KILLED
    if (course.getOrgName() == null || course.getInstallationId() == null) {
51
      ctx.log("ERROR: Course has no linked GitHub organization");
52
      return;
53
    }
54
55
    List<GithubTeamInfo> githubTeams;
56
    try {
57
      githubTeams = githubTeamService.getAllTeams(course);
58
    } catch (Exception e) {
59
      ctx.log(String.format("ERROR: Failed to pull teams from GitHub: %s", e.getMessage()));
60
      return;
61
    }
62
63
    Map<Integer, Team> localByGithubId = new HashMap<>();
64
    Map<String, Team> localByName = new HashMap<>();
65
    Map<String, RosterStudent> localStudentsByGithubLogin = new HashMap<>();
66
    for (Team localTeam : teamRepository.findByCourseId(courseId)) {
67 1 1. accept : negated conditional → KILLED
      if (localTeam.getGithubTeamId() != null) {
68
        localByGithubId.put(localTeam.getGithubTeamId(), localTeam);
69
      }
70
      localByName.put(localTeam.getName(), localTeam);
71
    }
72 1 1. accept : negated conditional → KILLED
    if (course.getRosterStudents() != null) {
73
      for (RosterStudent student : course.getRosterStudents()) {
74 1 1. accept : negated conditional → KILLED
        if (student.getGithubLogin() != null) {
75
          localStudentsByGithubLogin.put(student.getGithubLogin(), student);
76
        }
77
      }
78
    }
79
80
    int created = 0;
81
    int updated = 0;
82
    int unchanged = 0;
83
84
    for (GithubTeamInfo githubTeam : githubTeams) {
85
      Team localTeam = localByGithubId.get(githubTeam.id());
86 1 1. accept : negated conditional → KILLED
      if (localTeam == null) {
87
        localTeam = localByName.get(githubTeam.name());
88
      }
89
90
      boolean teamCreated = false;
91 1 1. accept : negated conditional → KILLED
      if (localTeam == null) {
92
        Team newTeam =
93
            Team.builder()
94
                .name(githubTeam.name())
95
                .course(course)
96
                .githubTeamId(githubTeam.id())
97
                .githubTeamSlug(githubTeam.slug())
98
                .build();
99
        teamRepository.save(newTeam);
100
        localByGithubId.put(githubTeam.id(), newTeam);
101
        localByName.put(githubTeam.name(), newTeam);
102 1 1. accept : Changed increment from 1 to -1 → KILLED
        created++;
103
        ctx.log(
104
            String.format(
105
                "Created local team '%s' with GitHub team ID: %d",
106
                githubTeam.name(), githubTeam.id()));
107
        localTeam = newTeam;
108
        teamCreated = true;
109
      }
110
111
      AtomicBoolean teamUnchanged = new AtomicBoolean(true);
112 1 1. accept : negated conditional → KILLED
      if (!teamCreated) {
113 1 1. accept : negated conditional → KILLED
        if (!githubTeam.name().equals(localTeam.getName())) {
114
          localByName.remove(localTeam.getName());
115 1 1. accept : removed call to edu/ucsb/cs156/frontiers/entities/Team::setName → KILLED
          localTeam.setName(githubTeam.name());
116 1 1. accept : removed call to java/util/concurrent/atomic/AtomicBoolean::set → KILLED
          teamUnchanged.set(false);
117
        }
118 1 1. accept : negated conditional → KILLED
        if (!githubTeam.id().equals(localTeam.getGithubTeamId())) {
119 1 1. accept : negated conditional → KILLED
          if (localTeam.getGithubTeamId() != null) {
120
            localByGithubId.remove(localTeam.getGithubTeamId());
121
          }
122 1 1. accept : removed call to edu/ucsb/cs156/frontiers/entities/Team::setGithubTeamId → KILLED
          localTeam.setGithubTeamId(githubTeam.id());
123 1 1. accept : removed call to java/util/concurrent/atomic/AtomicBoolean::set → KILLED
          teamUnchanged.set(false);
124
        }
125 1 1. accept : negated conditional → KILLED
        if (localTeam.getGithubTeamSlug() == null
126 1 1. accept : negated conditional → KILLED
            || !githubTeam.slug().equals(localTeam.getGithubTeamSlug())) {
127 1 1. accept : removed call to edu/ucsb/cs156/frontiers/entities/Team::setGithubTeamSlug → KILLED
          localTeam.setGithubTeamSlug(githubTeam.slug());
128 1 1. accept : removed call to java/util/concurrent/atomic/AtomicBoolean::set → KILLED
          teamUnchanged.set(false);
129
        }
130
131 1 1. accept : negated conditional → KILLED
        if (!teamUnchanged.get()) {
132
          teamRepository.save(localTeam);
133
          ctx.log(
134
              String.format(
135
                  "Updated local team '%s' with GitHub team ID: %d",
136
                  localTeam.getName(), githubTeam.id()));
137
        }
138
      }
139
140
      localByGithubId.put(githubTeam.id(), localTeam);
141
      localByName.put(localTeam.getName(), localTeam);
142
143 1 1. accept : negated conditional → KILLED
      if (!localStudentsByGithubLogin.isEmpty()) {
144
        Map<String, TeamStatus> githubMemberships =
145
            githubTeamService.getTeamMemberships(githubTeam.slug(), course);
146
        Team currentTeam = localTeam;
147 1 1. accept : removed call to java/util/Map::forEach → KILLED
        githubMemberships.forEach(
148
            (githubLogin, membershipStatus) -> {
149
              RosterStudent student = localStudentsByGithubLogin.get(githubLogin);
150 1 1. lambda$accept$0 : negated conditional → KILLED
              if (student == null) {
151
                return;
152
              }
153
154
              Optional<TeamMember> existingTeamMember =
155
                  teamMemberRepository.findByTeamAndRosterStudent(currentTeam, student);
156 1 1. lambda$accept$0 : negated conditional → KILLED
              if (existingTeamMember.isPresent()) {
157
                TeamMember teamMember = existingTeamMember.get();
158 1 1. lambda$accept$0 : negated conditional → KILLED
                if (teamMember.getTeamStatus() != membershipStatus) {
159 1 1. lambda$accept$0 : removed call to edu/ucsb/cs156/frontiers/entities/TeamMember::setTeamStatus → KILLED
                  teamMember.setTeamStatus(membershipStatus);
160
                  teamMemberRepository.save(teamMember);
161 1 1. lambda$accept$0 : removed call to java/util/concurrent/atomic/AtomicBoolean::set → KILLED
                  teamUnchanged.set(false);
162
                  ctx.log(
163
                      String.format(
164
                          "Updated team member '%s' in team '%s' with status %s",
165
                          githubLogin, currentTeam.getName(), membershipStatus));
166
                }
167
              } else {
168
                TeamMember newTeamMember =
169
                    TeamMember.builder()
170
                        .team(currentTeam)
171
                        .rosterStudent(student)
172
                        .teamStatus(membershipStatus)
173
                        .build();
174
                teamMemberRepository.save(newTeamMember);
175 1 1. lambda$accept$0 : removed call to java/util/concurrent/atomic/AtomicBoolean::set → KILLED
                teamUnchanged.set(false);
176
                ctx.log(
177
                    String.format(
178
                        "Created team member '%s' in team '%s' with status %s",
179
                        githubLogin, currentTeam.getName(), membershipStatus));
180
              }
181
            });
182
      }
183
184 1 1. accept : negated conditional → KILLED
      if (!teamCreated) {
185 1 1. accept : negated conditional → KILLED
        if (teamUnchanged.get()) {
186 1 1. accept : Changed increment from 1 to -1 → KILLED
          unchanged++;
187
        } else {
188 1 1. accept : Changed increment from 1 to -1 → KILLED
          updated++;
189
        }
190
      }
191
    }
192
193
    ctx.log(
194
        String.format(
195
            "Completed pull teams from GitHub job for course ID: %s (GitHub teams: %d, created: %d, updated: %d, unchanged: %d)",
196
            courseId, githubTeams.size(), created, updated, unchanged));
197
  }
198
}

Mutations

33

1.1
Location : getCourse
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:test_getCourse_returnsCourse_whenFound()]
replaced return value with null for edu/ucsb/cs156/frontiers/jobs/PullTeamsFromGithubJob::getCourse → KILLED

41

1.1
Location : accept
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_CourseNotFound()]
negated conditional → KILLED

50

1.1
Location : accept
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_GetAllTeamsFailure()]
negated conditional → KILLED

2.2
Location : accept
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_CourseWithOrgNameButNoInstallationId()]
negated conditional → KILLED

67

1.1
Location : accept
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_UpdatesExistingTeamWhenOnlyNameChanges()]
negated conditional → KILLED

72

1.1
Location : accept
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_UpdatesExistingTeamWhenOnlyNameChanges()]
negated conditional → KILLED

74

1.1
Location : accept
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_DoesNotUpdateOrLogWhenMembershipStatusIsUnchanged()]
negated conditional → KILLED

86

1.1
Location : accept
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_UpdatesExistingTeamWhenOnlyNameChanges()]
negated conditional → KILLED

91

1.1
Location : accept
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_UpdatesExistingTeamWhenOnlyNameChanges()]
negated conditional → KILLED

102

1.1
Location : accept
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_RemovesOldGithubIdMappingWhenMatchingByName()]
Changed increment from 1 to -1 → KILLED

112

1.1
Location : accept
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_UpdatesExistingTeamWhenOnlyNameChanges()]
negated conditional → KILLED

113

1.1
Location : accept
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_UpdatesExistingTeamWhenOnlyNameChanges()]
negated conditional → KILLED

115

1.1
Location : accept
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_UpdatesExistingTeamWhenOnlyNameChanges()]
removed call to edu/ucsb/cs156/frontiers/entities/Team::setName → KILLED

116

1.1
Location : accept
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_UpdatesExistingTeamWhenOnlyNameChanges()]
removed call to java/util/concurrent/atomic/AtomicBoolean::set → KILLED

118

1.1
Location : accept
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_UpdatesExistingTeamWhenOnlyGithubIdChanges()]
negated conditional → KILLED

119

1.1
Location : accept
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_RemovesOldGithubIdMappingWhenMatchingByName()]
negated conditional → KILLED

122

1.1
Location : accept
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_UpdatesExistingTeamWhenOnlyGithubIdChanges()]
removed call to edu/ucsb/cs156/frontiers/entities/Team::setGithubTeamId → KILLED

123

1.1
Location : accept
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_UpdatesExistingTeamWhenOnlyGithubIdChanges()]
removed call to java/util/concurrent/atomic/AtomicBoolean::set → KILLED

125

1.1
Location : accept
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_DoesNotUpdateOrLogWhenMembershipStatusIsUnchanged()]
negated conditional → KILLED

126

1.1
Location : accept
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_UpdatesExistingTeamWhenOnlySlugChanges()]
negated conditional → KILLED

127

1.1
Location : accept
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_UpdatesExistingTeamWhenOnlySlugChanges()]
removed call to edu/ucsb/cs156/frontiers/entities/Team::setGithubTeamSlug → KILLED

128

1.1
Location : accept
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_UpdatesExistingTeamWhenOnlySlugChanges()]
removed call to java/util/concurrent/atomic/AtomicBoolean::set → KILLED

131

1.1
Location : accept
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_UpdatesExistingTeamWhenOnlyNameChanges()]
negated conditional → KILLED

143

1.1
Location : accept
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_UpdatesExistingTeamWhenOnlyNameChanges()]
negated conditional → KILLED

147

1.1
Location : accept
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_DoesNotUpdateOrLogWhenMembershipStatusIsUnchanged()]
removed call to java/util/Map::forEach → KILLED

150

1.1
Location : lambda$accept$0
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_DoesNotUpdateOrLogWhenMembershipStatusIsUnchanged()]
negated conditional → KILLED

156

1.1
Location : lambda$accept$0
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_DoesNotUpdateOrLogWhenMembershipStatusIsUnchanged()]
negated conditional → KILLED

158

1.1
Location : lambda$accept$0
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_DoesNotUpdateOrLogWhenMembershipStatusIsUnchanged()]
negated conditional → KILLED

159

1.1
Location : lambda$accept$0
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_CountsTeamUpdatedWhenOnlyMembershipUpdateOccurs()]
removed call to edu/ucsb/cs156/frontiers/entities/TeamMember::setTeamStatus → KILLED

161

1.1
Location : lambda$accept$0
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_CountsTeamUpdatedWhenOnlyMembershipUpdateOccurs()]
removed call to java/util/concurrent/atomic/AtomicBoolean::set → KILLED

175

1.1
Location : lambda$accept$0
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_CountsTeamUpdatedWhenOnlyMembershipCreateOccurs()]
removed call to java/util/concurrent/atomic/AtomicBoolean::set → KILLED

184

1.1
Location : accept
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_UpdatesExistingTeamWhenOnlyNameChanges()]
negated conditional → KILLED

185

1.1
Location : accept
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_UpdatesExistingTeamWhenOnlyNameChanges()]
negated conditional → KILLED

186

1.1
Location : accept
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_DoesNotUpdateOrLogWhenMembershipStatusIsUnchanged()]
Changed increment from 1 to -1 → KILLED

188

1.1
Location : accept
Killed by : edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.jobs.PullTeamsFromGithubJobTests]/[method:testAccept_UpdatesExistingTeamWhenOnlyNameChanges()]
Changed increment from 1 to -1 → KILLED

Active mutators

Tests examined


Report generated by PIT 1.17.0