Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(website,cli,serverless): introduce production/preview deployments #238

Merged
merged 10 commits into from Nov 5, 2022
6 changes: 6 additions & 0 deletions .changeset/heavy-terms-grow.md
@@ -0,0 +1,6 @@
---
'@lagon/cli': patch
'@lagon/docs': patch
---

Add --prod option to `lagon deploy`
6 changes: 6 additions & 0 deletions .changeset/rich-lies-pull.md
@@ -0,0 +1,6 @@
---
'@lagon/serverless': patch
'@lagon/website': patch
---

Add production/preview deployments
15 changes: 12 additions & 3 deletions packages/cli/src/commands/deploy.rs
Expand Up @@ -57,7 +57,7 @@ pub async fn deploy(
file: PathBuf,
client: Option<PathBuf>,
public_dir: Option<PathBuf>,
_force: bool,
prod: bool,
) -> Result<()> {
let config = Config::new()?;

Expand Down Expand Up @@ -112,8 +112,15 @@ pub async fn deploy(
organization_id: organization.id.clone(),
})?;

create_deployment(function.id.clone(), &file, &client, &public_dir, &config)
.await?;
create_deployment(
function.id.clone(),
&file,
&client,
&public_dir,
&config,
prod,
)
.await?;
}
false => {
let name = Input::<String>::new()
Expand Down Expand Up @@ -149,6 +156,7 @@ pub async fn deploy(
&client,
&public_dir,
&config,
prod,
)
.await?;
}
Expand All @@ -163,6 +171,7 @@ pub async fn deploy(
&client,
&public_dir,
&config,
prod,
)
.await
}
Expand Down
10 changes: 5 additions & 5 deletions packages/cli/src/main.rs
Expand Up @@ -42,9 +42,9 @@ enum Commands {
/// Path to the public directory to serve assets from
#[clap(short, long, value_parser)]
public_dir: Option<PathBuf>,
/// Force the creation of a new Function
#[clap(short, long)]
force: bool,
/// Deploy as a production deployment
#[clap(visible_alias = "production", long)]
prod: bool,
},
/// Undeploy an existing Function
Undeploy {
Expand Down Expand Up @@ -99,8 +99,8 @@ async fn main() {
file,
client,
public_dir,
force,
} => commands::deploy(file, client, public_dir, force).await,
prod,
} => commands::deploy(file, client, public_dir, prod).await,
Commands::Undeploy { file } => commands::undeploy(file).await,
Commands::Dev {
file,
Expand Down
12 changes: 5 additions & 7 deletions packages/cli/src/utils/deployments.rs
Expand Up @@ -171,12 +171,12 @@ struct CreateDeploymentResponse {
struct DeployDeploymentRequest {
function_id: String,
deployment_id: String,
is_production: bool,
}

#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
struct DeployDeploymentResponse {
function_name: String,
url: String,
}

pub async fn create_deployment(
Expand All @@ -185,6 +185,7 @@ pub async fn create_deployment(
client: &Option<PathBuf>,
public_dir: &PathBuf,
config: &Config,
prod: bool,
) -> Result<()> {
let (index, assets) = bundle_function(file, client, public_dir)?;

Expand Down Expand Up @@ -240,18 +241,15 @@ pub async fn create_deployment(
DeployDeploymentRequest {
function_id,
deployment_id,
is_production: prod,
},
)
.await?;

println!();
println!("{}", success("Function deployed!"));
println!();
println!(
" {} https://{}.lagon.app",
"➤".black(),
response.result.data.function_name.blue()
);
println!(" {} {}", "➤".black(), response.result.data.url.blue());
println!();

Ok(())
Expand Down
27 changes: 16 additions & 11 deletions packages/docs/pages/cli.mdx
@@ -1,11 +1,13 @@
import { Callout, Collapse } from 'nextra-theme-docs'
import { Callout, Collapse } from 'nextra-theme-docs';

The easiest way to deploy and manage Functions is through our [Command-line interface](https://en.wikipedia.org/wiki/Command-line_interface).

## Installation

<Callout type="warning">
The CLI is not stable yet, so you might encounter bugs. Please [open an issue](https://github.com/lagonapp/lagon/issues/new?assignees=&labels=bug&template=bug_report.md&title=) if it's the case.
The CLI is not stable yet, so you might encounter bugs. Please [open an
issue](https://github.com/lagonapp/lagon/issues/new?assignees=&labels=bug&template=bug_report.md&title=) if it's the
case.
</Callout>

Lagon CLI is available for the following operating systems:
Expand All @@ -26,10 +28,10 @@ pnpm install --global @lagon/cli
```

<Callout type="info">
You will also be able to install it through [Cargo](https://doc.rust-lang.org/stable/cargo/) - Rust's package manager - soon.
You will also be able to install it through [Cargo](https://doc.rust-lang.org/stable/cargo/) - Rust's package manager
- soon.
</Callout>


## Usage

Once installed, execute the `lagon` CLI to see all the commands available.
Expand All @@ -50,14 +52,15 @@ To proceed, run `lagon logout` and follow the instructions.

Create a new Function or a new Deployment for the given files. Make sure you are [logged in](#lagon-login) before proceeding. If you are executing the command for the first time:

1) You will be prompted to select an Organization
2) You will be able to link to an existing Function, or create a new one by specifying a name
1. You will be prompted to select an Organization
2. You will be able to link to an existing Function, or create a new one by specifying a name

If you then want to trigger a new Deployment, re-run the same command. This command accept the following arguments and options:

- `<FILE>` is the only required argument. It should be the path to a file containing and exporting a Function.
- `--client, -c <CLIENT>` allows you to specify a path to an additional file to bundle as a client-side script.
- `--public, -p <CLIENT>` allows you to specify a path a custom assets directory, that will be served at the root (`/`) of the Function. (Default: `public`)
- `--production, --prod` allows you to deploy the Function in production mode. (Default: `false`)

Examples:

Expand All @@ -69,7 +72,8 @@ lagon deploy ./server.tsx --client App.tsx --public ./assets
### `lagon undeploy`

<Callout type="error">
Un-deploying a Function deletes permanently all of its Deployments, statistics and logs. You will be prompted to confirm before continuing.
Un-deploying a Function deletes permanently all of its Deployments, statistics and logs. You will be prompted to
confirm before continuing.
</Callout>

Un-deploy completely a Function. Make sure you are [logged in](#lagon-login) before proceeding. This command accept only one argument:
Expand All @@ -80,7 +84,7 @@ Example:

```bash
lagon undeploy ./index.ts
````
```

### `lagon dev`

Expand All @@ -93,7 +97,9 @@ This command accept the same arguments and options as `lagon deploy` and `lagon
- `--env <PATH>` allows you to specify an environment file (typically `.env`) to use to inject environment variables.

<Callout type="warning">
Although the `dev` command uses the exact same Runtime as when deployed, the local HTTP server itself doesn't have the same optimizations. As such, you shouldn't run a production environment on it, or run any kind of load tests/benchmarks.
Although the `dev` command uses the exact same Runtime as when deployed, the local HTTP server itself doesn't have the
same optimizations. As such, you shouldn't run a production environment on it, or run any kind of load
tests/benchmarks.
</Callout>

Examples:
Expand Down Expand Up @@ -123,9 +129,8 @@ If you are [self-hosting](/self-hosted/installation) Lagon, you will need to upd
```json
{
"token": "**************",
"site_url":"https://dash.lagon.app" // Replace this field
"site_url": "https://dash.lagon.app" // Replace this field
}
```

Replace the `site_url` field by the one configured during the installation. To verify if it's working correctly, login to your installation using `lagon login`.

6 changes: 2 additions & 4 deletions packages/docs/pages/index.mdx
@@ -1,10 +1,8 @@
import { Callout } from 'nextra-theme-docs'
import { Callout } from 'nextra-theme-docs';

Lagon is a free Open Source Runtime and SaaS that make it easy to deploy TypeScript and JavaScript Serverless Functions at the Edge, using V8 Isolates. It's also self-hostable.

<Callout type="warning">
Lagon is still in heavy development. Do not use for production usages.
</Callout>
<Callout type="warning">Lagon is still in heavy development. Do not use for production usages.</Callout>

Current status:

Expand Down
14 changes: 5 additions & 9 deletions packages/docs/pages/runtime-apis.mdx
@@ -1,4 +1,4 @@
import { Callout } from 'nextra-theme-docs'
import { Callout } from 'nextra-theme-docs';

The following APIs are the same as the Web APIS you already know. Additionally, we follow the [WinterCG](https://wintercg.org/) conventions.

Expand All @@ -8,7 +8,7 @@ The only required code to make your Function runnable is to export a `handler` f

```typescript
export function handler(request: Request): Response {
return new Response('Hello World!')
return new Response('Hello World!');
}
```

Expand Down Expand Up @@ -36,7 +36,7 @@ Example:

```typescript
export function handler(request: Request): Response {
return new Response(`My secret is: ${process.env.SECRET}`)
return new Response(`My secret is: ${process.env.SECRET}`);
}
```

Expand All @@ -50,9 +50,7 @@ The standard `TextDecoder` object. [See the documentation on MDN](https://develo

### Fetch

<Callout type="info">
Looking for the `fetch()` method? [Jump to fetch()](#fetch-1).
</Callout>
<Callout type="info">Looking for the `fetch()` method? [Jump to fetch()](#fetch-1).</Callout>

#### `Request`

Expand All @@ -69,9 +67,7 @@ You can pass a [`ReadableStream`](#readablestream) object as the `body` of a `Re

The standard `URL` object. [See the documentation on MDN](https://developer.mozilla.org/en-US/docs/Web/API/URL).

<Callout type="warning">
This URL implementation only supports URLs with a scheme.
</Callout>
<Callout type="warning">This URL implementation only supports URLs with a scheme.</Callout>

#### `URLSearchParams`

Expand Down
23 changes: 15 additions & 8 deletions packages/serverless/src/deployments/mod.rs
Expand Up @@ -31,6 +31,7 @@ pub struct Deployment {
pub environment_variables: HashMap<String, String>,
pub memory: usize, // in MB (MegaBytes)
pub timeout: usize, // in ms (MilliSeconds)
pub is_production: bool,
}

impl Deployment {
Expand All @@ -43,13 +44,16 @@ impl Deployment {
dotenv::var("LAGON_ROOT_DOMAIN").expect("LAGON_ROOT_DOMAIN must be set")
));

// TODO: should only set function name and domains deployments when deployment is the production one
domains.push(format!(
"{}.{}",
self.function_name,
dotenv::var("LAGON_ROOT_DOMAIN").expect("LAGON_ROOT_DOMAIN must be set")
));
domains.extend(self.domains.clone());
// Default domain (function's name) and custom domains are only set in production deployments
if self.is_production {
domains.push(format!(
"{}.{}",
self.function_name,
dotenv::var("LAGON_ROOT_DOMAIN").expect("LAGON_ROOT_DOMAIN must be set")
));

domains.extend(self.domains.clone());
}

domains
}
Expand All @@ -67,6 +71,7 @@ pub async fn get_deployments(
r"
SELECT
Deployment.id,
Deployment.isProduction,
Function.id,
Function.name,
Function.memory,
Expand All @@ -82,8 +87,9 @@ pub async fn get_deployments(
LEFT JOIN Asset
ON Deployment.id = Asset.deploymentId
",
|(id, function_id, function_name, memory, timeout, domain, asset): (
|(id, is_production, function_id, function_name, memory, timeout, domain, asset): (
String,
bool,
String,
String,
usize,
Expand Down Expand Up @@ -123,6 +129,7 @@ pub async fn get_deployments(
environment_variables: HashMap::new(),
memory,
timeout,
is_production,
});
},
)?;
Expand Down