@xn-intenton-z2a/agentic-lib 7.1.51 → 7.1.52

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.
@@ -1,457 +0,0 @@
1
- # SPDX-License-Identifier: MIT
2
- # Copyright (C) 2025-2026 Polycode Limited
3
- # .github/workflows/ci-automerge.yml
4
- #
5
- # This file is part of the example suite for `agentic-lib` see: https://github.com/xn-intenton-z2a/agentic-lib
6
- # This file is licensed under the MIT License. For details, see LICENSE-MIT
7
-
8
- name: ci-automerge
9
- concurrency: agentic-lib-merge-main
10
- run-name: "ci-automerge [${{ github.ref_name }}]"
11
-
12
- on:
13
- pull_request:
14
- check_suite:
15
- workflow_run:
16
- workflows:
17
- - test
18
- types:
19
- - completed
20
- workflow_dispatch:
21
- workflow_call:
22
- inputs:
23
- workflow:
24
- description: 'Was this workflow called by another workflow?, e.g. "true"'
25
- type: string
26
- required: false
27
- default: "true"
28
-
29
- env:
30
- pullRequestLabel: "automerge"
31
- branchPrefix: "agentic-lib-"
32
- copilotBranchPrefix: "copilot/"
33
-
34
- jobs:
35
- label:
36
- runs-on: ubuntu-latest
37
- steps:
38
- - name: echo
39
- shell: bash
40
- run: |
41
- echo "Label: ${{ env.pullRequestLabel }}"
42
- outputs:
43
- pullRequestLabel: ${{ env.pullRequestLabel }}
44
-
45
- pr:
46
- needs: label
47
- if: github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, needs.label.outputs.pullRequestLabel)
48
- runs-on: ubuntu-latest
49
- steps:
50
- - name: check-pr
51
- id: check-pr
52
- uses: actions/github-script@v7
53
- with:
54
- script: |
55
- const pr = context.payload.pull_request;
56
- const pullNumber = pr.number;
57
- const owner = context.repo.owner;
58
- const repo = context.repo.repo;
59
- let shouldSkipMerge;
60
- let prMerged;
61
-
62
- const { data: pullRequest } = await github.rest.pulls.get({
63
- owner,
64
- repo,
65
- pull_number: pullNumber,
66
- });
67
- core.info(`Found pull request #${pullRequest.number} with state: ${pullRequest.state}, mergeable: ${pullRequest.mergeable}`);
68
-
69
- if (pullRequest.state === "closed") {
70
- core.info(`PR #${pullNumber} is already closed.`);
71
- shouldSkipMerge = 'true';
72
- prMerged = 'true';
73
- } else if (pullRequest.state !== "open") {
74
- core.info(`PR #${pullNumber} is not open, it is ${pullRequest.state}.`);
75
- shouldSkipMerge = 'true';
76
- prMerged = 'false';
77
- } else if (pullRequest.mergeable === true) {
78
- core.info(`PR #${pullNumber} is mergeable.`);
79
- shouldSkipMerge = 'false';
80
- prMerged = 'false';
81
- } else if (pullRequest.mergeable === false) {
82
- core.info(`PR #${pullNumber} is not mergeable.`);
83
- shouldSkipMerge = 'true';
84
- prMerged = 'false';
85
- } else {
86
- core.info(`PR #${pullNumber} mergeability is ${pullRequest.mergeable}.`);
87
- shouldSkipMerge = 'true';
88
- prMerged = 'false';
89
- }
90
-
91
- core.setOutput('pullNumber', pullNumber ? pullNumber.toString() : '');
92
- core.setOutput('shouldSkipMerge', shouldSkipMerge);
93
- core.setOutput('prMerged', prMerged);
94
- outputs:
95
- pullNumber: ${{ steps.check-pr.outputs.pullNumber }}
96
- shouldSkipMerge: ${{ steps.check-pr.outputs.shouldSkipMerge }}
97
- prMerged: ${{ steps.check-pr.outputs.prMerged }}
98
-
99
- cs:
100
- if: github.event_name == 'check_suite' && github.event.check_suite.conclusion == 'success'
101
- runs-on: ubuntu-latest
102
- steps:
103
- - name: find-pr
104
- id: find-pr
105
- uses: actions/github-script@v7
106
- with:
107
- script: |
108
- const checkSuite = context.payload.check_suite;
109
- const owner = context.repo.owner;
110
- const repo = context.repo.repo;
111
- const headSha = checkSuite.head_sha;
112
- let pullNumber;
113
- let shouldSkipMerge;
114
- let prMerged;
115
-
116
- const { data: prs } = await github.rest.repos.listPullRequestsAssociatedWithCommit({
117
- owner,
118
- repo,
119
- commit_sha: headSha,
120
- });
121
-
122
- if (!prs || prs.length === 0) {
123
- core.info('No pull requests associated with this check suite.');
124
- pullNumber = '';
125
- shouldSkipMerge = 'true';
126
- prMerged = 'false';
127
- } else {
128
- const openPRs = prs.filter(pr => pr.state === 'open');
129
- const prWithAutomerge = openPRs.find(pr => pr.labels.some(label => label.name === 'automerge'));
130
-
131
- if (!prWithAutomerge) {
132
- core.info('No open pull requests with the "automerge" label.');
133
- pullNumber = '';
134
- shouldSkipMerge = 'true';
135
- prMerged = 'false';
136
- } else {
137
- core.info(`Open pull request with "automerge" label: #${prWithAutomerge.number}`);
138
- pullNumber = prWithAutomerge.number;
139
- shouldSkipMerge = 'false';
140
- prMerged = 'false';
141
- }
142
- }
143
-
144
- core.setOutput('pullNumber', pullNumber ? pullNumber.toString() : '');
145
- core.setOutput('shouldSkipMerge', shouldSkipMerge);
146
- core.setOutput('prMerged', prMerged);
147
- outputs:
148
- pullNumber: ${{ steps.find-pr.outputs.pullNumber }}
149
- shouldSkipMerge: ${{ steps.find-pr.outputs.shouldSkipMerge }}
150
- prMerged: ${{ steps.find-pr.outputs.prMerged }}
151
-
152
- ls:
153
- needs: label
154
- if: >-
155
- github.event_name == 'workflow_dispatch' ||
156
- github.event_name == 'workflow_run' ||
157
- inputs.workflow == 'true' ||
158
- github.event_name == 'workflow_call'
159
- runs-on: ubuntu-latest
160
- steps:
161
- - name: Determine pull request number
162
- id: get-pull
163
- uses: actions/github-script@v7
164
- env:
165
- pullRequestLabel: ${{ needs.label.outputs.pullRequestLabel }}
166
- with:
167
- github-token: ${{ secrets.GITHUB_TOKEN }}
168
- script: |
169
- const branchPrefix = process.env.branchPrefix;
170
- const pullRequestLabel = process.env.pullRequestLabel;
171
- let pullNumber = ''
172
- let branchName = '';
173
- let issueNumber = '';
174
- const { data: pullRequests } = await github.rest.pulls.list({
175
- owner: context.repo.owner,
176
- repo: context.repo.repo,
177
- state: 'open',
178
- per_page: 1,
179
- sort: 'created',
180
- direction: 'asc'
181
- });
182
- if (pullRequests.length > 0) {
183
- const filteredPRs = pullRequests
184
- .filter(pr => pr.labels.some(label => label.name === pullRequestLabel ))
185
- .filter(pr => pr.head.ref.startsWith(branchPrefix));
186
- if (filteredPRs.length > 0) {
187
- const pullRequest = filteredPRs[0];
188
- pullNumber = pullRequest.number;
189
- core.info(`Found open pull request with label ${pullRequestLabel}: #${pullRequest.number} and branch name ${pullRequest.head.ref}`);
190
- core.info(JSON.stringify(pullRequest));
191
- } else {
192
- core.info(`No open pull request found with label ${pullRequestLabel}.`);
193
- pullNumber = '';
194
- }
195
- } else {
196
- pullNumber = '';
197
- core.info('No open pull requests found.');
198
- }
199
- core.info(`pullNumber: ${pullNumber}`);
200
- core.setOutput('pullNumber', pullNumber);
201
- result-encoding: string
202
- outputs:
203
- pullNumber: ${{ steps.get-pull.outputs.pullNumber }}
204
-
205
- merge-check:
206
- if: ${{ !cancelled() }}
207
- needs:
208
- - pr
209
- - cs
210
- - ls
211
- runs-on: ubuntu-latest
212
- steps:
213
- - name: get-pull
214
- id: get-pull
215
- uses: actions/github-script@v7
216
- env:
217
- prMerged: ${{ needs.pr.outputs.prMerged || 'false' }}
218
- pullNumber: ${{ needs.pr.outputs.pullNumber || needs.cs.outputs.pullNumber || needs.ls.outputs.pullNumber || ''}}
219
- shouldSkipMerge: ${{ needs.pr.outputs.shouldSkipMerge || 'false' }}
220
- with:
221
- script: |
222
- // Merge outputs from pr-check, cs-check, and determine-ls.
223
- // Only one of pr-check or cs-check should have run.
224
- const prMerged = process.env.prMerged;
225
- const pullNumber = process.env.pullNumber;
226
- const branchPrefix = process.env.branchPrefix;
227
- const shouldSkipMerge = process.env.shouldSkipMerge;
228
- const owner = context.repo.owner;
229
- const repo = context.repo.repo;
230
-
231
- core.setOutput('prMerged', `${prMerged}`);
232
- core.setOutput('pullNumber', `${pullNumber}`);
233
- core.setOutput('shouldSkipMerge', `${shouldSkipMerge}`);
234
- core.info(`prMerged: '${prMerged}'`);
235
- core.info(`pullNumber: '${pullNumber}'`);
236
- core.info(`shouldSkipMerge: '${shouldSkipMerge}'`);
237
- core.info(`branchPrefix '${branchPrefix}'`);
238
-
239
- let branchName = '';
240
- let issueNumber = '';
241
- if( pullNumber) {
242
- const { data: pullRequest } = await github.rest.pulls.get({
243
- owner,
244
- repo,
245
- pull_number: pullNumber
246
- });
247
- branchName = pullRequest.head.ref;
248
- core.info(`branchName '${branchName}'`);
249
-
250
- // Extract issue number from branch name (supports agentic-lib-* and copilot/* prefixes)
251
- let issueNumberMatch = '';
252
- if (branchName.startsWith(branchPrefix)) {
253
- issueNumberMatch = branchName.replace(branchPrefix, '');
254
- } else if (branchName.startsWith('copilot/')) {
255
- // Copilot branches may contain issue number in the name, e.g. copilot/fix-123
256
- const match = branchName.match(/(\d+)/);
257
- issueNumberMatch = match ? match[1] : '';
258
- }
259
- if (parseInt(issueNumberMatch)) {
260
- issueNumber = `${parseInt(issueNumberMatch)}`;
261
- } else {
262
- issueNumber = '';
263
- }
264
- }
265
-
266
- core.setOutput('branchName', branchName);
267
- core.info(`branchName '${branchName}'`);
268
- core.setOutput('issueNumber', issueNumber);
269
- core.info(`issueNumber '${issueNumber}'`);
270
- result-encoding: string
271
- outputs:
272
- prMerged: ${{ steps.get-pull.outputs.prMerged }}
273
- pullNumber: ${{ steps.get-pull.outputs.pullNumber }}
274
- shouldSkipMerge: ${{ steps.get-pull.outputs.shouldSkipMerge }}
275
- branchName: ${{ steps.get-pull.outputs.branchName }}
276
- issueNumber: ${{ steps.get-pull.outputs.issueNumber }}
277
-
278
- automerge:
279
- needs:
280
- - merge-check
281
- if: ${{ !cancelled() && needs.merge-check.outputs.shouldSkipMerge != 'true' && needs.merge-check.outputs.pullNumber != '' }}
282
- permissions:
283
- contents: write
284
- pull-requests: write
285
- checks: write
286
- runs-on: ubuntu-latest
287
- env:
288
- pullNumber: ${{ needs.merge-check.outputs.pullNumber }}
289
- steps:
290
- - name: trigger-checks
291
- id: trigger-checks
292
- uses: actions/github-script@v7
293
- with:
294
- script: |
295
- const pullNumber = parseInt(process.env.pullNumber);
296
- if (!pullNumber) return;
297
- const owner = context.repo.owner;
298
- const repo = context.repo.repo;
299
-
300
- const { data: pullRequest } = await github.rest.pulls.get({
301
- owner, repo, pull_number: pullNumber,
302
- });
303
- core.info(`PR #${pullNumber} state: ${pullRequest.state}, mergeable: ${pullRequest.mergeable}`);
304
-
305
- if (pullRequest.state === "closed") {
306
- core.info(`PR #${pullNumber} is already closed.`);
307
- } else if (pullRequest.mergeable === null) {
308
- core.info(`PR #${pullNumber} mergeability unknown, triggering check re-runs.`);
309
- const ref = pullRequest.head.sha;
310
- const { data: checkSuites } = await github.rest.checks.listSuitesForRef({ owner, repo, ref });
311
- for (const suite of checkSuites.check_suites) {
312
- try {
313
- await github.rest.checks.rerequestSuite({ owner, repo, check_suite_id: suite.id });
314
- } catch (error) {
315
- core.info(`Failed to re-request check suite: ${error.message}`);
316
- }
317
- }
318
- }
319
-
320
- - name: Wait for checks
321
- run: sleep 5
322
-
323
- - name: auto-merge-pr
324
- id: auto-merge-pr
325
- uses: actions/github-script@v7
326
- with:
327
- script: |
328
- const pullNumber = parseInt(process.env.pullNumber);
329
- if (!pullNumber) { core.setOutput('prMerged', 'false'); core.setOutput('message', 'No PR number'); return; }
330
- const owner = context.repo.owner;
331
- const repo = context.repo.repo;
332
- let prMerged;
333
- let message = '';
334
-
335
- const { data: pullRequest } = await github.rest.pulls.get({
336
- owner, repo, pull_number: pullNumber,
337
- });
338
- core.info(`PR #${pullNumber} state: ${pullRequest.state}, mergeable_state: ${pullRequest.mergeable_state}`);
339
-
340
- if (pullRequest.state === "closed") {
341
- if (pullRequest.merged) {
342
- message = `PR #${pullNumber} is closed and merged.`;
343
- prMerged = 'true';
344
- } else {
345
- message = `PR #${pullNumber} is closed but not merged.`;
346
- prMerged = 'false';
347
- }
348
- } else if (pullRequest.mergeable && pullRequest.mergeable_state === 'clean') {
349
- await github.rest.pulls.merge({ owner, repo, pull_number: pullNumber, merge_method: 'squash' });
350
- core.info(`PR #${pullNumber} merged successfully.`);
351
- const branchRef = `heads/${pullRequest.head.ref}`;
352
- await github.rest.git.deleteRef({ owner, repo, ref: branchRef });
353
- message = `Branch '${pullRequest.head.ref}' deleted.`;
354
- prMerged = 'true';
355
- } else if (pullRequest.mergeable_state === 'dirty' || pullRequest.mergeable === false) {
356
- message = `PR #${pullNumber} has conflicts. Removing automerge label.`;
357
- try {
358
- await github.rest.issues.removeLabel({
359
- owner, repo, issue_number: pullNumber, name: 'automerge',
360
- });
361
- } catch (e) {
362
- core.info(`Could not remove automerge label: ${e.message}`);
363
- }
364
- await github.rest.issues.createComment({
365
- owner, repo, issue_number: pullNumber,
366
- body: `Automerge label removed — this PR has conflicts (mergeable_state: ${pullRequest.mergeable_state}). Resolve conflicts and re-add the label to retry.`,
367
- });
368
- prMerged = 'false';
369
- } else if (pullRequest.mergeable_state === 'unstable') {
370
- message = `PR #${pullNumber} checks still running (mergeable_state: unstable). Will retry when test workflow completes.`;
371
- prMerged = 'false';
372
- } else if (pullRequest.mergeable === null) {
373
- message = `PR #${pullNumber} does not yet have a value for mergeability.`;
374
- prMerged = 'false';
375
- } else {
376
- message = `PR #${pullNumber} is in an unexpected state: ${pullRequest.mergeable_state}.`;
377
- prMerged = 'false';
378
- }
379
-
380
- core.setOutput('prMerged', prMerged);
381
- core.setOutput('message', message);
382
- outputs:
383
- prMerged: ${{ steps.auto-merge-pr.outputs.prMerged }}
384
- message: ${{ steps.auto-merge-pr.outputs.message }}
385
-
386
- validate-issue-number:
387
- needs:
388
- - merge-check
389
- if: ${{ !cancelled() }}
390
- runs-on: ubuntu-latest
391
- steps:
392
- - id: validate-issue-number
393
- run: |
394
- issueNumber="${{ needs.merge-check.outputs.issueNumber }}"
395
- if [[ -n "$issueNumber" && "$issueNumber" =~ [0-9] ]]; then
396
- echo "[$issueNumber] is a valid issue number."
397
- echo "isValid=true" >> $GITHUB_OUTPUT
398
- else
399
- echo "[$issueNumber] is not a valid issue number."
400
- echo "isValid=false" >> $GITHUB_OUTPUT
401
- fi
402
- outputs:
403
- isValid: ${{ steps.validate-issue-number.outputs.isValid }}
404
-
405
- label-issue-after-automerge:
406
- needs:
407
- - merge-check
408
- - automerge
409
- - validate-issue-number
410
- if: ${{ !cancelled() && ( needs.automerge.outputs.prMerged == 'true' && needs.merge-check.outputs.pullNumber != '' && needs.validate-issue-number.outputs.isValid == 'true' ) }}
411
- permissions:
412
- contents: write
413
- issues: write
414
- pull-requests: read
415
- runs-on: ubuntu-latest
416
- env:
417
- pullNumber: ${{ needs.automerge.outputs.prMerged == 'true' && needs.merge-check.outputs.pullNumber || '' }}
418
- issueNumber: ${{ needs.merge-check.outputs.issueNumber }}
419
- steps:
420
- - name: Label issue after merge
421
- uses: actions/github-script@v7
422
- with:
423
- script: |
424
- const pullNumber = parseInt(process.env.pullNumber);
425
- const issueNumber = parseInt(process.env.issueNumber);
426
- if (!pullNumber || !issueNumber) return;
427
- const owner = context.repo.owner;
428
- const repo = context.repo.repo;
429
-
430
- const { data: pullRequest } = await github.rest.pulls.get({
431
- owner, repo, pull_number: pullNumber,
432
- });
433
- const branchName = pullRequest.head.ref;
434
-
435
- const { data: issue } = await github.rest.issues.get({
436
- owner, repo, issue_number: issueNumber,
437
- });
438
- const hasMergedLabel = issue.labels.some(label => label.name === 'merged');
439
- const hasInProgressLabel = issue.labels.some(label => label.name === 'in-progress');
440
-
441
- if (!hasMergedLabel) {
442
- core.info(`Adding "merged" label to issue #${issueNumber}.`);
443
- await github.rest.issues.addLabels({
444
- owner, repo, issue_number: issueNumber, labels: ['merged'],
445
- });
446
- await github.rest.issues.createComment({
447
- owner, repo, issue_number: issueNumber,
448
- body: `The feature branch has been merged: ${branchName}`,
449
- });
450
- }
451
-
452
- if (hasInProgressLabel) {
453
- core.info(`Removing "in-progress" label from issue #${issueNumber}.`);
454
- await github.rest.issues.removeLabel({
455
- owner, repo, issue_number: issueNumber, name: 'in-progress',
456
- });
457
- }