Skip to content

Commit 3cecd4d

Browse files
authored
[Feature] Conditions (#12)
1 parent 59da392 commit 3cecd4d

File tree

267 files changed

+5345
-2045
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

267 files changed

+5345
-2045
lines changed

.github/workflows/testing.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
uses: actions/cache@v2
2323
with:
2424
path: vendor
25-
key: ${{ runner.os }}-php-mr-linter-$GITHUB_REF-${{ hashFiles('**/composer.lock') }}
25+
key: ${{ runner.os }}-php-mr-linter-$GITHUB_REF-${{ hashFiles('**/composer.json') }}
2626
restore-keys: |
2727
${{ runner.os }}-php-
2828

.mr-linter.php

+9-7
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
<?php
22

3-
use ArtARTs36\MergeRequestLinter\Ci\Credentials\Token;
4-
use ArtARTs36\MergeRequestLinter\Ci\System\GithubActions;
5-
use ArtARTs36\MergeRequestLinter\Ci\System\GitlabCi;
6-
use ArtARTs36\MergeRequestLinter\Contracts\Environment;
7-
use ArtARTs36\MergeRequestLinter\Rule\HasAnyLabelsOfRule;
3+
use ArtARTs36\MergeRequestLinter\CI\Credentials\Token;
4+
use ArtARTs36\MergeRequestLinter\CI\System\Github\GithubActions;
5+
use ArtARTs36\MergeRequestLinter\CI\System\Gitlab\GitlabCi;
86
use ArtARTs36\MergeRequestLinter\Rule\DescriptionNotEmptyRule;
7+
use ArtARTs36\MergeRequestLinter\Rule\HasAnyLabelsOfRule;
98
use ArtARTs36\MergeRequestLinter\Rule\TitleStartsWithAnyPrefixRule;
109

1110
return [
@@ -17,7 +16,7 @@
1716
'Docs',
1817
'Tests',
1918
]),
20-
TitleStartsWithAnyPrefixRule::make([
19+
new TitleStartsWithAnyPrefixRule([
2120
'[Feature]',
2221
'[Bug]',
2322
'[Docs]',
@@ -28,5 +27,8 @@
2827
GitlabCi::class => new Token(getenv('MR_LINTER_GITLAB_HTTP_TOKEN')),
2928
GithubActions::class => new Token(getenv('MR_LINTER_GITHUB_HTTP_TOKEN')),
3029
],
31-
'http_client' => fn (string $ciName, Environment $environment, string $ciSystemClass) => new \GuzzleHttp\Client(),
30+
'http_client' => [
31+
'type' => 'guzzle',
32+
'params' => [],
33+
],
3234
];

Makefile

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
# usage as `make try MR_ID=1 TOKEN=aszbdg3htyhtgrfg5h5`
22
try:
3-
GITHUB_ACTIONS=1 GITHUB_REPOSITORY=artarts36/php-merge-request-linter GITHUB_GRAPHQL_URL=https://api.github.com/graphql GITHUB_REF_NAME=${MR_ID}/merge MR_LINTER_GITHUB_HTTP_TOKEN=${TOKEN} ./bin/mr-linter lint
3+
GITHUB_ACTIONS=1 GITHUB_REPOSITORY=artarts36/php-merge-request-linter GITHUB_GRAPHQL_URL=https://api.github.com/graphql GITHUB_REF_NAME=${MR_ID}/merge MR_LINTER_GITHUB_HTTP_TOKEN=${TOKEN} ./bin/mr-linter lint --debug
4+
5+
# usage as `make try-gitlab MR_ID=1 TOKEN=aszbdg3htyhtgrfg5h5`
6+
try-gitlab:
7+
GITLAB_CI=1 \
8+
CI_MERGE_REQUEST_IID=${MR_ID} \
9+
CI_MERGE_REQUEST_PROJECT_ID=41749211 \
10+
CI_SERVER_URL=https://gitlab.com \
11+
MR_LINTER_GITLAB_HTTP_TOKEN=${TOKEN} ./bin/mr-linter lint --debug
412

513
docker-build:
614
docker build . -t artarts36/merge-request-linter

README.MD

+18-8
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,18 @@ docker run \
118118
},
119119
"@mr-linter/jira/has_issue_link": {
120120
"domain": "jira.com",
121-
"projectCode": "MYPROJECT"
121+
"projectCode": "MYPROJECT",
122+
"when": {
123+
"title": {
124+
"starts": "WIP-REQUEST"
125+
}
126+
}
122127
},
123-
"@mr-linter/description_not_empty": {}
128+
"@mr-linter/description_not_empty": {
129+
"when": {
130+
"targetBranch": "master"
131+
}
132+
}
124133
},
125134
"credentials": {
126135
"github_actions": "env(MR_LINTER_GITHUB_HTTP_TOKEN)"
@@ -130,12 +139,13 @@ docker run \
130139

131140
## Development Commands
132141

133-
| Command | Description |
134-
|--------------------|---------------------------------------|
135-
| composer test | Run tests (via PHPUnit) |
136-
| composer lint | Run lint (via PHPCsFixer) |
137-
| composer doc-rules | Build rules doc page |
138-
| make try | Run MR-Linter on really merge-request |
142+
| Command | Description |
143+
|-----------------------------------|---------------------------------------|
144+
| composer test | Run tests (via PHPUnit) |
145+
| composer lint | Run lint (via PHPCsFixer) |
146+
| composer doc-rules | Build rules doc page |
147+
| make try | Run MR-Linter on really merge-request |
148+
| composer build-config-json-schema | Build JSON Schema for config |
139149

140150
## Console output example
141151

bin/mr-linter

+33-12
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,21 @@
22
<?php
33

44
use ArtARTs36\FileSystem\Local\LocalFileSystem;
5-
use ArtARTs36\MergeRequestLinter\Ci\System\DefaultSystems;
5+
use ArtARTs36\MergeRequestLinter\CI\System\DefaultSystems;
6+
use ArtARTs36\MergeRequestLinter\Condition\Evaluator\DefaultEvaluators;
7+
use ArtARTs36\MergeRequestLinter\Condition\Evaluator\EvaluatorFactory;
8+
use ArtARTs36\MergeRequestLinter\Condition\Operator\OperatorFactory;
9+
use ArtARTs36\MergeRequestLinter\Condition\Operator\OperatorResolver;
610
use ArtARTs36\MergeRequestLinter\Configuration\Loader\CompositeLoader;
711
use ArtARTs36\MergeRequestLinter\Configuration\Loader\ConfigLoaderProxy;
12+
use ArtARTs36\MergeRequestLinter\Configuration\Loader\CredentialMapper;
813
use ArtARTs36\MergeRequestLinter\Configuration\Loader\JsonConfigLoader;
914
use ArtARTs36\MergeRequestLinter\Configuration\Loader\PhpConfigLoader;
15+
use ArtARTs36\MergeRequestLinter\Configuration\Loader\RulesMapper;
1016
use ArtARTs36\MergeRequestLinter\Configuration\Resolver\ConfigResolver;
1117
use ArtARTs36\MergeRequestLinter\Configuration\Resolver\PathResolver;
1218
use ArtARTs36\MergeRequestLinter\Configuration\Value\EnvTransformer;
19+
use ArtARTs36\MergeRequestLinter\Configuration\Value\FileTransformer;
1320
use ArtARTs36\MergeRequestLinter\Console\DumpCommand;
1421
use ArtARTs36\MergeRequestLinter\Console\InstallCommand;
1522
use ArtARTs36\MergeRequestLinter\Console\LintCommand;
@@ -21,7 +28,7 @@ use ArtARTs36\MergeRequestLinter\Rule\Factory\Argument\DefaultResolvers;
2128
use ArtARTs36\MergeRequestLinter\Rule\Factory\Constructor\ConstructorFinder;
2229
use ArtARTs36\MergeRequestLinter\Rule\Factory\Resolver;
2330
use ArtARTs36\MergeRequestLinter\Rule\Factory\RuleFactory;
24-
use ArtARTs36\MergeRequestLinter\Support\Map;
31+
use ArtARTs36\MergeRequestLinter\Support\Reflector\CallbackPropertyExtractor;
2532
use Symfony\Component\Console\Application;
2633

2734
$loaded = false;
@@ -50,21 +57,35 @@ $application = new Application('Merge Request Linter', '0.3.0');
5057

5158
$filesystem = new LocalFileSystem();
5259
$environment = new LocalEnvironment();
53-
$runnerFactory = new RunnerFactory($environment);
60+
$ciSystemsMap = DefaultSystems::map();
61+
$runnerFactory = new RunnerFactory($environment, $ciSystemsMap);
5462

5563
$configLoader = new CompositeLoader([
5664
'php' => new PhpConfigLoader($filesystem),
57-
'json' => new ConfigLoaderProxy(static function () use ($filesystem, $environment) {
65+
'json' => new ConfigLoaderProxy(static function () use ($filesystem, $environment, $ciSystemsMap) {
66+
$ruleFactory = new RuleFactory(
67+
new Builder(
68+
DefaultResolvers::get(),
69+
),
70+
new ConstructorFinder(),
71+
);
72+
73+
$operatorFactory = new OperatorFactory(new CallbackPropertyExtractor(), new EvaluatorFactory(
74+
DefaultEvaluators::map(),
75+
));
76+
5877
return new JsonConfigLoader(
59-
Resolver::make(DefaultRules::RULES, new RuleFactory(
60-
new Builder(
61-
DefaultResolvers::get(),
62-
),
63-
new ConstructorFinder(),
64-
)),
6578
$filesystem,
66-
[new EnvTransformer($environment)],
67-
new Map(DefaultSystems::MAP),
79+
new CredentialMapper(
80+
[
81+
new EnvTransformer($environment),
82+
new FileTransformer($filesystem),
83+
],
84+
$ciSystemsMap,
85+
),
86+
new RulesMapper(
87+
new Resolver(DefaultRules::map(), $ruleFactory, new OperatorResolver($operatorFactory)),
88+
),
6889
);
6990
}),
7091
]);

composer.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"type": "library",
55
"require": {
66
"php": "^8.1",
7-
"artarts36/str": "^2.0",
7+
"artarts36/str": "^2.0.13",
88
"symfony/console": "^4.0 | ^5.0 | ^6.0",
99
"psr/http-client-implementation": "^1.0",
1010
"guzzlehttp/psr7": "^2",
@@ -53,6 +53,9 @@
5353
],
5454
"doc-rules": [
5555
"php docs/Builder/build_rules.php"
56+
],
57+
"build-config-json-schema": [
58+
"php docs/Builder/build_config_json_schema.php"
5659
]
5760
}
5861
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
namespace ArtARTs36\MergeRequestLinter\DocBuilder\ConfigJsonSchema;
4+
5+
class Generator
6+
{
7+
public function __construct(
8+
private RuleSchemaGenerator $ruleSchemaGenerator = new RuleSchemaGenerator(),
9+
private OperatorSchemaArrayGenerator $operatorSchemaArrayGenerator = new OperatorSchemaArrayGenerator(),
10+
) {
11+
//
12+
}
13+
14+
public function generate(): array
15+
{
16+
return [
17+
'$schema' => 'http://json-schema.org/draft-04/schema#',
18+
'type' => 'object',
19+
'properties' => [
20+
'rules' => [
21+
'type' => 'object',
22+
'properties' => $this->ruleSchemaGenerator->generate(),
23+
],
24+
'credentials' => [
25+
'type' => 'object',
26+
'properties' => [
27+
'gitlab_ci' => [
28+
'description' => 'Token',
29+
'type' => 'string',
30+
],
31+
'github_actions' => [
32+
'description' => 'Token',
33+
'type' => 'string',
34+
],
35+
],
36+
],
37+
],
38+
'definitions' => [
39+
'rule_conditions' => $this->operatorSchemaArrayGenerator->generate(),
40+
],
41+
'required' => [
42+
'rules',
43+
'credentials',
44+
],
45+
];
46+
}
47+
}
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace ArtARTs36\MergeRequestLinter\DocBuilder\ConfigJsonSchema;
4+
5+
use ArtARTs36\Str\Str;
6+
7+
class JsonType
8+
{
9+
private const MAP = [
10+
Str::class => 'string',
11+
'int' => 'integer',
12+
'iterable' => 'array',
13+
'float' => 'number',
14+
'bool' => 'boolean',
15+
];
16+
17+
public static function to(string $type): string
18+
{
19+
if (isset(self::MAP[$type])) {
20+
return self::MAP[$type];
21+
}
22+
23+
return $type;
24+
}
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace ArtARTs36\MergeRequestLinter\DocBuilder\ConfigJsonSchema;
4+
5+
class OperatorMetadata
6+
{
7+
/**
8+
* @param array<string> $names
9+
* @param array<Parameter> $parameters
10+
*/
11+
public function __construct(
12+
public readonly array $names,
13+
public readonly string $class,
14+
public readonly bool $evaluatesSameType,
15+
public readonly bool $evaluatesGenericType,
16+
public readonly array $parameters,
17+
public readonly string $description,
18+
) {
19+
//
20+
}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
3+
namespace ArtARTs36\MergeRequestLinter\DocBuilder\ConfigJsonSchema;
4+
5+
use ArtARTs36\MergeRequestLinter\Condition\Attribute\EvaluatesGenericType;
6+
use ArtARTs36\MergeRequestLinter\Condition\Attribute\EvaluatesSameType;
7+
use ArtARTs36\MergeRequestLinter\Condition\Evaluator\DefaultEvaluators;
8+
use ArtARTs36\MergeRequestLinter\Contracts\Condition\ConditionOperator;
9+
use ArtARTs36\MergeRequestLinter\Support\Reflector\Generic;
10+
use ArtARTs36\MergeRequestLinter\Support\Reflector\Reflector;
11+
12+
class OperatorMetadataLoader
13+
{
14+
private const OPERATOR_VALUE_FIELD = 'value';
15+
16+
/**
17+
* @return array<class-string<ConditionOperator>, OperatorMetadata>>
18+
*/
19+
public function load(): array
20+
{
21+
/** @var array<class-string<ConditionOperator>, OperatorMetadata> $operators */
22+
$operators = [];
23+
24+
foreach (DefaultEvaluators::map()->groupKeysByValue() as $operatorClass => $operatorNames) {
25+
$operatorReflector = new \ReflectionClass($operatorClass);
26+
27+
$param = Reflector::findParamByName($operatorReflector->getConstructor(), self::OPERATOR_VALUE_FIELD);
28+
29+
if ($param === null || ! $param->hasType()) {
30+
continue;
31+
}
32+
33+
$paramRawType = $param->getType();
34+
$paramTypes = $paramRawType instanceof \ReflectionUnionType ? $paramRawType->getTypes() : [$paramRawType];
35+
36+
/** @var array<Parameter> $paramTypeNames */
37+
$paramTypeNames = [];
38+
39+
$genericAttr = $param->getAttributes(Generic::class);
40+
$genericAttrFirst = current($genericAttr);
41+
42+
$genericType = null;
43+
44+
if ($genericAttrFirst !== false) {
45+
$genericType = current($genericAttrFirst->getArguments());
46+
}
47+
48+
foreach ($paramTypes as $paramType) {
49+
$paramTypeNames[] = new Parameter(
50+
$paramType->getName(),
51+
JsonType::to($paramType->getName()),
52+
$genericType,
53+
);
54+
}
55+
56+
$operators[$operatorClass] = new OperatorMetadata(
57+
$operatorNames,
58+
$operatorClass,
59+
Reflector::hasAttribute($operatorReflector, EvaluatesSameType::class),
60+
Reflector::hasAttribute($operatorReflector, EvaluatesGenericType::class),
61+
$paramTypeNames,
62+
Reflector::findPHPDocSummary($operatorReflector) ?? '',
63+
);
64+
}
65+
66+
return $operators;
67+
}
68+
}

0 commit comments

Comments
 (0)