-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat!: support for .jsonc and .yml files (#6)
* remove old readme * add new readme * add json schema * edit githooks.ts * recommend `stackbreak.comment-divider` extension * fix typo in readme * update readme * remove extension * fix json schema * fix reader
- Loading branch information
1 parent
87810fb
commit a70bc53
Showing
4 changed files
with
227 additions
and
89 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,60 +1,93 @@ | ||
export type Githooks = { | ||
githooks: Record<string, string[]>; | ||
}; | ||
import { | ||
brightGreen, | ||
brightRed, | ||
gray, | ||
} from "https://deno.land/[email protected]/fmt/colors.ts"; | ||
import * as jsonc from "https://deno.land/[email protected]/jsonc/parse.ts"; | ||
import * as yaml from "https://deno.land/[email protected]/yaml/parse.ts"; | ||
|
||
export type GithooksOptions = { | ||
getConfig: () => Promise<Githooks>; | ||
verbose?: boolean; | ||
}; | ||
/* find file ---------------------------------------------------------------- */ | ||
|
||
type ConfigFile = | ||
| `${string}.json` | ||
| `${string}.jsonc` | ||
| `${string}.yaml` | ||
| `${string}.yml`; | ||
|
||
export async function readJson(filePath: string): Promise<unknown> { | ||
async function findFile( | ||
...paths: ConfigFile[] | ||
): Promise< | ||
| Record<string, string> | ||
| undefined | ||
> { | ||
try { | ||
const jsonString = await Deno.readTextFile(filePath); | ||
const content = await Deno.readTextFile(paths[0]); | ||
|
||
const parsedContent = paths[0].endsWith(".json") | ||
? JSON.parse(content) | ||
: paths[0].endsWith(".jsonc") | ||
? jsonc.parse(content) as Record<string, string> | ||
: yaml.parse(content) as Record<string, string>; | ||
|
||
return JSON.parse(jsonString); | ||
} catch (err) { | ||
err.message = `${filePath}: ${err.message}`; | ||
return paths[0].endsWith("deno.json") || paths[0].endsWith("deno.jsonc") | ||
? (parsedContent.githooks ? parsedContent.githooks : undefined) | ||
: parsedContent; | ||
} catch (_) { | ||
paths.shift(); | ||
|
||
throw err; | ||
if (paths.length > 0) { | ||
return await findFile(...paths); | ||
} | ||
} | ||
} | ||
|
||
export function readDenoJson(): Promise<Githooks> { | ||
return readJson("./deno.json") as Promise<Githooks>; | ||
} | ||
/* setup hooks -------------------------------------------------------------- */ | ||
|
||
const defaultOptions: GithooksOptions = { | ||
getConfig: readDenoJson, | ||
verbose: true, | ||
}; | ||
export async function setup({ | ||
verbose = true, | ||
file, | ||
}: { | ||
file?: ConfigFile; | ||
verbose?: boolean; | ||
} = {}) { | ||
const githooks = file ? await findFile(file) : await findFile( | ||
"./githooks.json", | ||
"./githooks.jsonc", | ||
"./githooks.yaml", | ||
"./githooks.yml", | ||
"./deno.json", | ||
"./deno.jsonc", | ||
); | ||
|
||
export async function setupGithooks(opts: GithooksOptions = defaultOptions) { | ||
const config = await opts.getConfig(); | ||
if (!githooks) { | ||
return verbose && | ||
console.error(brightRed("No githooks found!")); | ||
} | ||
|
||
if (!config.githooks) { | ||
opts.verbose && | ||
console.log("No githooks found in deno.json — skipping setup."); | ||
} else { | ||
const hooks = Object.keys(config.githooks); | ||
const hooks = Object.keys(githooks); | ||
|
||
for (const hook of hooks) { | ||
const task = config.githooks[hook]; | ||
const hookPath = `./.git/hooks/${hook}`; | ||
const hookScript = `#!/bin/sh\nexec deno task ${task}`; | ||
for (const h of hooks) { | ||
const task = githooks[h]; | ||
const hookPath = `./.git/hooks/${h}`; | ||
const hookScript = `#!/bin/sh\nexec deno task ${task}`; | ||
|
||
await Deno.writeTextFile(hookPath, hookScript); | ||
await Deno.writeTextFile(hookPath, hookScript); | ||
|
||
if (Deno.build.os !== "windows") { | ||
await Deno.chmod(hookPath, 0o755); | ||
} | ||
if (Deno.build.os !== "windows") { | ||
await Deno.chmod(hookPath, 0o755); | ||
} | ||
|
||
opts.verbose && | ||
console.log("Githooks setup successfully:", hooks.join(", ")); | ||
} | ||
|
||
verbose && | ||
console.info( | ||
gray( | ||
`${brightGreen("Added githooks:")} ${hooks.join(", ")}`, | ||
), | ||
); | ||
} | ||
|
||
// Execute when called directly | ||
/* execute cli -------------------------------------------------------------- */ | ||
|
||
if (import.meta.main) { | ||
await setupGithooks(); | ||
await setup(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
## githooks for Deno | ||
|
||
This is a simple tool for [Deno](https://deno.land) projects that allows you to | ||
associate specific [deno tasks](https://deno.land/manual/tools/task_runner) with | ||
specific [Git Hooks](https://git-scm.com/docs/githooks) by extending the native | ||
`deno.json` configuration file or adding a separate one. | ||
|
||
It works like this: | ||
|
||
1. In your `deno.json` (or `deno.jsonc`) file, add a `githooks` key containing a | ||
map of `{githook}` to `{deno task}`. For example: | ||
|
||
```json | ||
{ | ||
"tasks": { | ||
"start": "deno run -A dev.ts", | ||
"check": "deno fmt --check && deno lint" | ||
}, | ||
"githooks": { | ||
"pre-commit": "check" | ||
} | ||
} | ||
``` | ||
|
||
You can also create a separate `githooks.json`, `githooks.jsonc`, | ||
`githooks.yaml` or `githooks.yml` file: | ||
|
||
```json | ||
{ | ||
"pre-commit": "check" | ||
} | ||
``` | ||
|
||
```yaml | ||
pre-commit: check | ||
``` | ||
To add autocompletion, you can use our JSON schema. This schema can either be | ||
specified in the settings of your code editor or directly in the JSON file: | ||
```json | ||
{ | ||
"$schema": "https://deno.land/x/githooks/schema.json", | ||
"pre-commit": "check" | ||
} | ||
``` | ||
|
||
2. In your terminal, run the `githooks.ts` script. It will automatically create | ||
a hook file for each githook in your `deno.json` file. | ||
|
||
```bash | ||
deno run -A -r https://deno.land/x/githooks/githooks.ts | ||
``` | ||
|
||
That's it. Now your Git Hook should call `deno task check` before every commit. | ||
|
||
--- | ||
|
||
**PROTIP:** [**deco**](https://github.com/deco-cx/deco) projects come with this | ||
extension pre-installed in the `dev` script. You don't have to do anything, just | ||
add `githooks` to `deno.json` and run `dev` to install the hooks transparently. | ||
|
||
--- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
{ | ||
"$id": "https://deno.land/x/githooks/schema.json", | ||
"$schema": "https://json-schema.org/draft-07/schema", | ||
"type": "object", | ||
"properties": { | ||
"applypatch-msg": { | ||
"type": "string" | ||
}, | ||
"pre-applypatch": { | ||
"type": "string" | ||
}, | ||
"post-applypatch": { | ||
"type": "string" | ||
}, | ||
"pre-commit": { | ||
"type": "string" | ||
}, | ||
"pre-merge-commit": { | ||
"type": "string" | ||
}, | ||
"prepare-commit-msg": { | ||
"type": "string" | ||
}, | ||
"commit-msg": { | ||
"type": "string" | ||
}, | ||
"post-commit": { | ||
"type": "string" | ||
}, | ||
"pre-rebase": { | ||
"type": "string" | ||
}, | ||
"post-checkout": { | ||
"type": "string" | ||
}, | ||
"post-merge": { | ||
"type": "string" | ||
}, | ||
"pre-push": { | ||
"type": "string" | ||
}, | ||
"pre-receive": { | ||
"type": "string" | ||
}, | ||
"update": { | ||
"type": "string" | ||
}, | ||
"proc-receive": { | ||
"type": "string" | ||
}, | ||
"post-receive": { | ||
"type": "string" | ||
}, | ||
"post-update": { | ||
"type": "string" | ||
}, | ||
"reference-transaction": { | ||
"type": "string" | ||
}, | ||
"push-to-checkout": { | ||
"type": "string" | ||
}, | ||
"pre-auto-gc": { | ||
"type": "string" | ||
}, | ||
"post-rewrite": { | ||
"type": "string" | ||
}, | ||
"sendemail-validate": { | ||
"type": "string" | ||
}, | ||
"fsmonitor-watchman": { | ||
"type": "string" | ||
}, | ||
"p4-changelist": { | ||
"type": "string" | ||
}, | ||
"p4-prepare-changelist": { | ||
"type": "string" | ||
}, | ||
"p4-post-changelist": { | ||
"type": "string" | ||
}, | ||
"p4-pre-submit": { | ||
"type": "string" | ||
}, | ||
"post-index-change": { | ||
"type": "string" | ||
} | ||
} | ||
} |