diff --git a/.env b/.env index 5c75d150..1c2a2328 100644 --- a/.env +++ b/.env @@ -21,7 +21,7 @@ APP_SECRET=5dd8ffca252d95e8b4fb5b2d15310e92 SYMFONY_DOCS_SECRET='' SYMFONY_SECRET='' -BOT_USERNAME='carsonbot-test' +BOT_USERNAME='carsonbot' ###> knplabs/github-api ### #GITHUB_TOKEN=XXX ###< knplabs/github-api ### diff --git a/.github/workflows/docs-invalid-use.yml b/.github/workflows/docs-invalid-use.yml new file mode 100644 index 00000000..9e1ccd3a --- /dev/null +++ b/.github/workflows/docs-invalid-use.yml @@ -0,0 +1,70 @@ +name: Verify docs + +on: + schedule: + - cron: '58 6 * * *' + +jobs: + use: + name: Invalid use statements + runs-on: ubuntu-latest + strategy: + fail-fast: false + + steps: + - name: Set up PHP + uses: shivammathur/setup-php@2.7.0 + with: + php-version: 7.4 + coverage: none + + - name: Checkout code + uses: actions/checkout@v2 + + - name: Checkout Symfony repo + run: git clone https://github.com/symfony/symfony .github/workflows/docs-invalid-use/symfony + + - name: Checkout Symfony Docs repo + run: git clone https://github.com/symfony/symfony-docs .github/workflows/docs-invalid-use/docs + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: composer-${{ runner.os }}-7.4-${{ hashFiles('composer.*') }} + restore-keys: | + composer-${{ runner.os }}-7.4- + composer-${{ runner.os }}- + composer- + + - name: Download dependencies + run: | + composer install --no-interaction --optimize-autoloader + cd .github/workflows/docs-invalid-use + composer update --prefer-stable --no-interaction --optimize-autoloader + cd symfony + composer update --prefer-stable --no-interaction --optimize-autoloader + + - name: Verify docs + run: | + cd .github/workflows/docs-invalid-use + ./run.php `pwd`/docs `pwd`/symfony > output.txt + cat output.txt + + - name: Open issue + env: + GITHUB_TOKEN: ${{ secrets.CARSONPROD_GITHUB_TOKEN }} + run: | + if [ ! -s .github/workflows/docs-invalid-use/output.txt ]; then + echo "No issues to report" + exit 0 + fi + + echo -e "I've found some pages that have invalid class references. This is a list of use statements that I couldn't find the correct class to: \n\n\`\`\`" > issue.txt + cat .github/workflows/docs-invalid-use/output.txt >> issue.txt + echo -e "\n\`\`\`\n\nCould someone please verify these?" >> issue.txt + bin/console app:issue:open symfony/symfony-docs "Invalid use statements" `pwd`/issue.txt diff --git a/.github/workflows/docs-invalid-use/composer.json b/.github/workflows/docs-invalid-use/composer.json new file mode 100644 index 00000000..b061b2ce --- /dev/null +++ b/.github/workflows/docs-invalid-use/composer.json @@ -0,0 +1,24 @@ +{ + "name": "tobias/docs-checker", + "type": "project", + "authors": [ + { + "name": "Nyholm", + "email": "tobias.nyholm@gmail.com" + } + ], + "require": { + "symfony/filesystem": "^5.1", + "symfony/finder": "^5.1", + "symfony/phpunit-bridge": "^5.1", + "phpunit/phpunit": "^9.4", + "defuse/php-encryption": "^2.2", + "sensiolabs/ansi-to-html": "^1.2", + "twig/twig": "^3.0", + "symfony/mercure": "^0.4.0", + "lcobucci/jwt": "^3.3", + "symfony/psr-http-message-bridge": "^2.0", + "ramsey/uuid": "^4.1", + "twig/cssinliner-extra": "^3.0" + } +} diff --git a/.github/workflows/docs-invalid-use/run.php b/.github/workflows/docs-invalid-use/run.php new file mode 100755 index 00000000..5f6fdc83 --- /dev/null +++ b/.github/workflows/docs-invalid-use/run.php @@ -0,0 +1,89 @@ +#!/usr/bin/env php +in($docs)->name('*.rst'); + +$blocklist = getBlocklist(); +$count = 0; +foreach ($finder as $file) { + $contents = $file->getContents(); + $matches = []; + if (preg_match_all('|^ +use (.*\\\.*); *?$|im', $contents, $matches)) { + foreach ($matches[1] as $class) { + if (substr($class, 0, 3) === 'App' || substr($class, 0, 4) === 'Acme') { + continue; + } + + if (false !== $pos = strpos($class, ' as ')) { + $class = substr($class, 0, $pos); + } + + if (false !== $pos = strpos($class, 'function ')) { + continue; + } + + if (in_array($class, $blocklist)) { + continue; + } + + $explode = explode('\\', $class); + if (count($explode) === 3 && $explode[0] === 'Symfony' && $explode[1] === 'Component') { + continue; + } + + if (!class_exists($class) && !interface_exists($class) && !trait_exists($class)) { + $count++; + echo $file->getRelativePath().'/'.$file->getFilename(). ' - '.$class. PHP_EOL; + } + } + } +} + +if ($count === 0) { + error_log("We found nothing\n"); +} + +exit(0); + +function getBlocklist(): array +{ + return [ + 'Doctrine\ORM\Mapping', + 'Symfony\Component\Validator\Constraints', + 'Simplex\StringResponseListener', + 'Calendar\Model\LeapYear', + 'Symfony\Component\Security\Core\Validator\Constraints', + 'Simplex\Framework', + 'Calendar\Controller\LeapYearController', + 'ApiPlatform\Core\Annotation\ApiResource', + 'Other\Qux', + 'Doctrine\Bundle\FixturesBundle\Fixture', + 'Vendor\DependencyClass', + 'Example\Namespace\YourAwesomeCoolClass', + 'Your\Transport\YourTransportFactory', + ]; +} diff --git a/src/Command/OpenIssueCommand.php b/src/Command/OpenIssueCommand.php new file mode 100644 index 00000000..431ee99a --- /dev/null +++ b/src/Command/OpenIssueCommand.php @@ -0,0 +1,64 @@ + + */ +class OpenIssueCommand extends Command +{ + protected static $defaultName = 'app:issue:open'; + private $issueApi; + private $repositoryProvider; + + public function __construct(RepositoryProvider $repositoryProvider, IssueApi $issueApi) + { + parent::__construct(); + $this->issueApi = $issueApi; + $this->repositoryProvider = $repositoryProvider; + } + + protected function configure() + { + $this->addArgument('repository', InputArgument::REQUIRED, 'The full name to the repository, eg symfony/symfony-docs'); + $this->addArgument('title', InputArgument::REQUIRED, 'The title of the issue'); + $this->addArgument('file', InputArgument::REQUIRED, 'The path to the issue body text file'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + /** @var string $repositoryName */ + $repositoryName = $input->getArgument('repository'); + $repository = $this->repositoryProvider->getRepository($repositoryName); + if (null === $repository) { + $output->writeln('Repository not configured'); + + return 1; + } + + /** @var string $title */ + $title = $input->getArgument('title'); + /** @var string $filePath */ + $filePath = $input->getArgument('file'); + + $body = file_get_contents($filePath); + if (false === $body) { + return 1; + } + + $this->issueApi->open($repository, $title, $body, ['help wanted']); + + return 0; + } +}