Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 159b9de19a | |||
| e4a85722f1 |
13
.dockerignore
Normal file
13
.dockerignore
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
build
|
||||||
|
out
|
||||||
|
GH_TOKEN.txt
|
||||||
|
Makefile
|
||||||
|
var
|
||||||
|
gradle
|
||||||
|
.idea
|
||||||
|
.gradle
|
||||||
|
docker
|
||||||
|
gradlew
|
||||||
|
gradlew.bat
|
||||||
|
docker-compose.yml
|
||||||
|
src/test
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -6,4 +6,6 @@
|
|||||||
*.ipr
|
*.ipr
|
||||||
*.iws
|
*.iws
|
||||||
dcproject.iml
|
dcproject.iml
|
||||||
/var
|
/var
|
||||||
|
GH_TOKEN.txt
|
||||||
|
allSQL.sql
|
||||||
38
Makefile
Normal file
38
Makefile
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
.EXPORT_ALL_VARIABLES:
|
||||||
|
VERSION=$(shell ./hook/version.sh)
|
||||||
|
GITHUB_USERNAME=$(shell git config user.email)
|
||||||
|
GITHUB_TOKEN=$(shell cat ./GH_TOKEN.txt)
|
||||||
|
|
||||||
|
# HELP
|
||||||
|
# This will output the help for each task
|
||||||
|
# thanks to https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html
|
||||||
|
.PHONY: help
|
||||||
|
|
||||||
|
help: ## This help.
|
||||||
|
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
|
||||||
|
|
||||||
|
.DEFAULT_GOAL := help
|
||||||
|
|
||||||
|
build-docker: ## Build the docker image of application
|
||||||
|
docker build -t dc-project -f docker/app/Dockerfile .
|
||||||
|
|
||||||
|
publish-docker: build-docker ## Publish docker image of application to Github
|
||||||
|
git diff --quiet --exit-code || (echo "The git is DIRTY !!! You cannot publish this crap!" && exit 1)
|
||||||
|
cat ./GH_TOKEN.txt | docker login docker.pkg.github.com -u ${GITHUB_USERNAME} --password-stdin
|
||||||
|
docker tag dc-project docker.pkg.github.com/flecomte/dc-project/dc-project:${VERSION}
|
||||||
|
docker push docker.pkg.github.com/flecomte/dc-project/dc-project:${VERSION}
|
||||||
|
|
||||||
|
run-docker: ## Build and Run all docker services
|
||||||
|
docker-compose up -d --build
|
||||||
|
|
||||||
|
publish-jar: ## Publish JAR file to Github
|
||||||
|
git diff --quiet --exit-code || (echo "The git is DIRTY !!! You cannot publish this crap!" && exit 1)
|
||||||
|
gradlew publish
|
||||||
|
|
||||||
|
fixtures: ## Import fixtures
|
||||||
|
bash src/main/resources/sql/fixtures/fixtures.sh
|
||||||
|
|
||||||
|
v: vertion
|
||||||
|
|
||||||
|
vertion: ## Show current version
|
||||||
|
@echo ${VERSION}
|
||||||
22
README.md
Normal file
22
README.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# Installation
|
||||||
|
|
||||||
|
## On windows
|
||||||
|
1. Install git
|
||||||
|
- Download and install: https://git-scm.com/download/win
|
||||||
|
2. Install Make
|
||||||
|
- Go to [ezwinports](https://sourceforge.net/projects/ezwinports/files/).
|
||||||
|
- Download `make-4.1-2-without-guile-w32-bin.zip` (get the version without guile).
|
||||||
|
- Extract zip.
|
||||||
|
- Copy the contents to your `Git\mingw64\` merging the folders, but **do NOT overwrite/replace** any existing files.
|
||||||
|
|
||||||
|
## Run dockers
|
||||||
|
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ make run-docker
|
||||||
|
```
|
||||||
|
|
||||||
|
## Add fixtures
|
||||||
|
```bash
|
||||||
|
$ make fixtures
|
||||||
|
```
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
import org.owasp.dependencycheck.reporting.ReportGenerator
|
import org.owasp.dependencycheck.reporting.ReportGenerator
|
||||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
|
||||||
val ktor_version: String by project
|
val ktor_version: String by project
|
||||||
val kotlin_version: String by project
|
val kotlin_version: String by project
|
||||||
@@ -11,7 +12,13 @@ val jackson_version: String by project
|
|||||||
val cucumber_version: String by project
|
val cucumber_version: String by project
|
||||||
|
|
||||||
group = "com.github.flecomte"
|
group = "com.github.flecomte"
|
||||||
version = "0.0.1"
|
version = versioning.info.run {
|
||||||
|
if (dirty) {
|
||||||
|
versioning.info.full
|
||||||
|
} else {
|
||||||
|
versioning.info.lastTag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
jacoco
|
jacoco
|
||||||
@@ -24,6 +31,7 @@ plugins {
|
|||||||
id("org.jlleitschuh.gradle.ktlint") version "8.2.0"
|
id("org.jlleitschuh.gradle.ktlint") version "8.2.0"
|
||||||
id("org.owasp.dependencycheck") version "5.1.0"
|
id("org.owasp.dependencycheck") version "5.1.0"
|
||||||
id("org.sonarqube") version "2.7"
|
id("org.sonarqube") version "2.7"
|
||||||
|
id("net.nemerosa.versioning") version "2.13.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
application {
|
application {
|
||||||
@@ -48,6 +56,38 @@ tasks.withType<Jar> {
|
|||||||
tasks {
|
tasks {
|
||||||
named<ShadowJar>("shadowJar") {
|
named<ShadowJar>("shadowJar") {
|
||||||
mergeServiceFiles("META-INF/services")
|
mergeServiceFiles("META-INF/services")
|
||||||
|
archiveFileName.set("${archiveBaseName.get()}-latest-all.${archiveExtension.get()}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val sourcesJar by tasks.creating(Jar::class) {
|
||||||
|
archiveClassifier.set("sources")
|
||||||
|
from(sourceSets.getByName("main").allSource)
|
||||||
|
}
|
||||||
|
|
||||||
|
publishing {
|
||||||
|
if (versioning.info.dirty == false) {
|
||||||
|
repositories {
|
||||||
|
maven {
|
||||||
|
name = "dc-project"
|
||||||
|
group = "com.github.flecomte"
|
||||||
|
url = uri("https://maven.pkg.github.com/flecomte/dc-project")
|
||||||
|
credentials {
|
||||||
|
username = System.getenv("GITHUB_USERNAME")
|
||||||
|
password = System.getenv("GITHUB_TOKEN")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
publications {
|
||||||
|
create<MavenPublication>("dc-project") {
|
||||||
|
from(components["java"])
|
||||||
|
artifact(sourcesJar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LoggerFactory.getLogger("gradle")
|
||||||
|
.warn("The git is DIRTY !!! You cannot publish this crap! (${versioning.info.full})")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,8 +36,8 @@ services:
|
|||||||
app:
|
app:
|
||||||
container_name: app_${NAME}
|
container_name: app_${NAME}
|
||||||
build:
|
build:
|
||||||
context: ./build
|
context: .
|
||||||
dockerfile: ../docker/app/Dockerfile
|
dockerfile: docker/app/Dockerfile
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
- ${APP_PORT}:8080
|
- ${APP_PORT}:8080
|
||||||
@@ -60,8 +60,12 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- ${ELASTIC_REST}:9200
|
- ${ELASTIC_REST}:9200
|
||||||
- ${ELASTIC_NODES}:9300
|
- ${ELASTIC_NODES}:9300
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://elasticsearch:9200"]
|
||||||
|
interval: 3s
|
||||||
|
timeout: 2s
|
||||||
|
retries: 20
|
||||||
|
|
||||||
# Database
|
|
||||||
db:
|
db:
|
||||||
container_name: postgresql_${NAME}
|
container_name: postgresql_${NAME}
|
||||||
build:
|
build:
|
||||||
@@ -75,11 +79,14 @@ services:
|
|||||||
POSTGRES_DB: ${DB_PWD}
|
POSTGRES_DB: ${DB_PWD}
|
||||||
volumes:
|
volumes:
|
||||||
- ./var/log/postgresql:/var/log/postgresql:rw
|
- ./var/log/postgresql:/var/log/postgresql:rw
|
||||||
- ./var/postgresql/data:/var/lib/postgresql/data:rw
|
- db-data:/var/lib/postgresql/data:rw
|
||||||
depends_on:
|
depends_on:
|
||||||
- elasticsearch
|
- elasticsearch
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "-f", "http://elasticsearch:9200/"]
|
test: [ "CMD", "pg_isready", "-q", "-d", "${DB_NAME}", "-U", "${DB_USER}" ]
|
||||||
interval: 3s
|
interval: 3s
|
||||||
timeout: 2s
|
timeout: 2s
|
||||||
retries: 20
|
retries: 20
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
db-data:
|
||||||
@@ -1,5 +1,12 @@
|
|||||||
FROM adoptopenjdk/openjdk11:jre-11.0.4_11-alpine
|
#### BUILD ####
|
||||||
|
FROM gradle:5.6.4-jdk11 AS build
|
||||||
|
COPY --chown=gradle:gradle . /home/gradle/src
|
||||||
|
|
||||||
|
WORKDIR /home/gradle/src
|
||||||
|
RUN gradle build -x test -x ktlintKotlinScriptCheck -x ktlintTestSourceSetCheck -x ktlintMainSourceSetCheck --no-daemon
|
||||||
|
|
||||||
|
#### RUN ####
|
||||||
|
FROM adoptopenjdk/openjdk11:jre-11.0.4_11-alpine
|
||||||
ENV APPLICATION_USER ktor
|
ENV APPLICATION_USER ktor
|
||||||
RUN adduser -D -g '' $APPLICATION_USER
|
RUN adduser -D -g '' $APPLICATION_USER
|
||||||
|
|
||||||
@@ -8,7 +15,7 @@ RUN chown -R $APPLICATION_USER /app
|
|||||||
|
|
||||||
USER $APPLICATION_USER
|
USER $APPLICATION_USER
|
||||||
|
|
||||||
COPY ./libs/dcproject-0.0.1-all.jar /app/dcproject.jar
|
COPY --from=build /home/gradle/src/build/libs/dcproject-latest-all.jar /app/dcproject.jar
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
CMD ["java", "-server", "-XX:+UnlockExperimentalVMOptions", "-XX:InitialRAMFraction=2", "-XX:MinRAMFraction=2", "-XX:MaxRAMFraction=2", "-XX:+UseG1GC", "-XX:MaxGCPauseMillis=100", "-XX:+UseStringDeduplication", "-jar", "dcproject.jar"]
|
CMD ["java", "-server", "-XX:+UnlockExperimentalVMOptions", "-XX:InitialRAMFraction=2", "-XX:MinRAMFraction=2", "-XX:MaxRAMFraction=2", "-XX:+UseG1GC", "-XX:MaxGCPauseMillis=100", "-XX:+UseStringDeduplication", "-jar", "dcproject.jar"]
|
||||||
|
|||||||
12
hook/version.sh
Normal file
12
hook/version.sh
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [[ $(git describe --tags --dirty) =~ ^V?([0-9][0-9.]*(-dirty)?)$ ]]; then
|
||||||
|
VERSION="${BASH_REMATCH[1]}"
|
||||||
|
elif [[ $(git describe --tags --dirty) =~ ^V?([0-9][0-9.]*)-([0-9]+)-g(.+(-dirty)?)$ ]]; then
|
||||||
|
VERSION="${BASH_REMATCH[1]}-${BASH_REMATCH[3]}"
|
||||||
|
else
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo $VERSION
|
||||||
@@ -8,6 +8,7 @@ import com.fasterxml.jackson.databind.SerializationFeature
|
|||||||
import com.fasterxml.jackson.datatype.joda.JodaModule
|
import com.fasterxml.jackson.datatype.joda.JodaModule
|
||||||
import com.github.jasync.sql.db.postgresql.exceptions.GenericDatabaseException
|
import com.github.jasync.sql.db.postgresql.exceptions.GenericDatabaseException
|
||||||
import fr.dcproject.Env.PROD
|
import fr.dcproject.Env.PROD
|
||||||
|
import fr.dcproject.elasticsearch.configElasticIndexes
|
||||||
import fr.dcproject.entity.*
|
import fr.dcproject.entity.*
|
||||||
import fr.dcproject.event.EventNotification
|
import fr.dcproject.event.EventNotification
|
||||||
import fr.dcproject.event.EventSubscriber
|
import fr.dcproject.event.EventSubscriber
|
||||||
@@ -38,8 +39,6 @@ import io.ktor.routing.Routing
|
|||||||
import io.ktor.util.KtorExperimentalAPI
|
import io.ktor.util.KtorExperimentalAPI
|
||||||
import io.ktor.websocket.WebSockets
|
import io.ktor.websocket.WebSockets
|
||||||
import org.eclipse.jetty.util.log.Slf4jLog
|
import org.eclipse.jetty.util.log.Slf4jLog
|
||||||
import org.elasticsearch.client.Request
|
|
||||||
import org.elasticsearch.client.RestClient
|
|
||||||
import org.koin.core.qualifier.named
|
import org.koin.core.qualifier.named
|
||||||
import org.koin.ktor.ext.Koin
|
import org.koin.ktor.ext.Koin
|
||||||
import org.koin.ktor.ext.get
|
import org.koin.ktor.ext.get
|
||||||
@@ -192,56 +191,7 @@ fun Application.module(env: Env = PROD) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create index if not exist */
|
configElasticIndexes(get())
|
||||||
get<RestClient>().run {
|
|
||||||
if (performRequest(Request("HEAD", "/views?include_type_name=false")).statusLine.statusCode == 404) {
|
|
||||||
Request(
|
|
||||||
"PUT",
|
|
||||||
"/views?include_type_name=false"
|
|
||||||
).apply {
|
|
||||||
//language=JSON
|
|
||||||
setJsonEntity(
|
|
||||||
"""
|
|
||||||
{
|
|
||||||
"settings": {
|
|
||||||
"number_of_shards": 5
|
|
||||||
},
|
|
||||||
"mappings": {
|
|
||||||
"properties": {
|
|
||||||
"logged": {
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"type": {
|
|
||||||
"type": "keyword"
|
|
||||||
},
|
|
||||||
"user_ref": {
|
|
||||||
"type": "keyword"
|
|
||||||
},
|
|
||||||
"id": {
|
|
||||||
"type": "keyword"
|
|
||||||
},
|
|
||||||
"version_id": {
|
|
||||||
"type": "keyword"
|
|
||||||
},
|
|
||||||
"ip": {
|
|
||||||
"type": "keyword"
|
|
||||||
},
|
|
||||||
"citizen_id": {
|
|
||||||
"type": "keyword"
|
|
||||||
},
|
|
||||||
"view_at": {
|
|
||||||
"type": "date"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
""".trimIndent()
|
|
||||||
)
|
|
||||||
}.let {
|
|
||||||
performRequest(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
install(WebSockets) {
|
install(WebSockets) {
|
||||||
pingPeriod = Duration.ofSeconds(60) // Disabled (null) by default
|
pingPeriod = Duration.ofSeconds(60) // Disabled (null) by default
|
||||||
|
|||||||
83
src/main/kotlin/elasticsearch/Config.kt
Normal file
83
src/main/kotlin/elasticsearch/Config.kt
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
package fr.dcproject.elasticsearch
|
||||||
|
|
||||||
|
import org.elasticsearch.client.Request
|
||||||
|
import org.elasticsearch.client.RestClient
|
||||||
|
import org.slf4j.Logger
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
|
||||||
|
fun waitElasticsearchIsUp(client: RestClient) {
|
||||||
|
val logger: Logger = LoggerFactory.getLogger("fr.dcproject.elasticsearch")
|
||||||
|
val request = Request("GET", "/_cluster/health")
|
||||||
|
repeat(40) {
|
||||||
|
runCatching {
|
||||||
|
client.performRequest(request).statusLine.statusCode
|
||||||
|
}.onSuccess {
|
||||||
|
if (it == 200) {
|
||||||
|
logger.debug("Elasticsearch is Ready! Continue...")
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
logger.debug("sleep 2s and retry...")
|
||||||
|
Thread.sleep(2000)
|
||||||
|
}
|
||||||
|
}.onFailure {
|
||||||
|
logger.debug("${it.message}, sleep 2s and retry...")
|
||||||
|
Thread.sleep(2000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
error("Elasticsearch is not ready")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun configElasticIndexes(client: RestClient) {
|
||||||
|
waitElasticsearchIsUp(client)
|
||||||
|
|
||||||
|
/* Create index if not exist */
|
||||||
|
client.run {
|
||||||
|
if (performRequest(Request("HEAD", "/views?include_type_name=false")).statusLine.statusCode == 404) {
|
||||||
|
Request(
|
||||||
|
"PUT",
|
||||||
|
"/views?include_type_name=false"
|
||||||
|
).apply {
|
||||||
|
//language=JSON
|
||||||
|
setJsonEntity(
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"settings": {
|
||||||
|
"number_of_shards": 5
|
||||||
|
},
|
||||||
|
"mappings": {
|
||||||
|
"properties": {
|
||||||
|
"logged": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "keyword"
|
||||||
|
},
|
||||||
|
"user_ref": {
|
||||||
|
"type": "keyword"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "keyword"
|
||||||
|
},
|
||||||
|
"version_id": {
|
||||||
|
"type": "keyword"
|
||||||
|
},
|
||||||
|
"ip": {
|
||||||
|
"type": "keyword"
|
||||||
|
},
|
||||||
|
"citizen_id": {
|
||||||
|
"type": "keyword"
|
||||||
|
},
|
||||||
|
"view_at": {
|
||||||
|
"type": "date"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}.let {
|
||||||
|
performRequest(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user