sase-github 0.2.5__tar.gz → 0.2.7__tar.gz
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.
- sase_github-0.2.7/.release-please-manifest.json +3 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/CHANGELOG.md +20 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/PKG-INFO +1 -1
- {sase_github-0.2.5 → sase_github-0.2.7}/pyproject.toml +1 -1
- sase_github-0.2.7/src/sase_github/scripts/gh_setup.py +280 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/src/sase_github/workspace_plugin.py +32 -21
- {sase_github-0.2.5 → sase_github-0.2.7}/src/sase_github/xprompts/gh.yml +3 -0
- sase_github-0.2.7/tests/test_gh_workspace_claims.py +950 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/tests/test_workspace_plugin.py +29 -11
- sase_github-0.2.5/.release-please-manifest.json +0 -3
- sase_github-0.2.5/src/sase_github/scripts/gh_setup.py +0 -78
- {sase_github-0.2.5 → sase_github-0.2.7}/.github/workflows/ci.yml +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/.github/workflows/pr-title.yml +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/.github/workflows/publish.yml +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/.sase_beads/beads.db +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/.sase_beads/config.json +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/.sase_beads/issues.jsonl +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/CLAUDE.md +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/Justfile +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/LICENSE +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/README.md +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/docs/architecture.md +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/docs/configuration.md +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/docs/xprompts.md +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/release-please-config.json +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/src/sase_github/__init__.py +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/src/sase_github/config.py +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/src/sase_github/default_config.yml +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/src/sase_github/errors.py +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/src/sase_github/plugin.py +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/src/sase_github/scripts/__init__.py +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/src/sase_github/scripts/new_pr_desc_get_context.py +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/src/sase_github/task_types.py +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/src/sase_github/xprompts/new_pr_desc.yml +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/src/sase_github/xprompts/pr_diff.yml +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/src/sase_github/xprompts/prdd.yml +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/tests/__init__.py +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/tests/test_ci_install_contract.py +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/tests/test_config.py +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/tests/test_github_issues.py +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/tests/test_github_plugin.py +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/tests/test_github_pull_requests.py +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/tests/test_submit_with_recorded_pr.py +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/tests/test_task_types.py +0 -0
- {sase_github-0.2.5 → sase_github-0.2.7}/uv.lock +0 -0
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.2.7](https://github.com/sase-org/sase-github/compare/v0.2.6...v0.2.7) (2026-08-28)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **gh-setup:** adopt the runner's numbered workspace claim ([5e8e9ea](https://github.com/sase-org/sase-github/commit/5e8e9ea6a48b5b285a65d9cb1fa087f74d52b6b0))
|
|
9
|
+
|
|
10
|
+
## [0.2.6](https://github.com/sase-org/sase-github/compare/v0.2.5...v0.2.6) (2026-08-18)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* claim GitHub workspaces atomically ([61dd36f](https://github.com/sase-org/sase-github/commit/61dd36fa1aef7ec71475608e19de3ddf91b67b74))
|
|
16
|
+
* **workspace:** guard gh workflow steps against occupied checkouts ([51347d4](https://github.com/sase-org/sase-github/commit/51347d4f0a256c80785e7e2633fa589259073481))
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Bug Fixes
|
|
20
|
+
|
|
21
|
+
* **workspace:** release the gh setup claim when the occupancy guard refuses ([99a6277](https://github.com/sase-org/sase-github/commit/99a6277ecceb47d702c42351623ed27fbed11822))
|
|
22
|
+
|
|
3
23
|
## [0.2.5](https://github.com/sase-org/sase-github/compare/v0.2.4...v0.2.5) (2026-08-18)
|
|
4
24
|
|
|
5
25
|
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
"""Setup step for the #gh xprompt workflow."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
from sase.core.occupancy_guard import OccupancyCaller, ensure_workspace_not_occupied
|
|
7
|
+
from sase.running_field import (
|
|
8
|
+
WorkspaceClaim,
|
|
9
|
+
claim_next_axe_workspace,
|
|
10
|
+
claim_workspace,
|
|
11
|
+
find_runner_numbered_workspace,
|
|
12
|
+
get_claimed_workspaces,
|
|
13
|
+
release_workspace,
|
|
14
|
+
)
|
|
15
|
+
from sase.sdd.store import materialize_sdd_store
|
|
16
|
+
from sase.workspace_provider import resolve_ref
|
|
17
|
+
from sase.workspace_provider.occupant import new_occupant_record, write_occupant_record
|
|
18
|
+
from sase.workspace_provider.utils import ensure_workspace_checkout
|
|
19
|
+
|
|
20
|
+
_CALLER_TAG = "gh-setup"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def main(
|
|
24
|
+
*,
|
|
25
|
+
gh_ref: str,
|
|
26
|
+
n: int | None,
|
|
27
|
+
release: bool,
|
|
28
|
+
workflow_label: str | None = None,
|
|
29
|
+
) -> None:
|
|
30
|
+
"""Resolve GitHub ref, claim a workspace, and print config.
|
|
31
|
+
|
|
32
|
+
Prints key=value output for the workflow executor.
|
|
33
|
+
"""
|
|
34
|
+
resolved = resolve_ref(gh_ref, "gh")
|
|
35
|
+
|
|
36
|
+
project_name = resolved.project_name
|
|
37
|
+
project_file = resolved.project_file
|
|
38
|
+
workflow_name = workflow_label or f"gh-{gh_ref}"
|
|
39
|
+
cl_name = None if "/" in gh_ref else gh_ref
|
|
40
|
+
|
|
41
|
+
# Use the parent process PID, not our own. This setup step runs as a
|
|
42
|
+
# short-lived subprocess (via ``subprocess.run``), so ``os.getpid()``
|
|
43
|
+
# would die immediately after setup. ``stale_running_cleanup`` would
|
|
44
|
+
# then incorrectly remove the RUNNING entry while the real workflow
|
|
45
|
+
# (the parent process) is still alive.
|
|
46
|
+
pid = os.getppid()
|
|
47
|
+
|
|
48
|
+
# Skip claiming when pre-allocated — the launcher already claimed the workspace
|
|
49
|
+
pre_allocated = os.environ.get("SASE_GH_PRE_ALLOCATED") == "1"
|
|
50
|
+
if pre_allocated:
|
|
51
|
+
workspace_num = int(os.environ["SASE_GH_WORKSPACE_NUM"])
|
|
52
|
+
workspace_dir = os.environ["SASE_GH_WORKSPACE_DIR"]
|
|
53
|
+
materialize_sdd_store(workspace_dir, workspace_num)
|
|
54
|
+
elif n is not None:
|
|
55
|
+
workspace_num, workspace_dir = _claim_pinned_workspace(
|
|
56
|
+
project_file=project_file,
|
|
57
|
+
primary_workspace_dir=resolved.primary_workspace_dir,
|
|
58
|
+
workspace_num=n,
|
|
59
|
+
workflow_name=workflow_name,
|
|
60
|
+
pid=pid,
|
|
61
|
+
cl_name=cl_name,
|
|
62
|
+
pinned=not release,
|
|
63
|
+
)
|
|
64
|
+
else:
|
|
65
|
+
adopted = _adopt_runner_workspace(
|
|
66
|
+
project_file=project_file,
|
|
67
|
+
primary_workspace_dir=resolved.primary_workspace_dir,
|
|
68
|
+
)
|
|
69
|
+
if adopted is not None:
|
|
70
|
+
workspace_num, workspace_dir = adopted
|
|
71
|
+
pre_allocated = True
|
|
72
|
+
else:
|
|
73
|
+
workspace_num, workspace_dir = _claim_next_workspace(
|
|
74
|
+
project_file=project_file,
|
|
75
|
+
primary_workspace_dir=resolved.primary_workspace_dir,
|
|
76
|
+
workflow_name=workflow_name,
|
|
77
|
+
pid=pid,
|
|
78
|
+
cl_name=cl_name,
|
|
79
|
+
pinned=not release,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
# Refuse to hand this checkout to `prepare`/`checkout` if another live
|
|
83
|
+
# agent still occupies it. Runs on the pre_allocated branch too: the
|
|
84
|
+
# launcher already wrote its own occupant record, and the conflict
|
|
85
|
+
# decision recognises the caller's own lineage via the shared pid.
|
|
86
|
+
# A refusal here aborts the step, so the slot this run just claimed must
|
|
87
|
+
# go back — the workflow's `release` step never runs once `setup` fails.
|
|
88
|
+
# The pre_allocated branch claimed nothing, so it releases nothing.
|
|
89
|
+
try:
|
|
90
|
+
ensure_workspace_not_occupied(
|
|
91
|
+
workspace_dir,
|
|
92
|
+
project_file=project_file,
|
|
93
|
+
caller=OccupancyCaller(
|
|
94
|
+
pid=pid,
|
|
95
|
+
workspace_num=workspace_num,
|
|
96
|
+
project=project_name,
|
|
97
|
+
workflow=workflow_name,
|
|
98
|
+
),
|
|
99
|
+
)
|
|
100
|
+
except Exception:
|
|
101
|
+
if not pre_allocated:
|
|
102
|
+
release_workspace(
|
|
103
|
+
project_file,
|
|
104
|
+
workspace_num,
|
|
105
|
+
workflow_name,
|
|
106
|
+
cl_name,
|
|
107
|
+
caller_tag=_CALLER_TAG,
|
|
108
|
+
)
|
|
109
|
+
raise
|
|
110
|
+
|
|
111
|
+
# Claim the checkout for this run. Workspace numbers 0/1 both mean
|
|
112
|
+
# "primary", never a real numbered workspace (see
|
|
113
|
+
# ``ensure_workspace_checkout``), and the pre_allocated branch's
|
|
114
|
+
# occupant record already belongs to the launcher.
|
|
115
|
+
if not pre_allocated and workspace_num > 1:
|
|
116
|
+
write_occupant_record(
|
|
117
|
+
workspace_dir,
|
|
118
|
+
new_occupant_record(
|
|
119
|
+
pid=pid,
|
|
120
|
+
workflow=workflow_name,
|
|
121
|
+
project=project_name,
|
|
122
|
+
workspace_num=workspace_num,
|
|
123
|
+
cl_name=cl_name,
|
|
124
|
+
),
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
print(f"project_name={project_name}")
|
|
128
|
+
print(f"project_file={project_file}")
|
|
129
|
+
print(f"workspace_dir={workspace_dir}")
|
|
130
|
+
print(f"workspace_num={workspace_num}")
|
|
131
|
+
print(f"checkout_target={resolved.checkout_target}")
|
|
132
|
+
print(f"primary_workspace_dir={resolved.primary_workspace_dir}")
|
|
133
|
+
# Don't release pre-allocated workspaces — the launcher handles that
|
|
134
|
+
should_release = release and not pre_allocated
|
|
135
|
+
print(f"should_release={'true' if should_release else 'false'}")
|
|
136
|
+
print(f"_chdir={workspace_dir}")
|
|
137
|
+
print(f"meta_workspace={workspace_num}")
|
|
138
|
+
print(f"workflow_name={workflow_name}")
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _adopt_runner_workspace(
|
|
142
|
+
*,
|
|
143
|
+
project_file: str,
|
|
144
|
+
primary_workspace_dir: str,
|
|
145
|
+
) -> tuple[int, str] | None:
|
|
146
|
+
"""Reuse the calling runner's numbered pool claim, if it holds one."""
|
|
147
|
+
workspace_num = find_runner_numbered_workspace(project_file)
|
|
148
|
+
if workspace_num is None:
|
|
149
|
+
return None
|
|
150
|
+
workspace_dir = ensure_workspace_checkout(primary_workspace_dir, workspace_num)
|
|
151
|
+
materialize_sdd_store(workspace_dir, workspace_num)
|
|
152
|
+
return workspace_num, workspace_dir
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def _claim_next_workspace(
|
|
156
|
+
*,
|
|
157
|
+
project_file: str,
|
|
158
|
+
primary_workspace_dir: str,
|
|
159
|
+
workflow_name: str,
|
|
160
|
+
pid: int,
|
|
161
|
+
cl_name: str | None,
|
|
162
|
+
pinned: bool,
|
|
163
|
+
) -> tuple[int, str]:
|
|
164
|
+
"""Atomically allocate a slot, then materialize the checkout."""
|
|
165
|
+
workspace_num = claim_next_axe_workspace(
|
|
166
|
+
project_file,
|
|
167
|
+
workflow_name,
|
|
168
|
+
pid,
|
|
169
|
+
cl_name=cl_name,
|
|
170
|
+
pinned=pinned,
|
|
171
|
+
caller_tag=_CALLER_TAG,
|
|
172
|
+
)
|
|
173
|
+
workspace_dir = _materialize_or_release(
|
|
174
|
+
project_file=project_file,
|
|
175
|
+
primary_workspace_dir=primary_workspace_dir,
|
|
176
|
+
workspace_num=workspace_num,
|
|
177
|
+
workflow_name=workflow_name,
|
|
178
|
+
cl_name=cl_name,
|
|
179
|
+
)
|
|
180
|
+
return workspace_num, workspace_dir
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def _claim_pinned_workspace(
|
|
184
|
+
*,
|
|
185
|
+
project_file: str,
|
|
186
|
+
primary_workspace_dir: str,
|
|
187
|
+
workspace_num: int,
|
|
188
|
+
workflow_name: str,
|
|
189
|
+
pid: int,
|
|
190
|
+
cl_name: str | None,
|
|
191
|
+
pinned: bool,
|
|
192
|
+
) -> tuple[int, str]:
|
|
193
|
+
"""Claim a pinned ``n=<num>`` target once. Occupied slots fail with the occupant named."""
|
|
194
|
+
claim_result = claim_workspace(
|
|
195
|
+
project_file,
|
|
196
|
+
workspace_num,
|
|
197
|
+
workflow_name,
|
|
198
|
+
pid,
|
|
199
|
+
cl_name,
|
|
200
|
+
pinned=pinned,
|
|
201
|
+
caller_tag=_CALLER_TAG,
|
|
202
|
+
)
|
|
203
|
+
if not claim_result.success:
|
|
204
|
+
occupant = _describe_workspace_occupant(project_file, workspace_num)
|
|
205
|
+
if occupant is not None:
|
|
206
|
+
print(
|
|
207
|
+
f"Pinned workspace #{workspace_num} is already claimed by {occupant}",
|
|
208
|
+
file=sys.stderr,
|
|
209
|
+
)
|
|
210
|
+
else:
|
|
211
|
+
print(
|
|
212
|
+
f"Pinned workspace #{workspace_num} could not be claimed: "
|
|
213
|
+
f"{claim_result.error or 'unknown reason'}",
|
|
214
|
+
file=sys.stderr,
|
|
215
|
+
)
|
|
216
|
+
sys.exit(1)
|
|
217
|
+
workspace_dir = _materialize_or_release(
|
|
218
|
+
project_file=project_file,
|
|
219
|
+
primary_workspace_dir=primary_workspace_dir,
|
|
220
|
+
workspace_num=workspace_num,
|
|
221
|
+
workflow_name=workflow_name,
|
|
222
|
+
cl_name=cl_name,
|
|
223
|
+
)
|
|
224
|
+
return workspace_num, workspace_dir
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def _materialize_or_release(
|
|
228
|
+
*,
|
|
229
|
+
project_file: str,
|
|
230
|
+
primary_workspace_dir: str,
|
|
231
|
+
workspace_num: int,
|
|
232
|
+
workflow_name: str,
|
|
233
|
+
cl_name: str | None,
|
|
234
|
+
) -> str:
|
|
235
|
+
"""Materialize after a successful claim; release the slot if setup fails."""
|
|
236
|
+
try:
|
|
237
|
+
workspace_dir = ensure_workspace_checkout(primary_workspace_dir, workspace_num)
|
|
238
|
+
materialize_sdd_store(workspace_dir, workspace_num)
|
|
239
|
+
except Exception:
|
|
240
|
+
release_workspace(
|
|
241
|
+
project_file,
|
|
242
|
+
workspace_num,
|
|
243
|
+
workflow_name,
|
|
244
|
+
cl_name,
|
|
245
|
+
caller_tag=_CALLER_TAG,
|
|
246
|
+
)
|
|
247
|
+
raise
|
|
248
|
+
return workspace_dir
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def _describe_workspace_occupant(project_file: str, workspace_num: int) -> str | None:
|
|
252
|
+
occupants = [
|
|
253
|
+
claim
|
|
254
|
+
for claim in get_claimed_workspaces(project_file)
|
|
255
|
+
if claim.workspace_num == workspace_num
|
|
256
|
+
]
|
|
257
|
+
if not occupants:
|
|
258
|
+
return None
|
|
259
|
+
return "; ".join(_format_workspace_occupant(claim) for claim in occupants)
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def _format_workspace_occupant(claim: WorkspaceClaim) -> str:
|
|
263
|
+
name = claim.cl_name or claim.workflow
|
|
264
|
+
liveness = "live" if _pid_is_alive(claim.pid) else "dead"
|
|
265
|
+
detail = f"{name} (pid {claim.pid}, {liveness}, workflow {claim.workflow}"
|
|
266
|
+
if claim.artifacts_timestamp:
|
|
267
|
+
detail += f", artifacts {claim.artifacts_timestamp}"
|
|
268
|
+
return detail + ")"
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def _pid_is_alive(pid: int) -> bool:
|
|
272
|
+
if pid <= 0:
|
|
273
|
+
return False
|
|
274
|
+
try:
|
|
275
|
+
os.kill(pid, 0)
|
|
276
|
+
except ProcessLookupError:
|
|
277
|
+
return False
|
|
278
|
+
except PermissionError:
|
|
279
|
+
return True
|
|
280
|
+
return True
|
|
@@ -487,10 +487,14 @@ class GitHubWorkspacePlugin:
|
|
|
487
487
|
kill_and_persist_all_running_processes,
|
|
488
488
|
)
|
|
489
489
|
from sase.ace.operations import has_active_children
|
|
490
|
+
from sase.core.occupancy_guard import (
|
|
491
|
+
OccupancyCaller,
|
|
492
|
+
WorkspaceOccupiedError,
|
|
493
|
+
ensure_workspace_not_occupied,
|
|
494
|
+
)
|
|
490
495
|
from sase.running_field import (
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
get_workspace_directory_for_num,
|
|
496
|
+
WorkspaceClaimError,
|
|
497
|
+
claim_next_axe_workspace_dir,
|
|
494
498
|
release_workspace,
|
|
495
499
|
)
|
|
496
500
|
from sase.vcs_provider import get_vcs_provider
|
|
@@ -536,36 +540,42 @@ class GitHubWorkspacePlugin:
|
|
|
536
540
|
if not workspace_dir:
|
|
537
541
|
return (False, "WORKSPACE_DIR is not set for this project")
|
|
538
542
|
|
|
539
|
-
workspace_num = get_first_available_axe_workspace(patch_file)
|
|
540
543
|
workflow_name = f"submit-{patch_name}"
|
|
541
|
-
pid = os.getpid()
|
|
542
|
-
|
|
543
544
|
try:
|
|
544
|
-
ws_dir, _ =
|
|
545
|
-
|
|
546
|
-
|
|
545
|
+
workspace_num, ws_dir, _ = claim_next_axe_workspace_dir(
|
|
546
|
+
patch_file,
|
|
547
|
+
workflow_name,
|
|
548
|
+
os.getpid(),
|
|
549
|
+
project_basename,
|
|
550
|
+
cl_name=patch_name,
|
|
551
|
+
caller_tag="gh-submit",
|
|
552
|
+
)
|
|
553
|
+
except WorkspaceClaimError as exc:
|
|
554
|
+
return (False, f"Failed to claim workspace: {exc}")
|
|
547
555
|
|
|
548
556
|
if rich_console:
|
|
549
557
|
rich_console.print(f"[cyan]Claiming workspace #{workspace_num}[/cyan]")
|
|
550
558
|
|
|
551
|
-
if not claim_workspace(
|
|
552
|
-
patch_file,
|
|
553
|
-
workspace_num,
|
|
554
|
-
workflow_name,
|
|
555
|
-
pid,
|
|
556
|
-
patch_name,
|
|
557
|
-
):
|
|
558
|
-
return (
|
|
559
|
-
False,
|
|
560
|
-
f"Failed to claim workspace #{workspace_num}",
|
|
561
|
-
)
|
|
562
|
-
|
|
563
559
|
try:
|
|
564
560
|
if rich_console:
|
|
565
561
|
rich_console.print(
|
|
566
562
|
f"[cyan]Checking out {escape_markup(patch_name)}...[/cyan]"
|
|
567
563
|
)
|
|
568
564
|
|
|
565
|
+
try:
|
|
566
|
+
ensure_workspace_not_occupied(
|
|
567
|
+
ws_dir,
|
|
568
|
+
project_file=patch_file,
|
|
569
|
+
caller=OccupancyCaller(
|
|
570
|
+
pid=os.getpid(),
|
|
571
|
+
workspace_num=workspace_num,
|
|
572
|
+
project=project_basename,
|
|
573
|
+
workflow=workflow_name,
|
|
574
|
+
),
|
|
575
|
+
)
|
|
576
|
+
except WorkspaceOccupiedError as exc:
|
|
577
|
+
return (False, f"Refusing checkout: {exc}")
|
|
578
|
+
|
|
569
579
|
provider = get_vcs_provider(ws_dir)
|
|
570
580
|
branch_name = provider.resolve_revision(
|
|
571
581
|
patch_name, project_basename, ws_dir
|
|
@@ -619,6 +629,7 @@ class GitHubWorkspacePlugin:
|
|
|
619
629
|
workspace_num,
|
|
620
630
|
workflow_name,
|
|
621
631
|
patch_name,
|
|
632
|
+
caller_tag="gh-submit",
|
|
622
633
|
)
|
|
623
634
|
if rich_console:
|
|
624
635
|
rich_console.print(f"[cyan]Released workspace #{workspace_num}[/cyan]")
|
|
@@ -120,13 +120,16 @@ steps:
|
|
|
120
120
|
if: "{{ setup.should_release }}"
|
|
121
121
|
python: |
|
|
122
122
|
from sase.running_field import release_workspace
|
|
123
|
+
from sase.workspace_provider.occupant import clear_occupant_record
|
|
123
124
|
|
|
124
125
|
release_workspace(
|
|
125
126
|
{{ setup.project_file | tojson }},
|
|
126
127
|
{{ setup.workspace_num }},
|
|
127
128
|
{{ setup.workflow_name | tojson }},
|
|
128
129
|
{{ gh_ref | tojson }} if "/" not in {{ gh_ref | tojson }} else None,
|
|
130
|
+
caller_tag="gh-release",
|
|
129
131
|
)
|
|
132
|
+
clear_occupant_record({{ setup.workspace_dir | tojson }})
|
|
130
133
|
print("released=true")
|
|
131
134
|
output: { released: bool }
|
|
132
135
|
|