From de38c891f5d22731a5f095b3ca03dcf7b8f0052e Mon Sep 17 00:00:00 2001 From: hiroki osame Date: Thu, 16 Feb 2023 00:15:07 -0500 Subject: [PATCH] feat: config file at `~/.aicommits` (#51) Co-authored-by: Yu Le --- README.md | 22 +++++++++++++++------- package.json | 2 ++ pnpm-lock.yaml | 13 +++++++++++++ src/cli.ts | 10 +++++++--- src/utils.ts | 21 +++++++++++++++++++++ 5 files changed, 58 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 6e5036a..8828ad9 100644 --- a/README.md +++ b/README.md @@ -14,20 +14,28 @@ ## Installation and Usage -Install the CLI then grab your [OpenAI key](https://openai.com/api/) and add it as an env variable with the two commands below. +1. Install the CLI: -1. `npm install -g aicommits` -2. `export OPENAI_KEY=sk-xxxxxxxxxxxxxxxx` + ```sh + npm install -g aicommits + ``` -It's recommended to add the line in #2 to your `.zshrc` or `.bashrc` so it persists instead of having to define it in each terminal session. +2. Retrieve your API key from [OpenAI](https://platform.openai.com/account/api-keys) + > Note: If you haven't already, you'll have to create an account and set up billing. -After doing the two steps above, generate your commit by running `aicommits`. +3. Set the key so aicommits can use it: -> Note: If you get a EACCESS error on mac/linux when running the first command, try running it with `sudo npm install -g aicommits`. + ```sh + echo "OPENAI_KEY=" >> ~/.aicommits + ``` + +4. You're ready to go! + + Run `aicommits` in any Git repo and it will generate a commit message for you. ## How it works -This CLI tool runs a `git diff` command to grab all the latest changes, sends this to OpenAI's GPT-3, then returns the AI generated commit message. I also want to note that it does cost money since GPT-3 generations aren't free. However, OpenAI gives folks $18 of free credits and commit message generations are cheap so it should be free for a long time. +This CLI tool runs `git diff` to grab all the latest changes, sends them to OpenAI's GPT-3, then returns the AI generated commit message. Video coming soon where I rebuild it from scratch to show you how to easily build your own CLI tools powered by AI. diff --git a/package.json b/package.json index 8eef0da..cbbff6d 100644 --- a/package.json +++ b/package.json @@ -20,11 +20,13 @@ }, "dependencies": { "chalk": "^4.1.2", + "ini": "^3.0.1", "inquirer": "^8.0.0", "openai": "^3.1.0" }, "devDependencies": { "@pvtnbr/eslint-config": "^0.33.0", + "@types/ini": "^1.3.31", "@types/node": "^18.13.0", "eslint": "^8.34.0", "typescript": "^4.9.5" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 182001f..e897b97 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2,20 +2,24 @@ lockfileVersion: 5.4 specifiers: '@pvtnbr/eslint-config': ^0.33.0 + '@types/ini': ^1.3.31 '@types/node': ^18.13.0 chalk: ^4.1.2 eslint: ^8.34.0 + ini: ^3.0.1 inquirer: ^8.0.0 openai: ^3.1.0 typescript: ^4.9.5 dependencies: chalk: 4.1.2 + ini: 3.0.1 inquirer: 8.2.5 openai: 3.1.0 devDependencies: '@pvtnbr/eslint-config': 0.33.0_7kw3g6rralp5ps6mg3uyzz6azm + '@types/ini': 1.3.31 '@types/node': 18.13.0 eslint: 8.34.0 typescript: 4.9.5 @@ -141,6 +145,10 @@ packages: - typescript dev: true + /@types/ini/1.3.31: + resolution: {integrity: sha512-8ecxxaG4AlVEM1k9+BsziMw8UsX0qy3jYI1ad/71RrDZ+rdL6aZB0wLfAuflQiDhkD5o4yJ0uPK3OSUic3fG0w==} + dev: true + /@types/json-schema/7.0.11: resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} dev: true @@ -1487,6 +1495,11 @@ packages: /inherits/2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + /ini/3.0.1: + resolution: {integrity: sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + dev: false + /inquirer/8.2.5: resolution: {integrity: sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==} engines: {node: '>=12.0.0'} diff --git a/src/cli.ts b/src/cli.ts index 79c03df..8cb4b66 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -3,11 +3,15 @@ import { execSync } from 'child_process'; import chalk from 'chalk'; import inquirer from 'inquirer'; -import { generateCommitMessage } from './utils'; - -const OPENAI_KEY = process.env.OPENAI_KEY ?? process.env.OPENAI_API_KEY; +import { + getConfig, + generateCommitMessage, +} from './utils'; (async () => { + const config = await getConfig(); + const OPENAI_KEY = process.env.OPENAI_KEY ?? process.env.OPENAI_API_KEY ?? config.OPENAI_KEY; + console.log(chalk.white('▲ ') + chalk.green('Welcome to AICommits!')); if (!OPENAI_KEY) { diff --git a/src/utils.ts b/src/utils.ts index 6ed4290..74b8d53 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,5 +1,26 @@ +import fs from 'fs/promises'; +import path from 'path'; +import os from 'os'; +import ini from 'ini'; import { Configuration, OpenAIApi } from 'openai'; +const fileExists = (filePath: string) => fs.access(filePath).then(() => true, () => false); + +type ConfigType = { + OPENAI_KEY?: string; +}; + +export const getConfig = async (): Promise => { + const configPath = path.join(os.homedir(), '.aicommits'); + const configExists = await fileExists(configPath); + if (!configExists) { + return {}; + } + + const configString = await fs.readFile(configPath, 'utf8'); + return ini.parse(configString); +}; + export const generateCommitMessage = async ( apiKey: string, prompt: string,