@vaharoni/devops 1.0.47

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 (342) hide show
  1. package/README.md +51 -0
  2. package/dist/app-support/crypto/index.d.ts +15 -0
  3. package/dist/app-support/crypto/index.d.ts.map +1 -0
  4. package/dist/app-support/crypto/index.js +30 -0
  5. package/dist/app-support/crypto/internal-token.d.ts +20 -0
  6. package/dist/app-support/crypto/internal-token.d.ts.map +1 -0
  7. package/dist/app-support/crypto/internal-token.js +42 -0
  8. package/dist/app-support/crypto/internal-token.spec.d.ts +2 -0
  9. package/dist/app-support/crypto/internal-token.spec.d.ts.map +1 -0
  10. package/dist/app-support/crypto/internal-token.spec.js +45 -0
  11. package/dist/app-support/crypto/secret.d.ts +3 -0
  12. package/dist/app-support/crypto/secret.d.ts.map +1 -0
  13. package/dist/app-support/crypto/secret.js +12 -0
  14. package/dist/app-support/crypto/secret.spec.d.ts +2 -0
  15. package/dist/app-support/crypto/secret.spec.d.ts.map +1 -0
  16. package/dist/app-support/crypto/secret.spec.js +15 -0
  17. package/dist/app-support/discovery/dev-discovery-loader.d.ts +2 -0
  18. package/dist/app-support/discovery/dev-discovery-loader.d.ts.map +1 -0
  19. package/dist/app-support/discovery/dev-discovery-loader.js +30 -0
  20. package/dist/app-support/discovery/service-endpoint.d.ts +2 -0
  21. package/dist/app-support/discovery/service-endpoint.d.ts.map +1 -0
  22. package/dist/app-support/discovery/service-endpoint.js +10 -0
  23. package/dist/cli/affected.d.ts +11 -0
  24. package/dist/cli/affected.d.ts.map +1 -0
  25. package/dist/cli/affected.js +103 -0
  26. package/dist/cli/common.d.ts +89 -0
  27. package/dist/cli/common.d.ts.map +1 -0
  28. package/dist/cli/common.js +236 -0
  29. package/dist/cli/common.spec.d.ts +2 -0
  30. package/dist/cli/common.spec.d.ts.map +1 -0
  31. package/dist/cli/common.spec.js +64 -0
  32. package/dist/cli/console.d.ts +11 -0
  33. package/dist/cli/console.d.ts.map +1 -0
  34. package/dist/cli/console.js +35 -0
  35. package/dist/cli/constant.d.ts +11 -0
  36. package/dist/cli/constant.d.ts.map +1 -0
  37. package/dist/cli/constant.js +22 -0
  38. package/dist/cli/db.d.ts +11 -0
  39. package/dist/cli/db.d.ts.map +1 -0
  40. package/dist/cli/db.js +119 -0
  41. package/dist/cli/dml.d.ts +11 -0
  42. package/dist/cli/dml.d.ts.map +1 -0
  43. package/dist/cli/dml.js +116 -0
  44. package/dist/cli/env.d.ts +11 -0
  45. package/dist/cli/env.d.ts.map +1 -0
  46. package/dist/cli/env.js +67 -0
  47. package/dist/cli/exec.d.ts +11 -0
  48. package/dist/cli/exec.d.ts.map +1 -0
  49. package/dist/cli/exec.js +50 -0
  50. package/dist/cli/image.d.ts +11 -0
  51. package/dist/cli/image.d.ts.map +1 -0
  52. package/dist/cli/image.js +140 -0
  53. package/dist/cli/init.d.ts +11 -0
  54. package/dist/cli/init.d.ts.map +1 -0
  55. package/dist/cli/init.js +66 -0
  56. package/dist/cli/internal-curl.d.ts +11 -0
  57. package/dist/cli/internal-curl.d.ts.map +1 -0
  58. package/dist/cli/internal-curl.js +43 -0
  59. package/dist/cli/job.d.ts +11 -0
  60. package/dist/cli/job.d.ts.map +1 -0
  61. package/dist/cli/job.js +67 -0
  62. package/dist/cli/jwt.d.ts +11 -0
  63. package/dist/cli/jwt.d.ts.map +1 -0
  64. package/dist/cli/jwt.js +27 -0
  65. package/dist/cli/namespace.d.ts +11 -0
  66. package/dist/cli/namespace.d.ts.map +1 -0
  67. package/dist/cli/namespace.js +70 -0
  68. package/dist/cli/prep-build.d.ts +11 -0
  69. package/dist/cli/prep-build.d.ts.map +1 -0
  70. package/dist/cli/prep-build.js +82 -0
  71. package/dist/cli/prisma.d.ts +11 -0
  72. package/dist/cli/prisma.d.ts.map +1 -0
  73. package/dist/cli/prisma.js +25 -0
  74. package/dist/cli/redis.d.ts +11 -0
  75. package/dist/cli/redis.d.ts.map +1 -0
  76. package/dist/cli/redis.js +76 -0
  77. package/dist/cli/registry.d.ts +11 -0
  78. package/dist/cli/registry.d.ts.map +1 -0
  79. package/dist/cli/registry.js +58 -0
  80. package/dist/cli/run-many.d.ts +11 -0
  81. package/dist/cli/run-many.d.ts.map +1 -0
  82. package/dist/cli/run-many.js +50 -0
  83. package/dist/cli/run.d.ts +11 -0
  84. package/dist/cli/run.d.ts.map +1 -0
  85. package/dist/cli/run.js +37 -0
  86. package/dist/cli/template.d.ts +11 -0
  87. package/dist/cli/template.d.ts.map +1 -0
  88. package/dist/cli/template.js +123 -0
  89. package/dist/cli/test.d.ts +11 -0
  90. package/dist/cli/test.d.ts.map +1 -0
  91. package/dist/cli/test.js +28 -0
  92. package/dist/devops.d.ts +3 -0
  93. package/dist/devops.d.ts.map +1 -0
  94. package/dist/devops.js +103 -0
  95. package/dist/index.d.ts +4 -0
  96. package/dist/index.d.ts.map +1 -0
  97. package/dist/index.js +3 -0
  98. package/dist/libs/affected-entities.d.ts +15 -0
  99. package/dist/libs/affected-entities.d.ts.map +1 -0
  100. package/dist/libs/affected-entities.js +52 -0
  101. package/dist/libs/config.d.ts +6 -0
  102. package/dist/libs/config.d.ts.map +1 -0
  103. package/dist/libs/config.js +98 -0
  104. package/dist/libs/dependencies.d.ts +19 -0
  105. package/dist/libs/dependencies.d.ts.map +1 -0
  106. package/dist/libs/dependencies.js +62 -0
  107. package/dist/libs/dependencies.spec.d.ts +2 -0
  108. package/dist/libs/dependencies.spec.d.ts.map +1 -0
  109. package/dist/libs/dependencies.spec.js +21 -0
  110. package/dist/libs/digital-ocean/container-reg.d.ts +6 -0
  111. package/dist/libs/digital-ocean/container-reg.d.ts.map +1 -0
  112. package/dist/libs/digital-ocean/container-reg.js +69 -0
  113. package/dist/libs/discovery/dependencies.d.ts +19 -0
  114. package/dist/libs/discovery/dependencies.d.ts.map +1 -0
  115. package/dist/libs/discovery/dependencies.js +62 -0
  116. package/dist/libs/discovery/dependencies.spec.d.ts +2 -0
  117. package/dist/libs/discovery/dependencies.spec.d.ts.map +1 -0
  118. package/dist/libs/discovery/dependencies.spec.js +21 -0
  119. package/dist/libs/discovery/images.d.ts +5 -0
  120. package/dist/libs/discovery/images.d.ts.map +1 -0
  121. package/dist/libs/discovery/images.js +45 -0
  122. package/dist/libs/discovery/index.d.ts +5 -0
  123. package/dist/libs/discovery/index.d.ts.map +1 -0
  124. package/dist/libs/discovery/index.js +55 -0
  125. package/dist/libs/discovery/package-json-processor.d.ts +3 -0
  126. package/dist/libs/discovery/package-json-processor.d.ts.map +1 -0
  127. package/dist/libs/discovery/package-json-processor.js +34 -0
  128. package/dist/libs/discovery/process-common.d.ts +25 -0
  129. package/dist/libs/discovery/process-common.d.ts.map +1 -0
  130. package/dist/libs/discovery/process-common.js +40 -0
  131. package/dist/libs/discovery/process-package-json.d.ts +3 -0
  132. package/dist/libs/discovery/process-package-json.d.ts.map +1 -0
  133. package/dist/libs/discovery/process-package-json.js +34 -0
  134. package/dist/libs/discovery/process-pyproject-toml.d.ts +3 -0
  135. package/dist/libs/discovery/process-pyproject-toml.d.ts.map +1 -0
  136. package/dist/libs/discovery/process-pyproject-toml.js +36 -0
  137. package/dist/libs/discovery/pyproject-toml-processor.d.ts +3 -0
  138. package/dist/libs/discovery/pyproject-toml-processor.d.ts.map +1 -0
  139. package/dist/libs/discovery/pyproject-toml-processor.js +39 -0
  140. package/dist/libs/git-helpers.d.ts +8 -0
  141. package/dist/libs/git-helpers.d.ts.map +1 -0
  142. package/dist/libs/git-helpers.js +20 -0
  143. package/dist/libs/hetzner/reg-secret.d.ts +3 -0
  144. package/dist/libs/hetzner/reg-secret.d.ts.map +1 -0
  145. package/dist/libs/hetzner/reg-secret.js +39 -0
  146. package/dist/libs/k8s-constants.d.ts +12 -0
  147. package/dist/libs/k8s-constants.d.ts.map +1 -0
  148. package/dist/libs/k8s-constants.js +66 -0
  149. package/dist/libs/k8s-db.d.ts +18 -0
  150. package/dist/libs/k8s-db.d.ts.map +1 -0
  151. package/dist/libs/k8s-db.js +73 -0
  152. package/dist/libs/k8s-generate.d.ts +17 -0
  153. package/dist/libs/k8s-generate.d.ts.map +1 -0
  154. package/dist/libs/k8s-generate.js +179 -0
  155. package/dist/libs/k8s-helpers.d.ts +11 -0
  156. package/dist/libs/k8s-helpers.d.ts.map +1 -0
  157. package/dist/libs/k8s-helpers.js +42 -0
  158. package/dist/libs/k8s-image-config.d.ts +8 -0
  159. package/dist/libs/k8s-image-config.d.ts.map +1 -0
  160. package/dist/libs/k8s-image-config.js +113 -0
  161. package/dist/libs/k8s-job-waiter.d.ts +8 -0
  162. package/dist/libs/k8s-job-waiter.d.ts.map +1 -0
  163. package/dist/libs/k8s-job-waiter.js +84 -0
  164. package/dist/libs/k8s-namespace.d.ts +7 -0
  165. package/dist/libs/k8s-namespace.d.ts.map +1 -0
  166. package/dist/libs/k8s-namespace.js +27 -0
  167. package/dist/libs/k8s-redis.d.ts +6 -0
  168. package/dist/libs/k8s-redis.d.ts.map +1 -0
  169. package/dist/libs/k8s-redis.js +31 -0
  170. package/dist/libs/k8s-secrets-manager.d.ts +5 -0
  171. package/dist/libs/k8s-secrets-manager.d.ts.map +1 -0
  172. package/dist/libs/k8s-secrets-manager.js +61 -0
  173. package/dist/libs/validate-env.d.ts +56 -0
  174. package/dist/libs/validate-env.d.ts.map +1 -0
  175. package/dist/libs/validate-env.js +214 -0
  176. package/dist/libs/validate-env.spec.d.ts +2 -0
  177. package/dist/libs/validate-env.spec.d.ts.map +1 -0
  178. package/dist/libs/validate-env.spec.js +168 -0
  179. package/dist/libs/workspace-discovery.d.ts +2 -0
  180. package/dist/libs/workspace-discovery.d.ts.map +1 -0
  181. package/dist/libs/workspace-discovery.js +75 -0
  182. package/dist/test.d.ts +2 -0
  183. package/dist/test.d.ts.map +1 -0
  184. package/dist/test.js +1 -0
  185. package/dist/types/index.d.ts +925 -0
  186. package/dist/types/index.d.ts.map +1 -0
  187. package/dist/types/index.js +79 -0
  188. package/package.json +55 -0
  189. package/src/app-support/crypto/index.ts +31 -0
  190. package/src/app-support/crypto/internal-token.spec.ts +53 -0
  191. package/src/app-support/crypto/internal-token.ts +82 -0
  192. package/src/app-support/crypto/secret.spec.ts +18 -0
  193. package/src/app-support/crypto/secret.ts +13 -0
  194. package/src/app-support/discovery/dev-discovery-loader.ts +35 -0
  195. package/src/app-support/discovery/service-endpoint.ts +12 -0
  196. package/src/cli/affected.ts +116 -0
  197. package/src/cli/common.spec.ts +78 -0
  198. package/src/cli/common.ts +323 -0
  199. package/src/cli/console.ts +46 -0
  200. package/src/cli/constant.ts +25 -0
  201. package/src/cli/db.ts +133 -0
  202. package/src/cli/dml.ts +126 -0
  203. package/src/cli/env.ts +87 -0
  204. package/src/cli/exec.sh +21 -0
  205. package/src/cli/exec.ts +57 -0
  206. package/src/cli/image.ts +197 -0
  207. package/src/cli/init.ts +75 -0
  208. package/src/cli/internal-curl.ts +48 -0
  209. package/src/cli/job.ts +80 -0
  210. package/src/cli/jwt.ts +32 -0
  211. package/src/cli/namespace.ts +78 -0
  212. package/src/cli/prep-build.ts +96 -0
  213. package/src/cli/prisma.ts +33 -0
  214. package/src/cli/redis.ts +83 -0
  215. package/src/cli/registry.ts +76 -0
  216. package/src/cli/run-many.ts +61 -0
  217. package/src/cli/run.ts +46 -0
  218. package/src/cli/template.ts +169 -0
  219. package/src/cli/test.ts +30 -0
  220. package/src/devops.ts +119 -0
  221. package/src/index.ts +3 -0
  222. package/src/libs/affected-entities.ts +71 -0
  223. package/src/libs/config.ts +117 -0
  224. package/src/libs/digital-ocean/container-reg.ts +81 -0
  225. package/src/libs/discovery/dependencies.spec.ts +25 -0
  226. package/src/libs/discovery/dependencies.ts +73 -0
  227. package/src/libs/discovery/images.ts +57 -0
  228. package/src/libs/discovery/index.ts +60 -0
  229. package/src/libs/discovery/process-common.ts +55 -0
  230. package/src/libs/discovery/process-package-json.ts +47 -0
  231. package/src/libs/discovery/process-pyproject-toml.ts +43 -0
  232. package/src/libs/git-helpers.ts +32 -0
  233. package/src/libs/hetzner/reg-secret.ts +54 -0
  234. package/src/libs/k8s-constants.ts +83 -0
  235. package/src/libs/k8s-db.ts +83 -0
  236. package/src/libs/k8s-generate.ts +211 -0
  237. package/src/libs/k8s-helpers.ts +59 -0
  238. package/src/libs/k8s-image-config.ts +165 -0
  239. package/src/libs/k8s-job-waiter.ts +124 -0
  240. package/src/libs/k8s-namespace.ts +41 -0
  241. package/src/libs/k8s-redis.ts +31 -0
  242. package/src/libs/k8s-secrets-manager.ts +79 -0
  243. package/src/libs/validate-env.spec.ts +223 -0
  244. package/src/libs/validate-env.ts +266 -0
  245. package/src/target-templates/.devops/config/constants.yaml +17 -0
  246. package/src/target-templates/.devops/config/images.yaml +88 -0
  247. package/src/target-templates/.devops/docker-images/common/docker-common.sh +23 -0
  248. package/src/target-templates/.devops/docker-images/node-services/node-exec.sh +8 -0
  249. package/src/target-templates/.devops/docker-images/node-services/node-run.sh +8 -0
  250. package/src/target-templates/.devops/docker-images/node-services.Dockerfile +34 -0
  251. package/src/target-templates/.devops/docker-images/python-services/python-exec.sh +8 -0
  252. package/src/target-templates/.devops/docker-images/python-services/python-run.sh +8 -0
  253. package/src/target-templates/.devops/docker-images/python-services.Dockerfile +29 -0
  254. package/src/target-templates/.devops/env.example.yaml +23 -0
  255. package/src/target-templates/.devops/infra/hetzner/abandoned/harbor-values.yaml +30 -0
  256. package/src/target-templates/.devops/infra/hetzner/abandoned/hcloud-config.yaml +134 -0
  257. package/src/target-templates/.devops/infra/hetzner/cert-manager.yaml +25 -0
  258. package/src/target-templates/.devops/infra/hetzner/harbor-cert.yaml +13 -0
  259. package/src/target-templates/.devops/infra/hetzner/harbor-values.yaml +76 -0
  260. package/src/target-templates/.devops/infra/hetzner/hcloud-config.yaml +113 -0
  261. package/src/target-templates/.devops/infra/hetzner/ingress-nginx-annotations.yaml +49 -0
  262. package/src/target-templates/.devops/infra/hetzner/ingress-nginx-configmap.yaml +8 -0
  263. package/src/target-templates/.devops/infra/hetzner/retain-storage-class.yaml +8 -0
  264. package/src/target-templates/.devops/infra/monitoring-ingress.yaml +62 -0
  265. package/src/target-templates/.devops/infra/stackgres-ui-ingress.yaml +35 -0
  266. package/src/target-templates/.devops/infra/test.yaml +60 -0
  267. package/src/target-templates/.devops/manifests/_index.yaml +21 -0
  268. package/src/target-templates/.devops/manifests/cron-jobs.yaml.hb +55 -0
  269. package/src/target-templates/.devops/manifests/db-migrate-job.yaml.hb +42 -0
  270. package/src/target-templates/.devops/manifests/deployment-debug.yaml.hb +44 -0
  271. package/src/target-templates/.devops/manifests/deployment-process.yaml.hb +47 -0
  272. package/src/target-templates/.devops/manifests/deployment-web.yaml.hb +53 -0
  273. package/src/target-templates/.devops/manifests/ingress.yaml.hb +21 -0
  274. package/src/target-templates/.devops/manifests/prefect.yaml.hb +62 -0
  275. package/src/target-templates/.devops/manifests/service.yaml.hb +15 -0
  276. package/src/target-templates/.devops/milvus/production/milvus-values.yaml +2 -0
  277. package/src/target-templates/.devops/milvus/staging/milvus-values.yaml +2 -0
  278. package/src/target-templates/.devops/postgres/DailyOperatorRestart.yaml +54 -0
  279. package/src/target-templates/.devops/postgres/production/cluster/PodDisruptionBudget.yaml +27 -0
  280. package/src/target-templates/.devops/postgres/production/cluster/SGCluster.yaml +47 -0
  281. package/src/target-templates/.devops/postgres/production/cluster/StackGres-alerts.yaml +191 -0
  282. package/src/target-templates/.devops/postgres/production/configurations/06-SGDistributedLogs.yaml +11 -0
  283. package/src/target-templates/.devops/postgres/production/configurations/07-SGObjectStorage.yaml +18 -0
  284. package/src/target-templates/.devops/postgres/production/configurations/08-SGScript.yaml +12 -0
  285. package/src/target-templates/.devops/postgres/staging/cluster/SGCluster.yaml +42 -0
  286. package/src/target-templates/.devops/postgres/staging/configurations/07-SGObjectStorage.yaml +18 -0
  287. package/src/target-templates/.devops/postgres/staging/configurations/08-SGScript.yaml +12 -0
  288. package/src/target-templates/.devops/prefect/production/prefect-values.yaml +14 -0
  289. package/src/target-templates/.devops/prefect/staging/prefect-values.yaml +14 -0
  290. package/src/target-templates/.devops/redis/production/redis-values.yaml +20 -0
  291. package/src/target-templates/.devops/redis/staging/redis-values.yaml +8 -0
  292. package/src/target-templates/.envrc +5 -0
  293. package/src/target-templates/.github/actions/build-image@v1/action.yaml +86 -0
  294. package/src/target-templates/.github/actions/connect-to-digital-ocean@v1/action.yaml +29 -0
  295. package/src/target-templates/.github/actions/connect-to-hetzner@v1/action.yaml +31 -0
  296. package/src/target-templates/.github/actions/connect-to-infra@v1/action.yaml +46 -0
  297. package/src/target-templates/.github/actions/db-migrate@v1/action.yaml +23 -0
  298. package/src/target-templates/.github/actions/deploy-image@v1/action.yaml +33 -0
  299. package/src/target-templates/.github/actions/setup-prereq@v1/action.yaml +29 -0
  300. package/src/target-templates/.github/workflows/k8s-build.yaml +84 -0
  301. package/src/target-templates/applications/example-data-pipeline/pyproject.toml +14 -0
  302. package/src/target-templates/applications/example-data-pipeline/src/example_data_pipeline/main.py +38 -0
  303. package/src/target-templates/applications/example-node/index.ts +30 -0
  304. package/src/target-templates/applications/example-node/package.json +26 -0
  305. package/src/target-templates/applications/example-node/tsconfig.json +3 -0
  306. package/src/target-templates/applications/example-python/pyproject.toml +20 -0
  307. package/src/target-templates/applications/example-python/src/example_python/__init__.py +0 -0
  308. package/src/target-templates/applications/example-python/src/example_python/main.py +13 -0
  309. package/src/target-templates/applications/example-python/src/example_python/scripts.py +17 -0
  310. package/src/target-templates/applications/example-python/tests/__init__.py +0 -0
  311. package/src/target-templates/applications/jobs/README.md +68 -0
  312. package/src/target-templates/applications/jobs/index.ts +1 -0
  313. package/src/target-templates/applications/jobs/package.json +30 -0
  314. package/src/target-templates/applications/jobs/tsconfig.json +3 -0
  315. package/src/target-templates/config/.env.development +1 -0
  316. package/src/target-templates/config/.env.global +4 -0
  317. package/src/target-templates/config/.env.test +1 -0
  318. package/src/target-templates/db/db/__init__.py +0 -0
  319. package/src/target-templates/db/db/db_client_test.py +46 -0
  320. package/src/target-templates/db/db-client-test.ts +140 -0
  321. package/src/target-templates/db/db-client.ts +19 -0
  322. package/src/target-templates/db/env.yaml +4 -0
  323. package/src/target-templates/db/package.json +17 -0
  324. package/src/target-templates/db/prisma/schema.prisma +24 -0
  325. package/src/target-templates/db/prisma-setup-vitest.ts +27 -0
  326. package/src/target-templates/db/pyproject.toml +14 -0
  327. package/src/target-templates/db/tsconfig.json +3 -0
  328. package/src/target-templates/devops +3 -0
  329. package/src/target-templates/devopspy +3 -0
  330. package/src/target-templates/dml/package.json +7 -0
  331. package/src/target-templates/dml/tsconfig.json +3 -0
  332. package/src/target-templates/libs/example-node-lib/bun.lock +27 -0
  333. package/src/target-templates/libs/example-node-lib/index.ts +3 -0
  334. package/src/target-templates/libs/example-node-lib/package.json +12 -0
  335. package/src/target-templates/libs/example-node-lib/tsconfig.json +3 -0
  336. package/src/target-templates/libs/example-python-lib/pyproject.toml +11 -0
  337. package/src/target-templates/libs/example-python-lib/src/example_python_lib/__init__.py +2 -0
  338. package/src/target-templates/pyproject.toml +19 -0
  339. package/src/target-templates/tmp/.gitkeep +0 -0
  340. package/src/target-templates/tsconfig.json +27 -0
  341. package/src/test.ts +0 -0
  342. package/src/types/index.ts +173 -0
@@ -0,0 +1,86 @@
1
+ name: "Build image"
2
+ description: "Build the specified image if it's affected"
3
+ inputs:
4
+ image_name:
5
+ description: 'The image key in images.yaml'
6
+ required: true
7
+ gh_pat_token:
8
+ description: "GitHub personal access token"
9
+ required: true
10
+ cache_path:
11
+ description: "The path to cache inside the container"
12
+ required: true
13
+ outputs:
14
+ affected:
15
+ description: "Whether the image is affected"
16
+ value: ${{ steps.check_affected.outputs.affected }}
17
+ runs:
18
+ using: "composite"
19
+ steps:
20
+ - name: Setup basic vars
21
+ shell: bash
22
+ run: |
23
+ echo "IMAGE_NAME=${{ inputs.image_name }}" >> $GITHUB_ENV
24
+
25
+ - name: Set up Docker Buildx
26
+ uses: docker/setup-buildx-action@v3
27
+
28
+ - name: Check if affected
29
+ id: check_affected
30
+ shell: bash
31
+ run: |
32
+ AFFECTED=$(devops affected image $IMAGE_NAME --from-live-version)
33
+ echo "affected=$AFFECTED" >> $GITHUB_OUTPUT
34
+ if [[ "$AFFECTED" == "true" ]]; then
35
+ echo "${{ env.IMAGE_NAME }} is affected. Proceeding with build."
36
+ else
37
+ echo "${{ env.IMAGE_NAME }} is not affected. Skipping."
38
+ fi
39
+
40
+ - name: Prepare build
41
+ shell: bash
42
+ if: steps.check_affected.outputs.affected == 'true'
43
+ run: |
44
+ echo "CACHE_PREFIX=v1-${{ runner.os }}-${{ env.IMAGE_NAME }}-${{ github.ref_name }}" >> $GITHUB_ENV
45
+ echo "ECR_URL=$(devops registry repo-url ${{ env.IMAGE_NAME }} ${{ github.sha }})" >> $GITHUB_ENV
46
+ folder=$(devops prep-build ${{ env.IMAGE_NAME }})
47
+ mv $folder /home/runner/build
48
+ echo MONOREPO_ENV=${{ env.MONOREPO_ENV }}
49
+
50
+ - name: Setup cache
51
+ if: steps.check_affected.outputs.affected == 'true'
52
+ id: setup-cache
53
+ uses: actions/cache@v4
54
+ with:
55
+ path: cache-path
56
+ key: ${{ env.CACHE_PREFIX }}
57
+
58
+ - name: Inject cache into docker
59
+ if: steps.check_affected.outputs.affected == 'true'
60
+ uses: reproducible-containers/buildkit-cache-dance@v3.1.0
61
+ with:
62
+ cache-map: |
63
+ {
64
+ "cache-path": "${{ inputs.cache_path }}"
65
+ }
66
+ skip-extraction: ${{ steps.setup-cache.outputs.cache-hit }}
67
+
68
+ - name: Build and push Docker image
69
+ if: steps.check_affected.outputs.affected == 'true'
70
+ uses: docker/build-push-action@v6
71
+ with:
72
+ context: /home/runner/build
73
+ push: true
74
+ tags: ${{ env.ECR_URL }}
75
+ cache-from: type=gha
76
+ cache-to: type=gha,mode=max
77
+ secrets: |
78
+ GH_PAT_TOKEN=${{ inputs.gh_pat_token }}
79
+ build-args: |
80
+ MONOREPO_ENV=${{ env.MONOREPO_ENV }}
81
+
82
+ - name: Prune registry
83
+ if: steps.check_affected.outputs.affected == 'true'
84
+ shell: bash
85
+ run: |
86
+ devops registry prune ${{ env.IMAGE_NAME }}
@@ -0,0 +1,29 @@
1
+ name: "Connect to Digital Ocean"
2
+ description: "Sets up kubernetes connection to Digital Ocean and ensures connection"
3
+ inputs:
4
+ access_token:
5
+ description: "DigitalOcean access token"
6
+ required: true
7
+ cluster_name:
8
+ description: "DigitalOcean cluster name"
9
+ required: true
10
+ runs:
11
+ using: "composite"
12
+ steps:
13
+ - name: Install doctl
14
+ uses: digitalocean/action-doctl@v2
15
+ with:
16
+ token: ${{ inputs.access_token }}
17
+
18
+ - name: Log in to DigitalOcean Container Registry with short-lived credentials
19
+ run: doctl registry login --expiry-seconds 1200
20
+ shell: bash
21
+
22
+ - name: Save DigitalOcean kubeconfig with short-lived credentials
23
+ run: |
24
+ doctl kubernetes cluster kubeconfig save --expiry-seconds 1200 ${{ inputs.cluster_name }}
25
+ shell: bash
26
+
27
+ - name: verify namepsace exists
28
+ run: devops namespace check --env ${{ github.ref_name }}
29
+ shell: bash
@@ -0,0 +1,31 @@
1
+ name: "Connect to Hetzner"
2
+ description: "Sets up kubernetes connection to Hetzner and ensures connection"
3
+ inputs:
4
+ kubeconfig:
5
+ description: "The Hetzner kubeconfig file"
6
+ required: true
7
+ harbor_user:
8
+ description: "The user name for the harbor registry"
9
+ required: true
10
+ harbor_password:
11
+ description: "The password for the harbor registry"
12
+ required: true
13
+ runs:
14
+ using: "composite"
15
+ steps:
16
+ - name: Create a kubeconfig file
17
+ run: |
18
+ mkdir -p ~/.kube
19
+ echo "${{ inputs.kubeconfig }}" > ~/.kube/config
20
+ chmod 600 ~/.kube/config
21
+ shell: bash
22
+
23
+ - name: Verify cluster connection and that namepsace exists
24
+ run: devops namespace check --env ${{ github.ref_name }}
25
+ shell: bash
26
+
27
+ - name: Connect to the registry
28
+ run: |
29
+ server_url=$(devops registry server-url)
30
+ docker login $server_url -u '${{ inputs.harbor_user }}' -p ${{ inputs.harbor_password }}
31
+ shell: bash
@@ -0,0 +1,46 @@
1
+ name: "Connect to the infrastructure"
2
+ description: "Convenience action to connect either to Digital Ocean or Hetzner based on the inputs provided"
3
+ inputs:
4
+ do_access_token:
5
+ description: "DigitalOcean access token"
6
+ required: false
7
+ do_cluster_name:
8
+ description: "DigitalOcean cluster name"
9
+ required: false
10
+ hetzner_kubeconfig:
11
+ description: "The Hetzner kubeconfig file"
12
+ required: false
13
+ harbor_user:
14
+ description: "The user name for the harbor registry"
15
+ required: false
16
+ harbor_password:
17
+ description: "The password for the harbor registry"
18
+ required: false
19
+ outputs:
20
+ infra:
21
+ description: "Which infrastructure is being used"
22
+ value: steps.determine_infrastructure.outputs.infra
23
+ runs:
24
+ using: "composite"
25
+ steps:
26
+ - name: Determine the infrastructure
27
+ id: determine_infrastructure
28
+ shell: bash
29
+ run: |
30
+ INFRA=$(devops constant infra)
31
+ echo "infra=$INFRA" >> $GITHUB_OUTPUT
32
+
33
+ - name: Connect to Digital Ocean
34
+ if: steps.determine_infrastructure.outputs.infra == 'digitalocean'
35
+ uses: ./.github/actions/connect-to-digital-ocean@v1
36
+ with:
37
+ access_token: ${{ inputs.do_access_token }}
38
+ cluster_name: ${{ inputs.do_cluster_name }}
39
+
40
+ - name: Connect to Hetzner
41
+ if: steps.determine_infrastructure.outputs.infra == 'hetzner'
42
+ uses: ./.github/actions/connect-to-hetzner@v1
43
+ with:
44
+ kubeconfig: ${{ inputs.hetzner_kubeconfig }}
45
+ harbor_user: ${{ inputs.harbor_user }}
46
+ harbor_password: ${{ inputs.harbor_password }}
@@ -0,0 +1,23 @@
1
+ name: "DB Migrate"
2
+ description: "Run DB migrate on an affected image, if applicable"
3
+ runs:
4
+ using: "composite"
5
+ steps:
6
+ - name: run-db-migrate
7
+ shell: bash
8
+ run: |
9
+ set +e
10
+ IMAGE=$(devops affected find-migrator --from-live-version)
11
+ status=$?
12
+ set -e
13
+ if [[ $status -eq 13 ]]; then
14
+ echo "db project missing, skipping DB migration"
15
+ elif [[ $status -ne 0 ]]; then
16
+ exit $status
17
+ elif [[ "$IMAGE" != "" ]]; then
18
+ devops job db-migrate create $IMAGE ${{ github.sha }} --timeout 240
19
+ else
20
+ echo "No image requires a DB migration"
21
+ fi
22
+
23
+
@@ -0,0 +1,33 @@
1
+ name: "Deploy image"
2
+ description: "Deploy the specified image if it's affected and set its version"
3
+ inputs:
4
+ image_name:
5
+ description: 'The image key in images.yaml'
6
+ required: true
7
+ runs:
8
+ using: "composite"
9
+ steps:
10
+ - name: Setup basic vars
11
+ shell: bash
12
+ run: |
13
+ echo "IMAGE_NAME=${{ inputs.image_name }}" >> $GITHUB_ENV
14
+
15
+ - name: Check if affected
16
+ id: check_affected
17
+ shell: bash
18
+ run: |
19
+ AFFECTED=$(devops affected image $IMAGE_NAME --from-live-version)
20
+ echo "affected=$AFFECTED" >> $GITHUB_OUTPUT
21
+ echo "affected=$AFFECTED"
22
+ if [[ "$AFFECTED" == "true" ]]; then
23
+ echo "${{ env.IMAGE_NAME }} is affected. Proceeding with deployment."
24
+ else
25
+ echo "${{ env.IMAGE_NAME }} is not affected. Skipping."
26
+ fi
27
+
28
+ - name: Deploy
29
+ shell: bash
30
+ if: steps.check_affected.outputs.affected == 'true'
31
+ run: |
32
+ devops image deployment create ${{ env.IMAGE_NAME }} ${{ github.sha }}
33
+ devops image version set ${{ env.IMAGE_NAME }} ${{ github.sha }}
@@ -0,0 +1,29 @@
1
+ name: "Install prerequesites"
2
+ description: "Sets up Node, Bun, and devops"
3
+ inputs:
4
+ gh_pat_token:
5
+ description: "The GitHub Personal Access Token"
6
+ required: true
7
+ runs:
8
+ using: "composite"
9
+ steps:
10
+ - name: Setup Node.js
11
+ uses: actions/setup-node@v4
12
+ with:
13
+ node-version: 23
14
+
15
+ - name: Setup bun
16
+ uses: oven-sh/setup-bun@v2
17
+
18
+ - name: set $MONOREPO_ENV
19
+ shell: bash
20
+ run: |
21
+ BRANCH_NAME=${{ github.ref_name }}
22
+ echo "MONOREPO_ENV=$BRANCH_NAME" >> $GITHUB_ENV
23
+ echo "GH_PAT_TOKEN=${{ inputs.gh_pat_token }}" >> $GITHUB_ENV
24
+
25
+ - name: Install the devops tool
26
+ shell: bash
27
+ run: |
28
+ bun install @vaharoni/devops
29
+ echo "$(pwd)/node_modules/.bin" >> $GITHUB_PATH
@@ -0,0 +1,84 @@
1
+ name: "Monorepo Build and Deploy"
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - staging
7
+ - production
8
+
9
+ permissions:
10
+ contents: read
11
+ packages: read
12
+
13
+ jobs:
14
+ build_images:
15
+ runs-on: ubuntu-latest
16
+ strategy:
17
+ matrix:
18
+ include:
19
+ - image_name: main-node
20
+ - image_name: main-python
21
+ cache_path: /root/.cache/uv
22
+ steps:
23
+ # Fetch the last 50 commits so that devops affected works
24
+ - name: Checkout repo and history
25
+ uses: actions/checkout@v4
26
+ with:
27
+ fetch-depth: 50
28
+
29
+ - name: Setup prerequesites
30
+ uses: ./.github/actions/setup-prereq@v1
31
+ with:
32
+ gh_pat_token: ${{ secrets.GH_PAT_TOKEN }}
33
+
34
+ - name: Connect to infrastructure
35
+ uses: ./.github/actions/connect-to-infra@v1
36
+ with:
37
+ do_access_token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
38
+ do_cluster_name: ${{ secrets.DIGITALOCEAN_CLUSTER_NAME }}
39
+ hetzner_kubeconfig: ${{ secrets.HCLOUD_KUBECONFIG }}
40
+ harbor_user: ${{ secrets.HARBOR_USER }}
41
+ harbor_password: ${{ secrets.HARBOR_PASSWORD }}
42
+
43
+ - name: Build image
44
+ uses: ./.github/actions/build-image@v1
45
+ with:
46
+ image_name: ${{ matrix.image_name }}
47
+ gh_pat_token: ${{ secrets.GH_PAT_TOKEN }}
48
+ cache_path: ${{ matrix.cache_path || '/root/.bun/install/cache' }}
49
+
50
+ db_migrate_and_deploy:
51
+ needs: [build_images]
52
+ runs-on: ubuntu-latest
53
+ steps:
54
+ # Fetch the last 50 commits so that devops affected works
55
+ - name: Checkout repo and history
56
+ uses: actions/checkout@v4
57
+ with:
58
+ fetch-depth: 50
59
+
60
+ - name: Setup prerequesites
61
+ uses: ./.github/actions/setup-prereq@v1
62
+ with:
63
+ gh_pat_token: ${{ secrets.GH_PAT_TOKEN }}
64
+
65
+ - name: Connect to infrastructure
66
+ uses: ./.github/actions/connect-to-infra@v1
67
+ with:
68
+ do_access_token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
69
+ do_cluster_name: ${{ secrets.DIGITALOCEAN_CLUSTER_NAME }}
70
+ hetzner_kubeconfig: ${{ secrets.HCLOUD_KUBECONFIG }}
71
+ harbor_user: ${{ secrets.HARBOR_USER }}
72
+ harbor_password: ${{ secrets.HARBOR_PASSWORD }}
73
+
74
+ - name: Run DB Migrate
75
+ uses: ./.github/actions/db-migrate@v1
76
+
77
+ # Repeat per image (it checks if the image is affected and deploys it if it is)
78
+ - name: Deploy main node
79
+ uses: ./.github/actions/deploy-image@v1
80
+ with: { "image_name": "main-node" }
81
+
82
+ - name: Deploy main python
83
+ uses: ./.github/actions/deploy-image@v1
84
+ with: { "image_name": "main-python" }
@@ -0,0 +1,14 @@
1
+ [project]
2
+ name = "example-data-pipeline"
3
+ version = "0.1.0"
4
+ description = ""
5
+ authors = []
6
+ requires-python = ">=3.12"
7
+ dependencies = ["prefect (>=3.2.14,<4.0.0)"]
8
+
9
+ [tool.devops.deployment]
10
+ template = "prefect"
11
+
12
+ [[tool.devops.deployment.prefectFlows]]
13
+ flow_name = "test-flow"
14
+ script_path = "src.example_data_pipeline.main"
@@ -0,0 +1,38 @@
1
+ import httpx
2
+
3
+ from prefect import flow, task # Prefect flow and task decorators
4
+
5
+
6
+ @flow(log_prints=True)
7
+ def show_stars(github_repos: list[str]):
8
+ """Flow: Show the number of stars that GitHub repos have"""
9
+ for repo in github_repos:
10
+ # Call Task 1
11
+ repo_stats = fetch_stats(repo)
12
+
13
+ # Call Task 2
14
+ stars = get_stars(repo_stats)
15
+
16
+ # Print the result
17
+ print(f"{repo}: {stars} stars")
18
+
19
+
20
+ @task
21
+ def fetch_stats(github_repo: str):
22
+ """Task 1: Fetch the statistics for a GitHub repo"""
23
+ return httpx.get(f"https://api.github.com/repos/{github_repo}").json()
24
+
25
+
26
+ @task
27
+ def get_stars(repo_stats: dict):
28
+ """Task 2: Get the number of stars from GitHub repo statistics"""
29
+ return repo_stats['stargazers_count']
30
+
31
+
32
+ # Run the flow
33
+ if __name__ == "__main__":
34
+ show_stars.serve(
35
+ name="Show Stars",
36
+ parameters={"github_repos": ["PrefectHQ/prefect", "pydantic/pydantic", "huggingface/transformers"]},
37
+ interval=60*60
38
+ )
@@ -0,0 +1,30 @@
1
+ import express from "express";
2
+ import { InternalToken } from '@vaharoni/devops';
3
+
4
+ const app = express();
5
+ const port = 3001;
6
+
7
+ app.get("/", (req, res) => {
8
+ res.send("Hello from node");
9
+ });
10
+
11
+ // See applications/jobs/README.md for more information
12
+ app.post("/ping-from-jobs", (req, res) => {
13
+ const authorizationHeader = req.headers['authorization'];
14
+ try {
15
+ new InternalToken('jobs').verifyFromHeaderOrThrow(authorizationHeader);
16
+ } catch {
17
+ res.status(401).json({ status: 'unauthorized' });
18
+ return;
19
+ }
20
+ console.log('Pong');
21
+ res.json({ status: 'ok' });
22
+ });
23
+
24
+ app.get("/healthz", (req, res) => {
25
+ res.send("OK");
26
+ });
27
+
28
+ app.listen(port, () => {
29
+ console.log(`Server is listening on ${port}`);
30
+ });
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "example-node",
3
+ "module": "index.ts",
4
+ "type": "module",
5
+ "private": true,
6
+ "deployment": {
7
+ "service_name": "example-node",
8
+ "port": 3001,
9
+ "template": "external-service"
10
+ },
11
+ "scripts": {
12
+ "start": "tsx index.ts",
13
+ "verify": "tsc -p ./tsconfig.json --noEmit"
14
+ },
15
+ "dependencies": {
16
+ "express": "^4.21.2",
17
+ "example-node-lib": "workspace:*"
18
+ },
19
+ "devDependencies": {
20
+ "@types/bun": "latest",
21
+ "@types/express": "^5.0.0"
22
+ },
23
+ "peerDependencies": {
24
+ "typescript": "^5"
25
+ }
26
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "../../tsconfig.json"
3
+ }
@@ -0,0 +1,20 @@
1
+ [project]
2
+ name = "example-python"
3
+ version = "0.1.0"
4
+ description = ""
5
+ authors = []
6
+ requires-python = ">=3.12"
7
+ dependencies = ["example-python-lib", "fastapi[standard]"]
8
+
9
+ [tool.devops.scripts]
10
+ dev = "python -c 'from src.example_python.scripts import dev; dev()'"
11
+ start = "python -c 'from src.example_python.scripts import start; start()'"
12
+
13
+ [tool.uv.sources]
14
+ example-python-lib = { workspace = true }
15
+
16
+
17
+ [tool.devops.deployment]
18
+ template = "external-service"
19
+ service_name = "example-python"
20
+ port = 3002
@@ -0,0 +1,13 @@
1
+ import os
2
+ from fastapi import FastAPI
3
+
4
+ app = FastAPI()
5
+
6
+
7
+ @app.get("/")
8
+ def read_root():
9
+ return "Hello from python"
10
+
11
+ @app.get("/healthz")
12
+ def healthz():
13
+ return {"status": "ok"}
@@ -0,0 +1,17 @@
1
+ import subprocess
2
+ from devops_python.pyproject import get_pyproject_data
3
+
4
+ package_name = "example_python"
5
+ data = get_pyproject_data()
6
+ port = data.deployment["port"]
7
+ workers = data.deployment.get("workers")
8
+
9
+ def dev():
10
+ subprocess.run(["fastapi", "dev", f"src/{package_name}/main.py", "--port", str(port)], check=True)
11
+
12
+ def start():
13
+ cmd = ["fastapi", "run", f"src/{package_name}/main.py", "--port", str(port)]
14
+ if (workers):
15
+ cmd.extend(["--workers", str(workers)])
16
+
17
+ subprocess.run(cmd, check=True)
@@ -0,0 +1,68 @@
1
+ This application allows running commands at a certain schedule via k8s cron jobs.
2
+ Currently only curl is supported. A special auth token is injected to the Authorization Bearer which can
3
+ be verified by the receiver.
4
+
5
+ ## Adding a cron job
6
+
7
+ To add a cron job, add an entry in `package.json` under `deployments.cronJobs`:
8
+ ```json
9
+ "deployment": {
10
+ "template": "cron-job",
11
+ "cronJobs": [
12
+ {
13
+ "name": "call-check-something-in-example",
14
+ "cron": "*/15 * * * *",
15
+ "curl": ["jobs", "-X", "POST", "http://example/jobs/check-something"]
16
+ }
17
+ ]
18
+ }
19
+ ```
20
+
21
+ - `name` - must be unique across jobs and a valid k8s name. No spaces are allowed.
22
+ - `cron` - must be a valid Cron format per [here](https://en.wikipedia.org/wiki/Cron).
23
+ - `curl` - must be an array of strings, where each arg is an element in the array.
24
+
25
+ A few things to note about the `curl` argument:
26
+ - We use an array here, since curl relies heavily on args with spaces, e.g. `Content-Type: application/json` is a single arg.
27
+ - The first element must be the subject of the token sent to the endpoint. The endpoint should verify the request header contains a bearer token with the expected subject.
28
+ - The endpoint can be a DNS internal to the cluster, i.e. simply use the service name if it is in the same namepsace.
29
+
30
+ Downsides of this approach:
31
+ - the domain name used is a duplication of the `deployment.service_name` of the target application. This can be addressed in the future, e.g. by adding another arg to the cronjob with the `appName` that performs service discovery.
32
+
33
+ ## Securing an API endpoint
34
+
35
+ Next.js example:
36
+
37
+ ```typescript
38
+ // app/someroute/route.ts
39
+
40
+ import { NextResponse } from 'next/server';
41
+ import { InternalToken } from '@vaharoni/devops';
42
+
43
+ export async function POST(request: Request) {
44
+ const authorizationHeader = request.headers.get('Authorization');
45
+ try {
46
+ new InternalToken('jobs').verifyFromHeaderOrThrow(authorizationHeader);
47
+ } catch {
48
+ return NextResponse.json({ status: 'unauthorized' }, { status: 401 });
49
+ }
50
+
51
+ // Do something
52
+
53
+ return NextResponse.json({ status: 'ok' });
54
+ }
55
+ ```
56
+
57
+ ## Testing a secure endpoint in local development
58
+
59
+ Make sure your `config/.env.global` has something like:
60
+ ```text
61
+ MONOREPO_BASE_SECRET=123456789abcdef
62
+ ```
63
+
64
+ Then run:
65
+
66
+ ```bash
67
+ devops internal-curl jobs -v -X POST localhost:3001/jobs/someroute
68
+ ```
@@ -0,0 +1 @@
1
+ // no-op
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "jobs",
3
+ "type": "module",
4
+ "version": "0.0.1",
5
+ "main": "index.ts",
6
+ "nx": {
7
+ "projectType": "application"
8
+ },
9
+ "scripts": {
10
+ "print-token": "bunx tsx print-token.ts",
11
+ "verify": "tsc -p ./tsconfig.json --noEmit"
12
+ },
13
+ "author": "",
14
+ "license": "ISC",
15
+ "deployment": {
16
+ "template": "cron-jobs",
17
+ "cronJobs": [
18
+ {
19
+ "name": "test",
20
+ "cron": "*/15 * * * *",
21
+ "curl": [
22
+ "jobs",
23
+ "-X",
24
+ "POST",
25
+ "http://example-node/ping-from-jobs"
26
+ ]
27
+ }
28
+ ]
29
+ }
30
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "../../tsconfig.json"
3
+ }
@@ -0,0 +1 @@
1
+ # Add here env variables that are for local development environment
@@ -0,0 +1,4 @@
1
+ # Add here env variables that are global to all environments
2
+
3
+ # This should remain locally on your machine. There is no need to set this in the remote environment.
4
+ MONOREPO_BASE_SECRET=123456789abcdef
@@ -0,0 +1 @@
1
+ # Add here env variables that are for local test environment
File without changes