• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ubccpsc / classy / d75e2632-84ef-47f0-968b-c513a1ce335b

12 Aug 2025 10:17PM UTC coverage: 88.309% (+1.1%) from 87.191%
d75e2632-84ef-47f0-968b-c513a1ce335b

push

circleci

web-flow
Merge pull request #480 from ubccpsc310/main

Merge 25w1 changes

1092 of 1321 branches covered (82.66%)

Branch coverage included in aggregate %.

3931 of 4367 relevant lines covered (90.02%)

37.09 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.9
packages/portal/backend/src/controllers/RepositoryController.ts
1
import Log from "@common/Log";
1✔
2
import { RepositoryTransport } from "@common/types/PortalTypes";
3
import Util from "@common/Util";
1✔
4
import { Deliverable, GitHubStatus, Person, Repository, Team } from "../Types";
1✔
5

6
import { DatabaseController } from "./DatabaseController";
1✔
7
import { DeliverablesController } from "./DeliverablesController";
1✔
8
import { TeamController } from "./TeamController";
1✔
9

10
export class RepositoryController {
1✔
11
        private db: DatabaseController = DatabaseController.getInstance();
204✔
12

13
        public static repositoryToTransport(repository: Repository): RepositoryTransport {
14
                if (typeof repository === "undefined" || repository === null) {
12✔
15
                        throw new Error("RepositoryController::repositoryToTransport( .. ) - ERROR: repository not provided.");
2✔
16
                }
17

18
                const repo: RepositoryTransport = {
10✔
19
                        id: repository.id,
20
                        URL: repository.URL,
21
                        delivId: repository.delivId,
22
                        gitHubStatus: repository.gitHubStatus.toString(),
23
                };
24

25
                return repo;
10✔
26
        }
27

28
        public async getAllRepos(): Promise<Repository[]> {
29
                Log.trace("RepositoryController::getAllRepos() - start");
26✔
30
                const start = Date.now();
26✔
31

32
                const repos = await this.db.getRepositories();
26✔
33

34
                Log.trace("RepositoryController::getAllRepos() - done; # repos: " + repos.length + "; took: " + Util.took(start));
26✔
35
                return repos;
26✔
36
        }
37

38
        public async getRepository(name: string): Promise<Repository | null> {
39
                Log.trace("RepositoryController::getRepository( " + name + " ) - start");
95✔
40
                const start = Date.now();
95✔
41

42
                const repo = await this.db.getRepository(name);
95✔
43

44
                Log.trace("RepositoryController::getRepository( " + name + " ) - done; took: " + Util.took(start));
95✔
45
                return repo;
95✔
46
        }
47

48
        public async getReposForPerson(myPerson: Person): Promise<Repository[]> {
49
                Log.trace("RepositoryController::getReposForPerson( " + myPerson.id + " ) - start");
4✔
50
                const start = Date.now();
4✔
51

52
                // TODO: this is slow; there is a faster implementation in db.getReposForPerson now, but it is untested
53
                // db.getRepositoriesForPerson(myPerson.id)
54

55
                const myTeams = await new TeamController().getTeamsForPerson(myPerson);
4✔
56
                Log.trace("RepositoryController::getReposForPerson( " + myPerson.id + " ) - # teams: " + myTeams.length);
4✔
57

58
                const myRepos: Repository[] = [];
4✔
59
                const allRepos = await this.db.getRepositories();
4✔
60
                for (const repo of allRepos) {
4✔
61
                        for (const team of myTeams) {
9✔
62
                                if (repo.teamIds.indexOf(team.id) >= 0) {
26✔
63
                                        myRepos.push(repo);
9✔
64
                                }
65
                        }
66
                }
67

68
                Log.trace(
4✔
69
                        "RepositoryController::getReposForPerson( " +
70
                                myPerson.id +
71
                                " ) - done; # found: " +
72
                                myRepos.length +
73
                                "; took: " +
74
                                Util.took(start)
75
                );
76
                return myRepos;
4✔
77
        }
78

79
        /**
80
         * Updates an existing repository record.
81
         *
82
         * @param {Repository} repo
83
         * @returns {Promise<Repository>}
84
         */
85
        public async updateRepository(repo: Repository): Promise<Repository> {
86
                if (typeof repo === "undefined" || repo === null) {
3✔
87
                        return null;
1✔
88
                }
89

90
                Log.info("RepositoryController::updateRepository( " + repo.id + " ) - start");
2✔
91

92
                const existingRepo = await this.getRepository(repo.id);
2✔
93
                if (existingRepo === null) {
2✔
94
                        // repo not in db, create new one
95
                        const teams: Team[] = [];
1✔
96
                        const tc = new TeamController();
1✔
97
                        for (const tid of repo.teamIds) {
1✔
98
                                const team = await tc.getTeam(tid);
×
99
                                teams.push(team);
×
100
                        }
101
                        const dc = new DeliverablesController();
1✔
102
                        const deliv = await dc.getDeliverable(repo.delivId);
1✔
103
                        await this.createRepository(repo.id, deliv, teams, repo.custom);
1✔
104
                } else {
105
                        // overwrite existing repo
106
                        const customExisting = Object.assign({}, existingRepo.custom); // overwrite with new fields
1✔
107
                        const customCombined = Object.assign(customExisting, existingRepo.custom);
1✔
108
                        repo.custom = customCombined;
1✔
109
                        await this.db.writeRepository(repo);
1✔
110
                }
111

112
                Log.info("RepositoryController::updateRepository( " + repo.id + " ) - done");
2✔
113
                return await this.db.getRepository(repo.id);
2✔
114
        }
115

116
        // public async createPullRequest(repoId: string, prId: string, custom: any): Promise<Repository | null> {
117
        //     Log.error("RepositoryController::createPullRequest( " + repoId + ", " + prId + ", .. ) -  NOT IMPLEMENTED!!");
118
        //     // TODO: implement PR functionality
119
        //
120
        //     // NOTE: this impl is more complex than it needs to be but is erring on the side of caution
121
        //     const repo = await this.getRepository(repoId);
122
        //     const customA = Object.assign({}, repo.custom);
123
        //     const customB = Object.assign(customA, custom); // overwrite with new fields
124
        //     repo.custom = customB;
125
        //     await this.db.writeRepository(repo);
126
        //     return await this.getRepository(repoId);
127
        // }
128

129
        public async createRepository(name: string, deliv: Deliverable, teams: Team[], custom: any): Promise<Repository | null> {
130
                Log.info("RepositoryController::createRepository( " + name + ", .. ) - start");
55✔
131

132
                const existingRepo = await this.getRepository(name);
55✔
133
                if (existingRepo === null) {
55✔
134
                        const teamIds: string[] = teams.map((team) => team.id);
40✔
135

136
                        if (custom === null) {
39!
137
                                custom = {}; // custom must not be null
×
138
                        }
139

140
                        const repo: Repository = {
39✔
141
                                id: name,
142
                                delivId: deliv.id,
143
                                URL: null,
144
                                gitHubStatus: GitHubStatus.NOT_PROVISIONED,
145
                                cloneURL: null,
146
                                teamIds: teamIds,
147
                                custom: custom,
148
                        };
149

150
                        await this.db.writeRepository(repo);
39✔
151

152
                        Log.info("RepositoryController::createRepository( " + name + ", .. ) - done");
39✔
153
                        return await this.db.getRepository(repo.id);
39✔
154
                } else {
155
                        Log.info("RepositoryController::createRepository( " + name + ", .. ) - repository exists: " + JSON.stringify(existingRepo));
15✔
156
                        return await this.db.getRepository(name);
15✔
157
                }
158
        }
159

160
        public async getPeopleForRepo(repoId: string): Promise<string[] | null> {
161
                Log.trace("RepositoryController::getPeopleForRepo( " + repoId + ", .. ) -  start");
6✔
162
                const start = Date.now();
6✔
163

164
                const peopleIds: string[] = [];
6✔
165
                const tc = new TeamController();
6✔
166
                const repo = await this.getRepository(repoId);
6✔
167
                if (repo !== null) {
6✔
168
                        for (const teamId of repo.teamIds) {
5✔
169
                                const team = await tc.getTeam(teamId);
5✔
170
                                for (const personId of team.personIds) {
5✔
171
                                        if (peopleIds.indexOf(personId) < 0) {
10!
172
                                                peopleIds.push(personId);
10✔
173
                                        }
174
                                }
175
                        }
176
                }
177

178
                Log.trace(
6✔
179
                        "RepositoryController::getPeopleForRepo( " +
180
                                repoId +
181
                                ", .. ) -  done; # people: " +
182
                                peopleIds.length +
183
                                "; took: " +
184
                                Util.took(start)
185
                );
186
                return peopleIds;
6✔
187
        }
188
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc