licenseguard-cli 1.0.0 â 1.2.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/README.md +36 -1
- package/bin/licenseguard.js +11 -1
- package/lib/commands/setup.js +56 -0
- package/lib/postinstall.js +117 -0
- package/package.json +2 -12
package/README.md
CHANGED
|
@@ -153,7 +153,7 @@ This configuration is used by the git hooks to display license information.
|
|
|
153
153
|
LicenseGuard installs two informational git hooks:
|
|
154
154
|
|
|
155
155
|
### Post-Checkout Hook
|
|
156
|
-
Displays a notification after `git
|
|
156
|
+
Displays a notification after `git checkout` or branch switches:
|
|
157
157
|
```
|
|
158
158
|
đ This project uses MIT License by Your Name
|
|
159
159
|
```
|
|
@@ -169,6 +169,40 @@ Displays a reminder before each commit:
|
|
|
169
169
|
- Hooks always exit with code 0 (success)
|
|
170
170
|
- If `.licenseguardrc` is missing, hooks silently exit
|
|
171
171
|
|
|
172
|
+
### Auto-Setup on Clone (npm projects)
|
|
173
|
+
|
|
174
|
+
Git hooks live in `.git/hooks/` which is **not tracked by git**. This means hooks are not copied when someone clones your repository.
|
|
175
|
+
|
|
176
|
+
For npm projects, you can use the `prepare` script to automatically set up hooks when developers run `npm install`:
|
|
177
|
+
|
|
178
|
+
**Add to your package.json:**
|
|
179
|
+
```json
|
|
180
|
+
{
|
|
181
|
+
"devDependencies": {
|
|
182
|
+
"licenseguard-cli": "^1.1.0"
|
|
183
|
+
},
|
|
184
|
+
"scripts": {
|
|
185
|
+
"prepare": "licenseguard --setup || true"
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**What happens when someone clones your project:**
|
|
191
|
+
```bash
|
|
192
|
+
git clone <your-repo> # Gets code + .licenseguardrc
|
|
193
|
+
npm install # AUTOMATICALLY:
|
|
194
|
+
# đ "This project uses MIT License by Your Name"
|
|
195
|
+
# â Git hooks installed
|
|
196
|
+
git checkout feature # Notification appears (hooks active)
|
|
197
|
+
git commit # Reminder appears (hooks active)
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
The `--setup` command:
|
|
201
|
+
- Reads `.licenseguardrc` and displays license notification
|
|
202
|
+
- Installs git hooks automatically
|
|
203
|
+
- Always exits 0 (never breaks `npm install`)
|
|
204
|
+
- Safe to run multiple times (idempotent)
|
|
205
|
+
|
|
172
206
|
### Existing Hooks
|
|
173
207
|
|
|
174
208
|
If you already have git hooks, LicenseGuard will NOT overwrite them. Instead, it creates variants:
|
|
@@ -182,6 +216,7 @@ You can manually merge these with your existing hooks if desired.
|
|
|
182
216
|
If your project is not a git repository:
|
|
183
217
|
- Interactive mode (`--init`) will offer to run `git init`
|
|
184
218
|
- Fast mode (`--init-fast`) will skip hooks and warn you
|
|
219
|
+
- `--setup` command will skip hooks with a warning
|
|
185
220
|
- LICENSE file is always created regardless of git status
|
|
186
221
|
|
|
187
222
|
## FAQ
|
package/bin/licenseguard.js
CHANGED
|
@@ -4,9 +4,10 @@ const { program } = require('commander')
|
|
|
4
4
|
const { runList } = require('../lib/commands/list')
|
|
5
5
|
const { runInit } = require('../lib/commands/init')
|
|
6
6
|
const { runInitFast } = require('../lib/commands/init-fast')
|
|
7
|
+
const { setupCommand } = require('../lib/commands/setup')
|
|
7
8
|
|
|
8
9
|
program
|
|
9
|
-
.version('1.
|
|
10
|
+
.version('1.1.0')
|
|
10
11
|
.description('License setup & compliance helper for developers')
|
|
11
12
|
|
|
12
13
|
program
|
|
@@ -17,6 +18,10 @@ program
|
|
|
17
18
|
.option('--year <year>', 'Copyright year (for --init-fast)')
|
|
18
19
|
.option('--url <url>', 'Project URL (for --init-fast)')
|
|
19
20
|
.option('--ls', 'List available license templates')
|
|
21
|
+
.option(
|
|
22
|
+
'--setup',
|
|
23
|
+
'Setup license notification and install git hooks (for npm prepare script)'
|
|
24
|
+
)
|
|
20
25
|
.parse(process.argv)
|
|
21
26
|
|
|
22
27
|
const options = program.opts()
|
|
@@ -36,6 +41,11 @@ if (options.init) {
|
|
|
36
41
|
console.error('Error:', err.message)
|
|
37
42
|
process.exit(1)
|
|
38
43
|
})
|
|
44
|
+
} else if (options.setup) {
|
|
45
|
+
setupCommand().catch((err) => {
|
|
46
|
+
// Even on error, don't exit 1 - npm prepare compatibility
|
|
47
|
+
console.error('Setup warning:', err.message)
|
|
48
|
+
})
|
|
39
49
|
} else {
|
|
40
50
|
program.help()
|
|
41
51
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
const chalk = require('chalk')
|
|
3
|
+
const { isGitRepo, installHooks } = require('../utils/git-helpers')
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Setup command - Install git hooks and show license notification
|
|
7
|
+
* Used in npm prepare script for auto-setup on clone
|
|
8
|
+
*
|
|
9
|
+
* This command is designed for use in package.json prepare scripts:
|
|
10
|
+
* {
|
|
11
|
+
* "scripts": {
|
|
12
|
+
* "prepare": "licenseguard --setup || true"
|
|
13
|
+
* }
|
|
14
|
+
* }
|
|
15
|
+
*
|
|
16
|
+
* @returns {Promise<void>}
|
|
17
|
+
*/
|
|
18
|
+
async function setupCommand() {
|
|
19
|
+
try {
|
|
20
|
+
// Check for .licenseguardrc
|
|
21
|
+
if (!fs.existsSync('.licenseguardrc')) {
|
|
22
|
+
console.log(
|
|
23
|
+
chalk.yellow(
|
|
24
|
+
'No .licenseguardrc found. Run \'licenseguard --init\' first.'
|
|
25
|
+
)
|
|
26
|
+
)
|
|
27
|
+
return // Exit 0 implicitly
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Read config
|
|
31
|
+
const configContent = fs.readFileSync('.licenseguardrc', 'utf-8')
|
|
32
|
+
const config = JSON.parse(configContent)
|
|
33
|
+
|
|
34
|
+
// Display license notification (MAIN PURPOSE)
|
|
35
|
+
// This is what developers see when they run npm install
|
|
36
|
+
console.log(
|
|
37
|
+
chalk.blue(
|
|
38
|
+
`đ This project uses ${config.license.toUpperCase()} License by ${config.owner}`
|
|
39
|
+
)
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
// Install hooks if git repo
|
|
43
|
+
if (isGitRepo()) {
|
|
44
|
+
installHooks()
|
|
45
|
+
// Note: installHooks() already prints success/warning messages
|
|
46
|
+
} else {
|
|
47
|
+
console.log(chalk.yellow('â ī¸ Skipping git hooks (not a git repo)'))
|
|
48
|
+
}
|
|
49
|
+
} catch (error) {
|
|
50
|
+
// Always exit 0 - never break npm install
|
|
51
|
+
// This is CRITICAL for npm prepare script compatibility
|
|
52
|
+
console.log(chalk.yellow(`â ī¸ Setup warning: ${error.message}`))
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
module.exports = { setupCommand }
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs')
|
|
4
|
+
const path = require('path')
|
|
5
|
+
const os = require('os')
|
|
6
|
+
const { execSync } = require('child_process')
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Setup global git hooks for automatic license notifications
|
|
10
|
+
* Runs automatically after npm install -g licenseguard-cli
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const homeDir = os.homedir()
|
|
14
|
+
const templateDir = path.join(homeDir, '.git-templates')
|
|
15
|
+
const hooksDir = path.join(templateDir, 'hooks')
|
|
16
|
+
|
|
17
|
+
// Self-contained hook scripts (only needs Node.js, not licenseguard)
|
|
18
|
+
const postCheckoutHook = `#!/usr/bin/env node
|
|
19
|
+
const fs = require('fs')
|
|
20
|
+
const path = require('path')
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
const configPath = path.join(process.cwd(), '.licenseguardrc')
|
|
24
|
+
if (!fs.existsSync(configPath)) process.exit(0)
|
|
25
|
+
|
|
26
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'))
|
|
27
|
+
const blue = '\\x1b[34m'
|
|
28
|
+
const reset = '\\x1b[0m'
|
|
29
|
+
|
|
30
|
+
console.log(\`\${blue}đ This project uses \${config.license.toUpperCase()} License by \${config.owner}\${reset}\`)
|
|
31
|
+
} catch (e) {
|
|
32
|
+
// Silent fail - never block git
|
|
33
|
+
}
|
|
34
|
+
process.exit(0)
|
|
35
|
+
`
|
|
36
|
+
|
|
37
|
+
const preCommitHook = `#!/usr/bin/env node
|
|
38
|
+
const fs = require('fs')
|
|
39
|
+
const path = require('path')
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
const configPath = path.join(process.cwd(), '.licenseguardrc')
|
|
43
|
+
if (!fs.existsSync(configPath)) process.exit(0)
|
|
44
|
+
|
|
45
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'))
|
|
46
|
+
const blue = '\\x1b[34m'
|
|
47
|
+
const reset = '\\x1b[0m'
|
|
48
|
+
|
|
49
|
+
console.log(\`\${blue}âšī¸ Reminder: This project is licensed under \${config.license.toUpperCase()}\${reset}\`)
|
|
50
|
+
} catch (e) {
|
|
51
|
+
// Silent fail - never block git
|
|
52
|
+
}
|
|
53
|
+
process.exit(0)
|
|
54
|
+
`
|
|
55
|
+
|
|
56
|
+
function setupGlobalHooks() {
|
|
57
|
+
try {
|
|
58
|
+
// Only setup global hooks when installed globally
|
|
59
|
+
// Check if we're in a global npm directory
|
|
60
|
+
const isGlobalInstall =
|
|
61
|
+
process.env.npm_config_global === 'true' ||
|
|
62
|
+
__dirname.includes('npm-global') ||
|
|
63
|
+
__dirname.includes('/usr/lib/node_modules') ||
|
|
64
|
+
__dirname.includes('/usr/local/lib/node_modules')
|
|
65
|
+
|
|
66
|
+
if (!isGlobalInstall) {
|
|
67
|
+
// Local install, skip global hooks setup
|
|
68
|
+
return
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Create template directories
|
|
72
|
+
if (!fs.existsSync(hooksDir)) {
|
|
73
|
+
fs.mkdirSync(hooksDir, { recursive: true })
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Write hook files
|
|
77
|
+
const hooks = [
|
|
78
|
+
{ name: 'post-checkout', script: postCheckoutHook },
|
|
79
|
+
{ name: 'pre-commit', script: preCommitHook },
|
|
80
|
+
]
|
|
81
|
+
|
|
82
|
+
for (const hook of hooks) {
|
|
83
|
+
const hookPath = path.join(hooksDir, hook.name)
|
|
84
|
+
|
|
85
|
+
// Check for existing hooks
|
|
86
|
+
if (fs.existsSync(hookPath)) {
|
|
87
|
+
const existing = fs.readFileSync(hookPath, 'utf8')
|
|
88
|
+
if (!existing.includes('.licenseguardrc')) {
|
|
89
|
+
// Not our hook, create variant
|
|
90
|
+
const variantPath = path.join(hooksDir, `licenseguard-${hook.name}`)
|
|
91
|
+
fs.writeFileSync(variantPath, hook.script, 'utf8')
|
|
92
|
+
fs.chmodSync(variantPath, 0o755)
|
|
93
|
+
console.log(`â ī¸ Existing ${hook.name} found, created licenseguard-${hook.name}`)
|
|
94
|
+
}
|
|
95
|
+
// Our hook already exists, skip
|
|
96
|
+
} else {
|
|
97
|
+
fs.writeFileSync(hookPath, hook.script, 'utf8')
|
|
98
|
+
fs.chmodSync(hookPath, 0o755)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Configure git to use template directory
|
|
103
|
+
execSync(`git config --global init.templateDir "${templateDir}"`, {
|
|
104
|
+
stdio: 'pipe',
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
console.log('â LicenseGuard global hooks installed')
|
|
108
|
+
console.log(` Template directory: ${templateDir}`)
|
|
109
|
+
console.log(' Now every git clone/init will check for .licenseguardrc')
|
|
110
|
+
} catch (error) {
|
|
111
|
+
// Don't fail installation if hooks setup fails
|
|
112
|
+
console.log('â ī¸ Could not setup global hooks:', error.message)
|
|
113
|
+
console.log(' LicenseGuard still works, run licenseguard --setup manually')
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
setupGlobalHooks()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "licenseguard-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "License setup & compliance helper for developers",
|
|
5
5
|
"bin": {
|
|
6
6
|
"licenseguard": "./bin/licenseguard.js"
|
|
@@ -9,11 +9,7 @@
|
|
|
9
9
|
"doc": "docs"
|
|
10
10
|
},
|
|
11
11
|
"scripts": {
|
|
12
|
-
"
|
|
13
|
-
"test:watch": "jest --watch",
|
|
14
|
-
"test:coverage": "jest --coverage",
|
|
15
|
-
"lint": "eslint .",
|
|
16
|
-
"format": "prettier --write ."
|
|
12
|
+
"postinstall": "node lib/postinstall.js"
|
|
17
13
|
},
|
|
18
14
|
"keywords": [
|
|
19
15
|
"license",
|
|
@@ -29,11 +25,5 @@
|
|
|
29
25
|
"chalk": "^4.1.2",
|
|
30
26
|
"commander": "^11.1.0",
|
|
31
27
|
"inquirer": "^8.2.5"
|
|
32
|
-
},
|
|
33
|
-
"devDependencies": {
|
|
34
|
-
"eslint": "^8.54.0",
|
|
35
|
-
"jest": "^29.7.0",
|
|
36
|
-
"mock-fs": "^5.2.0",
|
|
37
|
-
"prettier": "^3.1.0"
|
|
38
28
|
}
|
|
39
29
|
}
|