Compare commits

..

215 Commits

Author SHA1 Message Date
bd0158d04d fix(deps): update rust crate tracing to v0.1.41
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-11-28 01:30:41 +00:00
b43c322dbd chore(deps): update rust crate serde_json to v1.0.133
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-11-17 05:24:58 +00:00
453f405124
feat: remove deps
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-11-16 17:11:30 +01:00
c05442baf6
feat: remove ci
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-11-16 17:11:06 +01:00
cuddle-please
811969871f chore(release): 0.3.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2024-11-16 16:08:05 +00:00
c8b8328ce2
feat: with lib drone
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-11-16 17:06:07 +01:00
7932e7a913
feat: with rust something
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-11-16 17:05:16 +01:00
c8f56874d0
feat: fix errors
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-11-16 16:09:07 +01:00
66efb97120
feat: update dagger
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-11-16 15:59:59 +01:00
ca2f490f6d chore(deps): update rust crate serde to v1.0.215
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-11-12 01:24:07 +00:00
34b081d004 chore(deps): update rust crate serde to v1.0.214
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-10-29 01:30:12 +00:00
d902fc186e chore(deps): update rust crate serde to v1.0.213
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-10-23 00:31:07 +00:00
4685dd28f9
feat: update
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-09-07 23:34:34 +02:00
6aa5686a0d chore(deps): update rust crate serde to v1.0.210
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-09-07 00:23:53 +00:00
eb66d51984 chore(deps): update rust crate serde to v1.0.209
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-08-24 03:49:04 +00:00
fe665a61a2 chore(deps): update rust crate serde to v1.0.208
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-08-21 20:52:10 +00:00
171fa0e6fa
feat: without extra packages
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-08-18 12:02:23 +02:00
90598c9ffc
feat: wrong exclude
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-08-07 11:31:11 +02:00
7800794271
feat: also exclude tests
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-08-07 11:24:26 +02:00
12dff478a3
feat: update dagger 0.11.10
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-08-01 22:53:04 +02:00
a7656a9da1
feat: update dagger 0.11.7
Some checks reported errors
continuous-integration/drone/push Build was killed
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-08-01 22:19:59 +02:00
f11687dc26
feat: add empty cuddle please for now
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-06-01 14:40:47 +02:00
2eef711f9d
feat: update
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-05-26 15:49:41 +02:00
9996fb742a
feat: update a lot
Some checks reported errors
continuous-integration/drone/push Build encountered an error
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-05-26 15:47:26 +02:00
6dbd681d67 chore(deps): update rust crate serde to v1.0.203
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-05-25 21:17:21 +00:00
4bd6032c05
feat: update components on prs to also build release
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-05-25 23:10:11 +02:00
65735ba15a fix(deps): update rust crate chrono to 0.4.38
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-04-15 10:15:17 +00:00
5c580691dd chore(deps): update rust crate async-trait to 0.1.80
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
continuous-integration/drone Build is passing
2024-04-11 19:09:17 +00:00
fa6654bb3b
feat: update version
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-04-09 23:29:13 +02:00
3155e75240
feat: update image
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-04-09 23:03:42 +02:00
82a7b7e9b1
feat: move to user local bin
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-04-06 23:04:06 +02:00
556cb152e8
feat: with alpine instead
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-04-06 22:56:45 +02:00
372b7a2526
feat: add permissions
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-04-06 22:49:42 +02:00
c4e3e5781c
feat: use version as well
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-04-06 22:42:35 +02:00
a38906466e
feat: install curl
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-04-06 22:40:23 +02:00
d115d57129
fix: typo
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-04-06 22:38:17 +02:00
4141079d8c
feat: trying again
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-04-06 22:36:00 +02:00
ff55c99279
feat: add dagger bin actually6 compiles
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-04-06 22:33:00 +02:00
7d586337e9
feat: add dagger bin
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-04-06 22:29:06 +02:00
48f142ef58
feat: add file
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-04-06 21:53:09 +02:00
59748fb6e6
feat: match values first
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-04-05 23:08:05 +02:00
62d54ce56f
feat: pretty print
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-04-05 23:06:51 +02:00
5cac7d1c88
feat: with debug
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-04-05 23:04:37 +02:00
8b080f2f43
feat: return with sqlx
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-04-05 23:01:11 +02:00
2daa0864e2
feat: add debug logs
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-04-05 22:58:25 +02:00
c3f9613541
feat: with single migrations
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-04-05 22:55:07 +02:00
924bcf8c8c
feat: handle for cuddle_file
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-04-05 22:45:25 +02:00
99bc420f71
feat: with cuddle release clone
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-30 23:48:20 +01:00
5fb1399f0c
feat: use stuff
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-30 23:40:46 +01:00
c0fe864923
feat: with as ref as well
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-30 23:39:14 +01:00
6ec6844ebb
feat: implement clone
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-30 23:34:23 +01:00
8690a06aa4
feat: now with to owned as well
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-30 23:33:44 +01:00
20ea9fd3c6
feat: use generics
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-30 23:18:56 +01:00
c38062bb46
feat: use cuddle please
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-30 22:54:56 +01:00
c03f351d81
refactor: split module
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-30 22:53:09 +01:00
823712e2bf
feat: with rust workspace members
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-30 22:33:25 +01:00
0539e375b1
feat: update dagger
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-30 21:17:29 +01:00
a6dab9a178
feat: fix cuddle_releaser
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-30 21:03:37 +01:00
f4e7ced9d8
feat: make cloneable
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-30 15:49:10 +01:00
4f15e5a887
feat: remove extra fluff
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-30 15:42:41 +01:00
e7e456e5d9
feat: add trace
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-30 15:37:07 +01:00
250807d16f
feat: add image tag
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-30 15:30:59 +01:00
e479c79cc9
feat: make sure to add values property
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-30 15:26:13 +01:00
9aa3e88b32
feat: update image
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-30 15:13:15 +01:00
0d744623ce
feat: add system time
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-30 14:33:36 +01:00
5234c1da89
feat: update drone templater
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-30 14:25:00 +01:00
b9417747a8
feat: include pipeline
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-30 02:26:08 +01:00
365b840fe9
feat: include sync
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-30 01:56:57 +01:00
ef77451bb7
feat: use self.client
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-30 01:48:26 +01:00
a6d83daf4d
feat: with aborting
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-30 01:47:57 +01:00
29c59f1ca6
feat: fix errors
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-30 01:46:54 +01:00
8282f89640
feat: fix errors
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-30 01:46:25 +01:00
9ba98284ae
feat: create drone templater action
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-30 01:41:33 +01:00
d9ea6162d4 fix(deps): update all dependencies
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-03-28 17:31:15 +00:00
95d6704fc1 chore(deps): update rust crate async-trait to 0.1.79
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-03-24 03:49:51 +00:00
22f15505aa chore(deps): update rust crate async-trait to 0.1.78
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-03-17 00:18:24 +00:00
d1285aa7ee fix(deps): update rust crate chrono to 0.4.35
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-03-06 14:09:46 +00:00
9b4c3a61e1
feat: make cuddle_releaser great again
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-02 16:54:44 +01:00
378d60e943
feat: upgrade services to bookworm
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-02 16:22:42 +01:00
359222b281
feat: upgrade to bookworm
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-02 16:13:11 +01:00
d2467529b3
feat: with apt
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-02 16:07:05 +01:00
d42bd82f76
feat: with logging
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-02 15:52:10 +01:00
11f6fdb1d5
feat: with logging
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-02 15:51:36 +01:00
34145ba380
feat: update leptos service
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-02 15:23:54 +01:00
ac435a843e
feat: rerun blabla
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-02-11 14:24:20 +01:00
6a47528f11
feat: with export
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-02-11 14:16:30 +01:00
999cc9d59f
feat: with fix
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-02-11 14:13:27 +01:00
5dbaf3c87f
feat: cargo update
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-02-11 14:11:44 +01:00
90692d026d
feat: with ignore sub source as well
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-02-11 14:11:24 +01:00
0ad738700a fix(deps): update rust crate chrono to 0.4.34
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-02-11 05:59:00 +00:00
49d0da5e82
feat: add helm to kubectl
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-02-06 21:42:51 +01:00
122d453387
feat: add main
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-02-03 21:09:08 +01:00
018d21872a
feat: add timestamp
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-02-03 21:00:15 +01:00
d471a6190a
feat: use tag instead
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-02-03 20:42:23 +01:00
2735b7d2cf
feat: use tag instead
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-02-03 20:42:17 +01:00
96ea5e83f5
feat: revert
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-02-03 19:57:55 +01:00
385e4ab771
feat: from cuddle file up
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-02-03 19:55:08 +01:00
a62a88915e
feat: remember to split output string
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-02-03 19:39:05 +01:00
e475550004
feat: with cuddle x render args
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-02-03 19:02:03 +01:00
512c3f625e
feat: with context
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-02-03 18:54:17 +01:00
e8507cd2f2 chore(deps): update rust crate tokio to 1.36.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-02-02 12:40:25 +00:00
5465f1eef7 chore(deps): update rust crate eyre to 0.6.12
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-01-31 20:54:54 +00:00
f62b90dd3b
feat: with kubeslice
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-31 21:17:16 +01:00
f0a719e3ed
feat: with kubeslice
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-31 21:16:48 +01:00
91ff1f17ae
feat: add kubectl command
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-31 20:55:24 +01:00
c16396db8c
feat: trying spawn
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-31 20:37:45 +01:00
c016752e4f
feat: trying std::process instead
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-31 20:34:46 +01:00
2611b6c7f9
feat: stderr pipes
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-31 20:32:38 +01:00
050d599d81
feat: with nonzero exit code
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-31 20:26:32 +01:00
0deb6f83a0
feat: with more logs
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-31 20:11:36 +01:00
f2196920f4
feat: update releaser
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-31 19:50:16 +01:00
cc13070f77 fix(deps): update all dependencies
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-01-28 23:31:42 +00:00
ab9e764cc3 fix(deps): update rust crate futures to 0.3.30
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-01-28 23:04:24 +00:00
3f8aa88617
feat: disable ci for now
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-28 23:43:30 +01:00
050b81c6ae
feat: add cuddle_cli
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-28 23:42:54 +01:00
2b4a67e38c
feat: add cuddle_cli
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-28 23:41:59 +01:00
7363871ffb
feat: with docker
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-28 23:34:05 +01:00
a2250edadb
feat: with apt before package
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-28 23:24:33 +01:00
14ab05eb9b
feat: all the logs
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-28 22:59:32 +01:00
2cb8929b91
feat: all the logs
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-28 22:58:23 +01:00
1f23425150
feat: all the logs
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-28 22:57:37 +01:00
c40b74513d
feat: all the logs
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-28 22:54:49 +01:00
f5b1f2a1d8
feat: all the logs
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-28 22:52:17 +01:00
068ad47598
feat: all the logs
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-28 22:45:25 +01:00
bc4bc3df94
feat: with new image
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-28 22:43:31 +01:00
ca237f2ee3
feat: with new image
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-28 22:34:51 +01:00
46c88f1e6f
feat: with new image
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-28 22:28:35 +01:00
42c968f460
feat: set rust log error
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-28 22:25:59 +01:00
f882f56c9c
feat: add time str
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-28 22:24:28 +01:00
1fa94aa5ff
feat: new image
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-28 22:18:51 +01:00
19ad63d31d
feat: without logs
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-28 22:12:46 +01:00
fa67d71d64
feat: try again
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-28 22:12:35 +01:00
1aa9d1993b
feat: with updated releaser
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-28 22:03:17 +01:00
f86c19c510
feat: with trace
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-28 21:56:46 +01:00
5875c96aa8
feat: with output
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-28 21:49:52 +01:00
663fe0b199
feat: use proper releaser
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-28 21:46:05 +01:00
7a1f04a071
feat: add auth sock
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-28 21:19:02 +01:00
8788f78f81
feat: with cuddle x render
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-28 21:06:16 +01:00
c0ae03376b
feat: add deployment take 2
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-28 20:45:25 +01:00
3da154882d
feat: add deployment
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-28 20:44:12 +01:00
5378b5f537
feat: add releaser
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-28 19:20:38 +01:00
926199a487
feat: conditionally disable deployment
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-01-28 00:25:42 +01:00
3a6f5bb6d2
feat: without home
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-12-30 22:51:26 +01:00
fb4c064bec
feat: run before base
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-12-30 22:50:18 +01:00
3ff9cff6d6
fix: as isize
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-12-30 22:45:06 +01:00
84626939e7
feat: set user
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-12-30 22:43:53 +01:00
638117e7e9
feat: with empty string
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-12-30 22:41:56 +01:00
877f19aa72
fix: actually build the builder
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-12-30 22:40:49 +01:00
7daf873e37
feat: with ingored host key checking
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-12-30 22:40:08 +01:00
cf05cf4228
feat: with migrations as well
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-12-30 22:18:13 +01:00
97b70164d1
feat: with opinionated ssh auth sock fetch
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-12-30 22:07:44 +01:00
830e39e8bf
feat: set env variable as well
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-12-30 22:00:00 +01:00
8248b61545
chore: rename with_socket to with_ssh_agent
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-12-30 21:59:21 +01:00
9ee64020fe
fix: build errors on ssh agent
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-12-30 21:58:17 +01:00
c759db28b0
feat: with ssh agent
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-12-30 21:55:29 +01:00
e67c4baa97
feat: extract cuddle_please
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-12-29 19:55:10 +01:00
1b5ee9b7e3
feat: update image
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-12-29 19:52:27 +01:00
80b99c27a5
feat: with cuddle please
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-12-29 19:43:04 +01:00
124aa93b98
feat: without new async
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-12-29 17:19:22 +01:00
10ef2294d2
feat: with rust_lib
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-12-29 17:18:02 +01:00
1e257b1269
feat: with main as well
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-12-28 14:31:32 +01:00
97bf2b217c
feat: with test with leptos
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-12-28 14:26:55 +01:00
0e7f134bd0
feat: add initial leptos
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-12-28 14:17:31 +01:00
c977fdbcaa
feat: add postgresql-dev
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-12-26 18:07:18 +01:00
63fbecd194
feat: without nodemodules
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-12-26 17:34:17 +01:00
d352ace1ea
feat: with entry point
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-12-26 17:30:14 +01:00
08c36e737c
feat: with actual pr
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-12-26 17:25:18 +01:00
8b929c912c
feat: with pub fn new
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-12-26 17:22:46 +01:00
a78803d35b
feat: add node service
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-12-26 17:20:41 +01:00
3cdd876e05
feat: trying again with opts
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-12-01 22:36:44 +01:00
ec2a0f5779
feat: without opts
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-12-01 22:12:59 +01:00
4e380b17c0
feat: set registry
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-12-01 21:59:26 +01:00
88a467780c
feat: move to after package
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-12-01 21:42:58 +01:00
bcdfaf2b2d
feat: with docker cache
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-12-01 21:41:13 +01:00
94efc99d05
feat: update assets
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-28 11:27:15 +01:00
320ff343e6
feat: with assets
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-28 10:12:19 +01:00
67803d315c
feat: with package as well
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-28 01:02:04 +01:00
5908cd9526
feat: without deps
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-28 00:51:29 +01:00
62f66452c2
feat: with ca certificates
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-28 00:49:28 +01:00
a5d08f4a0d
feat: with working ssh
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-27 23:28:35 +01:00
12b7c27342
feat: update with ssh
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-27 22:32:27 +01:00
9c3f806a80
feat: with ssh sock dep
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-27 22:18:39 +01:00
663feba85d
feat: can use ssh sock
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-27 22:18:05 +01:00
e5b3e1b62a
feat: with username
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-27 22:15:11 +01:00
0f7ed2b6f4
feat: with git name
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-27 22:04:39 +01:00
c391482874
feat: with sync
Some checks reported errors
continuous-integration/drone/push Build encountered an error
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-27 21:36:46 +01:00
b879da4d2f
feat: with update deployment
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-27 21:34:23 +01:00
a900ebae54
feat: with registry
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-27 21:24:45 +01:00
c893dc9005
feat: with before test
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-27 20:31:29 +01:00
30587b2f97
feat: with impl into
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-27 20:19:50 +01:00
bda242422d
feat: with arc
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-27 20:11:49 +01:00
999d81bb7a
feat: with &mut service
Some checks reported errors
continuous-integration/drone/push Build encountered an error
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-27 19:20:41 +01:00
93e73cc66e
feat: with mutex
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-27 19:14:31 +01:00
52266599e2
feat: with rust service impl
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-27 18:11:58 +01:00
85ad929d80
feat: with src
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-27 14:15:43 +01:00
a0acb54896
feat: with sqlx
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-27 13:52:11 +01:00
2a988c33a4
feat: forgot async_trait
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-27 13:44:44 +01:00
015cb6b23a
feat: with cargo clean
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-27 13:42:13 +01:00
8869b75072
feat: with extensions
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-27 13:25:31 +01:00
3c28b30f8f
feat: extract arch
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-26 22:46:34 +01:00
7a1ad63b57
feat: with full support for rust services
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-26 22:19:34 +01:00
80782e70f9
chore: fmt
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-25 23:16:21 +01:00
3939940c01
chore: fmt
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-25 23:14:38 +01:00
82ccdefd93
feat: with middleware
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-25 23:10:09 +01:00
3e9a840851 chore(deps): update rust crate async-scoped to 0.8.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-11-25 21:26:21 +00:00
455660f1e0 chore(deps): update rust crate futures to 0.3.29
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-11-25 21:01:05 +00:00
f5ba46186b
feat: with logs
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-25 21:49:04 +01:00
8cf148726a
feat: add cuddle ci draft
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-25 21:41:17 +01:00
e29615cb05
feat: with offline mode
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-25 14:00:17 +01:00
cdd13283e0
feat: with cargo clean
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-25 13:50:43 +01:00
a3d92cdde3
feat: without export
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-25 13:47:17 +01:00
e4fc1cc834
feat: with output
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-25 13:33:54 +01:00
d6af354776
feat: with nested mold
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-25 12:55:56 +01:00
0524b2e0bf
feat: fix name
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-25 12:48:57 +01:00
5c69c3fa16
feat: with mold
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-11-25 12:47:43 +01:00
51 changed files with 4836 additions and 2829 deletions

View File

@ -1,170 +1,2 @@
kind: pipeline kind: template
name: default load: cuddle-rust-lib-plan.yaml
type: docker
steps:
- name: build ci
image: rustlang/rust:nightly
volumes:
- name: ci
path: /mnt/ci
environment:
PKG_CONFIG_SYSROOT_DIR: "/"
CI_PREFIX: "/mnt/ci"
commands:
- set -e
- apt update
- apt install musl-tools pkg-config libssl-dev openssl build-essential musl-dev -y
- rustup target add x86_64-unknown-linux-musl
- cargo build --target=x86_64-unknown-linux-musl -p ci
#- cargo build -p ci
- mv target/x86_64-unknown-linux-musl/debug/ci "$CI_PREFIX/ci"
#- mv target/debug/ci $CI_PREFIX/ci
- name: load_secret
image: debian:buster-slim
volumes:
- name: ssh
path: /root/.ssh/
environment:
SSH_KEY:
from_secret: gitea_id_ed25519
commands:
- mkdir -p $HOME/.ssh/
- echo "$SSH_KEY" | base64 -d > $HOME/.ssh/id_ed25519
- name: build pr
image: kasperhermansen/cuddle:latest
pull: always
volumes:
- name: ssh
path: /root/.ssh/
- name: dockersock
path: /var/run
- name: ci
path: /mnt/ci
commands:
- eval `ssh-agent`
- chmod -R 600 ~/.ssh
- ssh-add
- echo "$DOCKER_PASSWORD" | docker login --password-stdin --username="$DOCKER_USERNAME" docker.io
- ldd $CI_PREFIX
- apk add git
- cuddle x ci:pr
environment:
DOCKER_BUILDKIT: 1
DOCKER_PASSWORD:
from_secret: docker_password
DOCKER_USERNAME:
from_secret: docker_username
CUDDLE_SECRETS_PROVIDER: 1password
CUDDLE_ONE_PASSWORD_DOT_ENV: ".env.ci"
CUDDLE_SSH_AGENT: "true"
CI_PREFIX: "/mnt/ci/ci"
CUDDLE_PLEASE_TOKEN:
from_secret: cuddle_please_token
OP_SERVICE_ACCOUNT_TOKEN:
from_secret: op_service_account_token
when:
event:
- pull_request
exclude:
- main
- master
depends_on:
- "load_secret"
- "build ci"
- name: build main
image: kasperhermansen/cuddle:latest
pull: always
volumes:
- name: ssh
path: /root/.ssh/
- name: dockersock
path: /var/run
- name: ci
path: /mnt/ci
commands:
- eval `ssh-agent`
- chmod -R 600 ~/.ssh
- ssh-add
- echo "$DOCKER_PASSWORD" | docker login --password-stdin --username="$DOCKER_USERNAME" docker.io
- ldd $CI_PREFIX
- apk add git
- cuddle x ci:main
environment:
DOCKER_BUILDKIT: 1
DOCKER_PASSWORD:
from_secret: docker_password
DOCKER_USERNAME:
from_secret: docker_username
CUDDLE_SECRETS_PROVIDER: 1password
CUDDLE_ONE_PASSWORD_DOT_ENV: ".env.ci"
CUDDLE_SSH_AGENT: "true"
CI_PREFIX: "/mnt/ci/ci"
CUDDLE_PLEASE_TOKEN:
from_secret: cuddle_please_token
OP_SERVICE_ACCOUNT_TOKEN:
from_secret: op_service_account_token
when:
event:
- push
branch:
- main
- master
exclude:
- pull_request
depends_on:
- "load_secret"
- "build ci"
- name: deploy release
image: kasperhermansen/cuddle:latest
pull: always
volumes:
- name: ssh
path: /root/.ssh/
- name: dockersock
path: /var/run
commands:
- eval `ssh-agent`
- chmod -R 600 ~/.ssh
- ssh-add
- cuddle x build:release:all
- cuddle x deploy:docs:preview
environment:
DOCKER_BUILDKIT: 1
CUDDLE_SECRETS_PROVIDER: 1password
CUDDLE_ONE_PASSWORD_DOT_ENV: ".env.ci"
CUDDLE_SSH_AGENT: "true"
CUDDLE_CI: "true"
CUDDLE_PLEASE_TOKEN:
from_secret: cuddle_please_token
OP_SERVICE_ACCOUNT_TOKEN:
from_secret: op_service_account_token
when:
event:
- tag
ref:
include:
- refs/tags/v*
depends_on:
- "load_secret"
- "build ci"
services:
- name: docker
image: docker:dind
privileged: true
volumes:
- name: dockersock
path: /var/run
volumes:
- name: ssh
temp: {}
- name: dockersock
temp: {}
- name: ci
temp: {}

View File

@ -6,6 +6,240 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
## [0.3.0] - 2024-11-16
### Added
- with lib drone
- with rust something
- fix errors
- update dagger
- update
- without extra packages
- wrong exclude
- also exclude tests
- update dagger 0.11.10
- update dagger 0.11.7
- add empty cuddle please for now
- update
- update a lot
- update components on prs to also build release
- update version
- update image
- move to user local bin
- with alpine instead
- add permissions
- use version as well
- install curl
- trying again
- add dagger bin actually6 compiles
- add dagger bin
- add file
- match values first
- pretty print
- with debug
- return with sqlx
- add debug logs
- with single migrations
- handle for cuddle_file
- with cuddle release clone
- use stuff
- with as ref as well
- implement clone
- now with to owned as well
- use generics
- use cuddle please
- with rust workspace members
- update dagger
- fix cuddle_releaser
- make cloneable
- remove extra fluff
- add trace
- add image tag
- make sure to add values property
- update image
- add system time
- update drone templater
- include pipeline
- include sync
- use self.client
- with aborting
- fix errors
- fix errors
- create drone templater action
- make cuddle_releaser great again
- upgrade services to bookworm
- upgrade to bookworm
- with apt
- with logging
- with logging
- update leptos service
- rerun blabla
- with export
- with fix
- cargo update
- with ignore sub source as well
- add helm to kubectl
- add main
- add timestamp
- use tag instead
- use tag instead
- revert
- from cuddle file up
- remember to split output string
- with cuddle x render args
- with context
- with kubeslice
- with kubeslice
- add kubectl command
- trying spawn
- trying std::process instead
- stderr pipes
- with nonzero exit code
- with more logs
- update releaser
- disable ci for now
- add cuddle_cli
- add cuddle_cli
- with docker
- with apt before package
- all the logs
- all the logs
- all the logs
- all the logs
- all the logs
- all the logs
- with new image
- with new image
- with new image
- set rust log error
- add time str
- new image
- without logs
- try again
- with updated releaser
- with trace
- with output
- use proper releaser
- add auth sock
- with cuddle x render
- add deployment take 2
- add deployment
- add releaser
- conditionally disable deployment
- without home
- run before base
- set user
- with empty string
- with ingored host key checking
- with migrations as well
- with opinionated ssh auth sock fetch
- set env variable as well
- with ssh agent
- extract cuddle_please
- update image
- with cuddle please
- without new async
- with rust_lib
- with main as well
- with test with leptos
- add initial leptos
- add postgresql-dev
- without nodemodules
- with entry point
- with actual pr
- with pub fn new
- add node service
- trying again with opts
- without opts
- set registry
- move to after package
- with docker cache
- update assets
- with assets
- with package as well
- without deps
- with ca certificates
- with working ssh
- update with ssh
- with ssh sock dep
- can use ssh sock
- with username
- with git name
- with sync
- with update deployment
- with registry
- with before test
- with impl into
- with arc
- with &mut service
- with mutex
- with rust service impl
- with src
- with sqlx
- forgot async_trait
- with cargo clean
- with extensions
- extract arch
- with full support for rust services
- with middleware
- with logs
- add cuddle ci draft
- with offline mode
- with cargo clean
- without export
- with output
- with nested mold
- fix name
- with mold
- with mold
- with htmx
- add leptos
- ignore cache
- update lock
- with updated dagger-sdk
- *(rust-publish)* with rust publish
### Fixed
- *(deps)* update rust crate chrono to 0.4.38
- typo
- *(deps)* update all dependencies
- *(deps)* update rust crate chrono to 0.4.35
- *(deps)* update rust crate chrono to 0.4.34
- *(deps)* update all dependencies
- *(deps)* update rust crate futures to 0.3.30
- as isize
- actually build the builder
- build errors on ssh agent
- *(deps)* update rust crate async-scoped to 0.8.0
- *(deps)* update rust crate futures to 0.3.29
- *(git)* make sure we actually fail when running an invalid git command
### Other
- *(deps)* update rust crate serde to v1.0.215
- *(deps)* update rust crate serde to v1.0.214
- *(deps)* update rust crate serde to v1.0.213
- *(deps)* update rust crate serde to v1.0.210
- *(deps)* update rust crate serde to v1.0.209
- *(deps)* update rust crate serde to v1.0.208
- *(deps)* update rust crate serde to v1.0.203
- *(deps)* update rust crate async-trait to 0.1.80
- split module
- *(deps)* update rust crate async-trait to 0.1.79
- *(deps)* update rust crate async-trait to 0.1.78
- *(deps)* update rust crate tokio to 1.36.0
- *(deps)* update rust crate eyre to 0.6.12
- rename with_socket to with_ssh_agent
- fmt
- fmt
- *(deps)* update rust crate async-scoped to 0.8.0
- *(deps)* update rust crate futures to 0.3.29
- *(deps)* update rust crate eyre to 0.6.9
- *(deps)* update rust crate tokio to 1.34.0
- *(deps)* update all dependencies
- with version 0.2.0
- publish
- add noop release script
## [0.2.0] - 2023-08-12 ## [0.2.0] - 2023-08-12
### Added ### Added

1370
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,9 @@
[workspace] [workspace]
members = ["crates/*", "examples/*", "ci"] members = ["crates/*", "examples/*"]
resolver = "2" resolver = "2"
[workspace.package] [workspace.package]
version = "0.2.0" version = "0.3.0"
edition = "2021" edition = "2021"
license = "MIT" license = "MIT"
authors = ["kjuulh <contact@kjuulh.io>"] authors = ["kjuulh <contact@kjuulh.io>"]
@ -15,11 +15,16 @@ cuddle-components = { path = "crates/cuddle-components" }
dagger-components = { path = "crates/dagger-components" } dagger-components = { path = "crates/dagger-components" }
dagger-cuddle-please = { path = "crates/dagger-cuddle-please" } dagger-cuddle-please = { path = "crates/dagger-cuddle-please" }
dagger-rust = { path = "crates/dagger-rust" } dagger-rust = { path = "crates/dagger-rust" }
ci = { path = "ci" }
#dagger-sdk = "0.3.2" dagger-sdk = "0.13.7"
dagger-sdk = {git = "https://github.com/kjuulh/dagger.git", branch = "feat/with-send-sync"} eyre = "0.6"
eyre = "0.6.9" tokio = "1"
tokio = "1.34.0"
dotenv = "0.15.0" dotenv = "0.15.0"
async-trait = "0.1.74" async-trait = "0.1"
color-eyre = "*"
clap = { version = "4", features = ["derive"] }
futures = "0.3"
async-scoped = { version = "0.9.0", features = ["tokio", "use-tokio"] }
serde_json = { version = "1" }
serde_yaml = { version = "0.9" }
serde = { version = "1", features = ["derive"] }

1861
ci/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,19 +0,0 @@
[package]
name = "ci"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
dagger-cuddle-please.workspace = true
dagger-rust.workspace = true
dagger-sdk.workspace = true
eyre = "*"
color-eyre = "*"
tokio = "1"
clap = {version = "4", features = ["derive"]}
futures = "0.3.29"
async-scoped = { version = "0.8.0", features = ["tokio", "use-tokio"] }
dotenv.workspace = true

View File

@ -1,157 +0,0 @@
use std::path::PathBuf;
use std::sync::Arc;
use clap::Args;
use clap::Parser;
use clap::Subcommand;
use clap::ValueEnum;
use crate::please_release::run_release_please;
#[derive(Parser, Clone)]
#[command(author, version, about, long_about = None, subcommand_required = true)]
pub struct Command {
#[command(subcommand)]
commands: Commands,
#[command(flatten)]
global: GlobalArgs,
}
#[derive(Subcommand, Clone)]
pub enum Commands {
#[command(subcommand_required = true)]
Local {
#[command(subcommand)]
command: LocalCommands,
},
PullRequest {},
Main {},
Release,
}
#[derive(Subcommand, Clone)]
pub enum LocalCommands {
Test,
PleaseRelease,
}
#[derive(Debug, Clone, ValueEnum)]
pub enum BuildProfile {
Debug,
Release,
}
#[derive(Debug, Clone, Args)]
pub struct GlobalArgs {
#[arg(long, global = true, help_heading = "Global")]
dry_run: bool,
#[arg(long, global = true, help_heading = "Global")]
rust_builder_image: Option<String>,
#[arg(long, global = true, help_heading = "Global")]
cuddle_please_image: Option<String>,
#[arg(long, global = true, help_heading = "Global")]
source: Option<PathBuf>,
}
#[tokio::main]
async fn main() -> eyre::Result<()> {
let _ = dotenv::dotenv();
let _ = color_eyre::install();
let client = dagger_sdk::connect().await?;
let cli = Command::parse();
match &cli.commands {
Commands::Local { command } => match command {
LocalCommands::Test => {
test::execute(client, &cli.global).await?;
}
LocalCommands::PleaseRelease => todo!(),
},
Commands::PullRequest {} => {
async fn test(client: dagger_sdk::Query, cli: &Command) {
let args = &cli.global;
test::execute(client.clone(), args).await.unwrap();
}
tokio::join!(test(client.clone(), &cli),);
}
Commands::Main {} => {
async fn test(client: dagger_sdk::Query, cli: &Command) {
let args = &cli.global;
test::execute(client.clone(), args).await.unwrap();
}
async fn cuddle_please(client: dagger_sdk::Query, cli: &Command) {
run_release_please(client.clone(), &cli.global)
.await
.unwrap();
}
tokio::join!(
test(client.clone(), &cli),
cuddle_please(client.clone(), &cli)
);
}
Commands::Release => {}
}
Ok(())
}
mod please_release {
use std::sync::Arc;
use dagger_cuddle_please::{models::CuddlePleaseSrcArgs, DaggerCuddlePleaseAction};
use crate::GlobalArgs;
pub async fn run_release_please(
client: dagger_sdk::Query,
args: &GlobalArgs,
) -> eyre::Result<()> {
DaggerCuddlePleaseAction::dagger(client)
.execute_src(&CuddlePleaseSrcArgs {
cuddle_image: args
.cuddle_please_image
.clone()
.unwrap_or("kasperhermansen/cuddle-please:latest".into()),
server: dagger_cuddle_please::models::SrcServer::Gitea {
token: std::env::var("CUDDLE_PLEASE_TOKEN")
.expect("CUDDLE_PLEASE_TOKEN to be present"),
},
log_level: Some(dagger_cuddle_please::models::LogLevel::Debug),
})
.await?;
Ok(())
}
}
mod test {
use std::{path::PathBuf, sync::Arc};
use dagger_rust::build::RustVersion;
use crate::GlobalArgs;
pub async fn execute(client: dagger_sdk::Query, _args: &GlobalArgs) -> eyre::Result<()> {
dagger_rust::test::RustTest::new(client)
.test(
None::<PathBuf>,
RustVersion::Nightly,
&["crates/*", "examples/*", "ci"],
&[],
)
.await?;
Ok(())
}
}

View File

@ -0,0 +1,36 @@
[package]
name = "cuddle-ci"
version.workspace = true
edition.workspace = true
license.workspace = true
authors.workspace = true
readme.workspace = true
repository.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
dagger-rust.workspace = true
dagger-cuddle-please.workspace = true
dagger-sdk.workspace = true
eyre.workspace = true
clap.workspace = true
async-trait.workspace = true
futures.workspace = true
tokio.workspace = true
serde_json.workspace = true
serde_yaml.workspace = true
serde.workspace = true
tracing = {version = "0.1.40", features = ["log"]}
chrono = {version = "0.4.38"}
toml = "0.8.12"
[dev-dependencies]
pretty_assertions = "1.4.0"
tokio.workspace = true
[features]
default = []
dagger = []
integration = []

198
crates/cuddle-ci/src/cli.rs Normal file
View File

@ -0,0 +1,198 @@
use std::{
collections::BTreeMap,
ops::{Deref, DerefMut},
};
use async_trait::async_trait;
pub struct CuddleCI {
pr_action: Vec<Box<dyn PullRequestAction + Send + Sync>>,
main_action: Vec<Box<dyn MainAction + Send + Sync>>,
release_action: Vec<Box<dyn ReleaseAction + Send + Sync>>,
}
#[derive(Default, Debug)]
pub struct Context {
store: BTreeMap<String, String>,
}
impl Deref for Context {
type Target = BTreeMap<String, String>;
fn deref(&self) -> &Self::Target {
&self.store
}
}
impl DerefMut for Context {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.store
}
}
impl CuddleCI {
pub fn new(
pr: Box<dyn PullRequestAction + Send + Sync>,
main: Box<dyn MainAction + Send + Sync>,
release: Box<dyn ReleaseAction + Send + Sync>,
) -> Self {
Self {
pr_action: vec![pr],
main_action: vec![main],
release_action: vec![release],
}
}
pub fn with_pull_request<T>(&mut self, pr: &T) -> &mut Self
where
T: PullRequestAction + ToOwned + Send + Sync + 'static,
T: ToOwned<Owned = T>,
{
self.pr_action.push(Box::new(pr.to_owned()));
self
}
pub fn with_main<T>(&mut self, main: &T) -> &mut Self
where
T: MainAction + Send + Sync + 'static,
T: ToOwned<Owned = T>,
{
self.main_action.push(Box::new(main.to_owned()));
self
}
pub fn with_release(&mut self, release: Box<dyn ReleaseAction + Send + Sync>) -> &mut Self {
self.release_action.push(release);
self
}
pub async fn execute(
&mut self,
args: impl IntoIterator<Item = impl Into<String>>,
) -> eyre::Result<()> {
let matches = clap::Command::new("cuddle-ci")
.about("is a wrapper around common CI actions")
.subcommand(clap::Command::new("pr"))
.subcommand(clap::Command::new("main"))
.subcommand(clap::Command::new("release"))
.subcommand_required(true)
.try_get_matches_from(args.into_iter().map(|a| a.into()).collect::<Vec<String>>())?;
let mut context = Context::default();
match matches.subcommand() {
Some((name, args)) => match (name, args) {
("pr", _args) => {
eprintln!("starting pr validate");
for pr_action in self.pr_action.iter() {
pr_action.execute_pull_request(&mut context).await?;
}
eprintln!("finished pr validate");
}
("main", _args) => {
eprintln!("starting main validate");
for main_action in self.main_action.iter() {
main_action.execute_main(&mut context).await?;
}
eprintln!("finished main validate");
}
("release", _args) => {
eprintln!("starting release validate");
for release_action in self.release_action.iter() {
release_action.execute_release(&mut context).await?;
}
eprintln!("finished release validate");
}
(command_name, _) => {
eyre::bail!("command is not recognized: {}", command_name)
}
},
None => eyre::bail!("command required a subcommand [pr, main, release] etc."),
}
Ok(())
}
}
impl Default for CuddleCI {
fn default() -> Self {
Self::new(
Box::new(DefaultPullRequestAction {}),
Box::new(DefaultMainAction {}),
Box::new(DefaultReleaseAction {}),
)
}
}
#[async_trait]
pub trait PullRequestAction {
async fn execute_pull_request(&self, _ctx: &mut Context) -> eyre::Result<()> {
eprintln!("validate pull request: noop");
Ok(())
}
}
pub struct DefaultPullRequestAction {}
#[async_trait]
impl PullRequestAction for DefaultPullRequestAction {}
#[async_trait]
pub trait MainAction {
async fn execute_main(&self, _ctx: &mut Context) -> eyre::Result<()>;
}
pub struct DefaultMainAction {}
#[async_trait]
impl MainAction for DefaultMainAction {
async fn execute_main(&self, _ctx: &mut Context) -> eyre::Result<()> {
Ok(())
}
}
#[async_trait]
pub trait ReleaseAction {
async fn execute_release(&self, _ctx: &mut Context) -> eyre::Result<()> {
eprintln!("validate release: noop");
Ok(())
}
}
pub struct DefaultReleaseAction {}
#[async_trait]
impl ReleaseAction for DefaultReleaseAction {}
#[cfg(test)]
mod test {
use super::*;
#[tokio::test]
async fn test_can_call_default() -> eyre::Result<()> {
CuddleCI::default().execute(["cuddle-ci", "pr"]).await?;
Ok(())
}
#[tokio::test]
async fn test_fails_on_no_command() -> eyre::Result<()> {
let res = CuddleCI::default().execute(["cuddle-ci"]).await;
assert!(res.is_err());
Ok(())
}
#[tokio::test]
async fn test_fails_on_wrong_command() -> eyre::Result<()> {
let res = CuddleCI::default()
.execute(["cuddle-ci", "something"])
.await;
assert!(res.is_err());
Ok(())
}
}

View File

@ -0,0 +1,273 @@
use std::{collections::BTreeMap, path::PathBuf};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct CuddleFile {
pub vars: CuddleVars,
pub deployment: Option<CuddleDeployment>,
pub components: Option<CuddleComponents>,
pub please: Option<CuddlePlease>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct CuddleComponents {
pub database: Option<CuddleDatabase>,
pub assets: Option<CuddleAssets>,
pub packages: Option<Packages>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct CuddleAssets {
pub volumes: Option<Vec<CuddleAssetInclude>>,
pub clean: Option<bool>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct CuddlePlease {}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct Packages {
pub debian: DebianPackages,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct DebianPackages {
pub dev: Vec<String>,
pub release: Vec<String>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct CuddleAssetInclude {
pub from: PathBuf,
pub to: PathBuf,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[serde(untagged)]
pub enum CuddleDatabase {
Enabled(bool),
Values { migrations: PathBuf },
Default {},
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct CuddleVars {
pub service: String,
pub registry: String,
pub clusters: Option<CuddleClusters>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct CuddleDeployment {
pub registry: String,
pub env: CuddleDeploymentEnv,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct CuddleDeploymentEnv(pub BTreeMap<String, CuddleDeploymentCluster>);
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct CuddleDeploymentCluster {
pub clusters: Vec<String>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct CuddleClusters(pub BTreeMap<String, CuddleCluster>);
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct CuddleCluster {
pub namespace: String,
}
impl CuddleFile {
pub async fn from_cuddle_file() -> eyre::Result<Self> {
let cuddle_file_content = tokio::fs::read_to_string("cuddle.yaml").await?;
Self::parse_cuddle_file(&cuddle_file_content)
}
pub fn parse_cuddle_file(content: &str) -> eyre::Result<Self> {
let cuddle_file: CuddleFile = serde_yaml::from_str(content)?;
Ok(cuddle_file)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn parse_file() {
let cuddle_file = r#"
base: "git@git.front.kjuulh.io:kjuulh/cuddle-base.git"
vars:
service: "infrastructure-example"
registry: kasperhermansen
clusters:
clank_prod:
replicas: "3"
namespace: clank_prod
deployment:
registry: git@git.front.kjuulh.io:kjuulh/clank-clusters
env:
prod:
clusters:
- clank_prod
components:
database: true
assets:
volumes:
- from: somewhere
to: somewhere-else
packages:
debian:
dev:
- "capnp"
release:
- "capnp"
scripts:
render:
type: shell
args:
cluster:
name: cluster
type: flag
image_tag:
name: image_tag
type: flag"#;
let res = CuddleFile::parse_cuddle_file(cuddle_file).expect("to parse file");
let mut clusters = BTreeMap::new();
clusters.insert(
"clank_prod".into(),
CuddleCluster {
namespace: "clank_prod".into(),
},
);
let mut deployment = BTreeMap::new();
deployment.insert(
"prod".into(),
CuddleDeploymentCluster {
clusters: vec!["clank_prod".into()],
},
);
let expected = CuddleFile {
vars: CuddleVars {
service: "infrastructure-example".into(),
registry: "kasperhermansen".into(),
clusters: Some(CuddleClusters(clusters)),
},
deployment: Some(crate::cuddle_file::CuddleDeployment {
registry: "git@git.front.kjuulh.io:kjuulh/clank-clusters".into(),
env: CuddleDeploymentEnv(deployment),
}),
components: Some(CuddleComponents {
database: Some(CuddleDatabase::Enabled(true)),
assets: Some(CuddleAssets {
volumes: Some(vec![CuddleAssetInclude {
from: "somewhere".into(),
to: "somewhere-else".into(),
}]),
clean: None,
}),
packages: Some(Packages {
debian: DebianPackages {
dev: vec!["capnp".into()],
release: vec!["capnp".into()],
},
}),
}),
please: None,
};
pretty_assertions::assert_eq!(expected, res)
}
#[test]
fn cuddle_database_default() {
let cuddle_file = r#"
base: "git@git.front.kjuulh.io:kjuulh/cuddle-base.git"
vars:
service: "infrastructure-example"
registry: kasperhermansen
components:
database: {}
"#;
let res = CuddleFile::parse_cuddle_file(cuddle_file).expect("to parse file");
let expected = CuddleFile {
vars: CuddleVars {
service: "infrastructure-example".into(),
registry: "kasperhermansen".into(),
clusters: None,
},
deployment: None,
components: Some(CuddleComponents {
database: Some(CuddleDatabase::Default {}),
assets: None,
packages: None,
}),
please: None,
};
pretty_assertions::assert_eq!(expected, res)
}
#[test]
fn cuddle_packages() {
let cuddle_file = r#"
base: "git@git.front.kjuulh.io:kjuulh/cuddle-base.git"
vars:
service: "infrastructure-example"
registry: kasperhermansen
components:
packages:
debian:
dev:
- "capnp"
release:
- "capnp"
"#;
let res = CuddleFile::parse_cuddle_file(cuddle_file).expect("to parse file");
let expected = CuddleFile {
vars: CuddleVars {
service: "infrastructure-example".into(),
registry: "kasperhermansen".into(),
clusters: None,
},
deployment: None,
components: Some(CuddleComponents {
database: None,
assets: None,
packages: Some(Packages {
debian: DebianPackages {
dev: vec!["capnp".into()],
release: vec!["capnp".into()],
},
}),
}),
please: None,
};
pretty_assertions::assert_eq!(expected, res)
}
}

View File

@ -0,0 +1,37 @@
use async_trait::async_trait;
use dagger_cuddle_please::{models::CuddlePleaseSrcArgs, DaggerCuddlePlease};
use crate::{Context, MainAction};
#[derive(Clone)]
pub struct CuddlePlease {
client: dagger_sdk::Query,
}
impl CuddlePlease {
pub fn new(client: dagger_sdk::Query) -> Self {
Self { client }
}
}
#[async_trait]
impl MainAction for CuddlePlease {
async fn execute_main(&self, _ctx: &mut Context) -> eyre::Result<()> {
let client = self.client.clone();
let action = DaggerCuddlePlease::new(client);
action
.cuddle_please_src(&CuddlePleaseSrcArgs {
cuddle_image: "kasperhermansen/cuddle-please:main-1712698022".into(),
server: dagger_cuddle_please::models::SrcServer::Gitea {
token: std::env::var("CUDDLE_PLEASE_TOKEN")
.expect("CUDDLE_PLEASE_TOKEN to be present"),
},
log_level: Some(dagger_cuddle_please::models::LogLevel::Debug),
})
.await?;
Ok(())
}
}

View File

@ -0,0 +1,152 @@
use std::fmt::Display;
use async_trait::async_trait;
use eyre::Context;
use crate::{cli, cuddle_file::CuddleFile, MainAction};
#[derive(Clone)]
pub struct CuddleReleaser {
client: dagger_sdk::Query,
env: Option<String>,
cuddle_file: CuddleFile,
folder: String,
}
pub struct CuddleReleaserOptions {
upstream: String,
cluster: String,
namespace: String,
app: String,
}
pub enum CuddleEnv {
Prod,
Dev,
}
impl Display for CuddleEnv {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
CuddleEnv::Prod => f.write_str("prod"),
CuddleEnv::Dev => f.write_str("dev"),
}
}
}
impl TryInto<CuddleEnv> for String {
type Error = eyre::Error;
fn try_into(self) -> Result<CuddleEnv, Self::Error> {
let env = match self.as_str() {
"prod" => CuddleEnv::Prod,
"dev" => CuddleEnv::Dev,
_ => eyre::bail!("was not a valid env: {}", self),
};
Ok(env)
}
}
impl CuddleReleaser {
pub async fn new(client: dagger_sdk::Query) -> eyre::Result<Self> {
let cuddle_file = CuddleFile::from_cuddle_file().await?;
let env = std::env::var("CUDDLE_ENV").ok();
Ok(Self {
client,
cuddle_file,
env,
folder: ".cuddle/tmp".into(),
})
}
pub async fn releaser(&self, env: CuddleEnv) -> eyre::Result<()> {
let client = self.client.clone();
if self.cuddle_file.deployment.is_none() {
return Ok(());
}
let chosen_cluster = match self
.cuddle_file
.deployment
.as_ref()
.unwrap()
.env
.0
.get(&self.env.as_ref().unwrap_or(&env.to_string()).to_string())
{
Some(c) => match c.clusters.first().take() {
Some(c) => c,
None => return Ok(()),
},
None => return Ok(()),
};
if let Some(clusters) = &self.cuddle_file.vars.clusters {
let cluster = match clusters.0.get(chosen_cluster) {
Some(c) => c,
None => eyre::bail!("no cluster found for: {}", chosen_cluster),
};
let options = CuddleReleaserOptions {
cluster: chosen_cluster.clone(),
namespace: cluster.namespace.clone(),
app: self.cuddle_file.vars.service.clone(),
upstream: self
.cuddle_file
.deployment
.as_ref()
.unwrap()
.registry
.clone(),
};
let cuddle_releaser_image = "docker.io/kasperhermansen/cuddle-releaser:main-1706726858";
let folder = client.host().directory(&self.folder);
let ssh_sock = std::env::var("SSH_AUTH_SOCK").context("SSH_AUTH_SOCK not set")?;
let cuddle_releaser = client
.container()
.from(cuddle_releaser_image)
.with_env_variable("RUST_LOG", "trace")
.with_directory("/mnt/templates", folder)
.with_unix_socket(
ssh_sock.clone(),
client.host().unix_socket(ssh_sock.clone()),
);
let time = chrono::Local::now();
cuddle_releaser
.with_exec(vec!["echo", &time.to_rfc3339()])
.with_exec(vec![
"cuddle-releaser",
"release",
&format!("--upstream={}", options.upstream),
&format!("--folder={}", "/mnt/templates/k8s"),
&format!("--cluster={}", options.cluster),
&format!("--namespace={}", options.namespace),
&format!("--app={}", options.app),
])
.sync()
.await?;
}
Ok(())
}
}
#[async_trait]
impl MainAction for CuddleReleaser {
async fn execute_main(&self, _ctx: &mut cli::Context) -> eyre::Result<()> {
self.releaser(CuddleEnv::Prod).await?;
Ok(())
}
}

View File

@ -0,0 +1,68 @@
pub struct CuddleX {
command: String,
args: Vec<String>,
}
impl CuddleX {
pub fn command(command: impl Into<String>) -> Self {
Self {
command: command.into(),
args: Vec::new(),
}
}
pub fn arg(&mut self, arg: impl Into<String>) -> &mut Self {
self.args.push(arg.into());
self
}
pub async fn run(&mut self) -> eyre::Result<(String, String, i32)> {
let mut cmd = tokio::process::Command::new("cuddle");
let cmd = cmd.arg("x").arg(&self.command).args(&self.args);
let process = cmd.spawn()?;
let output = process.wait_with_output().await?;
Ok((
std::str::from_utf8(&output.stdout)?.to_string(),
std::str::from_utf8(&output.stderr)?.to_string(),
output.status.code().unwrap_or(0),
))
}
}
pub mod well_known {
use super::CuddleX;
pub async fn render(args: impl IntoIterator<Item = impl Into<String>>) -> eyre::Result<()> {
tracing::info!("running render");
let mut cmd = CuddleX::command("render");
for arg in args.into_iter() {
let arg = arg.into();
cmd.arg(arg);
}
let (stdout, stderr, status) = cmd.run().await?;
for line in stdout.lines() {
tracing::trace!("render: {}", line);
}
for line in stderr.lines() {
tracing::trace!("render: {}", line);
}
if status != 0 {
tracing::warn!("finished render with non-zero exit code: {}", status);
}
tracing::info!("finished running render");
Ok(())
}
}

View File

@ -0,0 +1,54 @@
use async_trait::async_trait;
use dagger_sdk::Container;
use std::{future::Future, pin::Pin, sync::Arc};
pub type DynMiddleware = Arc<dyn DaggerMiddleware + Send + Sync>;
#[async_trait]
pub trait DaggerMiddleware {
async fn handle(
&self,
container: dagger_sdk::Container,
) -> eyre::Result<dagger_sdk::Container> {
Ok(container)
}
}
pub struct DaggerMiddlewareFn<F>
where
F: Fn(Container) -> Pin<Box<dyn Future<Output = eyre::Result<Container>> + Send>>,
{
pub func: F,
}
pub fn middleware<F>(func: F) -> Box<DaggerMiddlewareFn<F>>
where
F: Fn(Container) -> Pin<Box<dyn Future<Output = eyre::Result<Container>> + Send>>,
{
Box::new(DaggerMiddlewareFn { func })
}
#[async_trait]
impl<F> DaggerMiddleware for DaggerMiddlewareFn<F>
where
F: Fn(Container) -> Pin<Box<dyn Future<Output = eyre::Result<Container>> + Send>> + Send + Sync,
{
async fn handle(&self, container: Container) -> eyre::Result<Container> {
// Call the closure stored in the struct
(self.func)(container).await
}
}
#[cfg(test)]
mod test {
use futures::FutureExt;
use super::*;
#[tokio::test]
async fn can_add_middleware() -> eyre::Result<()> {
middleware(|c| async move { Ok(c) }.boxed());
Ok(())
}
}

View File

@ -0,0 +1,87 @@
use std::{collections::BTreeMap, path::PathBuf, time::UNIX_EPOCH};
const DRONE_TEMPLATER_IMAGE: &str = "kasperhermansen/drone-templater:main-1711807810";
use async_trait::async_trait;
use eyre::{Context, OptionExt};
use crate::{rust_service::RustServiceContext, MainAction};
#[derive(Clone)]
pub struct DroneTemplater {
client: dagger_sdk::Query,
template: PathBuf,
variables: BTreeMap<String, String>,
}
impl DroneTemplater {
pub fn new(client: dagger_sdk::Query, template: impl Into<PathBuf>) -> Self {
Self {
client,
template: template.into(),
variables: BTreeMap::default(),
}
}
pub fn with_variable(
&mut self,
name: impl Into<String>,
value: impl Into<String>,
) -> &mut Self {
self.variables.insert(name.into(), value.into());
self
}
}
#[async_trait]
impl MainAction for DroneTemplater {
async fn execute_main(&self, ctx: &mut crate::Context) -> eyre::Result<()> {
let image_tag = ctx
.get_image_tag()?
.ok_or_eyre(eyre::eyre!("failed to find image tag"))?;
let src = self.client.host().directory(".cuddle/tmp/");
let drone_host = std::env::var("DRONE_HOST").context("DRONE_HOST is missing")?;
let drone_user = std::env::var("DRONE_USER").context("DRONE_USER is missing")?;
let drone_token = std::env::var("DRONE_TOKEN").context("DRONE_TOKEN is missing")?;
let drone_token_secret = self.client.set_secret("DRONE_TOKEN", drone_token);
let now = std::time::SystemTime::now()
.duration_since(UNIX_EPOCH)
.context("failed to get system time")?;
let template_name = self.template.display().to_string();
let cmd = vec!["drone-templater", "upload", "--template", &template_name]
.into_iter()
.map(|v| v.to_string())
.chain(
self.variables
.iter()
.map(|(name, value)| format!(r#"--variable={name}={value}"#)),
)
.chain(vec![format!("--variable=image_tag={}", image_tag)])
.collect::<Vec<_>>();
self.client
.container()
.from(DRONE_TEMPLATER_IMAGE)
.with_env_variable("RUST_LOG", "drone_templater=trace")
.with_exec(vec!["echo", &format!("{}", now.as_secs())])
.with_directory("/src/templates", src)
.with_workdir("/src")
.with_env_variable("DRONE_HOST", drone_host)
.with_env_variable("DRONE_USER", drone_user)
.with_secret_variable("DRONE_TOKEN", drone_token_secret)
.with_exec(cmd)
.sync()
.await
.context("failed to upload drone templates with error")?;
Ok(())
}
}

View File

@ -0,0 +1,423 @@
use std::{path::PathBuf, sync::Arc};
use async_trait::async_trait;
use dagger_rust::source::RustSource;
use dagger_sdk::Container;
use futures::{stream, StreamExt};
use crate::{
dagger_middleware::DaggerMiddleware,
rust_service::{
architecture::{Architecture, Os},
extensions::CargoBInstallExt,
RustServiceContext, RustServiceStage,
},
Context, MainAction, PullRequestAction,
};
#[derive(Clone)]
pub struct LeptosService {
pub(crate) client: dagger_sdk::Query,
base_image: Option<dagger_sdk::Container>,
final_image: Option<dagger_sdk::Container>,
stages: Vec<RustServiceStage>,
source: Option<PathBuf>,
crates: Vec<String>,
bin_name: String,
arch: Option<Architecture>,
os: Option<Os>,
deploy_target_name: Option<String>,
deploy: bool,
}
impl LeptosService {
pub fn new(client: dagger_sdk::Query, bin_name: impl Into<String>) -> Self {
Self {
client,
base_image: None,
final_image: None,
stages: Vec::new(),
source: None,
crates: Vec::new(),
bin_name: bin_name.into(),
arch: None,
os: None,
deploy_target_name: None,
deploy: true,
}
}
pub fn with_base_image(&mut self, base: dagger_sdk::Container) -> &mut Self {
self.base_image = Some(base);
self
}
pub fn with_stage(&mut self, stage: RustServiceStage) -> &mut Self {
self.stages.push(stage);
self
}
pub fn with_source(&mut self, path: impl Into<PathBuf>) -> &mut Self {
self.source = Some(path.into());
self
}
pub fn with_deploy_target(&mut self, deploy_target: impl Into<String>) -> &mut Self {
self.deploy_target_name = Some(deploy_target.into());
self
}
pub fn with_crates(
&mut self,
crates: impl IntoIterator<Item = impl Into<String>>,
) -> &mut Self {
self.crates = crates.into_iter().map(|c| c.into()).collect();
self
}
pub fn with_arch(&mut self, arch: Architecture) -> &mut Self {
self.arch = Some(arch);
self
}
pub fn with_os(&mut self, os: Os) -> &mut Self {
self.os = Some(os);
self
}
pub fn with_deploy(&mut self, deploy: bool) -> &mut Self {
self.deploy = deploy;
self
}
fn get_src(&self) -> PathBuf {
self.source
.clone()
.unwrap_or(std::env::current_dir().unwrap())
}
pub fn get_arch(&self) -> Architecture {
self.arch
.clone()
.unwrap_or_else(|| match std::env::consts::ARCH {
"x86" | "x86_64" | "amd64" => Architecture::Amd64,
"arm" => Architecture::Arm64,
arch => panic!("unsupported architecture: {arch}"),
})
}
pub fn get_os(&self) -> Os {
self.os
.clone()
.unwrap_or_else(|| match std::env::consts::OS {
"linux" => Os::Linux,
"macos" => Os::MacOS,
os => panic!("unsupported os: {os}"),
})
}
async fn run_stage(
&self,
stages: impl IntoIterator<Item = &Arc<dyn DaggerMiddleware + Send + Sync>>,
container: Container,
) -> eyre::Result<Container> {
let before_deps_stream = stream::iter(stages.into_iter().map(Ok));
let res = StreamExt::fold(before_deps_stream, Ok(container), |base, m| async move {
match (base, m) {
(Ok(base), Ok(m)) => m.handle(base).await,
(_, Err(e)) | (Err(e), _) => eyre::bail!("failed with {e}"),
}
})
.await?;
Ok(res)
}
pub async fn build_base(&self) -> eyre::Result<Container> {
let rust_src = RustSource::new(self.client.clone());
let (src, dep_src) = rust_src
.get_rust_src(Some(&self.get_src()), self.crates.clone())
.await?;
let base_image = self
.base_image
.clone()
.unwrap_or(self.client.container().from("rustlang/rust:nightly"));
let before_deps = self
.stages
.iter()
.filter_map(|s| match s {
RustServiceStage::BeforeDeps(middleware) => Some(middleware),
_ => None,
})
.collect::<Vec<_>>();
let image = self.run_stage(before_deps, base_image).await?;
let image = image.with_exec(vec!["rustup", "target", "add", "wasm32-unknown-unknown"]);
let after_deps = self
.stages
.iter()
.filter_map(|s| match s {
RustServiceStage::AfterDeps(m) => Some(m),
_ => None,
})
.collect::<Vec<_>>();
let image = self.run_stage(after_deps, image).await?;
let before_base = self
.stages
.iter()
.filter_map(|s| match s {
RustServiceStage::BeforeBase(m) => Some(m),
_ => None,
})
.collect::<Vec<_>>();
let image = self.run_stage(before_base, image).await?;
let cache = self.client.cache_volume("rust_target_cache");
let rust_prebuild = image
.with_workdir("/mnt/src")
.with_directory("/mnt/src", dep_src)
.with_exec(vec![
"cargo",
"leptos",
"build",
"--release",
"-vv",
"--project",
&self.bin_name,
])
.with_mounted_cache("/mnt/src/target/", cache);
let incremental_dir = rust_src
.get_rust_target_src(&self.get_src(), rust_prebuild.clone(), self.crates.clone())
.await?;
let rust_with_src = image
.with_workdir("/mnt/src")
.with_directory(
"/usr/local/cargo",
rust_prebuild.directory("/usr/local/cargo"),
)
.with_directory("/mnt/src/target", incremental_dir)
.with_directory("/mnt/src/", src);
let after_base = self
.stages
.iter()
.filter_map(|s| match s {
RustServiceStage::AfterBase(m) => Some(m),
_ => None,
})
.collect::<Vec<_>>();
let image = self.run_stage(after_base, rust_with_src).await?;
Ok(image)
}
pub async fn build_release(&self) -> eyre::Result<Container> {
let base = self.build_base().await?;
let before_build = self
.stages
.iter()
.filter_map(|s| match s {
RustServiceStage::BeforeBuild(m) => Some(m),
_ => None,
})
.collect::<Vec<_>>();
let base = self.run_stage(before_build, base).await?;
let binary_build = base.with_exec(vec![
"cargo",
"leptos",
"build",
"--release",
"--project",
&self.bin_name,
]);
let after_build = self
.stages
.iter()
.filter_map(|s| match s {
RustServiceStage::AfterBuild(m) => Some(m),
_ => None,
})
.collect::<Vec<_>>();
let binary_build = self.run_stage(after_build, binary_build).await?;
let dest = self
.final_image
.clone()
.unwrap_or(self.client.container().from("debian:bookworm"));
let before_package = self
.stages
.iter()
.filter_map(|s| match s {
RustServiceStage::BeforePackage(m) => Some(m),
_ => None,
})
.collect::<Vec<_>>();
let dest = self.run_stage(before_package, dest).await?;
let final_image = dest
.with_workdir("/mnt/app")
.with_file(
format!("/usr/local/bin/{}", self.bin_name),
binary_build.file(format!("/mnt/src/target/release/{}", self.bin_name)),
)
.with_directory(
"/mnt/app/target/site",
binary_build.directory("/mnt/src/target/site"),
)
.with_file(
"/mnt/app/Cargo.toml",
binary_build.file(format!("/mnt/src/crates/{}/Cargo.toml", self.bin_name)),
)
.with_env_variable("APP_ENVIRONMENT", "production")
.with_env_variable("LEPTOS_OUTPUT_NAME", &self.bin_name)
.with_env_variable("LEPTOS_SITE_ADDR", "0.0.0.0:3000")
.with_env_variable("LEPTOS_SITE_PKG_DIR", "pkg")
.with_exposed_port(3000);
let after_package = self
.stages
.iter()
.filter_map(|s| match s {
RustServiceStage::AfterPackage(m) => Some(m),
_ => None,
})
.collect::<Vec<_>>();
let final_image = self.run_stage(after_package, final_image).await?;
Ok(final_image)
}
pub async fn build_test(&self) -> eyre::Result<()> {
let base = self.build_base().await?;
let before_build = self
.stages
.iter()
.filter_map(|s| match s {
RustServiceStage::BeforeBuild(m) => Some(m),
_ => None,
})
.collect::<Vec<_>>();
let base = self.run_stage(before_build, base).await?;
base.with_exec(vec!["cargo", "leptos", "test", "--release"])
.sync()
.await?;
Ok(())
}
fn get_deploy_target(&self) -> String {
self.deploy_target_name
.clone()
.unwrap_or(self.bin_name.clone())
}
}
#[async_trait]
impl PullRequestAction for LeptosService {
async fn execute_pull_request(&self, _ctx: &mut Context) -> eyre::Result<()> {
let mut s = self.clone();
s.with_cargo_binstall("latest", ["cargo-leptos"])
.build_test()
.await?;
Ok(())
}
}
#[async_trait]
impl MainAction for LeptosService {
async fn execute_main(&self, ctx: &mut Context) -> eyre::Result<()> {
let mut s = self.clone();
let container = s
.with_cargo_binstall("latest", ["cargo-leptos"])
.build_release()
.await?;
let timestamp = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs();
let tag = format!(
"docker.io/kasperhermansen/{}:main-{}",
self.bin_name, timestamp,
);
container.publish(tag.clone()).await?;
tracing::info!("published: {}", tag);
ctx.set_image_tag(format!("main-{}", &timestamp.to_string()))?;
if self.deploy {
let update_deployments_docker_image =
"docker.io/kasperhermansen/update-deployment:1701123940";
let dep = self
.client
.container()
.from(update_deployments_docker_image);
let dep = if let Ok(sock) = std::env::var("SSH_AUTH_SOCK") {
dep.with_unix_socket("/tmp/ssh_sock", self.client.host().unix_socket(sock))
.with_env_variable("SSH_AUTH_SOCK", "/tmp/ssh_sock")
.with_exec(vec![
"update-deployment",
"--repo",
&format!(
"git@git.front.kjuulh.io:kjuulh/{}-deployment.git",
self.get_deploy_target()
),
"--service",
&self.bin_name,
"--image",
&format!("kasperhermansen/{}:main-{}", self.bin_name, timestamp),
])
} else {
dep.with_env_variable("GIT_USERNAME", "kjuulh")
.with_env_variable(
"GIT_PASSWORD",
std::env::var("GIT_PASSWORD").expect("GIT_PASSWORD to be set"),
)
.with_exec(vec![
"update-deployment",
"--repo",
&format!(
"https://git.front.kjuulh.io/kjuulh/{}-deployment.git",
self.get_deploy_target()
),
"--service",
&self.bin_name,
"--image",
&format!("kasperhermansen/{}:main-{}", self.bin_name, timestamp),
])
};
dep.sync().await?;
}
Ok(())
}
}

View File

@ -0,0 +1,15 @@
pub mod cli;
pub use cli::*;
pub mod leptos_service;
pub mod node_service;
pub mod rust_lib;
pub mod rust_service;
pub mod cuddle_file;
pub mod cuddle_please;
pub mod cuddle_releaser;
pub mod cuddle_x;
pub mod dagger_middleware;
pub mod drone_templater;
pub mod rust_workspace;

View File

@ -0,0 +1,290 @@
use std::path::PathBuf;
use async_trait::async_trait;
use dagger_sdk::{Container, ContainerWithDirectoryOptsBuilder, HostDirectoryOptsBuilder};
use crate::{
dagger_middleware::DynMiddleware,
rust_service::architecture::{Architecture, Os},
Context, MainAction, PullRequestAction,
};
#[derive(Clone)]
pub enum NodeServiceStage {
BeforeDeps(DynMiddleware),
AfterDeps(DynMiddleware),
BeforeBase(DynMiddleware),
AfterBase(DynMiddleware),
BeforeBuild(DynMiddleware),
AfterBuild(DynMiddleware),
BeforePackage(DynMiddleware),
AfterPackage(DynMiddleware),
BeforeRelease(DynMiddleware),
AfterRelease(DynMiddleware),
}
#[derive(Clone)]
pub struct NodeService {
client: dagger_sdk::Query,
service: String,
base_image: Option<Container>,
final_image: Option<Container>,
stages: Vec<NodeServiceStage>,
source: Option<PathBuf>,
arch: Option<Architecture>,
os: Option<Os>,
}
impl NodeService {
pub fn new(value: dagger_sdk::Query, service: impl Into<String>) -> Self {
Self {
client: value,
service: service.into(),
base_image: None,
final_image: None,
stages: Vec::new(),
source: None,
arch: None,
os: None,
}
}
pub fn with_base_image(&mut self, base: dagger_sdk::Container) -> &mut Self {
self.base_image = Some(base);
self
}
pub fn with_service(&mut self, service: impl Into<String>) -> &mut Self {
self.service = service.into();
self
}
pub fn with_stage(&mut self, stage: NodeServiceStage) -> &mut Self {
self.stages.push(stage);
self
}
pub fn with_source(&mut self, path: impl Into<PathBuf>) -> &mut Self {
self.source = Some(path.into());
self
}
pub fn with_arch(&mut self, arch: Architecture) -> &mut Self {
self.arch = Some(arch);
self
}
pub fn with_os(&mut self, os: Os) -> &mut Self {
self.os = Some(os);
self
}
fn get_src(&self) -> PathBuf {
self.source
.clone()
.unwrap_or(std::env::current_dir().unwrap())
}
fn get_arch(&self) -> Architecture {
self.arch
.clone()
.unwrap_or_else(|| match std::env::consts::ARCH {
"x86" | "x86_64" | "amd64" => Architecture::Amd64,
"arm" => Architecture::Arm64,
arch => panic!("unsupported architecture: {arch}"),
})
}
fn get_os(&self) -> Os {
self.os
.clone()
.unwrap_or_else(|| match std::env::consts::OS {
"linux" => Os::Linux,
"macos" => Os::MacOS,
os => panic!("unsupported os: {os}"),
})
}
pub async fn build_base(&self) -> eyre::Result<Container> {
let src = self.client.host().directory_opts(
self.get_src().to_string_lossy(),
HostDirectoryOptsBuilder::default()
.exclude(vec!["node_modules/", ".git/", ".cuddle/"])
.build()?,
);
let pkg_files = self.client.host().directory_opts(
self.get_src().to_string_lossy(),
HostDirectoryOptsBuilder::default()
.include(vec!["package.json", "yarn.lock"])
.build()?,
);
let deps =
"apk add --no-cache build-base gcc autoconf automake zlib-dev libpng-dev vips-dev git postgresql-dev"
.split_whitespace();
let base_image = match self.base_image.clone() {
Some(image) => image,
None => self
.client
.container()
.from("node:20-alpine")
.with_exec(vec!["apk", "update"])
.with_exec(deps.collect()),
}
.with_env_variable("NODE_ENV", "production");
let base_yarn_image = base_image
.with_workdir("/opt/")
.with_directory(".", pkg_files)
.with_exec(vec!["yarn", "global", "add", "node-gyp"])
.with_exec(vec![
"yarn",
"config",
"set",
"network-timeout",
"600000",
"-g",
])
.with_exec(vec!["yarn", "install", "--production"]);
let base_build = base_yarn_image
.with_env_variable(
"PATH",
format!(
"/opt/node_modules/.bin:{}",
base_yarn_image.env_variable("PATH").await?
),
)
.with_workdir("/opt/app")
.with_directory(".", src)
.with_exec(vec!["yarn", "build"]);
Ok(base_build)
}
pub async fn build_release(&self) -> eyre::Result<Container> {
let base = self.build_base().await?;
let final_build_image = match self.final_image.clone() {
Some(c) => c,
None => self
.client
.container()
.from("node:20-alpine")
.with_exec(vec![
"apk",
"add",
"--no-cache",
"vips-dev",
"postgresql-dev",
]),
}
.with_env_variable("NODE_ENV", "production");
let final_image = final_build_image
.with_workdir("/opt/")
.with_directory("/opt/node_modules", base.directory("/opt/node_modules"))
.with_workdir("/opt/app")
.with_directory_opts(
"/opt/app",
base.directory("/opt/app"),
ContainerWithDirectoryOptsBuilder::default()
.owner("node:node")
.build()?,
)
.with_env_variable(
"PATH",
format!(
"/opt/node_modules/.bin:{}",
final_build_image.env_variable("PATH").await?
),
)
.with_user("node")
.with_exposed_port(1337)
.with_entrypoint(vec!["yarn", "start"]);
Ok(final_image)
}
}
#[async_trait]
impl PullRequestAction for NodeService {
async fn execute_pull_request(&self, _ctx: &mut Context) -> eyre::Result<()> {
let release = self.build_release().await?;
release.sync().await?;
Ok(())
}
}
#[async_trait]
impl MainAction for NodeService {
async fn execute_main(&self, _ctx: &mut Context) -> eyre::Result<()> {
let container = self.build_release().await?;
let timestamp = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs();
container
.publish(format!(
"docker.io/kasperhermansen/{}:main-{}",
self.service, timestamp,
))
.await?;
let update_deployments_docker_image =
"docker.io/kasperhermansen/update-deployment:1701123940";
let dep = self
.client
.container()
.from(update_deployments_docker_image);
let dep = match std::env::var("SSH_AUTH_SOCK").ok() {
Some(sock) => dep
.with_unix_socket("/tmp/ssh_sock", self.client.host().unix_socket(sock))
.with_env_variable("SSH_AUTH_SOCK", "/tmp/ssh_sock")
.with_exec(vec![
"update-deployment",
"--repo",
&format!(
"git@git.front.kjuulh.io:kjuulh/{}-deployment.git",
self.service
),
"--service",
&self.service,
"--image",
&format!("kasperhermansen/{}:main-{}", self.service, timestamp),
]),
_ => dep
.with_env_variable("GIT_USERNAME", "kjuulh")
.with_env_variable(
"GIT_PASSWORD",
std::env::var("GIT_PASSWORD").expect("GIT_PASSWORD to be set"),
)
.with_exec(vec![
"update-deployment",
"--repo",
&format!(
"https://git.front.kjuulh.io/kjuulh/{}-deployment.git",
self.service
),
"--service",
&self.service,
"--image",
&format!("kasperhermansen/{}:main-{}", self.service, timestamp),
]),
};
dep.sync().await?;
Ok(())
}
}

View File

@ -0,0 +1,147 @@
use std::path::PathBuf;
use async_trait::async_trait;
use dagger_rust::source::RustSource;
use dagger_sdk::Container;
use crate::{
cli,
rust_service::architecture::{Architecture, Os},
rust_workspace, MainAction, PullRequestAction,
};
#[derive(Clone)]
pub struct RustLib {
client: dagger_sdk::Query,
base_image: Option<dagger_sdk::Container>,
source: Option<PathBuf>,
crates: Vec<String>,
arch: Option<Architecture>,
os: Option<Os>,
}
impl RustLib {
pub fn new(value: dagger_sdk::Query) -> Self {
Self {
client: value,
source: None,
crates: Vec::new(),
arch: None,
os: None,
base_image: None,
}
}
pub fn with_source(&mut self, path: impl Into<PathBuf>) -> &mut Self {
self.source = Some(path.into());
self
}
pub fn with_base_image(&mut self, base: dagger_sdk::Container) -> &mut Self {
self.base_image = Some(base);
self
}
pub fn with_crates(
&mut self,
crates: impl IntoIterator<Item = impl Into<String>>,
) -> &mut Self {
self.crates = crates.into_iter().map(|c| c.into()).collect();
self
}
pub async fn with_workspace_crates(&mut self) -> &mut Self {
if let Ok(Some(file)) = rust_workspace::File::read_file().await {
if let Some(members) = file.get_workspace_members() {
return self.with_crates(members);
}
}
self
}
pub fn with_arch(&mut self, arch: Architecture) -> &mut Self {
self.arch = Some(arch);
self
}
pub fn with_os(&mut self, os: Os) -> &mut Self {
self.os = Some(os);
self
}
fn get_src(&self) -> PathBuf {
self.source
.clone()
.unwrap_or(std::env::current_dir().unwrap())
}
pub async fn build_base(&self) -> eyre::Result<Container> {
let rust_src = RustSource::new(self.client.clone());
let (src, dep_src) = rust_src
.get_rust_src(Some(&self.get_src()), self.crates.clone())
.await?;
let base_image = self
.base_image
.clone()
.unwrap_or(self.client.container().from("rustlang/rust:nightly"));
let cache = self.client.cache_volume("rust_target_cache");
let rust_prebuild = base_image
.with_workdir("/mnt/src")
.with_directory("/mnt/src", dep_src)
.with_exec(vec!["cargo", "build", "--tests", "--workspace"])
.with_mounted_cache("/mnt/src/target/", cache);
let incremental_dir = rust_src
.get_rust_target_src(&self.get_src(), rust_prebuild.clone(), self.crates.clone())
.await?;
let rust_with_src = base_image
.with_workdir("/mnt/src")
.with_directory(
"/usr/local/cargo",
rust_prebuild.directory("/usr/local/cargo"),
)
.with_directory("/mnt/src/target", incremental_dir)
.with_directory("/mnt/src/", src);
Ok(rust_with_src)
}
pub async fn build_test(&self) -> eyre::Result<()> {
let base = self.build_base().await?;
base.with_exec(vec!["cargo", "test", "--tests", "--workspace"])
.sync()
.await?;
Ok(())
}
}
#[async_trait]
impl PullRequestAction for RustLib {
async fn execute_pull_request(&self, _ctx: &mut cli::Context) -> eyre::Result<()> {
self.build_test().await?;
Ok(())
}
}
#[async_trait]
impl MainAction for RustLib {
async fn execute_main(&self, _ctx: &mut cli::Context) -> eyre::Result<()> {
self.build_test().await?;
Ok(())
}
}

View File

@ -0,0 +1,527 @@
use std::{path::PathBuf, sync::Arc};
use async_trait::async_trait;
use dagger_rust::source::RustSource;
use dagger_sdk::Container;
use futures::{stream, StreamExt};
use crate::{
dagger_middleware::{DaggerMiddleware, DynMiddleware},
Context, MainAction, PullRequestAction,
};
use self::architecture::{Architecture, Os};
#[derive(Clone)]
pub enum RustServiceStage {
BeforeDeps(DynMiddleware),
AfterDeps(DynMiddleware),
BeforeBase(DynMiddleware),
AfterBase(DynMiddleware),
BeforeBuild(DynMiddleware),
AfterBuild(DynMiddleware),
BeforePackage(DynMiddleware),
AfterPackage(DynMiddleware),
BeforeRelease(DynMiddleware),
AfterRelease(DynMiddleware),
}
#[derive(Clone)]
pub struct RustService {
client: dagger_sdk::Query,
base_image: Option<dagger_sdk::Container>,
final_image: Option<dagger_sdk::Container>,
stages: Vec<RustServiceStage>,
source: Option<PathBuf>,
crates: Vec<String>,
bin_name: String,
arch: Option<Architecture>,
os: Option<Os>,
deployment: bool,
}
impl From<dagger_sdk::Query> for RustService {
fn from(value: dagger_sdk::Query) -> Self {
Self {
client: value,
base_image: None,
final_image: None,
stages: Vec::new(),
source: None,
crates: Vec::new(),
bin_name: String::new(),
arch: None,
os: None,
deployment: true,
}
}
}
impl RustService {
pub async fn new(client: dagger_sdk::Query) -> eyre::Result<Self> {
Ok(Self {
client,
base_image: None,
final_image: None,
stages: Vec::new(),
source: None,
crates: Vec::new(),
bin_name: String::new(),
arch: None,
os: None,
deployment: true,
})
}
pub fn with_base_image(&mut self, base: dagger_sdk::Container) -> &mut Self {
self.base_image = Some(base);
self
}
pub fn with_stage(&mut self, stage: RustServiceStage) -> &mut Self {
self.stages.push(stage);
self
}
pub fn with_source(&mut self, path: impl Into<PathBuf>) -> &mut Self {
self.source = Some(path.into());
self
}
pub fn with_bin_name(&mut self, bin_name: impl Into<String>) -> &mut Self {
self.bin_name = bin_name.into();
self
}
pub fn with_crates(
&mut self,
crates: impl IntoIterator<Item = impl Into<String>>,
) -> &mut Self {
self.crates = crates.into_iter().map(|c| c.into()).collect();
self
}
pub fn with_arch(&mut self, arch: Architecture) -> &mut Self {
self.arch = Some(arch);
self
}
pub fn with_os(&mut self, os: Os) -> &mut Self {
self.os = Some(os);
self
}
pub fn with_deployment(&mut self, deployment: bool) -> &mut Self {
self.deployment = deployment;
self
}
fn get_src(&self) -> PathBuf {
self.source
.clone()
.unwrap_or(std::env::current_dir().unwrap())
}
fn get_arch(&self) -> Architecture {
self.arch
.clone()
.unwrap_or_else(|| match std::env::consts::ARCH {
"x86" | "x86_64" | "amd64" => Architecture::Amd64,
"arm" => Architecture::Arm64,
arch => panic!("unsupported architecture: {arch}"),
})
}
fn get_os(&self) -> Os {
self.os
.clone()
.unwrap_or_else(|| match std::env::consts::OS {
"linux" => Os::Linux,
"macos" => Os::MacOS,
os => panic!("unsupported os: {os}"),
})
}
async fn run_stage(
&self,
stages: impl IntoIterator<Item = &Arc<dyn DaggerMiddleware + Send + Sync>>,
container: Container,
) -> eyre::Result<Container> {
let before_deps_stream = stream::iter(stages.into_iter().map(Ok));
let res = StreamExt::fold(before_deps_stream, Ok(container), |base, m| async move {
match (base, m) {
(Ok(base), Ok(m)) => m.handle(base).await,
(_, Err(e)) | (Err(e), _) => eyre::bail!("failed with {e}"),
}
})
.await?;
Ok(res)
}
pub async fn build_base(&self) -> eyre::Result<Container> {
let client = self.client.clone();
let rust_src = RustSource::new(client.clone());
let (src, dep_src) = rust_src
.get_rust_src(Some(&self.get_src()), self.crates.clone())
.await?;
let base_image = self
.base_image
.clone()
.unwrap_or(client.container().from("rustlang/rust:nightly"));
let before_deps = self
.stages
.iter()
.filter_map(|s| match s {
RustServiceStage::BeforeDeps(middleware) => Some(middleware),
_ => None,
})
.collect::<Vec<_>>();
let image = self.run_stage(before_deps, base_image).await?;
let after_deps = self
.stages
.iter()
.filter_map(|s| match s {
RustServiceStage::AfterDeps(m) => Some(m),
_ => None,
})
.collect::<Vec<_>>();
let image = self.run_stage(after_deps, image).await?;
let before_base = self
.stages
.iter()
.filter_map(|s| match s {
RustServiceStage::BeforeBase(m) => Some(m),
_ => None,
})
.collect::<Vec<_>>();
let image = self.run_stage(before_base, image).await?;
let cache = client.cache_volume("rust_target_cache");
let rust_prebuild = image
.with_workdir("/mnt/src")
.with_directory("/mnt/src", dep_src)
.with_exec(vec!["cargo", "build", "--release", "--bin", &self.bin_name])
.with_mounted_cache("/mnt/src/target/", cache);
let incremental_dir = rust_src
.get_rust_target_src(&self.get_src(), rust_prebuild.clone(), self.crates.clone())
.await?;
let rust_with_src = image
.with_workdir("/mnt/src")
.with_directory(
"/usr/local/cargo",
rust_prebuild.directory("/usr/local/cargo"),
)
.with_directory("/mnt/src/target", incremental_dir)
.with_directory("/mnt/src/", src);
let after_base = self
.stages
.iter()
.filter_map(|s| match s {
RustServiceStage::AfterBase(m) => Some(m),
_ => None,
})
.collect::<Vec<_>>();
let image = self.run_stage(after_base, rust_with_src).await?;
Ok(image)
}
pub async fn build_release(&self) -> eyre::Result<Container> {
let base = self.build_base().await?;
let client = self.client.clone();
let before_build = self
.stages
.iter()
.filter_map(|s| match s {
RustServiceStage::BeforeBuild(m) => Some(m),
_ => None,
})
.collect::<Vec<_>>();
let base = self.run_stage(before_build, base).await?;
let binary_build =
base.with_exec(vec!["cargo", "build", "--release", "--bin", &self.bin_name]);
let after_build = self
.stages
.iter()
.filter_map(|s| match s {
RustServiceStage::AfterBuild(m) => Some(m),
_ => None,
})
.collect::<Vec<_>>();
let binary_build = self.run_stage(after_build, binary_build).await?;
let dest = self
.final_image
.clone()
.unwrap_or(client.container().from("debian:bookworm"));
let before_package = self
.stages
.iter()
.filter_map(|s| match s {
RustServiceStage::BeforePackage(m) => Some(m),
_ => None,
})
.collect::<Vec<_>>();
let dest = self.run_stage(before_package, dest).await?;
let final_image = dest.with_workdir("/mnt/app").with_file(
format!("/usr/local/bin/{}", self.bin_name),
binary_build.file(format!("/mnt/src/target/release/{}", self.bin_name)),
);
let after_package = self
.stages
.iter()
.filter_map(|s| match s {
RustServiceStage::AfterPackage(m) => Some(m),
_ => None,
})
.collect::<Vec<_>>();
let final_image = self.run_stage(after_package, final_image).await?;
Ok(final_image)
}
pub async fn build_test(&self) -> eyre::Result<()> {
let base = self.build_base().await?;
let before_build = self
.stages
.iter()
.filter_map(|s| match s {
RustServiceStage::BeforeBuild(m) => Some(m),
_ => None,
})
.collect::<Vec<_>>();
let base = self.run_stage(before_build, base).await?;
base.with_exec(vec!["cargo", "test", "--release"])
.sync()
.await?;
Ok(())
}
}
#[async_trait]
impl PullRequestAction for RustService {
async fn execute_pull_request(&self, ctx: &mut Context) -> eyre::Result<()> {
self.build_test().await?;
let container = self.build_release().await?;
let timestamp = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs();
let tag = format!(
"docker.io/kasperhermansen/{}:dev-{}",
self.bin_name, timestamp,
);
container.publish(&tag).await?;
ctx.set_image_tag(format!("dev-{}", &timestamp.to_string()))?;
Ok(())
}
}
const IMAGE_TAG: &str = "RUST_SERVICE_IMAGE_TAG";
pub trait RustServiceContext {
fn set_image_tag(&mut self, tag: impl Into<String>) -> eyre::Result<()>;
fn get_image_tag(&self) -> eyre::Result<Option<String>>;
}
impl RustServiceContext for Context {
fn get_image_tag(&self) -> eyre::Result<Option<String>> {
Ok(self.get(IMAGE_TAG).cloned())
}
fn set_image_tag(&mut self, tag: impl Into<String>) -> eyre::Result<()> {
let tag = tag.into();
self.insert(IMAGE_TAG.to_string(), tag);
Ok(())
}
}
#[async_trait]
impl MainAction for RustService {
async fn execute_main(&self, ctx: &mut Context) -> eyre::Result<()> {
let container = self.build_release().await?;
let timestamp = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs();
let tag = format!(
"docker.io/kasperhermansen/{}:main-{}",
self.bin_name, timestamp,
);
container.publish(&tag).await?;
ctx.set_image_tag(format!("main-{}", &timestamp.to_string()))?;
if self.deployment {
let update_deployments_docker_image =
"docker.io/kasperhermansen/update-deployment:1701123940";
let dep = self
.client
.container()
.from(update_deployments_docker_image);
let dep = if let Ok(sock) = std::env::var("SSH_AUTH_SOCK") {
dep.with_unix_socket("/tmp/ssh_sock", self.client.host().unix_socket(sock))
.with_env_variable("SSH_AUTH_SOCK", "/tmp/ssh_sock")
.with_exec(vec![
"update-deployment",
"--repo",
&format!(
"git@git.front.kjuulh.io:kjuulh/{}-deployment.git",
self.bin_name
),
"--service",
&self.bin_name,
"--image",
&format!("kasperhermansen/{}:main-{}", self.bin_name, timestamp),
])
} else {
dep.with_env_variable("GIT_USERNAME", "kjuulh")
.with_env_variable(
"GIT_PASSWORD",
std::env::var("GIT_PASSWORD").expect("GIT_PASSWORD to be set"),
)
.with_exec(vec![
"update-deployment",
"--repo",
&format!(
"https://git.front.kjuulh.io/kjuulh/{}-deployment.git",
self.bin_name
),
"--service",
&self.bin_name,
"--image",
&format!("kasperhermansen/{}:main-{}", self.bin_name, timestamp),
])
};
dep.sync().await?;
}
Ok(())
}
}
pub mod architecture {
#[derive(Debug, Clone)]
pub enum Architecture {
Amd64,
Arm64,
}
#[derive(Debug, Clone)]
pub enum Os {
Linux,
MacOS,
}
}
mod apt;
mod apt_ca_certificates;
mod assets;
mod cargo_binstall;
mod cargo_clean;
mod clap_sanity_test;
mod cuddle_cli;
mod cuddle_file;
mod dagger_bin;
mod docker_cache;
mod docker_cli;
mod kubectl;
mod mold;
mod rust_workspace;
mod sqlx;
mod ssh_agent;
pub mod extensions {
pub use super::apt::*;
pub use super::apt_ca_certificates::*;
pub use super::assets::*;
pub use super::cargo_binstall::*;
pub use super::cargo_clean::*;
pub use super::clap_sanity_test::*;
pub use super::cuddle_cli::*;
pub use super::cuddle_file::*;
pub use super::dagger_bin::*;
pub use super::docker_cache::*;
pub use super::docker_cli::*;
pub use super::kubectl::*;
pub use super::mold::*;
pub use super::rust_workspace::*;
pub use super::sqlx::*;
pub use super::ssh_agent::*;
}
#[cfg(test)]
mod test {
#[tokio::test]
#[cfg(any(feature = "dagger", feature = "integration"))]
async fn test_can_build_rust() -> eyre::Result<()> {
dagger_sdk::connect(|client| async move {
let root_dir = std::path::PathBuf::from("../../").canonicalize()?;
let container = RustService::from(client.clone())
.with_arch(Architecture::Amd64)
.with_os(Os::Linux)
.with_source(root_dir)
.with_bin_name("ci")
.with_crates(["crates/*", "examples/*", "ci"])
.with_apt(&["git"])
.with_cargo_binstall("latest", ["sqlx-cli"])
.with_mold("2.3.3")
// .with_stage(RustServiceStage::BeforeDeps(middleware(|c| {
// async move {
// // Noop
// Ok(c)
// }
// .boxed()
// })))
.with_clap_sanity_test()
.build_release()
.await?;
container.sync().await?;
Ok(())
})
.await?;
Ok(())
}
}

View File

@ -0,0 +1,86 @@
use std::sync::Arc;
use async_trait::async_trait;
use dagger_sdk::Container;
use crate::{dagger_middleware::DaggerMiddleware, leptos_service::LeptosService};
use super::RustService;
pub struct Apt {
deps: Vec<String>,
}
impl Default for Apt {
fn default() -> Self {
Self::new()
}
}
impl Apt {
pub fn new() -> Self {
Self { deps: Vec::new() }
}
pub fn add(mut self, dep_name: impl Into<String>) -> Self {
self.deps.push(dep_name.into());
self
}
pub fn extend(mut self, deps: &[&str]) -> Self {
self.deps.extend(deps.iter().map(|s| s.to_string()));
self
}
}
#[async_trait]
impl DaggerMiddleware for Apt {
async fn handle(&self, container: Container) -> eyre::Result<Container> {
let mut deps = vec!["apt", "install", "-y"];
deps.extend(self.deps.iter().map(|s| s.as_str()));
let c = container.with_exec(vec!["apt", "update"]).with_exec(deps);
Ok(c)
}
}
pub trait AptExt {
fn with_apt(&mut self, deps: &[&str]) -> &mut Self {
self
}
fn with_apt_release(&mut self, deps: &[&str]) -> &mut Self {
self
}
}
impl AptExt for RustService {
fn with_apt(&mut self, deps: &[&str]) -> &mut Self {
self.with_stage(super::RustServiceStage::BeforeDeps(Arc::new(
Apt::new().extend(deps),
)))
}
fn with_apt_release(&mut self, deps: &[&str]) -> &mut Self {
self.with_stage(super::RustServiceStage::BeforePackage(Arc::new(
Apt::new().extend(deps),
)))
}
}
impl AptExt for LeptosService {
fn with_apt(&mut self, deps: &[&str]) -> &mut Self {
self.with_stage(super::RustServiceStage::BeforeDeps(Arc::new(
Apt::new().extend(deps),
)))
}
fn with_apt_release(&mut self, deps: &[&str]) -> &mut Self {
self.with_stage(super::RustServiceStage::BeforePackage(Arc::new(
Apt::new().extend(deps),
)))
}
}

View File

@ -0,0 +1,62 @@
use std::sync::Arc;
use async_trait::async_trait;
use dagger_sdk::Container;
use crate::{dagger_middleware::DaggerMiddleware, leptos_service::LeptosService};
use super::RustService;
pub struct AptCaCertificates {}
impl Default for AptCaCertificates {
fn default() -> Self {
Self::new()
}
}
impl AptCaCertificates {
pub fn new() -> Self {
Self {}
}
}
#[async_trait]
impl DaggerMiddleware for AptCaCertificates {
async fn handle(&self, container: Container) -> eyre::Result<Container> {
let c = container
.with_exec(vec!["apt", "update"])
.with_exec(vec!["apt", "install", "-y", "ca-certificates"])
.with_exec(vec!["update-ca-certificates"]);
Ok(c)
}
}
pub trait AptCaCertificatesExt {
fn with_apt_ca_certificates(&mut self) -> &mut Self {
self
}
}
impl AptCaCertificatesExt for RustService {
fn with_apt_ca_certificates(&mut self) -> &mut Self {
self.with_stage(super::RustServiceStage::BeforeDeps(Arc::new(
AptCaCertificates::new(),
)))
.with_stage(super::RustServiceStage::BeforePackage(Arc::new(
AptCaCertificates::new(),
)))
}
}
impl AptCaCertificatesExt for LeptosService {
fn with_apt_ca_certificates(&mut self) -> &mut Self {
self.with_stage(super::RustServiceStage::BeforeDeps(Arc::new(
AptCaCertificates::new(),
)))
.with_stage(super::RustServiceStage::BeforePackage(Arc::new(
AptCaCertificates::new(),
)))
}
}

View File

@ -0,0 +1,68 @@
use std::{path::PathBuf, sync::Arc};
use async_trait::async_trait;
use dagger_sdk::Container;
use crate::{dagger_middleware::DaggerMiddleware, leptos_service::LeptosService};
use super::RustService;
pub struct Assets {
client: dagger_sdk::Query,
assets: Vec<(PathBuf, PathBuf)>,
}
impl Assets {
pub fn new(client: dagger_sdk::Query) -> Self {
Self {
client,
assets: Vec::default(),
}
}
fn with_folders(mut self, folders: impl IntoIterator<Item = (PathBuf, PathBuf)>) -> Self {
let mut folders = folders.into_iter().collect::<Vec<(PathBuf, PathBuf)>>();
self.assets.append(&mut folders);
self
}
}
#[async_trait]
impl DaggerMiddleware for Assets {
async fn handle(&self, container: Container) -> eyre::Result<Container> {
let container =
self.assets
.iter()
.fold(container, |container, (src_asset_path, dest_asset_path)| {
let src_path = src_asset_path.display().to_string();
let dest_path = dest_asset_path.display().to_string();
let path = self.client.host().directory(src_path);
container.with_directory(dest_path, path)
});
Ok(container)
}
}
pub trait AssetsExt {
fn with_assets(&mut self, folders: impl IntoIterator<Item = (PathBuf, PathBuf)>) -> &mut Self {
self
}
}
impl AssetsExt for RustService {
fn with_assets(&mut self, folders: impl IntoIterator<Item = (PathBuf, PathBuf)>) -> &mut Self {
self.with_stage(super::RustServiceStage::AfterPackage(Arc::new(
Assets::new(self.client.clone()).with_folders(folders),
)))
}
}
impl AssetsExt for LeptosService {
fn with_assets(&mut self, folders: impl IntoIterator<Item = (PathBuf, PathBuf)>) -> &mut Self {
self.with_stage(super::RustServiceStage::AfterPackage(Arc::new(
Assets::new(self.client.clone()).with_folders(folders),
)))
}
}

View File

@ -0,0 +1,120 @@
use std::sync::Arc;
use async_trait::async_trait;
use dagger_sdk::Container;
use crate::{dagger_middleware::DaggerMiddleware, leptos_service::LeptosService};
use super::{
architecture::{Architecture, Os},
RustService,
};
pub struct CargoBInstall {
arch: Architecture,
os: Os,
version: String,
crates: Vec<String>,
}
impl CargoBInstall {
pub fn new(
arch: Architecture,
os: Os,
version: impl Into<String>,
crates: impl Into<Vec<String>>,
) -> Self {
Self {
arch,
os,
version: version.into(),
crates: crates.into(),
}
}
fn get_arch(&self) -> String {
match self.arch {
Architecture::Amd64 => "x86_64",
Architecture::Arm64 => "armv7",
}
.into()
}
fn get_os(&self) -> String {
match self.os {
Os::Linux => "linux",
Os::MacOS => "darwin",
}
.into()
}
pub fn get_download_url(&self) -> String {
format!("https://github.com/cargo-bins/cargo-binstall/releases/{}/download/cargo-binstall-{}-unknown-{}-musl.tgz", self.version, self.get_arch(), self.get_os())
}
pub fn get_archive(&self) -> String {
format!(
"cargo-binstall-{}-unknown-{}-musl.tgz",
self.get_arch(),
self.get_os()
)
}
}
#[async_trait]
impl DaggerMiddleware for CargoBInstall {
async fn handle(&self, container: Container) -> eyre::Result<Container> {
let c = container
.with_exec(vec!["wget", &self.get_download_url()])
.with_exec(vec!["tar", "-xvf", &self.get_archive()])
.with_exec(
"mv cargo-binstall /usr/local/cargo/bin"
.split_whitespace()
.collect(),
);
let c = self.crates.iter().cloned().fold(c, |acc, item| {
acc.with_exec(vec!["cargo", "binstall", &item, "-y"])
});
Ok(c)
}
}
pub trait CargoBInstallExt {
fn with_cargo_binstall(
&mut self,
version: impl Into<String>,
crates: impl IntoIterator<Item = impl Into<String>>,
) -> &mut Self {
self
}
}
impl CargoBInstallExt for RustService {
fn with_cargo_binstall(
&mut self,
version: impl Into<String>,
crates: impl IntoIterator<Item = impl Into<String>>,
) -> &mut Self {
let crates: Vec<String> = crates.into_iter().map(|s| s.into()).collect();
self.with_stage(super::RustServiceStage::BeforeDeps(Arc::new(
CargoBInstall::new(self.get_arch(), self.get_os(), version, crates),
)))
}
}
impl CargoBInstallExt for LeptosService {
fn with_cargo_binstall(
&mut self,
version: impl Into<String>,
crates: impl IntoIterator<Item = impl Into<String>>,
) -> &mut Self {
let crates: Vec<String> = crates.into_iter().map(|s| s.into()).collect();
self.with_stage(super::RustServiceStage::BeforeDeps(Arc::new(
CargoBInstall::new(self.get_arch(), self.get_os(), version, crates),
)))
}
}

View File

@ -0,0 +1,45 @@
use std::sync::Arc;
use async_trait::async_trait;
use dagger_sdk::Container;
use crate::dagger_middleware::DaggerMiddleware;
use super::RustService;
pub struct CargoClean;
impl Default for CargoClean {
fn default() -> Self {
Self::new()
}
}
impl CargoClean {
pub fn new() -> Self {
Self {}
}
}
#[async_trait]
impl DaggerMiddleware for CargoClean {
async fn handle(&self, container: Container) -> eyre::Result<Container> {
Ok(container.with_exec(vec!["cargo", "clean"]))
}
}
pub trait CargoCleanExt {
fn with_cargo_clean(&mut self) -> &mut Self {
self
}
}
impl CargoCleanExt for RustService {
fn with_cargo_clean(&mut self) -> &mut Self {
self.with_stage(super::RustServiceStage::BeforeBuild(Arc::new(
CargoClean::new(),
)));
self
}
}

View File

@ -0,0 +1,43 @@
use std::sync::Arc;
use async_trait::async_trait;
use dagger_sdk::Container;
use crate::dagger_middleware::DaggerMiddleware;
use super::RustService;
pub struct ClapSanityTest {
bin_name: String,
}
impl ClapSanityTest {
pub fn new(bin_name: impl Into<String>) -> Self {
Self {
bin_name: bin_name.into(),
}
}
}
#[async_trait]
impl DaggerMiddleware for ClapSanityTest {
async fn handle(&self, container: Container) -> eyre::Result<Container> {
Ok(container.with_exec(vec![&self.bin_name, "--help"]))
}
}
pub trait ClapSanityTestExt {
fn with_clap_sanity_test(&mut self) -> &mut Self {
self
}
}
impl ClapSanityTestExt for RustService {
fn with_clap_sanity_test(&mut self) -> &mut Self {
self.with_stage(super::RustServiceStage::AfterPackage(Arc::new(
ClapSanityTest::new(&self.bin_name),
)));
self
}
}

View File

@ -0,0 +1,49 @@
use std::sync::Arc;
use async_trait::async_trait;
use dagger_sdk::Container;
use crate::dagger_middleware::DaggerMiddleware;
use super::RustService;
pub struct CuddleCli {
client: dagger_sdk::Query,
}
impl CuddleCli {
pub fn new(client: dagger_sdk::Query) -> Self {
Self { client }
}
}
#[async_trait]
impl DaggerMiddleware for CuddleCli {
async fn handle(&self, container: Container) -> eyre::Result<Container> {
let cuddle = self
.client
.container()
.from("kasperhermansen/cuddle:latest");
Ok(container.with_file(
"/usr/local/bin/cuddle",
cuddle.file("/usr/local/cargo/bin/cuddle"),
))
}
}
pub trait CuddleCliExt {
fn with_cuddle_cli(&mut self) -> &mut Self {
self
}
}
impl CuddleCliExt for RustService {
fn with_cuddle_cli(&mut self) -> &mut Self {
self.with_stage(super::RustServiceStage::BeforePackage(Arc::new(
CuddleCli::new(self.client.clone()),
)));
self
}
}

View File

@ -0,0 +1,86 @@
use std::path::PathBuf;
use crate::{
cuddle_file::{CuddleDatabase, CuddleFile},
rust_service::extensions::AptExt,
};
use super::{
extensions::{AssetsExt, CargoCleanExt, SqlxExt},
RustService,
};
#[derive(Default)]
pub struct CuddleFileAction {}
impl CuddleFileAction {
pub fn new() -> Self {
Self {}
}
}
pub trait CuddleFileExt {
fn with_cuddle_file(&mut self, cuddle_file: &CuddleFile) -> &mut Self;
}
impl CuddleFileExt for RustService {
fn with_cuddle_file(&mut self, cuddle_file: &CuddleFile) -> &mut Self {
let mut s = self
.with_bin_name(&cuddle_file.vars.service)
.with_deployment(false);
tracing::trace!("with cuddle file: {:+?}", &cuddle_file);
if let Some(components) = &cuddle_file.components {
s = if let Some(database) = &components.database {
match database {
CuddleDatabase::Enabled(true) => s.with_sqlx_migrations(
PathBuf::from("crates")
.join(&cuddle_file.vars.service)
.join("migrations/crdb"),
),
CuddleDatabase::Values { migrations } => s.with_sqlx_migrations(migrations),
CuddleDatabase::Enabled(false) | CuddleDatabase::Default {} => s,
}
} else {
s
};
if let Some(assets) = &components.assets {
if let Some(true) = assets.clean {
s = s.with_cargo_clean()
}
if let Some(volumes) = &assets.volumes {
let mappings = volumes.iter().cloned().map(|val| (val.from, val.to));
s = s.with_assets(mappings);
}
}
if let Some(packages) = &components.packages {
s = s
.with_apt(
packages
.debian
.dev
.iter()
.map(|r| r.as_str())
.collect::<Vec<_>>()
.as_slice(),
)
.with_apt_release(
packages
.debian
.release
.iter()
.map(|r| r.as_str())
.collect::<Vec<_>>()
.as_slice(),
);
}
}
s
}
}

View File

@ -0,0 +1,72 @@
use std::sync::Arc;
use async_trait::async_trait;
use dagger_sdk::Container;
use crate::dagger_middleware::DaggerMiddleware;
use super::RustService;
pub struct DaggerBin {
client: dagger_sdk::Query,
version: String,
}
impl DaggerBin {
pub fn new(client: dagger_sdk::Query, version: impl Into<String>) -> Self {
Self {
client,
version: version.into(),
}
}
}
#[async_trait]
impl DaggerMiddleware for DaggerBin {
async fn handle(&self, container: Container) -> eyre::Result<Container> {
let install_script = self.client.http("https://dl.dagger.io/dagger/install.sh");
let dagger_bin = self
.client
.container()
.from("alpine")
.with_file_opts(
"/mnt/install.sh",
install_script,
dagger_sdk::ContainerWithFileOpts {
owner: None,
permissions: Some(0o755),
expand: None,
},
)
.with_env_variable("DAGGER_VERSION", &self.version)
.with_exec(vec!["/mnt/install.sh"])
.file("/bin/dagger");
Ok(container
.with_file_opts(
"/usr/local/bin/dagger",
dagger_bin,
dagger_sdk::ContainerWithFileOpts {
owner: None,
permissions: Some(0o755),
expand: None,
},
)
.with_exec(vec!["/usr/local/bin/dagger", "version"]))
}
}
pub trait DaggerBinExt {
fn with_dagger_bin(&mut self, dagger_version: impl Into<String>) -> &mut Self;
}
impl DaggerBinExt for RustService {
fn with_dagger_bin(&mut self, dagger_version: impl Into<String>) -> &mut Self {
self.with_stage(super::RustServiceStage::AfterPackage(Arc::new(
DaggerBin::new(self.client.clone(), dagger_version.into()),
)));
self
}
}

View File

@ -0,0 +1,70 @@
use std::sync::Arc;
use async_trait::async_trait;
use dagger_sdk::{Container, ImageMediaTypes};
use crate::dagger_middleware::DaggerMiddleware;
use super::RustService;
pub struct DockerCache {
client: dagger_sdk::Query,
image_name: String,
}
impl DockerCache {
pub fn new(client: dagger_sdk::Query, image_name: impl Into<String>) -> Self {
Self {
client,
image_name: image_name.into(),
}
}
}
#[async_trait]
impl DaggerMiddleware for DockerCache {
async fn handle(&self, container: Container) -> eyre::Result<Container> {
match (
std::env::var("REGISTRY_CACHE_USERNAME"),
std::env::var("REGISTRY_CACHE_PASSWORD"),
) {
(Ok(username), Ok(password)) => {
let url = format!("harbor.front.kjuulh.io/cache/{}:cache", self.image_name);
let secret = self.client.set_secret("REGISTRY_CACHE_PASSWORD", password);
container
.with_registry_auth(&url, &username, secret)
.publish_opts(
&url,
dagger_sdk::ContainerPublishOpts {
forced_compression: Some(dagger_sdk::ImageLayerCompression::Zstd),
media_types: Some(ImageMediaTypes::OciMediaTypes),
platform_variants: None,
},
)
.await?;
}
_ => {
eprintln!("failed to find REGISTRY_CACHE_USERNAME or REGISTRY_CACHE_PASSWORD");
}
}
Ok(container)
}
}
pub trait DockerCacheExt {
fn with_docker_cache(&mut self) -> &mut Self {
self
}
}
impl DockerCacheExt for RustService {
fn with_docker_cache(&mut self) -> &mut Self {
self.with_stage(super::RustServiceStage::AfterPackage(Arc::new(
DockerCache::new(self.client.clone(), self.bin_name.clone()),
)));
self
}
}

View File

@ -0,0 +1,48 @@
use std::sync::Arc;
use async_trait::async_trait;
use dagger_sdk::{Container};
use crate::dagger_middleware::DaggerMiddleware;
use super::RustService;
pub struct DockerCli {
client: dagger_sdk::Query,
}
impl DockerCli {
pub fn new(client: dagger_sdk::Query) -> Self {
Self { client }
}
}
#[async_trait]
impl DaggerMiddleware for DockerCli {
async fn handle(&self, container: Container) -> eyre::Result<Container> {
let docker = self.client.container().from("docker:cli");
Ok(container
.with_file(
"/usr/local/bin/docker",
docker.file("/usr/local/bin/docker"),
)
.with_directory("/certs", docker.directory("/certs")))
}
}
pub trait DockerCliExt {
fn with_docker_cli(&mut self) -> &mut Self {
self
}
}
impl DockerCliExt for RustService {
fn with_docker_cli(&mut self) -> &mut Self {
self.with_stage(super::RustServiceStage::BeforePackage(Arc::new(
DockerCli::new(self.client.clone()),
)));
self
}
}

View File

@ -0,0 +1,75 @@
use std::sync::Arc;
use async_trait::async_trait;
use dagger_sdk::Container;
use crate::dagger_middleware::DaggerMiddleware;
use super::RustService;
pub struct Kubectl {
client: dagger_sdk::Query,
}
impl Kubectl {
pub fn new(client: dagger_sdk::Query) -> Self {
Self { client }
}
}
const KUBESLICEDOWNLOAD: &str = r#"slice_VERSION=v1.2.7 && \
wget -O kubectl-slice_linux_x86_64.tar.gz "https://github.com/patrickdappollonio/kubectl-slice/releases/download/$slice_VERSION/kubectl-slice_linux_x86_64.tar.gz" && \
tar -xf kubectl-slice_linux_x86_64.tar.gz && \
chmod +x ./kubectl-slice && \
mv ./kubectl-slice /usr/local/bin/kubectl-slice && \
rm kubectl-slice_linux_x86_64.tar.gz"#;
#[async_trait]
impl DaggerMiddleware for Kubectl {
async fn handle(&self, container: Container) -> eyre::Result<Container> {
let kubectl = self
.client
.container()
.from("line/kubectl-kustomize:1.29.1-5.3.0");
let kubeslice = self
.client
.container()
.from("alpine:3.19")
.with_exec(vec!["apk", "add", "tar", "wget"])
.with_exec(vec!["sh", "-c", KUBESLICEDOWNLOAD]);
let helm = self.client.container().from("alpine/helm:3.11.1");
Ok(container
.with_file(
"/usr/local/bin/kubectl",
kubectl.file("/usr/local/bin/kubectl"),
)
.with_file(
"/usr/local/bin/kustomize",
kubectl.file("/usr/local/bin/kustomize"),
)
.with_file(
"/usr/local/bin/kubectl-slice",
kubeslice.file("/usr/local/bin/kubectl-slice"),
)
.with_file("/usr/local/bin/helm", helm.file("/usr/bin/helm")))
}
}
pub trait KubectlExt {
fn with_kubectl(&mut self) -> &mut Self {
self
}
}
impl KubectlExt for RustService {
fn with_kubectl(&mut self) -> &mut Self {
self.with_stage(super::RustServiceStage::BeforePackage(Arc::new(
Kubectl::new(self.client.clone()),
)));
self
}
}

View File

@ -0,0 +1,104 @@
use std::sync::Arc;
use async_trait::async_trait;
use crate::dagger_middleware::DaggerMiddleware;
use super::{
architecture::{Architecture, Os},
RustService,
};
pub struct MoldInstall {
arch: Architecture,
os: Os,
version: String,
}
impl MoldInstall {
pub fn new(arch: Architecture, os: Os, version: impl Into<String>) -> Self {
Self {
arch,
os,
version: version.into(),
}
}
fn get_arch(&self) -> String {
match self.arch {
Architecture::Amd64 => "x86_64",
Architecture::Arm64 => "arm",
}
.into()
}
fn get_os(&self) -> String {
match &self.os {
Os::Linux => "linux",
o => todo!("os not implemented for mold: {:?}", o),
}
.into()
}
pub fn get_download_url(&self) -> String {
format!(
"https://github.com/rui314/mold/releases/download/v{}/mold-{}-{}-{}.tar.gz",
self.version,
self.version,
self.get_arch(),
self.get_os()
)
}
pub fn get_folder(&self) -> String {
format!(
"mold-{}-{}-{}",
self.version,
self.get_arch(),
self.get_os()
)
}
pub fn get_archive_name(&self) -> String {
format!(
"mold-{}-{}-{}.tar.gz",
self.version,
self.get_arch(),
self.get_os()
)
}
}
#[async_trait]
impl DaggerMiddleware for MoldInstall {
async fn handle(
&self,
container: dagger_sdk::Container,
) -> eyre::Result<dagger_sdk::Container> {
println!("installing mold");
let c = container
.with_exec(vec!["wget", &self.get_download_url()])
.with_exec(vec!["tar", "-xvf", &self.get_archive_name()])
.with_exec(vec![
"mv",
&format!("{}/bin/mold", self.get_folder()),
"/usr/bin/mold",
]);
Ok(c)
}
}
pub trait MoldActionExt {
fn with_mold(&mut self, version: impl Into<String>) -> &mut Self {
self
}
}
impl MoldActionExt for RustService {
fn with_mold(&mut self, version: impl Into<String>) -> &mut Self {
self.with_stage(super::RustServiceStage::AfterDeps(Arc::new(
MoldInstall::new(self.get_arch(), self.get_os(), version),
)))
}
}

View File

@ -0,0 +1,66 @@
use std::sync::Arc;
use async_trait::async_trait;
use dagger_sdk::Container;
use crate::{dagger_middleware::DaggerMiddleware, leptos_service::LeptosService, rust_workspace};
use super::RustService;
pub struct RustWorkspace {}
impl Default for RustWorkspace {
fn default() -> Self {
Self::new()
}
}
impl RustWorkspace {
pub fn new() -> Self {
Self {}
}
}
#[async_trait]
impl DaggerMiddleware for RustWorkspace {
async fn handle(&self, container: Container) -> eyre::Result<Container> {
Ok(container)
}
}
#[async_trait]
pub trait RustWorkspaceExt {
async fn with_workspace_crates(&mut self) -> &mut Self {
self
}
}
#[async_trait]
impl RustWorkspaceExt for RustService {
async fn with_workspace_crates(&mut self) -> &mut Self {
self.with_crates(get_members().await)
.with_stage(super::RustServiceStage::BeforeDeps(Arc::new(
RustWorkspace::new(),
)))
}
}
#[async_trait]
impl RustWorkspaceExt for LeptosService {
async fn with_workspace_crates(&mut self) -> &mut Self {
self.with_crates(get_members().await)
.with_stage(super::RustServiceStage::BeforeDeps(Arc::new(
RustWorkspace::new(),
)))
}
}
async fn get_members() -> Vec<String> {
if let Ok(Some(file)) = rust_workspace::File::read_file().await {
if let Some(members) = file.get_workspace_members() {
return members;
}
}
Vec::new()
}

View File

@ -0,0 +1,81 @@
use std::{path::PathBuf, sync::Arc};
use async_trait::async_trait;
use dagger_sdk::Container;
use crate::dagger_middleware::DaggerMiddleware;
use super::RustService;
pub struct Sqlx {
client: dagger_sdk::Query,
migration_path: Option<PathBuf>,
}
impl Sqlx {
pub fn new(client: dagger_sdk::Query) -> Self {
Self {
client,
migration_path: None,
}
}
pub fn with_migration_path(mut self, migration_path: impl Into<PathBuf>) -> Self {
self.migration_path = Some(migration_path.into());
self
}
}
#[async_trait]
impl DaggerMiddleware for Sqlx {
async fn handle(&self, container: Container) -> eyre::Result<Container> {
let container = if std::path::PathBuf::from(".sqlx/").exists() {
tracing::debug!("found .sqlx folder enabling offline mode");
let src = self.client.host().directory(".sqlx/");
container
.with_directory(".sqlx", src)
.with_env_variable("SQLX_OFFLINE", "true")
} else {
tracing::debug!("did not find a .sqlx folder, requires a running database");
container
};
let container = if let Some(migration_path) = &self.migration_path {
container
.with_directory(
"/mnt/sqlx/migrations",
self.client
.host()
.directory(migration_path.display().to_string()),
)
.with_env_variable("NEFARIOUS_DB_MIGRATION_PATH", "/mnt/sqlx/migrations")
} else {
container
};
Ok(container)
}
}
pub trait SqlxExt {
fn with_sqlx(&mut self) -> &mut Self;
fn with_sqlx_migrations(&mut self, path: impl Into<PathBuf>) -> &mut Self;
}
impl SqlxExt for RustService {
fn with_sqlx(&mut self) -> &mut Self {
self.with_stage(super::RustServiceStage::BeforeBuild(Arc::new(Sqlx::new(
self.client.clone(),
))))
}
fn with_sqlx_migrations(&mut self, path: impl Into<PathBuf>) -> &mut Self {
self.with_stage(super::RustServiceStage::BeforeBuild(Arc::new(
Sqlx::new(self.client.clone()).with_migration_path(path),
)))
}
}

View File

@ -0,0 +1,79 @@
use std::sync::Arc;
use async_trait::async_trait;
use dagger_sdk::{Container, ContainerWithNewFileOptsBuilder};
use eyre::Context;
use crate::{dagger_middleware::DaggerMiddleware, leptos_service::LeptosService};
use super::RustService;
pub struct SshAgent {
client: dagger_sdk::Query,
}
impl SshAgent {
pub fn new(client: dagger_sdk::Query) -> Self {
Self { client }
}
}
#[async_trait]
impl DaggerMiddleware for SshAgent {
async fn handle(&self, container: Container) -> eyre::Result<Container> {
let sock_var =
std::env::var("SSH_AUTH_SOCK").context("failed to find variable SSH_AUTH_SOCK")?;
let socket = self.client.host().unix_socket(&sock_var);
let c = container
.with_new_file_opts(
".ssh/config".to_string(),
r#"
Host *
UserKnownHostsFile=/dev/null
StrictHostKeyChecking no
"#,
ContainerWithNewFileOptsBuilder::default()
.permissions(0o700_isize)
.build()?,
)
.with_unix_socket(&sock_var, socket)
.with_env_variable("SSH_AUTH_SOCK", &sock_var);
Ok(c)
}
}
pub trait SshAgentExt {
fn with_ssh_agent(&mut self) -> &mut Self {
self
}
}
impl SshAgentExt for RustService {
fn with_ssh_agent(&mut self) -> &mut Self {
let client = self.client.clone();
self.with_stage(super::RustServiceStage::BeforeDeps(Arc::new(
SshAgent::new(client.clone()),
)))
.with_stage(super::RustServiceStage::BeforeBase(Arc::new(
SshAgent::new(client),
)))
}
}
impl SshAgentExt for LeptosService {
fn with_ssh_agent(&mut self) -> &mut Self {
let client = self.client.clone();
self.with_stage(super::RustServiceStage::BeforeDeps(Arc::new(
SshAgent::new(client.clone()),
)))
.with_stage(super::RustServiceStage::AfterBase(Arc::new(SshAgent::new(
client,
))))
}
}

View File

@ -0,0 +1,31 @@
use serde::Deserialize;
#[derive(Deserialize, Clone, Debug)]
pub struct Workspace {
pub members: Vec<String>,
}
#[derive(Deserialize, Clone, Debug)]
pub struct File {
pub workspace: Option<Workspace>,
}
impl File {
pub async fn read_file() -> eyre::Result<Option<Self>> {
let file = match tokio::fs::read_to_string("Cargo.toml").await {
Ok(file) => file,
Err(e) => {
tracing::warn!("Cargo.toml was not found: {}", e);
return Ok(None);
}
};
let workspace_file: File = toml::from_str(&file)?;
Ok(Some(workspace_file))
}
pub fn get_workspace_members(&self) -> Option<Vec<String>> {
self.workspace.as_ref().map(|w| w.members.clone())
}
}

View File

@ -1,4 +1,4 @@
use std::sync::{Arc, Mutex}; use std::sync::Arc;
use models::{CuddlePleaseArgs, CuddlePleaseSrcArgs}; use models::{CuddlePleaseArgs, CuddlePleaseSrcArgs};
use traits::CuddlePlease; use traits::CuddlePlease;
@ -103,7 +103,7 @@ impl DaggerCuddlePleaseAction {
} }
#[derive(Clone)] #[derive(Clone)]
struct DaggerCuddlePlease { pub struct DaggerCuddlePlease {
client: dagger_sdk::Query, client: dagger_sdk::Query,
} }
@ -189,13 +189,12 @@ impl DaggerCuddlePlease {
dagger_sdk::QueryGitOpts { dagger_sdk::QueryGitOpts {
experimental_service_host: None, experimental_service_host: None,
keep_git_dir: Some(true), keep_git_dir: Some(true),
ssh_auth_socket: Some(socket.id().await?),
ssh_known_hosts: None,
}, },
) )
.branch("main") .branch("main")
.tree_opts(dagger_sdk::GitRefTreeOpts { .tree()
ssh_auth_socket: Some(socket.id().await?),
ssh_known_hosts: None,
})
} else { } else {
self.client self.client
.git_opts( .git_opts(
@ -203,6 +202,8 @@ impl DaggerCuddlePlease {
dagger_sdk::QueryGitOpts { dagger_sdk::QueryGitOpts {
experimental_service_host: None, experimental_service_host: None,
keep_git_dir: Some(true), keep_git_dir: Some(true),
ssh_auth_socket: None,
ssh_known_hosts: None,
}, },
) )
.branch("main") .branch("main")
@ -284,17 +285,16 @@ impl DaggerCuddlePlease {
.with_env_variable("SSH_AUTH_SOCK", "/tmp/ssh.sock") .with_env_variable("SSH_AUTH_SOCK", "/tmp/ssh.sock")
.with_new_file_opts( .with_new_file_opts(
"/root/.ssh/config", "/root/.ssh/config",
dagger_sdk::ContainerWithNewFileOpts {
contents: Some(
" "
Host * Host *
User git User git
StrictHostKeyChecking no StrictHostKeyChecking no
UserKnownHostsFile /dev/null UserKnownHostsFile /dev/null
", ",
), dagger_sdk::ContainerWithNewFileOpts {
owner: Some("root"), owner: Some("root"),
permissions: Some(700), permissions: Some(700),
expand: None,
}, },
); );

View File

@ -44,6 +44,9 @@ impl RustBuild {
.from(rust_version.to_string()) .from(rust_version.to_string())
.with_exec(vec!["rustup", "target", "add", &target.to_string()]) .with_exec(vec!["rustup", "target", "add", &target.to_string()])
.with_exec(vec!["apt", "update"]) .with_exec(vec!["apt", "update"])
.with_exec(vec!["wget", "https://github.com/rui314/mold/releases/latest/download/mold-2.3.3-x86_64-linux.tar.gz"])
.with_exec("tar -xvf mold-2.3.3-x86_64-linux.tar.gz".split_whitespace().collect())
.with_exec("mv mold-2.3.3-x86_64-linux/bin/mold /usr/bin/mold".split_whitespace().collect())
.with_exec(deps); .with_exec(deps);
let target_cache = self.client.cache_volume(format!( let target_cache = self.client.cache_volume(format!(
@ -110,6 +113,8 @@ impl RustBuild {
.await?; .await?;
let bin = build_container let bin = build_container
.with_env_variable("SQLX_OFFLINE", "true")
.with_exec(vec!["cargo", "clean"])
.with_exec(vec![ .with_exec(vec![
"cargo", "cargo",
"build", "build",
@ -198,7 +203,6 @@ impl RustBuild {
let base_debian = self let base_debian = self
.client .client
.container_opts(dagger_sdk::QueryContainerOpts { .container_opts(dagger_sdk::QueryContainerOpts {
id: None,
platform: Some(target.into_platform()), platform: Some(target.into_platform()),
}) })
.from(image); .from(image);
@ -229,7 +233,6 @@ impl RustBuild {
let base_debian = self let base_debian = self
.client .client
.container_opts(dagger_sdk::QueryContainerOpts { .container_opts(dagger_sdk::QueryContainerOpts {
id: None,
platform: Some(target.into_platform()), platform: Some(target.into_platform()),
}) })
.from(image); .from(image);

View File

@ -110,7 +110,7 @@ impl HtmxBuild {
let container = let container =
match &container_image { match &container_image {
SlimImage::Debian { image, deps, .. } => { SlimImage::Debian { image, deps, .. } => {
let target = BuildTarget::from_target(&container_image); let _target = BuildTarget::from_target(&container_image);
let build_container = self let build_container = self
.build( .build(
@ -200,7 +200,6 @@ impl HtmxBuild {
let base_debian = self let base_debian = self
.client .client
.container_opts(dagger_sdk::QueryContainerOpts { .container_opts(dagger_sdk::QueryContainerOpts {
id: None,
platform: Some(target.into_platform()), platform: Some(target.into_platform()),
}) })
.from(image); .from(image);
@ -219,7 +218,7 @@ impl HtmxBuild {
) )
.with_directory( .with_directory(
"/mnt/app/target/site", "/mnt/app/target/site",
builder_image.directory(format!("/mnt/src/target/site")), builder_image.directory("/mnt/src/target/site".to_string()),
) )
.with_file( .with_file(
"/mnt/app/Cargo.toml", "/mnt/app/Cargo.toml",
@ -250,7 +249,6 @@ impl HtmxBuild {
let base_debian = self let base_debian = self
.client .client
.container_opts(dagger_sdk::QueryContainerOpts { .container_opts(dagger_sdk::QueryContainerOpts {
id: None,
platform: Some(target.into_platform()), platform: Some(target.into_platform()),
}) })
.from(image); .from(image);

View File

@ -55,7 +55,7 @@ impl LeptosBuild {
.client .client
.cache_volume(format!("rust_leptos_{}", profile.to_string())); .cache_volume(format!("rust_leptos_{}", profile.to_string()));
let mut build_options = vec!["cargo", "leptos", "build", "--release", "-vv"]; let build_options = vec!["cargo", "leptos", "build", "--release", "-vv"];
let rust_prebuild = rust_build_image let rust_prebuild = rust_build_image
.with_workdir("/mnt/src") .with_workdir("/mnt/src")
@ -95,7 +95,7 @@ impl LeptosBuild {
for container_image in images { for container_image in images {
let container = match &container_image { let container = match &container_image {
SlimImage::Debian { image, deps, .. } => { SlimImage::Debian { image, deps, .. } => {
let target = BuildTarget::from_target(&container_image); let _target = BuildTarget::from_target(&container_image);
let build_container = self let build_container = self
.build( .build(
@ -107,9 +107,13 @@ impl LeptosBuild {
) )
.await?; .await?;
let binary_build = let binary_build = build_container.with_exec(vec![
build_container "cargo",
.with_exec(vec!["cargo", "leptos", "build", "--release", "-vv"]); "leptos",
"build",
"--release",
"-vv",
]);
self.build_debian_image( self.build_debian_image(
binary_build, binary_build,
@ -146,7 +150,11 @@ impl LeptosBuild {
"-p", "-p",
bin_name, bin_name,
]) ])
.file(format!("target/{}/release/{}", target.to_string(), bin_name)); .file(format!(
"target/{}/release/{}",
target.to_string(),
bin_name
));
self.build_alpine_image( self.build_alpine_image(
bin, bin,
@ -179,7 +187,6 @@ impl LeptosBuild {
let base_debian = self let base_debian = self
.client .client
.container_opts(dagger_sdk::QueryContainerOpts { .container_opts(dagger_sdk::QueryContainerOpts {
id: None,
platform: Some(target.into_platform()), platform: Some(target.into_platform()),
}) })
.from(image); .from(image);
@ -198,7 +205,7 @@ impl LeptosBuild {
) )
.with_directory( .with_directory(
"/mnt/app/target/site", "/mnt/app/target/site",
builder_image.directory(format!("/mnt/src/target/site")), builder_image.directory("/mnt/src/target/site".to_string()),
) )
.with_file( .with_file(
"/mnt/app/Cargo.toml", "/mnt/app/Cargo.toml",
@ -229,7 +236,6 @@ impl LeptosBuild {
let base_debian = self let base_debian = self
.client .client
.container_opts(dagger_sdk::QueryContainerOpts { .container_opts(dagger_sdk::QueryContainerOpts {
id: None,
platform: Some(target.into_platform()), platform: Some(target.into_platform()),
}) })
.from(image); .from(image);

View File

@ -1,7 +1,4 @@
use std::{ use std::path::{Path, PathBuf};
path::{Path, PathBuf},
sync::Arc,
};
use eyre::Context; use eyre::Context;
@ -92,6 +89,7 @@ impl RustSource {
let mut excludes = self.exclude.clone(); let mut excludes = self.exclude.clone();
excludes.push("**/src".to_string()); excludes.push("**/src".to_string());
excludes.push("**/tests".to_string());
let directory = self.client.host().directory_opts( let directory = self.client.host().directory_opts(
source.display().to_string(), source.display().to_string(),
@ -119,7 +117,10 @@ impl RustSource {
.map(|c| format!("**/*{}*", c.replace('-', "_"))) .map(|c| format!("**/*{}*", c.replace('-', "_")))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let exclude = exclude.iter().map(|c| c.as_str()).collect(); let mut original_crates = crates.clone();
original_crates.extend(exclude);
let exclude = original_crates.iter().map(|c| c.as_str()).collect();
let incremental_dir = self.client.directory().with_directory_opts( let incremental_dir = self.client.directory().with_directory_opts(
".", ".",
@ -130,7 +131,7 @@ impl RustSource {
}, },
); );
return Ok(incremental_dir); Ok(incremental_dir)
} }
pub async fn get_rust_skeleton_files( pub async fn get_rust_skeleton_files(
@ -191,7 +192,7 @@ impl RustSource {
} }
directory = create_skeleton_files( directory = create_skeleton_files(
directory, directory,
rust_crate.strip_prefix(source_path).unwrap_or(&rust_crate), rust_crate.strip_prefix(source_path).unwrap_or(rust_crate),
)?; )?;
} }

View File

@ -1,4 +1,4 @@
use std::{path::PathBuf, sync::Arc}; use std::{path::PathBuf};
use crate::{build::RustVersion, source::RustSource}; use crate::{build::RustVersion, source::RustSource};
@ -40,7 +40,7 @@ impl RustTest {
.with_exec(vec!["apt", "update"]) .with_exec(vec!["apt", "update"])
.with_exec(deps); .with_exec(deps);
let target_cache = self.client.cache_volume(format!("rust_target_test",)); let target_cache = self.client.cache_volume("rust_target_test".to_string());
let build_options = vec!["cargo", "build", "--workspace"]; let build_options = vec!["cargo", "build", "--workspace"];
let rust_prebuild = rust_build_image let rust_prebuild = rust_build_image

View File

@ -15,6 +15,8 @@ please:
branch: main branch: main
settings: settings:
api_url: https://git.front.kjuulh.io api_url: https://git.front.kjuulh.io
actions:
rust:
scripts: scripts:
"ci:main": "ci:main":

View File

@ -2,8 +2,7 @@ use dagger_cuddle_please::{models::CuddlePleaseSrcArgs, DaggerCuddlePleaseAction
#[tokio::main] #[tokio::main]
pub async fn main() -> eyre::Result<()> { pub async fn main() -> eyre::Result<()> {
let client = dagger_sdk::connect().await?; dagger_sdk::connect(|client| async move {
DaggerCuddlePleaseAction::dagger(client.clone()) DaggerCuddlePleaseAction::dagger(client.clone())
.execute_src(&CuddlePleaseSrcArgs { .execute_src(&CuddlePleaseSrcArgs {
cuddle_image: "kasperhermansen/cuddle-please:main-1691504183".into(), cuddle_image: "kasperhermansen/cuddle-please:main-1691504183".into(),
@ -15,5 +14,9 @@ pub async fn main() -> eyre::Result<()> {
}) })
.await?; .await?;
Ok(())
})
.await?;
Ok(()) Ok(())
} }

View File

@ -2,8 +2,7 @@ use dagger_cuddle_please::{models::CuddlePleaseArgs, DaggerCuddlePleaseAction};
#[tokio::main] #[tokio::main]
pub async fn main() -> eyre::Result<()> { pub async fn main() -> eyre::Result<()> {
let client = dagger_sdk::connect().await?; dagger_sdk::connect(|client| async move {
DaggerCuddlePleaseAction::dagger(client) DaggerCuddlePleaseAction::dagger(client)
.execute(&CuddlePleaseArgs { .execute(&CuddlePleaseArgs {
repository: "dagger-components".into(), repository: "dagger-components".into(),
@ -23,4 +22,7 @@ pub async fn main() -> eyre::Result<()> {
.await?; .await?;
Ok(()) Ok(())
})
.await?;
Ok(())
} }

View File

@ -2,8 +2,7 @@ use std::path::PathBuf;
#[tokio::main] #[tokio::main]
pub async fn main() -> eyre::Result<()> { pub async fn main() -> eyre::Result<()> {
let client = dagger_sdk::connect().await?; dagger_sdk::connect(|client| async move {
let crates = ["some-crate"]; let crates = ["some-crate"];
let dag = dagger_rust::source::RustSource::new(client.clone()); let dag = dagger_rust::source::RustSource::new(client.clone());
let (_src, _rust_src) = dag.get_rust_src(None::<PathBuf>, crates).await?; let (_src, _rust_src) = dag.get_rust_src(None::<PathBuf>, crates).await?;
@ -13,4 +12,7 @@ pub async fn main() -> eyre::Result<()> {
.await?; .await?;
Ok(()) Ok(())
})
.await?;
Ok(())
} }

View File

@ -1,9 +1,8 @@
use dagger_rust::build::{BuildProfile, RustVersion, SlimImage}; use dagger_rust::build::{RustVersion, SlimImage};
#[tokio::main] #[tokio::main]
pub async fn main() -> eyre::Result<()> { pub async fn main() -> eyre::Result<()> {
let client = dagger_sdk::connect().await?; dagger_sdk::connect(|client| async move {
let rust_build = dagger_rust::leptos::LeptosBuild::new(client.clone()); let rust_build = dagger_rust::leptos::LeptosBuild::new(client.clone());
let containers = rust_build let containers = rust_build
@ -58,5 +57,8 @@ pub async fn main() -> eyre::Result<()> {
std::io::stdin().read_line(&mut String::new()).unwrap(); std::io::stdin().read_line(&mut String::new()).unwrap();
Ok(())
})
.await?;
Ok(()) Ok(())
} }

View File

@ -2,8 +2,7 @@ use dagger_rust::build::{RustVersion, SlimImage};
#[tokio::main] #[tokio::main]
pub async fn main() -> eyre::Result<()> { pub async fn main() -> eyre::Result<()> {
let client = dagger_sdk::connect().await?; dagger_sdk::connect(|client| async move {
let rust_build = dagger_rust::build::RustBuild::new(client.clone()); let rust_build = dagger_rust::build::RustBuild::new(client.clone());
let containers = rust_build let containers = rust_build
@ -25,5 +24,8 @@ pub async fn main() -> eyre::Result<()> {
container.sync().await?; container.sync().await?;
} }
Ok(())
})
.await?;
Ok(()) Ok(())
} }

View File

@ -2,8 +2,7 @@ use std::path::PathBuf;
#[tokio::main] #[tokio::main]
pub async fn main() -> eyre::Result<()> { pub async fn main() -> eyre::Result<()> {
let client = dagger_sdk::connect().await?; dagger_sdk::connect(|client| async move {
let crates = ["some-crate"]; let crates = ["some-crate"];
let dag = dagger_rust::source::RustSource::new(client.clone()); let dag = dagger_rust::source::RustSource::new(client.clone());
let (_src, _rust_src) = dag.get_rust_src(None::<PathBuf>, crates).await?; let (_src, _rust_src) = dag.get_rust_src(None::<PathBuf>, crates).await?;
@ -13,4 +12,7 @@ pub async fn main() -> eyre::Result<()> {
.await?; .await?;
Ok(()) Ok(())
})
.await?;
Ok(())
} }

View File

@ -2,7 +2,7 @@ use dagger_rust::{build::RustVersion, test::RustTest};
#[tokio::main] #[tokio::main]
pub async fn main() -> eyre::Result<()> { pub async fn main() -> eyre::Result<()> {
let client = dagger_sdk::connect().await?; dagger_sdk::connect(|client| async move {
RustTest::new(client.clone()) RustTest::new(client.clone())
.test( .test(
Some("testdata"), Some("testdata"),
@ -12,5 +12,9 @@ pub async fn main() -> eyre::Result<()> {
) )
.await?; .await?;
Ok(())
})
.await?;
Ok(()) Ok(())
} }