reposets 0.4.1 → 0.4.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,875 @@
1
+ import { GitHubApiError } from "../errors.js";
2
+ import { encryptSecret } from "../lib/crypto.js";
3
+ import { Context, Effect, Layer } from "effect";
4
+ import { Octokit } from "@octokit/rest";
5
+
6
+ //#region src/services/GitHubClient.ts
7
+ var GitHubClient = class extends Context.Tag("GitHubClient")() {};
8
+ /** Settings fields that are only valid for organization-owned repositories. */
9
+ const ORG_ONLY_SETTINGS = new Set(["allow_forking"]);
10
+ /**
11
+ * Fields in the user-facing security_and_analysis block that GitHub's API
12
+ * accepts as `{ status: "enabled" | "disabled" }`. The value as stored in
13
+ * config is the literal string; we wrap it before sending.
14
+ */
15
+ const SAA_STATUS_FIELDS = new Set([
16
+ "advanced_security",
17
+ "code_security",
18
+ "secret_scanning",
19
+ "secret_scanning_push_protection",
20
+ "secret_scanning_ai_detection",
21
+ "secret_scanning_non_provider_patterns",
22
+ "secret_scanning_delegated_alert_dismissal",
23
+ "secret_scanning_delegated_bypass",
24
+ "dependabot_security_updates"
25
+ ]);
26
+ /**
27
+ * Translate the user-facing security_and_analysis config block into the
28
+ * shape GitHub expects on `PATCH /repos/{o}/{r}`. Reviewer entries are
29
+ * expected to already have a numeric `reviewer_id` and `reviewer_type`
30
+ * (resolution from team slugs happens in the SyncEngine).
31
+ */
32
+ function transformSecurityAndAnalysis(value) {
33
+ if (value === null || typeof value !== "object") return void 0;
34
+ const input = value;
35
+ const out = {};
36
+ for (const [key, raw] of Object.entries(input)) {
37
+ if (raw === void 0) continue;
38
+ if (SAA_STATUS_FIELDS.has(key) && (raw === "enabled" || raw === "disabled")) out[key] = { status: raw };
39
+ else if (key === "delegated_bypass_reviewers" && Array.isArray(raw) && raw.length > 0) out.secret_scanning_delegated_bypass_options = { reviewers: raw };
40
+ }
41
+ return Object.keys(out).length > 0 ? out : void 0;
42
+ }
43
+ /**
44
+ * Settings fields only available via the GraphQL `updateRepository` mutation.
45
+ * Maps snake_case config keys to camelCase GraphQL input field names.
46
+ */
47
+ const GRAPHQL_SETTINGS = {
48
+ has_sponsorships: "hasSponsorshipsEnabled",
49
+ has_pull_requests: "hasPullRequestsEnabled"
50
+ };
51
+ /* v8 ignore start -- live Octokit API calls, tested via GitHubClientTest recorder */
52
+ function GitHubClientLive(token) {
53
+ return Layer.succeed(GitHubClient, (() => {
54
+ const octokit = new Octokit({ auth: token });
55
+ function wrapError(error) {
56
+ if (error instanceof Error) {
57
+ const asAny = error;
58
+ const status = typeof asAny.status === "number" ? asAny.status : void 0;
59
+ if (status !== void 0) return new GitHubApiError({
60
+ message: error.message,
61
+ status
62
+ });
63
+ return new GitHubApiError({ message: error.message });
64
+ }
65
+ return new GitHubApiError({ message: String(error) });
66
+ }
67
+ const ownerTypeCache = /* @__PURE__ */ new Map();
68
+ const teamIdCache = /* @__PURE__ */ new Map();
69
+ const roleIdCache = /* @__PURE__ */ new Map();
70
+ return {
71
+ getOwnerType(owner) {
72
+ return Effect.tryPromise({
73
+ try: async () => {
74
+ const cached = ownerTypeCache.get(owner);
75
+ if (cached) return cached;
76
+ const { data } = await octokit.users.getByUsername({ username: owner });
77
+ const ownerType = data.type === "Organization" ? "Organization" : "User";
78
+ ownerTypeCache.set(owner, ownerType);
79
+ return ownerType;
80
+ },
81
+ catch: wrapError
82
+ });
83
+ },
84
+ syncSecret(owner, repo, name, value, scope) {
85
+ return Effect.tryPromise({
86
+ try: async () => {
87
+ if (scope === "actions") {
88
+ const { data: publicKey } = await octokit.actions.getRepoPublicKey({
89
+ owner,
90
+ repo
91
+ });
92
+ const encryptedValue = encryptSecret(publicKey.key, value);
93
+ await octokit.actions.createOrUpdateRepoSecret({
94
+ owner,
95
+ repo,
96
+ secret_name: name,
97
+ encrypted_value: encryptedValue,
98
+ key_id: publicKey.key_id
99
+ });
100
+ } else if (scope === "dependabot") {
101
+ const { data: publicKey } = await octokit.dependabot.getRepoPublicKey({
102
+ owner,
103
+ repo
104
+ });
105
+ const encryptedValue = encryptSecret(publicKey.key, value);
106
+ await octokit.dependabot.createOrUpdateRepoSecret({
107
+ owner,
108
+ repo,
109
+ secret_name: name,
110
+ encrypted_value: encryptedValue,
111
+ key_id: publicKey.key_id
112
+ });
113
+ } else {
114
+ const { data: publicKey } = await octokit.codespaces.getRepoPublicKey({
115
+ owner,
116
+ repo
117
+ });
118
+ const encryptedValue = encryptSecret(publicKey.key, value);
119
+ await octokit.codespaces.createOrUpdateRepoSecret({
120
+ owner,
121
+ repo,
122
+ secret_name: name,
123
+ encrypted_value: encryptedValue,
124
+ key_id: publicKey.key_id
125
+ });
126
+ }
127
+ },
128
+ catch: wrapError
129
+ });
130
+ },
131
+ syncVariable(owner, repo, name, value) {
132
+ return Effect.tryPromise({
133
+ try: async () => {
134
+ const { data } = await octokit.actions.listRepoVariables({
135
+ owner,
136
+ repo
137
+ });
138
+ if (data.variables.some((v) => v.name === name)) await octokit.actions.updateRepoVariable({
139
+ owner,
140
+ repo,
141
+ name,
142
+ value
143
+ });
144
+ else await octokit.actions.createRepoVariable({
145
+ owner,
146
+ repo,
147
+ name,
148
+ value
149
+ });
150
+ },
151
+ catch: wrapError
152
+ });
153
+ },
154
+ syncSettings(owner, repo, settings) {
155
+ return Effect.tryPromise({
156
+ try: async () => {
157
+ const restSettings = {};
158
+ const graphqlInput = {};
159
+ for (const [key, value] of Object.entries(settings)) {
160
+ if (key === "security_and_analysis") {
161
+ const saa = transformSecurityAndAnalysis(value);
162
+ if (saa !== void 0) restSettings.security_and_analysis = saa;
163
+ continue;
164
+ }
165
+ const graphqlField = GRAPHQL_SETTINGS[key];
166
+ if (graphqlField !== void 0) graphqlInput[graphqlField] = value;
167
+ else restSettings[key] = value;
168
+ }
169
+ if (restSettings.allow_merge_commit === false) {
170
+ delete restSettings.merge_commit_title;
171
+ delete restSettings.merge_commit_message;
172
+ }
173
+ if (restSettings.allow_squash_merge === false) {
174
+ delete restSettings.squash_merge_commit_title;
175
+ delete restSettings.squash_merge_commit_message;
176
+ }
177
+ if (Object.keys(restSettings).length > 0) await octokit.repos.update({
178
+ owner,
179
+ repo,
180
+ ...restSettings
181
+ });
182
+ if (Object.keys(graphqlInput).length > 0) {
183
+ const { data: repoData } = await octokit.repos.get({
184
+ owner,
185
+ repo
186
+ });
187
+ await octokit.graphql(`mutation UpdateRepository($input: UpdateRepositoryInput!) {
188
+ updateRepository(input: $input) {
189
+ repository { id }
190
+ }
191
+ }`, { input: {
192
+ repositoryId: repoData.node_id,
193
+ ...graphqlInput
194
+ } });
195
+ }
196
+ },
197
+ catch: wrapError
198
+ });
199
+ },
200
+ syncRuleset(owner, repo, name, payload) {
201
+ return Effect.tryPromise({
202
+ try: async () => {
203
+ const { data: existing } = await octokit.repos.getRepoRulesets({
204
+ owner,
205
+ repo
206
+ });
207
+ const match = existing.find((r) => r.name === name);
208
+ const body = {
209
+ name: payload.name,
210
+ target: payload.target,
211
+ enforcement: payload.enforcement,
212
+ ...payload.conditions !== void 0 ? { conditions: payload.conditions } : {},
213
+ ...payload.rules !== void 0 ? { rules: payload.rules } : {},
214
+ ...payload.bypass_actors !== void 0 ? { bypass_actors: payload.bypass_actors } : {}
215
+ };
216
+ if (match) await octokit.repos.updateRepoRuleset({
217
+ owner,
218
+ repo,
219
+ ruleset_id: match.id,
220
+ ...body
221
+ });
222
+ else await octokit.repos.createRepoRuleset({
223
+ owner,
224
+ repo,
225
+ ...body
226
+ });
227
+ },
228
+ catch: wrapError
229
+ });
230
+ },
231
+ listSecrets(owner, repo, scope) {
232
+ return Effect.tryPromise({
233
+ try: async () => {
234
+ if (scope === "actions") {
235
+ const { data } = await octokit.actions.listRepoSecrets({
236
+ owner,
237
+ repo
238
+ });
239
+ return data.secrets.map((s) => ({ name: s.name }));
240
+ } else if (scope === "dependabot") {
241
+ const { data } = await octokit.dependabot.listRepoSecrets({
242
+ owner,
243
+ repo
244
+ });
245
+ return data.secrets.map((s) => ({ name: s.name }));
246
+ } else {
247
+ const { data } = await octokit.codespaces.listRepoSecrets({
248
+ owner,
249
+ repo
250
+ });
251
+ return data.secrets.map((s) => ({ name: s.name }));
252
+ }
253
+ },
254
+ catch: wrapError
255
+ });
256
+ },
257
+ listVariables(owner, repo) {
258
+ return Effect.tryPromise({
259
+ try: async () => {
260
+ const { data } = await octokit.actions.listRepoVariables({
261
+ owner,
262
+ repo
263
+ });
264
+ return data.variables.map((v) => ({ name: v.name }));
265
+ },
266
+ catch: wrapError
267
+ });
268
+ },
269
+ listRulesets(owner, repo) {
270
+ return Effect.tryPromise({
271
+ try: async () => {
272
+ const { data } = await octokit.repos.getRepoRulesets({
273
+ owner,
274
+ repo
275
+ });
276
+ return data.map((r) => ({
277
+ name: r.name,
278
+ id: r.id,
279
+ source_type: r.source_type
280
+ }));
281
+ },
282
+ catch: wrapError
283
+ });
284
+ },
285
+ deleteSecret(owner, repo, name, scope) {
286
+ return Effect.tryPromise({
287
+ try: async () => {
288
+ if (scope === "actions") await octokit.actions.deleteRepoSecret({
289
+ owner,
290
+ repo,
291
+ secret_name: name
292
+ });
293
+ else if (scope === "dependabot") await octokit.dependabot.deleteRepoSecret({
294
+ owner,
295
+ repo,
296
+ secret_name: name
297
+ });
298
+ else await octokit.codespaces.deleteRepoSecret({
299
+ owner,
300
+ repo,
301
+ secret_name: name
302
+ });
303
+ },
304
+ catch: wrapError
305
+ });
306
+ },
307
+ deleteVariable(owner, repo, name) {
308
+ return Effect.tryPromise({
309
+ try: async () => {
310
+ await octokit.actions.deleteRepoVariable({
311
+ owner,
312
+ repo,
313
+ name
314
+ });
315
+ },
316
+ catch: wrapError
317
+ });
318
+ },
319
+ deleteRuleset(owner, repo, rulesetId) {
320
+ return Effect.tryPromise({
321
+ try: async () => {
322
+ await octokit.repos.deleteRepoRuleset({
323
+ owner,
324
+ repo,
325
+ ruleset_id: rulesetId
326
+ });
327
+ },
328
+ catch: wrapError
329
+ });
330
+ },
331
+ syncEnvironment(owner, repo, name, config) {
332
+ return Effect.tryPromise({
333
+ try: async () => {
334
+ await octokit.repos.createOrUpdateEnvironment({
335
+ owner,
336
+ repo,
337
+ environment_name: name,
338
+ ...config
339
+ });
340
+ },
341
+ catch: wrapError
342
+ });
343
+ },
344
+ syncEnvironmentSecret(owner, repo, envName, name, value) {
345
+ return Effect.tryPromise({
346
+ try: async () => {
347
+ const { data: publicKey } = await octokit.actions.getEnvironmentPublicKey({
348
+ owner,
349
+ repo,
350
+ environment_name: envName
351
+ });
352
+ const encrypted_value = encryptSecret(publicKey.key, value);
353
+ await octokit.actions.createOrUpdateEnvironmentSecret({
354
+ owner,
355
+ repo,
356
+ environment_name: envName,
357
+ secret_name: name,
358
+ encrypted_value,
359
+ key_id: publicKey.key_id
360
+ });
361
+ },
362
+ catch: wrapError
363
+ });
364
+ },
365
+ syncEnvironmentVariable(owner, repo, envName, name, value) {
366
+ return Effect.tryPromise({
367
+ try: async () => {
368
+ const { data } = await octokit.actions.listEnvironmentVariables({
369
+ owner,
370
+ repo,
371
+ environment_name: envName
372
+ });
373
+ if (data.variables.some((v) => v.name === name)) await octokit.actions.updateEnvironmentVariable({
374
+ owner,
375
+ repo,
376
+ environment_name: envName,
377
+ name,
378
+ value
379
+ });
380
+ else await octokit.actions.createEnvironmentVariable({
381
+ owner,
382
+ repo,
383
+ environment_name: envName,
384
+ name,
385
+ value
386
+ });
387
+ },
388
+ catch: wrapError
389
+ });
390
+ },
391
+ listEnvironments(owner, repo) {
392
+ return Effect.tryPromise({
393
+ try: async () => {
394
+ const { data } = await octokit.repos.getAllEnvironments({
395
+ owner,
396
+ repo
397
+ });
398
+ return (data.environments ?? []).map((e) => ({ name: e.name }));
399
+ },
400
+ catch: wrapError
401
+ });
402
+ },
403
+ listEnvironmentSecrets(owner, repo, envName) {
404
+ return Effect.tryPromise({
405
+ try: async () => {
406
+ const { data } = await octokit.actions.listEnvironmentSecrets({
407
+ owner,
408
+ repo,
409
+ environment_name: envName
410
+ });
411
+ return data.secrets.map((s) => ({ name: s.name }));
412
+ },
413
+ catch: wrapError
414
+ });
415
+ },
416
+ listEnvironmentVariables(owner, repo, envName) {
417
+ return Effect.tryPromise({
418
+ try: async () => {
419
+ const { data } = await octokit.actions.listEnvironmentVariables({
420
+ owner,
421
+ repo,
422
+ environment_name: envName
423
+ });
424
+ return data.variables.map((v) => ({ name: v.name }));
425
+ },
426
+ catch: wrapError
427
+ });
428
+ },
429
+ deleteEnvironment(owner, repo, name) {
430
+ return Effect.tryPromise({
431
+ try: async () => {
432
+ await octokit.repos.deleteAnEnvironment({
433
+ owner,
434
+ repo,
435
+ environment_name: name
436
+ });
437
+ },
438
+ catch: wrapError
439
+ });
440
+ },
441
+ deleteEnvironmentSecret(owner, repo, envName, name) {
442
+ return Effect.tryPromise({
443
+ try: async () => {
444
+ await octokit.actions.deleteEnvironmentSecret({
445
+ owner,
446
+ repo,
447
+ environment_name: envName,
448
+ secret_name: name
449
+ });
450
+ },
451
+ catch: wrapError
452
+ });
453
+ },
454
+ deleteEnvironmentVariable(owner, repo, envName, name) {
455
+ return Effect.tryPromise({
456
+ try: async () => {
457
+ await octokit.actions.deleteEnvironmentVariable({
458
+ owner,
459
+ repo,
460
+ environment_name: envName,
461
+ name
462
+ });
463
+ },
464
+ catch: wrapError
465
+ });
466
+ },
467
+ getVulnerabilityAlerts(owner, repo) {
468
+ return Effect.tryPromise({
469
+ try: async () => {
470
+ try {
471
+ await octokit.request("GET /repos/{owner}/{repo}/vulnerability-alerts", {
472
+ owner,
473
+ repo
474
+ });
475
+ return true;
476
+ } catch (error) {
477
+ if (error.status === 404) return false;
478
+ throw error;
479
+ }
480
+ },
481
+ catch: wrapError
482
+ });
483
+ },
484
+ setVulnerabilityAlerts(owner, repo, enabled) {
485
+ return Effect.tryPromise({
486
+ try: async () => {
487
+ if (enabled) await octokit.request("PUT /repos/{owner}/{repo}/vulnerability-alerts", {
488
+ owner,
489
+ repo
490
+ });
491
+ else await octokit.request("DELETE /repos/{owner}/{repo}/vulnerability-alerts", {
492
+ owner,
493
+ repo
494
+ });
495
+ },
496
+ catch: wrapError
497
+ });
498
+ },
499
+ getAutomatedSecurityFixes(owner, repo) {
500
+ return Effect.tryPromise({
501
+ try: async () => {
502
+ const { data } = await octokit.request("GET /repos/{owner}/{repo}/automated-security-fixes", {
503
+ owner,
504
+ repo
505
+ });
506
+ return Boolean(data.enabled);
507
+ },
508
+ catch: wrapError
509
+ });
510
+ },
511
+ setAutomatedSecurityFixes(owner, repo, enabled) {
512
+ return Effect.tryPromise({
513
+ try: async () => {
514
+ if (enabled) await octokit.request("PUT /repos/{owner}/{repo}/automated-security-fixes", {
515
+ owner,
516
+ repo
517
+ });
518
+ else await octokit.request("DELETE /repos/{owner}/{repo}/automated-security-fixes", {
519
+ owner,
520
+ repo
521
+ });
522
+ },
523
+ catch: wrapError
524
+ });
525
+ },
526
+ getPrivateVulnerabilityReporting(owner, repo) {
527
+ return Effect.tryPromise({
528
+ try: async () => {
529
+ const { data } = await octokit.request("GET /repos/{owner}/{repo}/private-vulnerability-reporting", {
530
+ owner,
531
+ repo
532
+ });
533
+ return Boolean(data.enabled);
534
+ },
535
+ catch: wrapError
536
+ });
537
+ },
538
+ setPrivateVulnerabilityReporting(owner, repo, enabled) {
539
+ return Effect.tryPromise({
540
+ try: async () => {
541
+ if (enabled) await octokit.request("PUT /repos/{owner}/{repo}/private-vulnerability-reporting", {
542
+ owner,
543
+ repo
544
+ });
545
+ else await octokit.request("DELETE /repos/{owner}/{repo}/private-vulnerability-reporting", {
546
+ owner,
547
+ repo
548
+ });
549
+ },
550
+ catch: wrapError
551
+ });
552
+ },
553
+ updateCodeScanningDefaultSetup(owner, repo, config) {
554
+ return Effect.tryPromise({
555
+ try: async () => {
556
+ const body = {};
557
+ if (config.state !== void 0) body.state = config.state;
558
+ if (config.languages !== void 0) body.languages = [...config.languages];
559
+ if (config.query_suite !== void 0) body.query_suite = config.query_suite;
560
+ if (config.threat_model !== void 0) body.threat_model = config.threat_model;
561
+ if (config.runner_type !== void 0) body.runner_type = config.runner_type;
562
+ if (config.runner_label !== void 0) body.runner_label = config.runner_label;
563
+ await octokit.request("PATCH /repos/{owner}/{repo}/code-scanning/default-setup", {
564
+ owner,
565
+ repo,
566
+ ...body
567
+ });
568
+ },
569
+ catch: wrapError
570
+ });
571
+ },
572
+ listRepoLanguages(owner, repo) {
573
+ return Effect.tryPromise({
574
+ try: async () => {
575
+ const { data } = await octokit.repos.listLanguages({
576
+ owner,
577
+ repo
578
+ });
579
+ return Object.keys(data);
580
+ },
581
+ catch: wrapError
582
+ });
583
+ },
584
+ resolveTeamId(org, slug) {
585
+ return Effect.tryPromise({
586
+ try: async () => {
587
+ const cacheKey = `${org}:${slug}`;
588
+ const cached = teamIdCache.get(cacheKey);
589
+ if (cached !== void 0) return cached;
590
+ const { data } = await octokit.teams.getByName({
591
+ org,
592
+ team_slug: slug
593
+ });
594
+ teamIdCache.set(cacheKey, data.id);
595
+ return data.id;
596
+ },
597
+ catch: wrapError
598
+ });
599
+ },
600
+ resolveRoleId(org, name) {
601
+ return Effect.tryPromise({
602
+ try: async () => {
603
+ const cacheKey = `${org}:${name}`;
604
+ const cached = roleIdCache.get(cacheKey);
605
+ if (cached !== void 0) return cached;
606
+ const { data } = await octokit.request("GET /orgs/{org}/organization-roles", { org });
607
+ const roles = data.roles ?? [];
608
+ const role = roles.find((r) => r.name === name);
609
+ if (!role) throw new Error(`organization role '${name}' not found in '${org}' (available: ${roles.map((r) => r.name).join(", ") || "none"})`);
610
+ roleIdCache.set(cacheKey, role.id);
611
+ return role.id;
612
+ },
613
+ catch: wrapError
614
+ });
615
+ }
616
+ };
617
+ })());
618
+ }
619
+ function GitHubClientTest() {
620
+ const recorded = [];
621
+ return {
622
+ layer: Layer.succeed(GitHubClient, {
623
+ getOwnerType(_owner) {
624
+ return Effect.succeed("User");
625
+ },
626
+ syncSecret(owner, repo, name, _value, scope) {
627
+ recorded.push({
628
+ method: "syncSecret",
629
+ args: {
630
+ owner,
631
+ repo,
632
+ name,
633
+ scope
634
+ }
635
+ });
636
+ return Effect.void;
637
+ },
638
+ syncVariable(owner, repo, name, _value) {
639
+ recorded.push({
640
+ method: "syncVariable",
641
+ args: {
642
+ owner,
643
+ repo,
644
+ name
645
+ }
646
+ });
647
+ return Effect.void;
648
+ },
649
+ syncSettings(owner, repo, settings) {
650
+ recorded.push({
651
+ method: "syncSettings",
652
+ args: {
653
+ owner,
654
+ repo,
655
+ settings
656
+ }
657
+ });
658
+ return Effect.void;
659
+ },
660
+ syncRuleset(owner, repo, name, _payload) {
661
+ recorded.push({
662
+ method: "syncRuleset",
663
+ args: {
664
+ owner,
665
+ repo,
666
+ name
667
+ }
668
+ });
669
+ return Effect.void;
670
+ },
671
+ listSecrets(_owner, _repo, _scope) {
672
+ return Effect.succeed([]);
673
+ },
674
+ listVariables(_owner, _repo) {
675
+ return Effect.succeed([]);
676
+ },
677
+ listRulesets(_owner, _repo) {
678
+ return Effect.succeed([]);
679
+ },
680
+ deleteSecret(owner, repo, name, scope) {
681
+ recorded.push({
682
+ method: "deleteSecret",
683
+ args: {
684
+ owner,
685
+ repo,
686
+ name,
687
+ scope
688
+ }
689
+ });
690
+ return Effect.void;
691
+ },
692
+ deleteVariable(owner, repo, name) {
693
+ recorded.push({
694
+ method: "deleteVariable",
695
+ args: {
696
+ owner,
697
+ repo,
698
+ name
699
+ }
700
+ });
701
+ return Effect.void;
702
+ },
703
+ deleteRuleset(owner, repo, rulesetId) {
704
+ recorded.push({
705
+ method: "deleteRuleset",
706
+ args: {
707
+ owner,
708
+ repo,
709
+ rulesetId
710
+ }
711
+ });
712
+ return Effect.void;
713
+ },
714
+ syncEnvironment(owner, repo, name, _config) {
715
+ recorded.push({
716
+ method: "syncEnvironment",
717
+ args: {
718
+ owner,
719
+ repo,
720
+ name
721
+ }
722
+ });
723
+ return Effect.void;
724
+ },
725
+ syncEnvironmentSecret(owner, repo, envName, name, _value) {
726
+ recorded.push({
727
+ method: "syncEnvironmentSecret",
728
+ args: {
729
+ owner,
730
+ repo,
731
+ envName,
732
+ name
733
+ }
734
+ });
735
+ return Effect.void;
736
+ },
737
+ syncEnvironmentVariable(owner, repo, envName, name, _value) {
738
+ recorded.push({
739
+ method: "syncEnvironmentVariable",
740
+ args: {
741
+ owner,
742
+ repo,
743
+ envName,
744
+ name
745
+ }
746
+ });
747
+ return Effect.void;
748
+ },
749
+ listEnvironments(_owner, _repo) {
750
+ return Effect.succeed([]);
751
+ },
752
+ listEnvironmentSecrets(_owner, _repo, _envName) {
753
+ return Effect.succeed([]);
754
+ },
755
+ listEnvironmentVariables(_owner, _repo, _envName) {
756
+ return Effect.succeed([]);
757
+ },
758
+ deleteEnvironment(owner, repo, name) {
759
+ recorded.push({
760
+ method: "deleteEnvironment",
761
+ args: {
762
+ owner,
763
+ repo,
764
+ name
765
+ }
766
+ });
767
+ return Effect.void;
768
+ },
769
+ deleteEnvironmentSecret(owner, repo, envName, name) {
770
+ recorded.push({
771
+ method: "deleteEnvironmentSecret",
772
+ args: {
773
+ owner,
774
+ repo,
775
+ envName,
776
+ name
777
+ }
778
+ });
779
+ return Effect.void;
780
+ },
781
+ deleteEnvironmentVariable(owner, repo, envName, name) {
782
+ recorded.push({
783
+ method: "deleteEnvironmentVariable",
784
+ args: {
785
+ owner,
786
+ repo,
787
+ envName,
788
+ name
789
+ }
790
+ });
791
+ return Effect.void;
792
+ },
793
+ getVulnerabilityAlerts(_owner, _repo) {
794
+ return Effect.succeed(false);
795
+ },
796
+ setVulnerabilityAlerts(owner, repo, enabled) {
797
+ recorded.push({
798
+ method: "setVulnerabilityAlerts",
799
+ args: {
800
+ owner,
801
+ repo,
802
+ enabled
803
+ }
804
+ });
805
+ return Effect.void;
806
+ },
807
+ getAutomatedSecurityFixes(_owner, _repo) {
808
+ return Effect.succeed(false);
809
+ },
810
+ setAutomatedSecurityFixes(owner, repo, enabled) {
811
+ recorded.push({
812
+ method: "setAutomatedSecurityFixes",
813
+ args: {
814
+ owner,
815
+ repo,
816
+ enabled
817
+ }
818
+ });
819
+ return Effect.void;
820
+ },
821
+ getPrivateVulnerabilityReporting(_owner, _repo) {
822
+ return Effect.succeed(false);
823
+ },
824
+ setPrivateVulnerabilityReporting(owner, repo, enabled) {
825
+ recorded.push({
826
+ method: "setPrivateVulnerabilityReporting",
827
+ args: {
828
+ owner,
829
+ repo,
830
+ enabled
831
+ }
832
+ });
833
+ return Effect.void;
834
+ },
835
+ updateCodeScanningDefaultSetup(owner, repo, config) {
836
+ recorded.push({
837
+ method: "updateCodeScanningDefaultSetup",
838
+ args: {
839
+ owner,
840
+ repo,
841
+ config
842
+ }
843
+ });
844
+ return Effect.void;
845
+ },
846
+ listRepoLanguages(_owner, _repo) {
847
+ return Effect.succeed([]);
848
+ },
849
+ resolveTeamId(org, slug) {
850
+ recorded.push({
851
+ method: "resolveTeamId",
852
+ args: {
853
+ org,
854
+ slug
855
+ }
856
+ });
857
+ return Effect.succeed(0);
858
+ },
859
+ resolveRoleId(org, name) {
860
+ recorded.push({
861
+ method: "resolveRoleId",
862
+ args: {
863
+ org,
864
+ name
865
+ }
866
+ });
867
+ return Effect.succeed(0);
868
+ }
869
+ }),
870
+ calls: () => [...recorded]
871
+ };
872
+ }
873
+
874
+ //#endregion
875
+ export { GitHubClient, GitHubClientLive, GitHubClientTest, ORG_ONLY_SETTINGS };