-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add new API client to consolidate REST API calls
- Loading branch information
James M. Greene
authored and
James M. Greene
committed
Aug 3, 2022
1 parent
0455a16
commit bb42d7b
Showing
2 changed files
with
286 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| const axios = require('axios') | ||
| const core = require('@actions/core') | ||
|
|
||
| async function enablePagesSite({ repositoryNwo, githubToken }) { | ||
| const pagesEndpoint = `https://api.github.com/repos/${repositoryNwo}/pages` | ||
|
|
||
| try { | ||
| const response = await axios.post( | ||
| pagesEndpoint, | ||
| { build_type: 'workflow' }, | ||
| { | ||
| headers: { | ||
| Accept: 'application/vnd.github.v3+json', | ||
| Authorization: `Bearer ${githubToken}`, | ||
| 'Content-type': 'application/json' | ||
| } | ||
| } | ||
| ) | ||
|
|
||
| const pageObject = response.data | ||
| return pageObject | ||
| } catch (error) { | ||
| if (error.response && error.response.status === 409) { | ||
| return null | ||
| } | ||
|
|
||
| throw error | ||
| } | ||
| } | ||
|
|
||
| async function getPagesSite({ repositoryNwo, githubToken }) { | ||
| try { | ||
| const pagesEndpoint = `https://api.github.com/repos/${repositoryNwo}/pages` | ||
|
|
||
| const response = await axios.get(pagesEndpoint, { | ||
| headers: { | ||
| Accept: 'application/vnd.github.v3+json', | ||
| Authorization: `Bearer ${githubToken}` | ||
| } | ||
| }) | ||
|
|
||
| const pageObject = response.data | ||
| return pageObject | ||
| } catch (error) { | ||
| throw error | ||
| } | ||
| } | ||
|
|
||
| async function findOrCreatePagesSite({ repositoryNwo, githubToken, enablement = true }) { | ||
| let pageObject | ||
|
|
||
| // Try to find an existing Pages site first | ||
| try { | ||
| pageObject = await getPagesSite({ repositoryNwo, githubToken }) | ||
| } catch (error) { | ||
| if (!enablement) { | ||
| core.error('Get Pages site failed', error) | ||
| throw error | ||
| } | ||
| core.warning('Get Pages site failed', error) | ||
| } | ||
|
|
||
| if (!pageObject && enablement) { | ||
| // Create a new Pages site if one doesn't exist | ||
| try { | ||
| pageObject = await enablePagesSite({ repositoryNwo, githubToken }) | ||
| } catch (error) { | ||
| core.error('Create Pages site failed', error) | ||
| throw error | ||
| } | ||
|
|
||
| // This somehow implies that the Pages site was already created but initially failed to be retrieved. | ||
| // Try one more time for this extreme edge case! | ||
| if (pageObject == null) { | ||
| try { | ||
| pageObject = await getPagesSite({ repositoryNwo, githubToken }) | ||
| } catch (error) { | ||
| core.error('Get Pages site still failed', error) | ||
| throw error | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return pageObject | ||
| } | ||
|
|
||
| module.exports = { findOrCreatePagesSite, enablePagesSite, getPagesSite } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,199 @@ | ||
| const core = require('@actions/core') | ||
| const axios = require('axios') | ||
|
|
||
| const apiClient = require('./api-client') | ||
|
|
||
| describe('apiClient', () => { | ||
| const GITHUB_REPOSITORY = 'paper-spa/is-awesome' | ||
| const GITHUB_TOKEN = 'gha-token' | ||
|
|
||
| beforeEach(() => { | ||
| jest.restoreAllMocks() | ||
|
|
||
| // Mock error/warning/info/debug | ||
| jest.spyOn(core, 'error').mockImplementation(jest.fn()) | ||
| jest.spyOn(core, 'warning').mockImplementation(jest.fn()) | ||
| jest.spyOn(core, 'info').mockImplementation(jest.fn()) | ||
| jest.spyOn(core, 'debug').mockImplementation(jest.fn()) | ||
| }) | ||
|
|
||
|
|
||
| describe('enablePagesSite', () => { | ||
| it('makes a request to create a page', async () => { | ||
| const pageObject = { html_url: 'https://paper-spa.github.io/is-awesome/' } | ||
| jest.spyOn(axios, 'post').mockImplementationOnce(() => Promise.resolve({ status: 201, data: pageObject })) | ||
|
|
||
| const result = await apiClient.enablePagesSite({ | ||
| repositoryNwo: GITHUB_REPOSITORY, | ||
| githubToken: GITHUB_TOKEN | ||
| }) | ||
| expect(result).toEqual(pageObject) | ||
| }) | ||
|
|
||
| it('handles a 409 response when the page already exists', async () => { | ||
| jest | ||
| .spyOn(axios, 'post') | ||
| .mockImplementationOnce(() => Promise.reject({ response: { status: 409 } })) | ||
|
|
||
| // Simply assert that no error is raised | ||
| const result = await apiClient.enablePagesSite({ | ||
| repositoryNwo: GITHUB_REPOSITORY, | ||
| githubToken: GITHUB_TOKEN | ||
| }) | ||
|
|
||
| expect(result).toBe(null) | ||
| }) | ||
|
|
||
| it('re-raises errors on failure status codes', async () => { | ||
| jest | ||
| .spyOn(axios, 'post') | ||
| .mockImplementationOnce(() => Promise.reject({ response: { status: 404 } })) | ||
|
|
||
| let erred = false | ||
| try { | ||
| await apiClient.enablePagesSite({ | ||
| repositoryNwo: GITHUB_REPOSITORY, | ||
| githubToken: GITHUB_TOKEN | ||
| }) | ||
| } catch (error) { | ||
| erred = true | ||
| expect(error.response.status).toEqual(404) | ||
| } | ||
| expect(erred).toBe(true) | ||
| }) | ||
| }) | ||
|
|
||
| describe('getPagesSite', () => { | ||
| it('makes a request to get a page', async () => { | ||
| const pageObject = { html_url: 'https://paper-spa.github.io/is-awesome/' } | ||
| jest.spyOn(axios, 'get').mockImplementationOnce(() => Promise.resolve({ status: 200, data: pageObject })) | ||
|
|
||
| const result = await apiClient.getPagesSite({ | ||
| repositoryNwo: GITHUB_REPOSITORY, | ||
| githubToken: GITHUB_TOKEN | ||
| }) | ||
| expect(result).toEqual(pageObject) | ||
| }) | ||
|
|
||
| it('re-raises errors on failure status codes', async () => { | ||
| jest | ||
| .spyOn(axios, 'get') | ||
| .mockImplementationOnce(() => Promise.reject({ response: { status: 404 } })) | ||
|
|
||
| let erred = false | ||
| try { | ||
| await apiClient.getPagesSite({ | ||
| repositoryNwo: GITHUB_REPOSITORY, | ||
| githubToken: GITHUB_TOKEN | ||
| }) | ||
| } catch (error) { | ||
| erred = true | ||
| expect(error.response.status).toEqual(404) | ||
| } | ||
| expect(erred).toBe(true) | ||
| }) | ||
| }) | ||
|
|
||
| describe('findOrCreatePagesSite', () => { | ||
| it('does not make a request to create a page if it already exists', async () => { | ||
| const pageObject = { html_url: 'https://paper-spa.github.io/is-awesome/' } | ||
| jest.spyOn(axios, 'get').mockImplementationOnce(() => Promise.resolve({ status: 200, data: pageObject })) | ||
| jest.spyOn(axios, 'post').mockImplementationOnce(() => Promise.reject({ response: { status: 404 } })) | ||
|
|
||
| const result = await apiClient.findOrCreatePagesSite({ | ||
| repositoryNwo: GITHUB_REPOSITORY, | ||
| githubToken: GITHUB_TOKEN | ||
| }) | ||
| expect(result).toEqual(pageObject) | ||
| expect(axios.get).toHaveBeenCalledTimes(1) | ||
| expect(axios.post).toHaveBeenCalledTimes(0) | ||
| }) | ||
|
|
||
| it('makes request to create a page by default if it does not exist', async () => { | ||
| const pageObject = { html_url: 'https://paper-spa.github.io/is-awesome/' } | ||
| jest.spyOn(axios, 'get').mockImplementationOnce(() => Promise.reject({ response: { status: 404 } })) | ||
| jest.spyOn(axios, 'post').mockImplementationOnce(() => Promise.resolve({ status: 201, data: pageObject })) | ||
|
|
||
| const result = await apiClient.findOrCreatePagesSite({ | ||
| repositoryNwo: GITHUB_REPOSITORY, | ||
| githubToken: GITHUB_TOKEN | ||
| }) | ||
| expect(result).toEqual(pageObject) | ||
| expect(axios.get).toHaveBeenCalledTimes(1) | ||
| expect(axios.post).toHaveBeenCalledTimes(1) | ||
| }) | ||
|
|
||
| it('makes a request to create a page when explicitly enabled if it does not exist', async () => { | ||
| const pageObject = { html_url: 'https://paper-spa.github.io/is-awesome/' } | ||
| jest.spyOn(axios, 'get').mockImplementationOnce(() => Promise.reject({ response: { status: 404 } })) | ||
| jest.spyOn(axios, 'post').mockImplementationOnce(() => Promise.resolve({ status: 201, data: pageObject })) | ||
|
|
||
| const result = await apiClient.findOrCreatePagesSite({ | ||
| repositoryNwo: GITHUB_REPOSITORY, | ||
| githubToken: GITHUB_TOKEN, | ||
| enablement: true | ||
| }) | ||
| expect(result).toEqual(pageObject) | ||
| expect(axios.get).toHaveBeenCalledTimes(1) | ||
| expect(axios.post).toHaveBeenCalledTimes(1) | ||
| }) | ||
|
|
||
| it('does not make a request to create a page when explicitly disabled even if it does not exist', async () => { | ||
| jest.spyOn(axios, 'get').mockImplementationOnce(() => Promise.reject({ response: { status: 404 } })) | ||
| jest.spyOn(axios, 'post').mockImplementationOnce(() => Promise.reject({ response: { status: 500 } })) // just so they both aren't 404 | ||
|
|
||
| let erred = false | ||
| try { | ||
| await apiClient.findOrCreatePagesSite({ | ||
| repositoryNwo: GITHUB_REPOSITORY, | ||
| githubToken: GITHUB_TOKEN, | ||
| enablement: false | ||
| }) | ||
| } catch (error) { | ||
| erred = true | ||
| // re-raised error | ||
| expect(error.response.status).toEqual(404) | ||
| } | ||
| expect(erred).toBe(true) | ||
| expect(axios.get).toHaveBeenCalledTimes(1) | ||
| expect(axios.post).toHaveBeenCalledTimes(0) | ||
| }) | ||
|
|
||
| it('does not make a second request to get page if create fails for reason other than existence', async () => { | ||
| jest.spyOn(axios, 'get').mockImplementationOnce(() => Promise.reject({ response: { status: 404 } })) | ||
| jest.spyOn(axios, 'post').mockImplementationOnce(() => Promise.reject({ response: { status: 500 } })) // just so they both aren't 404 | ||
|
|
||
| let erred = false | ||
| try { | ||
| await apiClient.findOrCreatePagesSite({ | ||
| repositoryNwo: GITHUB_REPOSITORY, | ||
| githubToken: GITHUB_TOKEN | ||
| }) | ||
| } catch (error) { | ||
| erred = true | ||
| // re-raised error | ||
| expect(error.response.status).toEqual(500) | ||
| } | ||
| expect(erred).toBe(true) | ||
| expect(axios.get).toHaveBeenCalledTimes(1) | ||
| expect(axios.post).toHaveBeenCalledTimes(1) | ||
| }) | ||
|
|
||
| it('makes second request to get page if create fails because of existence', async () => { | ||
| const pageObject = { html_url: 'https://paper-spa.github.io/is-awesome/' } | ||
| jest.spyOn(axios, 'get') | ||
| .mockImplementationOnce(() => Promise.reject({ response: { status: 404 } })) | ||
| .mockImplementationOnce(() => Promise.resolve({ status: 200, data: pageObject })) | ||
| jest.spyOn(axios, 'post').mockImplementationOnce(() => Promise.reject({ response: { status: 409 } })) | ||
|
|
||
| const result = await apiClient.findOrCreatePagesSite({ | ||
| repositoryNwo: GITHUB_REPOSITORY, | ||
| githubToken: GITHUB_TOKEN | ||
| }) | ||
| expect(result).toEqual(pageObject) | ||
| expect(axios.get).toHaveBeenCalledTimes(2) | ||
| expect(axios.post).toHaveBeenCalledTimes(1) | ||
| }) | ||
| }) | ||
|
|
||
| }) |