@mokoconsulting/mcp-windows 3.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.
Files changed (184) hide show
  1. package/.gitattributes +94 -0
  2. package/.gitmessage +9 -0
  3. package/.mokogitea/ISSUE_TEMPLATE/adr.md +110 -0
  4. package/.mokogitea/ISSUE_TEMPLATE/bug_report.md +48 -0
  5. package/.mokogitea/ISSUE_TEMPLATE/config.yml +18 -0
  6. package/.mokogitea/ISSUE_TEMPLATE/documentation.md +52 -0
  7. package/.mokogitea/ISSUE_TEMPLATE/feature_request.md +51 -0
  8. package/.mokogitea/ISSUE_TEMPLATE/mcp_api_integration.md +48 -0
  9. package/.mokogitea/ISSUE_TEMPLATE/mcp_connection_issue.md +67 -0
  10. package/.mokogitea/ISSUE_TEMPLATE/mcp_tool_request.md +49 -0
  11. package/.mokogitea/ISSUE_TEMPLATE/question.md +82 -0
  12. package/.mokogitea/ISSUE_TEMPLATE/rfc.md +126 -0
  13. package/.mokogitea/ISSUE_TEMPLATE/security.md +51 -0
  14. package/.mokogitea/ISSUE_TEMPLATE/version.md +24 -0
  15. package/.mokogitea/branch-protection.yml +251 -0
  16. package/.mokogitea/workflows/auto-assign.yml +76 -0
  17. package/.mokogitea/workflows/auto-bump.yml +66 -0
  18. package/.mokogitea/workflows/auto-dev-issue.yml +207 -0
  19. package/.mokogitea/workflows/auto-release.yml +421 -0
  20. package/.mokogitea/workflows/branch-cleanup.yml +48 -0
  21. package/.mokogitea/workflows/cascade-dev.yml +10 -0
  22. package/.mokogitea/workflows/changelog-validation.yml +101 -0
  23. package/.mokogitea/workflows/ci-generic.yml +191 -0
  24. package/.mokogitea/workflows/cleanup.yml +87 -0
  25. package/.mokogitea/workflows/codeql-analysis.yml +115 -0
  26. package/.mokogitea/workflows/copilot-agent.yml +44 -0
  27. package/.mokogitea/workflows/deploy-manual.yml +126 -0
  28. package/.mokogitea/workflows/enterprise-firewall-setup.yml +758 -0
  29. package/.mokogitea/workflows/gitleaks.yml +92 -0
  30. package/.mokogitea/workflows/issue-branch.yml +73 -0
  31. package/.mokogitea/workflows/mcp-auto-release.yml +278 -0
  32. package/.mokogitea/workflows/mcp-build-test.yml +65 -0
  33. package/.mokogitea/workflows/mcp-sdk-check.yml +109 -0
  34. package/.mokogitea/workflows/mcp-tool-inventory.yml +61 -0
  35. package/.mokogitea/workflows/notify.yml +70 -0
  36. package/.mokogitea/workflows/npm-publish.yml +113 -0
  37. package/.mokogitea/workflows/pr-check.yml +534 -0
  38. package/.mokogitea/workflows/pre-release.yml +252 -0
  39. package/.mokogitea/workflows/rc-revert.yml +66 -0
  40. package/.mokogitea/workflows/repo-health.yml +712 -0
  41. package/.mokogitea/workflows/repository-cleanup.yml +525 -0
  42. package/.mokogitea/workflows/security-audit.yml +82 -0
  43. package/.mokogitea/workflows/standards-compliance.yml +2614 -0
  44. package/.mokogitea/workflows/sync-version-on-merge.yml +133 -0
  45. package/.mokogitea/workflows/update-server.yml +312 -0
  46. package/.mokogitea/workflows/workflow-sync-trigger.yml +73 -0
  47. package/CHANGELOG.md +130 -0
  48. package/CLAUDE.md +49 -0
  49. package/CONTRIBUTING.md +161 -0
  50. package/ISSUES.md +601 -0
  51. package/Makefile +70 -0
  52. package/README.md +80 -0
  53. package/automation/ci-issue-reporter.sh +237 -0
  54. package/config.example.json +18 -0
  55. package/dist/index.d.ts +3 -0
  56. package/dist/index.js +111 -0
  57. package/dist/shell.d.ts +50 -0
  58. package/dist/shell.js +209 -0
  59. package/dist/tools/apps.d.ts +3 -0
  60. package/dist/tools/apps.js +63 -0
  61. package/dist/tools/audio.d.ts +3 -0
  62. package/dist/tools/audio.js +142 -0
  63. package/dist/tools/audio_apps.d.ts +3 -0
  64. package/dist/tools/audio_apps.js +86 -0
  65. package/dist/tools/automation.d.ts +3 -0
  66. package/dist/tools/automation.js +261 -0
  67. package/dist/tools/bluetooth.d.ts +3 -0
  68. package/dist/tools/bluetooth.js +96 -0
  69. package/dist/tools/clipboard.d.ts +3 -0
  70. package/dist/tools/clipboard.js +118 -0
  71. package/dist/tools/config.d.ts +3 -0
  72. package/dist/tools/config.js +85 -0
  73. package/dist/tools/dialog.d.ts +3 -0
  74. package/dist/tools/dialog.js +72 -0
  75. package/dist/tools/display.d.ts +3 -0
  76. package/dist/tools/display.js +256 -0
  77. package/dist/tools/drives.d.ts +3 -0
  78. package/dist/tools/drives.js +98 -0
  79. package/dist/tools/environment.d.ts +3 -0
  80. package/dist/tools/environment.js +129 -0
  81. package/dist/tools/execute.d.ts +3 -0
  82. package/dist/tools/execute.js +28 -0
  83. package/dist/tools/filesystem.d.ts +3 -0
  84. package/dist/tools/filesystem.js +230 -0
  85. package/dist/tools/firewall.d.ts +3 -0
  86. package/dist/tools/firewall.js +108 -0
  87. package/dist/tools/hosts.d.ts +3 -0
  88. package/dist/tools/hosts.js +119 -0
  89. package/dist/tools/maintenance.d.ts +3 -0
  90. package/dist/tools/maintenance.js +236 -0
  91. package/dist/tools/netstat.d.ts +3 -0
  92. package/dist/tools/netstat.js +56 -0
  93. package/dist/tools/network.d.ts +3 -0
  94. package/dist/tools/network.js +70 -0
  95. package/dist/tools/notification.d.ts +3 -0
  96. package/dist/tools/notification.js +41 -0
  97. package/dist/tools/power.d.ts +3 -0
  98. package/dist/tools/power.js +104 -0
  99. package/dist/tools/printer.d.ts +3 -0
  100. package/dist/tools/printer.js +97 -0
  101. package/dist/tools/process.d.ts +3 -0
  102. package/dist/tools/process.js +54 -0
  103. package/dist/tools/process_kill.d.ts +3 -0
  104. package/dist/tools/process_kill.js +48 -0
  105. package/dist/tools/recycle_bin.d.ts +3 -0
  106. package/dist/tools/recycle_bin.js +108 -0
  107. package/dist/tools/registry.d.ts +3 -0
  108. package/dist/tools/registry.js +136 -0
  109. package/dist/tools/scheduler.d.ts +3 -0
  110. package/dist/tools/scheduler.js +116 -0
  111. package/dist/tools/service.d.ts +3 -0
  112. package/dist/tools/service.js +79 -0
  113. package/dist/tools/startup.d.ts +3 -0
  114. package/dist/tools/startup.js +159 -0
  115. package/dist/tools/storage.d.ts +3 -0
  116. package/dist/tools/storage.js +129 -0
  117. package/dist/tools/system.d.ts +3 -0
  118. package/dist/tools/system.js +84 -0
  119. package/dist/tools/system_mgmt.d.ts +3 -0
  120. package/dist/tools/system_mgmt.js +174 -0
  121. package/dist/tools/terminal.d.ts +3 -0
  122. package/dist/tools/terminal.js +80 -0
  123. package/dist/tools/theme.d.ts +3 -0
  124. package/dist/tools/theme.js +165 -0
  125. package/dist/tools/usb.d.ts +3 -0
  126. package/dist/tools/usb.js +52 -0
  127. package/dist/tools/virtual_desktop.d.ts +3 -0
  128. package/dist/tools/virtual_desktop.js +112 -0
  129. package/dist/tools/wifi.d.ts +3 -0
  130. package/dist/tools/wifi.js +136 -0
  131. package/dist/tools/window.d.ts +3 -0
  132. package/dist/tools/window.js +189 -0
  133. package/dist/tools/winget.d.ts +3 -0
  134. package/dist/tools/winget.js +79 -0
  135. package/dist/tools/wsl.d.ts +3 -0
  136. package/dist/tools/wsl.js +99 -0
  137. package/docs/API.md +63 -0
  138. package/docs/ARCHITECTURE.md +73 -0
  139. package/docs/INSTALLATION.md +102 -0
  140. package/docs/index.md +12 -0
  141. package/package.json +35 -0
  142. package/scripts/setup.mjs +123 -0
  143. package/src/index.ts +125 -0
  144. package/src/shell.ts +253 -0
  145. package/src/tools/apps.ts +76 -0
  146. package/src/tools/audio.ts +161 -0
  147. package/src/tools/audio_apps.ts +98 -0
  148. package/src/tools/automation.ts +297 -0
  149. package/src/tools/bluetooth.ts +114 -0
  150. package/src/tools/clipboard.ts +138 -0
  151. package/src/tools/config.ts +105 -0
  152. package/src/tools/dialog.ts +87 -0
  153. package/src/tools/display.ts +285 -0
  154. package/src/tools/drives.ts +124 -0
  155. package/src/tools/environment.ts +146 -0
  156. package/src/tools/execute.ts +35 -0
  157. package/src/tools/filesystem.ts +273 -0
  158. package/src/tools/firewall.ts +125 -0
  159. package/src/tools/hosts.ts +135 -0
  160. package/src/tools/maintenance.ts +299 -0
  161. package/src/tools/netstat.ts +72 -0
  162. package/src/tools/network.ts +84 -0
  163. package/src/tools/notification.ts +50 -0
  164. package/src/tools/power.ts +123 -0
  165. package/src/tools/printer.ts +114 -0
  166. package/src/tools/process.ts +80 -0
  167. package/src/tools/process_kill.ts +57 -0
  168. package/src/tools/recycle_bin.ts +126 -0
  169. package/src/tools/registry.ts +165 -0
  170. package/src/tools/scheduler.ts +140 -0
  171. package/src/tools/service.ts +102 -0
  172. package/src/tools/startup.ts +180 -0
  173. package/src/tools/storage.ts +141 -0
  174. package/src/tools/system.ts +99 -0
  175. package/src/tools/system_mgmt.ts +190 -0
  176. package/src/tools/terminal.ts +117 -0
  177. package/src/tools/theme.ts +205 -0
  178. package/src/tools/usb.ts +65 -0
  179. package/src/tools/virtual_desktop.ts +122 -0
  180. package/src/tools/wifi.ts +157 -0
  181. package/src/tools/window.ts +211 -0
  182. package/src/tools/winget.ts +100 -0
  183. package/src/tools/wsl.ts +112 -0
  184. package/tsconfig.json +19 -0
@@ -0,0 +1,207 @@
1
+ # Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
2
+ #
3
+ # This file is part of a Moko Consulting project.
4
+ #
5
+ # SPDX-License-Identifier: GPL-3.0-or-later
6
+ #
7
+ # FILE INFORMATION
8
+ # DEFGROUP: GitHub.Workflow
9
+ # INGROUP: MokoStandards.Automation
10
+ # REPO: https://github.com/mokoconsulting-tech/MokoStandards
11
+ # PATH: /templates/workflows/shared/auto-dev-issue.yml.template
12
+ # VERSION: 04.06.00
13
+ # BRIEF: Auto-create tracking issue with sub-issues for dev/rc branch workflow
14
+ # NOTE: Synced via bulk-repo-sync to .mokogitea/workflows/auto-dev-issue.yml in all governed repos.
15
+
16
+ name: "Universal: Dev/RC Branch Issue"
17
+
18
+ on:
19
+ # Auto-create on RC branch creation
20
+ create:
21
+ # Manual trigger for dev branches
22
+ workflow_dispatch:
23
+ inputs:
24
+ branch:
25
+ description: 'Branch name (e.g., dev/my-feature or dev/04.06)'
26
+ required: true
27
+ type: string
28
+
29
+ env:
30
+ FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
31
+
32
+ permissions:
33
+ contents: read
34
+ issues: write
35
+
36
+ jobs:
37
+ create-issue:
38
+ name: Create version tracking issue
39
+ runs-on: ubuntu-latest
40
+ if: >-
41
+ (github.event_name == 'workflow_dispatch') ||
42
+ (github.event.ref_type == 'branch' &&
43
+ (startsWith(github.event.ref, 'rc/') ||
44
+ startsWith(github.event.ref, 'alpha/') ||
45
+ startsWith(github.event.ref, 'beta/')))
46
+
47
+ steps:
48
+ - name: Create tracking issue and sub-issues
49
+ env:
50
+ GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
51
+ run: |
52
+ # For manual dispatch, use input; for auto, use event ref
53
+ if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
54
+ BRANCH="${{ inputs.branch }}"
55
+ else
56
+ BRANCH="${{ github.event.ref }}"
57
+ fi
58
+ REPO="${{ github.repository }}"
59
+ ACTOR="${{ github.actor }}"
60
+ NOW=$(date -u '+%Y-%m-%d %H:%M UTC')
61
+
62
+ # Determine branch type and version
63
+ if [[ "$BRANCH" == rc/* ]]; then
64
+ VERSION="${BRANCH#rc/}"
65
+ BRANCH_TYPE="Release Candidate"
66
+ LABEL_TYPE="type: release"
67
+ TITLE_PREFIX="rc"
68
+ elif [[ "$BRANCH" == beta/* ]]; then
69
+ VERSION="${BRANCH#beta/}"
70
+ BRANCH_TYPE="Beta"
71
+ LABEL_TYPE="type: release"
72
+ TITLE_PREFIX="beta"
73
+ elif [[ "$BRANCH" == alpha/* ]]; then
74
+ VERSION="${BRANCH#alpha/}"
75
+ BRANCH_TYPE="Alpha"
76
+ LABEL_TYPE="type: release"
77
+ TITLE_PREFIX="alpha"
78
+ else
79
+ VERSION="${BRANCH#dev/}"
80
+ BRANCH_TYPE="Development"
81
+ LABEL_TYPE="type: feature"
82
+ TITLE_PREFIX="feat"
83
+ fi
84
+
85
+ TITLE="${TITLE_PREFIX}(${VERSION}): ${BRANCH_TYPE} tracking for ${BRANCH}"
86
+
87
+ # Check for existing issue with same title prefix
88
+ EXISTING=$(gh api "repos/${REPO}/issues?state=open&per_page=10" \
89
+ --jq ".[] | select(.title | startswith(\"${TITLE_PREFIX}(${VERSION})\")) | .number" 2>/dev/null | head -1)
90
+
91
+ if [ -n "$EXISTING" ]; then
92
+ echo "ℹ️ Issue #${EXISTING} already exists for ${VERSION}" >> $GITHUB_STEP_SUMMARY
93
+ exit 0
94
+ fi
95
+
96
+ # ── Define sub-issues for the workflow ─────────────────────────
97
+ if [[ "$BRANCH" == rc/* ]]; then
98
+ SUB_ISSUES=(
99
+ "RC Testing|Verify all features work on rc branch|type: test,release-candidate"
100
+ "Regression Testing|Run full regression suite before merge|type: test,release-candidate"
101
+ "Version Bump|Bump version in README.md and all headers|type: version,release-candidate"
102
+ "Changelog Update|Update CHANGELOG.md with release notes|documentation,release-candidate"
103
+ "Merge to Version Branch|Create PR to version/XX|type: release,needs-review"
104
+ )
105
+ elif [[ "$BRANCH" == alpha/* ]] || [[ "$BRANCH" == beta/* ]]; then
106
+ SUB_ISSUES=(
107
+ "Testing|Verify features on ${BRANCH_TYPE} branch|type: test,status: in-progress"
108
+ "Bug Fixes|Fix issues found during ${BRANCH_TYPE} testing|type: bug,status: pending"
109
+ "Promote to Next Stage|Create PR to promote to next release stage|type: release,needs-review"
110
+ )
111
+ else
112
+ SUB_ISSUES=(
113
+ "Development|Implement feature/fix on dev branch|type: feature,status: in-progress"
114
+ "Unit Testing|Write and pass unit tests|type: test,status: pending"
115
+ "Code Review|Request and complete code review|needs-review,status: pending"
116
+ "Version Bump|Bump version in README.md and all headers|type: version,status: pending"
117
+ "Changelog Update|Update CHANGELOG.md with release notes|documentation,status: pending"
118
+ "Create RC Branch|Promote dev to rc branch for final testing|type: release,status: pending"
119
+ "Merge to Main|Create PR from rc/dev to main|type: release,needs-review,status: pending"
120
+ )
121
+ fi
122
+
123
+ # ── Create sub-issues first ───────────────────────────────────────
124
+ SUB_LIST=""
125
+ SUB_NUMBERS=""
126
+ for SUB in "${SUB_ISSUES[@]}"; do
127
+ IFS='|' read -r SUB_TITLE SUB_DESC SUB_LABELS <<< "$SUB"
128
+ SUB_FULL_TITLE="${TITLE_PREFIX}(${VERSION}): ${SUB_TITLE}"
129
+
130
+ SUB_BODY=$(printf '### %s\n\n%s\n\n| Field | Value |\n|-------|-------|\n| **Parent Branch** | `%s` |\n| **Version** | `%s` |\n\n---\n*Sub-issue of the %s tracking issue for `%s`.*' \
131
+ "$SUB_TITLE" "$SUB_DESC" "$BRANCH" "$VERSION" "$BRANCH_TYPE" "$BRANCH")
132
+
133
+ SUB_URL=$(gh issue create \
134
+ --repo "$REPO" \
135
+ --title "$SUB_FULL_TITLE" \
136
+ --body "$SUB_BODY" \
137
+ --label "${SUB_LABELS}" \
138
+ --assignee "jmiller" 2>&1)
139
+
140
+ SUB_NUM=$(echo "$SUB_URL" | grep -oE '[0-9]+$')
141
+ if [ -n "$SUB_NUM" ]; then
142
+ SUB_LIST="${SUB_LIST}\n- [ ] ${SUB_TITLE} (#${SUB_NUM})"
143
+ SUB_NUMBERS="${SUB_NUMBERS} #${SUB_NUM}"
144
+ fi
145
+ sleep 0.3
146
+ done
147
+
148
+ # ── Create parent tracking issue ──────────────────────────────────
149
+ PARENT_BODY=$(printf '## %s Branch Created\n\n| Field | Value |\n|-------|-------|\n| **Branch** | `%s` |\n| **Version** | `%s` |\n| **Type** | %s |\n| **Created by** | @%s |\n| **Created at** | %s |\n| **Repository** | `%s` |\n\n## Workflow Sub-Issues\n\n%b\n\n---\n*Auto-created by [auto-dev-issue.yml](.github/workflows/auto-dev-issue.yml) on branch creation.*' \
150
+ "$BRANCH_TYPE" "$BRANCH" "$VERSION" "$BRANCH_TYPE" "$ACTOR" "$NOW" "$REPO" "$SUB_LIST")
151
+
152
+ PARENT_URL=$(gh issue create \
153
+ --repo "$REPO" \
154
+ --title "$TITLE" \
155
+ --body "$PARENT_BODY" \
156
+ --label "${LABEL_TYPE},version" \
157
+ --assignee "jmiller" 2>&1)
158
+
159
+ PARENT_NUM=$(echo "$PARENT_URL" | grep -oE '[0-9]+$')
160
+
161
+ # ── Link sub-issues back to parent ────────────────────────────────
162
+ if [ -n "$PARENT_NUM" ]; then
163
+ for SUB in "${SUB_ISSUES[@]}"; do
164
+ IFS='|' read -r SUB_TITLE _ _ <<< "$SUB"
165
+ SUB_FULL_TITLE="${TITLE_PREFIX}(${VERSION}): ${SUB_TITLE}"
166
+ SUB_NUM=$(gh api "repos/${REPO}/issues?state=open&per_page=20" \
167
+ --jq ".[] | select(.title == \"${SUB_FULL_TITLE}\") | .number" 2>/dev/null | head -1)
168
+ if [ -n "$SUB_NUM" ]; then
169
+ gh api "repos/${REPO}/issues/${SUB_NUM}" -X PATCH \
170
+ -f body="$(gh api "repos/${REPO}/issues/${SUB_NUM}" --jq '.body' 2>/dev/null)
171
+
172
+ > **Parent Issue:** #${PARENT_NUM}" --silent 2>/dev/null || true
173
+ fi
174
+ sleep 0.2
175
+ done
176
+ fi
177
+
178
+ # ── Create or update prerelease for alpha/beta/rc ────────────────
179
+ if [[ "$BRANCH" == rc/* ]] || [[ "$BRANCH" == alpha/* ]] || [[ "$BRANCH" == beta/* ]]; then
180
+ case "$BRANCH_TYPE" in
181
+ Alpha) RELEASE_TAG="alpha" ;;
182
+ Beta) RELEASE_TAG="beta" ;;
183
+ "Release Candidate") RELEASE_TAG="release-candidate" ;;
184
+ esac
185
+
186
+ EXISTING=$(gh release view "$RELEASE_TAG" --json tagName -q .tagName 2>/dev/null || true)
187
+ if [ -z "$EXISTING" ]; then
188
+ gh release create "$RELEASE_TAG" \
189
+ --title "${RELEASE_TAG} (${VERSION})" \
190
+ --notes "## ${BRANCH_TYPE} ${VERSION}\n\nBranch: \`${BRANCH}\`\nTracking issue: ${PARENT_URL}" \
191
+ --prerelease \
192
+ --target main 2>/dev/null || true
193
+ echo "${BRANCH_TYPE} release created: ${RELEASE_TAG}" >> $GITHUB_STEP_SUMMARY
194
+ else
195
+ gh release edit "$RELEASE_TAG" \
196
+ --title "${RELEASE_TAG} (${VERSION})" --prerelease 2>/dev/null || true
197
+ echo "${BRANCH_TYPE} release updated: ${RELEASE_TAG}" >> $GITHUB_STEP_SUMMARY
198
+ fi
199
+ fi
200
+
201
+ # ── Summary ───────────────────────────────────────────────────────
202
+ echo "## Dev Workflow Issues Created" >> $GITHUB_STEP_SUMMARY
203
+ echo "" >> $GITHUB_STEP_SUMMARY
204
+ echo "| Item | Issue |" >> $GITHUB_STEP_SUMMARY
205
+ echo "|------|-------|" >> $GITHUB_STEP_SUMMARY
206
+ echo "| **Parent** | ${PARENT_URL} |" >> $GITHUB_STEP_SUMMARY
207
+ echo "| **Sub-issues** |${SUB_NUMBERS} |" >> $GITHUB_STEP_SUMMARY
@@ -0,0 +1,421 @@
1
+ # Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
2
+ #
3
+ # SPDX-License-Identifier: GPL-3.0-or-later
4
+ #
5
+ # FILE INFORMATION
6
+ # DEFGROUP: Gitea.Workflow
7
+ # INGROUP: mokocli.Release
8
+ # REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/mokocli
9
+ # PATH: /templates/workflows/universal/auto-release.yml.template
10
+ # VERSION: 05.00.00
11
+ # BRIEF: Universal build & release � detects platform from manifest.xml
12
+ #
13
+ # +========================================================================+
14
+ # | UNIVERSAL BUILD & RELEASE PIPELINE |
15
+ # +========================================================================+
16
+ # | |
17
+ # | Reads manifest.xml (joomla|dolibarr|generic) to branch logic. |
18
+ # | |
19
+ # | Platform-specific: |
20
+ # | joomla: XML manifest, type-prefixed packages |
21
+ # | dolibarr: mod*.class.php, update.txt, dev version reset |
22
+ # | generic: README-only, no update stream |
23
+ # | |
24
+ # +========================================================================+
25
+
26
+ name: "Universal: Build & Release"
27
+
28
+ on:
29
+ pull_request:
30
+ types: [opened, closed]
31
+ branches:
32
+ - main
33
+ workflow_dispatch:
34
+ inputs:
35
+ action:
36
+ description: 'Action to perform'
37
+ required: false
38
+ type: choice
39
+ default: release
40
+ options:
41
+ - release
42
+ - promote-rc
43
+
44
+ env:
45
+ FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
46
+ GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
47
+ GITEA_ORG: ${{ vars.GITEA_ORG || github.repository_owner }}
48
+ GITEA_REPO: ${{ vars.GITEA_REPO || github.event.repository.name }}
49
+
50
+ permissions:
51
+ contents: write
52
+
53
+ jobs:
54
+ # ── PR Opened → Rename branch to RC and build RC release ─────────────────────
55
+ promote-rc:
56
+ name: Promote to RC
57
+ runs-on: release
58
+ if: >-
59
+ (github.event.action == 'opened' && github.event.pull_request.merged != true) ||
60
+ (github.event_name == 'workflow_dispatch' && inputs.action == 'promote-rc')
61
+
62
+ steps:
63
+ - name: Checkout repository
64
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
65
+ with:
66
+ token: ${{ secrets.MOKOGITEA_TOKEN }}
67
+ fetch-depth: 1
68
+
69
+ - name: Setup mokocli tools
70
+ env:
71
+ MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
72
+ MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
73
+ run: |
74
+ if [ -f /opt/mokocli/cli/version_bump.php ] && [ -f /opt/mokocli/vendor/autoload.php ]; then
75
+ echo Using pre-installed /opt/mokocli
76
+ echo MOKO_CLI=/opt/mokocli/cli >> $GITHUB_ENV
77
+ else
78
+ echo Falling back to fresh clone
79
+ if ! command -v composer > /dev/null 2>&1; then
80
+ sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer > /dev/null 2>&1
81
+ fi
82
+ rm -rf /tmp/mokocli
83
+ CLONE_URL=https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/mokocli.git
84
+ git clone --depth 1 --branch main --quiet $CLONE_URL /tmp/mokocli
85
+ cd /tmp/mokocli
86
+ composer install --no-dev --no-interaction --quiet
87
+ echo MOKO_CLI=/tmp/mokocli/cli >> $GITHUB_ENV
88
+ fi
89
+
90
+ - name: Rename branch to rc
91
+ run: |
92
+ php ${MOKO_CLI}/branch_rename.php \
93
+ --from "${{ github.event.pull_request.head.ref || 'dev' }}" --to rc \
94
+ --token "${{ secrets.MOKOGITEA_TOKEN }}" \
95
+ --api-base "${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" \
96
+ --pr "${{ github.event.pull_request.number }}"
97
+
98
+ - name: Checkout rc and configure git
99
+ run: |
100
+ git fetch origin rc
101
+ git checkout rc
102
+ git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
103
+ git config --local user.name "gitea-actions[bot]"
104
+ git remote set-url origin "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
105
+
106
+ - name: Publish RC release
107
+ run: |
108
+ php ${MOKO_CLI}/release_publish.php \
109
+ --path . --stability rc --bump minor --branch rc \
110
+ --token "${{ secrets.MOKOGITEA_TOKEN }}"
111
+
112
+ - name: Update RC release notes from CHANGELOG.md
113
+ run: |
114
+ API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
115
+ TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
116
+
117
+ # Extract [Unreleased] section from changelog
118
+ NOTES=""
119
+ if [ -f "CHANGELOG.md" ]; then
120
+ NOTES=$(awk '/^## \[Unreleased\]/{found=1; next} /^## \[/{if(found) exit} found{print}' CHANGELOG.md)
121
+ fi
122
+ [ -z "$NOTES" ] && NOTES="Release candidate"
123
+
124
+ # Find the RC release and update its body
125
+ RELEASE_ID=$(curl -sf -H "Authorization: token ${TOKEN}" \
126
+ "${API_BASE}/releases/tags/release-candidate" \
127
+ | python3 -c "import json,sys; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true)
128
+
129
+ if [ -n "$RELEASE_ID" ]; then
130
+ python3 -c "
131
+ import json, urllib.request
132
+ body = open('/dev/stdin').read()
133
+ payload = json.dumps({'body': body}).encode()
134
+ req = urllib.request.Request(
135
+ '${API_BASE}/releases/${RELEASE_ID}',
136
+ data=payload, method='PATCH',
137
+ headers={
138
+ 'Authorization': 'token ${TOKEN}',
139
+ 'Content-Type': 'application/json'
140
+ })
141
+ urllib.request.urlopen(req)
142
+ " <<< "$NOTES"
143
+ echo "RC release notes updated from CHANGELOG.md"
144
+ fi
145
+
146
+ - name: Summary
147
+ if: always()
148
+ run: |
149
+ echo "## Promoted to Release Candidate" >> $GITHUB_STEP_SUMMARY
150
+ echo "Branch renamed to rc, minor bump, RC release built" >> $GITHUB_STEP_SUMMARY
151
+
152
+ # ── Merged PR → Build & Release (or promote RC to stable) ────────────────────
153
+ release:
154
+ name: Build & Release Pipeline
155
+ runs-on: release
156
+ if: >-
157
+ github.event.pull_request.merged == true ||
158
+ (github.event_name == 'workflow_dispatch' && inputs.action != 'promote-rc')
159
+
160
+ steps:
161
+ - name: Checkout repository
162
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
163
+ with:
164
+ token: ${{ secrets.MOKOGITEA_TOKEN }}
165
+ fetch-depth: 0
166
+
167
+ - name: Configure git for bot pushes
168
+ run: |
169
+ git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
170
+ git config --local user.name "gitea-actions[bot]"
171
+ git remote set-url origin "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
172
+
173
+ - name: Check for merge conflict markers
174
+ run: |
175
+ CONFLICTS=$(grep -rn '<<<<<<< \|>>>>>>> \|^=======$' --include='*.php' --include='*.xml' --include='*.css' --include='*.js' --include='*.json' --include='*.md' --include='*.yml' --include='*.yaml' --include='*.ini' --include='*.txt' . 2>/dev/null | grep -v '.git/' || true)
176
+ if [ -n "$CONFLICTS" ]; then
177
+ echo "::error::Merge conflict markers found — aborting release"
178
+ echo "## Release Blocked: Conflict Markers" >> $GITHUB_STEP_SUMMARY
179
+ echo '```' >> $GITHUB_STEP_SUMMARY
180
+ echo "$CONFLICTS" >> $GITHUB_STEP_SUMMARY
181
+ echo '```' >> $GITHUB_STEP_SUMMARY
182
+ exit 1
183
+ fi
184
+ echo "No conflict markers found"
185
+
186
+ - name: Setup mokocli tools
187
+ env:
188
+ MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
189
+ MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
190
+ COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_MIRROR_TOKEN }}"}}'
191
+ run: |
192
+ if [ -f /opt/mokocli/cli/version_bump.php ] && [ -f /opt/mokocli/vendor/autoload.php ]; then
193
+ echo Using pre-installed /opt/mokocli
194
+ echo MOKO_CLI=/opt/mokocli/cli >> $GITHUB_ENV
195
+ else
196
+ echo Falling back to fresh clone
197
+ if ! command -v composer > /dev/null 2>&1; then
198
+ sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer > /dev/null 2>&1
199
+ fi
200
+ rm -rf /tmp/mokocli
201
+ CLONE_URL=https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/mokocli.git
202
+ git clone --depth 1 --branch main --quiet $CLONE_URL /tmp/mokocli
203
+ cd /tmp/mokocli
204
+ composer install --no-dev --no-interaction --quiet
205
+ echo MOKO_CLI=/tmp/mokocli/cli >> $GITHUB_ENV
206
+ fi
207
+
208
+ - name: "Detect platform"
209
+ id: platform
210
+ run: |
211
+ php ${MOKO_CLI}/platform_detect.php --path . --github-output 2>/dev/null || true
212
+ php ${MOKO_CLI}/manifest_read.php --path . --github-output 2>/dev/null || true
213
+
214
+ - name: "Determine version bump level"
215
+ id: bump
216
+ run: |
217
+ # Fix/patch branches: version was already bumped by pre-release, just strip suffix
218
+ # Feature/dev branches: bump minor for the new stable release
219
+ HEAD_REF="${{ github.event.pull_request.head.ref || 'dev' }}"
220
+ case "$HEAD_REF" in
221
+ fix/*|patch/*|hotfix/*|bugfix/*) BUMP="none" ;;
222
+ *) BUMP="minor" ;;
223
+ esac
224
+ echo "level=${BUMP}" >> "$GITHUB_OUTPUT"
225
+ echo "Bump level: ${BUMP} (from branch: ${HEAD_REF})"
226
+
227
+ - name: "Publish stable release"
228
+ run: |
229
+ BUMP_FLAG=""
230
+ if [ "${{ steps.bump.outputs.level }}" != "none" ]; then
231
+ BUMP_FLAG="--bump ${{ steps.bump.outputs.level }}"
232
+ fi
233
+ php ${MOKO_CLI}/release_publish.php \
234
+ --path . --stability stable ${BUMP_FLAG} --branch main \
235
+ --token "${{ secrets.MOKOGITEA_TOKEN }}"
236
+
237
+ - name: "Read published version"
238
+ id: version
239
+ run: |
240
+ VERSION=$(php ${MOKO_CLI}/version_read.php --path . 2>/dev/null || echo "")
241
+ VERSION=$(echo "$VERSION" | sed 's/-\(dev\|alpha\|beta\|rc\)$//')
242
+ [ -z "$VERSION" ] && VERSION="00.00.00" && echo "skip=true" >> "$GITHUB_OUTPUT"
243
+ echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
244
+ echo "tag=stable" >> "$GITHUB_OUTPUT"
245
+ echo "release_tag=stable" >> "$GITHUB_OUTPUT"
246
+ echo "branch=main" >> "$GITHUB_OUTPUT"
247
+ echo "Published version: ${VERSION}"
248
+
249
+ - name: Update release notes and promote changelog
250
+ run: |
251
+ API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
252
+ TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
253
+
254
+ # Get the stable release info (version and ID)
255
+ RELEASE_JSON=$(curl -sf -H "Authorization: token ${TOKEN}" \
256
+ "${API_BASE}/releases/tags/stable" 2>/dev/null || echo '{}')
257
+ RELEASE_ID=$(python3 -c "import json,sys; print(json.load(sys.stdin).get('id',''))" <<< "$RELEASE_JSON" 2>/dev/null || true)
258
+ # Extract version from release name (e.g. "06.17.00" or "v06.17.00")
259
+ VERSION=$(python3 -c "
260
+ import json, sys, re
261
+ r = json.load(sys.stdin)
262
+ name = r.get('name', '')
263
+ m = re.search(r'(\d+\.\d+\.\d+)', name)
264
+ print(m.group(1) if m else '')
265
+ " <<< "$RELEASE_JSON" 2>/dev/null || true)
266
+
267
+ # Extract [Unreleased] section from changelog
268
+ NOTES=""
269
+ if [ -f "CHANGELOG.md" ]; then
270
+ NOTES=$(awk '/^## \[Unreleased\]/{found=1; next} /^## \[/{if(found) exit} found{print}' CHANGELOG.md)
271
+ fi
272
+ [ -z "$NOTES" ] && NOTES="Stable release"
273
+
274
+ # Update release body via API
275
+ if [ -n "$RELEASE_ID" ]; then
276
+ python3 -c "
277
+ import json, urllib.request
278
+ body = open('/dev/stdin').read()
279
+ payload = json.dumps({'body': body}).encode()
280
+ req = urllib.request.Request(
281
+ '${API_BASE}/releases/${RELEASE_ID}',
282
+ data=payload, method='PATCH',
283
+ headers={
284
+ 'Authorization': 'token ${TOKEN}',
285
+ 'Content-Type': 'application/json'
286
+ })
287
+ urllib.request.urlopen(req)
288
+ " <<< "$NOTES"
289
+ echo "Release notes updated from CHANGELOG.md"
290
+ fi
291
+
292
+ # Promote [Unreleased] → [version] in CHANGELOG.md and reset
293
+ if [ -n "$VERSION" ] && [ -f "CHANGELOG.md" ]; then
294
+ DATE=$(date +%Y-%m-%d)
295
+ python3 -c "
296
+ import sys
297
+ version, date = sys.argv[1], sys.argv[2]
298
+ content = open('CHANGELOG.md').read()
299
+ old = '## [Unreleased]'
300
+ new = f'## [Unreleased]\n\n## [{version}] --- {date}'
301
+ content = content.replace(old, new, 1)
302
+ open('CHANGELOG.md', 'w').write(content)
303
+ " "$VERSION" "$DATE"
304
+ git add CHANGELOG.md
305
+ git commit -m "chore: promote changelog [Unreleased] → [${VERSION}]" || true
306
+ git push origin main || true
307
+ echo "Changelog promoted: [Unreleased] → [${VERSION}]"
308
+ fi
309
+
310
+ # -- STEP 9: Mirror to GitHub (stable only) --------------------------------
311
+ - name: "Step 9: Mirror release to GitHub"
312
+ if: >-
313
+ steps.version.outputs.skip != 'true' &&
314
+ secrets.GH_MIRROR_TOKEN != ''
315
+ continue-on-error: true
316
+ run: |
317
+ VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
318
+ RELEASE_TAG="${{ steps.version.outputs.release_tag }}"
319
+ GH_REPO="${{ vars.GH_MIRROR_REPO || github.repository }}"
320
+ API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
321
+ php ${MOKO_CLI}/release_mirror.php \
322
+ --version "$VERSION" --tag "$RELEASE_TAG" \
323
+ --token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "$API_BASE" \
324
+ --gh-token "${{ secrets.GH_MIRROR_TOKEN }}" --gh-repo "$GH_REPO" \
325
+ --branch main 2>&1 || true
326
+ echo "GitHub mirror updated" >> $GITHUB_STEP_SUMMARY
327
+
328
+ # -- STEP 10: Sync main branch to GitHub mirror ----------------------------
329
+ - name: "Step 10: Push main to GitHub mirror"
330
+ if: >-
331
+ steps.version.outputs.skip != 'true' &&
332
+ secrets.GH_MIRROR_TOKEN != ''
333
+ continue-on-error: true
334
+ run: |
335
+ GH_REPO="${{ vars.GH_MIRROR_REPO || github.repository }}"
336
+ GH_ORG=$(echo "$GH_REPO" | cut -d/ -f1)
337
+ GH_NAME=$(echo "$GH_REPO" | cut -d/ -f2)
338
+ git remote add github "https://x-access-token:${{ secrets.GH_MIRROR_TOKEN }}@github.com/${GH_ORG}/${GH_NAME}.git" 2>/dev/null || \
339
+ git remote set-url github "https://x-access-token:${{ secrets.GH_MIRROR_TOKEN }}@github.com/${GH_ORG}/${GH_NAME}.git"
340
+ git fetch origin main --depth=1
341
+ git push github origin/main:refs/heads/main --force 2>/dev/null \
342
+ && echo "main branch pushed to GitHub mirror" \
343
+ || echo "WARNING: GitHub mirror push failed"
344
+
345
+ - name: "Step 11: Delete rc branch and recreate dev from main"
346
+ if: steps.version.outputs.skip != 'true'
347
+ continue-on-error: true
348
+ run: |
349
+ API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
350
+ TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
351
+
352
+ # Delete rc branch (ephemeral — created by promote-rc)
353
+ curl -sf -X DELETE -H "Authorization: token ${TOKEN}" \
354
+ "${API_BASE}/branches/rc" 2>/dev/null \
355
+ && echo "Deleted rc branch" || echo "rc branch not found"
356
+
357
+ # Delete dev branch
358
+ curl -sf -X DELETE -H "Authorization: token ${TOKEN}" \
359
+ "${API_BASE}/branches/dev" 2>/dev/null && echo "Deleted dev branch"
360
+
361
+ # Recreate dev from main (now includes version bump + changelog promotion)
362
+ curl -sf -X POST -H "Authorization: token ${TOKEN}" \
363
+ -H "Content-Type: application/json" \
364
+ "${API_BASE}/branches" \
365
+ -d '{"new_branch_name":"dev","old_branch_name":"main"}' 2>/dev/null && echo "Recreated dev from main"
366
+
367
+ echo "Pre-release branches cleaned, dev reset from main" >> $GITHUB_STEP_SUMMARY
368
+
369
+ - name: "Step 12: Create version branch from main"
370
+ if: steps.version.outputs.skip != 'true'
371
+ continue-on-error: true
372
+ run: |
373
+ API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
374
+ TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
375
+ VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
376
+ BRANCH_NAME="version/${VERSION}"
377
+ MAIN_SHA=$(git rev-parse HEAD)
378
+
379
+ # Delete old version branch if it exists (same version re-release)
380
+ curl -sf -X DELETE -H "Authorization: token ${TOKEN}" "${API_BASE}/branches/${BRANCH_NAME}" 2>/dev/null && echo "Deleted old ${BRANCH_NAME}"
381
+
382
+ # Create version/XX.YY.ZZ from main
383
+ curl -sf -X POST -H "Authorization: token ${TOKEN}" -H "Content-Type: application/json" "${API_BASE}/branches" -d "{\"new_branch_name\":\"${BRANCH_NAME}\",\"old_branch_name\":\"main\"}" 2>/dev/null && echo "Created ${BRANCH_NAME} from main (${MAIN_SHA})" || echo "WARNING: ${BRANCH_NAME} creation failed"
384
+
385
+ echo "Version branch created: ${BRANCH_NAME} (${MAIN_SHA})" >> $GITHUB_STEP_SUMMARY
386
+
387
+
388
+
389
+ # -- Dolibarr post-release: Reset dev version -----------------------------
390
+ - name: "Post-release: Reset dev version"
391
+ if: steps.version.outputs.skip != 'true'
392
+ continue-on-error: true
393
+ run: |
394
+ API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
395
+ php ${MOKO_CLI}/version_reset_dev.php \
396
+ --token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "${API_BASE}" \
397
+ --branch dev --path . 2>&1 || true
398
+
399
+ # -- Summary --------------------------------------------------------------
400
+ - name: Pipeline Summary
401
+ if: always()
402
+ run: |
403
+ VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
404
+ PLATFORM="${{ steps.platform.outputs.platform }}"
405
+ if [ "${{ steps.version.outputs.skip }}" = "true" ]; then
406
+ echo "## Release Skipped" >> $GITHUB_STEP_SUMMARY
407
+ echo "No VERSION in README.md" >> $GITHUB_STEP_SUMMARY
408
+ elif [ "${{ steps.check.outputs.already_released }}" = "true" ]; then
409
+ echo "## Already Released — ${VERSION}" >> $GITHUB_STEP_SUMMARY
410
+ else
411
+ echo "" >> $GITHUB_STEP_SUMMARY
412
+ echo "## Build & Release Complete (${PLATFORM})" >> $GITHUB_STEP_SUMMARY
413
+ echo "" >> $GITHUB_STEP_SUMMARY
414
+ echo "| Step | Result |" >> $GITHUB_STEP_SUMMARY
415
+ echo "|------|--------|" >> $GITHUB_STEP_SUMMARY
416
+ echo "| Platform | \`${PLATFORM}\` |" >> $GITHUB_STEP_SUMMARY
417
+ echo "| Version | \`${VERSION}\` |" >> $GITHUB_STEP_SUMMARY
418
+ echo "| Branch | \`${{ steps.version.outputs.branch }}\` |" >> $GITHUB_STEP_SUMMARY
419
+ echo "| Tag | \`${{ steps.version.outputs.tag }}\` |" >> $GITHUB_STEP_SUMMARY
420
+ echo "| Release | [View](${GITEA_URL}/${GITEA_ORG}/${GITEA_REPO}/releases/tag/${{ steps.version.outputs.tag }}) |" >> $GITHUB_STEP_SUMMARY
421
+ fi
@@ -0,0 +1,48 @@
1
+ # Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
2
+ #
3
+ # SPDX-License-Identifier: GPL-3.0-or-later
4
+ #
5
+ # FILE INFORMATION
6
+ # DEFGROUP: Gitea.Workflow
7
+ # INGROUP: MokoStandards.Universal
8
+ # REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli
9
+ # PATH: /.mokogitea/workflows/branch-cleanup.yml
10
+ # VERSION: 01.00.00
11
+ # BRIEF: Delete feature branches after PR merge
12
+
13
+ name: "Branch Cleanup"
14
+
15
+ on:
16
+ pull_request:
17
+ types: [closed]
18
+
19
+ env:
20
+ FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
21
+
22
+ jobs:
23
+ cleanup:
24
+ name: Delete merged branch
25
+ runs-on: ubuntu-latest
26
+ if: >-
27
+ github.event.pull_request.merged == true &&
28
+ github.event.pull_request.head.ref != 'dev' &&
29
+ github.event.pull_request.head.ref != 'main'
30
+
31
+ steps:
32
+ - name: Delete source branch
33
+ run: |
34
+ BRANCH="${{ github.event.pull_request.head.ref }}"
35
+ API="${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}/api/v1/repos/${{ github.repository }}/branches"
36
+ ENCODED=$(php -r "echo rawurlencode('${BRANCH}');")
37
+
38
+ STATUS=$(curl -sf -o /dev/null -w "%{http_code}" -X DELETE \
39
+ -H "Authorization: token ${{ secrets.MOKOGITEA_TOKEN }}" \
40
+ "${API}/${ENCODED}" 2>/dev/null || true)
41
+
42
+ if [ "$STATUS" = "204" ]; then
43
+ echo "Deleted branch: ${BRANCH}" >> $GITHUB_STEP_SUMMARY
44
+ elif [ "$STATUS" = "404" ]; then
45
+ echo "Branch already deleted: ${BRANCH}" >> $GITHUB_STEP_SUMMARY
46
+ else
47
+ echo "::warning::Failed to delete branch ${BRANCH} (HTTP ${STATUS})"
48
+ fi