Skip to content

Commit 27d6cc0

Browse files
Define shorthands for actions and conditions
1 parent bf78812 commit 27d6cc0

File tree

2 files changed

+226
-0
lines changed

2 files changed

+226
-0
lines changed

src/Runner/Shorthand.php

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
<?php
2+
3+
/**
4+
* This file is part of CaptainHook.
5+
*
6+
* (c) Sebastian Feldmann <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace CaptainHook\App\Runner;
13+
14+
use CaptainHook\App\Hook;
15+
use RuntimeException;
16+
17+
/**
18+
* Class Shorthand
19+
*
20+
* Defines some shorthands that can be used in the configuration file to not
21+
* clutter the configuration with the full classnames.
22+
*
23+
* @package CaptainHook
24+
* @author Sebastian Feldmann <[email protected]>
25+
* @link https://github.com/captainhook-git/captainhook
26+
* @since Class available since Release 5.26.0
27+
*/
28+
class Shorthand
29+
{
30+
/**
31+
* Shorthand to action mapping
32+
*
33+
* @var array<string, array<string, array<string, string>>>
34+
*/
35+
private static array $map = [
36+
'action' => [
37+
'branch' => [
38+
'ensurenaming' => Hook\Branch\Action\EnsureNaming::class,
39+
'preventpushoffixupandsquashcommits' => Hook\Branch\Action\BlockFixupAndSquashCommits::class,
40+
],
41+
'debug' => [
42+
'fail' => Hook\Debug\Failure::class,
43+
'ok' => Hook\Debug\Success::class,
44+
],
45+
'file' => [
46+
'blocksecrets' => Hook\Diff\Action\BlockSecrets::class,
47+
'doesnotcontainregex' => Hook\File\Action\DoesNotContainRegex::class,
48+
'isnotempty' => Hook\File\Action\IsNotEmpty::class,
49+
'maxsize' => Hook\File\Action\MaxSize::class,
50+
],
51+
'message' => [
52+
'injectissuekeyfrombranch' => Hook\Message\Action\InjectIssueKeyFromBranch::class,
53+
'cacheonfail ' => Hook\Message\Action\CacheOnFail::class,
54+
'mustfollowbeamsrules' => Hook\Message\Action\Beams::class,
55+
'mustcontainsregex' => Hook\Message\Action\Regex::class,
56+
'preparefromfile' => Hook\Message\Action\PrepareFromFile::class,
57+
'prepare' => Hook\Message\Action\Prepare::class,
58+
],
59+
'notify' => [
60+
'gitnotify' => Hook\Notify\Action\Notify::class,
61+
],
62+
],
63+
'condition' => [
64+
'inconfig' => [
65+
'customvalueistruthy' => Hook\Condition\Config\CustomValueIsTruthy::class,
66+
'customvalueisfalsy' => Hook\Condition\Config\CustomValueIsFalsy::class,
67+
],
68+
'filechanged' => [
69+
'any' => Hook\Condition\FileChanged\Any::class,
70+
'all' => Hook\Condition\FileChanged\All::class,
71+
],
72+
'filestaged' => [
73+
'all' => Hook\Condition\FileStaged\All::class,
74+
'any' => Hook\Condition\FileStaged\Any::class,
75+
'thatis' => Hook\Condition\FileStaged\ThatIs::class,
76+
],
77+
'status' => [
78+
'onbranch' => Hook\Condition\Branch\On::class,
79+
]
80+
]
81+
];
82+
83+
/**
84+
* Check if a configured action value is actually shorthand for an internal action
85+
*
86+
* @param string $action
87+
* @return bool
88+
*/
89+
public static function isShorthand(string $action): bool
90+
{
91+
return (bool) preg_match('#^captainhook\.[a-z]+#i', $action);
92+
}
93+
94+
/**
95+
* Return the matching action class for given action shorthand
96+
*
97+
* @param string $shorthand
98+
* @return string
99+
*/
100+
public static function getActionClass(string $shorthand): string
101+
{
102+
return Shorthand::getClass('action', $shorthand);
103+
}
104+
105+
/**
106+
* Return the matching condition class for given condition shorthand
107+
*
108+
* @param string $shorthand
109+
* @return string
110+
*/
111+
public static function getConditionClass(string $shorthand): string
112+
{
113+
return Shorthand::getClass('condition', $shorthand);
114+
}
115+
116+
/**
117+
* Returns the matching class for shorthand
118+
*
119+
* @param string $type
120+
* @param string $shorthand
121+
* @return string
122+
*/
123+
private static function getClass(string $type, string $shorthand): string
124+
{
125+
$path = explode('.', strtolower($shorthand));
126+
if (count($path) !== 3) {
127+
throw new RuntimeException('Invalid ' . $type . ' shorthand: ' . $shorthand);
128+
}
129+
[$trigger, $group, $name] = $path;
130+
if (!isset(self::$map[$type][$group])) {
131+
throw new RuntimeException('Invalid ' . $type . ' group: ' . $group);
132+
}
133+
if (!isset(self::$map[$type][$group][$name])) {
134+
throw new RuntimeException('Invalid ' . $type . ' => ' . $name);
135+
}
136+
return self::$map[$type][$group][$name];
137+
}
138+
}

tests/unit/Runner/ShorthandTest.php

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<?php
2+
3+
/**
4+
* This file is part of CaptainHook.
5+
*
6+
* (c) Sebastian Feldmann <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace CaptainHook\App\Runner;
13+
14+
use Exception;
15+
use PHPUnit\Framework\TestCase;
16+
17+
class ShorthandTest extends TestCase
18+
{
19+
/**
20+
* Checks if shorthands are identified correctly
21+
*/
22+
public function testCanIdentifyShorthand()
23+
{
24+
// negative
25+
$this->assertFalse(Shorthand::isShorthand('foo'));
26+
$this->assertFalse(Shorthand::isShorthand('\\CaptainHook\\App'));
27+
$this->assertFalse(Shorthand::isShorthand('CaptainHook.'));
28+
29+
// positive
30+
$this->assertTrue(Shorthand::isShorthand('CaptainHook.foo'));
31+
$this->assertTrue(Shorthand::isShorthand('captainhook.bar'));
32+
$this->assertTrue(Shorthand::isShorthand('CAPTAINHOOK.baz'));
33+
}
34+
35+
/**
36+
* Check if invalid shorthand detection works
37+
*/
38+
public function testDetectsInvalidActionShortHand(): void
39+
{
40+
$this->expectException(Exception::class);
41+
Shorthand::getActionClass('Captainhook.foo.bar.baz');
42+
}
43+
44+
/**
45+
* Check if an invalid shorthand group is detected
46+
*/
47+
public function testDetectsInvalidActionShorthandGroup(): void
48+
{
49+
$this->expectException(Exception::class);
50+
Shorthand::getActionClass('Captainhook.foo.bar');
51+
}
52+
53+
/**
54+
* Check if an invalid action shorthand name is detected
55+
*/
56+
public function testDetectsInvalidActionShorthandName(): void
57+
{
58+
$this->expectException(Exception::class);
59+
Shorthand::getActionClass('Captainhook.File.bar');
60+
}
61+
62+
/**
63+
* Check if an invalid condition shorthand name is detected
64+
*/
65+
public function testDetectsInvalidConditionShorthandName(): void
66+
{
67+
$this->expectException(Exception::class);
68+
Shorthand::getConditionClass('Captainhook.FileStaged.bar');
69+
}
70+
71+
/**
72+
* Check if a valid action shorthand is mapped correctly
73+
*/
74+
public function testFindsActionClassByShorthand(): void
75+
{
76+
$class = Shorthand::getActionClass('Captainhook.Branch.EnsureNaming');
77+
$this->assertTrue(str_contains($class, 'CaptainHook\App\Hook\Branch\Action\EnsureNaming'));
78+
}
79+
80+
/**
81+
* Check if a valid condition shorthand is mapped correctly
82+
*/
83+
public function testFindsConditionClassByShorthand(): void
84+
{
85+
$class = Shorthand::getConditionClass('Captainhook.Status.OnBranch');
86+
$this->assertTrue(str_contains($class, 'CaptainHook\App\Hook\Condition\Branch\On'));
87+
}
88+
}

0 commit comments

Comments
 (0)