hale-commenting-system 2.1.0 → 2.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 +1 -1
- package/bin/generators.d.ts +10 -8
- package/bin/generators.js +88 -9
- package/bin/onboarding.js +144 -93
- package/dist/cli/generators.d.ts +10 -8
- package/dist/cli/generators.js +88 -9
- package/dist/cli/onboarding.js +144 -93
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ After installation, the onboarding flow will automatically start to help you con
|
|
|
20
20
|
|
|
21
21
|
## Requirements
|
|
22
22
|
|
|
23
|
-
- PatternFly Seed project
|
|
23
|
+
- PatternFly Seed project with PatternFly v6+ (`@patternfly/react-core` ^6.0.0)
|
|
24
24
|
- GitHub account with OAuth app
|
|
25
25
|
- Jira access (Red Hat Jira: issues.redhat.com)
|
|
26
26
|
|
package/bin/generators.d.ts
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
interface GitHubConfig {
|
|
2
|
-
clientId
|
|
3
|
-
clientSecret
|
|
4
|
-
owner
|
|
5
|
-
repo
|
|
2
|
+
clientId?: string;
|
|
3
|
+
clientSecret?: string;
|
|
4
|
+
owner?: string;
|
|
5
|
+
repo?: string;
|
|
6
6
|
}
|
|
7
7
|
interface JiraConfig {
|
|
8
|
-
baseUrl
|
|
9
|
-
apiToken
|
|
8
|
+
baseUrl?: string;
|
|
9
|
+
apiToken?: string;
|
|
10
10
|
email?: string;
|
|
11
11
|
}
|
|
12
12
|
interface Config {
|
|
13
|
-
github: GitHubConfig;
|
|
14
|
-
jira: JiraConfig;
|
|
13
|
+
github: GitHubConfig | null;
|
|
14
|
+
jira: JiraConfig | null;
|
|
15
|
+
owner: string;
|
|
16
|
+
repo: string;
|
|
15
17
|
}
|
|
16
18
|
export declare function generateFiles(config: Config): Promise<void>;
|
|
17
19
|
export declare function integrateIntoProject(): Promise<void>;
|
package/bin/generators.js
CHANGED
|
@@ -41,16 +41,50 @@ async function generateFiles(config) {
|
|
|
41
41
|
const cwd = process.cwd();
|
|
42
42
|
// Generate .env file (client-safe)
|
|
43
43
|
const envPath = path.join(cwd, '.env');
|
|
44
|
-
|
|
44
|
+
let envContent = `# Hale Commenting System Configuration
|
|
45
|
+
# Client-safe environment variables (these are exposed to the browser)
|
|
46
|
+
|
|
47
|
+
`;
|
|
48
|
+
if (config.github && config.github.clientId) {
|
|
49
|
+
envContent += `# GitHub OAuth (client-side; safe to expose)
|
|
50
|
+
# Get your Client ID from: https://github.com/settings/developers
|
|
51
|
+
# 1. Click "New OAuth App"
|
|
52
|
+
# 2. Fill in the form (Homepage: http://localhost:9000, Callback: http://localhost:9000/api/github-oauth-callback)
|
|
53
|
+
# 3. Copy the Client ID
|
|
45
54
|
VITE_GITHUB_CLIENT_ID=${config.github.clientId}
|
|
46
55
|
|
|
47
56
|
# Target repo for Issues/Comments
|
|
48
|
-
VITE_GITHUB_OWNER=${config.github.owner}
|
|
49
|
-
VITE_GITHUB_REPO=${config.github.repo}
|
|
57
|
+
VITE_GITHUB_OWNER=${config.github.owner || config.owner}
|
|
58
|
+
VITE_GITHUB_REPO=${config.github.repo || config.repo}
|
|
59
|
+
|
|
60
|
+
`;
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
envContent += `# GitHub OAuth (client-side; safe to expose)
|
|
64
|
+
# Get your Client ID from: https://github.com/settings/developers
|
|
65
|
+
# 1. Click "New OAuth App"
|
|
66
|
+
# 2. Fill in the form (Homepage: http://localhost:9000, Callback: http://localhost:9000/api/github-oauth-callback)
|
|
67
|
+
# 3. Copy the Client ID
|
|
68
|
+
VITE_GITHUB_CLIENT_ID=
|
|
69
|
+
|
|
70
|
+
# Target repo for Issues/Comments
|
|
71
|
+
VITE_GITHUB_OWNER=${config.owner}
|
|
72
|
+
VITE_GITHUB_REPO=${config.repo}
|
|
50
73
|
|
|
51
|
-
|
|
74
|
+
`;
|
|
75
|
+
}
|
|
76
|
+
if (config.jira && config.jira.baseUrl) {
|
|
77
|
+
envContent += `# Jira Base URL
|
|
78
|
+
# For Red Hat Jira, use: https://issues.redhat.com
|
|
52
79
|
VITE_JIRA_BASE_URL=${config.jira.baseUrl}
|
|
53
80
|
`;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
envContent += `# Jira Base URL
|
|
84
|
+
# For Red Hat Jira, use: https://issues.redhat.com
|
|
85
|
+
VITE_JIRA_BASE_URL=
|
|
86
|
+
`;
|
|
87
|
+
}
|
|
54
88
|
// Check if .env exists and append or create
|
|
55
89
|
if (fs.existsSync(envPath)) {
|
|
56
90
|
const existing = fs.readFileSync(envPath, 'utf-8');
|
|
@@ -67,15 +101,56 @@ VITE_JIRA_BASE_URL=${config.jira.baseUrl}
|
|
|
67
101
|
fs.writeFileSync(envPath, envContent);
|
|
68
102
|
console.log(' ✅ Created .env file');
|
|
69
103
|
}
|
|
104
|
+
// Note about empty values
|
|
105
|
+
if (!config.github || !config.jira) {
|
|
106
|
+
console.log(' ℹ️ Some values are empty - see comments in .env for setup instructions');
|
|
107
|
+
}
|
|
70
108
|
// Generate .env.server file (secrets)
|
|
71
109
|
const envServerPath = path.join(cwd, '.env.server');
|
|
72
|
-
let envServerContent = `#
|
|
110
|
+
let envServerContent = `# Hale Commenting System - Server Secrets
|
|
111
|
+
# ⚠️ DO NOT COMMIT THIS FILE - It contains sensitive credentials
|
|
112
|
+
# This file is automatically added to .gitignore
|
|
113
|
+
|
|
114
|
+
`;
|
|
115
|
+
if (config.github && config.github.clientSecret) {
|
|
116
|
+
envServerContent += `# GitHub OAuth Client Secret (server-only)
|
|
117
|
+
# Get this from your GitHub OAuth App settings: https://github.com/settings/developers
|
|
118
|
+
# Click on your OAuth App, then "Generate a new client secret"
|
|
73
119
|
GITHUB_CLIENT_SECRET=${config.github.clientSecret}
|
|
74
120
|
|
|
75
|
-
|
|
121
|
+
`;
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
envServerContent += `# GitHub OAuth Client Secret (server-only)
|
|
125
|
+
# Get this from your GitHub OAuth App settings: https://github.com/settings/developers
|
|
126
|
+
# Click on your OAuth App, then "Generate a new client secret"
|
|
127
|
+
GITHUB_CLIENT_SECRET=
|
|
128
|
+
|
|
129
|
+
`;
|
|
130
|
+
}
|
|
131
|
+
if (config.jira && config.jira.apiToken) {
|
|
132
|
+
envServerContent += `# Jira API Token (server-only)
|
|
133
|
+
# For Red Hat Jira, generate a Personal Access Token:
|
|
134
|
+
# 1. Visit: https://issues.redhat.com/secure/ViewProfile.jspa
|
|
135
|
+
# 2. Click "Personal Access Tokens" in the left sidebar
|
|
136
|
+
# 3. Click "Create token"
|
|
137
|
+
# 4. Give it a name and remove expiration
|
|
138
|
+
# 5. Copy the token
|
|
76
139
|
JIRA_API_TOKEN=${config.jira.apiToken}
|
|
77
140
|
`;
|
|
78
|
-
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
envServerContent += `# Jira API Token (server-only)
|
|
144
|
+
# For Red Hat Jira, generate a Personal Access Token:
|
|
145
|
+
# 1. Visit: https://issues.redhat.com/secure/ViewProfile.jspa
|
|
146
|
+
# 2. Click "Personal Access Tokens" in the left sidebar
|
|
147
|
+
# 3. Click "Create token"
|
|
148
|
+
# 4. Give it a name and remove expiration
|
|
149
|
+
# 5. Copy the token
|
|
150
|
+
JIRA_API_TOKEN=
|
|
151
|
+
`;
|
|
152
|
+
}
|
|
153
|
+
if (config.jira && config.jira.email) {
|
|
79
154
|
envServerContent += `JIRA_EMAIL=${config.jira.email}\n`;
|
|
80
155
|
}
|
|
81
156
|
if (fs.existsSync(envServerPath)) {
|
|
@@ -92,6 +167,10 @@ JIRA_API_TOKEN=${config.jira.apiToken}
|
|
|
92
167
|
fs.writeFileSync(envServerPath, envServerContent);
|
|
93
168
|
console.log(' ✅ Created .env.server file');
|
|
94
169
|
}
|
|
170
|
+
// Note about empty values
|
|
171
|
+
if (!config.github || !config.jira) {
|
|
172
|
+
console.log(' ℹ️ Some values are empty - see comments in .env.server for setup instructions');
|
|
173
|
+
}
|
|
95
174
|
// Ensure .env.server is in .gitignore
|
|
96
175
|
const gitignorePath = path.join(cwd, '.gitignore');
|
|
97
176
|
if (fs.existsSync(gitignorePath)) {
|
|
@@ -121,8 +200,8 @@ async function integrateIntoProject() {
|
|
|
121
200
|
return;
|
|
122
201
|
}
|
|
123
202
|
// Read the template
|
|
124
|
-
// In compiled output, templates
|
|
125
|
-
const packageRoot = path.resolve(__dirname, '
|
|
203
|
+
// In compiled output, templates are in the package root (same level as bin/)
|
|
204
|
+
const packageRoot = path.resolve(__dirname, '..');
|
|
126
205
|
const templatePath = path.join(packageRoot, 'templates', 'webpack-middleware.js');
|
|
127
206
|
if (!fs.existsSync(templatePath)) {
|
|
128
207
|
console.log(' ⚠️ Template file not found. Manual integration required.');
|
package/bin/onboarding.js
CHANGED
|
@@ -228,117 +228,168 @@ async function runOnboarding() {
|
|
|
228
228
|
repo = repoAnswers.repo;
|
|
229
229
|
}
|
|
230
230
|
}
|
|
231
|
-
// Step 2: GitHub OAuth Setup
|
|
232
|
-
console.log('\n📦 Step 2: GitHub
|
|
233
|
-
console.log('
|
|
234
|
-
console.log('
|
|
235
|
-
|
|
236
|
-
console.log('1. Visit: https://github.com/settings/developers');
|
|
237
|
-
console.log('2. Click "New OAuth App"');
|
|
238
|
-
console.log('3. Fill in the form:');
|
|
239
|
-
console.log(' - Application name: Your app name (e.g., "My Design Comments")');
|
|
240
|
-
console.log(' - Homepage URL: http://localhost:9000 (or your dev server URL)');
|
|
241
|
-
console.log(' - Authorization callback URL: http://localhost:9000/api/github-oauth-callback');
|
|
242
|
-
console.log('4. Click "Register application"');
|
|
243
|
-
console.log('5. Copy the Client ID and generate a Client Secret\n');
|
|
244
|
-
const githubAnswers = await inquirer_1.default.prompt([
|
|
231
|
+
// Step 2: GitHub OAuth Setup (Optional)
|
|
232
|
+
console.log('\n📦 Step 2: GitHub Integration (Optional)\n');
|
|
233
|
+
console.log('GitHub integration allows comments to sync with GitHub Issues.');
|
|
234
|
+
console.log('You can set this up now or add it later.\n');
|
|
235
|
+
const setupGitHub = await inquirer_1.default.prompt([
|
|
245
236
|
{
|
|
246
|
-
type: '
|
|
247
|
-
name: '
|
|
248
|
-
message: 'GitHub
|
|
249
|
-
|
|
250
|
-
if (!input.trim())
|
|
251
|
-
return 'Client ID is required';
|
|
252
|
-
return true;
|
|
253
|
-
}
|
|
254
|
-
},
|
|
255
|
-
{
|
|
256
|
-
type: 'password',
|
|
257
|
-
name: 'clientSecret',
|
|
258
|
-
message: 'GitHub OAuth Client Secret:',
|
|
259
|
-
mask: '*',
|
|
260
|
-
validate: (input) => {
|
|
261
|
-
if (!input.trim())
|
|
262
|
-
return 'Client Secret is required';
|
|
263
|
-
return true;
|
|
264
|
-
}
|
|
237
|
+
type: 'confirm',
|
|
238
|
+
name: 'setup',
|
|
239
|
+
message: 'Do you want to set up GitHub integration now?',
|
|
240
|
+
default: true
|
|
265
241
|
}
|
|
266
242
|
]);
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
console.
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
if (!input.trim())
|
|
290
|
-
return 'Base URL is required';
|
|
291
|
-
try {
|
|
292
|
-
new URL(input);
|
|
243
|
+
let githubConfig = null;
|
|
244
|
+
let githubValid = false;
|
|
245
|
+
if (setupGitHub.setup) {
|
|
246
|
+
console.log('\nTo sync comments with GitHub Issues, we need to authenticate with GitHub.');
|
|
247
|
+
console.log('This requires creating a GitHub OAuth App.\n');
|
|
248
|
+
console.log('Instructions:');
|
|
249
|
+
console.log('1. Visit: https://github.com/settings/developers');
|
|
250
|
+
console.log('2. Click "New OAuth App"');
|
|
251
|
+
console.log('3. Fill in the form:');
|
|
252
|
+
console.log(' - Application name: Your app name (e.g., "My Design Comments")');
|
|
253
|
+
console.log(' - Homepage URL: http://localhost:9000 (or your dev server URL)');
|
|
254
|
+
console.log(' - Authorization callback URL: http://localhost:9000/api/github-oauth-callback');
|
|
255
|
+
console.log('4. Click "Register application"');
|
|
256
|
+
console.log('5. Copy the Client ID and generate a Client Secret\n');
|
|
257
|
+
const githubAnswers = await inquirer_1.default.prompt([
|
|
258
|
+
{
|
|
259
|
+
type: 'input',
|
|
260
|
+
name: 'clientId',
|
|
261
|
+
message: 'GitHub OAuth Client ID:',
|
|
262
|
+
validate: (input) => {
|
|
263
|
+
if (!input.trim())
|
|
264
|
+
return 'Client ID is required';
|
|
293
265
|
return true;
|
|
294
266
|
}
|
|
295
|
-
|
|
296
|
-
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
type: 'password',
|
|
270
|
+
name: 'clientSecret',
|
|
271
|
+
message: 'GitHub OAuth Client Secret:',
|
|
272
|
+
mask: '*',
|
|
273
|
+
validate: (input) => {
|
|
274
|
+
if (!input.trim())
|
|
275
|
+
return 'Client Secret is required';
|
|
276
|
+
return true;
|
|
297
277
|
}
|
|
298
278
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
if (!input.trim())
|
|
307
|
-
return 'API Token is required';
|
|
308
|
-
return true;
|
|
309
|
-
}
|
|
279
|
+
]);
|
|
280
|
+
// Validate GitHub credentials
|
|
281
|
+
console.log('\n🔍 Validating GitHub credentials...');
|
|
282
|
+
githubValid = await validators.validateGitHubCredentials(githubAnswers.clientId, githubAnswers.clientSecret, owner, repo);
|
|
283
|
+
if (!githubValid) {
|
|
284
|
+
console.error('❌ GitHub validation failed. Please check your credentials and try again.');
|
|
285
|
+
process.exit(1);
|
|
310
286
|
}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
console.log('\n🔍 Validating Jira credentials...');
|
|
314
|
-
const jiraValid = await validators.validateJiraCredentials(jiraAnswers.baseUrl, jiraAnswers.apiToken, undefined // No email for Bearer token
|
|
315
|
-
);
|
|
316
|
-
if (!jiraValid) {
|
|
317
|
-
console.error('❌ Jira validation failed. Please check your credentials and try again.');
|
|
318
|
-
process.exit(1);
|
|
319
|
-
}
|
|
320
|
-
console.log('✅ Jira credentials validated!\n');
|
|
321
|
-
// Step 4: Generate files
|
|
322
|
-
console.log('📝 Step 4: Generating configuration files...\n');
|
|
323
|
-
await generators.generateFiles({
|
|
324
|
-
github: {
|
|
287
|
+
console.log('✅ GitHub credentials validated!\n');
|
|
288
|
+
githubConfig = {
|
|
325
289
|
clientId: githubAnswers.clientId,
|
|
326
290
|
clientSecret: githubAnswers.clientSecret,
|
|
327
291
|
owner: owner,
|
|
328
292
|
repo: repo
|
|
329
|
-
}
|
|
330
|
-
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
console.log('\n⏭️ Skipping GitHub setup. You can add it later by editing .env and .env.server files.\n');
|
|
297
|
+
}
|
|
298
|
+
// Step 3: Jira Setup (Optional)
|
|
299
|
+
console.log('🎫 Step 3: Jira Integration (Optional)\n');
|
|
300
|
+
console.log('Jira integration allows you to link Jira tickets to pages in your design.');
|
|
301
|
+
console.log('You can set this up now or add it later.\n');
|
|
302
|
+
const setupJira = await inquirer_1.default.prompt([
|
|
303
|
+
{
|
|
304
|
+
type: 'confirm',
|
|
305
|
+
name: 'setup',
|
|
306
|
+
message: 'Do you want to set up Jira integration now?',
|
|
307
|
+
default: true
|
|
308
|
+
}
|
|
309
|
+
]);
|
|
310
|
+
let jiraConfig = null;
|
|
311
|
+
let jiraValid = false;
|
|
312
|
+
if (setupJira.setup) {
|
|
313
|
+
console.log('\nFor Red Hat Jira, generate a Personal Access Token:');
|
|
314
|
+
console.log('1. Visit: https://issues.redhat.com/secure/ViewProfile.jspa');
|
|
315
|
+
console.log('2. Click "Personal Access Tokens" in the left sidebar');
|
|
316
|
+
console.log('3. Click "Create token"');
|
|
317
|
+
console.log('4. Give it a name (e.g., "Hale Commenting System")');
|
|
318
|
+
console.log('5. Remove expiration (or set a long expiration)');
|
|
319
|
+
console.log('6. Click "Create" and copy the token\n');
|
|
320
|
+
console.log('Note: We use Bearer token authentication (no email required for Red Hat Jira).\n');
|
|
321
|
+
const jiraAnswers = await inquirer_1.default.prompt([
|
|
322
|
+
{
|
|
323
|
+
type: 'input',
|
|
324
|
+
name: 'baseUrl',
|
|
325
|
+
message: 'Jira Base URL (press Enter for Red Hat Jira):',
|
|
326
|
+
default: 'https://issues.redhat.com',
|
|
327
|
+
validate: (input) => {
|
|
328
|
+
if (!input.trim())
|
|
329
|
+
return 'Base URL is required';
|
|
330
|
+
try {
|
|
331
|
+
new URL(input);
|
|
332
|
+
return true;
|
|
333
|
+
}
|
|
334
|
+
catch {
|
|
335
|
+
return 'Please enter a valid URL';
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
},
|
|
339
|
+
{
|
|
340
|
+
type: 'password',
|
|
341
|
+
name: 'apiToken',
|
|
342
|
+
message: 'Jira API Token:',
|
|
343
|
+
mask: '*',
|
|
344
|
+
validate: (input) => {
|
|
345
|
+
if (!input.trim())
|
|
346
|
+
return 'API Token is required';
|
|
347
|
+
return true;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
]);
|
|
351
|
+
// Validate Jira credentials
|
|
352
|
+
console.log('\n🔍 Validating Jira credentials...');
|
|
353
|
+
jiraValid = await validators.validateJiraCredentials(jiraAnswers.baseUrl, jiraAnswers.apiToken, undefined // No email for Bearer token
|
|
354
|
+
);
|
|
355
|
+
if (!jiraValid) {
|
|
356
|
+
console.error('❌ Jira validation failed. Please check your credentials and try again.');
|
|
357
|
+
process.exit(1);
|
|
358
|
+
}
|
|
359
|
+
console.log('✅ Jira credentials validated!\n');
|
|
360
|
+
jiraConfig = {
|
|
331
361
|
baseUrl: jiraAnswers.baseUrl,
|
|
332
362
|
apiToken: jiraAnswers.apiToken,
|
|
333
|
-
email: undefined
|
|
334
|
-
}
|
|
363
|
+
email: undefined
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
else {
|
|
367
|
+
console.log('\n⏭️ Skipping Jira setup. You can add it later by editing .env and .env.server files.\n');
|
|
368
|
+
}
|
|
369
|
+
// Step 4: Generate files
|
|
370
|
+
console.log('📝 Step 4: Generating configuration files...\n');
|
|
371
|
+
await generators.generateFiles({
|
|
372
|
+
github: githubConfig,
|
|
373
|
+
jira: jiraConfig,
|
|
374
|
+
owner: owner,
|
|
375
|
+
repo: repo
|
|
335
376
|
});
|
|
336
377
|
// Step 5: Integrate into project
|
|
337
378
|
console.log('🔧 Step 5: Integrating into PatternFly Seed project...\n');
|
|
338
379
|
await generators.integrateIntoProject();
|
|
339
380
|
console.log('\n✅ Setup complete!');
|
|
340
381
|
console.log('\nNext steps:');
|
|
341
|
-
console.log('1.
|
|
342
|
-
console.log('
|
|
343
|
-
console.log('
|
|
382
|
+
console.log('1. Start your dev server: npm run start:dev');
|
|
383
|
+
console.log(' (If it\'s already running, restart it to load the new configuration)');
|
|
384
|
+
console.log('2. The commenting system will be available in your app!\n');
|
|
385
|
+
if (!githubConfig || !jiraConfig) {
|
|
386
|
+
console.log('📝 To add integrations later:');
|
|
387
|
+
if (!githubConfig) {
|
|
388
|
+
console.log(' • GitHub: Edit .env and .env.server files (see comments in files for instructions)');
|
|
389
|
+
}
|
|
390
|
+
if (!jiraConfig) {
|
|
391
|
+
console.log(' • Jira: Edit .env and .env.server files (see comments in files for instructions)');
|
|
392
|
+
}
|
|
393
|
+
console.log(' • Then restart your dev server\n');
|
|
394
|
+
}
|
|
344
395
|
}
|
package/dist/cli/generators.d.ts
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
interface GitHubConfig {
|
|
2
|
-
clientId
|
|
3
|
-
clientSecret
|
|
4
|
-
owner
|
|
5
|
-
repo
|
|
2
|
+
clientId?: string;
|
|
3
|
+
clientSecret?: string;
|
|
4
|
+
owner?: string;
|
|
5
|
+
repo?: string;
|
|
6
6
|
}
|
|
7
7
|
interface JiraConfig {
|
|
8
|
-
baseUrl
|
|
9
|
-
apiToken
|
|
8
|
+
baseUrl?: string;
|
|
9
|
+
apiToken?: string;
|
|
10
10
|
email?: string;
|
|
11
11
|
}
|
|
12
12
|
interface Config {
|
|
13
|
-
github: GitHubConfig;
|
|
14
|
-
jira: JiraConfig;
|
|
13
|
+
github: GitHubConfig | null;
|
|
14
|
+
jira: JiraConfig | null;
|
|
15
|
+
owner: string;
|
|
16
|
+
repo: string;
|
|
15
17
|
}
|
|
16
18
|
export declare function generateFiles(config: Config): Promise<void>;
|
|
17
19
|
export declare function integrateIntoProject(): Promise<void>;
|
package/dist/cli/generators.js
CHANGED
|
@@ -41,16 +41,50 @@ async function generateFiles(config) {
|
|
|
41
41
|
const cwd = process.cwd();
|
|
42
42
|
// Generate .env file (client-safe)
|
|
43
43
|
const envPath = path.join(cwd, '.env');
|
|
44
|
-
|
|
44
|
+
let envContent = `# Hale Commenting System Configuration
|
|
45
|
+
# Client-safe environment variables (these are exposed to the browser)
|
|
46
|
+
|
|
47
|
+
`;
|
|
48
|
+
if (config.github && config.github.clientId) {
|
|
49
|
+
envContent += `# GitHub OAuth (client-side; safe to expose)
|
|
50
|
+
# Get your Client ID from: https://github.com/settings/developers
|
|
51
|
+
# 1. Click "New OAuth App"
|
|
52
|
+
# 2. Fill in the form (Homepage: http://localhost:9000, Callback: http://localhost:9000/api/github-oauth-callback)
|
|
53
|
+
# 3. Copy the Client ID
|
|
45
54
|
VITE_GITHUB_CLIENT_ID=${config.github.clientId}
|
|
46
55
|
|
|
47
56
|
# Target repo for Issues/Comments
|
|
48
|
-
VITE_GITHUB_OWNER=${config.github.owner}
|
|
49
|
-
VITE_GITHUB_REPO=${config.github.repo}
|
|
57
|
+
VITE_GITHUB_OWNER=${config.github.owner || config.owner}
|
|
58
|
+
VITE_GITHUB_REPO=${config.github.repo || config.repo}
|
|
59
|
+
|
|
60
|
+
`;
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
envContent += `# GitHub OAuth (client-side; safe to expose)
|
|
64
|
+
# Get your Client ID from: https://github.com/settings/developers
|
|
65
|
+
# 1. Click "New OAuth App"
|
|
66
|
+
# 2. Fill in the form (Homepage: http://localhost:9000, Callback: http://localhost:9000/api/github-oauth-callback)
|
|
67
|
+
# 3. Copy the Client ID
|
|
68
|
+
VITE_GITHUB_CLIENT_ID=
|
|
69
|
+
|
|
70
|
+
# Target repo for Issues/Comments
|
|
71
|
+
VITE_GITHUB_OWNER=${config.owner}
|
|
72
|
+
VITE_GITHUB_REPO=${config.repo}
|
|
50
73
|
|
|
51
|
-
|
|
74
|
+
`;
|
|
75
|
+
}
|
|
76
|
+
if (config.jira && config.jira.baseUrl) {
|
|
77
|
+
envContent += `# Jira Base URL
|
|
78
|
+
# For Red Hat Jira, use: https://issues.redhat.com
|
|
52
79
|
VITE_JIRA_BASE_URL=${config.jira.baseUrl}
|
|
53
80
|
`;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
envContent += `# Jira Base URL
|
|
84
|
+
# For Red Hat Jira, use: https://issues.redhat.com
|
|
85
|
+
VITE_JIRA_BASE_URL=
|
|
86
|
+
`;
|
|
87
|
+
}
|
|
54
88
|
// Check if .env exists and append or create
|
|
55
89
|
if (fs.existsSync(envPath)) {
|
|
56
90
|
const existing = fs.readFileSync(envPath, 'utf-8');
|
|
@@ -67,15 +101,56 @@ VITE_JIRA_BASE_URL=${config.jira.baseUrl}
|
|
|
67
101
|
fs.writeFileSync(envPath, envContent);
|
|
68
102
|
console.log(' ✅ Created .env file');
|
|
69
103
|
}
|
|
104
|
+
// Note about empty values
|
|
105
|
+
if (!config.github || !config.jira) {
|
|
106
|
+
console.log(' ℹ️ Some values are empty - see comments in .env for setup instructions');
|
|
107
|
+
}
|
|
70
108
|
// Generate .env.server file (secrets)
|
|
71
109
|
const envServerPath = path.join(cwd, '.env.server');
|
|
72
|
-
let envServerContent = `#
|
|
110
|
+
let envServerContent = `# Hale Commenting System - Server Secrets
|
|
111
|
+
# ⚠️ DO NOT COMMIT THIS FILE - It contains sensitive credentials
|
|
112
|
+
# This file is automatically added to .gitignore
|
|
113
|
+
|
|
114
|
+
`;
|
|
115
|
+
if (config.github && config.github.clientSecret) {
|
|
116
|
+
envServerContent += `# GitHub OAuth Client Secret (server-only)
|
|
117
|
+
# Get this from your GitHub OAuth App settings: https://github.com/settings/developers
|
|
118
|
+
# Click on your OAuth App, then "Generate a new client secret"
|
|
73
119
|
GITHUB_CLIENT_SECRET=${config.github.clientSecret}
|
|
74
120
|
|
|
75
|
-
|
|
121
|
+
`;
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
envServerContent += `# GitHub OAuth Client Secret (server-only)
|
|
125
|
+
# Get this from your GitHub OAuth App settings: https://github.com/settings/developers
|
|
126
|
+
# Click on your OAuth App, then "Generate a new client secret"
|
|
127
|
+
GITHUB_CLIENT_SECRET=
|
|
128
|
+
|
|
129
|
+
`;
|
|
130
|
+
}
|
|
131
|
+
if (config.jira && config.jira.apiToken) {
|
|
132
|
+
envServerContent += `# Jira API Token (server-only)
|
|
133
|
+
# For Red Hat Jira, generate a Personal Access Token:
|
|
134
|
+
# 1. Visit: https://issues.redhat.com/secure/ViewProfile.jspa
|
|
135
|
+
# 2. Click "Personal Access Tokens" in the left sidebar
|
|
136
|
+
# 3. Click "Create token"
|
|
137
|
+
# 4. Give it a name and remove expiration
|
|
138
|
+
# 5. Copy the token
|
|
76
139
|
JIRA_API_TOKEN=${config.jira.apiToken}
|
|
77
140
|
`;
|
|
78
|
-
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
envServerContent += `# Jira API Token (server-only)
|
|
144
|
+
# For Red Hat Jira, generate a Personal Access Token:
|
|
145
|
+
# 1. Visit: https://issues.redhat.com/secure/ViewProfile.jspa
|
|
146
|
+
# 2. Click "Personal Access Tokens" in the left sidebar
|
|
147
|
+
# 3. Click "Create token"
|
|
148
|
+
# 4. Give it a name and remove expiration
|
|
149
|
+
# 5. Copy the token
|
|
150
|
+
JIRA_API_TOKEN=
|
|
151
|
+
`;
|
|
152
|
+
}
|
|
153
|
+
if (config.jira && config.jira.email) {
|
|
79
154
|
envServerContent += `JIRA_EMAIL=${config.jira.email}\n`;
|
|
80
155
|
}
|
|
81
156
|
if (fs.existsSync(envServerPath)) {
|
|
@@ -92,6 +167,10 @@ JIRA_API_TOKEN=${config.jira.apiToken}
|
|
|
92
167
|
fs.writeFileSync(envServerPath, envServerContent);
|
|
93
168
|
console.log(' ✅ Created .env.server file');
|
|
94
169
|
}
|
|
170
|
+
// Note about empty values
|
|
171
|
+
if (!config.github || !config.jira) {
|
|
172
|
+
console.log(' ℹ️ Some values are empty - see comments in .env.server for setup instructions');
|
|
173
|
+
}
|
|
95
174
|
// Ensure .env.server is in .gitignore
|
|
96
175
|
const gitignorePath = path.join(cwd, '.gitignore');
|
|
97
176
|
if (fs.existsSync(gitignorePath)) {
|
|
@@ -121,8 +200,8 @@ async function integrateIntoProject() {
|
|
|
121
200
|
return;
|
|
122
201
|
}
|
|
123
202
|
// Read the template
|
|
124
|
-
// In compiled output, templates
|
|
125
|
-
const packageRoot = path.resolve(__dirname, '
|
|
203
|
+
// In compiled output, templates are in the package root (same level as bin/)
|
|
204
|
+
const packageRoot = path.resolve(__dirname, '..');
|
|
126
205
|
const templatePath = path.join(packageRoot, 'templates', 'webpack-middleware.js');
|
|
127
206
|
if (!fs.existsSync(templatePath)) {
|
|
128
207
|
console.log(' ⚠️ Template file not found. Manual integration required.');
|
package/dist/cli/onboarding.js
CHANGED
|
@@ -228,117 +228,168 @@ async function runOnboarding() {
|
|
|
228
228
|
repo = repoAnswers.repo;
|
|
229
229
|
}
|
|
230
230
|
}
|
|
231
|
-
// Step 2: GitHub OAuth Setup
|
|
232
|
-
console.log('\n📦 Step 2: GitHub
|
|
233
|
-
console.log('
|
|
234
|
-
console.log('
|
|
235
|
-
|
|
236
|
-
console.log('1. Visit: https://github.com/settings/developers');
|
|
237
|
-
console.log('2. Click "New OAuth App"');
|
|
238
|
-
console.log('3. Fill in the form:');
|
|
239
|
-
console.log(' - Application name: Your app name (e.g., "My Design Comments")');
|
|
240
|
-
console.log(' - Homepage URL: http://localhost:9000 (or your dev server URL)');
|
|
241
|
-
console.log(' - Authorization callback URL: http://localhost:9000/api/github-oauth-callback');
|
|
242
|
-
console.log('4. Click "Register application"');
|
|
243
|
-
console.log('5. Copy the Client ID and generate a Client Secret\n');
|
|
244
|
-
const githubAnswers = await inquirer_1.default.prompt([
|
|
231
|
+
// Step 2: GitHub OAuth Setup (Optional)
|
|
232
|
+
console.log('\n📦 Step 2: GitHub Integration (Optional)\n');
|
|
233
|
+
console.log('GitHub integration allows comments to sync with GitHub Issues.');
|
|
234
|
+
console.log('You can set this up now or add it later.\n');
|
|
235
|
+
const setupGitHub = await inquirer_1.default.prompt([
|
|
245
236
|
{
|
|
246
|
-
type: '
|
|
247
|
-
name: '
|
|
248
|
-
message: 'GitHub
|
|
249
|
-
|
|
250
|
-
if (!input.trim())
|
|
251
|
-
return 'Client ID is required';
|
|
252
|
-
return true;
|
|
253
|
-
}
|
|
254
|
-
},
|
|
255
|
-
{
|
|
256
|
-
type: 'password',
|
|
257
|
-
name: 'clientSecret',
|
|
258
|
-
message: 'GitHub OAuth Client Secret:',
|
|
259
|
-
mask: '*',
|
|
260
|
-
validate: (input) => {
|
|
261
|
-
if (!input.trim())
|
|
262
|
-
return 'Client Secret is required';
|
|
263
|
-
return true;
|
|
264
|
-
}
|
|
237
|
+
type: 'confirm',
|
|
238
|
+
name: 'setup',
|
|
239
|
+
message: 'Do you want to set up GitHub integration now?',
|
|
240
|
+
default: true
|
|
265
241
|
}
|
|
266
242
|
]);
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
console.
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
if (!input.trim())
|
|
290
|
-
return 'Base URL is required';
|
|
291
|
-
try {
|
|
292
|
-
new URL(input);
|
|
243
|
+
let githubConfig = null;
|
|
244
|
+
let githubValid = false;
|
|
245
|
+
if (setupGitHub.setup) {
|
|
246
|
+
console.log('\nTo sync comments with GitHub Issues, we need to authenticate with GitHub.');
|
|
247
|
+
console.log('This requires creating a GitHub OAuth App.\n');
|
|
248
|
+
console.log('Instructions:');
|
|
249
|
+
console.log('1. Visit: https://github.com/settings/developers');
|
|
250
|
+
console.log('2. Click "New OAuth App"');
|
|
251
|
+
console.log('3. Fill in the form:');
|
|
252
|
+
console.log(' - Application name: Your app name (e.g., "My Design Comments")');
|
|
253
|
+
console.log(' - Homepage URL: http://localhost:9000 (or your dev server URL)');
|
|
254
|
+
console.log(' - Authorization callback URL: http://localhost:9000/api/github-oauth-callback');
|
|
255
|
+
console.log('4. Click "Register application"');
|
|
256
|
+
console.log('5. Copy the Client ID and generate a Client Secret\n');
|
|
257
|
+
const githubAnswers = await inquirer_1.default.prompt([
|
|
258
|
+
{
|
|
259
|
+
type: 'input',
|
|
260
|
+
name: 'clientId',
|
|
261
|
+
message: 'GitHub OAuth Client ID:',
|
|
262
|
+
validate: (input) => {
|
|
263
|
+
if (!input.trim())
|
|
264
|
+
return 'Client ID is required';
|
|
293
265
|
return true;
|
|
294
266
|
}
|
|
295
|
-
|
|
296
|
-
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
type: 'password',
|
|
270
|
+
name: 'clientSecret',
|
|
271
|
+
message: 'GitHub OAuth Client Secret:',
|
|
272
|
+
mask: '*',
|
|
273
|
+
validate: (input) => {
|
|
274
|
+
if (!input.trim())
|
|
275
|
+
return 'Client Secret is required';
|
|
276
|
+
return true;
|
|
297
277
|
}
|
|
298
278
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
if (!input.trim())
|
|
307
|
-
return 'API Token is required';
|
|
308
|
-
return true;
|
|
309
|
-
}
|
|
279
|
+
]);
|
|
280
|
+
// Validate GitHub credentials
|
|
281
|
+
console.log('\n🔍 Validating GitHub credentials...');
|
|
282
|
+
githubValid = await validators.validateGitHubCredentials(githubAnswers.clientId, githubAnswers.clientSecret, owner, repo);
|
|
283
|
+
if (!githubValid) {
|
|
284
|
+
console.error('❌ GitHub validation failed. Please check your credentials and try again.');
|
|
285
|
+
process.exit(1);
|
|
310
286
|
}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
console.log('\n🔍 Validating Jira credentials...');
|
|
314
|
-
const jiraValid = await validators.validateJiraCredentials(jiraAnswers.baseUrl, jiraAnswers.apiToken, undefined // No email for Bearer token
|
|
315
|
-
);
|
|
316
|
-
if (!jiraValid) {
|
|
317
|
-
console.error('❌ Jira validation failed. Please check your credentials and try again.');
|
|
318
|
-
process.exit(1);
|
|
319
|
-
}
|
|
320
|
-
console.log('✅ Jira credentials validated!\n');
|
|
321
|
-
// Step 4: Generate files
|
|
322
|
-
console.log('📝 Step 4: Generating configuration files...\n');
|
|
323
|
-
await generators.generateFiles({
|
|
324
|
-
github: {
|
|
287
|
+
console.log('✅ GitHub credentials validated!\n');
|
|
288
|
+
githubConfig = {
|
|
325
289
|
clientId: githubAnswers.clientId,
|
|
326
290
|
clientSecret: githubAnswers.clientSecret,
|
|
327
291
|
owner: owner,
|
|
328
292
|
repo: repo
|
|
329
|
-
}
|
|
330
|
-
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
console.log('\n⏭️ Skipping GitHub setup. You can add it later by editing .env and .env.server files.\n');
|
|
297
|
+
}
|
|
298
|
+
// Step 3: Jira Setup (Optional)
|
|
299
|
+
console.log('🎫 Step 3: Jira Integration (Optional)\n');
|
|
300
|
+
console.log('Jira integration allows you to link Jira tickets to pages in your design.');
|
|
301
|
+
console.log('You can set this up now or add it later.\n');
|
|
302
|
+
const setupJira = await inquirer_1.default.prompt([
|
|
303
|
+
{
|
|
304
|
+
type: 'confirm',
|
|
305
|
+
name: 'setup',
|
|
306
|
+
message: 'Do you want to set up Jira integration now?',
|
|
307
|
+
default: true
|
|
308
|
+
}
|
|
309
|
+
]);
|
|
310
|
+
let jiraConfig = null;
|
|
311
|
+
let jiraValid = false;
|
|
312
|
+
if (setupJira.setup) {
|
|
313
|
+
console.log('\nFor Red Hat Jira, generate a Personal Access Token:');
|
|
314
|
+
console.log('1. Visit: https://issues.redhat.com/secure/ViewProfile.jspa');
|
|
315
|
+
console.log('2. Click "Personal Access Tokens" in the left sidebar');
|
|
316
|
+
console.log('3. Click "Create token"');
|
|
317
|
+
console.log('4. Give it a name (e.g., "Hale Commenting System")');
|
|
318
|
+
console.log('5. Remove expiration (or set a long expiration)');
|
|
319
|
+
console.log('6. Click "Create" and copy the token\n');
|
|
320
|
+
console.log('Note: We use Bearer token authentication (no email required for Red Hat Jira).\n');
|
|
321
|
+
const jiraAnswers = await inquirer_1.default.prompt([
|
|
322
|
+
{
|
|
323
|
+
type: 'input',
|
|
324
|
+
name: 'baseUrl',
|
|
325
|
+
message: 'Jira Base URL (press Enter for Red Hat Jira):',
|
|
326
|
+
default: 'https://issues.redhat.com',
|
|
327
|
+
validate: (input) => {
|
|
328
|
+
if (!input.trim())
|
|
329
|
+
return 'Base URL is required';
|
|
330
|
+
try {
|
|
331
|
+
new URL(input);
|
|
332
|
+
return true;
|
|
333
|
+
}
|
|
334
|
+
catch {
|
|
335
|
+
return 'Please enter a valid URL';
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
},
|
|
339
|
+
{
|
|
340
|
+
type: 'password',
|
|
341
|
+
name: 'apiToken',
|
|
342
|
+
message: 'Jira API Token:',
|
|
343
|
+
mask: '*',
|
|
344
|
+
validate: (input) => {
|
|
345
|
+
if (!input.trim())
|
|
346
|
+
return 'API Token is required';
|
|
347
|
+
return true;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
]);
|
|
351
|
+
// Validate Jira credentials
|
|
352
|
+
console.log('\n🔍 Validating Jira credentials...');
|
|
353
|
+
jiraValid = await validators.validateJiraCredentials(jiraAnswers.baseUrl, jiraAnswers.apiToken, undefined // No email for Bearer token
|
|
354
|
+
);
|
|
355
|
+
if (!jiraValid) {
|
|
356
|
+
console.error('❌ Jira validation failed. Please check your credentials and try again.');
|
|
357
|
+
process.exit(1);
|
|
358
|
+
}
|
|
359
|
+
console.log('✅ Jira credentials validated!\n');
|
|
360
|
+
jiraConfig = {
|
|
331
361
|
baseUrl: jiraAnswers.baseUrl,
|
|
332
362
|
apiToken: jiraAnswers.apiToken,
|
|
333
|
-
email: undefined
|
|
334
|
-
}
|
|
363
|
+
email: undefined
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
else {
|
|
367
|
+
console.log('\n⏭️ Skipping Jira setup. You can add it later by editing .env and .env.server files.\n');
|
|
368
|
+
}
|
|
369
|
+
// Step 4: Generate files
|
|
370
|
+
console.log('📝 Step 4: Generating configuration files...\n');
|
|
371
|
+
await generators.generateFiles({
|
|
372
|
+
github: githubConfig,
|
|
373
|
+
jira: jiraConfig,
|
|
374
|
+
owner: owner,
|
|
375
|
+
repo: repo
|
|
335
376
|
});
|
|
336
377
|
// Step 5: Integrate into project
|
|
337
378
|
console.log('🔧 Step 5: Integrating into PatternFly Seed project...\n');
|
|
338
379
|
await generators.integrateIntoProject();
|
|
339
380
|
console.log('\n✅ Setup complete!');
|
|
340
381
|
console.log('\nNext steps:');
|
|
341
|
-
console.log('1.
|
|
342
|
-
console.log('
|
|
343
|
-
console.log('
|
|
382
|
+
console.log('1. Start your dev server: npm run start:dev');
|
|
383
|
+
console.log(' (If it\'s already running, restart it to load the new configuration)');
|
|
384
|
+
console.log('2. The commenting system will be available in your app!\n');
|
|
385
|
+
if (!githubConfig || !jiraConfig) {
|
|
386
|
+
console.log('📝 To add integrations later:');
|
|
387
|
+
if (!githubConfig) {
|
|
388
|
+
console.log(' • GitHub: Edit .env and .env.server files (see comments in files for instructions)');
|
|
389
|
+
}
|
|
390
|
+
if (!jiraConfig) {
|
|
391
|
+
console.log(' • Jira: Edit .env and .env.server files (see comments in files for instructions)');
|
|
392
|
+
}
|
|
393
|
+
console.log(' • Then restart your dev server\n');
|
|
394
|
+
}
|
|
344
395
|
}
|