diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..5423147
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,2 @@
+*
+!report.php
\ No newline at end of file
diff --git a/.drone.yml b/.drone.yml
new file mode 100644
index 0000000..aab4cb0
--- /dev/null
+++ b/.drone.yml
@@ -0,0 +1,120 @@
+---
+kind: pipeline
+type: docker
+name: main
+
+steps:
+ - name: Fetch tags
+ image: alpine/git
+ commands:
+ - git fetch --tags
+ - name: Update version and changelog
+ image: registry.riba-interactive.de/conventi:0.1.0
+ - name: Commit changelog updates
+ image: alpine/git
+ commands:
+ - git add .
+ - git commit -m "version and changelog update [CI SKIP]"
+ - git push origin $DRONE_TARGET_BRANCH
+ - name: Tag commit
+ image: registry.riba-interactive.de/conventi:0.1.0
+ commands:
+ - export VERSION=$(conventi.sh get_version)
+ - git tag -am "Tagging new version $VERSION" "$VERSION"
+ - git push origin "$VERSION"
+
+trigger:
+ branch:
+ - main
+ event:
+ - push
+
+image_pull_secrets:
+ - dockerconfig
+---
+kind: pipeline
+type: docker
+name: tag
+
+steps:
+ - name: Build release
+ image: docker:dind
+ volumes:
+ - name: dockersock
+ path: /var/run
+ environment:
+ DOCKER_USER:
+ from_secret: docker_user
+ DOCKER_PASSWORD:
+ from_secret: docker_password
+ commands:
+ - sleep 5 # give docker enough time to start
+ - echo "$DOCKER_PASSWORD" | docker login --username $DOCKER_USER --password-stdin registry.riba-interactive.de
+ - docker pull registry.riba-interactive.de/reportly:latest || true
+ - DOCKER_BUILDKIT=1 docker build --cache-from registry.riba-interactive.de/reportly:latest --tag registry.riba-interactive.de/reportly:latest .
+ - docker tag registry.riba-interactive.de/reportly:latest registry.riba-interactive.de/reportly:$DRONE_TAG
+ - docker push --all-tags registry.riba-interactive.de/reportly
+
+trigger:
+ event:
+ - tag
+
+services:
+ - name: docker
+ image: docker:dind
+ privileged: true
+ volumes:
+ - name: dockersock
+ path: /var/run
+
+volumes:
+ - name: dockersock
+ temp: {}
+
+image_pull_secrets:
+ - dockerconfig
+---
+kind: pipeline
+type: docker
+name: Build and Test
+
+steps:
+ - name: Build image
+ image: docker:dind
+ volumes:
+ - name: dockersock
+ path: /var/run
+ environment:
+ DOCKER_USER:
+ from_secret: docker_user
+ DOCKER_PASSWORD:
+ from_secret: docker_password
+ commands:
+ - sleep 5 # give docker enough time to start
+ - echo "$DOCKER_PASSWORD" | docker login --username $DOCKER_USER --password-stdin registry.riba-interactive.de
+ - docker pull registry.riba-interactive.de/reportly:latest || true
+ - DOCKER_BUILDKIT=1 docker build --cache-from registry.riba-interactive.de/reportly:latest --tag registry.riba-interactive.de/reportly:latest .
+ - docker tag registry.riba-interactive.de/reportly:latest registry.riba-interactive.de/reportly:build-$DRONE_BUILD_NUMBER
+ - docker push --all-tags registry.riba-interactive.de/reportly
+
+trigger:
+ branch:
+ - develop
+ - feature/*
+ - bugfix/*
+
+services:
+ - name: docker
+ image: docker:dind
+ privileged: true
+ volumes:
+ - name: dockersock
+ path: /var/run
+
+volumes:
+ - name: dockersock
+ temp: {}
+
+image_pull_secrets:
+ - dockerconfig
+...
\ No newline at end of file
diff --git a/.version.json b/.version.json
new file mode 100644
index 0000000..3de53a7
--- /dev/null
+++ b/.version.json
@@ -0,0 +1,5 @@
+{
+ "version": "0.0.0",
+ "sha": "",
+ "url": "https://git.riba-interactive.de/rick/reportly"
+}
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..f7ecd09
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,8 @@
+# Changelog
+
+All notable changes to this project will be documented in this file. See [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) for commit guidelines.
+
+This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+----
+
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..0cd860c
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,12 @@
+FROM php:8.1-cli-alpine3.16
+
+RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories; \
+ apk --no-cache add \
+ lcov@testing \
+ composer; \
+ cd /usr/local/bin/ \
+ && composer require erusev/parsedown
+
+COPY report.php /usr/local/bin/
+
+ENTRYPOINT ["report.php"]
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
index e06aa93..17aef81 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) year copyright holder. All Rights Reserved.
+Copyright (c) 2022 Rick Barenthin. All Rights Reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
diff --git a/README.md b/README.md
index f91c304..c6121c5 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,3 @@
# reportly
+[](https://drone.riba-interactive.de/rick/reportly)
diff --git a/report.php b/report.php
new file mode 100755
index 0000000..80ddbcb
--- /dev/null
+++ b/report.php
@@ -0,0 +1,164 @@
+#!/usr/bin/env php
+
%s',
+ $reportTitle,
+ '*,:after,:before{box-sizing:border-box}body{color:#444;font:18px/1.6 Georgia,Times New Roman,Times,serif;margin:40px auto;padding:0 20px}h1,h2,h3,h4,h5{font-family:Helvetica Neue,Helvetica,Arial,sans-serif;line-height:1.2}a{color:#07c;text-decoration:none}a:hover{color:#059;text-decoration:underline}hr{border:0;margin:25px 0}table{border-collapse:collapse;border-spacing:0;padding-bottom:25px;text-align:left}hr,td,th{border-bottom:1px solid #ddd}button,select{background:#ddd;border:0;font-size:14px;padding:9px 20px}input,table{font-size:1pc}input,td,th{padding:5px;vertical-align:bottom}button:hover,code,pre{background:#eee}pre{overflow-x:scroll;padding:8px;font-size:14px}textarea{border-color:#ccc}.row{display:block;min-height:1px;width:auto}.row:after{clear:both;content:"";display:table}.row .c{float:left}.g2,.g3,.g3-2,.m2,.m3,.m3-2,table{width:100%}@media(min-width:8in){.g2{width:50%}.m2{margin-left:50%}.g3{width:33.33%}.g3-2{width:66.66%}.m3{margin-left:33.33%}.m3-2{margin-left:66.66%}}'
+);
+$htmlFooter = '';
+
+$output .= sprintf("%s\n%s\n\n\n", $reportTitle, str_repeat('=', strlen($reportTitle)));
+
+$coverageInfoFile = join_paths($inputDir, 'coverage.info');
+$outputLcov = [];
+exec('lcov --rc lcov_branch_coverage=1 --list ' . $coverageInfoFile, $outputLcov);
+
+array_shift($outputLcov);
+
+$headerCovreport= 'Coverage report';
+$output .= sprintf("%s\n%s\n\n\n", $headerCovreport, str_repeat('-', strlen($headerCovreport)));
+$output .= sprintf("%s\n", '```');
+$output .= implode("\n", $outputLcov);
+$output .= sprintf("\n");
+$output .= sprintf("%s\n\n", '```');
+
+$output .= sprintf("%s\n\n", '[See full coverage report](coverage/index.html)');
+
+if($verbose) {
+ echo "Coverage report:\n";
+ echo implode("\n", $outputLcov) . "\n\n";
+}
+
+$inputReportDir = join_paths($inputDir, 'Testing');
+$inputReportFolder = '';
+foreach (new DirectoryIterator($inputReportDir) as $fileInfo) {
+ if ($fileInfo->isDot()) continue;
+ if (preg_match('/\d+-\d+/', $fileInfo->getFilename())) {
+ $inputReportFolder = $fileInfo->getFilename();
+ break;
+ }
+}
+
+function join_paths(...$paths) {
+ return preg_replace('~[/\\\\]+~', DIRECTORY_SEPARATOR, implode(DIRECTORY_SEPARATOR, $paths));
+}
+
+$inputReportFile = join_paths($inputReportDir, $inputReportFolder, 'DynamicAnalysis.xml');
+$xmlstr = file_get_contents($inputReportFile);
+
+$tests = new SimpleXMLElement($xmlstr);
+
+$countTests = count($tests->DynamicAnalysis->Test);
+$numTest = 1;
+
+$testMapping = [];
+$typeMapping = [
+ 'FIM' => 'Free Invalid Memory',
+ 'FMM' => 'Free Mismatched Memory',
+ 'UMR' => 'Uninitialised Memory Read',
+ 'UMC' => 'Uninitialised Memory Conditional',
+ 'IPW' => 'Invalid Pointer Write',
+];
+
+$headerMemreport = 'Memory check report';
+$output .= sprintf("%s\n%s\n\n\n", $headerMemreport, str_repeat('-', strlen($headerMemreport)));
+
+$memLeaksFound = count($tests->DynamicAnalysis->Test) != 0;
+
+$outputMem = '';
+
+if ($memLeaksFound) {
+ $outputMem .= sprintf("%s\n", '```');
+ foreach ($tests->DynamicAnalysis->Test as $test) {
+ $testMapping[$numTest] = $test->Name;
+ $outputMem .= sprintf("%d/%d MemCheck #%d: %s\n", $numTest, $countTests, $numTest, $test->Name);
+
+ $numResult = 1;
+ foreach ($test->Results->Defect as $result) {
+ $type = $result->attributes()->{'type'}->__toString();
+ $outputMem .= sprintf("\t%d: %s %s : %d\n",
+ $numResult,
+ str_repeat('.', 40),
+ ($typeMapping[$type] ?? $type), $result);
+ $numResult++;
+ }
+ $numTest++;
+ }
+ $outputMem .= sprintf("%s\n\n", '```');
+
+ $outputMem .= sprintf("\n");
+ foreach (new DirectoryIterator(join_paths($inputReportDir, 'Temporary')) as $fileInfo) {
+ if ($fileInfo->isDot()) continue;
+ if (preg_match('/MemoryChecker/', $fileInfo->getFilename())) {
+ $memReport = file_get_contents($fileInfo->getPathname());
+ if (strlen($memReport) == 0) continue;
+
+ $number = explode('.', $fileInfo->getFilename())[1];
+ $testName = $testMapping[$number];
+
+ $headerMemreport = sprintf("Report #%d %s:", $number, $testName);
+ $outputMem .= sprintf("%s\n%s\n\n", $headerMemreport, str_repeat('-', strlen($headerMemreport)));
+
+ $memReport = file_get_contents($fileInfo->getPathname());
+
+ $outputMem .= sprintf("%s\n", '```');
+ $outputMem .= sprintf("%s", $memReport);
+ $outputMem .= sprintf("%s\n\n", '```');
+ }
+ }
+} else {
+ $outputMem .= sprintf("%s\n\n", "NO MEMORY ISSUES, well done!");
+}
+
+if($verbose) {
+ echo "Memory check report\n";
+ echo $outputMem;
+}
+
+$output .= sprintf("%s", $outputMem);
+
+file_put_contents(join_paths($outputDir, 'report.html'), $htmlHeader . $Parsedown->text($output) . $htmlFooter);
+
+$coverageDirectoryOut = join_paths($outputDir, 'coverage');
+mkdir($coverageDirectoryOut);
+foreach (
+$iterator = new \RecursiveIteratorIterator(
+ new \RecursiveDirectoryIterator(join_paths($inputDir, 'coverage'), \RecursiveDirectoryIterator::SKIP_DOTS),
+ \RecursiveIteratorIterator::SELF_FIRST) as $item
+) {
+ if ($item->isDir()) {
+ mkdir(join_paths($coverageDirectoryOut, $iterator->getSubPathname()));
+ } else {
+ copy($item, join_paths($coverageDirectoryOut, $iterator->getSubPathname()));
+ }
+}
+
+return 0;