From 8e42b400cae534e9be4f56751e4472bd7d3004b0 Mon Sep 17 00:00:00 2001
From: Aliaksandr Budzko <abudzko@takima.fr>
Date: Tue, 3 Aug 2021 17:03:06 +0200
Subject: [PATCH] initiate repo and add examle

---
 .gitlab-ci.yml                                |  21 ++++++++
 README.md                                     |   7 ++-
 build/build-image.sh                          |  45 ++++++++++++++++++
 build/parse_yaml.sh                           |  17 +++++++
 resources/code_palindrome_test/Dockerfile     |   6 +++
 resources/code_palindrome_test/challenge.yaml |  14 ++++++
 .../code_palindrome_test/docs/briefing.md     |   7 +++
 .../code_palindrome_test/docs/fr/briefing.md  |   7 +++
 .../code_palindrome_test/docs/fr/hint1.md     |   3 ++
 .../code_palindrome_test/docs/fr/hint2.md     |   3 ++
 resources/code_palindrome_test/docs/hint1.md  |   3 ++
 resources/code_palindrome_test/docs/hint2.md  |   3 ++
 resources/code_palindrome_test/run.sh         |   8 ++++
 .../src/main/java/app/Logger.java             |  38 +++++++++++++++
 .../src/main/java/app/Run.java                |  17 +++++++
 .../src/main/java/app/Solve.java              |  31 ++++++++++++
 .../src/main/java/success/Palindrome.java     |  10 ++++
 .../src/main/java/template/Palindrome.java    |  10 ++++
 resources/code_palindrome_test/thumbnail.png  | Bin 0 -> 14095 bytes
 19 files changed, 248 insertions(+), 2 deletions(-)
 create mode 100644 .gitlab-ci.yml
 create mode 100755 build/build-image.sh
 create mode 100644 build/parse_yaml.sh
 create mode 100755 resources/code_palindrome_test/Dockerfile
 create mode 100755 resources/code_palindrome_test/challenge.yaml
 create mode 100755 resources/code_palindrome_test/docs/briefing.md
 create mode 100644 resources/code_palindrome_test/docs/fr/briefing.md
 create mode 100644 resources/code_palindrome_test/docs/fr/hint1.md
 create mode 100644 resources/code_palindrome_test/docs/fr/hint2.md
 create mode 100755 resources/code_palindrome_test/docs/hint1.md
 create mode 100644 resources/code_palindrome_test/docs/hint2.md
 create mode 100755 resources/code_palindrome_test/run.sh
 create mode 100755 resources/code_palindrome_test/src/main/java/app/Logger.java
 create mode 100755 resources/code_palindrome_test/src/main/java/app/Run.java
 create mode 100755 resources/code_palindrome_test/src/main/java/app/Solve.java
 create mode 100644 resources/code_palindrome_test/src/main/java/success/Palindrome.java
 create mode 100644 resources/code_palindrome_test/src/main/java/template/Palindrome.java
 create mode 100755 resources/code_palindrome_test/thumbnail.png

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000..ced011b
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,21 @@
+stages:
+  - build
+
+build-images:
+  services:
+    - docker:19.03.12-dind
+  tags:
+    - api
+  stage: build
+  image: registry.e-biz.fr/apuret/deadlock-public/ci-deadlock-cli:1.2.4
+  script:
+    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
+    - ./build/build-image.sh $CI_REGISTRY_IMAGE
+  cache:
+    paths:
+      - resources/*/runner
+      - resources/*/.hash
+  only:
+    - master
+  tags:
+    - docker
diff --git a/README.md b/README.md
index 0f91ff9..69a1ee5 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,6 @@
-# Deadlock challenges example
+# Example of a private Deadlock challenges repository
+
+Feel free to inspire take it as a template and add your challenges.
+
+You can see how to create a Deadlock challenge [here](https://deadlock-resources.github.io/challenge-documentation/).
 
-An example custom Deadlock custom challenges repository.
\ No newline at end of file
diff --git a/build/build-image.sh b/build/build-image.sh
new file mode 100755
index 0000000..2d37e84
--- /dev/null
+++ b/build/build-image.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+
+# include parse_yaml function
+. ./build/parse_yaml.sh
+
+# Verify that docker daemon is up
+until docker ps > /dev/null; do
+    echo  "Waiting for docker daemon to wake up..."
+    sleep 2
+done
+
+# $1 gitlab registry name
+
+for d in resources/*/; do
+    # read yaml file
+    eval $(parse_yaml "$d/challenge.yaml" "mission_");
+    IMAGE_NAME="$mission_name:$mission_version";
+    echo "=============================================================================";
+    echo "> Checking if image $IMAGE_NAME exists in registry <";
+    # Careful experimental feature (docker manifest inspect), can be change in the future.
+    docker manifest inspect "$1/$IMAGE_NAME" > /dev/null && echo "> Found.. continue" && continue || true;
+
+    # go into the folder to keep relative path when executing script
+    cd $d
+
+    [ -f build.sh ] && echo "> Building challenge <" && ./build.sh
+    [ -f entry.rs ] && echo "> Building runner for metamorph challenge <" && dcli build .
+    echo "> Building Docker image $IMAGE_NAME <";
+    docker build . -q -t "$1/$IMAGE_NAME" && docker push "$1/$IMAGE_NAME" || exit 1
+    if [ -d "./services" ]; then
+        for s in ./services/*/; do
+            echo ">>> Checking service image $s <";
+            eval $(parse_yaml "./service.yaml" "service_");
+            IMAGE_SERVICE_NAME="$mission_name/$service_name:$mission_version";
+            docker manifest inspect "$1/$IMAGE_SERVICE_NAME" > /dev/null && echo "> Found.. continue" && continue || true;
+            echo ">>> Building service image $s <";
+            docker build $s -q -t "$1/$IMAGE_SERVICE_NAME";
+            docker push "$1/$IMAGE_SERVICE_NAME";
+        done
+    fi
+
+    # back to previous folder
+    cd -
+done
+
diff --git a/build/parse_yaml.sh b/build/parse_yaml.sh
new file mode 100644
index 0000000..ca35ceb
--- /dev/null
+++ b/build/parse_yaml.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+parse_yaml() {
+   local prefix=$2
+   local s='[[:space:]]*' w='[a-zA-Z0-9_]*' fs=$(echo @|tr @ '\034')
+   sed -ne "s|^\($s\)\($w\)$s:$s\"\(.*\)\"$s\$|\1$fs\2$fs\3|p" \
+        -e "s|^\($s\)\($w\)$s:$s\(.*\)$s\$|\1$fs\2$fs\3|p"  $1 |
+   awk -F$fs '{
+      indent = length($1)/2;
+      vname[indent] = $2;
+      for (i in vname) {if (i > indent) {delete vname[i]}}
+      if (length($3) > 0) {
+         vn=""; for (i=0; i<indent; i++) {vn=(vn)(vname[i])("_")}
+         printf("%s%s%s=\"%s\"\n", "'$prefix'",vn, $2, $3);
+      }
+   }'
+}
\ No newline at end of file
diff --git a/resources/code_palindrome_test/Dockerfile b/resources/code_palindrome_test/Dockerfile
new file mode 100755
index 0000000..df536fa
--- /dev/null
+++ b/resources/code_palindrome_test/Dockerfile
@@ -0,0 +1,6 @@
+FROM openjdk:8-jdk-slim
+WORKDIR /
+COPY src src
+COPY run.sh /
+RUN chmod +x run.sh
+ENTRYPOINT ["/run.sh"]
diff --git a/resources/code_palindrome_test/challenge.yaml b/resources/code_palindrome_test/challenge.yaml
new file mode 100755
index 0000000..325b215
--- /dev/null
+++ b/resources/code_palindrome_test/challenge.yaml
@@ -0,0 +1,14 @@
+version: 1.0
+name: code_palindrome_test
+label: Example exercice - palindrome
+description: Can you read it from whatever side
+level: jarjarbinks
+type: CODING
+xp:
+  java: 1
+  programming: 1
+coding:
+  templateDirectory: src/main/java/template
+  successDirectory: src/main/java/success
+  target: Palindrome.java
+  editorMode: java
diff --git a/resources/code_palindrome_test/docs/briefing.md b/resources/code_palindrome_test/docs/briefing.md
new file mode 100755
index 0000000..a8a6eae
--- /dev/null
+++ b/resources/code_palindrome_test/docs/briefing.md
@@ -0,0 +1,7 @@
+# Palindrome
+
+A Palindrome is a word that can be read indifferently from left or right or from right to left and keeps the same meaning.
+
+Exemple: eye
+
+You have to check if a given word is a palindrome or not.
\ No newline at end of file
diff --git a/resources/code_palindrome_test/docs/fr/briefing.md b/resources/code_palindrome_test/docs/fr/briefing.md
new file mode 100644
index 0000000..84a29eb
--- /dev/null
+++ b/resources/code_palindrome_test/docs/fr/briefing.md
@@ -0,0 +1,7 @@
+# Palindrome
+
+Un palindrome est un mot qui peut être lu indifféremment de gauche à droite ou de droite à gauche et qui conserve le même sens.
+
+Exemple: elle
+
+Tu dois vérifier pour un mot donné s'il s'agit d'un palindrome ou non.
\ No newline at end of file
diff --git a/resources/code_palindrome_test/docs/fr/hint1.md b/resources/code_palindrome_test/docs/fr/hint1.md
new file mode 100644
index 0000000..d99e48e
--- /dev/null
+++ b/resources/code_palindrome_test/docs/fr/hint1.md
@@ -0,0 +1,3 @@
+# Indice 1
+
+Regarde du côté du StringBuilder.
diff --git a/resources/code_palindrome_test/docs/fr/hint2.md b/resources/code_palindrome_test/docs/fr/hint2.md
new file mode 100644
index 0000000..8fa0a36
--- /dev/null
+++ b/resources/code_palindrome_test/docs/fr/hint2.md
@@ -0,0 +1,3 @@
+# Indice 2
+
+Tu peux aussi t'aider de l'API Stream pour les String.
\ No newline at end of file
diff --git a/resources/code_palindrome_test/docs/hint1.md b/resources/code_palindrome_test/docs/hint1.md
new file mode 100755
index 0000000..aa044e6
--- /dev/null
+++ b/resources/code_palindrome_test/docs/hint1.md
@@ -0,0 +1,3 @@
+# Hint 1
+
+Look into the functions of StringBuilder.
diff --git a/resources/code_palindrome_test/docs/hint2.md b/resources/code_palindrome_test/docs/hint2.md
new file mode 100644
index 0000000..5f3ebc3
--- /dev/null
+++ b/resources/code_palindrome_test/docs/hint2.md
@@ -0,0 +1,3 @@
+# Hint 2
+
+You can check the stream API for Strings.
\ No newline at end of file
diff --git a/resources/code_palindrome_test/run.sh b/resources/code_palindrome_test/run.sh
new file mode 100755
index 0000000..6bf4306
--- /dev/null
+++ b/resources/code_palindrome_test/run.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+set -e
+echo "Compiling java code"
+cd src/main/java
+javac -Xmaxerrs 1 app/*.java
+echo "Executing code"
+java -Xms32m -Xmx64m app/$1
+echo "Done"
diff --git a/resources/code_palindrome_test/src/main/java/app/Logger.java b/resources/code_palindrome_test/src/main/java/app/Logger.java
new file mode 100755
index 0000000..f4ed299
--- /dev/null
+++ b/resources/code_palindrome_test/src/main/java/app/Logger.java
@@ -0,0 +1,38 @@
+package app;
+
+public class Logger {
+
+    public static void log(String message) {
+        System.out.println("----------------------------------------------------");
+        System.out.println(message);
+        System.out.println("----------------------------------------------------");
+    }
+
+    public static void logSuccess() {
+        System.out.println("----------------------------------------------------");
+        System.out.println("Good job!");
+        System.out.println("----------------------------------------------------");
+    }
+
+    public static void logNoMatch(Object... args) {
+        System.err.println("--------------------------------------------------------------------------");
+        System.err.println(String.format("You have to try again, the word %s evaluated to %s, expecting %s", args[0],
+                args[1], args[2]));
+        System.err.println("--------------------------------------------------------------------------");
+    }
+
+    public static void logException(Object... args) {
+        System.err.println("----------------------------------------------------");
+        System.err.println("An error occurred during runtime.");
+        System.err.println("Details:" + args[0]);
+    }
+
+    public static void logException(Throwable throwable) {
+        System.err.println("----------------------------------------------------");
+        System.err.println("Something bad happened!");
+        System.err.println(throwable.getMessage());
+        throwable.printStackTrace();
+        System.err.println("----------------------------------------------------");
+    }
+
+}
diff --git a/resources/code_palindrome_test/src/main/java/app/Run.java b/resources/code_palindrome_test/src/main/java/app/Run.java
new file mode 100755
index 0000000..ff2ff8b
--- /dev/null
+++ b/resources/code_palindrome_test/src/main/java/app/Run.java
@@ -0,0 +1,17 @@
+package app;
+
+import static template.Palindrome.isPalindrome;;
+
+public class Run {
+
+    public static void main(String[] args) {
+        String[] words = { "pop", "non", "eye", "hello" };
+        try {
+            for (String n : words) {
+                Logger.log("Input : " + n + " - Output : " + isPalindrome(n));
+            }
+        } catch (RuntimeException e) {
+            Logger.logException(e);
+        }
+    }
+}
diff --git a/resources/code_palindrome_test/src/main/java/app/Solve.java b/resources/code_palindrome_test/src/main/java/app/Solve.java
new file mode 100755
index 0000000..c2dfd9e
--- /dev/null
+++ b/resources/code_palindrome_test/src/main/java/app/Solve.java
@@ -0,0 +1,31 @@
+package app;
+
+import static template.Palindrome.isPalindrome;
+import static success.Palindrome.isPalindrome;
+
+import java.lang.Math;
+import java.util.*;
+
+public class Solve {
+
+    public static void main(String[] args) {
+        List<String> words = Arrays.asList("level", "deadlock", "java", "madam", "check", "rotator", "kayak", "anna");
+        Collections.shuffle(words);
+
+        try {
+            for (String word : words) {
+                boolean userValue = template.Palindrome.isPalindrome(word);
+                boolean expectedValue = success.Palindrome.isPalindrome(word);
+                if (expectedValue != userValue) {
+                    Logger.logNoMatch(word, userValue, expectedValue);
+                    System.exit(1);
+                }
+            }
+            // all test passed successfully
+            Logger.logSuccess();
+        } catch (RuntimeException e) {
+            Logger.logException(e);
+            System.exit(1);
+        }
+    }
+}
diff --git a/resources/code_palindrome_test/src/main/java/success/Palindrome.java b/resources/code_palindrome_test/src/main/java/success/Palindrome.java
new file mode 100644
index 0000000..630767b
--- /dev/null
+++ b/resources/code_palindrome_test/src/main/java/success/Palindrome.java
@@ -0,0 +1,10 @@
+package success;
+
+import java.util.*;
+
+public class Palindrome {
+
+    public static boolean isPalindrome(String word) {
+        return word.equals(new StringBuilder(word).reverse().toString());
+    }
+}
diff --git a/resources/code_palindrome_test/src/main/java/template/Palindrome.java b/resources/code_palindrome_test/src/main/java/template/Palindrome.java
new file mode 100644
index 0000000..da39943
--- /dev/null
+++ b/resources/code_palindrome_test/src/main/java/template/Palindrome.java
@@ -0,0 +1,10 @@
+package template;
+
+import java.util.*;
+
+public class Palindrome {
+
+    public static boolean isPalindrome(String word) {
+        return false;
+    }
+}
diff --git a/resources/code_palindrome_test/thumbnail.png b/resources/code_palindrome_test/thumbnail.png
new file mode 100755
index 0000000000000000000000000000000000000000..30f95b3a5e7b468f3dcc0638c29899c9493c4b85
GIT binary patch
literal 14095
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

literal 0
HcmV?d00001

-- 
GitLab