Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
50e0bd6
fixture.ml: more tests
monadius May 30, 2022
fe490bb
Dockerfile for OCaml 4.14
monadius Jun 13, 2022
f8c239d
Add DockerOcamlbuild: Ubuntu 22.04 + OCaml 5.0 + ocamlbuild
monadius Apr 4, 2023
18b7d85
Add examples
monadius Apr 4, 2023
f7306b1
Remove fixture.ml and update test.ml and _tags
monadius Apr 4, 2023
c67b5a2
Add script files to build and run containers
monadius Apr 4, 2023
c248cc5
Rename test.ml to cwtest.ml and add an empty cwtest.mli
monadius Apr 4, 2023
2efbb11
Improve the batteries example
monadius Apr 5, 2023
b323760
Add the "compile-error" example
monadius Apr 5, 2023
b51bb85
Install the Base package
monadius Apr 5, 2023
2ad12d0
Add examples/base
monadius Apr 5, 2023
d58cd05
Add the domainslib package
monadius Apr 5, 2023
cf1e83e
Add examples/domainslib
monadius Apr 5, 2023
d8baf27
Add the zarith package
monadius Apr 5, 2023
f8310b7
Add examples/zarith
monadius Apr 5, 2023
38c1d6c
Use a multistage docker build
monadius Apr 6, 2023
880e332
Dockerfile: manually install opam and use Alpine-3.17
monadius Apr 7, 2023
bbde56c
Misc updates
monadius Apr 9, 2023
da9c27f
Add bin/build and bin/run for building and running ocaml:latest
monadius Apr 9, 2023
ee8dcf3
Add examples/unix
monadius Apr 9, 2023
579a5ee
Add Ubuntu image files
monadius Apr 9, 2023
d4ea086
Update README
monadius Apr 10, 2023
9d542e8
Merge remote-tracking branch 'upstream/main' into 5.0
monadius Apr 10, 2023
e79d853
Update _tags: include ounit2 for all targets except solution.ml
monadius Apr 10, 2023
6979f91
Ubuntu is the default image
monadius Apr 18, 2023
27e09b3
Add workflows/ci.yml
monadius Apr 18, 2023
3a492d0
Add "--shell-setup" to "opam init"
monadius Apr 18, 2023
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
42 changes: 42 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: CI
on:
push:
branches:
- main
pull_request:

jobs:
build:
runs-on: ubuntu-latest
if: ${{ github.repository == 'codewars/ocaml' }}
steps:
- uses: actions/checkout@v2
- uses: docker/setup-buildx-action@v2

- name: Build image
uses: docker/build-push-action@v3
with:
context: .
push: false
# Make the image available in next step
load: true
tags: ghcr.io/codewars/ocaml:latest
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Run Batteries Example
run: bin/run examples/batteries

- name: Run Base Example (with failing tests)
run: bin/run examples/base

- name: Run Domainslib Example
run: bin/run examples/domainslib

- name: Run Zarith Example
run: bin/run examples/zarith

- name: Report Image Size
run: |
echo "## Image Size" >> $GITHUB_STEP_SUMMARY
docker image inspect --format '{{.Size}}' ghcr.io/codewars/ocaml:latest | numfmt --to=si --suffix=B >> $GITHUB_STEP_SUMMARY
80 changes: 48 additions & 32 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,48 +1,64 @@
FROM buildpack-deps:bionic
FROM ubuntu:22.04 AS Builder

RUN set -ex; \
useradd --create-home codewarrior; \
# TODO Remove symlink in the next version
ln -s /home/codewarrior /workspace;

ENV OPAMROOT=/opt/opam \
OPAMCOLOR=never
ENV OPAMROOT=/opt/ocaml

RUN set -ex; \
mkdir -p $OPAMROOT; \
useradd --create-home codewarrior; \
chown codewarrior:codewarrior $OPAMROOT; \
apt-get update; \
apt-get install -y --no-install-recommends \
software-properties-common \
m4 \
rsync \
aspcud \
; \
# Needed for opam 2.0
add-apt-repository -y ppa:avsm/ppa; \
libgmp-dev \
opam \
;

USER codewarrior
ENV USER=codewarrior

RUN set -ex; \
opam init -y --shell-setup --disable-sandboxing --compiler=5.0.0;

RUN set -ex; \
opam install -y \
'batteries=3.6.0' \
'base=v0.15.1' \
'domainslib=0.5.0' \
'ocamlbuild=0.14.2' \
'ocamlfind=1.9.6' \
'ounit2=2.2.7' \
'zarith=1.12' \
;

FROM ubuntu:22.04

RUN set -ex; \
apt-get update; \
apt-get install -y --no-install-recommends \
opam \
gcc \
libc6-dev \
libgmp-dev \
; \
rm -rf /var/lib/apt/lists/*;

USER codewarrior
ENV USER=codewarrior \
HOME=/home/codewarrior
COPY --from=builder \
/opt/ocaml/5.0.0/bin/ocamlc.opt \
/opt/ocaml/5.0.0/bin/ocamlopt.opt \
/opt/ocaml/5.0.0/bin/ocamldep.opt \
/opt/ocaml/5.0.0/bin/ocamlbuild \
/opt/ocaml/5.0.0/bin/ocamlfind \
/opt/ocaml/5.0.0/bin/
COPY --from=builder \
/opt/ocaml/5.0.0/lib/ /opt/ocaml/5.0.0/lib/

# --disable-sandboxing is needed to do this in a container witout `--privileged`
RUN opam init -y --compiler=4.07.1 --disable-sandboxing

ENV OPAM_SWITCH_PREFIX=/opt/opam/4.07.1 \
CAML_LD_LIBRARY_PATH=/opt/opam/4.07.1/lib/stublibs \
OCAML_TOPLEVEL_PATH=/opt/opam/4.07.1/lib/toplevel \
PATH=/opt/opam/4.07.1/bin:$PATH
RUN set -ex; \
useradd --create-home codewarrior; \
mkdir -p /workspace; \
chown -R codewarrior:codewarrior /workspace;

RUN opam install -y \
'ounit=2.0.8' \
'batteries=2.9.0' \
'core=v0.11.3' \
;
USER codewarrior
ENV USER=codewarrior \
PATH=/opt/ocaml/5.0.0/bin:$PATH

COPY workspace/test.ml /workspace/test.ml
COPY workspace/_tags /workspace/_tags
COPY --chown=codewarrior:codewarrior workspace/. /workspace/
WORKDIR /workspace
63 changes: 63 additions & 0 deletions DockerfileAlpine
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
FROM alpine:3.17 AS builder

ENV OPAMROOT=/opt/ocaml

RUN set -ex; \
mkdir -p $OPAMROOT; \
adduser -D codewarrior; \
chown -R codewarrior:codewarrior /opt/ocaml; \
apk update; \
apk add --virtual .build-deps \
build-base \
ocaml-compiler-libs \
gmp-dev \
opam \
;

USER codewarrior
ENV USER=codewarrior

RUN set -ex; \
opam init -y --shell-setup --disable-sandboxing --compiler=5.0.0;

RUN set -ex; \
opam install -y \
'batteries=3.6.0' \
'base=v0.15.1' \
'domainslib=0.5.0' \
'ocamlbuild=0.14.2' \
'ocamlfind=1.9.6' \
'ounit2=2.2.7' \
'zarith=1.12' \
;

FROM alpine:3.17

RUN set -ex; \
apk add --no-cache \
gcc \
gmp-dev \
musl-dev \
;

COPY --from=builder \
/opt/ocaml/5.0.0/bin/ocamlc.opt \
/opt/ocaml/5.0.0/bin/ocamlopt.opt \
/opt/ocaml/5.0.0/bin/ocamldep.opt \
/opt/ocaml/5.0.0/bin/ocamlbuild \
/opt/ocaml/5.0.0/bin/ocamlfind \
/opt/ocaml/5.0.0/bin/
COPY --from=builder \
/opt/ocaml/5.0.0/lib/ /opt/ocaml/5.0.0/lib/

RUN set -ex; \
adduser -D codewarrior; \
mkdir /workspace; \
chown -R codewarrior:codewarrior /workspace;

USER codewarrior
ENV USER=codewarrior \
PATH=/opt/ocaml/5.0.0/bin:$PATH

COPY --chown=codewarrior:codewarrior workspace/. /workspace/
WORKDIR /workspace
13 changes: 6 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,15 @@ Container image for OCaml used by CodeRunner.
## Usage

```bash
W=/workspace/
W=/workspace
# Create container
C=$(docker container create --rm -w $W ghcr.io/codewars/ocaml:latest \
sh -c 'ocamlbuild -quiet -use-ocamlfind test.native && exec ./test.native')
BUILD="ocamlbuild -quiet -use-ocamlfind cwtest.native"
C=$(docker container create --rm -w $W ghcr.io/codewars/ocaml:latest sh -c "$BUILD && exec ./cwtest.native")

# Write solution and tests in workspace/fixture.ml
# Then copy it inside a container
docker container cp workspace/fixture.ml $C:$W/fixture.ml
# Copy solution and test files
docker container cp ${1:-examples/basic}/. $C:$W

# Run tests
# Start
docker container start --attach $C
```

Expand Down
1 change: 1 addition & 0 deletions bin/alpine_build
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
docker build -f DockerfileAlpine -t ocaml:alpine .
2 changes: 2 additions & 0 deletions bin/alpine_run
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export IMAGE=ocaml:alpine
exec "$(dirname "$0")/run" "$@"
1 change: 1 addition & 0 deletions bin/build
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
docker build -t ghcr.io/codewars/ocaml:latest .
16 changes: 16 additions & 0 deletions bin/run
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
set -eu

if [ -z "${IMAGE:+x}" ]; then
IMAGE=ghcr.io/codewars/ocaml:latest
fi

W=/workspace
# Create container
BUILD="ocamlbuild -quiet -use-ocamlfind cwtest.native"
C=$(docker container create --rm -w $W $IMAGE sh -c "$BUILD && exec ./cwtest.native")

# Copy files
docker container cp ${1:-examples/basic}/. $C:$W

# Start
docker container start --attach $C
3 changes: 3 additions & 0 deletions examples/base/preloaded.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
open Base

let print_int_list = Fn.compose Sexp.to_string (sexp_of_list sexp_of_int)
3 changes: 3 additions & 0 deletions examples/base/solution.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
open Base

let cubes = List.map ~f:Int.(fun x -> x ** 3)
15 changes: 15 additions & 0 deletions examples/base/tests.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
open Base
open OUnit
open Preloaded

let suite = [
"cubes tests (passing)" >:::
[
"Testing [1; 2; 3]" >:: (fun _ -> assert_equal [1; 8; 27] (Solution.cubes (List.range 1 4)) ~printer:print_int_list);
"Testing [5]" >:: (fun _ -> assert_equal [125] (Solution.cubes [5]) ~printer:print_int_list);
];
"cubes tests (failing)" >:::
[
"Testing [1; 2; 3]" >:: (fun _ -> assert_equal [1; 8; 27] (Solution.cubes (List.range 1 5)) ~printer:print_int_list);
];
]
Empty file added examples/basic/preloaded.ml
Empty file.
1 change: 1 addition & 0 deletions examples/basic/solution.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
let is_even n = n mod 2 = 0
44 changes: 44 additions & 0 deletions examples/basic/tests.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
open Solution
open OUnit

let suite = [
"Top level test case" >:: (fun _ -> assert_equal false (is_even 1024));
"Test Odd" >:::
[
"Should return false for 1" >:: (fun _ -> assert_equal false (is_even 1));
"Should return false for 7" >:: (fun _ -> assert_equal false (is_even 7))
];
"Test even" >:::
[
"Should return true for 100" >:: (fun _ -> assert_equal true (is_even 100));
"Should return true for 42" >:: (fun _ -> assert_equal true (is_even 42))
];
"Test edge cases" >:::
[
"Test zero" >:::
[
"Should return true for 0" >:: (fun _ -> assert_equal true (is_even 0))
];
"Test -1" >:::
[
"Should return false for -1" >:: (fun _ -> assert_equal false (is_even (-1)))
]
];
"Unlabeled tests" >:::
[
TestCase (fun _ -> assert_equal false (is_even 100) ~msg:"Incorrect answer for n=100");
TestCase (fun _ -> assert_equal false (is_even 100) ~msg:"Incorrect answer for n=100");
TestList [
TestCase (fun _ -> assert_equal false (is_even 100) ~msg:"Incorrect answer for n=100");
TestCase (fun _ -> assert_equal false (is_even 100) ~msg:"Incorrect answer for n=100");
]

];
"Nested labels" >::: [
"Outer label" >: ("Inner label" >: ("Tests with nested labels" >::: [
TestCase (fun _ -> assert_equal false (is_even 100) ~msg:"Incorrect answer for n=100" ~printer: string_of_bool);
TestCase (fun _ -> assert_equal false (is_even 100) ~msg:"Incorrect answer for n=100" ~printer: string_of_bool);

]))
]
]
4 changes: 4 additions & 0 deletions examples/batteries/preloaded.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
open Batteries

let print_int = IO.to_string Int.print
let print_int_list = IO.to_string (List.print Int.print)
8 changes: 8 additions & 0 deletions examples/batteries/solution.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
open Batteries

let sum n =
(1 -- n)
|> Enum.map (fun i -> Num.num_of_int i |> Num.int_of_num)
|> Enum.sum

let cubes = List.map Int.(fun x -> x ** 3)
16 changes: 16 additions & 0 deletions examples/batteries/tests.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
open Batteries
open OUnit
open Preloaded

let suite = [
"sum tests" >:::
[
"Testing 1" >:: (fun _ -> assert_equal 1 (Solution.sum 1) ~printer:print_int);
"Testing 9" >:: (fun _ -> assert_equal 45 (Solution.sum 9) ~printer:print_int);
];
"cubes tests" >:::
[
"Testing [1; 2; 3]" >:: (fun _ -> assert_equal [1; 8; 27] (Solution.cubes ((1 -- 3) |> List.of_enum)) ~printer:print_int_list);
"Testing [5]" >:: (fun _ -> assert_equal [125] (Solution.cubes [5]) ~printer:print_int_list);
];
]
5 changes: 5 additions & 0 deletions examples/compile-error/solution.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
let sum n =
if n = 0 then
0
else
n + sum (n - 1)
9 changes: 9 additions & 0 deletions examples/compile-error/tests.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
open OUnit

let suite = [
"sum tests" >:::
[
"Testing 1" >:: (fun _ -> assert_equal 1 (Solution.sum 1) ~printer:string_of_int);
"Testing 9" >:: (fun _ -> assert_equal 45 (Solution.sum 9) ~printer:string_of_int);
];
]
Loading