Skip to content

Commit

Permalink
feat: Add GitHub Integration (#3298)
Browse files Browse the repository at this point in the history
  • Loading branch information
novakzaballa authored Apr 24, 2024
1 parent ecb1022 commit 9aa72bd
Show file tree
Hide file tree
Showing 31 changed files with 1,978 additions and 49 deletions.
8 changes: 8 additions & 0 deletions docs/docs/integrations/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,14 @@ Manage your Flagsmith Change Requests inside ServiceNow. [Learn more](/integrati
You can integrate Flagsmith with Slack. Send flag change events from Flagsmith into your Slack channels.
[Learn more](/integrations/project-management/slack).

---

<a href="/integrations/project-management/github" alt="GitHub"><img width="30%" src="/img/integrations/github/github-logo.svg"/></a>

View your Flagsmith flags inside GitHub Issues and Pull Request. [Learn more](/integrations/project-management/github).

---

## Authentication Providers / IDPs

### OAuth
Expand Down
50 changes: 50 additions & 0 deletions docs/docs/integrations/project-management/github.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
title: GitHub
description: View your Flagsmith flags inside GitHub
sidebar_position: 10
hide_title: true
---

<img src="/img/integrations/github/github-logo.svg" alt="GitHub Logo" width="30%" height="30%"/>

View your Flagsmith Flags inside your GitHub Issues and Pull Request

:::tip

- The GitHub integration is currently only supported with our hosted Flagsmith SaaS service.

:::

## Integration Setup

### From Flagsmith

1. In the Integrations Option in the side bar, find the GitHub integration and click on 'Add Integration'.
2. A window will open asking you to select an organization you belong to.
3. Select the repositories and save.
4. In the Flagsmith application, the button will now say "Manage Integration", click on it.
5. Finally, select the repository you wish to link.

### From github

1. In GitHub, add the app from the [GitHub Marketplace](https://github.com/apps/flagsmith-github-integration).
2. Select your organisation.
3. Select your repositories where you want install the app.
4. You will be redirected back to the Flagsmith app to finish the integration setup.
5. Select your Flagsmith Organisation.
6. Select the Flagmsith Project you want to associate with the repository where the app was installed to create the
Integration.

## Adding a Flagsmith Flag to a GitHub issue or pull request

1. Create or select a Feature Flag.
2. Go to settings section.
3. Select your integration.
4. Select GitHub Issue or GitHub PR.
5. Select your external resource and save.

## Delete GitHub Integration

1. In the Integrations Option in the side bar, find the GitHub integration and click on 'Manage Integration'.
2. Click on 'Delete Integracion' button, and confirm.
3. In your Github organisation, uninstall the Flagsmith GitHub App.
48 changes: 48 additions & 0 deletions docs/static/img/integrations/github/github-logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
98 changes: 98 additions & 0 deletions frontend/common/services/useExternalResource.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { Res } from 'common/types/responses'
import { Req } from 'common/types/requests'
import { service } from 'common/service'

export const externalResourceService = service
.enhanceEndpoints({ addTagTypes: ['ExternalResource'] })
.injectEndpoints({
endpoints: (builder) => ({
createExternalResource: builder.mutation<
Res['externalResource'],
Req['createExternalResource']
>({
invalidatesTags: [{ id: 'LIST', type: 'ExternalResource' }],
query: (query: Req['createExternalResource']) => ({
body: query.body,
method: 'POST',
url: `projects/${query.project_id}/features/${query.feature_id}/feature-external-resources/`,
}),
}),
deleteExternalResource: builder.mutation<
Res['externalResource'],
Req['deleteExternalResource']
>({
invalidatesTags: [{ id: 'LIST', type: 'ExternalResource' }],
query: (query: Req['deleteExternalResource']) => ({
method: 'DELETE',
url: `projects/${query.project_id}/features/${query.feature_id}/feature-external-resources/${query.external_resource_id}/`,
}),
}),
getExternalResources: builder.query<
Res['externalResource'],
Req['getExternalResources']
>({
providesTags: [{ id: 'LIST', type: 'ExternalResource' }],
query: (query: Req['getExternalResources']) => ({
url: `projects/${query.project_id}/features/${query.feature_id}/feature-external-resources/`,
}),
}),
// END OF ENDPOINTS
}),
})

export async function createExternalResource(
store: any,
data: Req['createExternalResource'],
options?: Parameters<
typeof externalResourceService.endpoints.createExternalResource.initiate
>[1],
) {
return store.dispatch(
externalResourceService.endpoints.createExternalResource.initiate(
data,
options,
),
)
}
export async function deleteExternalResource(
store: any,
data: Req['deleteExternalResource'],
options?: Parameters<
typeof externalResourceService.endpoints.deleteExternalResource.initiate
>[1],
) {
return store.dispatch(
externalResourceService.endpoints.deleteExternalResource.initiate(
data,
options,
),
)
}
export async function getExternalResources(
store: any,
data: Req['getExternalResources'],
options?: Parameters<
typeof externalResourceService.endpoints.getExternalResources.initiate
>[1],
) {
return store.dispatch(
externalResourceService.endpoints.getExternalResources.initiate(
data,
options,
),
)
}
// END OF FUNCTION_EXPORTS

export const {
useCreateExternalResourceMutation,
useDeleteExternalResourceMutation,
useGetExternalResourcesQuery,
// END OF EXPORTS
} = externalResourceService

/* Usage examples:
const { data, isLoading } = useGetExternalResourceQuery({ id: 2 }, {}) //get hook
const [createExternalResource, { isLoading, data, isSuccess }] = useCreateExternalResourceMutation() //create hook
externalResourceService.endpoints.getExternalResources.select({id: 2})(store.getState()) //access data from any function
*/
85 changes: 85 additions & 0 deletions frontend/common/services/useGithub.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { Res } from 'common/types/responses'
import { Req } from 'common/types/requests'
import { service } from 'common/service'
import Utils from 'common/utils/utils'

export const githubService = service
.enhanceEndpoints({ addTagTypes: ['Github'] })
.injectEndpoints({
endpoints: (builder) => ({
getGithubIssues: builder.query<
Res['githubIssues'],
Req['getGithubIssues']
>({
providesTags: [{ id: 'LIST', type: 'Github' }],
query: (query: Req['getGithubIssues']) => ({
url: `organisations/${query.organisation_id}/github/issues/?repo_name=${query.repo_name}&repo_owner=${query.repo_owner}`,
}),
}),
getGithubPulls: builder.query<Res['githubPulls'], Req['getGithubPulls']>({
providesTags: [{ id: 'LIST', type: 'Github' }],
query: (query: Req['getGithubPulls']) => ({
url: `organisations/${query.organisation_id}/github/pulls/?repo_name=${query.repo_name}&repo_owner=${query.repo_owner}`,
}),
}),
getGithubRepos: builder.query<Res['githubRepos'], Req['getGithubRepos']>({
providesTags: [{ id: 'LIST', type: 'Github' }],
query: (query: Req['getGithubRepos']) => ({
url: `organisations/${
query.organisation_id
}/github/repositories/?${Utils.toParam({
installation_id: query.installation_id,
})}`,
}),
}),
// END OF ENDPOINTS
}),
})

export async function getGithubIssues(
store: any,
data: Req['getGithubIssues'],
options?: Parameters<
typeof githubService.endpoints.getGithubIssues.initiate
>[1],
) {
return store.dispatch(
githubService.endpoints.getGithubIssues.initiate(data, options),
)
}
export async function getGithubPulls(
store: any,
data: Req['getGithubPulls'],
options?: Parameters<
typeof githubService.endpoints.getGithubPulls.initiate
>[1],
) {
return store.dispatch(
githubService.endpoints.getGithubPulls.initiate(data, options),
)
}
export async function getGithubRepos(
store: any,
data: Req['getGithubRepos'],
options?: Parameters<
typeof githubService.endpoints.getGithubRepos.initiate
>[1],
) {
return store.dispatch(
githubService.endpoints.getGithubRepos.initiate(data, options),
)
}
// END OF FUNCTION_EXPORTS

export const {
useGetGithubIssuesQuery,
useGetGithubPullsQuery,
useGetGithubReposQuery,
// END OF EXPORTS
} = githubService

/* Usage examples:
const { data, isLoading } = useGetGithubIssuesQuery({ id: 2 }, {}) //get hook
const [createGithub, { isLoading, data, isSuccess }] = useCreateGithubMutation() //create hook
githubService.endpoints.getGithub.select({id: 2})(store.getState()) //access data from any function
*/
Loading

0 comments on commit 9aa72bd

Please sign in to comment.