├── .github
└── workflows
│ ├── ci.yaml
│ └── only-main.yaml
├── .gitignore
├── .php-cs-fixer.dist.php
├── Cli
├── Application.php
├── Command
│ ├── AnalysisCommand.php
│ ├── AnalyzeCommand.php
│ ├── ConfigureCommand.php
│ ├── NeedConfigurationInterface.php
│ ├── ProjectsCommand.php
│ └── SelfUpdateCommand.php
├── Configuration.php
├── Descriptor
│ ├── AbstractDescriptor.php
│ ├── JsonDescriptor.php
│ ├── PmdDescriptor.php
│ ├── TextDescriptor.php
│ └── XmlDescriptor.php
└── Helper
│ ├── ConfigurationHelper.php
│ ├── DescriptorHelper.php
│ └── FailConditionHelper.php
├── LICENSE
├── README.md
├── Sdk
├── Api.php
├── Exception
│ ├── ApiClientException.php
│ ├── ApiParserException.php
│ ├── ApiServerException.php
│ └── ExceptionInterface.php
├── Model
│ ├── Analyses.php
│ ├── Analysis.php
│ ├── Error.php
│ ├── Link.php
│ ├── Project.php
│ ├── Projects.php
│ ├── Violation.php
│ └── Violations.php
├── Parser.php
└── Tests
│ ├── ApiTest.php
│ ├── Model
│ └── ViolationsTest.php
│ ├── ParserTest.php
│ └── fixtures
│ ├── analyses.xml
│ ├── analysis.xml
│ ├── errors.xml
│ ├── project.xml
│ ├── projects.xml
│ ├── projects2.xml
│ └── status.xml
├── bin
└── insight
├── box.json
├── composer.json
└── phpunit.xml.dist
/.github/workflows/ci.yaml:
--------------------------------------------------------------------------------
1 | on: [pull_request]
2 | name: Insight SDK
3 |
4 | jobs:
5 | php-cs:
6 | name: Coding style
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@main
10 | - uses: shivammathur/setup-php@v2
11 | with:
12 | php-version: '7.2'
13 | tools: php-cs-fixer:3.2.1
14 | coverage: none
15 | - name: php-cs-fixer
16 | run: php-cs-fixer fix --dry-run --diff
17 |
18 | tests-phpunit:
19 | name: Unit tests
20 | runs-on: ubuntu-latest
21 |
22 | strategy:
23 | fail-fast: false
24 | matrix:
25 | sf-version: [ '^5.4', '^6.4', '^7.2' ]
26 | php-version: [ '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3' ]
27 | exclude:
28 | - sf-version: '^6.4'
29 | php-version: '7.2'
30 | - sf-version: '^6.4'
31 | php-version: '7.3'
32 | - sf-version: '^6.4'
33 | php-version: '7.4'
34 | - sf-version: '^6.4'
35 | php-version: '8.0'
36 | - sf-version: '^7.2'
37 | php-version: '7.2'
38 | - sf-version: '^7.2'
39 | php-version: '7.3'
40 | - sf-version: '^7.2'
41 | php-version: '7.4'
42 | - sf-version: '^7.2'
43 | php-version: '8.0'
44 | - sf-version: '^7.2'
45 | php-version: '8.1'
46 |
47 | steps:
48 | - uses: actions/checkout@main
49 | - name: Setup PHP
50 | uses: shivammathur/setup-php@v2
51 | with:
52 | php-version: ${{ matrix.php-version }}
53 | tools: phpunit-bridge
54 | coverage: none
55 |
56 | - name: Get Composer cache directory
57 | id: composer-cache
58 | run: echo "::set-output name=dir::$(composer config cache-files-dir)"
59 |
60 | - name: Mount PHP dependencies cache
61 | uses: actions/cache@v4
62 | with:
63 | path: ${{ steps.composer-cache.outputs.dir }}
64 | key: ${{ runner.os }}-composer-${{ hashFiles('console/composer.lock') }}
65 | restore-keys: ${{ runner.os }}-composer-
66 |
67 | - name: Install dependencies
68 | run: |
69 | composer global config --no-plugins allow-plugins.symfony/flex true
70 | composer global require symfony/flex:^1.0
71 | export SYMFONY_REQUIRE="${{ matrix.sf-version }}"
72 | composer update --prefer-dist --no-interaction --no-ansi --no-progress
73 |
74 | - name: Run the tests suite
75 | run: |
76 | php vendor/bin/simple-phpunit -v --log-junit ./phpunit/junit.xml
77 |
78 | - name: Run cmd
79 | run: bin/insight list
80 |
--------------------------------------------------------------------------------
/.github/workflows/only-main.yaml:
--------------------------------------------------------------------------------
1 | on:
2 | push:
3 | branches:
4 | - main
5 | name: Insight SDK (release)
6 |
7 | jobs:
8 | release:
9 | name: Release
10 | runs-on: ubuntu-latest
11 |
12 | env:
13 | AWS_DEFAULT_REGION: 'eu-west-1'
14 | AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
15 | AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
16 |
17 | steps:
18 | - uses: actions/checkout@main
19 | - name: Setup PHP
20 | uses: shivammathur/setup-php@v2
21 | with:
22 | php-version: '7.4'
23 | coverage: none
24 |
25 | - name: Get Composer cache directory
26 | id: composer-cache
27 | run: echo "::set-output name=dir::$(composer config cache-files-dir)"
28 |
29 | - name: Mount PHP dependencies cache
30 | uses: actions/cache@v4
31 | with:
32 | path: ${{ steps.composer-cache.outputs.dir }}
33 | key: ${{ runner.os }}-composer-${{ hashFiles('console/composer.lock') }}
34 | restore-keys: ${{ runner.os }}-composer-
35 |
36 | - name: Install dependencies
37 | run: composer install
38 |
39 | - name: Build
40 | run: |
41 | wget https://github.com/box-project/box/releases/download/3.13.0/box.phar -O /tmp/box.phar
42 | php /tmp/box.phar build
43 |
44 | - name: Test
45 | run: build/insight.phar list
46 |
47 | - name: Release
48 | run: |
49 | aws s3 cp build/insight.phar s3://get.insight.symfony.com/insight.phar
50 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /cache/
2 | /composer.lock
3 | /build/
4 | /insight.log
5 | /vendor/
6 | /.php_cs.cache
7 | /.phpunit.result.cache
8 |
--------------------------------------------------------------------------------
/.php-cs-fixer.dist.php:
--------------------------------------------------------------------------------
1 | in([__DIR__.'/Cli', __DIR__.'/Sdk']);
5 |
6 | $config = new PhpCsFixer\Config();
7 | $config
8 | ->setRules(array(
9 | '@Symfony' => true,
10 | '@Symfony:risky' => true,
11 | 'array_syntax' => ['syntax' => 'short'],
12 | 'class_attributes_separation' => ['elements' => ['const' => 'one']],
13 | ))
14 | ->setRiskyAllowed(true)
15 | ->setFinder($finder)
16 | ;
17 |
18 | return $config;
19 |
--------------------------------------------------------------------------------
/Cli/Application.php:
--------------------------------------------------------------------------------
1 |
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 SensioLabs\Insight\Cli;
13 |
14 | use Monolog\Handler\StreamHandler;
15 | use Monolog\Logger;
16 | use SensioLabs\Insight\Cli\Command as LocalCommand;
17 | use SensioLabs\Insight\Cli\Helper\ConfigurationHelper;
18 | use SensioLabs\Insight\Cli\Helper\FailConditionHelper;
19 | use SensioLabs\Insight\Sdk\Api;
20 | use Symfony\Component\Console\Application as SymfonyApplication;
21 | use Symfony\Component\Console\Command\Command;
22 | use Symfony\Component\Console\Helper\HelperSet;
23 | use Symfony\Component\Console\Input\InputDefinition;
24 | use Symfony\Component\Console\Input\InputInterface;
25 | use Symfony\Component\Console\Input\InputOption;
26 | use Symfony\Component\Console\Output\OutputInterface;
27 |
28 | class Application extends SymfonyApplication
29 | {
30 | const APPLICATION_NAME = 'SymfonyInsight CLI';
31 | const APPLICATION_VERSION = '1.7.4';
32 |
33 | private $api;
34 | private $apiConfig;
35 | private $logFile;
36 |
37 | public function __construct()
38 | {
39 | $this->apiConfig = [
40 | 'base_url' => Api::ENDPOINT,
41 | ];
42 |
43 | parent::__construct(static::APPLICATION_NAME, static::APPLICATION_VERSION);
44 | }
45 |
46 | public function getApi()
47 | {
48 | if ($this->api) {
49 | return $this->api;
50 | }
51 |
52 | $config = $this->apiConfig;
53 | if (\array_key_exists('api_endpoint', $config)) {
54 | $config['base_url'] = $config['api_endpoint'];
55 | }
56 |
57 | $this->api = new Api($config);
58 |
59 | if ($this->logFile) {
60 | if (!class_exists('Monolog\Logger')) {
61 | throw new \InvalidArgumentException('You must include monolog if you want to log (run "composer install --dev")');
62 | }
63 | $logger = new Logger('insight');
64 | $logger->pushHandler(new StreamHandler($this->logFile, Logger::DEBUG));
65 |
66 | $this->api->setLogger($logger);
67 | }
68 |
69 | return $this->api;
70 | }
71 |
72 | public function getLongVersion(): string
73 | {
74 | $version = parent::getLongVersion().' by Symfony';
75 | $commit = '@git-commit@';
76 |
77 | if ('@'.'git-commit@' !== $commit) {
78 | $version .= ' ('.substr($commit, 0, 7).')';
79 | }
80 |
81 | return $version;
82 | }
83 |
84 | protected function getDefaultHelperSet(): HelperSet
85 | {
86 | $helperSet = parent::getDefaultHelperSet();
87 |
88 | $helperSet->set(new ConfigurationHelper(Api::ENDPOINT));
89 | $helperSet->set(new FailConditionHelper());
90 |
91 | return $helperSet;
92 | }
93 |
94 | protected function getDefaultInputDefinition(): InputDefinition
95 | {
96 | $definition = parent::getDefaultInputDefinition();
97 |
98 | $definition->addOption(new InputOption('api-token', null, InputOption::VALUE_REQUIRED, 'Your api token.'));
99 | $definition->addOption(new InputOption('user-uuid', null, InputOption::VALUE_REQUIRED, 'Your user uuid.'));
100 | $definition->addOption(new InputOption('api-endpoint', null, InputOption::VALUE_REQUIRED, 'The api endpoint.'));
101 | $definition->addOption(new InputOption('log', null, InputOption::VALUE_OPTIONAL, 'Add some log capability. Specify a log file if you want to change the log location.'));
102 |
103 | return $definition;
104 | }
105 |
106 | protected function getDefaultCommands(): array
107 | {
108 | $defaultCommands = parent::getDefaultCommands();
109 |
110 | $defaultCommands[] = new LocalCommand\AnalysisCommand();
111 | $defaultCommands[] = new LocalCommand\AnalyzeCommand();
112 | $defaultCommands[] = new LocalCommand\ConfigureCommand();
113 | $defaultCommands[] = new LocalCommand\ProjectsCommand();
114 | $defaultCommands[] = new LocalCommand\SelfUpdateCommand();
115 |
116 | return $defaultCommands;
117 | }
118 |
119 | protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output): int
120 | {
121 | if (!$command instanceof LocalCommand\NeedConfigurationInterface) {
122 | return parent::doRunCommand($command, $input, $output);
123 | }
124 |
125 | $configuration = $this->getHelperSet()->get('configuration')->getConfiguration($input, $output);
126 | $this->apiConfig = array_merge($this->apiConfig, $configuration->toArray());
127 |
128 | if (false !== $input->getParameterOption('--log')) {
129 | $this->logFile = $input->getParameterOption('--log') ?: getcwd().'/insight.log';
130 | }
131 |
132 | return parent::doRunCommand($command, $input, $output);
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/Cli/Command/AnalysisCommand.php:
--------------------------------------------------------------------------------
1 |
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 SensioLabs\Insight\Cli\Command;
13 |
14 | use SensioLabs\Insight\Cli\Helper\DescriptorHelper;
15 | use Symfony\Component\Console\Command\Command;
16 | use Symfony\Component\Console\Input\InputArgument;
17 | use Symfony\Component\Console\Input\InputInterface;
18 | use Symfony\Component\Console\Input\InputOption;
19 | use Symfony\Component\Console\Output\OutputInterface;
20 |
21 | class AnalysisCommand extends Command implements NeedConfigurationInterface
22 | {
23 | protected function configure(): void
24 | {
25 | $this
26 | ->setName('analysis')
27 | ->addArgument('project-uuid', InputArgument::REQUIRED)
28 | ->addOption('format', null, InputOption::VALUE_REQUIRED, 'To output in other formats', 'txt')
29 | ->addOption('fail-condition', null, InputOption::VALUE_REQUIRED, '')
30 | ->addOption('show-ignored-violations', null, InputOption::VALUE_NONE, 'Show ignored violations')
31 | ->setDescription('Show the last project analysis')
32 | ;
33 | }
34 |
35 | protected function execute(InputInterface $input, OutputInterface $output): int
36 | {
37 | $api = $this->getApplication()->getApi();
38 | $analysis = $api->getProject($input->getArgument('project-uuid'))->getLastAnalysis();
39 |
40 | if (!$analysis) {
41 | $output->writeln('There are no analyses');
42 |
43 | return 1;
44 | }
45 |
46 | $helper = new DescriptorHelper($api->getSerializer());
47 | $helper->describe($output, $analysis, $input->getOption('format'), $input->getOption('show-ignored-violations'));
48 |
49 | if ('txt' === $input->getOption('format') && OutputInterface::VERBOSITY_VERBOSE > $output->getVerbosity()) {
50 | $output->writeln('');
51 | $output->writeln('Re-run this command with -v option to get the full report');
52 | }
53 |
54 | if (!$expr = $input->getOption('fail-condition')) {
55 | return 1;
56 | }
57 |
58 | return $this->getHelperSet()->get('fail_condition')->evaluate($analysis, $expr);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/Cli/Command/AnalyzeCommand.php:
--------------------------------------------------------------------------------
1 |
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 SensioLabs\Insight\Cli\Command;
13 |
14 | use SensioLabs\Insight\Cli\Helper\DescriptorHelper;
15 | use SensioLabs\Insight\Sdk\Api;
16 | use Symfony\Component\Console\Command\Command;
17 | use Symfony\Component\Console\Input\InputArgument;
18 | use Symfony\Component\Console\Input\InputInterface;
19 | use Symfony\Component\Console\Input\InputOption;
20 | use Symfony\Component\Console\Output\OutputInterface;
21 | use Symfony\Component\Console\Style\SymfonyStyle;
22 |
23 | class AnalyzeCommand extends Command implements NeedConfigurationInterface
24 | {
25 | protected function configure(): void
26 | {
27 | $this
28 | ->setName('analyze')
29 | ->addArgument('project-uuid', InputArgument::REQUIRED)
30 | ->addOption('format', null, InputOption::VALUE_REQUIRED, 'To output in other formats', 'txt')
31 | ->addOption('reference', null, InputOption::VALUE_REQUIRED, 'The git reference to analyze')
32 | ->addOption('branch', null, InputOption::VALUE_REQUIRED, 'The analysis current branch')
33 | ->addOption('show-ignored-violations', null, InputOption::VALUE_NONE, 'Show ignored violations')
34 | ->addOption('poll-period', null, InputOption::VALUE_REQUIRED, 'How regularly should the analysis status be checked in seconds', 30)
35 | ->addOption('fail-condition', null, InputOption::VALUE_REQUIRED, '')
36 | ->addOption('no-wait', null, InputOption::VALUE_NONE, 'Do not wait for analysis result')
37 | ->setDescription('Analyze a project')
38 | ;
39 | }
40 |
41 | protected function execute(InputInterface $input, OutputInterface $output): int
42 | {
43 | $projectUuid = $input->getArgument('project-uuid');
44 |
45 | $pollPeriod = (int) $input->getOption('poll-period');
46 | if ($pollPeriod < 30) {
47 | $pollPeriod = 30;
48 | }
49 |
50 | /** @var Api $api */
51 | $api = $this->getApplication()->getApi();
52 |
53 | if (false !== strpos($api->getBaseUrl(), '.sensiolabs.com')) {
54 | $io = new SymfonyStyle($input, $output);
55 | $io->warning('You are using the legacy URL of SymfonyInsight which may stop working in the future. You should reconfigure this tool by running the "configure" command and use "https://insight.symfony.com" as endpoint.');
56 | }
57 |
58 | $analysis = $api->analyze($projectUuid, $input->getOption('reference'), $input->getOption('branch'));
59 |
60 | $chars = ['-', '\\', '|', '/'];
61 | $noAnsiStatus = 'Analysis running';
62 | $output->getErrorOutput()->writeln($noAnsiStatus);
63 |
64 | if ($input->getOption('no-wait')) {
65 | $output->writeln('The analysis is launched. Please check the result in you SymfonyInsight notifications.');
66 |
67 | return 0;
68 | }
69 |
70 | $position = 1;
71 |
72 | while (true) {
73 | // Check the status every poll-period * 5 loops (5 * 200ms = 1s)
74 | if (0 === $position % (5 * $pollPeriod)) {
75 | $analysis = $api->getAnalysisStatus($projectUuid, $analysis->getNumber());
76 | }
77 |
78 | if ('txt' === $input->getOption('format')) {
79 | if (!$output->isDecorated()) {
80 | if ($noAnsiStatus !== $analysis->getStatusMessage()) {
81 | $output->writeln($noAnsiStatus = $analysis->getStatusMessage());
82 | }
83 | } else {
84 | $output->write(sprintf("%s %-80s\r", $chars[$position % 4], $analysis->getStatusMessage()));
85 | }
86 | }
87 |
88 | if ($analysis->isFinished()) {
89 | break;
90 | }
91 |
92 | usleep(200000);
93 |
94 | ++$position;
95 | }
96 |
97 | $analysis = $api->getAnalysis($projectUuid, $analysis->getNumber());
98 | if ($analysis->isFailed()) {
99 | $output->writeln(sprintf('There was an error: "%s"', $analysis->getFailureMessage()));
100 |
101 | return 1;
102 | }
103 |
104 | $helper = new DescriptorHelper($api->getSerializer());
105 | $helper->describe($output, $analysis, $input->getOption('format'), $input->getOption('show-ignored-violations'));
106 |
107 | if ('txt' === $input->getOption('format') && OutputInterface::VERBOSITY_VERBOSE > $output->getVerbosity()) {
108 | $output->writeln('');
109 | $output->writeln(sprintf('Run %s %s %s -v to get the full report', $_SERVER['PHP_SELF'], 'analysis', $projectUuid));
110 | }
111 |
112 | if (!$expr = $input->getOption('fail-condition')) {
113 | return 0;
114 | }
115 |
116 | return $this->getHelperSet()->get('fail_condition')->evaluate($analysis, $expr);
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/Cli/Command/ConfigureCommand.php:
--------------------------------------------------------------------------------
1 |
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 SensioLabs\Insight\Cli\Command;
13 |
14 | use Symfony\Component\Console\Command\Command;
15 | use Symfony\Component\Console\Input\InputInterface;
16 | use Symfony\Component\Console\Output\OutputInterface;
17 |
18 | class ConfigureCommand extends Command
19 | {
20 | protected function configure(): void
21 | {
22 | $this
23 | ->setName('configure')
24 | ->setDescription('(Re-)Configure your credentials.')
25 | ;
26 | }
27 |
28 | protected function execute(InputInterface $input, OutputInterface $output): int
29 | {
30 | $this->getHelperSet()->get('configuration')->updateConfigurationManually($input, $output);
31 |
32 | return 0;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Cli/Command/NeedConfigurationInterface.php:
--------------------------------------------------------------------------------
1 |
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 SensioLabs\Insight\Cli\Command;
13 |
14 | interface NeedConfigurationInterface
15 | {
16 | }
17 |
--------------------------------------------------------------------------------
/Cli/Command/ProjectsCommand.php:
--------------------------------------------------------------------------------
1 |
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 SensioLabs\Insight\Cli\Command;
13 |
14 | use Symfony\Component\Console\Command\Command;
15 | use Symfony\Component\Console\Helper\Table;
16 | use Symfony\Component\Console\Input\InputInterface;
17 | use Symfony\Component\Console\Output\OutputInterface;
18 |
19 | class ProjectsCommand extends Command implements NeedConfigurationInterface
20 | {
21 | protected function configure(): void
22 | {
23 | $this
24 | ->setName('projects')
25 | ->setDescription('List all your projects')
26 | ;
27 | }
28 |
29 | protected function execute(InputInterface $input, OutputInterface $output): int
30 | {
31 | $api = $this->getApplication()->getApi();
32 |
33 | $projectsResource = $api->getProjects();
34 | $projects = $projectsResource->getProjects();
35 | $nbPage = ceil($projectsResource->getTotal() / 10);
36 | $page = 1;
37 | while ($page < $nbPage) {
38 | ++$page;
39 | $projects = array_merge($projects, $api->getProjects($page)->getProjects());
40 | }
41 |
42 | if (!$projects) {
43 | $output->writeln('There are no projects');
44 | }
45 |
46 | $rows = [];
47 | foreach ($projects as $project) {
48 | if ($project->getLastAnalysis()) {
49 | $grade = $project->getLastAnalysis()->getGrade();
50 | } else {
51 | $grade = 'This project has no analyses';
52 | }
53 | $rows[] = [$project->getName(), $project->getUuid(), $grade];
54 | }
55 |
56 | $table = new Table($output);
57 | $table->setHeaders(['name', 'uuid', 'grade'])
58 | ->setRows($rows)
59 | ->render()
60 | ;
61 |
62 | return 0;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/Cli/Command/SelfUpdateCommand.php:
--------------------------------------------------------------------------------
1 |
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 SensioLabs\Insight\Cli\Command;
13 |
14 | use Symfony\Component\Console\Command\Command;
15 | use Symfony\Component\Console\Input\InputInterface;
16 | use Symfony\Component\Console\Output\OutputInterface;
17 |
18 | /**
19 | * @author Igor Wiedler
20 | * @author Stephane PY
21 | * @author Grégoire Pineau
22 | */
23 | class SelfUpdateCommand extends Command
24 | {
25 | /**
26 | * {@inheritdoc}
27 | */
28 | protected function configure(): void
29 | {
30 | $this
31 | ->setName('self-update')
32 | ->setDescription('Update insight.phar to the latest version.')
33 | ->setHelp(<<%command.name% command replace your insight.phar by the latest
35 | version.
36 |
37 | php insight.phar %command.name%
38 |
39 | EOT
40 | )
41 | ;
42 | }
43 |
44 | /**
45 | * {@inheritdoc}
46 | */
47 | protected function execute(InputInterface $input, OutputInterface $output): int
48 | {
49 | $remoteFilename = 'http://get.insight.sensiolabs.com/insight.phar';
50 | $localFilename = $_SERVER['argv'][0];
51 | $tempFilename = basename($localFilename, '.phar').'-temp.phar';
52 |
53 | try {
54 | copy($remoteFilename, $tempFilename);
55 |
56 | if (md5_file($localFilename) == md5_file($tempFilename)) {
57 | $output->writeln('insight is already up to date.');
58 | unlink($tempFilename);
59 |
60 | return 0;
61 | }
62 |
63 | chmod($tempFilename, 0777 & ~umask());
64 |
65 | // test the phar validity
66 | $phar = new \Phar($tempFilename);
67 | // free the variable to unlock the file
68 | unset($phar);
69 | rename($tempFilename, $localFilename);
70 |
71 | $output->writeln('insight updated.');
72 |
73 | return 0;
74 | } catch (\Exception $e) {
75 | if (!$e instanceof \UnexpectedValueException && !$e instanceof \PharException) {
76 | throw $e;
77 | }
78 | unlink($tempFilename);
79 | $output->writeln('The download is corrupt ('.$e->getMessage().').');
80 | $output->writeln('Please re-run the self-update command to try again.');
81 |
82 | return 1;
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/Cli/Configuration.php:
--------------------------------------------------------------------------------
1 | storagePath = $this->getStoragePath();
15 | $this->load();
16 | }
17 |
18 | public function getUserUuid()
19 | {
20 | return $this->userUuid;
21 | }
22 |
23 | public function setUserUuid($userUuid)
24 | {
25 | $this->userUuid = $userUuid;
26 | }
27 |
28 | public function getApiToken()
29 | {
30 | return $this->apiToken;
31 | }
32 |
33 | public function setApiToken($apiToken)
34 | {
35 | $this->apiToken = $apiToken;
36 | }
37 |
38 | public function getApiEndpoint()
39 | {
40 | return $this->apiEndpoint;
41 | }
42 |
43 | public function setApiEndpoint($apiEndpoint)
44 | {
45 | $this->apiEndpoint = $apiEndpoint;
46 | }
47 |
48 | public function toArray()
49 | {
50 | return [
51 | 'user_uuid' => $this->userUuid,
52 | 'api_token' => $this->apiToken,
53 | 'api_endpoint' => $this->apiEndpoint,
54 | ];
55 | }
56 |
57 | public function save()
58 | {
59 | file_put_contents($this->storagePath, json_encode($this->toArray()));
60 | }
61 |
62 | public function equals(self $configuration)
63 | {
64 | if ($this->userUuid !== $configuration->userUuid) {
65 | return false;
66 | }
67 | if ($this->apiToken !== $configuration->apiToken) {
68 | return false;
69 | }
70 | if ($this->apiEndpoint !== $configuration->apiEndpoint) {
71 | return false;
72 | }
73 |
74 | return true;
75 | }
76 |
77 | private function load()
78 | {
79 | if (!file_exists($this->storagePath)) {
80 | return;
81 | }
82 |
83 | $data = json_decode(file_get_contents($this->storagePath), true);
84 |
85 | if (\array_key_exists('user_uuid', $data)) {
86 | $this->userUuid = $data['user_uuid'];
87 | }
88 | if (\array_key_exists('api_token', $data)) {
89 | $this->apiToken = $data['api_token'];
90 | }
91 | if (\array_key_exists('api_endpoint', $data)) {
92 | $this->apiEndpoint = $data['api_endpoint'];
93 | }
94 | }
95 |
96 | private function getStoragePath()
97 | {
98 | $storagePath = getenv('INSIGHT_HOME');
99 |
100 | if (!$storagePath) {
101 | if (\defined('PHP_WINDOWS_VERSION_MAJOR')) {
102 | if (!getenv('APPDATA')) {
103 | throw new \RuntimeException('The APPDATA or INSIGHT_HOME environment variable must be set for insight to run correctly');
104 | }
105 | $storagePath = strtr(getenv('APPDATA'), '\\', '/').'/Sensiolabs';
106 | } else {
107 | if (!getenv('HOME')) {
108 | throw new \RuntimeException('The HOME or INSIGHT_HOME environment variable must be set for insight to run correctly');
109 | }
110 | $storagePath = rtrim(getenv('HOME'), '/').'/.sensiolabs';
111 | }
112 | }
113 |
114 | if (!is_dir($storagePath) && !@mkdir($storagePath, 0777, true)) {
115 | throw new \RuntimeException(sprintf('The directory "%s" does not exist and could not be created.', $storagePath));
116 | }
117 |
118 | if (!is_writable($storagePath)) {
119 | throw new \RuntimeException(sprintf('The directory "%s" is not writable.', $storagePath));
120 | }
121 |
122 | return $storagePath.'/insight.json';
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/Cli/Descriptor/AbstractDescriptor.php:
--------------------------------------------------------------------------------
1 |
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 SensioLabs\Insight\Cli\Descriptor;
13 |
14 | use SensioLabs\Insight\Sdk\Model\Analysis;
15 | use SensioLabs\Insight\Sdk\Model\Violation;
16 |
17 | abstract class AbstractDescriptor
18 | {
19 | public function describe($object, array $options = [])
20 | {
21 | if ($object instanceof Analysis) {
22 | if (!$options['show_ignored_violations'] && $object->getViolations()) {
23 | $object->getViolations()->filter(function (Violation $v) {
24 | return !$v->isIgnored();
25 | });
26 | }
27 |
28 | return $this->describeAnalysis($object, $options);
29 | }
30 |
31 | throw new \InvalidArgumentException(sprintf('Object of type "%s" is not describable.', \get_class($object)));
32 | }
33 |
34 | abstract protected function describeAnalysis(Analysis $argument, array $options = []);
35 | }
36 |
--------------------------------------------------------------------------------
/Cli/Descriptor/JsonDescriptor.php:
--------------------------------------------------------------------------------
1 |
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 SensioLabs\Insight\Cli\Descriptor;
13 |
14 | use JMS\Serializer\Serializer;
15 | use SensioLabs\Insight\Sdk\Model\Analysis;
16 |
17 | class JsonDescriptor extends AbstractDescriptor
18 | {
19 | private $serializer;
20 |
21 | public function __construct(Serializer $serializer)
22 | {
23 | $this->serializer = $serializer;
24 | }
25 |
26 | protected function describeAnalysis(Analysis $analysis, array $options = [])
27 | {
28 | $output = $options['output'];
29 | $output->writeln($this->serializer->serialize($analysis, 'json'));
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Cli/Descriptor/PmdDescriptor.php:
--------------------------------------------------------------------------------
1 | formatOutput = true;
24 | $xml->preserveWhiteSpace = true;
25 |
26 | $pmd = $xml->createElement('pmd');
27 | $pmd->setAttribute('timestamp', $analysis->getEndAt()->format('c'));
28 |
29 | $xml->appendChild($pmd);
30 |
31 | $violations = $analysis->getViolations();
32 | if ($violations) {
33 | foreach ($violations as $violation) {
34 | /*
35 | * @var $violation \SensioLabs\Insight\Sdk\Model\Violation
36 | */
37 | $filename = $violation->getResource();
38 |
39 | $nodes = $xpath->query(sprintf('//file[@name="%s"]', $filename));
40 |
41 | if ($nodes->length > 0) {
42 | $node = $nodes->item(0);
43 | } else {
44 | $node = $xml->createElement('file');
45 | $node->setAttribute('name', $filename);
46 |
47 | $pmd->appendChild($node);
48 | }
49 |
50 | $violationNode = $xml->createElement('violation', $violation->getMessage());
51 | $node->appendChild($violationNode);
52 |
53 | $violationNode->setAttribute('beginline', $violation->getLine());
54 | $violationNode->setAttribute('endline', $violation->getLine());
55 | $violationNode->setAttribute('rule', $violation->getTitle());
56 | $violationNode->setAttribute('ruleset', $violation->getCategory());
57 | $violationNode->setAttribute('priority', $this->getPriority($violation));
58 | }
59 | }
60 |
61 | $output->writeln($xml->saveXML());
62 | }
63 |
64 | private function getPriority(Violation $violation)
65 | {
66 | switch ($violation->getSeverity()) {
67 | case 'critical':
68 | return self::PHPMD_PRIORITY_HIGH;
69 |
70 | case 'major':
71 | return self::PHPMD_PRIORITY_MEDIUM;
72 |
73 | default:
74 | return self::PHPMD_PRIORITY_LOW;
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/Cli/Descriptor/TextDescriptor.php:
--------------------------------------------------------------------------------
1 |
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 SensioLabs\Insight\Cli\Descriptor;
13 |
14 | use SensioLabs\Insight\Sdk\Model\Analysis;
15 | use Symfony\Component\Console\Output\OutputInterface;
16 |
17 | class TextDescriptor extends AbstractDescriptor
18 | {
19 | protected function describeAnalysis(Analysis $analysis, array $options = [])
20 | {
21 | $output = $options['output'];
22 | if (OutputInterface::VERBOSITY_VERY_VERBOSE <= $output->getVerbosity()) {
23 | $output->write(sprintf('Began at: %s', $analysis->getBeginAt()->format('Y-m-d h:i:s')));
24 | }
25 | if (!$analysis->isFinished()) {
26 | if (OutputInterface::VERBOSITY_VERY_VERBOSE <= $output->getVerbosity()) {
27 | $output->writeln('');
28 | }
29 | $output->writeln('The analysis is not finished yet.');
30 |
31 | return;
32 | }
33 | if (OutputInterface::VERBOSITY_VERY_VERBOSE <= $output->getVerbosity()) {
34 | $output->write(sprintf(' Ended at: %s', $analysis->getEndAt()->format('Y-m-d h:i:s')));
35 | $output->writeln(sprintf(' Real duration: %s.', $analysis->getEndAt()->format('Y-m-d h:i:s')));
36 | $output->writeln('');
37 | }
38 | $output->write(sprintf(
39 | 'The project has %d violations, it got the %s grade.',
40 | $analysis->getNbViolations(),
41 | $analysis->getGrade()
42 | ));
43 |
44 | $grades = $analysis->getGrades();
45 | $bestGrade = end($grades);
46 | if ($bestGrade == $analysis->getGrade()) {
47 | $output->writeln('');
48 |
49 | return;
50 | }
51 |
52 | $output->writeln(sprintf(
53 | ' %d hours to get the %s grade and %d hours to get the %s grade',
54 | $analysis->getRemediationCostForNextGrade(),
55 | $analysis->getNextGrade(),
56 | $analysis->getRemediationCost(),
57 | $bestGrade
58 | ));
59 | $output->writeln('');
60 |
61 | if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity() && $analysis->getViolations()) {
62 | $template = <<{{ resource }}:{{ line }}
64 | Category: {{ category }} Severity: {{ severity }}
65 | Title: {{ title }}{{ ignored }}
66 | Message: {{ message }}
67 |
68 | EOL;
69 | foreach ($analysis->getViolations() as $violation) {
70 | $output->writeln(strtr($template, [
71 | '{{ resource }}' => $violation->getResource(),
72 | '{{ line }}' => $violation->getLine(),
73 | '{{ category }}' => $violation->getCategory(),
74 | '{{ severity }}' => $violation->getSeverity(),
75 | '{{ title }}' => $violation->getTitle(),
76 | '{{ message }}' => $violation->getMessage(),
77 | '{{ ignored }}' => $violation->isIgnored() ? ' (ignored)' : null,
78 | ]));
79 | }
80 | }
81 |
82 | foreach ($analysis->getLinks() as $link) {
83 | if ('self' == $link->getRel() && 'text/html' == $link->getType()) {
84 | $output->writeln(sprintf('You can get the full report at %s', $link->getHref()));
85 |
86 | break;
87 | }
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/Cli/Descriptor/XmlDescriptor.php:
--------------------------------------------------------------------------------
1 |
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 SensioLabs\Insight\Cli\Descriptor;
13 |
14 | use JMS\Serializer\Serializer;
15 | use SensioLabs\Insight\Sdk\Model\Analysis;
16 |
17 | class XmlDescriptor extends AbstractDescriptor
18 | {
19 | private $serializer;
20 |
21 | public function __construct(Serializer $serializer)
22 | {
23 | $this->serializer = $serializer;
24 | }
25 |
26 | protected function describeAnalysis(Analysis $analysis, array $options = [])
27 | {
28 | $output = $options['output'];
29 | $output->writeln($this->serializer->serialize($analysis, 'xml'));
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Cli/Helper/ConfigurationHelper.php:
--------------------------------------------------------------------------------
1 | apiEndpoint = $apiEndpoint;
20 | }
21 |
22 | public function updateConfigurationManually(InputInterface $input, OutputInterface $output)
23 | {
24 | $configuration = new Configuration();
25 |
26 | $userUuid = $input->getOption('user-uuid') ?: $configuration->getUserUuid();
27 | $apiToken = $input->getOption('api-token') ?: $configuration->getApiToken();
28 |
29 | // Avoid saving again a legacy URL
30 | $defaultEndpoint = $configuration->getApiEndpoint();
31 | if (false !== strpos($defaultEndpoint, '.sensiolabs.com')) {
32 | $defaultEndpoint = null;
33 | }
34 |
35 | $apiEndpoint = $input->getOption('api-endpoint') ?: $defaultEndpoint;
36 |
37 | $configuration->setUserUuid($this->askValue($input, $output, 'User Uuid', $userUuid));
38 | $configuration->setApiToken($this->askValue($input, $output, 'Api Token', $apiToken));
39 | $configuration->setApiEndpoint($this->askValue($input, $output, 'Api Endpoint', $apiEndpoint ?: $this->apiEndpoint));
40 |
41 | if (false !== strpos($configuration->getApiEndpoint(), '.sensiolabs.com')) {
42 | $io = new SymfonyStyle($input, $output);
43 | $io->warning('You are using the legacy URL of SymfonyInsight which may stop working in the future. You should reconfigure this tool by running the "configure" command and use "https://insight.symfony.com" as endpoint.');
44 | }
45 |
46 | $this->saveConfiguration($input, $output, $configuration);
47 | }
48 |
49 | public function getConfiguration(InputInterface $input, OutputInterface $output)
50 | {
51 | $previousConfiguration = new Configuration();
52 | $configuration = clone $previousConfiguration;
53 |
54 | $this->resolveValue($input, $output, $configuration, 'User Uuid', null);
55 | $this->resolveValue($input, $output, $configuration, 'Api Token', null);
56 | $this->resolveValue($input, $output, $configuration, 'Api Endpoint', $this->apiEndpoint);
57 |
58 | if (!$configuration->equals($previousConfiguration)) {
59 | $this->saveConfiguration($input, $output, $configuration);
60 | }
61 |
62 | return $configuration;
63 | }
64 |
65 | public function getName(): string
66 | {
67 | return 'configuration';
68 | }
69 |
70 | private function resolveValue(InputInterface $input, OutputInterface $output, Configuration $configuration, $varName, $default = null)
71 | {
72 | $configurationProperty = str_replace(' ', '', $varName);
73 |
74 | $value = $this->getValue($input, $varName);
75 |
76 | if (!$value) {
77 | $value = $configuration->{'get'.$configurationProperty}();
78 | }
79 | if (!$value) {
80 | $value = $default;
81 | }
82 | if (!$value && $input->isInteractive()) {
83 | $value = $this->askValue($input, $output, $varName);
84 | }
85 | if (!$value) {
86 | throw new \InvalidArgumentException(sprintf('You should provide your %s.', $varName));
87 | }
88 | $configuration->{'set'.$configurationProperty}($value);
89 | }
90 |
91 | private function getValue(InputInterface $input, $varName)
92 | {
93 | $envVarName = sprintf('INSIGHT_%s', str_replace(' ', '_', strtoupper($varName)));
94 | if ($value = getenv($envVarName)) {
95 | return $value;
96 | }
97 |
98 | $cliVarName = sprintf('--%s', str_replace(' ', '-', strtolower($varName)));
99 |
100 | return $input->getParameterOption($cliVarName);
101 | }
102 |
103 | private function askValue(InputInterface $input, OutputInterface $output, $varname, $default = null)
104 | {
105 | $validator = static function ($v) use ($varname) {
106 | if (!$v) {
107 | throw new \InvalidArgumentException(sprintf('Your must provide a %s!', $varname));
108 | }
109 |
110 | return $v;
111 | };
112 |
113 | if (!$input->isInteractive()) {
114 | return $validator($default);
115 | }
116 |
117 | $question = new Question(
118 | $default ? sprintf('What is your %s? [%s] ', $varname, $default) : sprintf('What is your %s? ', $varname),
119 | $default
120 | );
121 |
122 | $question->setValidator($validator);
123 |
124 | return $this->getHelperSet()->get('question')->ask($input, $output, $question);
125 | }
126 |
127 | private function saveConfiguration(InputInterface $input, OutputInterface $output, Configuration $configuration)
128 | {
129 | if (!$input->isInteractive()) {
130 | $configuration->save();
131 |
132 | return;
133 | }
134 |
135 | $question = new ConfirmationQuestion('Do you want to save this new configuration? [Y/n] ');
136 |
137 | if ($this->getHelperSet()->get('question')->ask($input, $output, $question)) {
138 | $configuration->save();
139 | }
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/Cli/Helper/DescriptorHelper.php:
--------------------------------------------------------------------------------
1 |
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 SensioLabs\Insight\Cli\Helper;
13 |
14 | use JMS\Serializer\Serializer;
15 | use SensioLabs\Insight\Cli\Descriptor\AbstractDescriptor;
16 | use SensioLabs\Insight\Cli\Descriptor\JsonDescriptor;
17 | use SensioLabs\Insight\Cli\Descriptor\PmdDescriptor;
18 | use SensioLabs\Insight\Cli\Descriptor\TextDescriptor;
19 | use SensioLabs\Insight\Cli\Descriptor\XmlDescriptor;
20 | use Symfony\Component\Console\Helper\Helper;
21 | use Symfony\Component\Console\Output\OutputInterface;
22 |
23 | class DescriptorHelper extends Helper
24 | {
25 | private $descriptors = [];
26 |
27 | public function __construct(Serializer $serializer)
28 | {
29 | $this
30 | ->register('json', new JsonDescriptor($serializer))
31 | ->register('pmd', new PmdDescriptor())
32 | ->register('txt', new TextDescriptor())
33 | ->register('xml', new XmlDescriptor($serializer))
34 | ;
35 | }
36 |
37 | public function describe(OutputInterface $output, $object, $format = null, $showIgnoredViolation = false)
38 | {
39 | $options = [
40 | 'raw_text' => false,
41 | 'format' => $format ?: 'txt',
42 | 'output' => $output,
43 | 'show_ignored_violations' => $showIgnoredViolation,
44 | ];
45 | $options['type'] = 'txt' === $options['format'] ? OutputInterface::OUTPUT_NORMAL : OutputInterface::OUTPUT_RAW;
46 |
47 | if (!isset($this->descriptors[$options['format']])) {
48 | throw new \InvalidArgumentException(sprintf('Unsupported format "%s".', $options['format']));
49 | }
50 |
51 | $this->descriptors[$options['format']]->describe($object, $options);
52 | }
53 |
54 | public function register($format, AbstractDescriptor $descriptor)
55 | {
56 | $this->descriptors[$format] = $descriptor;
57 |
58 | return $this;
59 | }
60 |
61 | /**
62 | * {@inheritdoc}
63 | */
64 | public function getName(): string
65 | {
66 | return 'descriptor';
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/Cli/Helper/FailConditionHelper.php:
--------------------------------------------------------------------------------
1 |
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 SensioLabs\Insight\Cli\Helper;
13 |
14 | use SensioLabs\Insight\Sdk\Model\Analysis;
15 | use Symfony\Component\Console\Helper\Helper;
16 | use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
17 |
18 | class FailConditionHelper extends Helper
19 | {
20 | private $el;
21 |
22 | public function __construct()
23 | {
24 | $this->el = new ExpressionLanguage();
25 | }
26 |
27 | public function evaluate(Analysis $analysis, $expr)
28 | {
29 | $analysisData = [
30 | 'grade' => $analysis->getGrade(),
31 | 'nbViolations' => 0,
32 | 'remediationCost' => $analysis->getRemediationCost(),
33 | ];
34 |
35 | $counts = [
36 | // Category
37 | 'architecture' => 0,
38 | 'bugrisk' => 0,
39 | 'codestyle' => 0,
40 | 'deadcode' => 0,
41 | 'performance' => 0,
42 | 'readability' => 0,
43 | 'security' => 0,
44 |
45 | // Severity
46 | 'critical' => 0,
47 | 'major' => 0,
48 | 'minor' => 0,
49 | 'info' => 0,
50 | ];
51 |
52 | $violations = $analysis->getViolations() ?: [];
53 |
54 | foreach ($violations as $violation) {
55 | ++$counts[$violation->getCategory()];
56 | ++$counts[$violation->getSeverity()];
57 | ++$analysisData['nbViolations'];
58 | }
59 |
60 | $vars = [
61 | 'analysis' => (object) $analysisData,
62 | 'counts' => (object) $counts,
63 | ];
64 |
65 | if ($this->el->evaluate($expr, $vars)) {
66 | return 70;
67 | }
68 |
69 | return 0;
70 | }
71 |
72 | public function getName(): string
73 | {
74 | return 'fail_condition';
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013 Symfony
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is furnished
8 | to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | SymfonyInsight SDK
2 | ==================
3 |
4 | About
5 | -----
6 |
7 | This is the official SDK for the [SymfonyInsight](https://insight.symfony.com/) API.
8 |
9 | Installation
10 | ------------
11 |
12 | To install the SDK, run the command below and you will get the latest version:
13 |
14 | composer require sensiolabs/insight
15 |
16 | Command Line Tool
17 | -----------------
18 |
19 | The easiest way to use the SymfonyInsight API is via the built-in command line tool.
20 |
21 | A phar version of the command line tool exists to avoid installation of this
22 | project. Download it, then use it like the command line tool:
23 |
24 | $ curl -o insight.phar -s https://get.insight.symfony.com/insight.phar
25 | # or
26 | $ wget https://get.insight.symfony.com/insight.phar
27 |
28 | # Then
29 | $ php insight.phar
30 |
31 | List all the projects in your account:
32 |
33 | $ php insight.phar projects
34 |
35 | The first time, you will be prompted for your SymfonyInsight API key and
36 | user UUID (which can be found under the ["Account" section](https://insight.symfony.com/account) on the website).
37 |
38 | These information are then stored locally, but can still be overridden via the
39 | `--api-token` and `--user-uuid` options.
40 |
41 | To run an analysis:
42 |
43 | $ php insight.phar analyze UUID
44 |
45 | where `UUID` is the UUID of the project you want to analyze (the UUIDs are
46 | listed by the `projects` command).
47 |
48 | To export an analysis report:
49 |
50 | $ php insight.phar analysis UUID --format="xml" # or --format="json" or --format="pmd"
51 |
52 | Configuration
53 | -------------
54 |
55 | use SensioLabs\Insight\Sdk\Api;
56 |
57 | $api = new Api(array(
58 | 'api_token' => 'your api token',
59 | 'user_uuid' => 'your user uuid',
60 | ));
61 |
62 | Usage
63 | -----
64 |
65 | ### List all projects:
66 |
67 | $api->getProjects();
68 | $api->getProjects(2); // For the second page
69 |
70 | ### Get a project:
71 |
72 | $project = $api->getProject('project uuid');
73 |
74 | ### Update a project
75 |
76 | $api->updateProject($project);
77 |
78 | Note: If something went wrong, see *Error management* section
79 |
80 | ### Post a project
81 |
82 | use SensioLabs\Insight\Sdk\Model\Project;
83 |
84 | $project = new Project();
85 | $project
86 | ->setName('Foo')
87 | ->setDescription('Foo')
88 | ->setType(TYPE_WEBSITE::TYPE_WEBSITE)
89 | ;
90 |
91 | $api->createProject($project)
92 |
93 | Note: If something went wrong, see *Error management* section
94 |
95 | ### Run an analysis
96 |
97 | // on the default branch
98 | $api->analyze('project uuid', 'master');
99 |
100 | // for a specific branch or reference
101 | $api->analyze('project uuid', '1.0');
102 |
103 | ### Get all analyses
104 |
105 | $api->getAnalyses('project uuid');
106 |
107 | // for a specific branch
108 | $api->getAnalyses('project uuid', 'branch name');
109 |
110 | ### Get an analysis
111 |
112 | $api->getAnalysis('project uuid', 'analysis id');
113 |
114 | ### Get a status analysis
115 |
116 | $api->getAnalysisStatus('project uuid', 'analysis id');
117 |
118 | ### Error management
119 |
120 | If something went wrong, an
121 | `SensioLabs\Insight\Sdk\Exception\ExceptionInterface` will be throw:
122 |
123 | * `ApiClientException` If you did something wrong. This exception contains the
124 | previous exception throw by guzzle. You can easily check if it is a:
125 | * 403: In this case, check your credentials
126 | * 404: In this case, check your request
127 | * 400: In this case, check the data sent. In this case, the Exception will
128 | contains a `SensioLabs\Insight\Sdk\Model\Error` object. Which will contains
129 | all form errors.
130 | * `ApiServerException` If something went wrong with the API.
131 |
132 | Jenkins/Hudson Integration
133 | --------------------------
134 |
135 | Thanks to [Jenkins PMD Plugin](https://wiki.jenkins-ci.org/display/JENKINS/PMD+Plugin) and
136 | SymfonyInsight SDK PMD output you can easily embed SymfonyInsight reports into your build
137 | workflow, following these steps:
138 |
139 | *It is assumed you already have your project up and building in Jenkins and SymfonyInsight SDK installed*.
140 |
141 | 1. Retrieve your `SymfonyInsight API Token`, `User UUID` and `Project UUID`
142 | on your [account page](https://insight.symfony.com/account)
143 | 2. Install the Jenkins `PMD plugin`:
144 | [How to install a jenkins plugin](https://wiki.jenkins-ci.org/display/JENKINS/Plugins#Plugins-Howtoinstallplugins)
145 | 3. Optionally you can also install the `EnvInject Plugin`
146 | 4. Edit your project configuration
147 | 5. If you have EnvInject Plugin installed,
148 | enabled `Set environment variables` then add and adapt the following lines to variables name:
149 |
150 | INSIGHT_API_TOKEN="Your API Token"
151 | INSIGHT_USER_UUID="Your user UUID"
152 | INSIGHT_PROJECT_UUID="Your project UUID"
153 |
154 | 6. Add a `Execute shell` build step
155 | 7. In the new shell step add and adapt the following command (if you don't have EnvInject plugin, replace variables by plain values):
156 |
157 | /path/to/insight-sdk/bin/insight analysis \
158 | --user-uuid $INSIGHT_USER_UUID \
159 | --api-token $INSIGHT_API_TOKEN \
160 | $INSIGHT_PROJECT_UUID --format=pmd > insight-pmd.xml
161 |
162 | 8. Enable `Publish PMD analysis results` using `insight-pmd.xml` as PMD result filename
163 | 9. Optionally, you can add the `insight-pmd.xml` file to artifacts to archive
164 | 10. Save and build!
165 |
166 | License
167 | -------
168 |
169 | This library is licensed under the MIT license.
170 |
--------------------------------------------------------------------------------
/Sdk/Api.php:
--------------------------------------------------------------------------------
1 |
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 SensioLabs\Insight\Sdk;
13 |
14 | use JMS\Serializer\Serializer;
15 | use JMS\Serializer\SerializerBuilder;
16 | use Psr\Log\LoggerInterface;
17 | use SensioLabs\Insight\Sdk\Exception\ApiClientException;
18 | use SensioLabs\Insight\Sdk\Exception\ApiServerException;
19 | use SensioLabs\Insight\Sdk\Model\Analyses;
20 | use SensioLabs\Insight\Sdk\Model\Analysis;
21 | use SensioLabs\Insight\Sdk\Model\Project;
22 | use SensioLabs\Insight\Sdk\Model\Projects;
23 | use Symfony\Component\HttpClient\HttpClient;
24 | use Symfony\Component\HttpClient\ScopingHttpClient;
25 | use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
26 | use Symfony\Contracts\HttpClient\Exception\ExceptionInterface;
27 | use Symfony\Contracts\HttpClient\Exception\HttpExceptionInterface;
28 | use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
29 | use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
30 | use Symfony\Contracts\HttpClient\HttpClientInterface;
31 |
32 | class Api
33 | {
34 | const ENDPOINT = 'https://insight.symfony.com';
35 |
36 | private $baseUrl;
37 | private $httpClient;
38 | private $serializer;
39 | private $parser;
40 | private $logger;
41 |
42 | public function __construct(array $options = [], ?HttpClientInterface $httpClient = null, ?Parser $parser = null, ?LoggerInterface $logger = null)
43 | {
44 | $this->httpClient = $httpClient ?: HttpClient::create();
45 | $this->parser = $parser ?: new Parser();
46 |
47 | $defaultOptions = [
48 | 'base_url' => static::ENDPOINT,
49 | 'cache' => false,
50 | 'debug' => false,
51 | ];
52 |
53 | $required = ['api_token', 'base_url', 'user_uuid'];
54 | $options = array_merge($defaultOptions, $options);
55 |
56 | if ($missing = array_diff($required, array_keys($options))) {
57 | throw new \Exception('Config is missing the following keys: '.implode(', ', $missing));
58 | }
59 |
60 | $this->baseUrl = $options['base_url'];
61 |
62 | $this->httpClient = new ScopingHttpClient(
63 | $this->httpClient,
64 | [
65 | '.+' => [
66 | 'base_uri' => $this->baseUrl,
67 | 'auth_basic' => [$options['user_uuid'], $options['api_token']],
68 | 'headers' => ['accept' => 'application/vnd.com.sensiolabs.insight+xml'],
69 | ],
70 | ],
71 | '.+'
72 | );
73 |
74 | $serializerBuilder = SerializerBuilder::create()
75 | ->addMetadataDir(__DIR__.'/Model')
76 | ->setDebug($options['debug'])
77 | ;
78 |
79 | if ($cache = $options['cache']) {
80 | $serializerBuilder = $serializerBuilder->setCacheDir($cache);
81 | }
82 |
83 | $this->serializer = $serializerBuilder->build();
84 | $this->logger = $logger;
85 | }
86 |
87 | public function getBaseUrl(): string
88 | {
89 | return $this->baseUrl;
90 | }
91 |
92 | /**
93 | * @param int $page
94 | *
95 | * @return Projects
96 | */
97 | public function getProjects($page = 1)
98 | {
99 | return $this->serializer->deserialize(
100 | $this->send('GET', '/api/projects?page='.$page),
101 | Projects::class,
102 | 'xml'
103 | );
104 | }
105 |
106 | /**
107 | * @param string $uuid
108 | *
109 | * @return Project
110 | */
111 | public function getProject($uuid)
112 | {
113 | return $this->serializer->deserialize(
114 | $this->send('GET', sprintf('/api/projects/%s', $uuid)),
115 | Project::class,
116 | 'xml'
117 | );
118 | }
119 |
120 | /**
121 | * @return Project
122 | */
123 | public function updateProject(Project $project)
124 | {
125 | return $this->serializer->deserialize(
126 | $this->send('PUT', sprintf('/api/projects/%s', $project->getUuid()), ['insight_project' => $project->toArray()]),
127 | Project::class,
128 | 'xml'
129 | );
130 | }
131 |
132 | /**
133 | * @return Project
134 | */
135 | public function createProject(Project $project)
136 | {
137 | return $this->serializer->deserialize(
138 | $this->send('POST', '/api/projects', ['insight_project' => $project->toArray()]),
139 | Project::class,
140 | 'xml'
141 | );
142 | }
143 |
144 | /**
145 | * @param string $projectUuid
146 | *
147 | * @return Analyses
148 | */
149 | public function getAnalyses($projectUuid, $branch = null)
150 | {
151 | $url = sprintf('/api/projects/%s/analyses', $projectUuid);
152 |
153 | if ($branch) {
154 | $url .= '?branch='.$branch;
155 | }
156 |
157 | return $this->serializer->deserialize(
158 | $this->send('GET', $url),
159 | Analyses::class,
160 | 'xml'
161 | );
162 | }
163 |
164 | /**
165 | * @param string $projectUuid
166 | * @param int $analysesNumber
167 | *
168 | * @return Analysis
169 | */
170 | public function getAnalysis($projectUuid, $analysesNumber)
171 | {
172 | return $this->serializer->deserialize(
173 | $this->send('GET', sprintf('/api/projects/%s/analyses/%s', $projectUuid, $analysesNumber), null),
174 | Analysis::class,
175 | 'xml'
176 | );
177 | }
178 |
179 | /**
180 | * @param string $projectUuid
181 | * @param int $analysesNumber
182 | *
183 | * @return Analysis an incomplete Analysis object
184 | */
185 | public function getAnalysisStatus($projectUuid, $analysesNumber)
186 | {
187 | return $this->serializer->deserialize(
188 | $this->send('GET', sprintf('/api/projects/%s/analyses/%s/status', $projectUuid, $analysesNumber)),
189 | Analysis::class,
190 | 'xml'
191 | );
192 | }
193 |
194 | /**
195 | * @param string $projectUuid
196 | * @param string|null $reference A git reference. It can be a commit sha, a tag name or a branch name
197 | * @param string|null $branch Current analysis branch, used by SymfonyInsight to distinguish between the main branch and PRs
198 | *
199 | * @return Analysis
200 | */
201 | public function analyze($projectUuid, $reference = null, $branch = null)
202 | {
203 | return $this->serializer->deserialize(
204 | $this->send(
205 | 'POST',
206 | sprintf('/api/projects/%s/analyses', $projectUuid),
207 | $branch ? ['reference' => $reference, 'branch' => $branch] : ['reference' => $reference]
208 | ),
209 | Analysis::class,
210 | 'xml'
211 | );
212 | }
213 |
214 | /**
215 | * Use this method to call a specific API resource.
216 | */
217 | public function call($method = 'GET', $uri = null, $headers = null, $body = null, array $options = [], $classToUnserialize = null)
218 | {
219 | if ($classToUnserialize) {
220 | return $this->serializer->deserialize(
221 | $this->send($method, $uri, $body),
222 | $classToUnserialize,
223 | 'xml'
224 | );
225 | }
226 |
227 | return $this->send($method, $uri, $body);
228 | }
229 |
230 | public function setLogger(LoggerInterface $logger)
231 | {
232 | $this->logger = $logger;
233 |
234 | return $this;
235 | }
236 |
237 | /**
238 | * @return Serializer
239 | */
240 | public function getSerializer()
241 | {
242 | return $this->serializer;
243 | }
244 |
245 | private function send($method, $url, $body = null): string
246 | {
247 | try {
248 | $option = [];
249 | if ($body) {
250 | $option['body'] = $body;
251 | }
252 |
253 | $this->logger && $this->logger->debug(sprintf('%s "%s"', $method, $url));
254 | $response = $this->httpClient->request($method, $url, $option);
255 |
256 | // block until headers arrive
257 | $response->getStatusCode();
258 | $this->logger && $this->logger->debug(sprintf("Request:\n%s", (string) $response->getInfo('debug')));
259 |
260 | return $response->getContent();
261 | } catch (ClientExceptionInterface $e) {
262 | $this->logException($e);
263 |
264 | $this->processClientError($e);
265 | } catch (TransportExceptionInterface $e) {
266 | $this->logException($e);
267 |
268 | throw new ApiServerException('Something went wrong with upstream', 0, $e);
269 | } catch (ServerExceptionInterface $e) {
270 | $this->logException($e);
271 |
272 | throw new ApiServerException('Something went wrong with upstream', 0, $e);
273 | }
274 | }
275 |
276 | private function processClientError(HttpExceptionInterface $e)
277 | {
278 | $statusCode = $e->getResponse()->getStatusCode();
279 | $error = null;
280 | $message = sprintf('Your request in not valid (status code: "%d").', $statusCode);
281 |
282 | if (400 === $statusCode) {
283 | $error = $this->parser->parseError($e->getResponse()->getContent(false));
284 | $message .= 'See $error attached to the exception';
285 | }
286 |
287 | throw new ApiClientException($message, $error, 0, $e);
288 | }
289 |
290 | private function logException(ExceptionInterface $e)
291 | {
292 | $message = sprintf("Exception: Class: \"%s\", Message: \"%s\", Response:\n%s",
293 | \get_class($e),
294 | $e->getMessage(),
295 | $e->getResponse()->getInfo('debug')
296 | );
297 |
298 | $this->logger && $this->logger->error($message, ['exception' => $e]);
299 | }
300 | }
301 |
--------------------------------------------------------------------------------
/Sdk/Exception/ApiClientException.php:
--------------------------------------------------------------------------------
1 |
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 SensioLabs\Insight\Sdk\Exception;
13 |
14 | use SensioLabs\Insight\Sdk\Model\Error;
15 |
16 | class ApiClientException extends \LogicException implements ExceptionInterface
17 | {
18 | private $error;
19 |
20 | public function __construct($message = '', Error $error = null, $code = 0, $e = null)
21 | {
22 | $this->error = $error;
23 |
24 | parent::__construct($message, $code, $e);
25 | }
26 |
27 | public function getError()
28 | {
29 | return $this->error;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Sdk/Exception/ApiParserException.php:
--------------------------------------------------------------------------------
1 |
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 SensioLabs\Insight\Sdk\Exception;
13 |
14 | class ApiParserException extends \RuntimeException implements ExceptionInterface
15 | {
16 | }
17 |
--------------------------------------------------------------------------------
/Sdk/Exception/ApiServerException.php:
--------------------------------------------------------------------------------
1 |
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 SensioLabs\Insight\Sdk\Exception;
13 |
14 | class ApiServerException extends \RuntimeException implements ExceptionInterface
15 | {
16 | }
17 |
--------------------------------------------------------------------------------
/Sdk/Exception/ExceptionInterface.php:
--------------------------------------------------------------------------------
1 |
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 SensioLabs\Insight\Sdk\Exception;
13 |
14 | interface ExceptionInterface
15 | {
16 | }
17 |
--------------------------------------------------------------------------------
/Sdk/Model/Analyses.php:
--------------------------------------------------------------------------------
1 |
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 SensioLabs\Insight\Sdk\Model;
13 |
14 | use JMS\Serializer\Annotation\Type;
15 | use JMS\Serializer\Annotation\XmlList;
16 |
17 | class Analyses
18 | {
19 | /**
20 | * @Type("array")
21 | * @XmlList(inline = true, entry = "link")
22 | */
23 | #[Type("array")]
24 | #[XmlList(inline: true, entry: "link")]
25 | private $links = [];
26 |
27 | /**
28 | * @Type("array")
29 | * @XmlList(inline = true, entry = "analysis")
30 | */
31 | #[Type("array")]
32 | #[XmlList(inline: true, entry: "analysis")]
33 | private $analyses = [];
34 |
35 | /**
36 | * @return Link[]
37 | */
38 | public function getLinks()
39 | {
40 | return $this->links;
41 | }
42 |
43 | /**
44 | * @return Analysis[]
45 | */
46 | public function getAnalyses()
47 | {
48 | return $this->analyses;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Sdk/Model/Analysis.php:
--------------------------------------------------------------------------------
1 |
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 SensioLabs\Insight\Sdk\Model;
13 |
14 | use JMS\Serializer\Annotation\SerializedName;
15 | use JMS\Serializer\Annotation\Type;
16 | use JMS\Serializer\Annotation\XmlList;
17 |
18 | class Analysis
19 | {
20 | const STATUS_ORDERED = 'ordered';
21 | const STATUS_RUNNING = 'running';
22 | const STATUS_MEASURED = 'measured';
23 | const STATUS_ANALYZED = 'analyzed';
24 | const STATUS_FINISHED = 'finished';
25 |
26 | /**
27 | * @Type("array")
28 | * @XmlList(inline = true, entry = "link")
29 | */
30 | #[Type("array")]
31 | #[XmlList(inline: true, entry: "link")]
32 | private $links = [];
33 |
34 | /** @Type("integer") */
35 | #[Type("integer")]
36 | private $number;
37 |
38 | /** @Type("string") */
39 | #[Type("string")]
40 | private $grade;
41 |
42 | /**
43 | * @Type("string")
44 | * @SerializedName("next-grade")
45 | */
46 | #[Type("string")]
47 | #[SerializedName("next-grade")]
48 | private $nextGrade;
49 |
50 | /** @Type("array") */
51 | #[Type("array")]
52 | private $grades = [];
53 |
54 | /**
55 | * @Type("float")
56 | * @SerializedName("remediation-cost")
57 | */
58 | #[Type("float")]
59 | #[SerializedName("remediation-cost")]
60 | private $remediationCost;
61 |
62 | /**
63 | * @Type("float")
64 | * @SerializedName("remediation-cost-for-next-grade")
65 | */
66 | #[Type("float")]
67 | #[SerializedName("remediation-cost-for-next-grade")]
68 | private $remediationCostForNextGrade;
69 |
70 | /**
71 | * @Type("integer")
72 | * @SerializedName("nb-violations")
73 | */
74 | #[Type("integer")]
75 | #[SerializedName("nb-violations")]
76 | private $nbViolations;
77 |
78 | /**
79 | * @Type("DateTime")
80 | * @SerializedName("begin-at")
81 | */
82 | #[Type("DateTime")]
83 | #[SerializedName("begin-at")]
84 | private $beginAt;
85 |
86 | /**
87 | * @Type("DateTime")
88 | * @SerializedName("end-at")
89 | */
90 | #[Type("DateTime")]
91 | #[SerializedName("end-at")]
92 | private $endAt;
93 |
94 | /** @Type("integer") */
95 | #[Type("integer")]
96 | private $duration;
97 |
98 | /**
99 | * @Type("string")
100 | * @SerializedName("failure-message")
101 | */
102 | #[Type("string")]
103 | #[SerializedName("failure-message")]
104 | private $failureMessage;
105 |
106 | /**
107 | * @Type("string")
108 | * @SerializedName("failure-code")
109 | */
110 | #[Type("string")]
111 | #[SerializedName("failure-code")]
112 | private $failureCode;
113 |
114 | /** @Type("boolean") */
115 | #[Type("boolean")]
116 | private $failed;
117 |
118 | /** @Type("string") */
119 | #[Type("string")]
120 | private $status;
121 |
122 | /**
123 | * @Type("string")
124 | * @SerializedName("status-message")
125 | */
126 | #[Type("string")]
127 | #[SerializedName("status-message")]
128 | private $statusMessage;
129 |
130 | /**
131 | * @Type("boolean")
132 | * @SerializedName("altered")
133 | */
134 | #[Type("boolean")]
135 | #[SerializedName("altered")]
136 | private $isAltered;
137 |
138 | /** @Type("SensioLabs\Insight\Sdk\Model\Violations") */
139 | #[Type("SensioLabs\Insight\Sdk\Model\Violations")]
140 | private $violations;
141 |
142 | /** @Type("string") */
143 | #[Type("string")]
144 | private $branch;
145 |
146 | /** @Type("string") */
147 | #[Type("string")]
148 | private $reference;
149 |
150 | /**
151 | * @return Link[]
152 | */
153 | public function getLinks()
154 | {
155 | return $this->links;
156 | }
157 |
158 | /**
159 | * @return int
160 | */
161 | public function getNumber()
162 | {
163 | return $this->number;
164 | }
165 |
166 | /**
167 | * @return string
168 | */
169 | public function getGrade()
170 | {
171 | return $this->grade;
172 | }
173 |
174 | /**
175 | * @return string
176 | */
177 | public function getNextGrade()
178 | {
179 | return $this->nextGrade;
180 | }
181 |
182 | /**
183 | * @return string[]
184 | */
185 | public function getGrades()
186 | {
187 | return $this->grades;
188 | }
189 |
190 | /**
191 | * @return float
192 | */
193 | public function getRemediationCost()
194 | {
195 | return $this->remediationCost;
196 | }
197 |
198 | /**
199 | * @return float
200 | */
201 | public function getRemediationCostForNextGrade()
202 | {
203 | return $this->remediationCostForNextGrade;
204 | }
205 |
206 | /**
207 | * @return int
208 | */
209 | public function getNbViolations()
210 | {
211 | return $this->nbViolations;
212 | }
213 |
214 | /**
215 | * @return \DateTime
216 | */
217 | public function getBeginAt()
218 | {
219 | return $this->beginAt;
220 | }
221 |
222 | /**
223 | * @return \DateTime|null
224 | */
225 | public function getEndAt()
226 | {
227 | return $this->endAt;
228 | }
229 |
230 | /**
231 | * @return \DateInterval
232 | */
233 | public function getDuration()
234 | {
235 | return new \DateInterval('PT'.($this->duration ?: '0').'S');
236 | }
237 |
238 | /**
239 | * @return string
240 | */
241 | public function getFailureMessage()
242 | {
243 | return $this->failureMessage;
244 | }
245 |
246 | /**
247 | * @return string
248 | */
249 | public function getFailureCode()
250 | {
251 | return $this->failureCode;
252 | }
253 |
254 | /**
255 | * @return bool
256 | */
257 | public function isFailed()
258 | {
259 | return $this->failed;
260 | }
261 |
262 | /**
263 | * @return bool
264 | */
265 | public function isFinished()
266 | {
267 | return static::STATUS_FINISHED == $this->status;
268 | }
269 |
270 | /**
271 | * @return string One of the STATUS_* constants
272 | */
273 | public function getStatus()
274 | {
275 | return $this->status;
276 | }
277 |
278 | /**
279 | * @return string
280 | */
281 | public function getStatusMessage()
282 | {
283 | return $this->statusMessage;
284 | }
285 |
286 | /**
287 | * @return bool
288 | */
289 | public function isAltered()
290 | {
291 | return $this->isAltered;
292 | }
293 |
294 | /**
295 | * @return Violations|null
296 | */
297 | public function getViolations()
298 | {
299 | return $this->violations;
300 | }
301 | }
302 |
--------------------------------------------------------------------------------
/Sdk/Model/Error.php:
--------------------------------------------------------------------------------
1 |
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 SensioLabs\Insight\Sdk\Model;
13 |
14 | class Error
15 | {
16 | private $entityBodyParameters = [];
17 |
18 | public function getEntityBodyParameters()
19 | {
20 | return $this->entityBodyParameters;
21 | }
22 |
23 | public function hasEntityBodyParameter($name)
24 | {
25 | return \array_key_exists($name, $this->entityBodyParameters);
26 | }
27 |
28 | public function addEntityBodyParameter($name)
29 | {
30 | if (!$this->hasEntityBodyParameter($name)) {
31 | $this->entityBodyParameters[$name] = [];
32 | }
33 |
34 | return $this;
35 | }
36 |
37 | public function addEntityBodyParameterError($name, $message)
38 | {
39 | $this->entityBodyParameters[$name][] = $message;
40 |
41 | return $this;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Sdk/Model/Link.php:
--------------------------------------------------------------------------------
1 |
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 SensioLabs\Insight\Sdk\Model;
13 |
14 | use JMS\Serializer\Annotation\Type;
15 | use JMS\Serializer\Annotation\XmlAttribute;
16 |
17 | class Link
18 | {
19 | /**
20 | * @XmlAttribute
21 | * @Type("string")
22 | */
23 | #[XmlAttribute]
24 | #[Type("string")]
25 | private $href;
26 |
27 | /**
28 | * @XmlAttribute
29 | * @Type("string")
30 | */
31 | #[XmlAttribute]
32 | #[Type("string")]
33 | private $rel;
34 |
35 | /**
36 | * @XmlAttribute
37 | * @Type("string")
38 | */
39 | #[XmlAttribute]
40 | #[Type("string")]
41 | private $type;
42 |
43 | /**
44 | * @return string
45 | */
46 | public function getHref()
47 | {
48 | return $this->href;
49 | }
50 |
51 | /**
52 | * @return string
53 | */
54 | public function getRel()
55 | {
56 | return $this->rel;
57 | }
58 |
59 | /**
60 | * @return string
61 | */
62 | public function getType()
63 | {
64 | return $this->type;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/Sdk/Model/Project.php:
--------------------------------------------------------------------------------
1 |
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 SensioLabs\Insight\Sdk\Model;
13 |
14 | use JMS\Serializer\Annotation\Exclude;
15 | use JMS\Serializer\Annotation\SerializedName;
16 | use JMS\Serializer\Annotation\Type;
17 | use JMS\Serializer\Annotation\XmlList;
18 |
19 | class Project
20 | {
21 | /**
22 | * @see https://github.com/sensiolabs/connect/blob/master/src/SensioLabs/Connect/Api/Entity/Project.php
23 | */
24 | const TYPE_PHP_WEBSITE = 0;
25 | const TYPE_PHP_LIBRARY = 1;
26 | const TYPE_SYMFONY2_BUNDLE = 2;
27 | const TYPE_SYMFONY1_PLUGIN = 4;
28 | const TYPE_OTHER = 6;
29 | const TYPE_DRUPAL_MODULE = 7;
30 | const TYPE_LARAVAL_WEB_PROJECT = 8;
31 | const TYPE_SILEX_WEB_PROJECT = 9;
32 | const TYPE_SYMFONY2_WEB_PROJECT = 10;
33 | const TYPE_SYMFONY1_WEB_PROJECT = 11;
34 |
35 | /**
36 | * @Exclude()
37 | */
38 | #[Exclude]
39 | public static $types = [
40 | self::TYPE_SYMFONY2_WEB_PROJECT => 'Symfony2 Web Project',
41 | self::TYPE_SYMFONY1_WEB_PROJECT => 'symfony1 Web Project',
42 | self::TYPE_SILEX_WEB_PROJECT => 'Silex Web Project',
43 | self::TYPE_LARAVAL_WEB_PROJECT => 'Laravel Web Project',
44 | self::TYPE_SYMFONY2_BUNDLE => 'Symfony2 Bundle',
45 | self::TYPE_SYMFONY1_PLUGIN => 'symfony1 Plugin',
46 | self::TYPE_DRUPAL_MODULE => 'Drupal Module',
47 | self::TYPE_PHP_WEBSITE => 'PHP Web Project',
48 | self::TYPE_PHP_LIBRARY => 'PHP Library',
49 | self::TYPE_OTHER => 'Other',
50 | ];
51 |
52 | /**
53 | * @Type("array")
54 | * @XmlList(inline = true, entry = "link")
55 | */
56 | #[Type("array")]
57 | #[XmlList(inline: true, entry: "link")]
58 | private $links = [];
59 |
60 | /**
61 | * @Type("string")
62 | * @SerializedName("id")
63 | */
64 | #[Type("string")]
65 | #[SerializedName("id")]
66 | private $uuid;
67 |
68 | /** @Type("string") */
69 | #[Type("string")]
70 | private $name;
71 |
72 | /** @Type("string") */
73 | #[Type("string")]
74 | private $configuration;
75 |
76 | /** @Type("string") */
77 | #[Type("string")]
78 | private $description;
79 |
80 | /** @Type("integer") */
81 | #[Type("integer")]
82 | private $type;
83 |
84 | /**
85 | * @Type("string")
86 | * @SerializedName("repository-url")
87 | */
88 | #[Type("string")]
89 | #[SerializedName("repository-url")]
90 | private $repositoryUrl;
91 |
92 | /** @Type("boolean") */
93 | #[Type("boolean")]
94 | private $private;
95 |
96 | /**
97 | * @Type("boolean")
98 | * @SerializedName("report-available")
99 | */
100 | #[Type("boolean")]
101 | #[SerializedName("report-available")]
102 | private $reportAvailable;
103 |
104 | /**
105 | * @Type("SensioLabs\Insight\Sdk\Model\Analysis")
106 | * @SerializedName("last-analysis")
107 | */
108 | #[Type("SensioLabs\Insight\Sdk\Model\Analysis")]
109 | #[SerializedName("last-analysis")]
110 | private $lastAnalysis;
111 |
112 | public function toArray()
113 | {
114 | return [
115 | 'name' => $this->name,
116 | 'public' => !$this->private,
117 | 'description' => $this->description,
118 | 'repositoryUrl' => $this->repositoryUrl,
119 | 'type' => $this->type,
120 | 'configuration' => $this->configuration,
121 | ];
122 | }
123 |
124 | /**
125 | * @return Link[]
126 | */
127 | public function getLinks()
128 | {
129 | return $this->links;
130 | }
131 |
132 | /**
133 | * @return string
134 | */
135 | public function getUuid()
136 | {
137 | return $this->uuid;
138 | }
139 |
140 | /**
141 | * @return string
142 | */
143 | public function getName()
144 | {
145 | return $this->name;
146 | }
147 |
148 | public function setName($name)
149 | {
150 | $this->name = $name;
151 |
152 | return $this;
153 | }
154 |
155 | /**
156 | * @return string
157 | */
158 | public function getConfiguration()
159 | {
160 | return $this->configuration;
161 | }
162 |
163 | public function setConfiguration($configuration)
164 | {
165 | $this->configuration = $configuration;
166 |
167 | return $this;
168 | }
169 |
170 | /**
171 | * @return string
172 | */
173 | public function getDescription()
174 | {
175 | return $this->description;
176 | }
177 |
178 | public function setDescription($description)
179 | {
180 | $this->description = $description;
181 |
182 | return $this;
183 | }
184 |
185 | /**
186 | * @return int
187 | */
188 | public function getType()
189 | {
190 | return $this->type;
191 | }
192 |
193 | public function setType($type)
194 | {
195 | if (!\array_key_exists($type, static::$types)) {
196 | throw new \InvalidArgumentException(sprintf('"%s" is not a valid type. You must pick one among "%"', $type, implode('", "', array_keys(static::$types))));
197 | }
198 |
199 | $this->type = $type;
200 |
201 | return $this;
202 | }
203 |
204 | /**
205 | * @return string
206 | */
207 | public function getRepositoryUrl()
208 | {
209 | return $this->repositoryUrl;
210 | }
211 |
212 | public function setRepositoryUrl($repositoryUrl)
213 | {
214 | $this->repositoryUrl = $repositoryUrl;
215 |
216 | return $this;
217 | }
218 |
219 | /**
220 | * @return bool
221 | */
222 | public function isPublic()
223 | {
224 | return !$this->private;
225 | }
226 |
227 | public function setPublic($isPublic = false)
228 | {
229 | $this->private = !$isPublic;
230 |
231 | return $this;
232 | }
233 |
234 | /**
235 | * @return bool
236 | */
237 | public function isPrivate()
238 | {
239 | return $this->private;
240 | }
241 |
242 | public function setPrivate($isPrivate = true)
243 | {
244 | $this->private = $isPrivate;
245 |
246 | return $this;
247 | }
248 |
249 | /**
250 | * @return bool
251 | */
252 | public function isReportAvailable()
253 | {
254 | return $this->reportAvailable;
255 | }
256 |
257 | /**
258 | * @return Analysis|null
259 | */
260 | public function getLastAnalysis()
261 | {
262 | return $this->lastAnalysis;
263 | }
264 | }
265 |
--------------------------------------------------------------------------------
/Sdk/Model/Projects.php:
--------------------------------------------------------------------------------
1 |
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 SensioLabs\Insight\Sdk\Model;
13 |
14 | use JMS\Serializer\Annotation\Type;
15 | use JMS\Serializer\Annotation\XmlAttribute;
16 | use JMS\Serializer\Annotation\XmlList;
17 | use JMS\Serializer\Annotation\XmlRoot;
18 |
19 | /**
20 | * @XmlRoot("projects")
21 | */
22 | #[XmlRoot("projects")]
23 | class Projects
24 | {
25 | /**
26 | * @XmlAttribute
27 | * @Type("integer")
28 | */
29 | #[XmlAttribute]
30 | #[Type("integer")]
31 | private $page;
32 |
33 | /**
34 | * @XmlAttribute
35 | * @Type("integer")
36 | */
37 | #[XmlAttribute]
38 | #[Type("integer")]
39 | private $total;
40 |
41 | /**
42 | * @XmlAttribute
43 | * @Type("integer")
44 | */
45 | #[XmlAttribute]
46 | #[Type("integer")]
47 | private $limit;
48 |
49 | /**
50 | * @Type("array")
51 | * @XmlList(inline = true, entry = "link")
52 | */
53 | #[Type("array")]
54 | #[XmlList(inline: true, entry: "link")]
55 | private $links = [];
56 |
57 | /**
58 | * @Type("array")
59 | * @XmlList(inline = true, entry = "project")
60 | */
61 | #[Type("array")]
62 | #[XmlList(inline: true, entry: "project")]
63 | private $projects = [];
64 |
65 | /**
66 | * @return int
67 | */
68 | public function getPage()
69 | {
70 | return $this->page;
71 | }
72 |
73 | /**
74 | * @return int
75 | */
76 | public function getTotal()
77 | {
78 | return $this->total;
79 | }
80 |
81 | /**
82 | * @return int
83 | */
84 | public function getLimit()
85 | {
86 | return $this->limit;
87 | }
88 |
89 | /**
90 | * @return Link[]
91 | */
92 | public function getLinks()
93 | {
94 | return $this->links;
95 | }
96 |
97 | /**
98 | * @return Project[]
99 | */
100 | public function getProjects()
101 | {
102 | return $this->projects;
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/Sdk/Model/Violation.php:
--------------------------------------------------------------------------------
1 |
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 SensioLabs\Insight\Sdk\Model;
13 |
14 | use JMS\Serializer\Annotation\Type;
15 | use JMS\Serializer\Annotation\XmlAttribute;
16 |
17 | class Violation
18 | {
19 | /** @Type("string") */
20 | #[Type("string")]
21 | private $title;
22 |
23 | /** @Type("string") */
24 | #[Type("string")]
25 | private $message;
26 |
27 | /** @Type("string") */
28 | #[Type("string")]
29 | private $resource;
30 |
31 | /** @Type("integer") */
32 | #[Type("integer")]
33 | private $line;
34 |
35 | /**
36 | * @Type("string")
37 | * @XmlAttribute
38 | */
39 | #[Type("string")]
40 | #[XmlAttribute]
41 | private $severity;
42 |
43 | /**
44 | * @Type("string")
45 | * @XmlAttribute
46 | */
47 | #[Type("string")]
48 | #[XmlAttribute]
49 | private $category;
50 |
51 | /**
52 | * @Type("boolean")
53 | * @XmlAttribute
54 | */
55 | #[Type("boolean")]
56 | #[XmlAttribute]
57 | private $ignored;
58 |
59 | /**
60 | * @return string
61 | */
62 | public function getTitle()
63 | {
64 | return $this->title;
65 | }
66 |
67 | /**
68 | * @return string
69 | */
70 | public function getMessage()
71 | {
72 | return $this->message;
73 | }
74 |
75 | /**
76 | * @return string
77 | */
78 | public function getResource()
79 | {
80 | return $this->resource;
81 | }
82 |
83 | /**
84 | * @return int
85 | */
86 | public function getLine()
87 | {
88 | return $this->line;
89 | }
90 |
91 | /**
92 | * @return string
93 | */
94 | public function getSeverity()
95 | {
96 | return $this->severity;
97 | }
98 |
99 | /**
100 | * @return string
101 | */
102 | public function getCategory()
103 | {
104 | return $this->category;
105 | }
106 |
107 | /**
108 | * @return bool
109 | */
110 | public function isIgnored()
111 | {
112 | return $this->ignored;
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/Sdk/Model/Violations.php:
--------------------------------------------------------------------------------
1 |
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 SensioLabs\Insight\Sdk\Model;
13 |
14 | use JMS\Serializer\Annotation\Type;
15 | use JMS\Serializer\Annotation\XmlList;
16 |
17 | class Violations implements \Countable, \IteratorAggregate
18 | {
19 | /**
20 | * @Type("array")
21 | * @XmlList(inline = true, entry = "violation")
22 | */
23 | #[Type("array")]
24 | #[XmlList(inline: true, entry: "violation")]
25 | private $violations = [];
26 |
27 | public function count(): int
28 | {
29 | return \count($this->violations);
30 | }
31 |
32 | public function getIterator(): \Traversable
33 | {
34 | return new \ArrayIterator($this->violations);
35 | }
36 |
37 | /**
38 | * @return Violation[]
39 | */
40 | public function getViolations()
41 | {
42 | return $this->violations;
43 | }
44 |
45 | /**
46 | * @param callable $callback
47 | */
48 | public function filter($callback)
49 | {
50 | if (!\is_callable($callback)) {
51 | throw new \InvalidArgumentException('The callback is not callable.');
52 | }
53 |
54 | $this->violations = array_filter($this->violations, $callback);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Sdk/Parser.php:
--------------------------------------------------------------------------------
1 |
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 SensioLabs\Insight\Sdk;
13 |
14 | use SensioLabs\Insight\Sdk\Exception\ApiParserException;
15 | use SensioLabs\Insight\Sdk\Model\Error;
16 |
17 | class Parser
18 | {
19 | public function parseError($content)
20 | {
21 | if (!$content) {
22 | throw new ApiParserException('Could not transform this xml to a \DOMDocument instance.');
23 | }
24 |
25 | $internalErrors = libxml_use_internal_errors(true);
26 | $disableEntities = libxml_disable_entity_loader(true);
27 | libxml_clear_errors();
28 |
29 | $document = new \DOMDocument();
30 | $document->validateOnParse = true;
31 | if (!$document->loadXML($content, \LIBXML_NONET | (\defined('LIBXML_COMPACT') ? \LIBXML_COMPACT : 0))) {
32 | libxml_disable_entity_loader($disableEntities);
33 |
34 | libxml_clear_errors();
35 | libxml_use_internal_errors($internalErrors);
36 |
37 | throw new ApiParserException('Could not transform this xml to a \DOMDocument instance.');
38 | }
39 |
40 | $document->normalizeDocument();
41 |
42 | libxml_use_internal_errors($internalErrors);
43 | libxml_disable_entity_loader($disableEntities);
44 |
45 | $xpath = new \DOMXpath($document);
46 |
47 | $nodes = $xpath->evaluate('./error');
48 | if (1 === $nodes->length) {
49 | throw new ApiParserException('The dom contains more than one error node.');
50 | }
51 |
52 | $error = new Error();
53 |
54 | $parameters = $xpath->query('./entity/body/parameter', $nodes->item(0));
55 | foreach ($parameters as $parameter) {
56 | $name = $parameter->getAttribute('name');
57 | $error->addEntityBodyParameter($name);
58 |
59 | $messages = $xpath->query('./message', $parameter);
60 | foreach ($messages as $message) {
61 | $error->addEntityBodyParameterError($name, $this->sanitizeValue($message->nodeValue));
62 | }
63 | }
64 |
65 | return $error;
66 | }
67 |
68 | protected function sanitizeValue($value)
69 | {
70 | if ('true' === $value) {
71 | $value = true;
72 | } elseif ('false' === $value) {
73 | $value = false;
74 | } elseif (empty($value)) {
75 | $value = null;
76 | }
77 |
78 | return $value;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/Sdk/Tests/ApiTest.php:
--------------------------------------------------------------------------------
1 |
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 SensioLabs\Insight\Sdk\Tests;
13 |
14 | use PHPUnit\Framework\TestCase;
15 | use SensioLabs\Insight\Sdk\Api;
16 | use SensioLabs\Insight\Sdk\Model\Project;
17 | use Symfony\Component\HttpClient\MockHttpClient;
18 | use Symfony\Component\HttpClient\Response\MockResponse;
19 |
20 | class ApiTest extends TestCase
21 | {
22 | /**
23 | * @var Api
24 | */
25 | private $api;
26 | private $logger;
27 |
28 | protected function setUp(): void
29 | {
30 | $this->logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
31 | }
32 |
33 | public function testConstructorWithoutOption()
34 | {
35 | $this->expectException(\Exception::class);
36 | $this->expectExceptionMessage('Config is missing the following keys: api_token, user_uuid');
37 | new Api();
38 | }
39 |
40 | public function testGetProjects()
41 | {
42 | $api = $this->createApi('projects');
43 |
44 | $projects = $api->getProjects();
45 |
46 | $this->assertInstanceOf('SensioLabs\Insight\Sdk\Model\Projects', $projects);
47 | $this->assertCount(10, $projects->getProjects());
48 | $this->assertSame(1, $projects->getPage());
49 | $this->assertSame(12, $projects->getTotal());
50 | $this->assertSame(10, $projects->getLimit());
51 |
52 | $projects = $projects->getProjects();
53 | $this->assertInstanceOf('SensioLabs\Insight\Sdk\Model\Project', reset($projects));
54 | }
55 |
56 | public function testGetProjectsWithPage()
57 | {
58 | $this->logger
59 | ->expects($this->exactly(2))
60 | ->method('debug')
61 | ;
62 | $this->logger
63 | ->expects($this->at(1))
64 | ->method('debug')
65 | ->with($this->stringContains('/api/projects?page=2'))
66 | ;
67 | $api = $this->createApi('projects2', ['debug' => '/api/projects?page=2']);
68 |
69 | $projects = $api->getProjects(2);
70 |
71 | $this->assertInstanceOf('SensioLabs\Insight\Sdk\Model\Projects', $projects);
72 | $this->assertCount(2, $projects->getProjects());
73 | $this->assertSame(2, $projects->getPage());
74 | $this->assertSame(12, $projects->getTotal());
75 | $this->assertSame(10, $projects->getLimit());
76 |
77 | $projects = $projects->getProjects();
78 | $this->assertInstanceOf('SensioLabs\Insight\Sdk\Model\Project', reset($projects));
79 | }
80 |
81 | public function testGetProject()
82 | {
83 | $api = $this->createApi('project');
84 |
85 | $project = $api->getProject('6718526f-ecdf-497d-bffb-8512f0b402ea');
86 |
87 | $this->assertInstanceOf('SensioLabs\Insight\Sdk\Model\Project', $project);
88 | $this->assertSame('demo', $project->getName());
89 | $this->assertNotnull($project->getConfiguration());
90 | $this->assertSame('git@github.com:lyrixx/demoer.git', $project->getRepositoryUrl());
91 | $this->assertTrue($project->isPublic());
92 | $this->assertTrue($project->isReportAvailable());
93 | $this->assertSame(1, $project->getType());
94 |
95 | $this->assertInstanceOf('SensioLabs\Insight\Sdk\Model\Analysis', $project->getLastAnalysis());
96 | }
97 |
98 | public function testCreateProjectOk()
99 | {
100 | $project = new Project();
101 |
102 | $api = $this->createApi('project');
103 |
104 | $project = $api->createProject($project);
105 |
106 | $this->assertInstanceOf('SensioLabs\Insight\Sdk\Model\Project', $project);
107 | }
108 |
109 | public function testCreateProjectNOk()
110 | {
111 | $project = new Project();
112 |
113 | $api = $this->createApi('errors', ['http_code' => 400]);
114 |
115 | try {
116 | $project = $api->createProject($project);
117 | $this->fail('Something should go wrong');
118 | } catch (\Exception $e) {
119 | $this->assertInstanceOf('SensioLabs\Insight\Sdk\Exception\ApiClientException', $e);
120 | $this->assertSame('Your request in not valid (status code: "400").See $error attached to the exception', $e->getMessage());
121 | $this->assertInstanceOf('SensioLabs\Insight\Sdk\Model\Error', $e->getError());
122 | }
123 | }
124 |
125 | public function testupdateProjectOk()
126 | {
127 | $project = new Project();
128 |
129 | $api = $this->createApi('project');
130 |
131 | $project = $api->updateProject($project);
132 |
133 | $this->assertInstanceOf('SensioLabs\Insight\Sdk\Model\Project', $project);
134 | }
135 |
136 | public function testupdateProjectNOk()
137 | {
138 | $project = new Project();
139 | $api = $this->createApi('errors', ['http_code' => 400]);
140 |
141 | try {
142 | $project = $api->updateProject($project);
143 | $this->fail('Something should go wrong');
144 | } catch (\Exception $e) {
145 | $this->assertInstanceOf('SensioLabs\Insight\Sdk\Exception\ApiClientException', $e);
146 | $this->assertSame('Your request in not valid (status code: "400").See $error attached to the exception', $e->getMessage());
147 | $this->assertInstanceOf('SensioLabs\Insight\Sdk\Model\Error', $e->getError());
148 | }
149 | }
150 |
151 | public function testGetAnalyses()
152 | {
153 | $api = $this->createApi('analyses');
154 |
155 | $analyses = $api->getAnalyses('6718526f-ecdf-497d-bffb-8512f0b402ea');
156 |
157 | $this->assertInstanceOf('SensioLabs\Insight\Sdk\Model\Analyses', $analyses);
158 | $this->assertCount(2, $analyses->getAnalyses());
159 |
160 | $analyses = $analyses->getAnalyses();
161 | $this->assertInstanceOf('SensioLabs\Insight\Sdk\Model\Analysis', reset($analyses));
162 | }
163 |
164 | public function testGetAnalysis()
165 | {
166 | $api = $this->createApi('analysis');
167 |
168 | $analysis = $api->getAnalysis('6718526f-ecdf-497d-bffb-8512f0b402ea', 1);
169 |
170 | $this->assertInstanceOf('SensioLabs\Insight\Sdk\Model\Analysis', $analysis);
171 | $this->assertSame(49, $analysis->getNumber());
172 | $this->assertSame('error', $analysis->getGrade());
173 | $this->assertSame('bronze', $analysis->getNextGrade());
174 | $this->assertSame(['error', 'bronze', 'silver', 'gold', 'platinum'], $analysis->getGrades());
175 | $this->assertSame(181.75, $analysis->getRemediationCost());
176 | $this->assertSame(55.5, $analysis->getRemediationCostForNextGrade());
177 | $this->assertSame('2013-06-25T19:37:20+02:00', $analysis->getBeginAt()->format('c'));
178 | $this->assertSame('2013-06-25T19:37:53+02:00', $analysis->getEndAt()->format('c'));
179 | $this->assertSame('0', $analysis->getDuration()->format('%s'));
180 | $this->assertSame(250, $analysis->getNbViolations());
181 | $this->assertNull($analysis->getFailureMessage());
182 | $this->assertNull($analysis->getFailureCode());
183 | $this->assertFalse($analysis->isAltered());
184 | $this->assertInstanceOf('SensioLabs\Insight\Sdk\Model\Violations', $analysis->getViolations());
185 | $this->assertCount(250, $analysis->getViolations()->getViolations());
186 |
187 | $violations = $analysis->getViolations()->getViolations();
188 | $firstViolation = reset($violations);
189 | $this->assertInstanceOf('SensioLabs\Insight\Sdk\Model\Violation', $firstViolation);
190 |
191 | $this->assertSame(7, $firstViolation->getLine());
192 | $this->assertSame('critical', $firstViolation->getSeverity());
193 | $this->assertSame('security', $firstViolation->getCategory());
194 | $this->assertSame('snippets/001-HelloWorld.php', $firstViolation->getResource());
195 | }
196 |
197 | public function testGetAnalysisStatus()
198 | {
199 | $api = $this->createApi('status');
200 |
201 | $analysis = $api->getAnalysisStatus('6718526f-ecdf-497d-bffb-8512f0b402ea', 1);
202 |
203 | $this->assertInstanceOf('SensioLabs\Insight\Sdk\Model\Analysis', $analysis);
204 | $this->assertSame(49, $analysis->getNumber());
205 | $this->assertSame('2013-06-25T19:37:20+02:00', $analysis->getBeginAt()->format('c'));
206 | $this->assertSame('2013-06-25T19:37:53+02:00', $analysis->getEndAt()->format('c'));
207 | $this->assertSame('finished', $analysis->getStatus());
208 | }
209 |
210 | public function testAnalyze()
211 | {
212 | $api = $this->createApi('analysis');
213 |
214 | $analysis = $api->analyze('6718526f-ecdf-497d-bffb-8512f0b402ea', 'SHA');
215 |
216 | $this->assertInstanceOf('SensioLabs\Insight\Sdk\Model\Analysis', $analysis);
217 | }
218 |
219 | protected function tearDown(): void
220 | {
221 | $this->logger = null;
222 | $this->api = null;
223 | $this->pluginMockResponse = null;
224 | }
225 |
226 | private function createResponse($fixture, $statusCode = 200)
227 | {
228 | return file_get_contents(sprintf('%s/fixtures/%s.xml', __DIR__, $fixture));
229 | }
230 |
231 | private function createApi($fixture, $option = [])
232 | {
233 | $client = new MockHttpClient([new MockResponse($this->createResponse($fixture), $option)]);
234 |
235 | return new Api(['api_token' => 'my-token', 'user_uuid' => 'my-user-uuid'], $client, null, $this->logger);
236 | }
237 | }
238 |
--------------------------------------------------------------------------------
/Sdk/Tests/Model/ViolationsTest.php:
--------------------------------------------------------------------------------
1 |
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 SensioLabs\Insight\Tests\Sdk\Model;
13 |
14 | use PHPUnit\Framework\TestCase;
15 | use SensioLabs\Insight\Sdk\Model\Violations;
16 |
17 | class ViolationsTest extends TestCase
18 | {
19 | public function testCount()
20 | {
21 | $violations = new Violations();
22 |
23 | $reflector = new \ReflectionObject($violations);
24 | $violationsAttr = $reflector->getProperty('violations');
25 | $violationsAttr->setAccessible(true);
26 | $violationsAttr->setValue($violations, range(1, 10));
27 | $violationsAttr->setAccessible(false);
28 |
29 | $this->assertSame(10, \count($violations));
30 | }
31 |
32 | public function testIterable()
33 | {
34 | $violations = new Violations();
35 |
36 | $reflector = new \ReflectionObject($violations);
37 | $violationsAttr = $reflector->getProperty('violations');
38 | $violationsAttr->setAccessible(true);
39 | $violationsAttr->setValue($violations, range(0, 10));
40 | $violationsAttr->setAccessible(false);
41 |
42 | foreach ($violations as $k => $violation) {
43 | $this->assertSame($k, $violation);
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Sdk/Tests/ParserTest.php:
--------------------------------------------------------------------------------
1 |
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 SensioLabs\Insight\Sdk\Tests;
13 |
14 | use PHPUnit\Framework\TestCase;
15 | use SensioLabs\Insight\Sdk\Exception\ApiParserException;
16 | use SensioLabs\Insight\Sdk\Parser;
17 |
18 | class ParserTest extends TestCase
19 | {
20 | /**
21 | * @var Parser
22 | */
23 | private $parser;
24 |
25 | protected function setUp(): void
26 | {
27 | $this->parser = new Parser();
28 | }
29 |
30 | public function getParseErrorsFailedIfDocumentIfInvalidTests()
31 | {
32 | return [
33 | [null],
34 | [''],
35 | ['403'],
36 | ];
37 | }
38 |
39 | /**
40 | * @dataProvider getParseErrorsFailedIfDocumentIfInvalidTests
41 | */
42 | public function testParseErrorsFailedIfDocumentIfInvalid($xml)
43 | {
44 | $this->expectException(ApiParserException::class);
45 | $this->expectExceptionMessage('Could not transform this xml to a \DOMDocument instance.');
46 | $this->parser->parseError($xml);
47 | }
48 |
49 | public function testParseErrors()
50 | {
51 | $xml = file_get_contents(__DIR__.'/fixtures/errors.xml');
52 |
53 | $error = $this->parser->parseError($xml);
54 |
55 | $expectedFields = [
56 | 'foo' => [
57 | 0 => 'This value should not be null.',
58 | 1 => 'This value should not be blank.',
59 | ],
60 | 'bar' => [
61 | 0 => 'This value should be equals to 6.',
62 | ],
63 | ];
64 |
65 | $this->assertInstanceOf('SensioLabs\Insight\Sdk\Model\Error', $error);
66 | $this->assertSame($expectedFields, $error->getEntityBodyParameters());
67 | }
68 |
69 | protected function tearDown(): void
70 | {
71 | $this->parser = null;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/Sdk/Tests/fixtures/analyses.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | 49
18 | false
19 |
20 |
21 |
22 |
23 | 0
24 | false
25 |
26 | 181.75
27 | 55.5
28 | 250
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | 48
45 | true
46 |
58 |
59 |
60 |
61 | 0
62 | false
63 |
64 | 0
65 | 0
66 | 0
67 |
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/Sdk/Tests/fixtures/errors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | This value should not be null.
7 | This value should not be blank.
8 |
9 |
10 | This value should be equals to 6.
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Sdk/Tests/fixtures/projects.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | false
15 | true
16 | 11
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | false
25 | false
26 | 1
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | 47
42 | true
43 |
44 |
45 | false
46 |
47 | 0
48 | 0
49 | 0
50 |
51 |
52 |
53 | false
54 | false
55 | 6
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | false
65 | false
66 | 4
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | false
75 | false
76 | 10
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 | false
85 | false
86 | 10
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 | false
95 | false
96 | 7
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 | false
105 | false
106 | 9
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 | false
115 | false
116 | 11
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 | 49
132 | false
133 |
134 |
135 |
136 |
137 | 0
138 | false
139 |
140 | 181.75
141 | 55.5
142 | 250
143 |
144 |
145 |
146 | true
147 | true
148 | 1
149 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
177 |
178 |
179 |
180 |
181 |
--------------------------------------------------------------------------------
/Sdk/Tests/fixtures/projects2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | false
15 | false
16 | 7
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | false
25 | false
26 | 4
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/Sdk/Tests/fixtures/status.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | 49
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/bin/insight:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 |
8 | *
9 | * For the full copyright and license information, please view the LICENSE
10 | * file that was distributed with this source code.
11 | */
12 |
13 | // installed via composer?
14 | if (file_exists($a = __DIR__.'/../../../autoload.php')) {
15 | require_once $a;
16 | } else {
17 | require_once __DIR__.'/../vendor/autoload.php';
18 | }
19 |
20 | use SensioLabs\Insight\Cli\Application;
21 |
22 | $application = new Application();
23 |
24 | $application->run();
25 |
--------------------------------------------------------------------------------
/box.json:
--------------------------------------------------------------------------------
1 | {
2 | "check-requirements": false,
3 | "output": "build/insight.phar",
4 | "git-commit": "git-commit",
5 | "finder": [
6 | {"in": "bin"},
7 | {"in": "Cli"},
8 | {"in": "Sdk", "exclude": ["Tests"]},
9 | {"in": "vendor", "notName": "/LICENSE|.*\\.md|.*\\.dist|Makefile|composer\\.json|composer\\.lock/"}
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sensiolabs/insight",
3 | "description": "SymfonyInsight SDK",
4 | "license": "MIT",
5 | "require": {
6 | "php": ">=7.2",
7 | "ext-json": "*",
8 | "doctrine/annotations": "^1.14|^2.0",
9 | "jms/serializer": "^3.29",
10 | "psr/log": "^1.0",
11 | "symfony/http-client": "^5.4|^6.4|^7.0",
12 | "symfony/console": "^5.4|^6.4|^7.0",
13 | "symfony/expression-language": "^5.4|^6.4|^7.0"
14 | },
15 | "require-dev": {
16 | "monolog/monolog": "^1.4",
17 | "symfony/phpunit-bridge": "^5.4|^6.4|^7.0",
18 | "symfony/var-dumper": "^5.4|^6.4|^7.0"
19 | },
20 | "suggest": {
21 | "monolog/monolog": "Will add some log capability to this library"
22 | },
23 | "autoload": {
24 | "psr-4": {
25 | "SensioLabs\\Insight\\": ""
26 | }
27 | },
28 | "bin": ["bin/insight"],
29 | "extra": {
30 | "branch-alias": {
31 | "dev-main": "1.x-dev"
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Sdk/Tests
23 |
24 |
25 |
26 |
27 |
28 | Sdk
29 |
30 | Sdk/Tests
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------