• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JBZoo / CI-Report-Converter / 6116586974

03 Sep 2023 10:00PM UTC coverage: 94.375% (-0.007%) from 94.382%
6116586974

push

github

web-flow
Immutable jbzoo/data (#39)

3 of 3 new or added lines in 3 files covered. (100.0%)

1426 of 1511 relevant lines covered (94.37%)

28.38 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

83.33
/src/Formats/TeamCity/Helper.php
1
<?php
2

3
/**
4
 * JBZoo Toolbox - CI-Report-Converter.
5
 *
6
 * This file is part of the JBZoo Toolbox project.
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 *
10
 * @license    MIT
11
 * @copyright  Copyright (C) JBZoo.com, All rights reserved.
12
 * @see        https://github.com/JBZoo/CI-Report-Converter
13
 */
14

15
declare(strict_types=1);
16

17
namespace JBZoo\CIReportConverter\Formats\TeamCity;
18

19
final class Helper
20
{
21
    public const PREDEFINED_METRICS = [
22
        'ArtifactsSize',
23
        'VisibleArtifactsSize',
24
        'buildStageDuration:artifactsPublishing',
25
        'buildStageDuration:buildStepRunner_<N>',
26
        'buildStageDuration:sourcesUpdate',
27
        'buildStageDuration:dependenciesResolving',
28
        'BuildDuration',
29
        'BuildDurationNetTime',
30
        'CodeCoverageB',
31
        'CodeCoverageC',
32
        'CodeCoverageL',
33
        'CodeCoverageM',
34
        'CodeCoverageR',
35
        'CodeCoverageS',
36
        'CodeCoverageAbsBCovered',
37
        'CodeCoverageAbsBTotal',
38
        'CodeCoverageAbsCCovered',
39
        'CodeCoverageAbsCTotal',
40
        'CodeCoverageAbsLCovered',
41
        'CodeCoverageAbsLTotal',
42
        'CodeCoverageAbsMCovered',
43
        'CodeCoverageAbsMTotal',
44
        'CodeCoverageAbsRCovered',
45
        'CodeCoverageAbsRTotal',
46
        'CodeCoverageAbsSCovered',
47
        'CodeCoverageAbsSTotal',
48
        'DuplicatorStats',
49
        'TotalTestCount',
50
        'PassedTestCount',
51
        'FailedTestCount',
52
        'IgnoredTestCount',
53
        'InspectionStatsE',
54
        'InspectionStatsW',
55
        'SuccessRate',
56
        'TimeSpentInQueue',
57
    ];
58
    private const TIMESTAMP_FORMAT = 'Y-m-d\TH:i:s.uO';
59

60
    public static function printEvent(string $eventName, array $params = []): string
61
    {
62
        self::ensureValidJavaId($eventName);
88✔
63

64
        $result = "\n##teamcity[{$eventName}";
88✔
65

66
        foreach ($params as $propertyName => $propertyValue) {
88✔
67
            $escapedValue = self::escapeValue((string)$propertyValue);
88✔
68
            if (\is_int($propertyName)) {
88✔
69
                $result .= " '{$escapedValue}'"; // Value without name; skip the key and dump just the value
×
70
            } else {
71
                self::ensureValidJavaId($propertyName);
88✔
72
                $result .= " {$propertyName}='{$escapedValue}'"; // Classic name=value pair
88✔
73
            }
74
        }
75

76
        $result .= "]\n";
88✔
77

78
        return $result;
88✔
79
    }
80

81
    /**
82
     * Checks if given value is valid Java ID.
83
     * Valid Java ID starts with alpha-character and continues with mix of alphanumeric characters and `-`.
84
     */
85
    public static function ensureValidJavaId(string $value): void
86
    {
87
        if (\preg_match('/^[a-z][-a-z0-9]+$/i', $value) === 0) {
88✔
88
            throw new Exception("Value \"{$value}\" is not valid Java ID.");
×
89
        }
90
    }
91

92
    /**
93
     * @param null|\DateTime $datetime either date with timestamp or `NULL` for now
94
     */
95
    public static function formatTimestamp(?\DateTime $datetime = null): string
96
    {
97
        $datetime ??= new \DateTime();
88✔
98
        $formatted = $datetime->format(self::TIMESTAMP_FORMAT);
88✔
99

100
        // We need to pass only 3 microsecond digits.
101
        // 2000-01-01T12:34:56.123450+0100 <- before
102
        // 2000-01-01T12:34:56.123+0100 <- after
103
        return \substr($formatted, 0, 23) . \substr($formatted, 26);
88✔
104
    }
105

106
    private static function escapeValue(?string $value): ?string
107
    {
108
        if ($value === null) {
88✔
109
            return null;
×
110
        }
111

112
        $escapeCharacterMap = [
88✔
113
            '\'' => '|\'',
44✔
114
            "\n" => '|n',
44✔
115
            "\r" => '|r',
44✔
116
            '|'  => '||',
44✔
117
            '['  => '|[',
44✔
118
            ']'  => '|]',
44✔
119
        ];
44✔
120

121
        return \preg_replace_callback(
88✔
122
            '/([\'\n\r|[\]])|\\\\u(\d{4})/',
44✔
123
            static function (array $matches) use ($escapeCharacterMap) {
88✔
124
                if ($matches[1] !== '') {
52✔
125
                    return $escapeCharacterMap[$matches[1]];
52✔
126
                }
127

128
                if ($matches[2] !== '') {
×
129
                    return '|0x' . $matches[2];
×
130
                }
131

132
                throw new Exception('Unexpected match combination.');
×
133
            },
44✔
134
            $value,
44✔
135
        );
44✔
136
    }
137
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc