Compare commits

...

3 Commits

12 changed files with 827 additions and 135 deletions

View File

@ -9,10 +9,16 @@
This command would send an invoice for last month created from the template This command would send an invoice for last month created from the template
file and last month report from youtrack as an email attachment. file and last month report from youtrack as an email attachment.
~./rprt.php report -r~
Asks which report to print from the list of your reports and then prints out
a table with that report.
** Install/Getting started ** Install/Getting started
Get ~.phar~ file, run configuration wizzard (planned for version 1.0). Get ~.phar~ file from r, run configuration wizzard (planned for version 1.0).
Before version 1.0 is released you have to navigate into ~/app~ directory Before version 1.0 is released you have to navigate into ~/app~ directory
and call command through ~.rprt.php~ file. and call command through ~.rprt.php~ file.
@ -25,6 +31,12 @@
3. You have to allow [[https://support.google.com/accounts/answer/6010255?hl=en][less secure applications]] in your gmail if you are using 3. You have to allow [[https://support.google.com/accounts/answer/6010255?hl=en][less secure applications]] in your gmail if you are using
that email provider. that email provider.
*** Building a phar
php box: https://github.com/box-project/box
~./box.phar compile~
** Specs ** Specs
A simple Console Command that prints out monthly report from youtrack. A simple Console Command that prints out monthly report from youtrack.

640
app/composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,7 @@
use function DI\create; use function DI\create;
use function DI\get; use function DI\get;
use function DI\factory;
use RprtCli\Commands\InvoiceCommand; use RprtCli\Commands\InvoiceCommand;
use RprtCli\Commands\ReportCommand; use RprtCli\Commands\ReportCommand;
@ -18,6 +19,7 @@ use RprtCli\Utils\PdfExport\PdfExportInterface;
use RprtCli\Utils\PdfExport\PdfExportService; use RprtCli\Utils\PdfExport\PdfExportService;
use RprtCli\Utils\TimeTrackingServices\YoutrackInterface; use RprtCli\Utils\TimeTrackingServices\YoutrackInterface;
use RprtCli\Utils\TimeTrackingServices\YoutrackService; use RprtCli\Utils\TimeTrackingServices\YoutrackService;
use Psr\Container\ContainerInterface;
# use Symfony\Component\Translation\Translator; # use Symfony\Component\Translation\Translator;
#use Symfony\Component\Translation\Loader\PoFileLoader; #use Symfony\Component\Translation\Loader\PoFileLoader;
@ -32,7 +34,13 @@ return [
'config.path' => '~/.config/rprt-cli/', 'config.path' => '~/.config/rprt-cli/',
'default_locale' => 'en', 'default_locale' => 'en',
'guzzle' => get(Client::class), 'guzzle' => get(Client::class),
'mpdf' => get(Mpdf::class), // 'mpdf' => get(Mpdf::class),
'mpdf' => factory(function (ContainerInterface $c) {
return new Mpdf(['tempDir' => sys_get_temp_dir()]);
}),
// 'mpdf' => function () {
// return new Mpdf(['tempDir' => sys_get_temp_dir()]);
// },
ConfigurationInterface::class => get(ConfigurationService::class), ConfigurationInterface::class => get(ConfigurationService::class),
ConfigurationService::class => create()->constructor( ConfigurationService::class => create()->constructor(
get('config.path'), get('config.path'),

View File

@ -12,7 +12,7 @@ $builder = new ContainerBuilder();
$builder->addDefinitions(__DIR__ . '/dependencies.php'); $builder->addDefinitions(__DIR__ . '/dependencies.php');
$container = $builder->build(); $container = $builder->build();
$application = new Application(); $application = new Application('Command Line Tool to process Youtrack Reports', '0.1.0');
$invoiceCommand = $container->get(InvoiceCommand::class); $invoiceCommand = $container->get(InvoiceCommand::class);
$application->add($invoiceCommand); $application->add($invoiceCommand);

View File

@ -201,7 +201,7 @@ class InvoiceCommand extends Command
} }
$output_path = $this->pdfExport->fromDefaultDataToPdf($nice_data); $output_path = $this->pdfExport->fromDefaultDataToPdf($nice_data);
// Notify the user where the file was generated to. // Notify the user where the file was generated to.
$output->writeln("The file was generated at ${output_path}."); $output->writeln("The file was generated at <info>${output_path}</info>.");
} }
// return Command::SUCCESS; // return Command::SUCCESS;
@ -209,7 +209,7 @@ class InvoiceCommand extends Command
if ($input->getOption('send') && $output_path) { if ($input->getOption('send') && $output_path) {
// @TODO If no output path print an error. // @TODO If no output path print an error.
// Send email to configured address. // Send email to configured address.
if ($recipients = $input->getOption('send-to')) { if ($recipients = $input->getOption('recipients')) {
$this->mailer->setRecipients(explode(',', $recipients)); $this->mailer->setRecipients(explode(',', $recipients));
} }
$this->mailer->sendDefaultMail($output_path); $this->mailer->sendDefaultMail($output_path);

View File

@ -199,7 +199,7 @@ class ReportCsv implements ReportCsvInterface
$table[] = ReportCsvInterface::SEPARATOR_MEDIUM; $table[] = ReportCsvInterface::SEPARATOR_MEDIUM;
$table[] = [null, $project, null, $project_time / 60]; $table[] = [null, $project, null, $project_time / 60];
$time_sum += (float) $project_time; $time_sum += (float) $project_time;
$all_projects[] = $project; // $all_projects[] = $project;
// Add a sum of time for whole day. // Add a sum of time for whole day.
$table[] = ReportCsvInterface::SEPARATOR_MEDIUM; $table[] = ReportCsvInterface::SEPARATOR_MEDIUM;
$table[] = [null, implode(', ', $all_projects), null, $time_sum/60]; $table[] = [null, implode(', ', $all_projects), null, $time_sum/60];

View File

@ -88,7 +88,7 @@ class PdfExportService implements PdfExportInterface {
} }
$table .= implode('', $rows); $table .= implode('', $rows);
$table .= '</tbody></table>'; $table .= '</tbody></table>';
var_dump($table); // var_dump($table);
return $table; return $table;
} }

View File

@ -115,9 +115,14 @@ class YoutrackService implements YoutrackInterface
if ($status == 409) { if ($status == 409) {
sleep(3); sleep(3);
// @TODO Find a way to break of of loop if necessary! // @TODO Find a way to break of of loop if necessary!
$this->downloadReport($report_id); var_dump("409 response status during download of report {$report_id}. Sleep 3 and try again.");
return $this->downloadReport($report_id);
} }
} }
catch (\Throwable $t) {
$status = $t->getMessage();
var_dump($status);
}
throw new \Exception("Unable to download report {$report_id}!"); throw new \Exception("Unable to download report {$report_id}!");
} }

18
box.json 100644
View File

@ -0,0 +1,18 @@
{
"main": "rprt.php",
"base-path": "app",
"compression": "GZ",
"output": "../bin/rprt-gz.phar",
"blacklist": ["config", "resources", "tests", "translations"],
"directories": ["src", "vendor"],
"files": [
"dependencies.php"
],
"finder": [
{
"name": "*.php",
"exclude": ["Tests"],
"in": "vendor"
}
]
}

View File

@ -0,0 +1,157 @@
#!/bin/bash
# Dependencies:
# getopt
# Track drunomix and kurier dailies.
# KUR-181 (everyday 9.30)
# DEV-122 (tue-fri 10.00) - TEAM-6
# DEV-360 (tracking time) - TEAM-14
# TO DO:
# - Implement track cli (WIP)
track_help () {
echo "Tracks dailies and other weekly meetings."
echo -e "\t-d|--drunomics-daily :: [TEAM-6] Drunomics daily - Tue-Fri(10.00) - 15m."
echo -e "\t-w|--drunomics-weekly :: [TEAM-1] Drunomics weekly - Mon(11.00) - 1h."
echo -e "\t-k|--kurier-daily :: [KUR-181] Kurier daily - Mon-Fri(9.30) - 15m."
echo -e "\t-o|--devops-weekly :: [DEV-1967] DevOps weekly - Mon(14.30) - 60m."
echo -e "\t-u|--drupal-weekly :: [CTB-24] Drupal weekly - Wed(14.00) - 30m."
echo -e "\t-l|--ldp-weekly :: [LDP-683] LDP weekly - Tue(11.00) - 30m."
echo -e "\t-v|--wv-weekly :: [WV-31] WV weekly - Wed(10.30) - 30m."
echo -e "\t-e|--kurier-weekly :: [KUR-181] Kurier weekly - Wed(15.00) - 1h."
echo -e "\t-p|--lupus-d-weekly :: [CTB-55] Lupus dcpld weekly- Thu(11.00) - 30m."
echo -e "\t-t|--tracking-time :: [TEAM-14] Personal time tracking - 15m."
echo -e "\t-s|--date :: Date in timestamp-miliseconds. Defaults to [\$(date +%s)000]"
echo -e "\tmissing :: Work type id. (Not supported yet)."
}
track_help_color () {
green='\033[0;32m'
cyan='\033[0;36m'
clr='\033[0m'
DAY_OF_WEEK=$(date +%u -d "@$DATE")
COLOR_TUE_FRI=$clr
COLOR_MON=$clr
COLOR_TUE=$clr
COLOR_WED=$clr
COLOR_THU=$clr
COLOR_ALL_DAYS=$green
COLOR_PERSONAL=$clr
if [ "$DAY_OF_WEEK" == "1" ] ; then
COLOR_MON=$green
COLOR_MON_2=$cyan
elif [ "$DAY_OF_WEEK" == "2" ] ; then
COLOR_TUE=$green
COLOR_TEAM6=$green
COLOR_TUE_FRI=$green
elif [ "$DAY_OF_WEEK" == "3" ] ; then
COLOR_WED=$green
COLOR_TUE_FRI=$green
elif [ "$DAY_OF_WEEK" == "4" ] ; then
COLOR_THU=$green
COLOR_TUE_FRI=$green
elif [ "$DAY_OF_WEEK" == "5" ] ; then
COLOR_TUE_FRI=$green
else
COLOR_ALL_DAYS=$clr
fi
if [ "$DEV360" == "1" ] ; then
COLOR_PERSONAL=$green
fi
echo "Tracks dailies and other weekly meetings."
echo -e "\t-w|--drunomics-weekly :: ${COLOR_MON}[TEAM-1]${clr} Drunomics weekly - ${COLOR_MON}Mon(11.00)${clr} - ${DEV46}m."
echo -e "\t-o|--devops-weekly :: ${COLOR_MON}[DEV-1967]${clr} DevOps weekly - ${COLOR_MON}Mon(14.00)${clr} - ${DEVOPS}m."
echo -e "\t-d|--drunomics-daily :: ${COLOR_TUE_FRI}[TEAM-6]${clr} Drunomics daily - ${COLOR_TUE_FRI}Tue-Fri(10.00)${clr} - ${DEV122}m."
echo -e "\t-k|--kurier-daily :: ${COLOR_ALL_DAYS}[KUR-181]${clr} Kurier daily - ${COLOR_ALL_DAYS}Mon-Fri(9.30)${clr} - ${KUR181}m."
echo -e "\t-l|--ldp-weekly :: ${COLOR_TUE}[LDP-683]${clr} LDP weekly - ${COLOR_TUE}Tue(11.00)${clr} - ${LDP683}m."
echo -e "\t-u|--drupal-weekly :: ${COLOR_WED}[CTB-24]${clr} Drupal weekly - ${COLOR_WED}Wed(14.00)${clr} - ${CTB24}m."
echo -e "\t-v|--wv-weekly :: ${COLOR_WED}[WV-31]${clr} WV weekly - ${COLOR_WED}Wed(10.30)${clr} - ${WV31}m."
echo -e "\t-e|--kurier-weekly :: ${COLOR_WED}[KUR-182]${clr} Kurier weekly - ${COLOR_WED}Wed(15.00)${clr} - ${KUR182}."
echo -e "\t-p|--lupus-d-weekly :: ${COLOR_THU}[CTB-55]${clr} Lupus dcpld weekly- ${COLOR_WED}Thu(11.00)${clr} - ${CTB55}."
echo -e "\t-t|--tracking-time :: ${COLOR_PERSONAL}[TEAM-14]${clr} Personal time tracking - 15m."
echo -e "\t-s|--date :: Date in timestamp-miliseconds. Defaults to [\$(date +%s)000]"
echo -e "\tmissing :: Work type id. (Not supported yet)."
}
DEV122=15 # now TEAM-6
DEV46=60 # now TEAM-1
KUR181=15
KUR182=60
WV31=30
LDP683=30
DEV360=0 # now TEAM-14
DEVOPS=60
CTB24=30
CTB55=30
DATE=$(date +%s)
# options may be followed by one colon to indicate they have a required argument
if ! options=$(getopt -u -o thd:w:k:e:l:v:s:o:u:p: -l help,time-tracking,drunomics-daily:,drunomics-weekly:,kurier-daily:,kurier-weekly:,ldp-weekly:,wv-weekly:,devops-weekly,drupal-weekly,lupus-d-weekly,date -- "$@")
then
# something went wrong, getopt will put out an error message for us
exit 1
fi
set -- $options
while [ $# -gt 0 ]
do
case $1 in
-t|--tracking-time) DEV360=1 ;;
-d|--drunomics-daily) DEV122=$2 ; shift ;;
-w|--drunomics-weekly) DEV46=$2 ; shift ;;
-k|--kurier-daily) KUR181=$2 ; shift ;;
-e|--kurier-weekly) KUR182=$2 ; shift ;;
-l|--ldp-weekly) LDP683=$2 ; shift ;;
-v|--wv-weekly) WV31=$2 ; shift ;;
-o|--devops-weekly) DEVOPS=$2 ; shift ;;
-u|--drupal-weekly) CTB24=$2 ; shift ;;
-p|--lupus-d-weekly) CTB55=$2 ; shift ;;
-h|--help) TRACK_HELP=1;;
-s|--date) DATE=$2 ; shift ;;
(--) shift; break;;
(-*) echo "$0: error - unrecognized option $1" 1>&2; exit 1;;
(*) break;;
esac
shift
done
if [ "$TRACK_HELP" == "1" ] ; then
track_help_color
else
DAY_OF_WEEK=$(date +%u -d "@$DATE")
if [ "$DAY_OF_WEEK" == "1" ] ; then
echo "Monday: Kurier daily, Drunomics weekly, DevOps weekly:"
/home/lio/Projects/drunomix/ytest/scripts/ytrack.sh KUR-181 $KUR181 'daily' "$(echo $DATE)000"
/home/lio/Projects/drunomix/ytest/scripts/ytrack.sh TEAM-1 $DEV46 'weekly' "$(echo $DATE)000"
/home/lio/Projects/drunomix/ytest/scripts/ytrack.sh DEV-1967 $DEVOPS 'weekly' "$(echo $DATE)000"
elif [ "$DAY_OF_WEEK" == "2" ] ; then
echo "Tuesday: Kurier daily, Drunomics daily, LDP weekly:"
/home/lio/Projects/drunomix/ytest/scripts/ytrack.sh KUR-181 $KUR181 'daily + retro' "$(echo $DATE)000"
/home/lio/Projects/drunomix/ytest/scripts/ytrack.sh TEAM-6 $DEV122 'daily' "$(echo $DATE)000"
/home/lio/Projects/drunomix/ytest/scripts/ytrack.sh LDP-683 $LDP683 'ldp weekly' "$(echo $DATE)000"
elif [ "$DAY_OF_WEEK" == "3" ] ; then
echo "Wednesday: Kurier daily, Drunomics daily, Wirtschaftsverlag weekly, Kurier weekly:"
/home/lio/Projects/drunomix/ytest/scripts/ytrack.sh KUR-181 $KUR181 'daily' "$(echo $DATE)000"
/home/lio/Projects/drunomix/ytest/scripts/ytrack.sh TEAM-6 $DEV122 'daily' "$(echo $DATE)000"
/home/lio/Projects/drunomix/ytest/scripts/ytrack.sh CTB-24 $CTB24 'drupal weekly' "$(echo $DATE)000"
/home/lio/Projects/drunomix/ytest/scripts/ytrack.sh KUR-182 $KUR182 'Kurier weekly grooming' "$(echo $DATE)000"
/home/lio/Projects/drunomix/ytest/scripts/ytrack.sh WV-31 $WV31 'weekly' "$(echo $DATE)000"
elif [ $DAY_OF_WEEK == "4" ] ; then
echo "Thursday: Kurier, Drunomics daily, Lupus Decoupled weekly:"
/home/lio/Projects/drunomix/ytest/scripts/ytrack.sh CTB-55 $CTB55 'weekly' "$(echo $DATE)000"
elif [ $DAY_OF_WEEK -gt 5 ] ; then
echo "No dailies over the weekend."
else
echo "Youtrack drunomix & kurier dailies"
/home/lio/Projects/drunomix/ytest/scripts/ytrack.sh KUR-181 $KUR181 'daily' "$(echo $DATE)000"
/home/lio/Projects/drunomix/ytest/scripts/ytrack.sh TEAM-6 $DEV122 'daily' "$(echo $DATE)000"
fi
if [ "$DEV360" == "1" ] ; then
/home/lio/Projects/drunomix/ytest/scripts/ytrack.sh TEAM-14 15 'tracking time' "$(echo $DATE)000"
fi
fi

73
scripts/ytrack.sh 100755
View File

@ -0,0 +1,73 @@
#!/bin/bash
# Usage:
# First export your youtrack api token (you can put this in .bashrc)
#
# export YTOKEN=<your-youtrack-token-created-in-yt-hub>
#
# All parameters are optional but the sort order defines priority
#
# ytrack.sh <issue-name> <time> <description> <timestamp-miliseconds>
#
# or:
#
# ytrack.sh [DEV-122] [15] [daily] [1631567581342]
#
# @TODO:
# - Figure a nice way to set type: Development(57-0), Project management, Testing & Review(57-1)...
# - Write a proper script with parameters and everything
# Development (57-0)
# Testing, Review (57-1)
track_help () {
echo "Youtrack command line tool."
echo -e "\t\$1 :: Ticket name. Defaults to [DEV-122]."
echo -e "\t\$2 :: Number of minutes. Defaults to [15]."
echo -e "\t\$3 :: Work item description. Defaults to [daily]."
echo -e "\t\$4 :: Date in timestamp-miliseconds. Defaults to [\$(date +%s)000]"
echo -e "\t\$5 :: Work type id. (Not supported yet)."
}
# FLAGS SETUP
while getopts "h" option
do
case "${option}"
in
h) TRACK_HELP=1;;
esac
done
shift $((OPTIND -1))
if [ "$TRACK_HELP" == "1" ] ; then
track_help
else
YT_ISSUE=${1:-DEV-122}
YT_MINUTES=${2:-15}
YT_TEXT=${3:-daily}
CURRENT_DATE="$(date +%s)000"
YT_DATE=${4:-$CURRENT_DATE}
YT_WORK_TYPE=${5:-null}
YT_USER_RESP=$(curl -s 'https://drunomics.myjetbrains.com/youtrack/api/admin/users/me?fields=id,mail,fullName' -H "Authorization: Bearer $YTOKEN" -H 'Cache-Control: no-cache')
YT_USER_ID=$(echo $YT_USER_RESP | jq .id)
YT_USER_ID="${YT_USER_ID:1:-1}"
YT_USER_NAME=$(echo $YT_USER_RESP | jq .fullName)
YT_ISSUE_ID=$(curl -s "https://drunomics.myjetbrains.com/youtrack/api/issues?fields=id,idReadable&query=$YT_ISSUE" -H "Authorization: Bearer $YTOKEN" -H 'Cache-Control: no-cache' -H 'Content-Type: application/json' -H 'Accept: application/json' | jq -c ".[] | select ( .idReadable == \"$YT_ISSUE\") | .id")
YT_ISSUE_ID="${YT_ISSUE_ID:1:-1}"
echo "issue: $YT_ISSUE"
echo "issue_id: $YT_ISSUE_ID"
echo "minutes: $YT_MINUTES"
echo "text: $YT_TEXT"
echo "date: $YT_DATE"
echo "user: $YT_USER_NAME"
echo "type: $YT_WORK_TYPE"
# curl -s -X POST "https://drunomics.myjetbrains.com/youtrack/api/issues/$YT_ISSUE_ID/timeTracking/workItems?fields=id,created,type(name,id),author(name,id),duration(minutes,presentation)" -H "Authorization: Bearer $YTOKEN" -H 'Cache-Control: no-cache' -d "{\"author\": {\"id\":\"$YT_USER_ID\"},\"duration\":{\"minutes\":$YT_MINUTES},\"text\":\"$YT_TEXT\",\"date\":$YT_DATE,\"type\":{\"id\":\"$YT_WORK_TYPE\"}}" -H 'Content-Type: application/json' | jq .
curl -s -X POST "https://drunomics.myjetbrains.com/youtrack/api/issues/$YT_ISSUE_ID/timeTracking/workItems?fields=id,created,type(name,id),author(name,id),duration(minutes,presentation)" -H "Authorization: Bearer $YTOKEN" -H 'Cache-Control: no-cache' -d "{\"author\": {\"id\":\"$YT_USER_ID\"},\"duration\":{\"minutes\":$YT_MINUTES},\"text\":\"$YT_TEXT\",\"date\":$YT_DATE}" -H 'Content-Type: application/json' | jq .
fi

33
todo.txt 100644
View File

@ -0,0 +1,33 @@
TODO:
- nice report selection
- clean up the config (default reports)
- Improve readme
- abstract baseCommand with some input params
- add time tracking command
- plugin system for services:
- in dependencies.php find subdependencies.php
- Create interface for 3rd party service integration and abstract class
- Create factory to add correct service of a 3rd party service to the Command
- separator constant
------------------------
- add plugin system for time tracking service
- add tests
------------------------
- question helper: https://symfony.com/doc/current/components/console/helpers/questionhelper.html
- psr-12 code check and add phpstan https://phpstan.org/user-guide/getting-started
- phing for build automation
- add ddev for dockerization
DONE:
- expenses default value
- pretify output
- rename rprt to invoice
- select report
- build phar file
- upload a phar file on repo
- create release
- clear report cache