Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
**/node_modules
**/bg-jobs

command/

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
name: Publish CI image
name: Publish mono image

on:
workflow_dispatch:
schedule:
- cron: '0 17 * * *'
push:
paths:
- '.github/workflows/ci-image.yml'
- 'conf/ci.conf'
- 'docker/ci.Dockerfile'
- '.github/workflows/mono-image.yml'
- 'conf/mono.conf'
- 'docker/mono.Dockerfile'

jobs:
build-and-publish:
Expand Down Expand Up @@ -61,11 +61,13 @@ jobs:
images: ghcr.io/${{ github.repository }}

- name: Build and push Docker image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
file: docker/ci.Dockerfile
file: docker/mono.Dockerfile
push: true
cache-from: type=gha
cache-to: type=gha,mode=max
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

Lichess development environment using Docker Compose, for developing on Mac, Linux, or Windows (via WSL).

The only requirements for running on your local machine are `git` and Docker Desktop. All the other dependencies (Scala, MongoDB, Node.js, etc) are installed and run in Docker containers.
The only requirement for running on your local machine is Docker Desktop, and optionally git. All the other dependencies (Scala, MongoDB, Node.js, etc) are installed and run in Docker containers.

![image](https://github.com/user-attachments/assets/0192574a-4cb7-42da-a19e-e75af24b0565)

Expand Down
157 changes: 95 additions & 62 deletions command/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const DEFAULT_PASSWORD: &str = "password";

#[derive(Serialize, Deserialize, Debug, Default)]
struct Config {
quick_setup: Option<bool>,
compose_profiles: Option<Vec<String>>,
setup_database: Option<bool>,
setup_bbppairings: Option<bool>,
Expand Down Expand Up @@ -74,6 +75,7 @@ impl Config {

fn to_env(&self) -> String {
let Self {
quick_setup,
compose_profiles,
setup_database,
setup_bbppairings,
Expand All @@ -92,6 +94,7 @@ impl Config {
.unwrap_or_default();

vec![
to_env!(quick_setup),
to_env!(compose_profiles, compose_profiles_string),
to_env!(setup_database),
to_env!(setup_bbppairings),
Expand Down Expand Up @@ -225,6 +228,12 @@ fn pwd_input(user_type: &str) -> std::io::Result<String> {
.interact()
}

#[derive(Debug, Clone, Eq, PartialEq)]
enum SetupMethod {
Quick,
Advanced,
}

#[allow(clippy::too_many_lines)]
fn setup(mut config: Config, first_setup: bool, noninteractive: bool) -> std::io::Result<()> {
if first_setup {
Expand All @@ -238,7 +247,31 @@ fn setup(mut config: Config, first_setup: bool, noninteractive: bool) -> std::io

let mut services: Vec<OptionalService<'static>> = vec![];

if noninteractive {
info(
[
"Your Lichess development site will include a basic instance of Lichess.",
"You will be able to use the site, play games, and test most of the main functionality.",
"If you want additional features, you can select them here.",
]
.join("\n"),
)?;
let is_quick_setup = noninteractive
|| select("Choose a setup method:")
.item(
SetupMethod::Quick,
"Quick",
"If you just want a basic lila instance without making any code changes",
)
.item(
SetupMethod::Advanced,
"Advanced",
"If you want to make changes or test specific features",
)
.interact()?
== SetupMethod::Quick;
config.quick_setup = Some(is_quick_setup);

if noninteractive || is_quick_setup {
config.password = Some(DEFAULT_PASSWORD.to_string());
config.su_password = Some(DEFAULT_PASSWORD.to_string());
config.setup_api_tokens = Some(true);
Expand Down Expand Up @@ -270,14 +303,6 @@ fn setup(mut config: Config, first_setup: bool, noninteractive: bool) -> std::io
config.su_password = Some(su_password);
config.password = Some(password);

if Gitpod::is_host()
&& confirm("By default, only this browser session can access your Gitpod development site.\nWould you like it to be accessible to other clients?")
.initial_value(false)
.interact()?
{
gitpod_public()?;
}

config.setup_bbppairings = Some(
services
.iter()
Expand All @@ -297,6 +322,15 @@ fn setup(mut config: Config, first_setup: bool, noninteractive: bool) -> std::io
);
}

if Gitpod::is_host()
&& !noninteractive
&& confirm("By default, only this browser session can access your Lichess development site.\nWould you like it to be accessible to other clients?")
.initial_value(false)
.interact()?
{
gitpod_public()?;
}

let selected_profiles: Vec<String> = services
.iter()
.filter_map(|service| service.compose_profile.as_ref())
Expand All @@ -308,6 +342,11 @@ fn setup(mut config: Config, first_setup: bool, noninteractive: bool) -> std::io
if !first_setup {
profiles.extend(config.compose_profiles.unwrap_or_default());
}
if is_quick_setup {
profiles.push("quick".to_string());
} else {
profiles.push("base".to_string());
}
profiles.sort();
profiles.dedup();

Expand All @@ -321,52 +360,54 @@ fn setup(mut config: Config, first_setup: bool, noninteractive: bool) -> std::io

config.save()?;

create_placeholder_dirs();
if !is_quick_setup {
create_placeholder_dirs();

let mut repos_to_clone: Vec<Repository> = vec![
Repository::new("lichess-org", "lila"),
Repository::new("lichess-org", "lila-ws"),
];

if config.setup_database.unwrap_or_default() {
repos_to_clone.push(Repository::new("lichess-org", "lila-db-seed"));
}
let mut repos_to_clone: Vec<Repository> = vec![
Repository::new("lichess-org", "lila"),
Repository::new("lichess-org", "lila-ws"),
];

let optional_repos: Vec<Repository> = services
.iter()
.filter_map(|service| service.repositories.clone())
.flatten()
.collect();
if config.setup_database.unwrap_or_default() {
repos_to_clone.push(Repository::new("lichess-org", "lila-db-seed"));
}

repos_to_clone.extend(optional_repos);
let optional_repos: Vec<Repository> = services
.iter()
.filter_map(|service| service.repositories.clone())
.flatten()
.collect();

for repo in repos_to_clone {
let progress = spinner();
progress.start(format!("Cloning {}...", repo.full_name()));
repos_to_clone.extend(optional_repos);

if repo.clone_path().read_dir()?.next().is_some() {
progress.stop(format!("✓ Already cloned {}", repo.full_name()));
continue;
}
for repo in repos_to_clone {
let progress = spinner();
progress.start(format!("Cloning {}...", repo.full_name()));

let mut cmd = Command::new("git");
cmd.arg("clone")
.arg("--origin")
.arg("upstream")
.arg("--depth")
.arg("1")
.arg("--recurse-submodules")
.arg(repo.url())
.arg(repo.clone_path());

let output = cmd.output()?;
assert!(
output.status.success(),
"Failed to clone repo: {} - {output:?}",
repo.full_name()
);
if repo.clone_path().read_dir()?.next().is_some() {
progress.stop(format!("✓ Already cloned {}", repo.full_name()));
continue;
}

progress.stop(format!("✓ Cloned {}", repo.full_name()));
let mut cmd = Command::new("git");
cmd.arg("clone")
.arg("--origin")
.arg("upstream")
.arg("--depth")
.arg("1")
.arg("--recurse-submodules")
.arg(repo.url())
.arg(repo.clone_path());

let output = cmd.output()?;
assert!(
output.status.success(),
"Failed to clone repo: {} - {output:?}",
repo.full_name()
);

progress.stop(format!("✓ Cloned {}", repo.full_name()));
}
}

if Gitpod::is_host() {
Expand Down Expand Up @@ -448,14 +489,6 @@ fn gitpod_checkout_pr() -> std::io::Result<()> {

#[allow(clippy::too_many_lines)]
fn prompt_for_services() -> Result<Vec<OptionalService<'static>>, Error> {
info(
[
"Your Lichess development site will include a basic instance of Lichess.",
"You will be able to use the site, play games, and test most of the main functionality.",
"If you want additional features, you can select them here.",
]
.join("\n"),
)?;
multiselect(
"Select which optional services to include:\n (Use arrows, <space> to toggle, <enter> to continue)\n",
)
Expand Down Expand Up @@ -662,10 +695,10 @@ fn hostname(mut config: Config) -> std::io::Result<()> {
}

fn welcome(config: Config) -> std::io::Result<()> {
intro("Your Lichess development environment is starting!")?;
intro("Your Lichess instance is starting!")?;

note(
"Your development site will be available at:",
"The site will be available at:",
config
.lila_url
.unwrap_or("http://localhost:8080".to_owned()),
Expand All @@ -683,10 +716,7 @@ fn welcome(config: Config) -> std::io::Result<()> {
)?;
}

note(
"To monitor the progress:",
"docker compose logs lila --follow",
)?;
note("To monitor the progress:", "./lila-docker logs")?;

outro("🚀")
}
Expand Down Expand Up @@ -742,6 +772,7 @@ mod tests {
#[test]
fn test_set_env_vars_from_struct() {
let contents = Config {
quick_setup: Some(true),
compose_profiles: Some(vec!["foo".to_string(), "bar".to_string()]),
setup_database: Some(true),
setup_bbppairings: Some(false),
Expand All @@ -759,6 +790,7 @@ mod tests {
assert_eq!(
contents,
vec![
"QUICK_SETUP=true",
"COMPOSE_PROFILES=foo,bar",
"SETUP_DATABASE=true",
"SETUP_BBPPAIRINGS=false",
Expand All @@ -778,6 +810,7 @@ mod tests {
#[test]
fn test_env_removes_empty_lines() {
let contents = Config {
quick_setup: None,
compose_profiles: None,
setup_database: None,
setup_bbppairings: None,
Expand Down
7 changes: 0 additions & 7 deletions conf/ci.conf

This file was deleted.

16 changes: 16 additions & 0 deletions conf/mono.Caddyfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
:8080

@websockets {
header Connection *Upgrade*
header Upgrade websocket
}

handle_errors 502 {
root * /errors
rewrite * /502.html
file_server
}

reverse_proxy @websockets :9664

reverse_proxy :9663
11 changes: 11 additions & 0 deletions conf/mono.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
include "base"
include "version"

user.password.bpass.secret = "9qEYN0ThHer1KWLNekA76Q=="

net.site.name = "lila-docker"
net.domain = ${?LILA_DOMAIN}
net.socket.domains = [ ${?LILA_DOMAIN} ]
net.asset.base_url = ${?LILA_URL}
net.base_url = ${?LILA_URL}
net.ratelimit = false
Loading