Skip to content

Commit 084883c

Browse files
committed
Refactor GitHubRepositoryDataSource for improved readability and consistency
1 parent 0f6711a commit 084883c

File tree

1 file changed

+149
-161
lines changed

1 file changed

+149
-161
lines changed

src/features/projects/data/GitHubRepositoryDataSource.ts

Lines changed: 149 additions & 161 deletions
Original file line numberDiff line numberDiff line change
@@ -2,173 +2,162 @@ import {
22
GitHubRepository,
33
IGitHubRepositoryDataSource,
44
IGitHubLoginDataSource,
5-
IGitHubGraphQLClient,
6-
} from "../domain";
5+
IGitHubGraphQLClient
6+
} from "../domain"
77

88
type GraphQLGitHubRepository = {
9-
readonly name: string;
9+
readonly name: string
1010
readonly owner: {
11-
readonly login: string;
12-
};
11+
readonly login: string
12+
}
1313
readonly defaultBranchRef: {
14-
readonly name: string;
14+
readonly name: string
1515
readonly target: {
16-
readonly oid: string;
17-
};
18-
};
16+
readonly oid: string
17+
}
18+
}
1919
readonly configYml?: {
20-
readonly text: string;
21-
};
20+
readonly text: string
21+
}
2222
readonly configYaml?: {
23-
readonly text: string;
24-
};
25-
readonly branches: EdgesContainer<GraphQLGitHubRepositoryRef>;
26-
readonly tags: EdgesContainer<GraphQLGitHubRepositoryRef>;
27-
};
23+
readonly text: string
24+
}
25+
readonly branches: EdgesContainer<GraphQLGitHubRepositoryRef>
26+
readonly tags: EdgesContainer<GraphQLGitHubRepositoryRef>
27+
}
2828

2929
type EdgesContainer<T> = {
30-
readonly edges: Edge<T>[];
31-
};
30+
readonly edges: Edge<T>[]
31+
}
3232

3333
type Edge<T> = {
34-
readonly node: T;
35-
};
34+
readonly node: T
35+
}
3636

3737
type GraphQLGitHubRepositoryRef = {
38-
readonly name: string;
38+
readonly name: string
3939
readonly target: {
40-
readonly oid: string;
40+
readonly oid: string
4141
readonly tree: {
4242
readonly entries: {
43-
readonly name: string;
44-
}[];
45-
};
46-
};
47-
};
43+
readonly name: string
44+
}[]
45+
}
46+
}
47+
}
4848

4949
type GraphQLPullRequest = {
50-
readonly headRefName: string;
51-
readonly baseRefName: string;
52-
readonly baseRefOid: string;
53-
};
54-
55-
export default class GitHubProjectDataSource
56-
implements IGitHubRepositoryDataSource
57-
{
58-
private readonly loginsDataSource: IGitHubLoginDataSource;
59-
private readonly graphQlClient: IGitHubGraphQLClient;
60-
private readonly repositoryNameSuffix: string;
61-
private readonly projectConfigurationFilename: string;
50+
readonly headRefName: string
51+
readonly baseRefName: string
52+
readonly baseRefOid: string
53+
}
6254

55+
export default class GitHubProjectDataSource implements IGitHubRepositoryDataSource {
56+
private readonly loginsDataSource: IGitHubLoginDataSource
57+
private readonly graphQlClient: IGitHubGraphQLClient
58+
private readonly repositoryNameSuffix: string
59+
private readonly projectConfigurationFilename: string
60+
6361
constructor(config: {
64-
loginsDataSource: IGitHubLoginDataSource;
65-
graphQlClient: IGitHubGraphQLClient;
66-
repositoryNameSuffix: string;
67-
projectConfigurationFilename: string;
62+
loginsDataSource: IGitHubLoginDataSource,
63+
graphQlClient: IGitHubGraphQLClient,
64+
repositoryNameSuffix: string,
65+
projectConfigurationFilename: string
6866
}) {
69-
this.loginsDataSource = config.loginsDataSource;
70-
this.graphQlClient = config.graphQlClient;
71-
this.repositoryNameSuffix = config.repositoryNameSuffix;
72-
this.projectConfigurationFilename =
73-
config.projectConfigurationFilename.replace(/\.ya?ml$/, "");
67+
this.loginsDataSource = config.loginsDataSource
68+
this.graphQlClient = config.graphQlClient
69+
this.repositoryNameSuffix = config.repositoryNameSuffix
70+
this.projectConfigurationFilename = config.projectConfigurationFilename.replace(/\.ya?ml$/, "")
7471
}
75-
72+
7673
async getRepositories(): Promise<GitHubRepository[]> {
77-
const logins = await this.loginsDataSource.getLogins();
78-
return await this.getRepositoriesForLogins({ logins });
74+
const logins = await this.loginsDataSource.getLogins()
75+
return await this.getRepositoriesForLogins({ logins })
7976
}
80-
81-
private async getRepositoriesForLogins({
82-
logins,
83-
}: {
84-
logins: string[];
85-
}): Promise<GitHubRepository[]> {
86-
let searchQueries: string[] = [];
77+
78+
private async getRepositoriesForLogins({ logins }: { logins: string[] }): Promise<GitHubRepository[]> {
79+
let searchQueries: string[] = []
8780
// Search for all private repositories the user has access to. This is needed to find
8881
// repositories for external collaborators who do not belong to an organization.
89-
searchQueries.push(`"${this.repositoryNameSuffix}" in:name is:private`);
82+
searchQueries.push(`"${this.repositoryNameSuffix}" in:name is:private`)
9083
// Search for public repositories belonging to a user or organization.
91-
searchQueries = searchQueries.concat(
92-
logins.map((login) => {
93-
return `"${this.repositoryNameSuffix}" in:name user:${login} is:public`;
84+
searchQueries = searchQueries.concat(logins.map(login => {
85+
return `"${this.repositoryNameSuffix}" in:name user:${login} is:public`
86+
}))
87+
return await Promise.all(searchQueries.map(searchQuery => {
88+
return this.getRepositoriesForSearchQuery({ searchQuery })
89+
}))
90+
.then(e => e.flat())
91+
.then(repositories => {
92+
// GitHub's search API does not enable searching for repositories whose name ends with "-openapi",
93+
// only repositories whose names include "openapi" so we filter the results ourselves.
94+
return repositories.filter(repository => {
95+
return repository.name.endsWith(this.repositoryNameSuffix)
9496
})
95-
);
96-
return await Promise.all(
97-
searchQueries.map((searchQuery) => {
98-
return this.getRepositoriesForSearchQuery({ searchQuery });
97+
})
98+
.then(repositories => {
99+
// Ensure we don't have duplicates in the resulting repositories.
100+
const uniqueIdentifiers = new Set<string>()
101+
return repositories.filter(repository => {
102+
const identifier = `${repository.owner.login}-${repository.name}`
103+
const alreadyAdded = uniqueIdentifiers.has(identifier)
104+
uniqueIdentifiers.add(identifier)
105+
return !alreadyAdded
99106
})
100-
)
101-
.then((e) => e.flat())
102-
.then((repositories) => {
103-
// GitHub's search API does not enable searching for repositories whose name ends with "-openapi",
104-
// only repositories whose names include "openapi" so we filter the results ourselves.
105-
return repositories.filter((repository) => {
106-
return repository.name.endsWith(this.repositoryNameSuffix);
107-
});
108-
})
109-
.then((repositories) => {
110-
// Ensure we don't have duplicates in the resulting repositories.
111-
const uniqueIdentifiers = new Set<string>();
112-
return repositories.filter((repository) => {
113-
const identifier = `${repository.owner.login}-${repository.name}`;
114-
const alreadyAdded = uniqueIdentifiers.has(identifier);
115-
uniqueIdentifiers.add(identifier);
116-
return !alreadyAdded;
117-
});
118-
})
119-
.then(async (repositories) => {
120-
// Fetch PRs for all repositories in a single query
121-
const allPullRequests = await this.getOpenPullRequestsForRepositories(
122-
repositories.map((repo) => ({
123-
owner: repo.owner.login,
124-
name: repo.name,
125-
}))
126-
);
107+
})
108+
.then(async repositories => {
109+
// Fetch PRs for all repositories in a single query
110+
const allPullRequests = await this.getOpenPullRequestsForRepositories(
111+
repositories.map(repo => ({
112+
owner: repo.owner.login,
113+
name: repo.name
114+
}))
115+
)
127116

128-
// Map from the internal model to the public model.
129-
return repositories.map((repository) => {
130-
const repoKey = `${repository.owner.login}/${repository.name}`;
131-
const pullRequests = allPullRequests.get(repoKey) || new Map();
117+
// Map from the internal model to the public model.
118+
return repositories.map(repository => {
119+
const repoKey = `${repository.owner.login}/${repository.name}`
120+
const pullRequests = allPullRequests.get(repoKey) || new Map()
132121

133-
const branches = repository.branches.edges.map((branch) => {
134-
const pr = pullRequests.get(branch.node.name);
122+
const branches = repository.branches.edges.map(branch => {
123+
const pr = pullRequests.get(branch.node.name)
135124

125+
return {
126+
id: branch.node.target.oid,
127+
name: branch.node.name,
128+
baseRef: pr?.baseRefName,
129+
baseRefOid: pr?.baseRefOid,
130+
files: branch.node.target.tree.entries
131+
}
132+
})
133+
134+
return {
135+
name: repository.name,
136+
owner: repository.owner.login,
137+
defaultBranchRef: {
138+
id: repository.defaultBranchRef.target.oid,
139+
name: repository.defaultBranchRef.name
140+
},
141+
configYml: repository.configYml,
142+
configYaml: repository.configYaml,
143+
branches: branches,
144+
tags: repository.tags.edges.map(branch => {
136145
return {
137146
id: branch.node.target.oid,
138147
name: branch.node.name,
139-
baseRef: pr?.baseRefName,
140-
baseRefOid: pr?.baseRefOid,
141-
files: branch.node.target.tree.entries,
142-
};
143-
});
144-
145-
return {
146-
name: repository.name,
147-
owner: repository.owner.login,
148-
defaultBranchRef: {
149-
id: repository.defaultBranchRef.target.oid,
150-
name: repository.defaultBranchRef.name,
151-
},
152-
configYml: repository.configYml,
153-
configYaml: repository.configYaml,
154-
branches: branches,
155-
tags: repository.tags.edges.map((branch) => {
156-
return {
157-
id: branch.node.target.oid,
158-
name: branch.node.name,
159-
files: branch.node.target.tree.entries,
160-
};
161-
}),
162-
};
163-
});
164-
});
148+
files: branch.node.target.tree.entries
149+
}
150+
})
151+
}
152+
})
153+
})
165154
}
166-
155+
167156
private async getOpenPullRequestsForRepositories(
168-
repositories: Array<{ owner: string; name: string }>
157+
repositories: Array<{ owner: string, name: string }>
169158
): Promise<Map<string, Map<string, GraphQLPullRequest>>> {
170159
if (repositories.length === 0) {
171-
return new Map();
160+
return new Map()
172161
}
173162

174163
// Build a query that fetches PRs for all repositories
@@ -185,52 +174,51 @@ export default class GitHubProjectDataSource
185174
}
186175
}
187176
}
188-
}`;
177+
}`
189178
})
190-
.join("\n");
179+
.join("\n")
191180

192181
const request = {
193182
query: `
194183
query PullRequests {
195184
${repoQueries}
196185
}
197186
`,
198-
variables: {},
199-
};
187+
variables: {}
188+
}
200189

201-
const response = await this.graphQlClient.graphql(request);
202-
const allPullRequests = new Map<string, Map<string, GraphQLPullRequest>>();
190+
const response = await this.graphQlClient.graphql(request)
191+
const allPullRequests = new Map<string, Map<string, GraphQLPullRequest>>()
203192

204193
repositories.forEach((repo, index) => {
205-
const repoKey = `${repo.owner}/${repo.name}`;
206-
const repoData = response[`repo${index}`];
207-
const pullRequests = new Map<string, GraphQLPullRequest>();
194+
const repoKey = `${repo.owner}/${repo.name}`
195+
const repoData = response[`repo${index}`]
196+
const pullRequests = new Map<string, GraphQLPullRequest>()
208197

209198
if (repoData?.pullRequests?.edges) {
210-
const pullRequestEdges =
211-
repoData.pullRequests.edges as Edge<GraphQLPullRequest>[];
199+
const pullRequestEdges = repoData.pullRequests.edges as Edge<GraphQLPullRequest>[]
212200

213-
pullRequestEdges.forEach((edge) => {
214-
const pr = edge.node;
201+
pullRequestEdges.forEach(edge => {
202+
const pr = edge.node
215203
pullRequests.set(pr.headRefName, {
216204
headRefName: pr.headRefName,
217205
baseRefName: pr.baseRefName,
218-
baseRefOid: pr.baseRefOid,
219-
});
220-
});
206+
baseRefOid: pr.baseRefOid
207+
})
208+
})
221209
}
222210

223-
allPullRequests.set(repoKey, pullRequests);
224-
});
211+
allPullRequests.set(repoKey, pullRequests)
212+
})
225213

226-
return allPullRequests;
214+
return allPullRequests
227215
}
228-
216+
229217
private async getRepositoriesForSearchQuery(params: {
230-
searchQuery: string;
231-
cursor?: string;
218+
searchQuery: string,
219+
cursor?: string
232220
}): Promise<GraphQLGitHubRepository[]> {
233-
const { searchQuery, cursor } = params;
221+
const { searchQuery, cursor } = params
234222
const request = {
235223
query: `
236224
query Repositories($searchQuery: String!, $cursor: String) {
@@ -298,23 +286,23 @@ export default class GitHubProjectDataSource
298286
}
299287
}
300288
`,
301-
variables: { searchQuery, cursor },
302-
};
303-
const response = await this.graphQlClient.graphql(request);
289+
variables: { searchQuery, cursor }
290+
}
291+
const response = await this.graphQlClient.graphql(request)
304292
if (!response.search || !response.search.results) {
305-
return [];
293+
return []
306294
}
307-
const pageInfo = response.search.pageInfo;
295+
const pageInfo = response.search.pageInfo
308296
if (!pageInfo) {
309-
return response.search.results;
297+
return response.search.results
310298
}
311299
if (!pageInfo.hasNextPage || !pageInfo.endCursor) {
312-
return response.search.results;
300+
return response.search.results
313301
}
314302
const nextResults = await this.getRepositoriesForSearchQuery({
315303
searchQuery,
316-
cursor: pageInfo.endCursor,
317-
});
318-
return response.search.results.concat(nextResults);
304+
cursor: pageInfo.endCursor
305+
})
306+
return response.search.results.concat(nextResults)
319307
}
320308
}

0 commit comments

Comments
 (0)