github-delivery-os 1.0.0 → 1.0.2

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.
@@ -0,0 +1,27 @@
1
+ # Create GitHub release when a version tag is pushed
2
+ # Usage: git tag v1.0.2 && git push origin v1.0.2
3
+
4
+ name: Release
5
+
6
+ on:
7
+ push:
8
+ tags:
9
+ - 'v*'
10
+
11
+ permissions:
12
+ contents: write
13
+
14
+ jobs:
15
+ release:
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+ with:
20
+ fetch-depth: 0
21
+
22
+ - name: Create Release
23
+ uses: softprops/action-gh-release@v2
24
+ with:
25
+ generate_release_notes: true
26
+ env:
27
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
package/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  > A GitHub-native Delivery Governance Framework for structured sprint execution, QA review, and collaborative production release control.
4
4
 
5
+ [![Socket Badge](https://badge.socket.dev/npm/package/github-delivery-os)](https://socket.dev/npm/package/github-delivery-os)
6
+
5
7
  ---
6
8
 
7
9
  ## Why This Exists
@@ -48,6 +50,13 @@ cd github-delivery-operating-system
48
50
 
49
51
  **Note:** By default, existing files are **never overwritten**. Use `--overwrite` only when updating Delivery OS. See [Consumer Setup](docs/consumer-setup.md) for the full command guide.
50
52
 
53
+ **Other commands:**
54
+ ```bash
55
+ npx github-delivery-os status . # Show what's installed
56
+ npx github-delivery-os uninstall . # Remove workflows
57
+ npx github-delivery-os uninstall --with-templates . # Remove workflows + templates
58
+ ```
59
+
51
60
  **What gets installed:**
52
61
 
53
62
  | Workflow | Purpose |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "github-delivery-os",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "A GitHub-native Delivery Governance Framework for structured sprint execution, QA review, and collaborative production release control.",
5
5
  "main": "src/install.js",
6
6
  "bin": {
@@ -11,13 +11,18 @@
11
11
  },
12
12
  "keywords": [
13
13
  "github",
14
+ "github-actions",
14
15
  "delivery",
15
16
  "sprint",
17
+ "sprint-planning",
16
18
  "qa",
17
19
  "release",
20
+ "release-management",
18
21
  "governance",
19
22
  "workflows",
20
- "automation"
23
+ "automation",
24
+ "devops",
25
+ "ci-cd"
21
26
  ],
22
27
  "author": "",
23
28
  "license": "MIT",
package/src/cli.js CHANGED
@@ -3,7 +3,7 @@
3
3
  const { program } = require('commander');
4
4
  const path = require('path');
5
5
  const fs = require('fs');
6
- const { runInstall } = require('./install');
6
+ const { runInstall, runStatus, runUninstall } = require('./install');
7
7
 
8
8
  const pkgPath = path.join(__dirname, '..', 'package.json');
9
9
  const version = fs.existsSync(pkgPath)
@@ -34,6 +34,26 @@ program
34
34
  });
35
35
  });
36
36
 
37
+ program
38
+ .command('status [target]')
39
+ .description('Show which workflows and templates are installed')
40
+ .action((target) => {
41
+ runStatus({ targetDir: target || '.' });
42
+ });
43
+
44
+ program
45
+ .command('uninstall [target]')
46
+ .description('Remove Delivery OS workflows (and optionally templates)')
47
+ .option('-t, --with-templates', 'Also remove issue templates')
48
+ .option('-d, --dry-run', 'Show what would be removed without deleting')
49
+ .action((target, options) => {
50
+ runUninstall({
51
+ targetDir: target || '.',
52
+ withTemplates: options.withTemplates ?? false,
53
+ dryRun: options.dryRun ?? false,
54
+ });
55
+ });
56
+
37
57
  program.parse();
38
58
 
39
59
  // Show help if no command
package/src/install.js CHANGED
@@ -1,6 +1,6 @@
1
1
  const path = require('path');
2
2
  const fs = require('fs');
3
- const { execSync } = require('child_process');
3
+ const { execFileSync } = require('child_process');
4
4
 
5
5
  const WORKFLOWS = [
6
6
  'sprint-child-creator',
@@ -141,7 +141,7 @@ function runInstall(options) {
141
141
  console.log(' [dry-run] Labels would be created (skipped)');
142
142
  } else {
143
143
  try {
144
- execSync('gh --version', { stdio: 'ignore' });
144
+ execFileSync('gh', ['--version'], { stdio: 'ignore' });
145
145
  } catch {
146
146
  labelsSkipReason = 'gh CLI not installed. Install from https://cli.github.com/';
147
147
  console.log(` Skipped labels: ${labelsSkipReason}`);
@@ -154,7 +154,7 @@ function runInstall(options) {
154
154
 
155
155
  if (!labelsSkipReason) {
156
156
  try {
157
- execSync('gh auth status', { cwd: targetAbs, stdio: 'ignore' });
157
+ execFileSync('gh', ['auth', 'status'], { cwd: targetAbs, stdio: 'ignore' });
158
158
  } catch {
159
159
  labelsSkipReason = 'gh CLI not authenticated. Run: gh auth login';
160
160
  console.log(` Skipped labels: ${labelsSkipReason}`);
@@ -163,7 +163,7 @@ function runInstall(options) {
163
163
 
164
164
  if (!labelsSkipReason) {
165
165
  try {
166
- execSync('gh repo view', { cwd: targetAbs, stdio: 'ignore' });
166
+ execFileSync('gh', ['repo', 'view'], { cwd: targetAbs, stdio: 'ignore' });
167
167
  } catch {
168
168
  labelsSkipReason = 'Target repo not on GitHub or no push access.';
169
169
  console.log(` Skipped labels: ${labelsSkipReason}`);
@@ -173,7 +173,7 @@ function runInstall(options) {
173
173
  if (!labelsSkipReason) {
174
174
  for (const [name, color] of LABELS) {
175
175
  try {
176
- execSync(`gh label create "${name}" --color "${color}"`, {
176
+ execFileSync('gh', ['label', 'create', name, '--color', color], {
177
177
  cwd: targetAbs,
178
178
  stdio: 'pipe',
179
179
  });
@@ -229,4 +229,117 @@ function runInstall(options) {
229
229
  console.log('=== Installation complete ===');
230
230
  }
231
231
 
232
- module.exports = { runInstall };
232
+ const TEMPLATES = [
233
+ 'config.yml',
234
+ 'sprint_planning.yml',
235
+ 'task.yml',
236
+ 'qa_request.yml',
237
+ 'production_release_qa_signoff.yml',
238
+ 'bug_report.yml',
239
+ ];
240
+
241
+ function runStatus(options) {
242
+ const { targetDir = '.' } = options;
243
+ const targetAbs = path.resolve(process.cwd(), targetDir);
244
+ const workflowsDest = path.join(targetAbs, '.github', 'workflows');
245
+ const templatesDest = path.join(targetAbs, '.github', 'ISSUE_TEMPLATE');
246
+
247
+ console.log('=== GitHub Delivery Operating System — Status ===');
248
+ console.log(`Target: ${targetAbs}`);
249
+ console.log('');
250
+
251
+ const installedWorkflows = WORKFLOWS.filter((wf) =>
252
+ fs.existsSync(path.join(workflowsDest, `${wf}.yml`))
253
+ );
254
+ const installedTemplates = TEMPLATES.filter((t) =>
255
+ fs.existsSync(path.join(templatesDest, t))
256
+ );
257
+
258
+ if (installedWorkflows.length > 0) {
259
+ console.log('Workflows:');
260
+ installedWorkflows.forEach((wf) => console.log(` ✓ ${wf}.yml`));
261
+ console.log('');
262
+ }
263
+ if (installedTemplates.length > 0) {
264
+ console.log('Templates:');
265
+ installedTemplates.forEach((t) => console.log(` ✓ ${t}`));
266
+ console.log('');
267
+ }
268
+
269
+ const missingWorkflows = WORKFLOWS.filter((wf) => !installedWorkflows.includes(wf));
270
+ if (missingWorkflows.length > 0) {
271
+ console.log('Missing workflows:');
272
+ missingWorkflows.forEach((wf) => console.log(` ○ ${wf}.yml`));
273
+ console.log('');
274
+ }
275
+
276
+ if (installedWorkflows.length === 0 && installedTemplates.length === 0) {
277
+ console.log('Delivery OS is not installed in this repository.');
278
+ console.log('Run: npx github-delivery-os install --with-templates .');
279
+ } else {
280
+ const total = installedWorkflows.length + installedTemplates.length;
281
+ console.log(`Summary: ${installedWorkflows.length}/${WORKFLOWS.length} workflows, ${installedTemplates.length}/${TEMPLATES.length} templates`);
282
+ }
283
+ console.log('');
284
+ }
285
+
286
+ function runUninstall(options) {
287
+ const { targetDir = '.', withTemplates = false, dryRun = false } = options;
288
+ const targetAbs = path.resolve(process.cwd(), targetDir);
289
+ const workflowsDest = path.join(targetAbs, '.github', 'workflows');
290
+ const templatesDest = path.join(targetAbs, '.github', 'ISSUE_TEMPLATE');
291
+
292
+ console.log('=== GitHub Delivery Operating System — Uninstall ===');
293
+ console.log(`Target: ${targetAbs}`);
294
+ if (dryRun) console.log('Mode: dry-run (no files will be deleted)');
295
+ console.log('');
296
+
297
+ let workflowsRemoved = 0;
298
+ let templatesRemoved = 0;
299
+
300
+ for (const wf of WORKFLOWS) {
301
+ const dest = path.join(workflowsDest, `${wf}.yml`);
302
+ if (fs.existsSync(dest)) {
303
+ if (dryRun) {
304
+ console.log(` [dry-run] Would remove: ${wf}.yml`);
305
+ } else {
306
+ fs.unlinkSync(dest);
307
+ console.log(` Removed: ${wf}.yml`);
308
+ }
309
+ workflowsRemoved++;
310
+ }
311
+ }
312
+
313
+ if (withTemplates) {
314
+ for (const t of TEMPLATES) {
315
+ const dest = path.join(templatesDest, t);
316
+ if (fs.existsSync(dest)) {
317
+ if (dryRun) {
318
+ console.log(` [dry-run] Would remove template: ${t}`);
319
+ } else {
320
+ fs.unlinkSync(dest);
321
+ console.log(` Removed template: ${t}`);
322
+ }
323
+ templatesRemoved++;
324
+ }
325
+ }
326
+ }
327
+
328
+ console.log('');
329
+ if (workflowsRemoved > 0 || templatesRemoved > 0) {
330
+ if (dryRun) {
331
+ console.log(`Would remove ${workflowsRemoved} workflow(s)${withTemplates ? `, ${templatesRemoved} template(s)` : ''}.`);
332
+ } else {
333
+ console.log(`Removed ${workflowsRemoved} workflow(s)${withTemplates ? `, ${templatesRemoved} template(s)` : ''}.`);
334
+ if (!withTemplates) {
335
+ console.log('Templates were kept. Re-run with --with-templates to remove them.');
336
+ }
337
+ }
338
+ } else {
339
+ console.log('No Delivery OS files found to remove.');
340
+ }
341
+ console.log('');
342
+ console.log('=== Uninstall complete ===');
343
+ }
344
+
345
+ module.exports = { runInstall, runStatus, runUninstall };