Skip to content

Commit

Permalink
Merge branch 'feature/filter-repositories' into enhancement/adds-avat…
Browse files Browse the repository at this point in the history
…ars-to-logins
  • Loading branch information
simonbs committed Jul 25, 2024
2 parents 5bb7627 + 00910cc commit 724e63d
Show file tree
Hide file tree
Showing 8 changed files with 209 additions and 7 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ POSTGRESQL_USER=dbuser
POSTGRESQL_PASSWORD=
POSTGRESQL_DB=shape-docs
REPOSITORY_NAME_SUFFIX=-openapi
HIDDEN_REPOSITORIES=
GITHUB_WEBHOOK_SECRET=preshared secret also put in app configuration in GitHub
GITHUB_WEBHOK_REPOSITORY_ALLOWLIST=
GITHUB_WEBHOK_REPOSITORY_DISALLOWLIST=
Expand Down
125 changes: 125 additions & 0 deletions __test__/projects/FilteringGitHubRepositoryDataSource.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { FilteringGitHubRepositoryDataSource } from "../../src/features/projects/domain"

test("It returns all repositories when no hidden repositories are provided", async () => {
const sut = new FilteringGitHubRepositoryDataSource({
hiddenRepositories: [],
dataSource: {
async getRepositories() {
return [{
owner: "acme",
name: "foo-openapi",
defaultBranchRef: {
id: "12345678",
name: "main"
},
branches: [],
tags: []
}, {
owner: "acme",
name: "bar-openapi",
defaultBranchRef: {
id: "12345678",
name: "bar"
},
branches: [],
tags: []
}]
}
}
})
const repositories = await sut.getRepositories()
expect(repositories.length).toEqual(2)
})

test("It removes hidden repository", async () => {
const sut = new FilteringGitHubRepositoryDataSource({
hiddenRepositories: ["acme/foo-openapi"],
dataSource: {
async getRepositories() {
return [{
owner: "acme",
name: "foo-openapi",
defaultBranchRef: {
id: "12345678",
name: "main"
},
branches: [],
tags: []
}, {
owner: "acme",
name: "bar-openapi",
defaultBranchRef: {
id: "12345678",
name: "bar"
},
branches: [],
tags: []
}]
}
}
})
const repositories = await sut.getRepositories()
expect(repositories.length).toEqual(1)
})

test("It returns unmodified list when hidden repository was not found", async () => {
const sut = new FilteringGitHubRepositoryDataSource({
hiddenRepositories: ["acme/baz-openapi"],
dataSource: {
async getRepositories() {
return [{
owner: "acme",
name: "foo-openapi",
defaultBranchRef: {
id: "12345678",
name: "main"
},
branches: [],
tags: []
}, {
owner: "acme",
name: "bar-openapi",
defaultBranchRef: {
id: "12345678",
name: "bar"
},
branches: [],
tags: []
}]
}
}
})
const repositories = await sut.getRepositories()
expect(repositories.length).toEqual(2)
})

test("It removes multiple hidden repositories", async () => {
const sut = new FilteringGitHubRepositoryDataSource({
hiddenRepositories: ["acme/foo-openapi", "acme/bar-openapi"],
dataSource: {
async getRepositories() {
return [{
owner: "acme",
name: "foo-openapi",
defaultBranchRef: {
id: "12345678",
name: "main"
},
branches: [],
tags: []
}, {
owner: "acme",
name: "bar-openapi",
defaultBranchRef: {
id: "12345678",
name: "bar"
},
branches: [],
tags: []
}]
}
}
})
const repositories = await sut.getRepositories()
expect(repositories.length).toEqual(0)
})
26 changes: 26 additions & 0 deletions __test__/utils/splitOwnerAndRepository.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { splitOwnerAndRepository } from "@/common"

test("It returns undefined when string includes no slash", async () => {
const result = splitOwnerAndRepository("foo")
expect(result).toBeUndefined()
})

test("It returns undefined when repository is empty", async () => {
const result = splitOwnerAndRepository("foo/")
expect(result).toBeUndefined()
})

test("It returns undefined when owner is empty", async () => {
const result = splitOwnerAndRepository("/foo")
expect(result).toBeUndefined()
})

test("It splits owner and repository", async () => {
const result = splitOwnerAndRepository("acme/foo")
expect(result).toEqual({ owner: "acme", repository: "foo" })
})

test("It splits owner and repository for repository name containing a slash", async () => {
const result = splitOwnerAndRepository("acme/foo/bar")
expect(result).toEqual({ owner: "acme", repository: "foo/bar" })
})
1 change: 1 addition & 0 deletions src/common/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export { default as env } from "./env"
export { default as getBaseFilename } from "./getBaseFilename"
export { default as isMac } from "./isMac"
export { default as useKeyboardShortcut } from "./useKeyboardShortcut"
export { default as splitOwnerAndRepository } from "./splitOwnerAndRepository"
14 changes: 14 additions & 0 deletions src/common/utils/splitOwnerAndRepository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Split full repository names into owner and repository.
// shapehq/foo becomes { owner: "shapehq", "repository": "foo" }
export default (str: string) => {
const index = str.indexOf("/")
if (index === -1) {
return undefined
}
const owner = str.substring(0, index)
const repository = str.substring(index + 1)
if (owner.length == 0 || repository.length == 0) {
return undefined
}
return { owner, repository }
}
18 changes: 11 additions & 7 deletions src/composition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
} from "@/features/projects/data"
import {
CachingProjectDataSource,
FilteringGitHubRepositoryDataSource,
ProjectRepository
} from "@/features/projects/domain"
import {
Expand Down Expand Up @@ -158,13 +159,16 @@ export const projectRepository = new ProjectRepository({

export const projectDataSource = new CachingProjectDataSource({
dataSource: new GitHubProjectDataSource({
repositoryDataSource: new GitHubRepositoryDataSource({
loginsDataSource: new GitHubLoginDataSource({
graphQlClient: userGitHubClient
}),
graphQlClient: userGitHubClient,
repositoryNameSuffix: env.getOrThrow("REPOSITORY_NAME_SUFFIX"),
projectConfigurationFilename: env.getOrThrow("SHAPE_DOCS_PROJECT_CONFIGURATION_FILENAME")
repositoryDataSource: new FilteringGitHubRepositoryDataSource({
hiddenRepositories: listFromCommaSeparatedString(env.get("HIDDEN_REPOSITORIES")),
dataSource: new GitHubRepositoryDataSource({
loginsDataSource: new GitHubLoginDataSource({
graphQlClient: userGitHubClient
}),
graphQlClient: userGitHubClient,
repositoryNameSuffix: env.getOrThrow("REPOSITORY_NAME_SUFFIX"),
projectConfigurationFilename: env.getOrThrow("SHAPE_DOCS_PROJECT_CONFIGURATION_FILENAME")
})
}),
repositoryNameSuffix: env.getOrThrow("REPOSITORY_NAME_SUFFIX")
}),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import IGitHubRepositoryDataSource, {
GitHubRepository
} from "./IGitHubRepositoryDataSource"
import { splitOwnerAndRepository } from "@/common"

export default class FilteringGitHubRepositoryDataSource implements IGitHubRepositoryDataSource {
private readonly dataSource: IGitHubRepositoryDataSource
private readonly hiddenRepositories: string[]

constructor(config: {
dataSource: IGitHubRepositoryDataSource,
hiddenRepositories: string[]
}) {
this.dataSource = config.dataSource
this.hiddenRepositories = config.hiddenRepositories
}

async getRepositories(): Promise<GitHubRepository[]> {
const repositories = await this.dataSource.getRepositories()
const hiddenOwnerAndRepoNameList = this.hiddenRepositories
.map(splitOwnerAndRepository)
.filter(e => e !== undefined)
return repositories.filter(repository => {
const hiddenMatch = hiddenOwnerAndRepoNameList.find(e =>
e.owner == repository.owner && e.repository == repository.name
)
return hiddenMatch === undefined
})
}
}
1 change: 1 addition & 0 deletions src/features/projects/domain/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { default as CachingProjectDataSource } from "./CachingProjectDataSource"
export { default as FilteringGitHubRepositoryDataSource } from "./FilteringGitHubRepositoryDataSource"
export { default as getSelection } from "./getSelection"
export type { default as IGitHubLoginDataSource } from "./IGitHubLoginDataSource"
export type { default as IGitHubRepositoryDataSource } from "./IGitHubRepositoryDataSource"
Expand Down

0 comments on commit 724e63d

Please sign in to comment.