github-delivery-os 1.0.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.
@@ -0,0 +1,61 @@
1
+ # Run once: Actions → Setup Labels → Run workflow
2
+ # Uses built-in GITHUB_TOKEN — no personal token or gh CLI needed.
3
+ # Labels must match scripts/install.sh --with-labels (same order and colors).
4
+
5
+ name: Setup Labels
6
+
7
+ on:
8
+ workflow_dispatch:
9
+
10
+ permissions:
11
+ contents: read
12
+ issues: write
13
+
14
+ jobs:
15
+ create-labels:
16
+ runs-on: ubuntu-latest
17
+ permissions:
18
+ contents: read
19
+ issues: write
20
+ steps:
21
+ - name: Create labels
22
+ uses: actions/github-script@v7
23
+ with:
24
+ script: |
25
+ const labels = [
26
+ { name: 'intake', color: '0E8A16' },
27
+ { name: 'bug', color: 'D93F0B' },
28
+ { name: 'sprint', color: '1D76DB' },
29
+ { name: 'sprint-active', color: '1D76DB' },
30
+ { name: 'planning', color: '5319E7' },
31
+ { name: 'sprint-planning', color: '5319E7' },
32
+ { name: 'task', color: '7057FF' },
33
+ { name: 'qa', color: 'FBCA04' },
34
+ { name: 'qa-request', color: 'FBCA04' },
35
+ { name: 'production', color: 'D93F0B' },
36
+ { name: 'release', color: 'B60205' },
37
+ { name: 'approval', color: '0E8A16' },
38
+ { name: 'ready-for-deploy', color: '0E8A16' },
39
+ { name: 'declined', color: 'B60205' },
40
+ { name: 'risk', color: 'B60205' },
41
+ ];
42
+ let created = 0;
43
+ for (const { name, color } of labels) {
44
+ try {
45
+ await github.rest.issues.createLabel({
46
+ owner: context.repo.owner,
47
+ repo: context.repo.repo,
48
+ name,
49
+ color,
50
+ });
51
+ console.log(`Created: ${name}`);
52
+ created++;
53
+ } catch (e) {
54
+ if (e.message?.includes('already exists')) {
55
+ console.log(`Exists: ${name}`);
56
+ } else {
57
+ console.log(`Failed: ${name} - ${e.message}`);
58
+ }
59
+ }
60
+ }
61
+ console.log(`\nCreated ${created} label(s).`);
@@ -0,0 +1,44 @@
1
+ name: Sprint Child Issue Creator
2
+
3
+ on:
4
+ issues:
5
+ types: [opened]
6
+
7
+ permissions:
8
+ issues: write
9
+
10
+ jobs:
11
+ create-child-issues:
12
+ if: contains(github.event.issue.title, 'SPRINT -')
13
+ runs-on: ubuntu-latest
14
+ permissions:
15
+ issues: write
16
+
17
+ steps:
18
+ - name: Create Child Issues
19
+ uses: actions/github-script@v7
20
+ with:
21
+ script: |
22
+ const issue = context.payload.issue;
23
+ const body = issue.body || "";
24
+ const parentNumber = issue.number;
25
+
26
+ const featuresMatch = body.match(/### Sprint Features[\s\S]*?(?=###|$)/);
27
+ if (!featuresMatch) return;
28
+
29
+ const features = featuresMatch[0]
30
+ .split('\n')
31
+ .map(line => line.trim())
32
+ .filter(line => line && !line.startsWith('###'));
33
+
34
+ const bodyContent = `Parent Sprint: #${parentNumber}\n\n---\n*Created by Delivery OS Sprint Child Creator*`;
35
+
36
+ for (const title of features) {
37
+ await github.rest.issues.create({
38
+ owner: context.repo.owner,
39
+ repo: context.repo.repo,
40
+ title,
41
+ body: bodyContent,
42
+ labels: ['sprint-active']
43
+ });
44
+ }
@@ -0,0 +1,135 @@
1
+ name: GitHub → Telegram Alerts
2
+
3
+ on:
4
+ issues:
5
+ types: [opened, closed, reopened]
6
+
7
+ issue_comment:
8
+ types: [created]
9
+
10
+ pull_request:
11
+ types: [closed]
12
+
13
+ permissions:
14
+ contents: read
15
+
16
+ jobs:
17
+ notify:
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - name: Send Telegram Alert
21
+ shell: bash
22
+ env:
23
+ TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
24
+ TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
25
+ RELEASE_APPROVER: ${{ vars.RELEASE_APPROVER || 'release-approver' }}
26
+ EVENT_NAME: ${{ github.event_name }}
27
+ EVENT_ACTION: ${{ github.event.action }}
28
+ ACTOR: ${{ github.actor }}
29
+ ISSUE_TITLE: ${{ github.event.issue.title }}
30
+ ISSUE_URL: ${{ github.event.issue.html_url }}
31
+ COMMENT_BODY: ${{ github.event.comment.body }}
32
+ PR_MERGED: ${{ github.event.pull_request.merged }}
33
+ PR_BASE: ${{ github.event.pull_request.base.ref }}
34
+ PR_TITLE: ${{ github.event.pull_request.title }}
35
+ PR_URL: ${{ github.event.pull_request.html_url }}
36
+ run: |
37
+ EVENT="${EVENT_NAME}"
38
+ ACTION="${EVENT_ACTION}"
39
+ TIMESTAMP=$(TZ=Africa/Nairobi date +"%Y-%m-%d %-I:%M %p EAT")
40
+ MESSAGE=""
41
+
42
+ if [ -z "$TELEGRAM_BOT_TOKEN" ] || [ -z "$TELEGRAM_CHAT_ID" ]; then
43
+ echo "Telegram secrets not configured. Skipping."
44
+ exit 0
45
+ fi
46
+
47
+ if [ "$EVENT" = "issues" ]; then
48
+
49
+ TITLE="${ISSUE_TITLE}"
50
+ URL="${ISSUE_URL}"
51
+
52
+ if [[ "${{ contains(github.event.issue.labels.*.name || fromJSON('[]'), 'bug') }}" == "true" ]]; then
53
+ if [ "$ACTION" = "opened" ]; then
54
+ MESSAGE="🟢🪲 BUG OPENED%0A$TITLE%0A$URL%0A---%0A👤 $ACTOR%0A🕒 $TIMESTAMP"
55
+ elif [ "$ACTION" = "reopened" ]; then
56
+ MESSAGE="🟡♻️ BUG REOPENED%0A$TITLE%0A$URL%0A---%0A👤 $ACTOR%0A🕒 $TIMESTAMP"
57
+ elif [ "$ACTION" = "closed" ]; then
58
+ MESSAGE="🟣✅ BUG CLOSED%0A$TITLE%0A$URL%0A---%0A👤 $ACTOR%0A🕒 $TIMESTAMP"
59
+ fi
60
+ fi
61
+
62
+ if [[ "${{ contains(github.event.issue.labels.*.name || fromJSON('[]'), 'qa') }}" == "true" ]] || \
63
+ [[ "${{ contains(github.event.issue.labels.*.name || fromJSON('[]'), 'qa-request') }}" == "true" ]]; then
64
+ if [ "$ACTION" = "opened" ]; then
65
+ MESSAGE="🔵🧪 QA REQUEST OPENED%0A$TITLE%0A$URL%0A---%0A👤 $ACTOR%0A🕒 $TIMESTAMP"
66
+ elif [ "$ACTION" = "reopened" ]; then
67
+ MESSAGE="🟠🔁 QA REQUEST REOPENED%0A$TITLE%0A$URL%0A---%0A👤 $ACTOR%0A🕒 $TIMESTAMP"
68
+ elif [ "$ACTION" = "closed" ]; then
69
+ MESSAGE="🟢✅ QA REQUEST CLOSED%0A$TITLE%0A$URL%0A---%0A👤 $ACTOR%0A🕒 $TIMESTAMP"
70
+ fi
71
+ fi
72
+
73
+ if [[ "${{ contains(github.event.issue.labels.*.name || fromJSON('[]'), 'sprint') }}" == "true" ]] && \
74
+ [[ "${{ contains(github.event.issue.labels.*.name || fromJSON('[]'), 'planning') }}" == "true" ]]; then
75
+ if [ "$ACTION" = "opened" ]; then
76
+ MESSAGE="🟣📋 SPRINT CREATED%0A$TITLE%0A$URL%0A---%0A👤 $ACTOR%0A🕒 $TIMESTAMP"
77
+ fi
78
+ fi
79
+
80
+ if [[ "${{ contains(github.event.issue.labels.*.name || fromJSON('[]'), 'sprint-active') }}" == "true" ]]; then
81
+ if [ "$ACTION" = "opened" ]; then
82
+ MESSAGE="🟡🛠️ SPRINT TASK CREATED%0A$TITLE%0A$URL%0A---%0A👤 $ACTOR%0A🕒 $TIMESTAMP"
83
+ elif [ "$ACTION" = "closed" ]; then
84
+ MESSAGE="🟢✅ SPRINT TASK COMPLETED%0A$TITLE%0A$URL%0A---%0A👤 $ACTOR%0A🕒 $TIMESTAMP"
85
+ fi
86
+ fi
87
+
88
+ if [[ "${{ contains(github.event.issue.labels.*.name || fromJSON('[]'), 'production') }}" == "true" ]]; then
89
+ if [ "$ACTION" = "opened" ]; then
90
+ MESSAGE="🚀📦 PRODUCTION RELEASE CREATED%0A$TITLE%0A$URL%0A---%0A👤 $ACTOR%0A🕒 $TIMESTAMP"
91
+ elif [ "$ACTION" = "closed" ]; then
92
+ MESSAGE="🟣🚀 RELEASE CLOSED%0A$TITLE%0A$URL%0A---%0A👤 $ACTOR%0A🕒 $TIMESTAMP"
93
+ fi
94
+ fi
95
+ fi
96
+
97
+ if [ "$EVENT" = "issue_comment" ]; then
98
+
99
+ TITLE="${ISSUE_TITLE}"
100
+ URL="${ISSUE_URL}"
101
+ COMMENT=$(echo "$COMMENT_BODY" | head -c 300)
102
+
103
+ if [[ "$ACTOR" == "$RELEASE_APPROVER" ]] && echo "$COMMENT_BODY" | grep -iq "declined\|reject\|not approved"; then
104
+ MESSAGE="🔴🛑 RELEASE DECLINED%0A$TITLE%0A$URL%0A---%0A👤 $ACTOR%0A🕒 $TIMESTAMP"
105
+
106
+ elif [[ "$ACTOR" == "$RELEASE_APPROVER" ]] && echo "$COMMENT_BODY" | grep -iq "^approved"; then
107
+ MESSAGE="🟢🛡️ RELEASE APPROVED%0A$TITLE%0A$URL%0A---%0A👤 $ACTOR%0A🕒 $TIMESTAMP"
108
+
109
+ elif [[ "${{ contains(github.event.issue.labels.*.name || fromJSON('[]'), 'bug') }}" == "true" ]]; then
110
+ MESSAGE="💬🪲 BUG COMMENT%0A$TITLE%0A$URL%0A---%0A$COMMENT%0A---%0A👤 $ACTOR%0A🕒 $TIMESTAMP"
111
+
112
+ elif [[ "${{ contains(github.event.issue.labels.*.name || fromJSON('[]'), 'qa') }}" == "true" ]] || \
113
+ [[ "${{ contains(github.event.issue.labels.*.name || fromJSON('[]'), 'qa-request') }}" == "true" ]]; then
114
+ MESSAGE="💬🧪 QA COMMENT%0A$TITLE%0A$URL%0A---%0A$COMMENT%0A---%0A👤 $ACTOR%0A🕒 $TIMESTAMP"
115
+
116
+ elif [[ "${{ contains(github.event.issue.labels.*.name || fromJSON('[]'), 'production') }}" == "true" ]]; then
117
+ MESSAGE="💬🚀 RELEASE COMMENT%0A$TITLE%0A$URL%0A---%0A$COMMENT%0A---%0A👤 $ACTOR%0A🕒 $TIMESTAMP"
118
+
119
+ elif [[ "${{ contains(github.event.issue.labels.*.name || fromJSON('[]'), 'sprint-active') }}" == "true" ]]; then
120
+ MESSAGE="💬🛠️ SPRINT TASK COMMENT%0A$TITLE%0A$URL%0A---%0A$COMMENT%0A---%0A👤 $ACTOR%0A🕒 $TIMESTAMP"
121
+ fi
122
+ fi
123
+
124
+ if [ "$EVENT" = "pull_request" ]; then
125
+
126
+ if [ "$PR_MERGED" = "true" ] && [ "$PR_BASE" = "main" ]; then
127
+ MESSAGE="🟢🔀 PR MERGED TO MAIN%0A${PR_TITLE}%0A${PR_URL}%0A---%0A👤 $ACTOR%0A🕒 $TIMESTAMP"
128
+ fi
129
+ fi
130
+
131
+ if [ -n "$MESSAGE" ]; then
132
+ curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
133
+ -d chat_id="${TELEGRAM_CHAT_ID}" \
134
+ -d text="${MESSAGE}"
135
+ fi
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 GitHub Delivery Operating System Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,104 @@
1
+ # GitHub Delivery Operating System
2
+
3
+ > A GitHub-native Delivery Governance Framework for structured sprint execution, QA review, and collaborative production release control.
4
+
5
+ ---
6
+
7
+ ## Why This Exists
8
+
9
+ Engineering teams often rely on informal coordination inside GitHub — manual approvals, inconsistent sprint tracking, reactive QA engagement, and socially enforced production releases.
10
+
11
+ As teams scale, this creates:
12
+
13
+ * Delivery ambiguity
14
+ * QA bottlenecks
15
+ * Unclear accountability
16
+ * Release risk
17
+ * Cross-team misalignment
18
+
19
+ The **GitHub Delivery Operating System (Delivery OS)** embeds structured intake, sprint orchestration, QA governance, and collaborative release gates directly into engineering repositories — without replacing CI/CD pipelines or disrupting developer workflows.
20
+
21
+ ---
22
+
23
+ ## Installation
24
+
25
+ **One command** (recommended):
26
+
27
+ ```bash
28
+ npx github-delivery-os install --with-templates .
29
+ ```
30
+
31
+ From your repo root. Add `--with-labels` to create labels via `gh` CLI (requires `gh auth`). Use `--dry-run` to preview first.
32
+
33
+ **Alternative — clone and run script:**
34
+
35
+ ```bash
36
+ git clone https://github.com/jkaweesi22/github-delivery-operating-system
37
+ cd github-delivery-operating-system
38
+
39
+ # New install or repo with existing workflows — adds only missing files (safe)
40
+ ./scripts/install.sh --with-templates /path/to/your-repo
41
+
42
+ # Also create labels via gh CLI (requires gh auth)
43
+ ./scripts/install.sh --with-templates --with-labels /path/to/your-repo
44
+
45
+ # Update Delivery OS (replace existing) — use --dry-run first to preview
46
+ ./scripts/install.sh --with-templates --overwrite /path/to/your-repo
47
+ ```
48
+
49
+ **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
+
51
+ **What gets installed:**
52
+
53
+ | Workflow | Purpose |
54
+ |----------|---------|
55
+ | `sprint-child-creator` | Creates child issues when a sprint (title `SPRINT -`) is opened |
56
+ | `auto-close-sprint` | Burn-down, sprint health, auto-close at 100% |
57
+ | `notify-release-approver` | Pings approver when production release issue opens |
58
+ | `authorize-deployment` | Dual approval (release approver + QA) |
59
+ | `auto-assign-qa` | Assigns QA team to `qa` / `qa-request` issues |
60
+ | `telegram-issues` | Telegram alerts for bugs, QA, sprints, releases |
61
+ | `setup-labels` | One-time workflow to create required labels |
62
+
63
+ Workflows and templates are **copied directly** into your repo. No `workflow_call` or external references.
64
+
65
+ ---
66
+
67
+ ## Quick Start (After Install)
68
+
69
+ 1. **Create labels:** Actions → Setup Labels → Run workflow
70
+ 2. **Configure variables:** Settings → Secrets and variables → Actions → Variables
71
+ - `RELEASE_APPROVER` — GitHub username
72
+ - `QA_APPROVER` — GitHub username
73
+ - `QA_ASSIGNEES` — Comma-separated usernames (e.g. `user1,user2`)
74
+ 3. **Optional:** Add `TELEGRAM_BOT_TOKEN` and `TELEGRAM_CHAT_ID` for alerts
75
+
76
+ ---
77
+
78
+ ## Sprint Child Creation
79
+
80
+ When you open an issue using the **Sprint Planning** template with a title like `SPRINT - Sprint 12`:
81
+
82
+ 1. Each line under "Sprint Features (One Per Line)" becomes a child issue
83
+ 2. Child issues link back with `Parent Sprint: #N`
84
+ 3. Closing child issues updates burn-down; sprint auto-closes at 100%
85
+
86
+ **Required:** Install with `--with-templates` so the sprint form is available.
87
+
88
+ ---
89
+
90
+ ## Documentation
91
+
92
+ | Document | Description |
93
+ |----------|-------------|
94
+ | **[Landing page & quick start](https://jkaweesi22.github.io/github-delivery-operating-system/)** | Overview, one-command install, features |
95
+ | [Consumer Setup](docs/consumer-setup.md) | Installation, configuration, variables, labels, Telegram, uninstall |
96
+ | [How To](docs/how-to.md) | Create sprints, request releases, approve, report bugs, QA requests |
97
+ | [Architecture](docs/architecture.md) | Workflows, templates, data flow |
98
+ | [Governance](docs/governance.md) | Lifecycle, approval gates, automation rules |
99
+
100
+ ---
101
+
102
+ ## License
103
+
104
+ MIT License. See [LICENSE](LICENSE) for details.
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+
3
+ require('../src/cli');
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "github-delivery-os",
3
+ "version": "1.0.0",
4
+ "description": "A GitHub-native Delivery Governance Framework for structured sprint execution, QA review, and collaborative production release control.",
5
+ "main": "src/install.js",
6
+ "bin": {
7
+ "delivery-os": "./bin/delivery-os.js"
8
+ },
9
+ "scripts": {
10
+ "install:local": "node bin/delivery-os.js install --with-templates ."
11
+ },
12
+ "keywords": [
13
+ "github",
14
+ "delivery",
15
+ "sprint",
16
+ "qa",
17
+ "release",
18
+ "governance",
19
+ "workflows",
20
+ "automation"
21
+ ],
22
+ "author": "",
23
+ "license": "MIT",
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "https://github.com/jkaweesi22/github-delivery-operating-system"
27
+ },
28
+ "homepage": "https://jkaweesi22.github.io/github-delivery-operating-system/",
29
+ "bugs": {
30
+ "url": "https://github.com/jkaweesi22/github-delivery-operating-system/issues"
31
+ },
32
+ "files": [
33
+ "bin",
34
+ "src",
35
+ ".github/workflows",
36
+ ".github/ISSUE_TEMPLATE"
37
+ ],
38
+ "engines": {
39
+ "node": ">=14.0.0"
40
+ },
41
+ "dependencies": {
42
+ "commander": "^11.1.0"
43
+ }
44
+ }
package/src/cli.js ADDED
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { program } = require('commander');
4
+ const path = require('path');
5
+ const fs = require('fs');
6
+ const { runInstall } = require('./install');
7
+
8
+ const pkgPath = path.join(__dirname, '..', 'package.json');
9
+ const version = fs.existsSync(pkgPath)
10
+ ? require(pkgPath).version
11
+ : '1.0.0';
12
+
13
+ program
14
+ .name('delivery-os')
15
+ .description('GitHub Delivery Operating System — structured sprint execution, QA review, and production release control')
16
+ .version(version);
17
+
18
+ program
19
+ .command('install [target]')
20
+ .description('Install workflows and templates into a repository')
21
+ .option('-t, --with-templates', 'Copy issue templates (sprint, task, bug, QA, production release)')
22
+ .option('-l, --with-labels', 'Create labels via gh CLI (requires gh auth)')
23
+ .option('-o, --overwrite', 'Replace existing workflow/template files')
24
+ .option('--no-overwrite', 'Skip existing files (default)')
25
+ .option('-d, --dry-run', 'Show what would happen without changing files')
26
+ .action((target, options) => {
27
+ const targetDir = target || '.';
28
+ runInstall({
29
+ targetDir,
30
+ withTemplates: options.withTemplates ?? false,
31
+ withLabels: options.withLabels ?? false,
32
+ overwrite: options.overwrite ?? false,
33
+ dryRun: options.dryRun ?? false,
34
+ });
35
+ });
36
+
37
+ program.parse();
38
+
39
+ // Show help if no command
40
+ if (!process.argv.slice(2).length) {
41
+ program.outputHelp();
42
+ }