Skip to content

Commit 0e54bba

Browse files
committed
feat: implement 'withWorkdir'
1 parent 476dbde commit 0e54bba

File tree

25 files changed

+384
-36
lines changed

25 files changed

+384
-36
lines changed

.devcontainer/devcontainer.json

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
2+
// README at: https://github.com/devcontainers/templates/tree/main/src/rust
3+
{
4+
"name": "Rust",
5+
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
6+
"image": "mcr.microsoft.com/devcontainers/rust:1-1-bullseye",
7+
"features": {
8+
"ghcr.io/devcontainers/features/github-cli:1": {},
9+
"ghcr.io/devcontainers/features/nix:1": {}
10+
},
11+
12+
// Use 'mounts' to make the cargo cache persistent in a Docker Volume.
13+
// "mounts": [
14+
// {
15+
// "source": "devcontainer-cargo-cache-${devcontainerId}",
16+
// "target": "/usr/local/cargo",
17+
// "type": "volume"
18+
// }
19+
// ]
20+
21+
// Features to add to the dev container. More info: https://containers.dev/features.
22+
// "features": {},
23+
24+
// Use 'forwardPorts' to make a list of ports inside the container available locally.
25+
// "forwardPorts": [],
26+
27+
// Use 'postCreateCommand' to run commands after the container is created.
28+
"postCreateCommand": "nix develop --experimental-features \"nix-command flakes\""
29+
30+
// Configure tool-specific properties.
31+
// "customizations": {},
32+
33+
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
34+
// "remoteUser": "root"
35+
}

.fluentci/src/dagger/jobs.ts

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* @description This module provides a set of functions to build, test, and run clippy on a Rust project 🦀
44
*/
55

6-
import { dag, env, Container, Directory, DirectoryID, File } from "../../deps.ts";
6+
import { dag, env, Directory, DirectoryID, File } from "../../deps.ts";
77

88
export enum Job {
99
clippy = "clippy",
@@ -220,12 +220,16 @@ export async function build(
220220
export async function e2e(
221221
src: string | Directory | undefined = ".",
222222
options: string[] = []
223-
): Promise<Container | string> {
224-
const context = await getDirectory(src);
223+
): Promise<string> {
224+
const context = await getDirectory(env.get("WORK_DIR") || src);
225225
const engine = dag
226226
.container()
227227
.from("debian:bookworm")
228-
.withFile("/fluentci-engine", dag.host().file('./target/release/fluentci-engine'))
228+
.withDirectory("/app", context, { exclude })
229+
.withFile(
230+
"/fluentci-engine",
231+
dag.host().file("./target/release/fluentci-engine")
232+
)
229233
.withEnvVariable("FLUENTCI_ENGINE_HOST", "0.0.0.0")
230234
.withExec(["/fluentci-engine"])
231235
.withExposedPort(6880)
@@ -237,14 +241,46 @@ export async function e2e(
237241
.from("pkgxdev/pkgx:latest")
238242
.withExec(["pkgx", "install", "httpie"])
239243
.withExec(["http", "--version"])
244+
.withDirectory("/app", context, { exclude })
240245
.withServiceBinding("fluentci-engine", engine)
241-
.sync();
246+
.sync();
247+
248+
ctr = ctr.withExec([
249+
"bash",
250+
"-c",
251+
`http POST http://fluentci-engine:6880/graphql Content-Type:application/json query="$(cat nix.graphql)"`,
252+
]);
253+
254+
let stdout = await ctr.stdout();
255+
console.log(stdout);
242256

243-
ctr = ctr.withExec(["http", "GET", "http://fluentci-engine:6880/graphiql"]);
257+
ctr = ctr.withExec([
258+
"bash",
259+
"-c",
260+
`http POST http://fluentci-engine:6880/graphql Content-Type:application/json query="$(cat flox.graphql)"`,
261+
]);
244262

245-
const stdout = await ctr.stdout();
263+
stdout = await ctr.stdout();
246264
console.log(stdout);
247-
265+
266+
ctr = ctr.withExec([
267+
"bash",
268+
"-c",
269+
`http POST http://fluentci-engine:6880/graphql Content-Type:application/json query="$(cat devenv.graphql)"`,
270+
]);
271+
272+
stdout = await ctr.stdout();
273+
console.log(stdout);
274+
275+
ctr = ctr.withExec([
276+
"bash",
277+
"-c",
278+
`http POST http://fluentci-engine:6880/graphql Content-Type:application/json query="$(cat devbox.graphql)"`,
279+
]);
280+
281+
stdout = await ctr.stdout();
282+
console.log(stdout);
283+
248284
return stdout;
249285
}
250286

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,5 @@ jobs:
1919
env:
2020
PACKAGE_NAME: fluentci-engine
2121
FLUENTCI_ENGINE_HOST: 0.0.0.0
22+
WORK_DIR: ./fixtures
2223
DAGGER_CLOUD_TOKEN: ${{ secrets.DAGGER_CLOUD_TOKEN }}

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77

88
FluentCI Engine is a programmable CI/CD engine that is designed to be simple, flexible, and easy to use. It is supposed to run on the host machine without containerization or virtualization, and it is designed to be used with [Nix](https://nixos.com), [Pkgx](https://pkgx.dev), [Devbox](https://www.jetpack.io/devbox/), [Flox](https://flox.dev), and [Devenv](https://devenv.sh).
99

10+
> [!NOTE]
11+
> **Project Status: 🐲 Unstable, alpha-ish quality.**
12+
> This project is still in the early stages of development,
13+
> and it is not yet ready for production use.
14+
> It is not feature-complete, and it is not yet stable. Use at your own risk.
15+
1016
## ✨ Features
1117

1218
- [x] Simple and easy to use
@@ -16,3 +22,17 @@ FluentCI Engine is a programmable CI/CD engine that is designed to be simple, fl
1622
- [ ] Cache support
1723
- [ ] SDK for writing pipelines in TypeScript
1824
- [x] GraphQL API
25+
26+
## 🚀 Quick Start
27+
28+
```bash
29+
# Clone the repository
30+
git clone https://github.com/fluentci-io/fluentci-engine.git
31+
# Go to the project directory
32+
cd fluentci-engine
33+
# Install dependencies
34+
nix develop
35+
cargo run -p fluentci-engine
36+
# Open the browser and go to http://localhost:6880/graphiql
37+
# See ./fixtures for some GraphQL queries examples
38+
```

crates/core/src/deps.rs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::fs;
1+
use std::env::current_dir;
22
use std::sync::mpsc::{self, Sender};
33
use std::sync::Arc;
44

@@ -21,22 +21,18 @@ pub struct Graph {
2121
pub edges: Vec<Edge>,
2222
tx: Sender<(String, usize)>,
2323
pub runner: Arc<Box<dyn Extension + Send + Sync>>,
24-
pub working_dir: String,
24+
pub work_dir: String,
2525
}
2626

2727
impl Graph {
2828
pub fn new(tx: Sender<(String, usize)>, runner: Arc<Box<dyn Extension + Send + Sync>>) -> Self {
29-
let working_dir = format!(
30-
"{}/.fluentci/workspace",
31-
dirs::home_dir().unwrap().to_str().unwrap()
32-
);
33-
fs::create_dir_all(&working_dir).unwrap();
29+
let work_dir = current_dir().unwrap().to_str().unwrap().to_string();
3430
Graph {
3531
vertices: Vec::new(),
3632
edges: Vec::new(),
3733
tx,
3834
runner,
39-
working_dir,
35+
work_dir,
4036
}
4137
}
4238

@@ -76,11 +72,17 @@ impl Graph {
7672

7773
let (tx, rx) = mpsc::channel();
7874

75+
if self.vertices[i].label == "withWorkdir" {
76+
self.work_dir = self.vertices[i].command.clone();
77+
continue;
78+
}
79+
7980
match self.vertices[i].run(
8081
self.runner.clone(),
8182
tx,
8283
Output::Stdout,
8384
stack.len() == 1,
85+
&self.work_dir,
8486
) {
8587
Ok(status) => {
8688
if !status.success() {
@@ -119,11 +121,18 @@ impl Graph {
119121
stack.push(edge.to);
120122
}
121123
let (tx, rx) = mpsc::channel();
124+
125+
if self.vertices[i].label == "withWorkdir" {
126+
self.work_dir = self.vertices[i].command.clone();
127+
continue;
128+
}
129+
122130
match self.vertices[i].run(
123131
self.runner.clone(),
124132
tx,
125133
Output::Stderr,
126134
stack.len() == 1,
135+
&self.work_dir,
127136
) {
128137
Ok(status) => {
129138
if !status.success() {

crates/core/src/vertex.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ pub trait Runnable {
2222
tx: Sender<String>,
2323
out: Output,
2424
last_cmd: bool,
25+
work_dir: &str,
2526
) -> Result<ExitStatus, Error>;
2627
}
2728

@@ -40,11 +41,12 @@ impl Runnable for Vertex {
4041
tx: Sender<String>,
4142
out: Output,
4243
last_cmd: bool,
44+
work_dir: &str,
4345
) -> Result<ExitStatus, Error> {
4446
let label = format!("[{}]", self.label);
4547
println!("{} {}", label.cyan(), self.id.bright_yellow());
4648
println!("{} {}", label.cyan(), self.command.bright_green());
4749

48-
runner.exec(&self.command, tx, out, last_cmd)
50+
runner.exec(&self.command, tx, out, last_cmd, work_dir)
4951
}
5052
}

crates/ext/src/devbox.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,22 +33,30 @@ impl Extension for Devbox {
3333
tx: Sender<String>,
3434
out: Output,
3535
last_cmd: bool,
36+
work_dir: &str,
3637
) -> Result<ExitStatus, Error> {
3738
self.setup()?;
39+
40+
if cmd.is_empty() {
41+
return Ok(ExitStatus::default());
42+
}
43+
3844
let (stdout_tx, stdout_rx): (Sender<String>, Receiver<String>) = mpsc::channel();
3945
let (stderr_tx, stderr_rx): (Sender<String>, Receiver<String>) = mpsc::channel();
4046

41-
Command::new("sh")
47+
Command::new("bash")
4248
.arg("-c")
43-
.arg("devbox init")
49+
.arg("[ -f devbox.json ] || devbox init")
50+
.current_dir(work_dir)
4451
.stdout(Stdio::inherit())
4552
.stderr(Stdio::inherit())
4653
.spawn()?
4754
.wait()?;
4855

49-
let mut child = Command::new("sh")
56+
let mut child = Command::new("bash")
5057
.arg("-c")
5158
.arg(format!("devbox run {}", cmd))
59+
.current_dir(work_dir)
5260
.stdout(Stdio::piped())
5361
.stderr(Stdio::piped())
5462
.spawn()?;

crates/ext/src/devenv.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,32 @@ impl Extension for Devenv {
1919
tx: Sender<String>,
2020
out: Output,
2121
last_cmd: bool,
22+
work_dir: &str,
2223
) -> Result<ExitStatus, Error> {
2324
self.setup()?;
25+
26+
if cmd.is_empty() {
27+
return Ok(ExitStatus::default());
28+
}
29+
2430
Pkgx::default().install(vec!["direnv"])?;
2531

2632
let (stdout_tx, stdout_rx): (Sender<String>, Receiver<String>) = mpsc::channel();
2733
let (stderr_tx, stderr_rx): (Sender<String>, Receiver<String>) = mpsc::channel();
2834

29-
Command::new("sh")
35+
Command::new("bash")
3036
.arg("-c")
31-
.arg("devenv init")
37+
.arg("[ -f devenv.nix ] || devenv init")
38+
.current_dir(work_dir)
3239
.stdout(Stdio::inherit())
3340
.stderr(Stdio::inherit())
3441
.spawn()?
3542
.wait()?;
3643

37-
let mut child = Command::new("sh")
44+
let mut child = Command::new("bash")
3845
.arg("-c")
3946
.arg(format!("devenv shell {}", cmd))
47+
.current_dir(work_dir)
4048
.stdout(Stdio::piped())
4149
.stderr(Stdio::piped())
4250
.spawn()?;

crates/ext/src/envhub.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,21 @@ impl Extension for Envhub {
1919
tx: Sender<String>,
2020
out: Output,
2121
last_cmd: bool,
22+
work_dir: &str,
2223
) -> Result<ExitStatus, Error> {
2324
self.setup()?;
2425

26+
if cmd.is_empty() {
27+
return Ok(ExitStatus::default());
28+
}
29+
2530
let (stdout_tx, stdout_rx): (Sender<String>, Receiver<String>) = mpsc::channel();
2631
let (stderr_tx, stderr_rx): (Sender<String>, Receiver<String>) = mpsc::channel();
2732

28-
let mut child = Command::new("sh")
33+
let mut child = Command::new("bash")
2934
.arg("-c")
3035
.arg(cmd)
36+
.current_dir(work_dir)
3137
.stdout(Stdio::piped())
3238
.stderr(Stdio::piped())
3339
.spawn()?;

crates/ext/src/flox.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,30 @@ impl Extension for Flox {
1919
tx: Sender<String>,
2020
out: Output,
2121
last_cmd: bool,
22+
work_dir: &str,
2223
) -> Result<ExitStatus, Error> {
2324
self.setup()?;
2425

26+
if cmd.is_empty() {
27+
return Ok(ExitStatus::default());
28+
}
29+
2530
let (stdout_tx, stdout_rx): (Sender<String>, Receiver<String>) = mpsc::channel();
2631
let (stderr_tx, stderr_rx): (Sender<String>, Receiver<String>) = mpsc::channel();
2732

28-
let mut child = Command::new("sh")
33+
Command::new("bash")
34+
.arg("-c")
35+
.arg("[ -d .flox ] || flox init")
36+
.current_dir(work_dir)
37+
.stdout(Stdio::inherit())
38+
.stderr(Stdio::inherit())
39+
.spawn()?
40+
.wait()?;
41+
42+
let mut child = Command::new("bash")
2943
.arg("-c")
3044
.arg(format!("flox activate -- {}", cmd))
45+
.current_dir(work_dir)
3146
.stdout(Stdio::piped())
3247
.stderr(Stdio::piped())
3348
.spawn()?;

0 commit comments

Comments
 (0)