@airscript/ghitgud 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.base +2 -0
- package/.github/CODEOWNERS +1 -0
- package/.github/FUNDING.yml +2 -0
- package/.github/ISSUE_TEMPLATE/build.md +9 -0
- package/.github/ISSUE_TEMPLATE/chore.md +9 -0
- package/.github/ISSUE_TEMPLATE/ci.md +9 -0
- package/.github/ISSUE_TEMPLATE/documentation.md +9 -0
- package/.github/ISSUE_TEMPLATE/feature.md +9 -0
- package/.github/ISSUE_TEMPLATE/fix.md +9 -0
- package/.github/ISSUE_TEMPLATE/performance.md +9 -0
- package/.github/ISSUE_TEMPLATE/refactor.md +9 -0
- package/.github/ISSUE_TEMPLATE/style.md +9 -0
- package/.github/ISSUE_TEMPLATE/test.md +9 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +28 -0
- package/.github/workflows/tests.yml +36 -0
- package/CHANGELOG.md +4 -0
- package/CITATION.cff +13 -0
- package/CODE_OF_CONDUCT.md +121 -0
- package/CONTRIBUTING.md +2 -0
- package/LICENSE +674 -0
- package/README.md +54 -0
- package/SECURITY.md +9 -0
- package/VERSION +1 -0
- package/app/api.ts +136 -0
- package/app/ascii.ts +18 -0
- package/app/commands.ts +117 -0
- package/app/config.ts +9 -0
- package/app/functions.ts +43 -0
- package/app/ghitgud.ts +18 -0
- package/app/library.ts +158 -0
- package/app/types.ts +8 -0
- package/dist/app/api.js +127 -0
- package/dist/app/ascii.js +20 -0
- package/dist/app/commands.js +89 -0
- package/dist/app/config.js +12 -0
- package/dist/app/functions.js +37 -0
- package/dist/app/ghitgud.js +19 -0
- package/dist/app/library.js +123 -0
- package/dist/app/types.js +2 -0
- package/dist/tests/library.test.js +84 -0
- package/package.json +38 -0
- package/scripts/clean.sh +2 -0
- package/templates/base.json +12 -0
- package/templates/conventional.json +53 -0
- package/templates/github.json +47 -0
- package/tests/library.test.ts +78 -0
- package/tsconfig.json +113 -0
package/README.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Ghitgud
|
|
2
|
+
A simple CLI to give superpowers to GitHub.
|
|
3
|
+
|
|
4
|
+
## Table of Contents
|
|
5
|
+
- [Installation](#installation)
|
|
6
|
+
- [Usage](#usage)
|
|
7
|
+
- [Contributing](#contributing)
|
|
8
|
+
- [Support](#support)
|
|
9
|
+
- [License](#license)
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
Follow the steps below to make use of Ghitgud.
|
|
13
|
+
|
|
14
|
+
Clone this repository:
|
|
15
|
+
```bash
|
|
16
|
+
git clone https://github.com/airscripts/ghitgud.git
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
After cloning the project just hit these few commands:
|
|
21
|
+
```bash
|
|
22
|
+
pnpm install
|
|
23
|
+
pnpm run build
|
|
24
|
+
pnpm link
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Then you'll be able to access the CLI and its relative help command:
|
|
28
|
+
```bash
|
|
29
|
+
ghitgud help
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Remember that to use the CLI you have to set a token and a repo with the format `username/repository` (e.g. airscripts/ghitgud):
|
|
33
|
+
```bash
|
|
34
|
+
ghitgud config set token `your-token-here`
|
|
35
|
+
ghitgud config set repo `username/repository`
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Contributing
|
|
39
|
+
Contributions and suggestions about how to improve this project are welcome!
|
|
40
|
+
Please follow [our contribution guidelines](https://github.com/airscripts/ghitgud/blob/main/CONTRIBUTING.md).
|
|
41
|
+
|
|
42
|
+
## Support
|
|
43
|
+
If you want to support my work you can do it by following me, leaving a star, sharing my projects or also donating at the links below.
|
|
44
|
+
Choose what you find more suitable for you:
|
|
45
|
+
|
|
46
|
+
<a href="https://sponsor.airscript.it" target="blank">
|
|
47
|
+
<img src="https://raw.githubusercontent.com/airscripts/assets/main/images/github-sponsors.svg" alt="GitHub Sponsors" width="30px" />
|
|
48
|
+
</a>
|
|
49
|
+
<a href="https://kofi.airscript.it" target="blank">
|
|
50
|
+
<img src="https://raw.githubusercontent.com/airscripts/assets/main/images/kofi.svg" alt="Kofi" width="30px" />
|
|
51
|
+
</a>
|
|
52
|
+
|
|
53
|
+
## License
|
|
54
|
+
This repository is licensed under [GPL-3.0 License](https://github.com/airscripts/ghitgud/blob/main/LICENSE).
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Supported Versions
|
|
4
|
+
| Version | Supported |
|
|
5
|
+
| ------- | ------------------ |
|
|
6
|
+
| 1.0.x | :white_check_mark: |
|
|
7
|
+
|
|
8
|
+
## Reporting Vulnerability
|
|
9
|
+
To report a vulnerability, open an [issue](https://github.com/airscripts/ghitgud/issues/new/choose).
|
package/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.0.0
|
package/app/api.ts
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import config from "./config";
|
|
2
|
+
import { Label } from "./types";
|
|
3
|
+
import functions from "./functions";
|
|
4
|
+
import "dotenv/config";
|
|
5
|
+
|
|
6
|
+
const VERSION = "2022-11-28";
|
|
7
|
+
const BASE_URL = "https://api.github.com";
|
|
8
|
+
const ACCEPT = "application/vnd.github+json";
|
|
9
|
+
const REPO = `${config.repo}`;
|
|
10
|
+
const AUTHORIZATION = `Bearer ${config.token}`;
|
|
11
|
+
|
|
12
|
+
const ERROR_UNAUTHORIZED = "Unauthorized.";
|
|
13
|
+
const ERROR_UNPROCESSABLE = "Content is unprocessable.";
|
|
14
|
+
const ERROR_NO_REPO = "You must set the GHITGUD_GITHUB_REPO environment variable.";
|
|
15
|
+
const ERROR_NO_TOKEN = "You must set the GHITGUD_GITHUB_TOKEN environment variable.";
|
|
16
|
+
|
|
17
|
+
const labels = {
|
|
18
|
+
fetch: async () => {
|
|
19
|
+
if (!functions.environment.hasRepo()) throw new Error(ERROR_NO_REPO);
|
|
20
|
+
if (!functions.environment.hasToken()) throw new Error(ERROR_NO_TOKEN);
|
|
21
|
+
|
|
22
|
+
const response = await fetch(`${BASE_URL}/repos/${REPO}/labels`, {
|
|
23
|
+
headers: {
|
|
24
|
+
Accept: ACCEPT,
|
|
25
|
+
Authorization: AUTHORIZATION,
|
|
26
|
+
"X-GitHub-Api-Version": VERSION,
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
if (functions.http.isNotAuthorized(response.status))
|
|
31
|
+
throw new Error(ERROR_UNAUTHORIZED);
|
|
32
|
+
|
|
33
|
+
return response;
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
get: async (name: string) => {
|
|
37
|
+
if (!functions.environment.hasRepo()) throw new Error(ERROR_NO_REPO);
|
|
38
|
+
if (!functions.environment.hasToken()) throw new Error(ERROR_NO_TOKEN);
|
|
39
|
+
|
|
40
|
+
const response = await fetch(`${BASE_URL}/repos/${REPO}/labels/${name}`, {
|
|
41
|
+
method: "GET",
|
|
42
|
+
headers: {
|
|
43
|
+
Accept: ACCEPT,
|
|
44
|
+
Authorization: AUTHORIZATION,
|
|
45
|
+
"X-GitHub-Api-Version": VERSION,
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
if (functions.http.isNotAuthorized(response.status))
|
|
50
|
+
throw new Error(ERROR_UNAUTHORIZED);
|
|
51
|
+
|
|
52
|
+
return response;
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
create: async (label: Label) => {
|
|
56
|
+
if (!functions.environment.hasRepo()) throw new Error(ERROR_NO_REPO);
|
|
57
|
+
if (!functions.environment.hasToken()) throw new Error(ERROR_NO_TOKEN);
|
|
58
|
+
|
|
59
|
+
const response = await fetch(`${BASE_URL}/repos/${REPO}/labels`, {
|
|
60
|
+
method: "POST",
|
|
61
|
+
|
|
62
|
+
body: JSON.stringify({
|
|
63
|
+
name: label.name,
|
|
64
|
+
color: label.color,
|
|
65
|
+
description: label.description,
|
|
66
|
+
}),
|
|
67
|
+
|
|
68
|
+
headers: {
|
|
69
|
+
Accept: ACCEPT,
|
|
70
|
+
Authorization: AUTHORIZATION,
|
|
71
|
+
"X-GitHub-Api-Version": VERSION,
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
if (functions.http.isUnprocessable(response.status))
|
|
76
|
+
throw new Error(ERROR_UNPROCESSABLE);
|
|
77
|
+
|
|
78
|
+
if (functions.http.isNotAuthorized(response.status))
|
|
79
|
+
throw new Error(ERROR_UNAUTHORIZED);
|
|
80
|
+
|
|
81
|
+
return response;
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
patch: async (label: Label) => {
|
|
85
|
+
if (!functions.environment.hasRepo()) throw new Error(ERROR_NO_REPO);
|
|
86
|
+
if (!functions.environment.hasToken()) throw new Error(ERROR_NO_TOKEN);
|
|
87
|
+
|
|
88
|
+
const response = await fetch(
|
|
89
|
+
`${BASE_URL}/repos/${REPO}/labels/${label.name}`,
|
|
90
|
+
{
|
|
91
|
+
method: "PATCH",
|
|
92
|
+
|
|
93
|
+
body: JSON.stringify({
|
|
94
|
+
color: label.color,
|
|
95
|
+
description: label.description,
|
|
96
|
+
new_name: label.newName || label.name,
|
|
97
|
+
}),
|
|
98
|
+
|
|
99
|
+
headers: {
|
|
100
|
+
Accept: ACCEPT,
|
|
101
|
+
Authorization: AUTHORIZATION,
|
|
102
|
+
"X-GitHub-Api-Version": VERSION,
|
|
103
|
+
},
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
if (functions.http.isNotAuthorized(response.status))
|
|
108
|
+
throw new Error(ERROR_UNAUTHORIZED);
|
|
109
|
+
|
|
110
|
+
return response;
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
delete: async (name: string) => {
|
|
114
|
+
if (!functions.environment.hasRepo()) throw new Error(ERROR_NO_REPO);
|
|
115
|
+
if (!functions.environment.hasToken()) throw new Error(ERROR_NO_TOKEN);
|
|
116
|
+
|
|
117
|
+
const response = await fetch(`${BASE_URL}/repos/${REPO}/labels/${name}`, {
|
|
118
|
+
method: "DELETE",
|
|
119
|
+
|
|
120
|
+
headers: {
|
|
121
|
+
Accept: ACCEPT,
|
|
122
|
+
Authorization: AUTHORIZATION,
|
|
123
|
+
"X-GitHub-Api-Version": VERSION,
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
if (functions.http.isNotAuthorized(response.status))
|
|
128
|
+
throw new Error(ERROR_UNAUTHORIZED);
|
|
129
|
+
|
|
130
|
+
return response;
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
export default {
|
|
135
|
+
labels,
|
|
136
|
+
};
|
package/app/ascii.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import figlet from "figlet";
|
|
2
|
+
|
|
3
|
+
const WIDTH = 80;
|
|
4
|
+
const TITLE = "Ghitgud";
|
|
5
|
+
const FONT = "Standard";
|
|
6
|
+
const WHITESPACE_BREAK = true;
|
|
7
|
+
const VERTICAL_LAYOUT = "default";
|
|
8
|
+
const HORIZONTAL_LAYOUT = "default";
|
|
9
|
+
|
|
10
|
+
const ascii = figlet.textSync(TITLE, {
|
|
11
|
+
font: FONT,
|
|
12
|
+
width: WIDTH,
|
|
13
|
+
verticalLayout: VERTICAL_LAYOUT,
|
|
14
|
+
whitespaceBreak: WHITESPACE_BREAK,
|
|
15
|
+
horizontalLayout: HORIZONTAL_LAYOUT,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export default ascii;
|
package/app/commands.ts
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { program, Command } from "commander";
|
|
2
|
+
import library from "./library";
|
|
3
|
+
|
|
4
|
+
const COMMANDS = {
|
|
5
|
+
ping: {
|
|
6
|
+
name: "ping",
|
|
7
|
+
action: () => void library.ping(),
|
|
8
|
+
description: "Check if the CLI is working.",
|
|
9
|
+
},
|
|
10
|
+
|
|
11
|
+
labels: {
|
|
12
|
+
name: "labels",
|
|
13
|
+
description: "Manage labels for a repository.",
|
|
14
|
+
|
|
15
|
+
commands: {
|
|
16
|
+
list: {
|
|
17
|
+
name: "list",
|
|
18
|
+
description: "List all labels for a repository.",
|
|
19
|
+
action: () => void library.labels.list(),
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
pull: {
|
|
23
|
+
name: "pull",
|
|
24
|
+
description: "Pull all related labels for a repository.",
|
|
25
|
+
action: () => void library.labels.pull(),
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
push: {
|
|
29
|
+
name: "push",
|
|
30
|
+
description: "Push all related labels for a repository.",
|
|
31
|
+
action: () => void library.labels.push(),
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
prune: {
|
|
35
|
+
name: "prune",
|
|
36
|
+
description: "Prune all related labels for a repository.",
|
|
37
|
+
action: () => void library.labels.prune(),
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
config: {
|
|
43
|
+
name: "config",
|
|
44
|
+
description: "Set CLI configurations.",
|
|
45
|
+
|
|
46
|
+
commands: {
|
|
47
|
+
set: {
|
|
48
|
+
name: "set",
|
|
49
|
+
description: "Set configuration.",
|
|
50
|
+
|
|
51
|
+
action: (key: string, value: string) =>
|
|
52
|
+
void library.config.set(key, value),
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const ping = () => {
|
|
59
|
+
program
|
|
60
|
+
.command(COMMANDS.ping.name)
|
|
61
|
+
.description(COMMANDS.ping.description)
|
|
62
|
+
.action(COMMANDS.ping.action);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const labels = () => {
|
|
66
|
+
const labels = program
|
|
67
|
+
.command(COMMANDS.labels.name)
|
|
68
|
+
.description(COMMANDS.labels.description);
|
|
69
|
+
|
|
70
|
+
labels.addCommand(
|
|
71
|
+
new Command(COMMANDS.labels.commands.list.name)
|
|
72
|
+
.description(COMMANDS.labels.commands.list.description)
|
|
73
|
+
.action(COMMANDS.labels.commands.list.action)
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
labels.addCommand(
|
|
77
|
+
new Command(COMMANDS.labels.commands.pull.name)
|
|
78
|
+
.description(COMMANDS.labels.commands.pull.description)
|
|
79
|
+
.action(COMMANDS.labels.commands.pull.action)
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
labels.addCommand(
|
|
83
|
+
new Command(COMMANDS.labels.commands.push.name)
|
|
84
|
+
.description(COMMANDS.labels.commands.push.description)
|
|
85
|
+
.action(COMMANDS.labels.commands.push.action)
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
labels.addCommand(
|
|
89
|
+
new Command(COMMANDS.labels.commands.prune.name)
|
|
90
|
+
.description(COMMANDS.labels.commands.prune.description)
|
|
91
|
+
.action(COMMANDS.labels.commands.prune.action)
|
|
92
|
+
);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const config = () => {
|
|
96
|
+
const config = program
|
|
97
|
+
.command(COMMANDS.config.name)
|
|
98
|
+
.description(COMMANDS.config.description);
|
|
99
|
+
|
|
100
|
+
config.addCommand(
|
|
101
|
+
new Command(COMMANDS.config.commands.set.name)
|
|
102
|
+
.description(COMMANDS.config.commands.set.description)
|
|
103
|
+
.arguments("<key> <value>")
|
|
104
|
+
|
|
105
|
+
.action((key: string, value: string) =>
|
|
106
|
+
COMMANDS.config.commands.set.action(key, value)
|
|
107
|
+
)
|
|
108
|
+
);
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const init = () => {
|
|
112
|
+
ping();
|
|
113
|
+
labels();
|
|
114
|
+
config();
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
export default init;
|
package/app/config.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import functions from "./functions";
|
|
2
|
+
import "dotenv/config";
|
|
3
|
+
|
|
4
|
+
const config = {
|
|
5
|
+
repo: process.env.GHITGUD_GITHUB_REPO || functions?.config.read("repo"),
|
|
6
|
+
token: process.env.GHITGUD_GITHUB_TOKEN || functions?.config.read("token"),
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export default config;
|
package/app/functions.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import os from "os";
|
|
3
|
+
import path from "path";
|
|
4
|
+
|
|
5
|
+
import conf from "./config";
|
|
6
|
+
import "dotenv/config";
|
|
7
|
+
|
|
8
|
+
const STATUS_OK = 200;
|
|
9
|
+
const STATUS_UNAUTHORIZED = 401;
|
|
10
|
+
const STATUS_NOT_FOUND = 404;
|
|
11
|
+
const STATUS_UNPROCESSABLE = 422;
|
|
12
|
+
|
|
13
|
+
const ENCODING = "utf8";
|
|
14
|
+
const CREDENTIALS_FILE = "credentials.json";
|
|
15
|
+
const GHITGUD_FOLDER = path.join(os.homedir(), ".config", "ghitgud");
|
|
16
|
+
|
|
17
|
+
const http = {
|
|
18
|
+
isOk: (status: number) => status === STATUS_OK,
|
|
19
|
+
isNotFound: (status: number) => status === STATUS_NOT_FOUND,
|
|
20
|
+
isNotAuthorized: (status: number) => status === STATUS_UNAUTHORIZED,
|
|
21
|
+
isUnprocessable: (status: number) => status === STATUS_UNPROCESSABLE,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const environment = {
|
|
25
|
+
hasRepo: () => (conf.repo ? true : false),
|
|
26
|
+
hasToken: () => (conf.token ? true : false),
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const config = {
|
|
30
|
+
read: (key: string) => {
|
|
31
|
+
if (!fs.existsSync(`${GHITGUD_FOLDER}/${CREDENTIALS_FILE}`)) return null;
|
|
32
|
+
|
|
33
|
+
const data = fs.readFileSync(
|
|
34
|
+
`${GHITGUD_FOLDER}/${CREDENTIALS_FILE}`,
|
|
35
|
+
ENCODING
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
const content = JSON.parse(data);
|
|
39
|
+
return content[key];
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export default { http, environment, config };
|
package/app/ghitgud.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import process from "process";
|
|
2
|
+
import { program } from "commander";
|
|
3
|
+
|
|
4
|
+
import ascii from "./ascii";
|
|
5
|
+
import commands from "./commands";
|
|
6
|
+
|
|
7
|
+
const NAME = "ghitgud";
|
|
8
|
+
const VERSION = "1.0.0";
|
|
9
|
+
const DESCRIPTION = "A simple CLI to give superpowers to GitHub.";
|
|
10
|
+
|
|
11
|
+
program
|
|
12
|
+
.name(NAME)
|
|
13
|
+
.description(DESCRIPTION)
|
|
14
|
+
.version(VERSION);
|
|
15
|
+
|
|
16
|
+
commands();
|
|
17
|
+
program.addHelpText("before", ascii);
|
|
18
|
+
program.parse(process.argv);
|
package/app/library.ts
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import os from "os";
|
|
3
|
+
import path from "path";
|
|
4
|
+
|
|
5
|
+
import api from "./api";
|
|
6
|
+
import { Label } from "./types";
|
|
7
|
+
import functions from "./functions";
|
|
8
|
+
|
|
9
|
+
const ENCODING = "utf8";
|
|
10
|
+
const PING_RESPONSE = "pong";
|
|
11
|
+
const METADATA_FOLDER = "metadata";
|
|
12
|
+
const METADATA_FILE = "labels.json";
|
|
13
|
+
const ERROR_NO_METADATA = "No metadata file found.";
|
|
14
|
+
|
|
15
|
+
const CREDENTIALS_FILE = "credentials.json";
|
|
16
|
+
const ERROR_UNSUPPORTED_KEY = "Trying to set unsupported key.";
|
|
17
|
+
const GHITGUD_FOLDER = path.join(os.homedir(), ".config", "ghitgud");
|
|
18
|
+
|
|
19
|
+
const ping = () => {
|
|
20
|
+
console.info(PING_RESPONSE);
|
|
21
|
+
return { success: true };
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const labels = {
|
|
25
|
+
list: async () => {
|
|
26
|
+
const response = await api.labels.fetch();
|
|
27
|
+
const data = await response.json();
|
|
28
|
+
|
|
29
|
+
const labels = data.map((label: Label) => ({
|
|
30
|
+
name: label.name,
|
|
31
|
+
color: label.color,
|
|
32
|
+
description: label.description,
|
|
33
|
+
}));
|
|
34
|
+
|
|
35
|
+
const result = { success: true, metadata: labels };
|
|
36
|
+
console.info(result);
|
|
37
|
+
return result;
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
pull: async () => {
|
|
41
|
+
const response = await api.labels.fetch();
|
|
42
|
+
const data = await response.json();
|
|
43
|
+
|
|
44
|
+
const labels = data.map((label: Label) => ({
|
|
45
|
+
name: label.name,
|
|
46
|
+
color: label.color,
|
|
47
|
+
description: label.description,
|
|
48
|
+
}));
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
fs.mkdirSync(METADATA_FOLDER, { recursive: true });
|
|
52
|
+
} catch (error) {
|
|
53
|
+
throw new Error(error instanceof Error ? error.message : String(error));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
fs.writeFileSync(
|
|
58
|
+
`${METADATA_FOLDER}/${METADATA_FILE}`,
|
|
59
|
+
JSON.stringify(labels, null, 2)
|
|
60
|
+
);
|
|
61
|
+
} catch (error) {
|
|
62
|
+
throw new Error(error instanceof Error ? error.message : String(error));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const result = { success: true };
|
|
66
|
+
console.info(result);
|
|
67
|
+
return result;
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
push: async () => {
|
|
71
|
+
if (!fs.existsSync(`${METADATA_FOLDER}/${METADATA_FILE}`))
|
|
72
|
+
throw new Error(ERROR_NO_METADATA);
|
|
73
|
+
|
|
74
|
+
const data = fs.readFileSync(
|
|
75
|
+
`${METADATA_FOLDER}/${METADATA_FILE}`,
|
|
76
|
+
ENCODING
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
const labels = JSON.parse(data);
|
|
80
|
+
|
|
81
|
+
await Promise.all(
|
|
82
|
+
labels.map(async (label: Label) => {
|
|
83
|
+
const response = await api.labels.get(label.name);
|
|
84
|
+
if (functions.http.isOk(response.status)) await api.labels.patch(label);
|
|
85
|
+
|
|
86
|
+
if (functions.http.isNotFound(response.status))
|
|
87
|
+
await api.labels.create(label);
|
|
88
|
+
})
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
const result = { success: true };
|
|
92
|
+
console.info(result);
|
|
93
|
+
return result;
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
prune: async () => {
|
|
97
|
+
if (!fs.existsSync(`${METADATA_FOLDER}/${METADATA_FILE}`))
|
|
98
|
+
throw new Error(ERROR_NO_METADATA);
|
|
99
|
+
|
|
100
|
+
const data = fs.readFileSync(
|
|
101
|
+
`${METADATA_FOLDER}/${METADATA_FILE}`,
|
|
102
|
+
ENCODING
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
const labels = JSON.parse(data);
|
|
106
|
+
labels.map(async (label: Label) => await api.labels.delete(label.name));
|
|
107
|
+
|
|
108
|
+
const result = { success: true };
|
|
109
|
+
console.info(result);
|
|
110
|
+
return result;
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const config = {
|
|
115
|
+
set: (key: string, value: string) => {
|
|
116
|
+
const knowns = ["token", "repo"];
|
|
117
|
+
|
|
118
|
+
if (!knowns.includes(key)) throw new Error(ERROR_UNSUPPORTED_KEY);
|
|
119
|
+
|
|
120
|
+
if (!fs.existsSync(`${GHITGUD_FOLDER}/${CREDENTIALS_FILE}`)) {
|
|
121
|
+
const credentials = { [key]: value };
|
|
122
|
+
|
|
123
|
+
try {
|
|
124
|
+
fs.mkdirSync(GHITGUD_FOLDER, { recursive: true });
|
|
125
|
+
} catch (error) {
|
|
126
|
+
throw new Error(error instanceof Error ? error.message : String(error));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
fs.writeFileSync(
|
|
130
|
+
`${GHITGUD_FOLDER}/${CREDENTIALS_FILE}`,
|
|
131
|
+
JSON.stringify(credentials, null, 2)
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
return { success: true };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const data = fs.readFileSync(
|
|
138
|
+
`${GHITGUD_FOLDER}/${CREDENTIALS_FILE}`,
|
|
139
|
+
ENCODING
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
const credentials = JSON.parse(data);
|
|
143
|
+
credentials[key] = value;
|
|
144
|
+
|
|
145
|
+
fs.writeFileSync(
|
|
146
|
+
`${GHITGUD_FOLDER}/${CREDENTIALS_FILE}`,
|
|
147
|
+
JSON.stringify(credentials, null, 2)
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
return { success: true };
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
export default {
|
|
155
|
+
ping,
|
|
156
|
+
labels,
|
|
157
|
+
config,
|
|
158
|
+
};
|