simrun 0.1.0__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.
Files changed (261) hide show
  1. simrun-0.1.0/.bumpversion.toml +24 -0
  2. simrun-0.1.0/.github/CODEOWNERS +1 -0
  3. simrun-0.1.0/.github/actions/setup/action.yml +48 -0
  4. simrun-0.1.0/.github/dependabot.yml +55 -0
  5. simrun-0.1.0/.github/pull_request_template.md +13 -0
  6. simrun-0.1.0/.github/rulesets/apply.sh +43 -0
  7. simrun-0.1.0/.github/rulesets/develop.json +61 -0
  8. simrun-0.1.0/.github/rulesets/main.json +25 -0
  9. simrun-0.1.0/.github/rulesets/tags.json +16 -0
  10. simrun-0.1.0/.github/workflows/ci-cd.yml +277 -0
  11. simrun-0.1.0/.github/workflows/cluster.yml +82 -0
  12. simrun-0.1.0/.github/workflows/docs.yml +67 -0
  13. simrun-0.1.0/.github/workflows/lint.yml +63 -0
  14. simrun-0.1.0/.gitignore +40 -0
  15. simrun-0.1.0/.pre-commit-config.yaml +64 -0
  16. simrun-0.1.0/.python-version +1 -0
  17. simrun-0.1.0/.ruff.toml +56 -0
  18. simrun-0.1.0/.zenodo.json +33 -0
  19. simrun-0.1.0/CITATION.cff +22 -0
  20. simrun-0.1.0/CLAUDE.md +69 -0
  21. simrun-0.1.0/LICENSE +7 -0
  22. simrun-0.1.0/PKG-INFO +107 -0
  23. simrun-0.1.0/README.md +50 -0
  24. simrun-0.1.0/deploy/cluster/argo/controller-config.yaml +19 -0
  25. simrun-0.1.0/deploy/cluster/argo/kustomization.yaml +12 -0
  26. simrun-0.1.0/deploy/cluster/argo/namespace-install.yaml +192212 -0
  27. simrun-0.1.0/deploy/cluster/argo/workflow-rbac.yaml +31 -0
  28. simrun-0.1.0/deploy/cluster/buildkit.yaml +94 -0
  29. simrun-0.1.0/deploy/cluster/kueue/config.yaml +38 -0
  30. simrun-0.1.0/deploy/cluster/kueue/kustomization.yaml +9 -0
  31. simrun-0.1.0/deploy/cluster/kueue/manifests.yaml +28482 -0
  32. simrun-0.1.0/deploy/cluster/kueue/queues.yaml +57 -0
  33. simrun-0.1.0/deploy/cluster/kustomization.yaml +43 -0
  34. simrun-0.1.0/deploy/cluster/namespace.yaml +4 -0
  35. simrun-0.1.0/deploy/cluster/off-workers.yaml +16 -0
  36. simrun-0.1.0/deploy/cluster/priority-classes.yaml +88 -0
  37. simrun-0.1.0/deploy/cluster/simrun.yaml +224 -0
  38. simrun-0.1.0/deploy/cluster/store-settings.yaml +11 -0
  39. simrun-0.1.0/deploy/cluster/store.yaml +29 -0
  40. simrun-0.1.0/deploy/cluster/zot.yaml +95 -0
  41. simrun-0.1.0/deploy/k3d/buildkit.yaml +27 -0
  42. simrun-0.1.0/deploy/k3d/kustomization.yaml +61 -0
  43. simrun-0.1.0/deploy/k3d/on-server.yaml +10 -0
  44. simrun-0.1.0/deploy/k3d/quotas.yaml +24 -0
  45. simrun-0.1.0/deploy/k3d/store-claim.yaml +11 -0
  46. simrun-0.1.0/deploy/k3d/store.yaml +16 -0
  47. simrun-0.1.0/deploy/service/Dockerfile +39 -0
  48. simrun-0.1.0/docs/api/argo.md +3 -0
  49. simrun-0.1.0/docs/api/cgroup.md +3 -0
  50. simrun-0.1.0/docs/api/cli.md +3 -0
  51. simrun-0.1.0/docs/api/client.md +3 -0
  52. simrun-0.1.0/docs/api/config.md +3 -0
  53. simrun-0.1.0/docs/api/cwl.md +3 -0
  54. simrun-0.1.0/docs/api/demo.md +3 -0
  55. simrun-0.1.0/docs/api/environment.md +3 -0
  56. simrun-0.1.0/docs/api/index.md +46 -0
  57. simrun-0.1.0/docs/api/ledger.md +3 -0
  58. simrun-0.1.0/docs/api/mcp.md +3 -0
  59. simrun-0.1.0/docs/api/planner.md +3 -0
  60. simrun-0.1.0/docs/api/plugins.md +3 -0
  61. simrun-0.1.0/docs/api/plugins_builtin.md +3 -0
  62. simrun-0.1.0/docs/api/podspec.md +3 -0
  63. simrun-0.1.0/docs/api/resources.md +3 -0
  64. simrun-0.1.0/docs/api/service.app.md +3 -0
  65. simrun-0.1.0/docs/api/service.argo_backend.md +3 -0
  66. simrun-0.1.0/docs/api/service.auth.md +3 -0
  67. simrun-0.1.0/docs/api/service.backend.md +3 -0
  68. simrun-0.1.0/docs/api/service.compare.md +3 -0
  69. simrun-0.1.0/docs/api/service.controller.md +3 -0
  70. simrun-0.1.0/docs/api/service.index.md +3 -0
  71. simrun-0.1.0/docs/api/service.logs.md +3 -0
  72. simrun-0.1.0/docs/api/service.submission.md +3 -0
  73. simrun-0.1.0/docs/api/snapshot.md +3 -0
  74. simrun-0.1.0/docs/api/store.md +3 -0
  75. simrun-0.1.0/docs/api/testing.md +3 -0
  76. simrun-0.1.0/docs/api/worker.md +3 -0
  77. simrun-0.1.0/docs/api/workflow.md +3 -0
  78. simrun-0.1.0/docs/command-line.md +98 -0
  79. simrun-0.1.0/docs/concepts.md +93 -0
  80. simrun-0.1.0/docs/deployment.md +90 -0
  81. simrun-0.1.0/docs/development.md +199 -0
  82. simrun-0.1.0/docs/index.md +58 -0
  83. simrun-0.1.0/docs/installation.md +44 -0
  84. simrun-0.1.0/docs/mcp.md +36 -0
  85. simrun-0.1.0/docs/plugins.md +58 -0
  86. simrun-0.1.0/docs/release-notes.md +5 -0
  87. simrun-0.1.0/docs/robots.txt +9 -0
  88. simrun-0.1.0/docs/service.md +104 -0
  89. simrun-0.1.0/docs/testing.md +90 -0
  90. simrun-0.1.0/docs/web-app.md +86 -0
  91. simrun-0.1.0/docs/workflows.md +85 -0
  92. simrun-0.1.0/examples/squares.yaml +7 -0
  93. simrun-0.1.0/frontend/README.md +22 -0
  94. simrun-0.1.0/frontend/index.html +13 -0
  95. simrun-0.1.0/frontend/mockup/workflow-icons.js +43 -0
  96. simrun-0.1.0/frontend/mockup/workflow-studio.html +921 -0
  97. simrun-0.1.0/frontend/package-lock.json +3604 -0
  98. simrun-0.1.0/frontend/package.json +48 -0
  99. simrun-0.1.0/frontend/public/favicon.svg +1 -0
  100. simrun-0.1.0/frontend/src/App.vue +18 -0
  101. simrun-0.1.0/frontend/src/api/client.test.ts +63 -0
  102. simrun-0.1.0/frontend/src/api/client.ts +98 -0
  103. simrun-0.1.0/frontend/src/api/http.ts +44 -0
  104. simrun-0.1.0/frontend/src/api/openapi.json +3402 -0
  105. simrun-0.1.0/frontend/src/api/schema.d.ts +2379 -0
  106. simrun-0.1.0/frontend/src/api/sse.test.ts +266 -0
  107. simrun-0.1.0/frontend/src/api/sse.ts +233 -0
  108. simrun-0.1.0/frontend/src/auth.ts +53 -0
  109. simrun-0.1.0/frontend/src/components/AppIcon.vue +20 -0
  110. simrun-0.1.0/frontend/src/components/EditBar.test.ts +144 -0
  111. simrun-0.1.0/frontend/src/components/EditBar.vue +139 -0
  112. simrun-0.1.0/frontend/src/components/EditCanvas.fit.test.ts +68 -0
  113. simrun-0.1.0/frontend/src/components/EditCanvas.test.ts +93 -0
  114. simrun-0.1.0/frontend/src/components/EditCanvas.vue +274 -0
  115. simrun-0.1.0/frontend/src/components/EditInspector.test.ts +139 -0
  116. simrun-0.1.0/frontend/src/components/EditInspector.vue +55 -0
  117. simrun-0.1.0/frontend/src/components/EditNode.vue +111 -0
  118. simrun-0.1.0/frontend/src/components/EditTaskPanel.vue +212 -0
  119. simrun-0.1.0/frontend/src/components/EditWorkflowPanel.vue +91 -0
  120. simrun-0.1.0/frontend/src/components/Inspector.test.ts +383 -0
  121. simrun-0.1.0/frontend/src/components/Inspector.vue +111 -0
  122. simrun-0.1.0/frontend/src/components/InspectorLogs.vue +109 -0
  123. simrun-0.1.0/frontend/src/components/InspectorOutputs.vue +96 -0
  124. simrun-0.1.0/frontend/src/components/InspectorOverview.vue +138 -0
  125. simrun-0.1.0/frontend/src/components/InspectorRun.vue +111 -0
  126. simrun-0.1.0/frontend/src/components/LogoMark.vue +18 -0
  127. simrun-0.1.0/frontend/src/components/RunBar.test.ts +105 -0
  128. simrun-0.1.0/frontend/src/components/RunBar.vue +158 -0
  129. simrun-0.1.0/frontend/src/components/RunCanvas.vue +151 -0
  130. simrun-0.1.0/frontend/src/components/RunCard.vue +86 -0
  131. simrun-0.1.0/frontend/src/components/RunList.test.ts +99 -0
  132. simrun-0.1.0/frontend/src/components/RunList.vue +69 -0
  133. simrun-0.1.0/frontend/src/components/SchemaForm.test.ts +89 -0
  134. simrun-0.1.0/frontend/src/components/SchemaForm.vue +189 -0
  135. simrun-0.1.0/frontend/src/components/ServerStrip.test.ts +69 -0
  136. simrun-0.1.0/frontend/src/components/ServerStrip.vue +83 -0
  137. simrun-0.1.0/frontend/src/components/StatusPill.vue +23 -0
  138. simrun-0.1.0/frontend/src/components/TaskNode.test.ts +153 -0
  139. simrun-0.1.0/frontend/src/components/TaskNode.vue +162 -0
  140. simrun-0.1.0/frontend/src/components/TaskPalette.test.ts +67 -0
  141. simrun-0.1.0/frontend/src/components/TaskPalette.vue +75 -0
  142. simrun-0.1.0/frontend/src/components/TopBar.test.ts +51 -0
  143. simrun-0.1.0/frontend/src/components/TopBar.vue +89 -0
  144. simrun-0.1.0/frontend/src/lib/edit-graph.test.ts +140 -0
  145. simrun-0.1.0/frontend/src/lib/edit-graph.ts +178 -0
  146. simrun-0.1.0/frontend/src/lib/filters.test.ts +40 -0
  147. simrun-0.1.0/frontend/src/lib/filters.ts +42 -0
  148. simrun-0.1.0/frontend/src/lib/format.test.ts +106 -0
  149. simrun-0.1.0/frontend/src/lib/format.ts +88 -0
  150. simrun-0.1.0/frontend/src/lib/graph.test.ts +63 -0
  151. simrun-0.1.0/frontend/src/lib/graph.ts +106 -0
  152. simrun-0.1.0/frontend/src/lib/icons.ts +42 -0
  153. simrun-0.1.0/frontend/src/lib/inspect.test.ts +58 -0
  154. simrun-0.1.0/frontend/src/lib/inspect.ts +153 -0
  155. simrun-0.1.0/frontend/src/lib/kinds.ts +32 -0
  156. simrun-0.1.0/frontend/src/lib/progress.test.ts +41 -0
  157. simrun-0.1.0/frontend/src/lib/progress.ts +44 -0
  158. simrun-0.1.0/frontend/src/lib/schema-form.test.ts +72 -0
  159. simrun-0.1.0/frontend/src/lib/schema-form.ts +193 -0
  160. simrun-0.1.0/frontend/src/lib/status.ts +35 -0
  161. simrun-0.1.0/frontend/src/lib/workers.ts +52 -0
  162. simrun-0.1.0/frontend/src/main.ts +6 -0
  163. simrun-0.1.0/frontend/src/router.test.ts +64 -0
  164. simrun-0.1.0/frontend/src/router.ts +63 -0
  165. simrun-0.1.0/frontend/src/stores/edit.test.ts +418 -0
  166. simrun-0.1.0/frontend/src/stores/edit.ts +297 -0
  167. simrun-0.1.0/frontend/src/stores/live.test.ts +62 -0
  168. simrun-0.1.0/frontend/src/stores/live.ts +60 -0
  169. simrun-0.1.0/frontend/src/stores/run.test.ts +87 -0
  170. simrun-0.1.0/frontend/src/stores/run.ts +61 -0
  171. simrun-0.1.0/frontend/src/style.css +35 -0
  172. simrun-0.1.0/frontend/src/test/fixtures.ts +78 -0
  173. simrun-0.1.0/frontend/src/views/EditSessions.test.ts +79 -0
  174. simrun-0.1.0/frontend/src/views/EditSessions.vue +109 -0
  175. simrun-0.1.0/frontend/src/views/EditorView.test.ts +202 -0
  176. simrun-0.1.0/frontend/src/views/EditorView.vue +207 -0
  177. simrun-0.1.0/frontend/src/views/ExecutionsView.vue +97 -0
  178. simrun-0.1.0/frontend/src/views/LoginView.test.ts +82 -0
  179. simrun-0.1.0/frontend/src/views/LoginView.vue +78 -0
  180. simrun-0.1.0/frontend/tsconfig.json +14 -0
  181. simrun-0.1.0/frontend/tsconfig.node.json +18 -0
  182. simrun-0.1.0/frontend/vite.config.ts +24 -0
  183. simrun-0.1.0/pyproject.toml +142 -0
  184. simrun-0.1.0/release-notes/0.1.0.md +16 -0
  185. simrun-0.1.0/scripts/llms_txt.py +301 -0
  186. simrun-0.1.0/scripts/openapi.py +30 -0
  187. simrun-0.1.0/src/simrun/__init__.py +3 -0
  188. simrun-0.1.0/src/simrun/argo.py +449 -0
  189. simrun-0.1.0/src/simrun/build_constraints.txt +20 -0
  190. simrun-0.1.0/src/simrun/cgroup.py +77 -0
  191. simrun-0.1.0/src/simrun/cli.py +350 -0
  192. simrun-0.1.0/src/simrun/client.py +407 -0
  193. simrun-0.1.0/src/simrun/config.py +63 -0
  194. simrun-0.1.0/src/simrun/cwl.py +287 -0
  195. simrun-0.1.0/src/simrun/demo.py +106 -0
  196. simrun-0.1.0/src/simrun/edit.py +408 -0
  197. simrun-0.1.0/src/simrun/environment.py +370 -0
  198. simrun-0.1.0/src/simrun/ledger.py +286 -0
  199. simrun-0.1.0/src/simrun/mcp.py +161 -0
  200. simrun-0.1.0/src/simrun/planner.py +303 -0
  201. simrun-0.1.0/src/simrun/plugins.py +149 -0
  202. simrun-0.1.0/src/simrun/plugins_builtin.py +33 -0
  203. simrun-0.1.0/src/simrun/podspec.py +166 -0
  204. simrun-0.1.0/src/simrun/resources.py +270 -0
  205. simrun-0.1.0/src/simrun/service/__init__.py +1 -0
  206. simrun-0.1.0/src/simrun/service/app.py +1721 -0
  207. simrun-0.1.0/src/simrun/service/argo_backend.py +842 -0
  208. simrun-0.1.0/src/simrun/service/auth.py +93 -0
  209. simrun-0.1.0/src/simrun/service/backend.py +170 -0
  210. simrun-0.1.0/src/simrun/service/compare.py +77 -0
  211. simrun-0.1.0/src/simrun/service/controller.py +788 -0
  212. simrun-0.1.0/src/simrun/service/edits.py +406 -0
  213. simrun-0.1.0/src/simrun/service/index.py +292 -0
  214. simrun-0.1.0/src/simrun/service/logs.py +91 -0
  215. simrun-0.1.0/src/simrun/service/submission.py +349 -0
  216. simrun-0.1.0/src/simrun/snapshot.py +196 -0
  217. simrun-0.1.0/src/simrun/store.py +190 -0
  218. simrun-0.1.0/src/simrun/testing.py +263 -0
  219. simrun-0.1.0/src/simrun/worker.py +1097 -0
  220. simrun-0.1.0/src/simrun/workflow.py +188 -0
  221. simrun-0.1.0/tests/cluster/Dockerfile +12 -0
  222. simrun-0.1.0/tests/cluster/conftest.py +118 -0
  223. simrun-0.1.0/tests/cluster/k3d_cluster.py +495 -0
  224. simrun-0.1.0/tests/cluster/local.py +110 -0
  225. simrun-0.1.0/tests/cluster/test_capacity.py +96 -0
  226. simrun-0.1.0/tests/cluster/test_cluster.py +228 -0
  227. simrun-0.1.0/tests/cluster/test_service_image.py +199 -0
  228. simrun-0.1.0/tests/cluster/test_sources.py +321 -0
  229. simrun-0.1.0/tests/conftest.py +362 -0
  230. simrun-0.1.0/tests/service/test_api.py +896 -0
  231. simrun-0.1.0/tests/service/test_argo_backend.py +782 -0
  232. simrun-0.1.0/tests/service/test_compare.py +68 -0
  233. simrun-0.1.0/tests/service/test_controller.py +682 -0
  234. simrun-0.1.0/tests/service/test_editor_api.py +73 -0
  235. simrun-0.1.0/tests/service/test_edits.py +374 -0
  236. simrun-0.1.0/tests/service/test_events.py +102 -0
  237. simrun-0.1.0/tests/service/test_index.py +216 -0
  238. simrun-0.1.0/tests/service/test_web_api.py +397 -0
  239. simrun-0.1.0/tests/test_argo.py +515 -0
  240. simrun-0.1.0/tests/test_cgroup.py +45 -0
  241. simrun-0.1.0/tests/test_cli.py +115 -0
  242. simrun-0.1.0/tests/test_client.py +231 -0
  243. simrun-0.1.0/tests/test_config.py +20 -0
  244. simrun-0.1.0/tests/test_cwl.py +193 -0
  245. simrun-0.1.0/tests/test_deploy.py +61 -0
  246. simrun-0.1.0/tests/test_edit.py +464 -0
  247. simrun-0.1.0/tests/test_environment.py +329 -0
  248. simrun-0.1.0/tests/test_exec.py +146 -0
  249. simrun-0.1.0/tests/test_ledger.py +273 -0
  250. simrun-0.1.0/tests/test_mcp.py +127 -0
  251. simrun-0.1.0/tests/test_planner.py +196 -0
  252. simrun-0.1.0/tests/test_plugins.py +69 -0
  253. simrun-0.1.0/tests/test_ports.py +94 -0
  254. simrun-0.1.0/tests/test_resources.py +217 -0
  255. simrun-0.1.0/tests/test_snapshot.py +208 -0
  256. simrun-0.1.0/tests/test_store.py +53 -0
  257. simrun-0.1.0/tests/test_worker.py +883 -0
  258. simrun-0.1.0/tests/test_workflow.py +116 -0
  259. simrun-0.1.0/tox.ini +19 -0
  260. simrun-0.1.0/uv.lock +3130 -0
  261. simrun-0.1.0/zensical.toml +173 -0
@@ -0,0 +1,24 @@
1
+ [tool.bumpversion]
2
+ current_version = "0.1.0"
3
+ commit = true
4
+ parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
5
+ serialize = ["{major}.{minor}.{patch}"]
6
+ search = "{current_version}"
7
+ replace = "{new_version}"
8
+ regex = false
9
+ ignore_missing_version = false
10
+ # no tag: the bump is merged into develop through a pull request, which
11
+ # rewrites the commit, so the tag is created on develop afterwards
12
+ tag = false
13
+ sign_tags = false
14
+ tag_name = "{new_version}"
15
+ tag_message = "Bump version: {current_version} → {new_version}"
16
+ allow_dirty = false
17
+ message = "Bump version: {current_version} → {new_version}"
18
+ commit_args = ""
19
+
20
+ [[tool.bumpversion.files]]
21
+ filename = "./src/simrun/__init__.py"
22
+
23
+ [[tool.bumpversion.files]]
24
+ filename = "./CITATION.cff"
@@ -0,0 +1 @@
1
+ * @matthiaskoenig
@@ -0,0 +1,48 @@
1
+ name: Set up the environment
2
+ description: >-
3
+ Install uv with its cache, set the python version of the job and sync the
4
+ environment of the project from uv.lock
5
+ inputs:
6
+ python-version:
7
+ description: the python version, e.g. 3.14
8
+ required: true
9
+ sync:
10
+ description: >-
11
+ the arguments of `uv sync --locked`, e.g. `--extra dev`; empty does not
12
+ sync
13
+ required: false
14
+ default: ""
15
+ save-cache:
16
+ description: >-
17
+ whether the job saves the cache of uv; jobs which share a key would race
18
+ for it and warn "Unable to reserve cache"
19
+ required: false
20
+ default: "false"
21
+ cache:
22
+ description: >-
23
+ whether the job uses the cache of uv at all; the release builds the
24
+ distributions without one, so nothing a cache holds ends up in them
25
+ required: false
26
+ default: "true"
27
+ runs:
28
+ using: composite
29
+ steps:
30
+ - name: Install uv and set the python version
31
+ # astral-sh/setup-uv publishes no floating major tag beyond v7
32
+ uses: astral-sh/setup-uv@v10.2.0
33
+ with:
34
+ python-version: ${{ inputs.python-version }}
35
+ enable-cache: ${{ inputs.cache }}
36
+ # the interpreter is cached with the packages instead of downloaded by every run
37
+ cache-python: ${{ inputs.cache }}
38
+ save-cache: ${{ inputs.save-cache }}
39
+ - name: Sync the environment from the lock (fails if uv.lock is out of date with pyproject.toml, run `uv lock`)
40
+ if: inputs.sync != ''
41
+ shell: bash
42
+ env:
43
+ SYNC: ${{ inputs.sync }}
44
+ # every job runs against the versions of uv.lock, the same ones as a
45
+ # local `uv sync`. `--locked` refuses to update the lock: a change of the
46
+ # dependencies in pyproject.toml has to come with the `uv lock` which
47
+ # records it. Word splitting of the arguments is intended
48
+ run: uv sync --locked $SYNC
@@ -0,0 +1,55 @@
1
+ # Keep the GitHub Actions used in the workflows and the locked python dependencies up to date,
2
+ # monthly, since every update pull request runs the checks.
3
+ # See https://docs.github.com/code-security/dependabot/dependabot-version-updates
4
+ version: 2
5
+ updates:
6
+ - package-ecosystem: "github-actions"
7
+ directory: "/"
8
+ schedule:
9
+ interval: "monthly"
10
+ # a single pull request for all action updates instead of one per action
11
+ groups:
12
+ github-actions:
13
+ patterns:
14
+ - "*"
15
+ open-pull-requests-limit: 5
16
+ commit-message:
17
+ prefix: "ci"
18
+
19
+ # the locked python dependencies (uv.lock), bumped together
20
+ - package-ecosystem: "uv"
21
+ directory: "/"
22
+ # only uv.lock is updated: the default would raise the lower bounds in
23
+ # pyproject.toml, which are what a user of the library installs against,
24
+ # so they are only ever changed by hand
25
+ versioning-strategy: lockfile-only
26
+ schedule:
27
+ interval: "monthly"
28
+ groups:
29
+ python-dependencies:
30
+ patterns:
31
+ - "*"
32
+ open-pull-requests-limit: 5
33
+ commit-message:
34
+ prefix: "build"
35
+
36
+ # the locked npm dependencies of the web app (frontend/package-lock.json), bumped together
37
+ - package-ecosystem: "npm"
38
+ directory: "/frontend"
39
+ schedule:
40
+ interval: "monthly"
41
+ ignore:
42
+ # vue-tsc and openapi-typescript need the API of the compiler in
43
+ # javascript, which TypeScript 7 (the native port) does not have
44
+ - dependency-name: "typescript"
45
+ update-types: ["version-update:semver-major"]
46
+ # the types of node follow the node of continuous integration (24)
47
+ - dependency-name: "@types/node"
48
+ update-types: ["version-update:semver-major"]
49
+ groups:
50
+ npm-dependencies:
51
+ patterns:
52
+ - "*"
53
+ open-pull-requests-limit: 5
54
+ commit-message:
55
+ prefix: "build"
@@ -0,0 +1,13 @@
1
+ ## Summary
2
+
3
+ <!-- what does this change and why -->
4
+
5
+ ## Checklist
6
+
7
+ - [ ] the pull request targets `develop`
8
+ - [ ] tests were added or updated for the change
9
+ - [ ] `pytest` and `ty check` pass locally, `tox run-parallel` runs the tests on every supported python
10
+ - [ ] the change to the cluster was tested on k3d (`SIMRUN_K3D=1 pytest -m cluster`) or the pull request has the label `cluster`
11
+ - [ ] `ruff check` and `ruff format` are clean, e.g., via `pre-commit run --all-files`
12
+ - [ ] public functions and classes have type annotations and a docstring
13
+ - [ ] user visible changes are in `release-notes/` and, if needed, in `docs/`
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # Apply the repository policies of simrun: the merge settings of the
4
+ # repository and the rulesets in this directory. The script is idempotent, i.e.,
5
+ # a ruleset which already exists is updated instead of added a second time, so
6
+ # it can be run again after every change of the json files.
7
+ #
8
+ # The file name of a ruleset has to match the "name" in the json. A ruleset which
9
+ # is removed from this directory stays on the repository, delete it with
10
+ # `gh api -X DELETE repos/<owner>/<repo>/rulesets/<id>`.
11
+ #
12
+ # Requires the github cli (https://cli.github.com) authenticated as a user with
13
+ # admin permission on the repository:
14
+ #
15
+ # gh auth login
16
+ # .github/rulesets/apply.sh [owner/repo]
17
+ #
18
+ set -euo pipefail
19
+
20
+ REPO="${1:-matthiaskoenig/simrun}"
21
+ DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
22
+
23
+ echo "repository settings of ${REPO}"
24
+ gh api -X PATCH "repos/${REPO}" \
25
+ -F allow_auto_merge=true \
26
+ -F delete_branch_on_merge=true \
27
+ -F allow_update_branch=true \
28
+ -F allow_squash_merge=true \
29
+ -F allow_rebase_merge=true \
30
+ -F allow_merge_commit=false \
31
+ --silent
32
+
33
+ for path in "${DIR}"/*.json; do
34
+ name="$(basename "${path}" .json)"
35
+ id="$(gh api "repos/${REPO}/rulesets" --jq "map(select(.name == \"${name}\")) | .[0].id // empty")"
36
+ if [[ -n "${id}" ]]; then
37
+ gh api -X PUT "repos/${REPO}/rulesets/${id}" --input "${path}" --silent
38
+ echo "ruleset ${name} updated (${id})"
39
+ else
40
+ id="$(gh api -X POST "repos/${REPO}/rulesets" --input "${path}" --jq .id)"
41
+ echo "ruleset ${name} created (${id})"
42
+ fi
43
+ done
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "develop",
3
+ "target": "branch",
4
+ "enforcement": "active",
5
+ "bypass_actors": [],
6
+ "conditions": {
7
+ "ref_name": {
8
+ "include": [
9
+ "refs/heads/develop"
10
+ ],
11
+ "exclude": []
12
+ }
13
+ },
14
+ "rules": [
15
+ {
16
+ "type": "deletion"
17
+ },
18
+ {
19
+ "type": "non_fast_forward"
20
+ },
21
+ {
22
+ "type": "required_linear_history"
23
+ },
24
+ {
25
+ "type": "pull_request",
26
+ "parameters": {
27
+ "required_approving_review_count": 0,
28
+ "dismiss_stale_reviews_on_push": true,
29
+ "require_code_owner_review": false,
30
+ "require_last_push_approval": false,
31
+ "required_review_thread_resolution": true,
32
+ "allowed_merge_methods": [
33
+ "squash",
34
+ "rebase"
35
+ ],
36
+ "require_extra_approval_for_unattributed_changes": false
37
+ }
38
+ },
39
+ {
40
+ "type": "required_status_checks",
41
+ "parameters": {
42
+ "strict_required_status_checks_policy": false,
43
+ "do_not_enforce_on_create": false,
44
+ "required_status_checks": [
45
+ {
46
+ "context": "tests"
47
+ },
48
+ {
49
+ "context": "ruff"
50
+ },
51
+ {
52
+ "context": "ty"
53
+ },
54
+ {
55
+ "context": "docs"
56
+ }
57
+ ]
58
+ }
59
+ }
60
+ ]
61
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "main",
3
+ "target": "branch",
4
+ "enforcement": "active",
5
+ "bypass_actors": [],
6
+ "conditions": {
7
+ "ref_name": {
8
+ "include": [
9
+ "refs/heads/main"
10
+ ],
11
+ "exclude": []
12
+ }
13
+ },
14
+ "rules": [
15
+ {
16
+ "type": "deletion"
17
+ },
18
+ {
19
+ "type": "non_fast_forward"
20
+ },
21
+ {
22
+ "type": "required_linear_history"
23
+ }
24
+ ]
25
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "tags",
3
+ "target": "tag",
4
+ "enforcement": "active",
5
+ "bypass_actors": [],
6
+ "conditions": {
7
+ "ref_name": {
8
+ "include": ["~ALL"],
9
+ "exclude": []
10
+ }
11
+ },
12
+ "rules": [
13
+ {"type": "deletion"},
14
+ {"type": "non_fast_forward"}
15
+ ]
16
+ }
@@ -0,0 +1,277 @@
1
+ name: CI-CD
2
+
3
+ on:
4
+ push:
5
+ # feature branches are tested through their pull request, tags release
6
+ branches: [develop, main]
7
+ tags: ['*']
8
+ pull_request:
9
+ branches: [develop, main]
10
+ workflow_dispatch:
11
+
12
+ # least privilege by default, the release job raises what it needs
13
+ permissions:
14
+ contents: read
15
+
16
+ concurrency:
17
+ # a newer run supersedes the running one of the same pull request. A push is
18
+ # a group of its own, so it is never superseded: a release waits for the run
19
+ # of its commit on develop (see the job `tested`), and two merges in a row
20
+ # would otherwise leave the first commit untested. A release is never
21
+ # superseded either, every tag is a group of its own
22
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || format('{0}-{1}', github.ref, github.sha) }}
23
+ cancel-in-progress: true
24
+
25
+ jobs:
26
+ test:
27
+ # a tag is not tested again, see the job `tested`
28
+ if: ${{ !startsWith(github.ref, 'refs/tags/') }}
29
+ runs-on: ubuntu-latest
30
+ timeout-minutes: 30
31
+ strategy:
32
+ fail-fast: false
33
+ matrix:
34
+ # simrun runs on linux only (cgroups, k3s); every supported python
35
+ python-version: ["3.14", "3.15"]
36
+
37
+ steps:
38
+ - uses: actions/checkout@v7
39
+ with:
40
+ persist-credentials: false
41
+ - name: Set up the environment
42
+ # the dependencies are the versions of uv.lock, the package is installed
43
+ # as a wheel and not editable, so the tests run against what is
44
+ # published. The key of the cache has the os and the python version but
45
+ # not the job, so every entry of the matrix has a key of its own and
46
+ # saves it; the other jobs with python 3.14 (ty, docs, cluster) share the
47
+ # key of the entry 3.14 and only restore it
48
+ uses: ./.github/actions/setup
49
+ with:
50
+ python-version: ${{ matrix.python-version }}
51
+ sync: --extra dev --no-editable
52
+ save-cache: "true"
53
+ - name: Test
54
+ # in parallel on every core (`addopts` of pyproject.toml), without the
55
+ # tests on the cluster (`-m 'not cluster'` of `addopts`, see the job
56
+ # `cluster`); the slowest tests are listed at the end of the log
57
+ run: uv run --no-sync pytest --durations=15
58
+
59
+ install:
60
+ # the package as `pip install simrun` installs it, without extras: the
61
+ # environment of the test matrix has the extras of `dev`, which would hide
62
+ # a dependency the package needs and does not declare. It is the one job
63
+ # which does not use uv.lock: it resolves from pyproject.toml as the
64
+ # install of a user does, i.e. the newest releases within the bounds, so a
65
+ # release of a dependency which breaks simrun shows up here before
66
+ # dependabot moves the lock to it
67
+ name: plain install
68
+ if: ${{ !startsWith(github.ref, 'refs/tags/') }}
69
+ runs-on: ubuntu-latest
70
+ timeout-minutes: 15
71
+ steps:
72
+ - uses: actions/checkout@v7
73
+ with:
74
+ persist-credentials: false
75
+ - name: Set up uv and python
76
+ uses: ./.github/actions/setup
77
+ with:
78
+ python-version: "3.14"
79
+ - name: Install the package without extras
80
+ run: |
81
+ uv venv "$RUNNER_TEMP/plain"
82
+ uv pip install --python "$RUNNER_TEMP/plain/bin/python" .
83
+ - name: Import every module and run the command line
84
+ # isolated (-I) and outside of the repository, so the package is the
85
+ # installed one and not the sources. Every module but `simrun.cwl`, whose
86
+ # export needs the extra `cwl`, imports at the top what it needs
87
+ working-directory: ${{ runner.temp }}
88
+ run: |
89
+ "$RUNNER_TEMP/plain/bin/python" -I -c '
90
+ import importlib, pkgutil, simrun
91
+ names = [m.name for m in pkgutil.walk_packages(simrun.__path__, "simrun.")]
92
+ for name in names:
93
+ importlib.import_module(name)
94
+ print(f"simrun {simrun.__version__}: {len(names)} modules imported")
95
+ '
96
+ "$RUNNER_TEMP/plain/bin/simrun" --help
97
+ "$RUNNER_TEMP/plain/bin/simrun" submit --help
98
+
99
+ frontend:
100
+ # the web app in frontend/: the versions of package-lock.json, the types,
101
+ # the tests and the build the service serves at /ui/
102
+ if: ${{ !startsWith(github.ref, 'refs/tags/') }}
103
+ runs-on: ubuntu-latest
104
+ timeout-minutes: 15
105
+ defaults:
106
+ run:
107
+ working-directory: frontend
108
+ steps:
109
+ - uses: actions/checkout@v7
110
+ with:
111
+ persist-credentials: false
112
+ - name: Set up node
113
+ uses: actions/setup-node@v7
114
+ with:
115
+ node-version: 24
116
+ cache: npm
117
+ cache-dependency-path: frontend/package-lock.json
118
+ - name: Install the dependencies
119
+ run: npm ci
120
+ - name: Check the types
121
+ run: npm run typecheck
122
+ - name: Test
123
+ run: npm test
124
+ - name: Build
125
+ run: npm run build
126
+ - name: Check that the types of the API are those of openapi.json
127
+ # src/api/schema.d.ts is generated from src/api/openapi.json, which a
128
+ # test of the service keeps equal to the API; after a change of the API
129
+ # run `uv run python scripts/openapi.py`, then `npm run types`
130
+ run: |
131
+ npm run types
132
+ git diff --exit-code -- src/api/schema.d.ts
133
+
134
+ tests:
135
+ # the one check the branch protection requires; the names of the matrix
136
+ # jobs change with the matrix, this name does not, see .github/rulesets/
137
+ name: tests
138
+ needs: [test, install, frontend]
139
+ if: ${{ always() && !startsWith(github.ref, 'refs/tags/') }}
140
+ runs-on: ubuntu-latest
141
+ timeout-minutes: 5
142
+ steps:
143
+ - name: Check the results of the test matrix, of the plain install and of the web app
144
+ env:
145
+ RESULT: ${{ needs.test.result }}
146
+ INSTALL: ${{ needs.install.result }}
147
+ FRONTEND: ${{ needs.frontend.result }}
148
+ run: |
149
+ echo "test matrix: $RESULT, plain install: $INSTALL, web app: $FRONTEND"
150
+ test "$RESULT" = "success" && test "$INSTALL" = "success" && test "$FRONTEND" = "success"
151
+
152
+ cluster:
153
+ # the tests on a k3d cluster with Kueue, Argo Workflows and BuildKit, on a
154
+ # push to develop, on a release and when the workflow is started by hand.
155
+ # A pull request runs them with the label `cluster`, see cluster.yml
156
+ if: github.event_name != 'pull_request'
157
+ uses: ./.github/workflows/cluster.yml
158
+
159
+ tested:
160
+ # a release does not run the test matrix again. The tag is on a commit of
161
+ # develop, and the push of that commit ran the matrix on exactly this
162
+ # tree; the job waits for that run and fails unless it succeeded, so the
163
+ # tag can be pushed right after the merge of the release
164
+ name: tested on develop
165
+ if: startsWith(github.ref, 'refs/tags/')
166
+ runs-on: ubuntu-latest
167
+ timeout-minutes: 90
168
+ permissions:
169
+ actions: read # the runs of this workflow
170
+ contents: read
171
+ steps:
172
+ - uses: actions/checkout@v7
173
+ with:
174
+ fetch-depth: 0
175
+ persist-credentials: false
176
+ - name: Check that the tag is on develop
177
+ run: |
178
+ if ! git merge-base --is-ancestor "$GITHUB_SHA" origin/develop; then
179
+ echo "::error::$GITHUB_REF_NAME is not on develop, a release is tagged on develop"
180
+ exit 1
181
+ fi
182
+ - name: Wait for the run of the commit on develop
183
+ env:
184
+ GH_TOKEN: ${{ github.token }}
185
+ run: |
186
+ api="repos/$GITHUB_REPOSITORY/actions"
187
+ # the run starts with the merge, a tag pushed right after it may be first
188
+ run_id=""
189
+ for attempt in $(seq 1 20); do
190
+ run_id=$(gh api "$api/workflows/ci-cd.yml/runs?branch=develop&event=push&head_sha=$GITHUB_SHA" \
191
+ --jq '.workflow_runs[0].id // empty' || true)
192
+ [ -n "$run_id" ] && break
193
+ sleep 15
194
+ done
195
+ if [ -z "$run_id" ]; then
196
+ echo "::error::no CI-CD run of the push of $GITHUB_SHA to develop"
197
+ exit 1
198
+ fi
199
+ url="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$run_id"
200
+ echo "waiting for $url"
201
+ # a failed request answers nothing, which is not `completed` either
202
+ until [ "$(gh api "$api/runs/$run_id" --jq .status || true)" = "completed" ]; do
203
+ sleep 30
204
+ done
205
+ conclusion=$(gh api "$api/runs/$run_id" --jq .conclusion)
206
+ echo "$url: $conclusion"
207
+ if [ "$conclusion" != "success" ]; then
208
+ echo "::error::the tests of $GITHUB_SHA on develop did not pass ($url); once they do, re-run the failed jobs of this release"
209
+ exit 1
210
+ fi
211
+
212
+ release:
213
+ needs: [tested, cluster]
214
+ if: >-
215
+ ${{ !cancelled() && startsWith(github.ref, 'refs/tags/')
216
+ && needs.tested.result == 'success'
217
+ && needs.cluster.result == 'success' }}
218
+ runs-on: ubuntu-latest
219
+ timeout-minutes: 15
220
+ environment:
221
+ name: pypi
222
+ url: https://pypi.org/p/simrun
223
+ permissions:
224
+ id-token: write # trusted publishing to PyPI
225
+ contents: write # create the GitHub release
226
+ steps:
227
+ - uses: actions/checkout@v7
228
+ with:
229
+ persist-credentials: false
230
+ - name: Set up uv
231
+ uses: ./.github/actions/setup
232
+ with:
233
+ python-version: "3.14"
234
+ cache: "false"
235
+ - name: Check that the tag is the version of the package
236
+ run: |
237
+ version=$(sed -n 's/^__version__ = "\(.*\)"$/\1/p' src/simrun/__init__.py)
238
+ if [ "$version" != "$GITHUB_REF_NAME" ]; then
239
+ echo "::error::the tag $GITHUB_REF_NAME is not the version $version of src/simrun/__init__.py"
240
+ exit 1
241
+ fi
242
+ - name: Build package
243
+ # the sdist and the wheel
244
+ run: uvx hatch build
245
+ - name: Check the package
246
+ run: uvx twine check --strict dist/*
247
+ - name: Publish to PyPI
248
+ # trusted publishing: the environment `pypi` of this repository is the
249
+ # publisher of the project on pypi.org, no token
250
+ uses: pypa/gh-action-pypi-publish@release/v1
251
+ with:
252
+ packages-dir: dist
253
+ - name: Create GitHub release
254
+ # the release triggers the archive on Zenodo
255
+ uses: softprops/action-gh-release@v3
256
+ with:
257
+ body_path: "release-notes/${{ github.ref_name }}.md"
258
+ files: dist/*
259
+ draft: false
260
+ prerelease: false
261
+
262
+ sync-main:
263
+ # main tracks the latest published release, see docs/development.md
264
+ needs: release
265
+ if: startsWith(github.ref, 'refs/tags/')
266
+ runs-on: ubuntu-latest
267
+ timeout-minutes: 5
268
+ permissions:
269
+ contents: write # fast-forward main to the released commit
270
+ steps:
271
+ - uses: actions/checkout@v7
272
+ with:
273
+ # a shallow clone cannot be pushed to another branch
274
+ fetch-depth: 0
275
+ - name: Fast-forward main to the release
276
+ # no --force: the push fails loudly if it would not be a fast-forward
277
+ run: git push origin HEAD:main
@@ -0,0 +1,82 @@
1
+ name: cluster
2
+
3
+ # The tests on a k3d cluster (`tests/cluster`): k3s with Kueue, Argo Workflows,
4
+ # BuildKit and a registry in docker, the service in the process of the tests.
5
+ # They take half an hour and are not part of the required checks: the job
6
+ # `cluster` of CI-CD calls this workflow on a push to develop, on a release,
7
+ # which waits for it, and when CI-CD is started by hand; a pull request runs it
8
+ # when it has the label `cluster`, once the label is added and with every push
9
+ # after it.
10
+
11
+ on:
12
+ workflow_call:
13
+ pull_request:
14
+ branches: [develop, main]
15
+ types: [opened, synchronize, reopened, labeled]
16
+
17
+ permissions:
18
+ contents: read
19
+
20
+ jobs:
21
+ cluster:
22
+ name: cluster
23
+ # a pull request without the label skips the job; adding another label to
24
+ # a pull request with the label does not run it again
25
+ if: >-
26
+ ${{ github.event_name != 'pull_request'
27
+ || (github.event.action == 'labeled' && github.event.label.name == 'cluster')
28
+ || (github.event.action != 'labeled' && contains(github.event.pull_request.labels.*.name, 'cluster')) }}
29
+ runs-on: ubuntu-latest
30
+ timeout-minutes: 75
31
+ concurrency:
32
+ # a newer push to a pull request supersedes its running cluster tests;
33
+ # a push to develop and a release are groups of their own
34
+ group: cluster-${{ github.event.pull_request.number || github.run_id }}
35
+ cancel-in-progress: true
36
+ steps:
37
+ - uses: actions/checkout@v7
38
+ with:
39
+ persist-credentials: false
40
+ - name: Free the disk for the images
41
+ # the tests need about 20 GiB for the images of k3s, Kueue, Argo,
42
+ # BuildKit, the runs and the environments (`MIN_FREE_GB` of
43
+ # tests/cluster/k3d_cluster.py); the toolchains of the runner image
44
+ # which the tests do not use take more than that
45
+ run: |
46
+ df -h /
47
+ sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc /usr/local/.ghcup \
48
+ /opt/hostedtoolcache/CodeQL /usr/local/share/boost /usr/share/swift
49
+ docker system prune --all --force
50
+ df -h /
51
+ - name: Set up the environment
52
+ uses: ./.github/actions/setup
53
+ with:
54
+ python-version: "3.14"
55
+ sync: --extra dev
56
+ - name: Set up node
57
+ # the image of the service has the web app, built in frontend/
58
+ # (`build_service_image` of tests/cluster/k3d_cluster.py)
59
+ uses: actions/setup-node@v7
60
+ with:
61
+ node-version: 24
62
+ cache: npm
63
+ cache-dependency-path: frontend/package-lock.json
64
+ - name: Test on the k3d cluster
65
+ # the session downloads k3d and kubectl into .tools/bin and creates the
66
+ # cluster; the cluster is kept (`SIMRUN_K3D_KEEP=1`), the runner is
67
+ # thrown away, so the next step can describe it after a failure
68
+ env:
69
+ SIMRUN_K3D: "1"
70
+ SIMRUN_K3D_KEEP: "1"
71
+ run: uv run --no-sync pytest -m cluster tests/cluster --durations=0
72
+ - name: Describe the cluster after a failure
73
+ if: failure()
74
+ env:
75
+ KUBECONFIG: .tools/kubeconfig
76
+ run: |
77
+ kubectl=.tools/bin/kubectl
78
+ $kubectl get nodes -o wide || true
79
+ $kubectl get pods --all-namespaces -o wide || true
80
+ $kubectl get workflows,workloads --namespace simrun || true
81
+ $kubectl get events --all-namespaces --sort-by=.lastTimestamp | tail -n 200 || true
82
+ df -h / || true