‪TYPO3CMS  9.5
validateRstFiles.php
Go to the documentation of this file.
1 #!/usr/bin/env php
2 <?php
3 declare(strict_types = 1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
18 require __DIR__ . '/../../vendor/autoload.php';
19 
20 if (PHP_SAPI !== 'cli') {
21  die('Script must be called from command line.' . chr(10));
22 }
23 
24 use Symfony\Component\Finder\Finder;
25 
36 {
40  protected ‪$messages;
41 
45  protected ‪$isError;
46 
50  protected ‪$baseDir = 'typo3/sysext/core/Documentation/Changelog';
51 
52  public function ‪__construct(string ‪$dir = '')
53  {
54  if (‪$dir) {
55  $this->baseDir = ‪$dir;
56  }
57  }
58 
59  public function ‪validate()
60  {
61  printf('Searching for rst snippets in ' . $this->baseDir . chr(10));
62 
63  $count = 0;
64  ‪$finder = $this->‪findFiles();
65  foreach (‪$finder as $file) {
66  $filename = (string)$file;
67  $this->‪clearMessages();
68  $fileContent = $file->getContents();
69  $this->‪validateContent($fileContent);
70  $a = explode(chr(10), trim($fileContent));
71  $lastLine = array_pop($a);
72  $this->‪validateLastLine($lastLine);
73  $this->‪validateLastLineByFilename($filename, $lastLine);
74 
75  if ($this->isError) {
76  $shortPath = substr($filename, strlen($this->baseDir));
77  $shortPath = ltrim($shortPath, '/\\');
78  $count++;
79  printf(
80  '%-10s | %-12s | %-17s | %s ' . chr(10),
81  $this->messages['include']['title'],
82  $this->messages['reference']['title'],
83  $this->messages['index']['title'],
84  $shortPath
85  );
86  if ($this->messages['include']['message']) {
87  printf($this->messages['include']['message'] . chr(10));
88  }
89  if ($this->messages['reference']['message']) {
90  printf($this->messages['reference']['message'] . chr(10));
91  }
92  if ($this->messages['index']['message']) {
93  printf($this->messages['index']['message'] . chr(10));
94  }
95  }
96  }
97 
98  if ($count > 0) {
99  fwrite(STDERR, 'Found ' . $count . ' rst files with errors, check full log for details.' . chr(10));
100  exit(1);
101  }
102  exit(0);
103  }
104 
105  public function ‪findFiles(): Finder
106  {
107  ‪$finder = new Finder();
108  ‪$finder
109  ->files()
110  ->in($this->baseDir)
111  ->name('/\.rst$/')
112  ->notName('Index.rst')
113  ->notName('Howto.rst');
114 
115  return ‪$finder;
116  }
117 
118  protected function ‪clearMessages()
119  {
120  $this->messages = [
121  'include' => [
122  'title' => '',
123  'message' => '',
124  ],
125  'reference' => [
126  'title' => '',
127  'message' => '',
128  ],
129  'index' => [
130  'title' => '',
131  'message' => '',
132  ],
133  ];
134 
135  $this->isError = false;
136  }
137 
138  protected function ‪validateContent(string $fileContent)
139  {
140  $checkFor = [
141  [
142  'type' => 'include',
143  'regex' => '#^\\.\\. include:: \\.\\./\\.\\./Includes.txt#m',
144  'title' => 'no include',
145  'message' => 'insert \'.. include:: ../../Includes.txt\' in first line of the file',
146  ],
147  [
148  'type' => 'reference',
149  'regex' => '#^See :issue:`[0-9]{4,6}`#m',
150  'title' => 'no reference',
151  'message' => 'insert \'See :issue:`<issuenumber>`\' after headline',
152  ],
153  ];
154 
155  foreach ($checkFor as $values) {
156  if (preg_match($values['regex'], $fileContent) !== 1) {
157  $this->messages[$values['type']]['title'] = $values['title'];
158  $this->messages[$values['type']]['message'] = $values['message'];
159  $this->isError = true;
160  }
161  }
162  }
163 
164  protected function ‪validateLastLine(string $line)
165  {
166  $checkFor = [
167  [
168  'type' => 'index',
169  'regex' => '#^\.\. index:: (?:(?:TypoScript|TSConfig|TCA|FlexForm|LocalConfiguration|Fluid|FAL|Database|JavaScript|PHP-API|Frontend|Backend|CLI|RTE|ext:[a-zA-Z_0-9]+)(?:,\\s|$))+#',
170  'title' => 'no or wrong index',
171  'message' => 'insert \'.. index:: <at least one valid keyword>\' at the last line of the file. See Build/Scripts/validateRstFiles.php for allowed keywords',
172  ],
173  ];
174 
175  foreach ($checkFor as $values) {
176  if (preg_match($values['regex'], $line) !== 1) {
177  $this->messages[$values['type']]['title'] = $values['title'];
178  $this->messages[$values['type']]['message'] = $values['message'];
179  $this->isError = true;
180  }
181  }
182  }
183 
184  protected function ‪validateLastLineByFilename(string $path, string $lastLine)
185  {
186  $checkFor = [
187  [
188  'type' => 'index',
189  'regexIgnoreFilename' => '#'
190  . 'Changelog[\\\\/]' // Ignore all Changelog files
191  . '(?:' // which are either
192  . '.+[\\\\/](?:Feature|Important)' // from any version but of type "Feature" or "Important"
193  . '|' // or
194  . '[78]' // from 7.x and 8.x (as there was no extension scanner back then)
195  . ')'
196  . '#',
197  'regex' => '#^\.\. index:: .*(?:FullyScanned|PartiallyScanned|NotScanned).*#',
198  'title' => 'missing FullyScanned / PartiallyScanned / NotScanned tag',
199  'message' => 'insert \'.. index:: <at least one valid keyword and either FullyScanned, PartiallyScanned or NotScanned>\' at the last line of the file. See Build/Scripts/validateRstFiles.php for allowed keywords',
200  ],
201  ];
202 
203  foreach ($checkFor as $values) {
204  if (preg_match($values['regexIgnoreFilename'], $path) === 1) {
205  continue;
206  }
207  if (preg_match($values['regex'], $lastLine) !== 1) {
208  $this->messages[$values['type']]['title'] = $values['title'];
209  $this->messages[$values['type']]['message'] = $values['message'];
210  $this->isError = true;
211  }
212  }
213  }
214 }
215 
216 ‪$dir = '';
217 ‪$args = getopt('d:');
218 if (isset(‪$args['d'])) {
219  ‪$dir = ‪$args['d'];
220 }
222 ‪$validator->validate();
‪validateRstFiles\validateLastLine
‪validateLastLine(string $line)
Definition: validateRstFiles.php:161
‪validateRstFiles\$baseDir
‪string $baseDir
Definition: validateRstFiles.php:47
‪$finder
‪$finder
Definition: annotationChecker.php:102
‪$dir
‪$dir
Definition: validateRstFiles.php:213
‪validateRstFiles\clearMessages
‪clearMessages()
Definition: validateRstFiles.php:115
‪validateRstFiles\$messages
‪array $messages
Definition: validateRstFiles.php:39
‪validateRstFiles\$isError
‪bool $isError
Definition: validateRstFiles.php:43
‪validateRstFiles\validateLastLineByFilename
‪validateLastLineByFilename(string $path, string $lastLine)
Definition: validateRstFiles.php:181
‪validateRstFiles\validate
‪validate()
Definition: validateRstFiles.php:56
‪validateRstFiles\__construct
‪__construct(string $dir='')
Definition: validateRstFiles.php:49
‪$validator
‪if(isset($args['d'])) $validator
Definition: validateRstFiles.php:218
‪validateRstFiles\findFiles
‪findFiles()
Definition: validateRstFiles.php:102
‪$args
‪$args
Definition: validateRstFiles.php:214
‪validateRstFiles
Definition: validateRstFiles.php:36
‪validateRstFiles\validateContent
‪validateContent(string $fileContent)
Definition: validateRstFiles.php:135