Compare commits

...

5 Commits

Author SHA1 Message Date
7205af017e Merge branch 'main' into feat/add-tests-to-sdk 2023-02-25 02:27:36 +01:00
e125adec98 feat: add tests to sdk 2023-02-25 02:27:01 +01:00
5f9b3a19c0 feat: set internal warnings as errors 2023-02-25 02:01:13 +01:00
f9e7af931d feat: introduce tests again 2023-02-25 01:47:57 +01:00
ecca036bc6 fix(sdk): fix builder pattern to actually work with default values
In previous versions the builder pattern required all values to be set.
This has not been fixed, so that default values are allowed.
2023-02-25 01:47:57 +01:00
12 changed files with 184 additions and 98 deletions

View File

@@ -165,8 +165,21 @@ async fn select_base_image(client: Arc<Query>) -> eyre::Result<Container> {
src_dir
}
async fn validate_pr(_client: Arc<Query>, container: Container) -> eyre::Result<()> {
//let container = container.with_exec(vec!["cargo", "test", "--all"], None);
async fn validate_pr(client: Arc<Query>, container: Container) -> eyre::Result<()> {
let exit = container.exit_code().await?;
if exit != 0 {
eyre::bail!("container failed with non-zero exit code");
}
let docker_cli = client
.container()
.from("docker:cli")
.file("/usr/local/bin/docker");
let socket = client.host().unix_socket("/var/run/docker.sock");
let container = container
.with_mounted_file("/usr/bin/docker", docker_cli.id().await?)
.with_unix_socket("/var/run/docker.sock", socket.id().await?)
.with_exec(vec!["cargo", "test", "--all"]);
let exit = container.exit_code().await?;
if exit != 0 {

View File

@@ -153,6 +153,7 @@ impl From<&TypeRef> for Scalar {
}
}
#[allow(dead_code)]
pub fn get_type_from_name<'t>(types: &'t [FullType], name: &'t str) -> Option<&'t FullType> {
types
.into_iter()
@@ -258,6 +259,7 @@ pub fn input_values_has_optionals(input_values: &[&InputValue]) -> bool {
> 0
}
#[allow(dead_code)]
pub fn input_values_is_empty(input_values: &[InputValue]) -> bool {
input_values.len() > 0
}

View File

@@ -1,3 +1,5 @@
#![deny(warnings)]
mod functions;
mod generator;
pub mod rust;

View File

@@ -86,7 +86,7 @@ pub fn render_optional_field_args(
}
quote! {
$(a.description.pipe(|d| format_struct_comment(d)))
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub $(format_struct_name(&a.name)): Option<$(type_)>,
}
});

View File

@@ -1,6 +1,6 @@
use std::{
fs::File,
io::{copy, Read, Write},
io::{copy, Write},
os::unix::prelude::PermissionsExt,
path::PathBuf,
};
@@ -27,6 +27,7 @@ impl Platform {
let normalize_arch = match arch.as_str() {
"x86_64" => "amd64",
"aarch" => "arm64",
"aarch64" => "arm64",
arch => arch,
};
@@ -138,6 +139,10 @@ impl Downloader {
if let Ok(entry) = file {
let path = entry.path();
if path != cli_bin_path {
println!(
"deleting client: path: {:?} vs cli_bin_path: {:?}",
path, cli_bin_path
);
std::fs::remove_file(path)?;
}
}
@@ -200,8 +205,6 @@ impl Downloader {
hasher.update(&bytes);
let res = hasher.finalize();
println!("{}", hex::encode(&res));
if archive_url.ends_with(".zip") {
// TODO: Nothing for now
todo!()
@@ -220,8 +223,6 @@ impl Downloader {
let mut entry = entry?;
let path = entry.path()?;
println!("path: {:?}", path);
if path.ends_with("dagger") {
copy(&mut entry, output)?;

View File

@@ -25,28 +25,3 @@ impl Engine {
self.from_cli(cfg).await
}
}
#[cfg(test)]
mod tests {
use crate::{config::Config, connect_params::ConnectParams};
use super::Engine;
// TODO: these tests potentially have a race condition
#[tokio::test]
async fn engine_can_start() {
let engine = Engine::new();
let params = engine
.start(&Config::new(None, None, None, None))
.await
.unwrap();
assert_ne!(
params.0,
ConnectParams {
port: 123,
session_token: "123".into()
}
)
}
}

View File

@@ -241,6 +241,7 @@ pub struct SchemaTypes {
pub full_type: FullType,
}
#[allow(dead_code)]
#[derive(Clone, Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SchemaDirectivesArgs {
@@ -257,6 +258,7 @@ pub struct SchemaDirectives {
pub args: Option<Vec<Option<SchemaDirectivesArgs>>>,
}
#[allow(dead_code)]
#[derive(Clone, Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Schema {

View File

@@ -1,3 +1,5 @@
#![deny(warnings)]
pub mod cli_session;
pub mod config;
pub mod connect_params;

View File

@@ -12,13 +12,3 @@ pub async fn get_schema() -> eyre::Result<IntrospectionResponse> {
Ok(schema)
}
#[cfg(test)]
mod tests {
use super::get_schema;
#[tokio::test]
async fn can_get_schema() {
let _ = get_schema().await.unwrap();
}
}

View File

@@ -50,134 +50,134 @@ pub struct Container {
pub struct ContainerBuildOpts<'a> {
/// Path to the Dockerfile to use.
/// Default: './Dockerfile'.
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub dockerfile: Option<&'a str>,
/// Additional build arguments.
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub build_args: Option<Vec<BuildArg>>,
/// Target build stage to build.
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub target: Option<&'a str>,
}
#[derive(Builder, Debug, PartialEq)]
pub struct ContainerEndpointOpts<'a> {
/// The exposed port number for the endpoint
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub port: Option<isize>,
/// Return a URL with the given scheme, eg. http for http://
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub scheme: Option<&'a str>,
}
#[derive(Builder, Debug, PartialEq)]
pub struct ContainerExecOpts<'a> {
/// Command to run instead of the container's default command (e.g., ["run", "main.go"]).
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub args: Option<Vec<&'a str>>,
/// Content to write to the command's standard input before closing (e.g., "Hello world").
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub stdin: Option<&'a str>,
/// Redirect the command's standard output to a file in the container (e.g., "/tmp/stdout").
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub redirect_stdout: Option<&'a str>,
/// Redirect the command's standard error to a file in the container (e.g., "/tmp/stderr").
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub redirect_stderr: Option<&'a str>,
/// Provide dagger access to the executed command.
/// Do not use this option unless you trust the command being executed.
/// The command being executed WILL BE GRANTED FULL ACCESS TO YOUR HOST FILESYSTEM.
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub experimental_privileged_nesting: Option<bool>,
}
#[derive(Builder, Debug, PartialEq)]
pub struct ContainerExportOpts {
/// Identifiers for other platform specific containers.
/// Used for multi-platform image.
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub platform_variants: Option<Vec<ContainerId>>,
}
#[derive(Builder, Debug, PartialEq)]
pub struct ContainerPipelineOpts<'a> {
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub description: Option<&'a str>,
}
#[derive(Builder, Debug, PartialEq)]
pub struct ContainerPublishOpts {
/// Identifiers for other platform specific containers.
/// Used for multi-platform image.
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub platform_variants: Option<Vec<ContainerId>>,
}
#[derive(Builder, Debug, PartialEq)]
pub struct ContainerWithDefaultArgsOpts<'a> {
/// Arguments to prepend to future executions (e.g., ["-v", "--no-cache"]).
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub args: Option<Vec<&'a str>>,
}
#[derive(Builder, Debug, PartialEq)]
pub struct ContainerWithDirectoryOpts<'a> {
/// Patterns to exclude in the written directory (e.g., ["node_modules/**", ".gitignore", ".git/"]).
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub exclude: Option<Vec<&'a str>>,
/// Patterns to include in the written directory (e.g., ["*.go", "go.mod", "go.sum"]).
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub include: Option<Vec<&'a str>>,
}
#[derive(Builder, Debug, PartialEq)]
pub struct ContainerWithExecOpts<'a> {
/// Content to write to the command's standard input before closing (e.g., "Hello world").
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub stdin: Option<&'a str>,
/// Redirect the command's standard output to a file in the container (e.g., "/tmp/stdout").
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub redirect_stdout: Option<&'a str>,
/// Redirect the command's standard error to a file in the container (e.g., "/tmp/stderr").
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub redirect_stderr: Option<&'a str>,
/// Provides dagger access to the executed command.
/// Do not use this option unless you trust the command being executed.
/// The command being executed WILL BE GRANTED FULL ACCESS TO YOUR HOST FILESYSTEM.
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub experimental_privileged_nesting: Option<bool>,
}
#[derive(Builder, Debug, PartialEq)]
pub struct ContainerWithExposedPortOpts<'a> {
/// Transport layer network protocol
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub protocol: Option<NetworkProtocol>,
/// Optional port description
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub description: Option<&'a str>,
}
#[derive(Builder, Debug, PartialEq)]
pub struct ContainerWithFileOpts {
/// Permission given to the copied file (e.g., 0600).
/// Default: 0644.
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub permissions: Option<isize>,
}
#[derive(Builder, Debug, PartialEq)]
pub struct ContainerWithMountedCacheOpts {
/// Identifier of the directory to use as the cache volume's root.
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub source: Option<DirectoryId>,
/// Sharing mode of the cache volume.
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub sharing: Option<CacheSharingMode>,
}
#[derive(Builder, Debug, PartialEq)]
pub struct ContainerWithNewFileOpts<'a> {
/// Content of the file to write (e.g., "Hello world!").
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub contents: Option<&'a str>,
/// Permission given to the written file (e.g., 0600).
/// Default: 0644.
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub permissions: Option<isize>,
}
#[derive(Builder, Debug, PartialEq)]
pub struct ContainerWithoutExposedPortOpts {
/// Port protocol to unexpose
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub protocol: Option<NetworkProtocol>,
}
@@ -1371,57 +1371,57 @@ pub struct Directory {
pub struct DirectoryDockerBuildOpts<'a> {
/// Path to the Dockerfile to use (e.g., "frontend.Dockerfile").
/// Defaults: './Dockerfile'.
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub dockerfile: Option<&'a str>,
/// The platform to build.
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub platform: Option<Platform>,
/// Build arguments to use in the build.
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub build_args: Option<Vec<BuildArg>>,
/// Target build stage to build.
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub target: Option<&'a str>,
}
#[derive(Builder, Debug, PartialEq)]
pub struct DirectoryEntriesOpts<'a> {
/// Location of the directory to look at (e.g., "/src").
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub path: Option<&'a str>,
}
#[derive(Builder, Debug, PartialEq)]
pub struct DirectoryPipelineOpts<'a> {
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub description: Option<&'a str>,
}
#[derive(Builder, Debug, PartialEq)]
pub struct DirectoryWithDirectoryOpts<'a> {
/// Exclude artifacts that match the given pattern (e.g., ["node_modules/", ".git*"]).
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub exclude: Option<Vec<&'a str>>,
/// Include only artifacts that match the given pattern (e.g., ["app/", "package.*"]).
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub include: Option<Vec<&'a str>>,
}
#[derive(Builder, Debug, PartialEq)]
pub struct DirectoryWithFileOpts {
/// Permission given to the copied file (e.g., 0600).
/// Default: 0644.
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub permissions: Option<isize>,
}
#[derive(Builder, Debug, PartialEq)]
pub struct DirectoryWithNewDirectoryOpts {
/// Permission granted to the created directory (e.g., 0777).
/// Default: 0755.
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub permissions: Option<isize>,
}
#[derive(Builder, Debug, PartialEq)]
pub struct DirectoryWithNewFileOpts {
/// Permission given to the copied file (e.g., 0600).
/// Default: 0644.
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub permissions: Option<isize>,
}
@@ -1948,9 +1948,9 @@ pub struct GitRef {
#[derive(Builder, Debug, PartialEq)]
pub struct GitRefTreeOpts<'a> {
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub ssh_known_hosts: Option<&'a str>,
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub ssh_auth_socket: Option<SocketId>,
}
@@ -2077,19 +2077,19 @@ pub struct Host {
#[derive(Builder, Debug, PartialEq)]
pub struct HostDirectoryOpts<'a> {
/// Exclude artifacts that match the given pattern (e.g., ["node_modules/", ".git*"]).
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub exclude: Option<Vec<&'a str>>,
/// Include only artifacts that match the given pattern (e.g., ["app/", "package.*"]).
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub include: Option<Vec<&'a str>>,
}
#[derive(Builder, Debug, PartialEq)]
pub struct HostWorkdirOpts<'a> {
/// Exclude artifacts that match the given pattern (e.g., ["node_modules/", ".git*"]).
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub exclude: Option<Vec<&'a str>>,
/// Include only artifacts that match the given pattern (e.g., ["app/", "package.*"]).
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub include: Option<Vec<&'a str>>,
}
@@ -2343,39 +2343,39 @@ pub struct Query {
#[derive(Builder, Debug, PartialEq)]
pub struct QueryContainerOpts {
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub id: Option<ContainerId>,
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub platform: Option<Platform>,
}
#[derive(Builder, Debug, PartialEq)]
pub struct QueryDirectoryOpts {
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub id: Option<DirectoryId>,
}
#[derive(Builder, Debug, PartialEq)]
pub struct QueryGitOpts {
/// Set to true to keep .git directory.
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub keep_git_dir: Option<bool>,
/// A service which must be started before the repo is fetched.
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub experimental_service_host: Option<ContainerId>,
}
#[derive(Builder, Debug, PartialEq)]
pub struct QueryHttpOpts {
/// A service which must be started before the URL is fetched.
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub experimental_service_host: Option<ContainerId>,
}
#[derive(Builder, Debug, PartialEq)]
pub struct QueryPipelineOpts<'a> {
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub description: Option<&'a str>,
}
#[derive(Builder, Debug, PartialEq)]
pub struct QuerySocketOpts {
#[builder(setter(into, strip_option))]
#[builder(setter(into, strip_option), default)]
pub id: Option<SocketId>,
}
@@ -2720,6 +2720,6 @@ pub enum CacheSharingMode {
}
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
pub enum NetworkProtocol {
TCP,
UDP,
TCP,
}

View File

@@ -1,3 +1,5 @@
#![deny(warnings)]
mod client;
mod gen;
mod querybuilder;

View File

@@ -1,4 +1,5 @@
use dagger_sdk::{connect, ContainerExecOptsBuilder};
use dagger_sdk::{connect, ContainerExecOpts, ContainerExecOptsBuilder};
use pretty_assertions::assert_eq;
#[tokio::test]
async fn test_example_container() {
@@ -19,3 +20,99 @@ async fn test_example_container() {
assert_eq!(out, "3.16.2\n".to_string())
}
#[tokio::test]
async fn test_directory() {
let c = connect().await.unwrap();
let contents = c
.directory()
.with_new_file("/hello.txt", "world")
.file("/hello.txt")
.contents()
.await
.unwrap();
assert_eq!("world", contents)
}
#[tokio::test]
async fn test_git() {
let c = connect().await.unwrap();
let tree = c.git("github.com/dagger/dagger").branch("main").tree();
let _ = tree
.entries()
.await
.unwrap()
.iter()
.find(|f| f.as_str() == "README.md")
.unwrap();
let readme_file = tree.file("README.md");
let readme = readme_file.contents().await.unwrap();
assert_eq!(true, readme.find("Dagger").is_some());
let readme_id = readme_file.id().await.unwrap();
let other_readme = c.file(readme_id).contents().await.unwrap();
assert_eq!(readme, other_readme);
}
#[tokio::test]
async fn test_container() {
let client = connect().await.unwrap();
let alpine = client.container().from("alpine:3.16.2");
let contents = alpine
.fs()
.file("/etc/alpine-release")
.contents()
.await
.unwrap();
assert_eq!(contents, "3.16.2\n".to_string());
let out = alpine
.exec_opts(
ContainerExecOptsBuilder::default()
.args(vec!["cat", "/etc/alpine-release"])
.build()
.unwrap(),
)
.stdout()
.await
.unwrap();
assert_eq!(out, "3.16.2\n".to_string());
let id = alpine.id().await.unwrap();
let contents = client
.container_opts(dagger_sdk::QueryContainerOpts {
id: Some(id),
platform: None,
})
.fs()
.file("/etc/alpine-release")
.contents()
.await
.unwrap();
assert_eq!(contents, "3.16.2\n".to_string());
}
#[tokio::test]
async fn test_err_message() {
let client = connect().await.unwrap();
let alpine = client.container().from("fake.invalid:latest").id().await;
assert_eq!(alpine.is_err(), true);
let err = alpine.expect_err("Tests expect err");
let error_msg = r#"
GQLClient Error: Look at json field for more details
Message: pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed
"#;
assert_eq!(err.to_string().as_str(), error_msg);
}