Skip to content
This repository was archived by the owner on May 20, 2020. It is now read-only.

Commit 442bbfb

Browse files
author
Adam Braimbridge
authored
Add support for Issues (#56)
Add support for Issues
2 parents 5653bdf + f25dfad commit 442bbfb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+957
-155
lines changed

README.md

+13-17
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## A human-friendly<sup>1</sup> command line tool for the GitHub API.
44

5-
<sup>1</sup> It's script-friendly too.
5+
<sup>1</sup> It's script-friendly too.
66

77
![image](https://user-images.githubusercontent.com/224547/57764890-42704180-76fc-11e9-9256-2be2037e2fdf.png)
88

@@ -59,77 +59,73 @@ ika --version
5959
### Working with GitHub Projects
6060

6161
```bash
62-
ika add-pull-request [--column-url] [--pull-request-url]
62+
ika projects add [--column-url] [--url]
6363

6464
# Add a pull request to a GitHub project column.
6565
```
6666

6767
```bash
68-
ika close-project <github-url>
68+
ika projects close <github-url>
6969

7070
# Set the state of an existing project board to `closed`.
7171
```
7272

7373
```bash
74-
ika create-project <github-url> [--body]
74+
ika projects create <github-url> [--body]
7575

7676
# Create a new project.
7777
```
7878

79-
@see: [`src/commands/projects/README.md`](https://github.com/Financial-Times/ika/blob/master/src/commands/projects/README.md) for more details.
80-
8179
### Working with GitHub Pull Requests
8280

8381
```bash
84-
ika close-pull-request <github-url>
82+
ika pulls close <github-url>
8583

8684
# Set the state of an existing pull request to `closed`.
8785
```
8886

8987
```bash
90-
ika create-comment <github-url> [--body]
88+
ika pulls create-comment <github-url> [--body]
9189

9290
# Create a comment on an existing pull request.
9391
```
9492

9593
```bash
96-
ika create-review-request <github-url> [reviewers|team-reviewers]
94+
ika pulls create-review-request <github-url> [reviewers|team-reviewers]
9795

9896
# Request a review for a pull request.
9997
```
10098

10199
```bash
102-
ika create-pull-request <github-url> [--base] [--body] [--title]
100+
ika pulls create <github-url> [--base] [--body] [--title]
103101

104102
# Create a new pull request.
105103
```
106104

107105
```bash
108-
ika delete-comment <github-url>
106+
ika pulls delete-comment <github-url>
109107

110108
# Delete a comment on an existing pull request.
111109
```
112110

113111
```bash
114-
ika delete-review-request <github-url> [reviewers|team-reviewers]
112+
ika pulls delete-review-request <github-url> [reviewers|team-reviewers]
115113

116114
# Delete a review for a pull request.
117115
```
118116

119117
```bash
120-
ika merge-pull-request <github-url> [--method]
118+
ika pulls merge <github-url> [--method]
121119

122120
# Merge an existing pull request.
123121
```
124122

125123
```bash
126-
ika open-pull-request <github-url>
124+
ika pulls open <github-url>
127125

128126
# Set the state of an existing pull request to `open`.
129127
```
130128

131-
@see: [`src/commands/pulls/README.md`](https://github.com/Financial-Times/ika/blob/master/src/commands/pulls/README.md) for more details.
132-
133129
### Global Options
134130

135131
```bash
@@ -145,7 +141,7 @@ ika open-pull-request <github-url>
145141
# Generate one at https://github.com/settings/tokens
146142
```
147143

148-
> Note: You can omit the `--token` argument, because it will default to `$GITHUB_PERSONAL_ACCESS_TOKEN`.
144+
> Note: You can omit the `--token` argument, because it will default to `$GITHUB_PERSONAL_ACCESS_TOKEN`.
149145
>
150146
> In that case you will need to export the token to your environment:
151147

bin/ika.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,19 @@ const baseOptions = flow([
1717
])
1818
baseOptions(yargs)
1919
.scriptName('ika')
20+
.usage('$0 <command> <subcommand> [...options]')
2021
/**
2122
* The --version argument only makes sense as an option for the main `ika` command.
2223
*/
2324
.command('[--version]', 'Show the version number.')
2425
.hide('version')
26+
.completion('completion', 'Output a generated script. To enable bash/zsh completions: \n 1. Install ika globally. \n 2. Add the script to your .bashrc or .bash_profile (or .zshrc for zsh).')
2527
/**
2628
* Load our yargs command modules from a directory.
2729
*
2830
* @see https://github.com/yargs/yargs/blob/master/docs/advanced.md#commanddirdirectory-opts
2931
*/
30-
.commandDir(yargsCommandsDirectoryPath, { recurse: true })
32+
.commandDir(yargsCommandsDirectoryPath)
3133
/**
3234
* Maximize the width of yargs’ usage instructions.
3335
*/

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"license": "MIT",
1919
"dependencies": {
2020
"@adambraimbridge/prettierrc-2019-05": "^1.0.0",
21+
"@octokit/plugin-throttling": "^2.6.0",
2122
"@octokit/rest": "^16.16.3",
2223
"lodash.flow": "^3.5.0",
2324
"update-notifier": "^3.0.0",

src/commands/allowance.js

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/**
2+
* @see: https://octokit.github.io/rest.js/#octokit-routes-rateLimit
3+
*/
4+
const printOutput = require('../lib/print-output')
5+
const authenticatedOctokit = require('../lib/octokit')
6+
7+
const handler = async ({ token, json }) => {
8+
try {
9+
const octokit = await authenticatedOctokit({ personalAccessToken: token })
10+
const result = await octokit.rateLimit.get()
11+
Object.keys(result.data.resources).forEach(row => {
12+
console.log(`${row} \n • Remaining = ${result.data.resources[row].remaining} / ${result.data.resources[row].limit} \n • Reset = ${new Date(result.data.resources[row].reset * 1000)}\n`)
13+
})
14+
printOutput({ json, resource: result.data })
15+
} catch (error) {
16+
printOutput({ json, error })
17+
}
18+
}
19+
20+
module.exports = {
21+
command: 'allowance',
22+
desc: 'Display current GitHub API rate-limiting allowance.',
23+
handler,
24+
}

src/commands/issues.js

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/**
2+
* This project follows the example provided in the Yargs documentation for command hierarchy and directory structure.
3+
* @see: https://github.com/yargs/yargs/blob/master/docs/advanced.md#commanddirdirectory-opts
4+
*/
5+
exports.command = 'issues <subcommand> [...options]'
6+
exports.desc = 'Manage GitHub issues.'
7+
exports.builder = function(yargs) {
8+
return yargs.commandDir('issues')
9+
}
10+
exports.handler = function() {}

src/commands/issues/close.js

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/**
2+
* @see: https://octokit.github.io/rest.js/#octokit-routes-issues-update
3+
* There is no "closed" endpoint in the Octokit API. We use "update" with a `state` of "closed".
4+
* const result = await octokit.issues.update({owner, repo, issue_number})
5+
*/
6+
const flow = require('lodash.flow')
7+
const commonYargs = require('../../lib/common-yargs')
8+
const printOutput = require('../../lib/print-output')
9+
const authenticatedOctokit = require('../../lib/octokit')
10+
11+
/**
12+
* yargs builder function.
13+
*
14+
* @param {import('yargs').Yargs} yargs - Instance of yargs
15+
*/
16+
const builder = yargs => {
17+
const baseOptions = flow([
18+
commonYargs.withGitHubUrl({
19+
describe: 'The URL of the GitHub issue to close.',
20+
}),
21+
])
22+
return baseOptions(yargs).example('github-url', 'Pattern: [https://][github.com]/[owner]/[repository]/issue/[number]')
23+
}
24+
25+
/**
26+
* Update an issue.
27+
*
28+
* @param {object} argv - argv parsed and filtered by yargs
29+
* @param {string} argv.token
30+
* @param {string} argv.json
31+
* @param {object} argv.githubUrl - The GitHub url parsed in the withGitHubUrl() yarg option into appropriate properties, such as `owner` and `repo`.
32+
*/
33+
const handler = async ({ token, json, githubUrl }) => {
34+
const { owner, repo, value } = githubUrl
35+
const inputs = {
36+
owner,
37+
repo,
38+
issue_number: value,
39+
state: 'closed',
40+
}
41+
try {
42+
const octokit = await authenticatedOctokit({ personalAccessToken: token })
43+
const result = await octokit.issues.update(inputs)
44+
printOutput({ json, resource: result })
45+
} catch (error) {
46+
printOutput({ json, error })
47+
}
48+
}
49+
50+
module.exports = {
51+
command: 'close <github-url>',
52+
desc: 'Set the state of an existing issue to `closed`',
53+
builder,
54+
handler,
55+
}

src/commands/issues/create.js

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* @see: https://octokit.github.io/rest.js/#octokit-routes-issues-create
3+
* const result = await octokit.issues.create({ owner, repo, title, [body], [assignees] })
4+
*/
5+
const flow = require('lodash.flow')
6+
const commonYargs = require('../../lib/common-yargs')
7+
const printOutput = require('../../lib/print-output')
8+
const authenticatedOctokit = require('../../lib/octokit')
9+
10+
/**
11+
* yargs builder function.
12+
*
13+
* @param {import('yargs').Yargs} yargs - Instance of yargs
14+
*/
15+
const builder = yargs => {
16+
const baseOptions = flow([
17+
commonYargs.withGitHubUrl({
18+
describe: 'The URL of the GitHub repository to add an issue to.',
19+
}),
20+
commonYargs.withBody(),
21+
commonYargs.withTitle({ demandOption: true }),
22+
])
23+
return baseOptions(yargs)
24+
.option('assignees', {
25+
type: 'array',
26+
describe: 'GitHub user names to assign to the issue',
27+
})
28+
.example('github-url', 'Pattern: https://github.com/[owner]/[repository]')
29+
}
30+
31+
/**
32+
* Return the contents of a pull request body and create a pull request.
33+
*
34+
* @param {object} argv - argv parsed and filtered by yargs
35+
* @param {string} argv.token
36+
* @param {string} argv.json
37+
* @param {string} argv.title
38+
* @param {string} argv.bodyContent — This is created in the withBody() yarg option middleware.
39+
* @param {array} argv.assignees — GitHub user names to assign to this issue.
40+
* @param {object} argv.githubUrl - The GitHub url parsed in the withGitHubUrl() yarg option into appropriate properties, such as `owner` and `repo`.
41+
*/
42+
const handler = async ({ token, json, title, bodyContent, assignees, githubUrl }) => {
43+
const { owner, repo } = githubUrl
44+
const inputs = {
45+
owner,
46+
repo,
47+
title,
48+
body: bodyContent,
49+
assignees,
50+
}
51+
try {
52+
const octokit = await authenticatedOctokit({ personalAccessToken: token })
53+
const result = await octokit.issues.create(inputs)
54+
printOutput({ json, resource: result })
55+
} catch (error) {
56+
printOutput({ json, error })
57+
}
58+
}
59+
60+
module.exports = {
61+
command: 'create <github-url> [--title] [--body] [--assignees]',
62+
desc: 'Create a new issue',
63+
builder,
64+
handler,
65+
}

src/commands/issues/list-for-repo.js

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* @see: https://octokit.github.io/rest.js/#octokit-routes-issues-list-for-repo
3+
* List all issues assigned to the authenticated user across all visible repositories.
4+
* const result = await octokit.issues.list([filter])
5+
*/
6+
const flow = require('lodash.flow')
7+
const commonYargs = require('../../lib/common-yargs')
8+
const printOutput = require('../../lib/print-output')
9+
const authenticatedOctokit = require('../../lib/octokit')
10+
11+
/**
12+
* yargs builder function.
13+
*
14+
* @param {import('yargs').Yargs} yargs - Instance of yargs
15+
*/
16+
const builder = yargs => {
17+
const baseOptions = flow([
18+
commonYargs.withGitHubUrl({
19+
describe: 'The URL of the GitHub repository, the issues whence to glean.',
20+
}),
21+
])
22+
return baseOptions(yargs).example('github-url', 'Pattern: https://github.com/[owner]/[repository]')
23+
}
24+
25+
/**
26+
* List all issues for a repository.
27+
*
28+
* @param {object} argv - argv parsed and filtered by yargs
29+
* @param {string} argv.token
30+
* @param {string} argv.json
31+
*/
32+
const handler = async ({ token, json, githubUrl }) => {
33+
try {
34+
const { owner, repo } = githubUrl
35+
const octokit = await authenticatedOctokit({ personalAccessToken: token })
36+
37+
// @see https://github.com/octokit/rest.js/blob/master/docs/src/pages/api/00_usage.md#pagination
38+
const request = octokit.issues.listForRepo.endpoint.merge({ owner, repo })
39+
const result = await octokit.paginate(request)
40+
if (json) {
41+
printOutput({ json, resource: result })
42+
} else {
43+
result.forEach(issue => {
44+
const { title, created_at, html_url, assignees } = issue
45+
const assigneeString = assignees.map(user => user.login).join(', ')
46+
console.log(
47+
// Prettier-ignore
48+
`\x1b[36m${created_at}\x1b[0m`,
49+
title,
50+
`\x1b[33m${assigneeString || 'unassigned'}\x1b[0m`,
51+
`\x1b[2m${html_url}\x1b[0m`
52+
)
53+
})
54+
}
55+
} catch (error) {
56+
printOutput({ json, error })
57+
}
58+
}
59+
60+
module.exports = {
61+
command: 'list-for-repo <github-url>',
62+
desc: 'List all issues in a repository.',
63+
builder,
64+
handler,
65+
}

0 commit comments

Comments
 (0)