Skip to content

Commit 0c9a901

Browse files
authored
Add api url as an optional input (#121)
- api_url added as optional input - tests updated to check for this - updated README with note of new input - Octokit uses api_url
2 parents b16066d + 8d13675 commit 0c9a901

File tree

7 files changed

+171
-5
lines changed

7 files changed

+171
-5
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ jobs:
7878
| `labels` | `label1` | **Line-separated** label list |
7979
| `issue_number` | `${{ github.event.issue.number }}` or `${{ github.event.pull_request.number }}` | The issue or PR numer |
8080
| `repository` | `${{ github.repository }}` | The repository (`owner/repo`) |
81+
| `api_url` | `${{ github.api_url }}` | The GitHub API URL to use |
8182

8283
> [!WARNING]
8384
>

__tests__/main.test.ts

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ describe('Invalid Usage', () => {
3131
.mockReturnValueOnce([].join('\n')) // labels
3232
.mockReturnValueOnce('MyAwesomeIssue') // issue_number
3333
.mockReturnValueOnce('issue-ops/invalid-repo') // repository
34+
.mockReturnValueOnce('') // api_url
3435
})
3536

3637
afterEach(() => {
@@ -45,6 +46,7 @@ describe('Invalid Usage', () => {
4546
.mockReturnValueOnce([].join('\n')) // labels
4647
.mockReturnValueOnce('MyAwesomeIssue') // issue_number
4748
.mockReturnValueOnce('issue-ops/invalid-repo') // repository
49+
.mockReturnValueOnce('') // api_url
4850

4951
await main.run()
5052

@@ -53,6 +55,104 @@ describe('Invalid Usage', () => {
5355
})
5456
})
5557

58+
describe('Input Validation', () => {
59+
afterEach(() => {
60+
jest.resetAllMocks()
61+
})
62+
63+
it('Uses default API URL when api_url is empty', async () => {
64+
// Mock the environment variable
65+
const originalGitHubApiUrl = process.env.GITHUB_API_URL
66+
process.env.GITHUB_API_URL = 'https://api.github.com'
67+
68+
core.getInput
69+
.mockReturnValueOnce('add') // action
70+
.mockReturnValueOnce('false') // create
71+
.mockReturnValueOnce('token') // github_token
72+
.mockReturnValueOnce(['test'].join('\n')) // labels
73+
.mockReturnValueOnce('1') // issue_number
74+
.mockReturnValueOnce('issue-ops/labeler') // repository
75+
.mockReturnValueOnce('') // api_url (empty)
76+
77+
await main.run()
78+
79+
expect(core.getInput).toHaveBeenCalledWith('api_url', { required: false })
80+
expect(core.info).toHaveBeenCalledWith(
81+
' - API URL: https://api.github.com'
82+
)
83+
84+
// Restore the original environment variable
85+
if (originalGitHubApiUrl !== undefined) {
86+
process.env.GITHUB_API_URL = originalGitHubApiUrl
87+
} else {
88+
delete process.env.GITHUB_API_URL
89+
}
90+
})
91+
92+
it('Uses GITHUB_API_URL environment variable when api_url is empty', async () => {
93+
// Mock the environment variable to a different value
94+
const originalGitHubApiUrl = process.env.GITHUB_API_URL
95+
process.env.GITHUB_API_URL = 'https://github.enterprise.internal/api/v3'
96+
97+
core.getInput
98+
.mockReturnValueOnce('add') // action
99+
.mockReturnValueOnce('false') // create
100+
.mockReturnValueOnce('token') // github_token
101+
.mockReturnValueOnce(['test'].join('\n')) // labels
102+
.mockReturnValueOnce('1') // issue_number
103+
.mockReturnValueOnce('issue-ops/labeler') // repository
104+
.mockReturnValueOnce('') // api_url (empty)
105+
106+
await main.run()
107+
108+
expect(core.getInput).toHaveBeenCalledWith('api_url', { required: false })
109+
expect(core.info).toHaveBeenCalledWith(
110+
' - API URL: https://github.enterprise.internal/api/v3'
111+
)
112+
113+
// Restore the original environment variable
114+
if (originalGitHubApiUrl !== undefined) {
115+
process.env.GITHUB_API_URL = originalGitHubApiUrl
116+
} else {
117+
delete process.env.GITHUB_API_URL
118+
}
119+
})
120+
121+
it('Uses custom API URL when provided', async () => {
122+
const customApiUrl = 'https://github.enterprise.com/api/v3'
123+
124+
core.getInput
125+
.mockReturnValueOnce('add') // action
126+
.mockReturnValueOnce('false') // create
127+
.mockReturnValueOnce('token') // github_token
128+
.mockReturnValueOnce(['test'].join('\n')) // labels
129+
.mockReturnValueOnce('1') // issue_number
130+
.mockReturnValueOnce('issue-ops/labeler') // repository
131+
.mockReturnValueOnce(customApiUrl) // api_url
132+
133+
await main.run()
134+
135+
expect(core.getInput).toHaveBeenCalledWith('api_url', { required: false })
136+
expect(core.info).toHaveBeenCalledWith(` - API URL: ${customApiUrl}`)
137+
})
138+
139+
it('Handles invalid issue number', async () => {
140+
core.getInput
141+
.mockReturnValueOnce('add') // action
142+
.mockReturnValueOnce('false') // create
143+
.mockReturnValueOnce('token') // github_token
144+
.mockReturnValueOnce(['test'].join('\n')) // labels
145+
.mockReturnValueOnce('not-a-number') // issue_number
146+
.mockReturnValueOnce('issue-ops/labeler') // repository
147+
.mockReturnValueOnce('') // api_url
148+
149+
await main.run()
150+
151+
// The parseInt will result in NaN, which should still be handled
152+
expect(core.info).toHaveBeenCalledWith(' - Issue Number: NaN')
153+
})
154+
})
155+
56156
describe('Add Labels', () => {
57157
beforeEach(() => {
58158
// Set the action's inputs as return values from core.getInput()
@@ -63,6 +163,7 @@ describe('Add Labels', () => {
63163
.mockReturnValueOnce(['bug', 'enhancement'].join('\n')) // labels
64164
.mockReturnValueOnce('1') // issue_number
65165
.mockReturnValueOnce('issue-ops/labeler') // repository
166+
.mockReturnValueOnce('') // api_url
66167
})
67168

68169
afterEach(() => {
@@ -88,6 +189,29 @@ describe('Add Labels', () => {
88189
expect(core.getInput).toHaveReturnedWith('1')
89190
expect(core.getInput).toHaveBeenCalledWith('repository', { required: true })
90191
expect(core.getInput).toHaveReturnedWith('issue-ops/labeler')
192+
expect(core.getInput).toHaveBeenCalledWith('api_url', { required: false })
193+
expect(core.getInput).toHaveReturnedWith('')
194+
})
195+
196+
it('Uses custom API URL when provided', async () => {
197+
// Reset mocks and set up new inputs
198+
jest.resetAllMocks()
199+
200+
core.getInput
201+
.mockReturnValueOnce('add') // action
202+
.mockReturnValueOnce('true') // create
203+
.mockReturnValueOnce('token') // github_token
204+
.mockReturnValueOnce(['bug'].join('\n')) // labels
205+
.mockReturnValueOnce('1') // issue_number
206+
.mockReturnValueOnce('issue-ops/labeler') // repository
207+
.mockReturnValueOnce('https://github.enterprise.com/api/v3') // api_url
208+
209+
await main.run()
210+
211+
expect(core.getInput).toHaveBeenCalledWith('api_url', { required: false })
212+
expect(core.info).toHaveBeenCalledWith(
213+
' - API URL: https://github.enterprise.com/api/v3'
214+
)
91215
})
92216

93217
it('Fails on GitHub API error', async () => {
@@ -130,6 +254,35 @@ describe('Add Labels', () => {
130254
repo: 'labeler'
131255
})
132256
})
257+
258+
it('Does not create labels when create is false', async () => {
259+
// Reset mocks and set up new inputs
260+
jest.resetAllMocks()
261+
262+
core.getInput
263+
.mockReturnValueOnce('add') // action
264+
.mockReturnValueOnce('false') // create
265+
.mockReturnValueOnce('token') // github_token
266+
.mockReturnValueOnce(['nonexistent-label'].join('\n')) // labels
267+
.mockReturnValueOnce('1') // issue_number
268+
.mockReturnValueOnce('issue-ops/labeler') // repository
269+
.mockReturnValueOnce('') // api_url
270+
271+
mocktokit.rest.issues.getLabel.mockRejectedValue({
272+
status: 404,
273+
message: 'Not found'
274+
})
275+
276+
await main.run()
277+
278+
expect(mocktokit.rest.issues.createLabel).not.toHaveBeenCalled()
279+
expect(mocktokit.rest.issues.addLabels).toHaveBeenCalledWith({
280+
issue_number: 1,
281+
labels: ['nonexistent-label'],
282+
owner: 'issue-ops',
283+
repo: 'labeler'
284+
})
285+
})
133286
})
134287

135288
describe('Remove Labels', () => {
@@ -142,6 +295,7 @@ describe('Remove Labels', () => {
142295
.mockReturnValueOnce(['bug', 'enhancement'].join('\n')) // labels
143296
.mockReturnValueOnce('1') // issue_number
144297
.mockReturnValueOnce('issue-ops/labeler') // repository
298+
.mockReturnValueOnce('') // api_url
145299
})
146300

147301
afterEach(() => {

action.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ inputs:
3131
description: The repository to use
3232
required: false
3333
default: ${{ github.repository }}
34+
api_url:
35+
description: The GitHub API URL to use
36+
required: false
37+
default: ${{ github.api_url }}
3438

3539
runs:
3640
using: node20

dist/index.js

Lines changed: 4 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "labeler",
33
"description": "Manage labels for issues and pull requests",
4-
"version": "2.1.0",
4+
"version": "2.2.0",
55
"type": "module",
66
"author": "Nick Alteen <[email protected]>",
77
"homepage": "https://github.com/issue-ops/labeler#readme",

src/main.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,17 @@ export async function run(): Promise<void> {
1919
const repository: string = core.getInput('repository', {
2020
required: true
2121
})
22+
const apiUrl: string =
23+
core.getInput('api_url', { required: false }) ||
24+
`${process.env.GITHUB_API_URL}`
2225

2326
core.info('Running action with the following inputs:')
2427
core.info(` - Action: ${action}`)
2528
core.info(` - Create: ${create}`)
2629
core.info(` - Issue Number: ${issueNumber}`)
2730
core.info(` - Labels: ${labels.join(', ')}`)
2831
core.info(` - Repository: ${repository}`)
32+
core.info(` - API URL: ${apiUrl}`)
2933

3034
// Verify action is `add` or `remove`
3135
if (!['add', 'remove'].includes(action))
@@ -35,7 +39,7 @@ export async function run(): Promise<void> {
3539
const repo: string = repository.split('/')[1]
3640

3741
// Create the Octokit client
38-
const github: Octokit = new Octokit({ auth: githubToken })
42+
const github: Octokit = new Octokit({ auth: githubToken, baseUrl: apiUrl })
3943

4044
if (action === 'add') {
4145
const missingLabels: string[] = []

0 commit comments

Comments
 (0)