Skip to content

Commit

Permalink
Add new API client to consolidate REST API calls
Browse files Browse the repository at this point in the history
  • Loading branch information
James M. Greene authored and James M. Greene committed Aug 3, 2022
1 parent 0455a16 commit bb42d7b
Show file tree
Hide file tree
Showing 2 changed files with 286 additions and 0 deletions.
87 changes: 87 additions & 0 deletions src/api-client.js
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 }
199 changes: 199 additions & 0 deletions src/api-client.test.js
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)
})
})

})

0 comments on commit bb42d7b

Please sign in to comment.