├── tests
├── _output
│ └── .gitkeep
├── _bootstrap.php
├── unit
│ ├── _bootstrap.php
│ ├── IO
│ │ ├── NativeTest.php
│ │ ├── FileTest.php
│ │ ├── GitHubReleasesTest.php
│ │ ├── FlysystemTest.php
│ │ └── GitHubTest.php
│ ├── Console
│ │ ├── ConvertTest.php
│ │ ├── AbstractCommandTest.php
│ │ ├── MergeTest.php
│ │ ├── AddTest.php
│ │ └── ReleaseTest.php
│ ├── AbstractIOTest.php
│ ├── Renderer
│ │ ├── XmlTest.php
│ │ ├── JsonTest.php
│ │ └── KeepAChangeLogTest.php
│ ├── GenericFactoryTest.php
│ ├── ChangeLogTest.php
│ ├── ReleaseTest.php
│ ├── Parser
│ │ └── KeepAChangeLogTest.php
│ ├── LogTest.php
│ └── UnitTester.php
├── resources
│ ├── partial-changelog-1.md
│ ├── partial-changelog-2.md
│ ├── changelog.no_unreleased.md
│ ├── Parser-Json-testRender.json
│ ├── changelog.md
│ ├── changelog.config.merge.php
│ ├── changelog.config.php
│ ├── Parser-Xml-testRender.xml
│ └── changelog.config_missing_unlreleased.php
├── unit.suite.yml
├── _support
│ ├── UnitHelper.php
│ ├── UnitTester.php
│ └── _generated
│ │ └── UnitTesterActions.php
└── stubs
│ ├── AbstractCommandStub.php
│ ├── GetableConstructorStub.php
│ ├── GitHubStub.php
│ ├── GitHubReleasesStub.php
│ └── AbstractIOStub.php
├── compose.yaml
├── .gitignore
├── Dockerfile
├── package
└── stub.php
├── .scrutinizer.yml
├── src
├── Version.php
├── Console
│ ├── ConfigNotFoundException.php
│ ├── ReleaseExistsException.php
│ ├── ReleaseNotFoundException.php
│ ├── InvalidArgumentException.php
│ ├── Convert.php
│ ├── Merge.php
│ ├── Add.php
│ ├── Release.php
│ └── AbstractCommand.php
├── RenderInterface.php
├── ParserInterface.php
├── IOInterface.php
├── IO
│ ├── Native.php
│ ├── AbstractGitHubIO.php
│ ├── File.php
│ ├── Flysystem.php
│ ├── GitHubReleases.php
│ └── GitHub.php
├── Renderer
│ ├── Json.php
│ ├── Xml.php
│ └── KeepAChangeLog.php
├── AbstractIO.php
├── GenericFactory.php
├── ChangeLog.php
├── Release.php
├── Parser
│ └── KeepAChangeLog.php
└── Log.php
├── .editorconfig
├── codeception.dist.yml
├── changelog
├── changelog.config.example.php
├── .github
└── workflows
│ └── main.yml
├── LICENSE
├── RoboFile.php
├── composer.json
├── CONTRIBUTING.md
├── CHANGELOG.md
└── README.md
/tests/_output/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/_bootstrap.php:
--------------------------------------------------------------------------------
1 | one = $config[0];
20 | $this->two = $config[1];
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/tests/stubs/GitHubStub.php:
--------------------------------------------------------------------------------
1 | api = $api;
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/tests/stubs/GitHubReleasesStub.php:
--------------------------------------------------------------------------------
1 | api = $api;
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/RenderInterface.php:
--------------------------------------------------------------------------------
1 | 'value',
20 | ];
21 |
22 | /**
23 | * {@inheritdoc}
24 | */
25 | public function getContent()
26 | {
27 | return null;
28 | }
29 |
30 | /**
31 | *{@inheritdoc}
32 | */
33 | public function setContent($content)
34 | {
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/tests/_support/UnitTester.php:
--------------------------------------------------------------------------------
1 | assertEquals(
24 | $content,
25 | $string->getContent()
26 | );
27 |
28 | $string = new Native;
29 | $string->setContent("baz\nbat");
30 | $this->assertEquals(
31 | ['baz', 'bat'],
32 | $string->getContent()
33 | );
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/tests/resources/changelog.config.merge.php:
--------------------------------------------------------------------------------
1 | [
12 | 'default' => [
13 | 'strategy' => 'File',
14 | 'config' => [
15 | 'file' => __DIR__.'/changelog.no_unreleased.md',
16 | ],
17 | ],
18 | ],
19 | 'parser' => [
20 | 'default' => [
21 | 'strategy' => 'KeepAChangeLog',
22 | ],
23 | ],
24 | 'renderer' => [
25 | 'default' => [
26 | 'strategy' => 'json',
27 | ],
28 | ],
29 | 'output' => [
30 | 'default' => [
31 | 'strategy' => 'File',
32 | 'config' => [
33 | 'file' => __DIR__.'/../_output/changelog.json',
34 | ],
35 | ],
36 | ],
37 | ];
38 |
--------------------------------------------------------------------------------
/tests/resources/changelog.config.php:
--------------------------------------------------------------------------------
1 | [
13 | 'default' => [
14 | 'strategy' => 'File',
15 | 'config' => [
16 | 'file' => __DIR__.'/changelog.md',
17 | ],
18 | ],
19 | ],
20 | 'parser' => [
21 | 'default' => [
22 | 'strategy' => 'KeepAChangeLog',
23 | ],
24 | ],
25 | 'renderer' => [
26 | 'default' => [
27 | 'strategy' => 'Json',
28 | ],
29 | ],
30 | 'output' => [
31 | 'default' => [
32 | 'strategy' => 'File',
33 | 'config' => [
34 | 'file' => __DIR__.'/../_output/changelog.json',
35 | ],
36 | ],
37 | ],
38 | ];
39 |
--------------------------------------------------------------------------------
/tests/resources/Parser-Xml-testRender.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Change Log
4 | A log for changes!
5 |
6 |
7 | 1.0.0
8 | http://fuelphp.com
9 | 2015-01-29
10 |
11 |
12 | fixed 1
13 | fixed 2
14 |
15 |
16 | changed 1
17 |
18 |
19 |
20 |
21 | 0.1.0
22 | http://google.com
23 | foobar
24 | 2015-01-20
25 |
26 |
27 | changed 2
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/tests/resources/changelog.config_missing_unlreleased.php:
--------------------------------------------------------------------------------
1 | [
13 | 'default' => [
14 | 'strategy' => 'File',
15 | 'config' => [
16 | 'file' => __DIR__.'/changelog.no_unreleased.md',
17 | ],
18 | ],
19 | ],
20 | 'parser' => [
21 | 'default' => [
22 | 'strategy' => 'KeepAChangeLog',
23 | ],
24 | ],
25 | 'renderer' => [
26 | 'default' => [
27 | 'strategy' => 'Json',
28 | ],
29 | ],
30 | 'output' => [
31 | 'default' => [
32 | 'strategy' => 'File',
33 | 'config' => [
34 | 'file' => __DIR__.'/../_output/changelog.json',
35 | ],
36 | ],
37 | ],
38 | ];
39 |
--------------------------------------------------------------------------------
/tests/unit/Console/ConvertTest.php:
--------------------------------------------------------------------------------
1 | add(new Convert('convert'));
23 |
24 | $command = $application->find('convert');
25 | $commandTester = new CommandTester($command);
26 | $commandTester->execute(['--config' => __DIR__.'/../../resources/changelog.config.php']);
27 |
28 | $this->assertFileExists($outputPath);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/changelog:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | add(new Release('release'));
29 | $app->add(new Convert('convert'));
30 | $app->add(new Add('add'));
31 | $app->add(new Merge('merge'));
32 |
33 | $app->run();
34 |
--------------------------------------------------------------------------------
/src/IOInterface.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT http://opensource.org/licenses/MIT
8 | * @link https://github.com/emlynwest/changelog
9 | *
10 | * Sample config.
11 | */
12 |
13 | /**
14 | * Sample config for the command line utility
15 | * TODO: expand this out to cover all the various IO, parser and renderer options
16 | */
17 |
18 | return [
19 | 'input' => [
20 | 'default' => [
21 | 'strategy' => 'File',
22 | 'config' => [
23 | 'file' => 'CHANGELOG.md',
24 | ],
25 | ],
26 | ],
27 | 'parser' => [
28 | 'default' => [
29 | 'strategy' => 'KeepAChangeLog',
30 | ],
31 | ],
32 | 'renderer' => [
33 | 'default' => [
34 | 'strategy' => 'KeepAChangeLog',
35 | ],
36 | 'json' => [
37 | 'strategy' => 'Json',
38 | ],
39 | ],
40 | 'output' => [
41 | 'default' => [
42 | 'strategy' => 'File',
43 | 'config' => [
44 | 'file' => 'CHANGELOG.updated.md',
45 | ],
46 | ],
47 | ],
48 | ];
49 |
--------------------------------------------------------------------------------
/tests/unit/Console/AbstractCommandTest.php:
--------------------------------------------------------------------------------
1 | add(new AbstractCommandStub('abstract_command'));
28 |
29 | $command = $application->find('abstract_command');
30 | $this->commandTester = new CommandTester($command);
31 | }
32 |
33 | public function testExecuteWithNoConfig()
34 | {
35 | $this->expectException(ConfigNotFoundException::class);
36 |
37 | $this->commandTester->execute([
38 | '--config' => 'this should not exist',
39 | ]);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: PHP Composer
2 |
3 | on:
4 | - push
5 | - pull_request
6 |
7 | permissions:
8 | contents: read
9 |
10 | jobs:
11 | run:
12 | runs-on: ${{ matrix.operating-system }}
13 | strategy:
14 | matrix:
15 | operating-system: ['ubuntu-latest']
16 | php-versions: ['8.2', '8.3']
17 | steps:
18 | - uses: actions/checkout@v4
19 | with:
20 | fetch-depth: 10
21 |
22 | - name: Setup PHP
23 | uses: shivammathur/setup-php@v2
24 | with:
25 | php-version: ${{ matrix.php-versions }}
26 | extensions: fileinfo
27 | tools: composer
28 | coverage: xdebug
29 |
30 | - name: Validate composer
31 | run: composer validate --strict
32 |
33 | - name: Install
34 | run: composer install --prefer-dist --no-progress
35 |
36 | - name: Unit Test
37 | run: vendor/bin/codecept run unit --coverage-xml
38 |
39 | - name: Upload Scrutinizer coverage
40 | uses: sudo-bot/action-scrutinizer@latest
41 | with:
42 | cli-args: "--format=php-clover tests/_output/coverage.xml"
43 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Emlyn West
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/src/IO/Native.php:
--------------------------------------------------------------------------------
1 | "\n",
25 | ];
26 |
27 | /**
28 | * @param string $content
29 | */
30 | public function __construct($content = '')
31 | {
32 | $this->setContent($content);
33 | }
34 |
35 | /**
36 | * {@inheritdoc}
37 | */
38 | public function setContent($content)
39 | {
40 | $this->content = $content;
41 | }
42 |
43 | /**
44 | * {@inheritdoc}
45 | */
46 | public function getContent()
47 | {
48 | if (is_string($this->content))
49 | {
50 | return explode(
51 | $this->getConfig('line_separator'),
52 | $this->content
53 | );
54 | }
55 |
56 | return $this->content;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/Console/Convert.php:
--------------------------------------------------------------------------------
1 | changeLog->parse();
40 | $this->changeLog->write($log);
41 |
42 | return Command::SUCCESS;
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/IO/AbstractGitHubIO.php:
--------------------------------------------------------------------------------
1 | api === null)
31 | {
32 | $this->createApiInstance();
33 | }
34 |
35 | return $this->api;
36 | }
37 |
38 | /**
39 | * Creates a new instance of the API library to use later.
40 | *
41 | * @throws InvalidArgumentException
42 | */
43 | protected function createApiInstance()
44 | {
45 | $configToken = $this->getConfig('token');
46 |
47 | if ($configToken === null)
48 | {
49 | throw new InvalidArgumentException('API token has not been set in the config.');
50 | }
51 |
52 | $token = new Token($configToken);
53 | $this->api = new Api();
54 | $this->api->setToken($token);
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/RoboFile.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT http://opensource.org/licenses/MIT
8 | * @link https://github.com/emlynwest/changelog
9 | */
10 |
11 | use Robo\Tasks;
12 | use Symfony\Component\Finder\Finder;
13 |
14 | class RoboFile extends Tasks
15 | {
16 | public function createPhar()
17 | {
18 | $collection = $this->collection();
19 |
20 | $this->taskComposerInstall()
21 | ->noDev()
22 | ->optimizeAutoloader()
23 | ->printed(false)
24 | ->addToCollection($collection);
25 |
26 | $packer = $this->taskPackPhar('package/changelog.phar')
27 | ->compress(true)
28 | ->stub('package/stub.php');
29 |
30 | $files = Finder::create()
31 | ->ignoreVCS(true)
32 | ->files()
33 | ->name('*.php')
34 | ->path('src')
35 | ->path('vendor')
36 | ->in(__DIR__);
37 |
38 | foreach ($files as $file) {
39 | $packer->addFile($file->getRelativePathname(), $file->getRealPath());
40 | }
41 |
42 | @unlink('package/bin');
43 | @unlink('package/changelog.phar');
44 | copy('changelog', 'package/bin');
45 |
46 | $packer->addFile('changelog', 'package/bin')
47 | ->addToCollection($collection);
48 |
49 | $this->taskComposerInstall()
50 | ->printed(false)
51 | ->addToCollection($collection);
52 |
53 | $collection->run();
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/tests/unit/AbstractIOTest.php:
--------------------------------------------------------------------------------
1 | provider = new AbstractIOStub;
27 | }
28 |
29 | public function testGetConfig()
30 | {
31 | $config = ['foo' => 'bar'];
32 |
33 | $this->provider->setConfig($config);
34 |
35 | $this->assertEquals(
36 | ['foo' => 'bar', 'default' => 'value'],
37 | $this->provider->getConfig()
38 | );
39 |
40 | $this->assertEquals(
41 | 'bar',
42 | $this->provider->getConfig('foo')
43 | );
44 |
45 | $this->assertEquals(
46 | 'value',
47 | $this->provider->getConfig('default')
48 | );
49 |
50 | $this->assertNull(
51 | $this->provider->getConfig('not here')
52 | );
53 | }
54 |
55 | public function testOverrideDefault()
56 | {
57 | $config = ['default' => 'new value'];
58 |
59 | $this->provider->setConfig($config);
60 |
61 | $this->assertEquals(
62 | $config,
63 | $this->provider->getConfig()
64 | );
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/tests/unit/Console/MergeTest.php:
--------------------------------------------------------------------------------
1 | add(new Merge('merge'));
27 |
28 | $command = $application->find('merge');
29 | $this->commandTester = new CommandTester($command);
30 | }
31 |
32 | public function testMergeMultipleChangelog()
33 | {
34 | $outputPath = __DIR__.'/../../_output/changelog.json';
35 | @unlink($outputPath);
36 |
37 | $this->commandTester->execute([
38 | 'files' => [
39 | __DIR__.'/../../resources/partial-changelog-1.md',
40 | __DIR__.'/../../resources/partial-changelog-2.md',
41 | ],
42 | '--config' => __DIR__.'/../../resources/changelog.config.merge.php',
43 | ]);
44 |
45 | $this->assertFileExists($outputPath);
46 | $jsonContent = json_decode(file_get_contents($outputPath), true);
47 |
48 | $this->assertCount(2, $jsonContent['releases']['unreleased']['changes']['Fixed']);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/IO/File.php:
--------------------------------------------------------------------------------
1 | "\n",
23 | ];
24 |
25 | /**
26 | * {@inheritdoc}
27 | *
28 | * @throws InvalidArgumentException
29 | */
30 | public function getContent()
31 | {
32 | $file = $this->getFileLocation();
33 |
34 | $content = file_get_contents($file);
35 |
36 | return explode(
37 | $this->getConfig('line_separator'),
38 | $content
39 | );
40 | }
41 |
42 | /**
43 | * {@inheritdoc}
44 | */
45 | public function setContent($content)
46 | {
47 | $file = $this->getFileLocation();
48 | file_put_contents($file, $content);
49 | }
50 |
51 | /**
52 | * Gets the file location from the config.
53 | *
54 | * @return string
55 | */
56 | protected function getFileLocation()
57 | {
58 | $file = $this->getConfig('file');
59 |
60 | if ( ! $file)
61 | {
62 | throw new InvalidArgumentException('File not specified.');
63 | }
64 |
65 | return $file;
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/src/Renderer/Json.php:
--------------------------------------------------------------------------------
1 | $log->getTitle(),
27 | 'description' => $log->getDescription(),
28 | 'releases' => [],
29 | ];
30 |
31 | /**
32 | * @var string $name
33 | * @var Release $release
34 | */
35 | foreach ($log as $name => $release)
36 | {
37 | $content['releases'][$name] = $this->renderRelease($release);
38 | }
39 |
40 | return json_encode($content);
41 | }
42 |
43 | /**
44 | * @param Release $release
45 | *
46 | * @return array
47 | */
48 | protected function renderRelease(Release $release)
49 | {
50 | $date = null;
51 |
52 | if ($release->getDate() !== null)
53 | {
54 | $date = $release->getDate()->format('Y-m-d');
55 | }
56 |
57 | return [
58 | 'name' => $release->getName(),
59 | 'link' => $release->getLink(),
60 | 'linkName' => $release->getLinkName(),
61 | 'date' => $date,
62 | 'changes' => $release->getAllChanges(),
63 | ];
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "emlynwest/changelog",
3 | "description": "Package to enable change logs to be parsed",
4 | "type": "library",
5 | "keywords": ["change", "log", "changelog", "parser"],
6 | "homepage": "https://github.com/emlynwest/changelog",
7 | "license": "MIT",
8 | "authors": [
9 | {
10 | "name": "Emlyn West",
11 | "email": "emlyn.west@gmail.com"
12 | }
13 | ],
14 | "require": {
15 | "symfony/console": "^7.0",
16 | "naneau/semver": "^0.0.7"
17 | },
18 | "require-dev": {
19 | "php": ">=8.2",
20 | "ext-json": "*",
21 | "codeception/codeception": "~5.1",
22 | "codeception/mockery-module": "~0.5",
23 | "milo/github-api": "dev-master",
24 | "league/flysystem": ">=3.29",
25 | "consolidation/robo": "^5.1",
26 | "codeception/module-asserts": "^3.0",
27 | "codeception/module-filesystem": "^3.0"
28 | },
29 | "autoload": {
30 | "psr-4": {
31 | "ChangeLog\\": "src/"
32 | }
33 | },
34 | "autoload-dev": {
35 | "psr-4": {
36 | "ChangeLog\\Stub\\": "tests/stubs"
37 | }
38 | },
39 | "suggest": {
40 | "milo/github-api": "Allows change logs to be loaded and committed to/from a github repo.",
41 | "league/flysystem": "Allows change logs to be read and written to pretty much everywhere."
42 | },
43 | "bin":["changelog"]
44 | }
45 |
--------------------------------------------------------------------------------
/src/AbstractIO.php:
--------------------------------------------------------------------------------
1 | setConfig($config);
34 | }
35 |
36 | /**
37 | * {@inheritdoc}
38 | */
39 | public function setConfig($config)
40 | {
41 | $this->config = $config;
42 | }
43 |
44 | /**
45 | * Gets the given config key, will load from config defaults if not set or return
46 | * null if there is no default.
47 | *
48 | * @param string|int $key
49 | *
50 | * @return string|array
51 | */
52 | public function getConfig($key = null)
53 | {
54 | if ($key === null)
55 | {
56 | return array_merge($this->configDefaults, $this->config);
57 | }
58 | elseif (isset($this->config[$key]))
59 | {
60 | return $this->config[$key];
61 | }
62 | elseif (isset($this->configDefaults[$key]))
63 | {
64 | return $this->configDefaults[$key];
65 | }
66 |
67 | return null;
68 | }
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/tests/unit/IO/FileTest.php:
--------------------------------------------------------------------------------
1 | file = new File;
28 | }
29 |
30 | public function testLoadFile()
31 | {
32 | $fileLocation = __DIR__ . '/../../_output/hello';
33 | @unlink ($fileLocation);
34 |
35 | file_put_contents($fileLocation, "hello\n");
36 |
37 | $this->file->setConfig([
38 | 'file' => $fileLocation,
39 | ]);
40 |
41 | $this->assertEquals(
42 | ['hello', ''],
43 | $this->file->getContent()
44 | );
45 | }
46 |
47 | public function testFileNotSet()
48 | {
49 | $this->expectException(InvalidArgumentException::class);
50 | $this->file->getContent();
51 | }
52 |
53 | public function testSetContent()
54 | {
55 | $content = 'foobar';
56 |
57 | $file = __DIR__.'/../../_output/IO-File-testSetContent.txt';
58 | touch($file);
59 |
60 | $this->file->setConfig(['file' => $file]);
61 | $this->file->setContent($content);
62 |
63 | /** @var Filesystem $filesystem */
64 | $filesystem = $this->getModule('Filesystem');
65 | $filesystem->openFile($file);
66 | $filesystem->seeInThisFile($content);
67 | $filesystem->deleteFile($file);
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/tests/unit/Renderer/XmlTest.php:
--------------------------------------------------------------------------------
1 |
5 | * @license MIT http://opensource.org/licenses/MIT
6 | * @link https://github.com/emlynwest/changelog
7 | */
8 |
9 | namespace ChangeLog\Renderer;
10 |
11 | use ChangeLog\Log;
12 | use ChangeLog\Release;
13 | use Codeception\Test\Unit;
14 | use DateTime;
15 |
16 | /**
17 | * Tests for Xml
18 | */
19 | class XmlTest extends Unit
20 | {
21 |
22 | /**
23 | * @var Json
24 | */
25 | protected $renderer;
26 |
27 | protected function _before()
28 | {
29 | $this->renderer = new Xml;
30 | }
31 |
32 | public function testRender()
33 | {
34 | $log = new Log;
35 | $log->setTitle('Change Log');
36 | $log->setDescription('A log for changes!');
37 |
38 | $release1 = new Release('1.0.0');
39 | $release1->setLink('http://fuelphp.com');
40 | $release1->setAllChanges([
41 | 'Fixed' => ['fixed 1', 'fixed 2'],
42 | 'Changed' => ['changed 1'],
43 | ]);
44 | $release1->setDate(DateTime::createFromFormat('Y-m-d', '2015-01-29'));
45 | $log->addRelease($release1);
46 |
47 | $release2 = new Release('0.1.0');
48 | $release2->setLink('http://google.com');
49 | $release2->setLinkName('foobar');
50 | $release2->setDate(DateTime::createFromFormat('Y-m-d', '2015-01-20'));
51 | $release2->setAllChanges([
52 | 'Changed' => ['changed 2'],
53 | ]);
54 | $log->addRelease($release2);
55 |
56 | $result = $this->renderer->render($log);
57 | $this->assertXmlStringEqualsXmlFile(
58 | __DIR__.'/../../resources/Parser-Xml-testRender.xml',
59 | $result
60 | );
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/tests/unit/Renderer/JsonTest.php:
--------------------------------------------------------------------------------
1 |
5 | * @license MIT http://opensource.org/licenses/MIT
6 | * @link https://github.com/emlynwest/changelog
7 | */
8 |
9 | namespace ChangeLog\Renderer;
10 |
11 | use ChangeLog\Log;
12 | use ChangeLog\Release;
13 | use Codeception\Test\Unit;
14 | use DateTime;
15 |
16 | /**
17 | * Tests for Json
18 | */
19 | class JsonTest extends Unit
20 | {
21 |
22 | /**
23 | * @var Json
24 | */
25 | protected $renderer;
26 |
27 | protected function _before()
28 | {
29 | $this->renderer = new Json;
30 | }
31 |
32 | public function testRender()
33 | {
34 | $log = new Log;
35 | $log->setTitle('Change Log');
36 | $log->setDescription('A log for changes!');
37 |
38 | $release1 = new Release('1.0.0');
39 | $release1->setLink('http://fuelphp.com');
40 | $release1->setAllChanges([
41 | 'Fixed' => ['fixed 1', 'fixed 2'],
42 | 'Changed' => ['changed 1'],
43 | ]);
44 | $release1->setDate(DateTime::createFromFormat('Y-m-d', '2015-01-29'));
45 | $log->addRelease($release1);
46 |
47 | $release2 = new Release('0.1.0');
48 | $release2->setLink('http://google.com');
49 | $release2->setLinkName('foobar');
50 | $release2->setDate(DateTime::createFromFormat('Y-m-d', '2015-01-20'));
51 | $release2->setAllChanges([
52 | 'Changed' => ['changed 2'],
53 | ]);
54 | $log->addRelease($release2);
55 |
56 | $result = $this->renderer->render($log);
57 | $this->assertJsonStringEqualsJsonFile(
58 | __DIR__.'/../../resources/Parser-Json-testRender.json',
59 | $result
60 | );
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/src/Console/Merge.php:
--------------------------------------------------------------------------------
1 | addArgument(
40 | 'files',
41 | InputArgument::IS_ARRAY,
42 | 'Changelog to merge.'
43 | );
44 | }
45 |
46 | public function execute(InputInterface $input, OutputInterface $output): int
47 | {
48 | parent::execute($input, $output);
49 |
50 | // Parse existing CHANGELOG
51 | $logs = $this->changeLog->parse();
52 |
53 | $files = $input->getArgument('files');
54 | foreach ($files as $f) {
55 | // Merge each file
56 | $this->changeLog->setInput(new File(['file' => $f]));
57 | $logs->mergeLog($this->changeLog->parse());
58 | }
59 |
60 | // Write updated CHANGELOG
61 | $this->changeLog->write($logs);
62 |
63 | return Command::SUCCESS;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Contributions are awesome but to help things along please take a look at the following.
4 |
5 | - [Issues](#-issues)
6 | - [Feature Requests](#-feature-requests)
7 | - [Pull Requests](#-pull-requests)
8 |
9 | ## Issues
10 |
11 | When opening an issue please make sure to include as much information as possible such as:
12 |
13 | - **things you have already tried**
14 | - Have you tried the latest package version? (`dev-main`)
15 | - Is there already a similar issue?
16 | - PHP version
17 | - Stack trace
18 | - Sample code or data
19 |
20 | ## Feature requests
21 |
22 | Feature requests can be either opened as an issue or you can contact me and ask for something.
23 |
24 | When you do think about what you are asking for, will others use it? Is it specific to your problem or not?
25 |
26 | ## Pull requests
27 |
28 | These are always welcome, it's what open source software is all about. But please keep a few things in mind:
29 |
30 | ### Follow the coding standard
31 |
32 | This package uses [PSR-2] with the exception that indentation should be `tab` characters, not `spaces` and that all `{`
33 | should be on a new line.
34 |
35 | ### Unit tests
36 |
37 | Any changes to the code should include updated or additional tests.
38 | Please make sure that if a test relates to an issue there is an `@link` to show that.
39 |
40 | Any new features should have related tests in the same pull request.
41 |
42 | All tests must pass, nothing will be merged in if there are tests failing.
43 |
44 | ### Code Quality
45 |
46 | While mostly a secondary concern code quality is still important. As a general rule of thumb make sure methods are not
47 | too long or needlessly complex when they can be broken up, use a bit of common sense.
48 |
49 | [PSR-2]: http://www.php-fig.org/psr/psr-2/
50 |
--------------------------------------------------------------------------------
/src/GenericFactory.php:
--------------------------------------------------------------------------------
1 | baseNamespace = $baseNamespace;
41 | }
42 |
43 | /**
44 | * Returns a constructed instance of the named class.
45 | *
46 | * @param string $name
47 | * @param array $parameters
48 | *
49 | * @return mixed
50 | *
51 | * @throws InvalidArgumentException If the class cannot be found.
52 | */
53 | public function getInstance($name, $parameters = [])
54 | {
55 | $class = $this->baseNamespace . ucfirst($name);
56 |
57 | // If we have a custom class, use that instead.
58 | if ( ! empty($this->addedClasses[$name]))
59 | {
60 | $class = $this->addedClasses[$name];
61 | }
62 |
63 | // Ensure our class actually exists
64 | if ( ! class_exists($class))
65 | {
66 | throw new InvalidArgumentException("$name is not a known class ($class)");
67 | }
68 |
69 | return new $class($parameters);
70 | }
71 |
72 | /**
73 | * Adds a new named class to the factory.
74 | *
75 | * @param string $name
76 | * @param string $class
77 | */
78 | public function addClass($name, $class)
79 | {
80 | $this->addedClasses[$name] = $class;
81 | }
82 |
83 | }
84 |
--------------------------------------------------------------------------------
/src/IO/Flysystem.php:
--------------------------------------------------------------------------------
1 | "\n",
24 | ];
25 |
26 | /**
27 | * {@inheritdoc}
28 | *
29 | * @throws InvalidArgumentException
30 | */
31 | public function getContent()
32 | {
33 | $file = $this->getFileLocation();
34 | $filesystem = $this->getFilesystem();
35 |
36 | $content = $filesystem->read($file);
37 |
38 | return explode(
39 | $this->getConfig('line_separator'),
40 | $content
41 | );
42 | }
43 |
44 | /**
45 | * {@inheritdoc}
46 | */
47 | public function setContent($content)
48 | {
49 | $file = $this->getFileLocation();
50 | $filesystem = $this->getFilesystem();
51 |
52 | $filesystem->put($file, $content);
53 | }
54 |
55 | /**
56 | * Gets the file location from the config.
57 | *
58 | * @return string
59 | */
60 | protected function getFileLocation()
61 | {
62 | $file = $this->getConfig('file');
63 |
64 | if ( ! $file)
65 | {
66 | throw new InvalidArgumentException('File not specified.');
67 | }
68 |
69 | return $file;
70 | }
71 |
72 | /**
73 | * @return Filesystem
74 | */
75 | protected function getFilesystem()
76 | {
77 | $adaptor = $this->getConfig('filesystem');
78 |
79 | if ( ! $adaptor)
80 | {
81 | throw new InvalidArgumentException('Filesystem object not specified.');
82 | }
83 |
84 | return $adaptor;
85 | }
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/tests/unit/GenericFactoryTest.php:
--------------------------------------------------------------------------------
1 | factory = new GenericFactory('ChangeLog\IO\\');
29 | }
30 |
31 | public function testGetInstance()
32 | {
33 | $this->assertInstanceOf(
34 | 'ChangeLog\IO\Native',
35 | $this->factory->getInstance('native')
36 | );
37 | }
38 |
39 | public function testGetInvalidClass()
40 | {
41 | $this->expectException(InvalidArgumentException::class);
42 |
43 | $this->factory->getInstance('If this works there is something seriously wrong!');
44 | }
45 |
46 | public function testCustomClass()
47 | {
48 | $class = 'ChangeLog\Stub\AbstractIOStub';
49 | $name = 'foobar';
50 |
51 | $this->factory->addClass($name, $class);
52 |
53 | $this->assertInstanceOf(
54 | $class,
55 | $this->factory->getInstance($name)
56 | );
57 | }
58 |
59 | public function testGetInstanceWithParameters()
60 | {
61 | $one = 'foo';
62 | $two = 'bar';
63 |
64 | $class = 'ChangeLog\Stub\GetableConstructorStub';
65 | $this->factory->addClass('bazbat', $class);
66 |
67 | /** @var GetableConstructorStub $instance */
68 | $instance = $this->factory->getInstance('bazbat', [$one, $two]);
69 |
70 | $this->assertInstanceOf(
71 | $class,
72 | $instance
73 | );
74 |
75 | $this->assertEquals(
76 | $one,
77 | $instance->one
78 | );
79 |
80 | $this->assertEquals(
81 | $two,
82 | $instance->two
83 | );
84 | }
85 |
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/src/Console/Add.php:
--------------------------------------------------------------------------------
1 | addArgument(
35 | 'release',
36 | InputOption::VALUE_REQUIRED,
37 | 'Release to add the change to, will be created if it does not exist.'
38 | );
39 |
40 | $this->addArgument(
41 | 'type',
42 | InputOption::VALUE_REQUIRED,
43 | 'Added, fixed, changed, etc'
44 | );
45 |
46 | $this->addArgument(
47 | 'change',
48 | InputOption::VALUE_REQUIRED,
49 | 'Change message, eg "fixed issue #123"'
50 | );
51 | }
52 |
53 | public function execute(InputInterface $input, OutputInterface $output): int
54 | {
55 | parent::execute($input, $output);
56 |
57 | $log = $this->changeLog->parse();
58 |
59 | $releaseName = $input->getArgument('release');
60 |
61 | // Create the release_name if needed
62 | if ( ! $log->hasRelease($releaseName)) {
63 | $newRelease = new LogRelease($releaseName);
64 | $log->addRelease($newRelease);
65 | }
66 |
67 | $release = $log->getRelease($releaseName);
68 |
69 | $release->addChange($input->getArgument('type'), $input->getArgument('change'));
70 |
71 | $this->changeLog->write($log);
72 |
73 | return Command::SUCCESS;
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/tests/unit/ChangeLogTest.php:
--------------------------------------------------------------------------------
1 | shouldReceive('getContent')
25 | ->once()
26 | ->andReturn($content);
27 |
28 | $parser = Mockery::mock('ChangeLog\ParserInterface');
29 | $parser->shouldReceive('parse')
30 | ->once()
31 | ->with($content);
32 |
33 | $changeLog = new ChangeLog;
34 | $changeLog->setParser($parser);
35 | $changeLog->setInput($input);
36 | $changeLog->parse();
37 | }
38 |
39 | public function testWrite()
40 | {
41 | $log = new Log;
42 | $parsed = 'foobar';
43 |
44 | $renderer = Mockery::mock('ChangeLog\RenderInterface');
45 | $renderer->shouldReceive('render')
46 | ->once()
47 | ->with($log)
48 | ->andReturn($parsed);
49 |
50 | $output = Mockery::mock('ChangeLog\IOInterface');
51 | $output->shouldReceive('setContent')
52 | ->once()
53 | ->with($parsed);
54 |
55 | $changeLog = new ChangeLog;
56 | $changeLog->setRenderer($renderer);
57 | $changeLog->setOutput($output);
58 | $changeLog->write($log);
59 | }
60 |
61 | public function testParseWithoutInput()
62 | {
63 | $this->expectException(LogicException::class);
64 |
65 | $parser = Mockery::mock('ChangeLog\ParserInterface');
66 | $changeLog = new ChangeLog($parser);
67 | $changeLog->parse();
68 | }
69 |
70 | public function testWriteWithoutInput()
71 | {
72 | $this->expectException(LogicException::class);
73 |
74 | $parser = Mockery::mock('ChangeLog\RenderInterface');
75 | $changeLog = new ChangeLog();
76 | $changeLog->setRenderer($parser);
77 | $changeLog->write(new Log);
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/tests/unit/IO/GitHubReleasesTest.php:
--------------------------------------------------------------------------------
1 | shouldReceive('get')
28 | ->with("/repos/$repo/releases")
29 | ->andReturn(true)
30 | ->once();
31 |
32 | $release1 = new stdClass;
33 | $release1->published_at = '2015-02-26';
34 | $release1->tag_name = '0.2.0';
35 | $release1->body = 'content 2';
36 | $release1->html_url = 'http://release.com/2';
37 |
38 | $release2 = new stdClass;
39 | $release2->published_at = '2015-02-25';
40 | $release2->tag_name = '0.1.0';
41 | $release2->body = 'content 1';
42 | $release2->html_url = 'http://release.com/1';
43 |
44 | $releases = [$release1, $release2];
45 |
46 | $apiMock->shouldReceive('decode')
47 | ->with(true)
48 | ->andReturn($releases)
49 | ->once();
50 |
51 | $gitHub = new GitHubReleasesStub;
52 | $gitHub->setApi($apiMock);
53 | $gitHub->setConfig([
54 | 'repo' => $repo,
55 | ]);
56 |
57 | $this->assertEquals(
58 | [
59 | '# GitHub Releases',
60 | '',
61 | '## [0.2.0] - 2015-02-26',
62 | 'content 2',
63 | '## [0.1.0] - 2015-02-25',
64 | 'content 1',
65 | '',
66 | '[0.2.0]: http://release.com/2',
67 | '[0.1.0]: http://release.com/1',
68 | ],
69 | $gitHub->getContent()
70 | );
71 | }
72 |
73 | public function testSetContent()
74 | {
75 | $this->expectException(Exception::class);
76 | $this->expectExceptionMessage('This has yet to be implemented.');
77 |
78 | $gitHub = new GitHubReleasesStub;
79 | $gitHub->setContent('foobar');
80 | }
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/tests/unit/IO/FlysystemTest.php:
--------------------------------------------------------------------------------
1 | file = new Flysystem;
27 | }
28 |
29 | public function testLoadFile()
30 | {
31 | $filesystem = \Mockery::mock('League\Flysystem\Filesystem');
32 | $filesystem->shouldReceive('read')
33 | ->with('hello.txt')
34 | ->once()
35 | ->andReturn("hello\n");
36 |
37 | $this->file->setConfig([
38 | 'file' => 'hello.txt',
39 | 'filesystem' => $filesystem,
40 | ]);
41 |
42 | $this->assertEquals(
43 | ['hello', ''],
44 | $this->file->getContent()
45 | );
46 | }
47 |
48 | public function testFileNotSet()
49 | {
50 | $this->expectException(InvalidArgumentException::class);
51 | $this->expectExceptionMessage('File not specified.');
52 |
53 | $filesystem = \Mockery::mock('League\Flysystem\Filesystem');
54 | $this->file->setConfig([
55 | 'filesystem' => $filesystem,
56 | ]);
57 | $this->file->getContent();
58 | }
59 |
60 | public function testFilesystemNotSet()
61 | {
62 | $this->expectException(InvalidArgumentException::class);
63 | $this->expectExceptionMessage('Filesystem object not specified.');
64 |
65 | $this->file->setConfig([
66 | 'file' => 'foobar',
67 | ]);
68 | $this->file->getContent();
69 | }
70 |
71 | public function testSetContent()
72 | {
73 | $content = 'foobar';
74 | $file = 'hello.txt';
75 |
76 | $filesystem = \Mockery::mock('League\Flysystem\Filesystem');
77 | $filesystem->shouldReceive('put')
78 | ->with('hello.txt', $content)
79 | ->once();
80 |
81 | $this->file->setConfig([
82 | 'file' => $file,
83 | 'filesystem' => $filesystem,
84 | ]);
85 |
86 | $this->file->setContent($content);
87 | }
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/tests/unit/Console/AddTest.php:
--------------------------------------------------------------------------------
1 | add(new Add('add'));
27 |
28 | $command = $application->find('add');
29 | $this->commandTester = new CommandTester($command);
30 | }
31 |
32 | public function testAddToExistingRelease()
33 | {
34 | $outputPath = __DIR__ . '/../../_output/changelog.json';
35 | @unlink($outputPath);
36 |
37 | $this->commandTester->execute([
38 | 'release' => '0.0.6',
39 | 'type' => 'foobar',
40 | 'change' => 'something',
41 | '--config' => __DIR__.'/../../resources/changelog.config.php',
42 | ]);
43 |
44 | $this->assertFileExists($outputPath);
45 | $jsonContent = json_decode(file_get_contents($outputPath), true);
46 |
47 | $this->assertFalse(empty($jsonContent['releases']['0.0.6']['changes']['foobar']));
48 | $this->assertTrue(in_array('something', $jsonContent['releases']['0.0.6']['changes']['foobar']));
49 | }
50 |
51 | public function testAddToNewRelease()
52 | {
53 | $outputPath = __DIR__ . '/../../_output/changelog.json';
54 | @unlink($outputPath);
55 |
56 | $this->commandTester->execute([
57 | 'release' => '1.0.0',
58 | 'type' => 'flip-flopped',
59 | 'change' => 'something',
60 | '--config' => __DIR__.'/../../resources/changelog.config.php',
61 | ]);
62 |
63 | $this->assertFileExists($outputPath);
64 | $jsonContent = json_decode(file_get_contents($outputPath), true);
65 |
66 | $this->assertFalse(empty($jsonContent['releases']['1.0.0']['changes']['flip-flopped']));
67 | $this->assertTrue(in_array('something', $jsonContent['releases']['1.0.0']['changes']['flip-flopped']));
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/IO/GitHubReleases.php:
--------------------------------------------------------------------------------
1 | /" The full username and repo name to use.
15 | * - token: GitHub API token, can be generated under account -> applications.
16 | * - log_title: Optional name of the change log.
17 | *
18 | * The token must have the "repo" or "public_repo" permission depending on the visibility of the repo.
19 | */
20 | class GitHubReleases extends AbstractGitHubIO
21 | {
22 |
23 | protected $configDefaults = [
24 | 'log_title' => 'GitHub Releases',
25 | ];
26 |
27 | /**
28 | * Returns the content of the change log to be parsed.
29 | * The returned data should be an array of strings, one entry for each file line.
30 | *
31 | * @return array
32 | */
33 | public function getContent()
34 | {
35 | $api = $this->getApi();
36 | $response = $api->get($this->getApiUrl());
37 | $content = $api->decode($response);
38 |
39 | $links = [];
40 |
41 | $title = $this->getConfig('log_title');
42 | $log = "# $title\n\n";
43 |
44 | foreach($content as $release)
45 | {
46 | // published_at for release date
47 | $date = substr($release->published_at, 0, 10);
48 |
49 | // tag_name for the release title
50 | $log .= "## [{$release->tag_name}] - $date\n";
51 |
52 | // body for the release changes
53 | $log .= $release->body."\n";
54 |
55 | // html_url for links added at the end
56 | $links[] = "[{$release->tag_name}]: {$release->html_url}";
57 | }
58 |
59 | return explode("\n", $log . "\n" . implode("\n", $links));
60 | }
61 |
62 | /**
63 | * Writes out the given content,
64 | *
65 | * @param string $content
66 | */
67 | public function setContent($content)
68 | {
69 | // TODO: Implement setContent() method.
70 | throw new \Exception('This has yet to be implemented.');
71 | }
72 |
73 | /**
74 | * Gets a URL for the GitHub api for our file.
75 | *
76 | * @return string
77 | */
78 | protected function getApiUrl()
79 | {
80 | $repo = $this->getConfig('repo');
81 |
82 | $url = "/repos/$repo/releases";
83 | return $url;
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/src/Renderer/Xml.php:
--------------------------------------------------------------------------------
1 | ');
27 |
28 | $xml->addChild('title', $log->getTitle());
29 | $xml->addChild('description', $log->getDescription());
30 |
31 | $releases = $xml->addChild('releases');
32 |
33 | /** @var Release $release */
34 | foreach ($log as $release)
35 | {
36 | $this->renderRelease($releases, $release);
37 | }
38 |
39 | $xml = $xml->asXML();
40 | return ($xml !== false) ? $xml : '' ;
41 | }
42 |
43 | /**
44 | * Adds the release's changes to the given xml release node.
45 | *
46 | * @param SimpleXMLElement $releaseNode
47 | * @param Release $release
48 | */
49 | protected function addChanges(SimpleXMLElement $releaseNode, Release $release)
50 | {
51 | $changesNode = $releaseNode->addChild('changes');
52 |
53 | foreach ($release->getAllChanges() as $type => $changes)
54 | {
55 | $typeNode = $changesNode->addChild('type');
56 | $typeNode->addAttribute('name', $type);
57 |
58 | foreach ($changes as $change)
59 | {
60 | $typeNode->addChild('change', $change);
61 | }
62 | }
63 | }
64 |
65 | /**
66 | * @param SimpleXMLElement $releases
67 | * @param Release $release
68 | */
69 | protected function renderRelease($releases, $release)
70 | {
71 | $releaseNode = $releases->addChild('release');
72 | $releaseNode->addChild('name', $release->getName());
73 | $releaseNode->addChild('link', $release->getLink());
74 |
75 | if ($release->getLinkName() !== null)
76 | {
77 | $releaseNode->addChild('linkName', $release->getLinkName());
78 | }
79 |
80 | if ($release->getDate() !== null)
81 | {
82 | $releaseNode->addChild('date',
83 | $release->getDate()
84 | ->format('Y-m-d')
85 | );
86 | }
87 |
88 | $this->addChanges($releaseNode, $release);
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/src/IO/GitHub.php:
--------------------------------------------------------------------------------
1 | /" The full username and repo name to use.
17 | * - file: Path to the file from the root of the repo
18 | * - token: GitHub API token, can be generated under account -> applications
19 | * - commit_message: Optional commit message, used when setContent() is called.
20 | *
21 | * The token must have the "repo" or "public_repo" permission depending on the visibility of the repo.
22 | */
23 | class GitHub extends AbstractGitHubIO
24 | {
25 |
26 | protected $configDefaults = [
27 | 'commit_message' => 'Updates change log.',
28 | 'line_separator' => "\n",
29 | ];
30 |
31 | /**
32 | * {@inheritdoc}
33 | */
34 | public function getContent()
35 | {
36 | $content = $this->requestFile();
37 |
38 | return explode(
39 | $this->getConfig('line_separator'),
40 | base64_decode($content->content)
41 | );
42 | }
43 |
44 | /**
45 | * {@inheritdoc}
46 | */
47 | public function setContent($content)
48 | {
49 | // Request the file so we can get its sha
50 | $fileInfo = $this->requestFile();
51 |
52 | $encodedContent = base64_encode($content);
53 | $data = [
54 | 'message' => $this->getConfig('commit_message'),
55 | 'content' => $encodedContent,
56 | 'sha' => $fileInfo->sha,
57 | ];
58 |
59 | $api = $this->getApi();
60 | $response = $api->put($this->getApiUrl(), $data);
61 | // Parse the response so an exception is thrown if anything goes funky
62 | $api->decode($response);
63 | }
64 |
65 | /**
66 | * Gets a URL for the GitHub api for our file.
67 | *
68 | * @return string
69 | */
70 | protected function getApiUrl()
71 | {
72 | $repo = $this->getConfig('repo');
73 | $file = $this->getConfig('file');
74 |
75 | $url = "/repos/$repo/contents/$file";
76 | return $url;
77 | }
78 |
79 | /**
80 | * @return stdClass
81 | */
82 | protected function requestFile()
83 | {
84 | $api = $this->getApi();
85 | $response = $api->get($this->getApiUrl());
86 | $content = $api->decode($response);
87 | return $content;
88 | }
89 |
90 | }
91 |
--------------------------------------------------------------------------------
/src/ChangeLog.php:
--------------------------------------------------------------------------------
1 | input === null)
48 | {
49 | throw new LogicException('You must specify an IOInterface for input first.');
50 | }
51 |
52 | return $this->parser->parse(
53 | $this->input->getContent()
54 | );
55 | }
56 |
57 | /**
58 | * Writes out the given Log to the chosen output.
59 | *
60 | * @param Log $log
61 | *
62 | * @throws LogicException
63 | */
64 | public function write(Log $log)
65 | {
66 | if ($this->output === null)
67 | {
68 | throw new LogicException('You must specify an IOInterface for output first.');
69 | }
70 |
71 | $this->output->setContent(
72 | $this->renderer->render($log)
73 | );
74 | }
75 |
76 | /**
77 | * Sets the adaptor to use for reading change logs.
78 | *
79 | * @param IOInterface $input
80 | */
81 | public function setInput(IOInterface $input)
82 | {
83 | $this->input = $input;
84 | }
85 |
86 | /**
87 | * Sets the adaptor to use for writing change logs.
88 | *
89 | * @param IOInterface $output
90 | */
91 | public function setOutput(IOInterface $output)
92 | {
93 | $this->output = $output;
94 | }
95 |
96 | /**
97 | * Sets the adaptor to render with.
98 | *
99 | * @param RenderInterface $renderer
100 | */
101 | public function setRenderer(RenderInterface $renderer)
102 | {
103 | $this->renderer = $renderer;
104 | }
105 |
106 | /**
107 | * Sets the adaptor to parse with.
108 | *
109 | * @param ParserInterface $parser
110 | */
111 | public function setParser(ParserInterface $parser)
112 | {
113 | $this->parser = $parser;
114 | }
115 |
116 | }
117 |
--------------------------------------------------------------------------------
/tests/unit/IO/GitHubTest.php:
--------------------------------------------------------------------------------
1 | shouldReceive('get')
29 | ->with("/repos/$repo/contents/$file")
30 | ->andReturn(true)
31 | ->once();
32 |
33 | $expected = new stdClass;
34 | $content = 'foobar';
35 | $expected->content = base64_encode($content);
36 |
37 | $apiMock->shouldReceive('decode')
38 | ->with(true)
39 | ->andReturn($expected)
40 | ->once();
41 |
42 | $gitHub = new GitHubStub;
43 | $gitHub->setApi($apiMock);
44 | $gitHub->setConfig([
45 | 'repo' => $repo,
46 | 'file' => $file,
47 | ]);
48 |
49 | $this->assertEquals(
50 | [$content],
51 | $gitHub->getContent()
52 | );
53 | }
54 |
55 | public function testCreateApiWithNoToken()
56 | {
57 | $this->expectException(InvalidArgumentException::class);
58 |
59 | $gitHub = new GitHubStub;
60 | $gitHub->getContent();
61 | }
62 |
63 | public function testSetContent()
64 | {
65 | $repo = 'foo/bar';
66 | $file = 'changelog.md';
67 | $path = "/repos/$repo/contents/$file";
68 | $message = 'I updated the changelog!';
69 | $newContent = 'foobarmazbat';
70 |
71 | $apiMock = Mockery::mock();
72 | $apiMock->shouldReceive('get')
73 | ->with($path)
74 | ->andReturn(true)
75 | ->once();
76 |
77 | $expected = new stdClass;
78 | $content = 'foobar';
79 | $sha = 'asdasd';
80 | $expected->sha = $sha;
81 | $expected->content = base64_encode($content);
82 |
83 | $apiMock->shouldReceive('decode')
84 | ->with(true)
85 | ->andReturn($expected)
86 | ->twice();
87 |
88 | $apiMock->shouldReceive('put')
89 | ->with($path, [
90 | 'message' => $message,
91 | 'content' => base64_encode($newContent),
92 | 'sha' => $sha,
93 | ])
94 | ->andReturn(true)
95 | ->once();
96 |
97 | $gitHub = new GitHubStub;
98 | $gitHub->setApi($apiMock);
99 | $gitHub->setConfig([
100 | 'repo' => $repo,
101 | 'file' => $file,
102 | 'commit_message' => $message,
103 | ]);
104 |
105 | $gitHub->setContent($newContent);
106 | }
107 |
108 | }
109 |
--------------------------------------------------------------------------------
/tests/unit/ReleaseTest.php:
--------------------------------------------------------------------------------
1 | release = new Release;
27 | }
28 |
29 | public function testGetSetName()
30 | {
31 | $name = '1.0.0';
32 | $this->release->setName($name);
33 | $this->assertEquals(
34 | $name,
35 | $this->release->getName()
36 | );
37 | }
38 |
39 | public function testGetSetYanked()
40 | {
41 | $this->assertFalse(
42 | $this->release->isYanked()
43 | );
44 |
45 | $this->release->setYanked(true);
46 |
47 | $this->assertTrue(
48 | $this->release->isYanked()
49 | );
50 | }
51 |
52 | public function testGetSetLink()
53 | {
54 | $link = 'http://google.com';
55 | $this->release->setLink($link);
56 | $this->assertEquals(
57 | $link,
58 | $this->release->getLink()
59 | );
60 | }
61 |
62 | public function testGetSetChanges()
63 | {
64 | $fixes = ['#1', '#2', '#3'];
65 | $changes = [
66 | 'fixed' => $fixes,
67 | 'added' => ['Super awesome feature']
68 | ];
69 |
70 | $this->release->setAllChanges($changes);
71 | $this->assertEquals(
72 | $changes,
73 | $this->release->getAllChanges()
74 | );
75 |
76 | $this->assertEquals(
77 | $fixes,
78 | $this->release->getChanges('fixed')
79 | );
80 |
81 | $this->assertNull(
82 | $this->release->getChanges('foobar')
83 | );
84 |
85 | $this->release->addChange('fixed', '#4');
86 | $this->assertEquals(
87 | array_merge($fixes, ['#4']),
88 | $this->release->getChanges('fixed')
89 | );
90 |
91 | $this->release->addChange('new', 'foobar');
92 | $this->assertEquals(
93 | ['foobar'],
94 | $this->release->getChanges('new')
95 | );
96 |
97 | $newFixes = ['a'];
98 | $this->release->setChanges('fixed', $newFixes);
99 | $this->assertEquals(
100 | $newFixes,
101 | $this->release->getChanges('fixed')
102 | );
103 | }
104 |
105 | public function testGetSetDate()
106 | {
107 | $date = new DateTime;
108 |
109 | $this->release->setDate($date);
110 | $this->assertEquals(
111 | $date,
112 | $this->release->getDate()
113 | );
114 | }
115 |
116 | public function testGetSetLinkName()
117 | {
118 | $name = 'abc';
119 |
120 | $this->release->setLinkName($name);
121 | $this->assertEquals(
122 | $name,
123 | $this->release->getLinkName()
124 | );
125 | }
126 |
127 | }
128 |
--------------------------------------------------------------------------------
/src/Console/Release.php:
--------------------------------------------------------------------------------
1 | addArgument(
34 | 'release',
35 | InputOption::VALUE_REQUIRED,
36 | 'New release number, can be any valid semver or [major|minor|patch]'
37 | );
38 | $this->addOption(
39 | 'link',
40 | null,
41 | InputOption::VALUE_REQUIRED,
42 | 'Optional link to the release\'s info page'
43 | );
44 | $this->addOption(
45 | 'linkName',
46 | null,
47 | InputOption::VALUE_REQUIRED,
48 | 'Optional link name, release name will be used if not specified'
49 | );
50 | }
51 |
52 | public function execute(InputInterface $input, OutputInterface $output): int
53 | {
54 | parent::execute($input, $output);
55 |
56 | $releaseName = $input->getArgument('release');
57 |
58 | if ($releaseName === null) {
59 | throw new InvalidArgumentException('A release name is required');
60 | }
61 |
62 | $log = $this->changeLog->parse();
63 |
64 | // Don't continue if there is no unreleased version
65 | if ( ! $log->hasRelease('unreleased')) {
66 | throw new ReleaseNotFoundException('Unable to find an unreleased version.');
67 | }
68 |
69 | // Work out what version number we actually want
70 | $newReleaseName = $log->getNextVersion($releaseName);
71 |
72 | // Don't continue if the release already exists
73 | if ($log->hasRelease($newReleaseName)) {
74 | throw new ReleaseExistsException('A release with the name "' . $newReleaseName . '" already exists."');
75 | }
76 |
77 | $release = $log->getRelease('unreleased');
78 | $release->setName($newReleaseName);
79 |
80 | $newLink = $input->getOption('link');
81 |
82 | if ($newLink === null) {
83 | $release->setLink(null);
84 | $release->setLinkName(null);
85 | } else {
86 | $newLinkName = $input->getOption('linkName');
87 | $newLinkName = $newLinkName === null ? $newReleaseName : $newLinkName;
88 |
89 | $release->setLink($newLink);
90 | $release->setLinkName($newLinkName);
91 | }
92 |
93 | // Remove and re-add the release to trigger the log internals
94 | $log->addRelease($release);
95 | $log->removeRelease('unreleased');
96 |
97 | $this->changeLog->write($log);
98 |
99 | return Command::SUCCESS;
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/tests/unit/Renderer/KeepAChangeLogTest.php:
--------------------------------------------------------------------------------
1 | renderer = new KeepAChangeLog;
29 | }
30 |
31 | public function testRender()
32 | {
33 | $log = new Log;
34 | $log->setDescription('This is my change log, it will have lots of changes in it!');
35 | $log->setTitle('My change log');
36 |
37 | $release1 = new Release('1.0.0');
38 | $release1->setAllChanges([
39 | 'Added' => ['Thing 1', 'Thing 2'],
40 | 'Changed' => ['Some change']
41 | ]);
42 | $log->addRelease($release1);
43 |
44 | $release2 = new Release('0.1.0');
45 | $release2->setAllChanges([
46 | 'Added' => ['Initial release'],
47 | ]);
48 | $log->addRelease($release2);
49 |
50 | $expected = implode("\n", [
51 | '# My change log',
52 | 'This is my change log, it will have lots of changes in it!',
53 | '',
54 | '## 1.0.0',
55 | '### Added',
56 | '- Thing 1',
57 | '- Thing 2',
58 | '',
59 | '### Changed',
60 | '- Some change',
61 | '',
62 | '## 0.1.0',
63 | '### Added',
64 | '- Initial release',
65 | '',
66 | ]);
67 |
68 | $actual = $this->renderer->render($log);
69 | $this->assertEquals(
70 | $expected,
71 | $actual
72 | );
73 |
74 | }
75 |
76 | public function testDateRender()
77 | {
78 | $release = new Release('1.0.0');
79 | $release->setDate(DateTime::createFromFormat('Y-m-d', '2015-01-25'));
80 |
81 | $result = $this->renderer->renderRelease($release);
82 | $this->assertEquals(
83 | "\n## 1.0.0 - 2015-01-25",
84 | $result
85 | );
86 | }
87 |
88 | public function testYankedRender()
89 | {
90 | $release = new Release('1.0.0');
91 | $release->setYanked(true);
92 |
93 | $result = $this->renderer->renderRelease($release);
94 | $this->assertEquals(
95 | "\n## 1.0.0 [YANKED]",
96 | $result
97 | );
98 | }
99 |
100 | public function testRenderLink()
101 | {
102 | $log = new Log();
103 | $log->setTitle('Change log');
104 | $log->setDescription('My change log');
105 |
106 | $release1 = new Release('1.0.0');
107 | $release1->setLink('http://fuelphp.com');
108 | $log->addRelease($release1);
109 |
110 | $release1 = new Release('0.1.0');
111 | $release1->setLink('http://google.com');
112 | $release1->setLinkName('a');
113 | $log->addRelease($release1);
114 |
115 | $expected = implode("\n", [
116 | '# Change log',
117 | 'My change log',
118 | '',
119 | '## [1.0.0]',
120 | '## [0.1.0][a]',
121 | '',
122 | '[1.0.0] http://fuelphp.com',
123 | '[a] http://google.com',
124 | '',
125 | ]);
126 |
127 | $result = $this->renderer->render($log);
128 |
129 | $this->assertEquals(
130 | $expected,
131 | $result
132 | );
133 | }
134 |
135 | }
136 |
--------------------------------------------------------------------------------
/src/Renderer/KeepAChangeLog.php:
--------------------------------------------------------------------------------
1 | getTitle()}\n" .
26 | "{$log->getDescription()}\n";
27 |
28 | $links = '';
29 |
30 | /** @var Release $release */
31 | foreach ($log as $release)
32 | {
33 | $content .= $this->renderRelease($release);
34 | $links .= $this->createLink($release);
35 | }
36 |
37 | if ($links !== '')
38 | {
39 | $content .= "\n\n" . $links;
40 | }
41 |
42 | return $content;
43 | }
44 |
45 | /**
46 | * Creates the needed link text for a Release.
47 | *
48 | * @param Release $release
49 | *
50 | * @return string
51 | */
52 | protected function createLink(Release $release)
53 | {
54 | $line = '';
55 |
56 | $link = $release->getLink();
57 |
58 | if ($link !== null)
59 | {
60 | $linkName = $release->getLinkName();
61 | $name = $release->getName();
62 |
63 | $reference = ($linkName === null) ? $name : $linkName;
64 |
65 | $line = "[$reference] $link\n";
66 | }
67 |
68 | return $line;
69 | }
70 |
71 | /**
72 | * Converts a Release into its text representation.
73 | *
74 | * @param Release $release
75 | *
76 | * @return string
77 | */
78 | public function renderRelease(Release $release)
79 | {
80 | $name = $release->getName();
81 |
82 | if ($release->getLink() !== null)
83 | {
84 | $name = "[$name]";
85 | }
86 |
87 | if ($release->getLinkName() !== null)
88 | {
89 | $name .= "[{$release->getLinkName()}]";
90 | }
91 |
92 | $content = "\n## $name";
93 |
94 | $content .= $this->addDate($release);
95 | $content .= $this->addYanked($release);
96 |
97 | $content .= "\n";
98 |
99 | foreach ($release->getAllChanges() as $type => $changes)
100 | {
101 | $content .= $this->renderType($type, $changes);
102 | }
103 |
104 | return substr($content, 0, strlen($content)-1);
105 | }
106 |
107 | /**
108 | * Converts a list of changes with a given type back into text.
109 | *
110 | * @param string $type
111 | * @param array $changes
112 | *
113 | * @return string
114 | */
115 | public function renderType($type, $changes)
116 | {
117 | $content = '';
118 |
119 | if (count($changes) > 0)
120 | {
121 | $content = "### $type\n" .
122 | '- ' . implode("\n- ", $changes) . "\n";
123 | }
124 |
125 | return $content . "\n";
126 | }
127 |
128 | /**
129 | * Adds the date to a Release title for rendering if the Release has a date.
130 | *
131 | * @param Release $release
132 | *
133 | * @return string
134 | */
135 | protected function addDate(Release $release)
136 | {
137 | $content = '';
138 | $date = $release->getDate();
139 | if ($date !== null)
140 | {
141 | $content = ' - ' . $date->format('Y-m-d');
142 | }
143 | return $content;
144 | }
145 | /**
146 | * Returns the YANKED tag if needed
147 | *
148 | * @param Release $release
149 | *
150 | * @return string
151 | */
152 | protected function addYanked(Release $release)
153 | {
154 | $content = '';
155 | if ($release->isYanked())
156 | {
157 | $content = ' [YANKED]';
158 | }
159 | return $content;
160 | }
161 |
162 | }
163 |
--------------------------------------------------------------------------------
/src/Console/AbstractCommand.php:
--------------------------------------------------------------------------------
1 | addOption(
37 | 'config',
38 | null,
39 | InputOption::VALUE_OPTIONAL,
40 | 'Location of config file.',
41 | 'changelog.config.php'
42 | );
43 | $this->addOption(
44 | 'input',
45 | null,
46 | InputOption::VALUE_OPTIONAL,
47 | 'Config to use for input processor',
48 | 'default'
49 | );
50 | $this->addOption(
51 | 'parser',
52 | null,
53 | InputOption::VALUE_OPTIONAL,
54 | 'Config to use for parser processor',
55 | 'default'
56 | );
57 | $this->addOption(
58 | 'renderer',
59 | null,
60 | InputOption::VALUE_OPTIONAL,
61 | 'Config to use for renderer processor',
62 | 'default'
63 | );
64 | $this->addOption(
65 | 'output',
66 | null,
67 | InputOption::VALUE_OPTIONAL,
68 | 'Config to use for output processor',
69 | 'default'
70 | );
71 | }
72 |
73 | public function execute(InputInterface $input, OutputInterface $output): int
74 | {
75 | $configLocation = $input->getOption('config');
76 |
77 | if ( ! is_file($configLocation) && ! is_readable($configLocation))
78 | {
79 | throw new ConfigNotFoundException('Unable to open config file: ' . $configLocation);
80 | }
81 |
82 | $this->config = require $configLocation;
83 |
84 | // Construct a changelog object to manipulate
85 | $this->changeLog = new ChangeLog();
86 |
87 | $this->setInput($input->getOption('input'));
88 | $this->setParser($input->getOption('parser'));
89 | $this->setRenderer($input->getOption('renderer'));
90 | $this->setOutput($input->getOption('output'));
91 |
92 | return Command::SUCCESS;
93 | }
94 |
95 | protected function setInput($factoryName)
96 | {
97 | $factory = new GenericFactory('\ChangeLog\IO\\');
98 | $instance = $factory->getInstance(
99 | $this->config['input'][$factoryName]['strategy'],
100 | $this->config['input'][$factoryName]['config']
101 | );
102 | $this->changeLog->setInput($instance);
103 | }
104 |
105 | protected function setParser($factoryName)
106 | {
107 | $factory = new GenericFactory('\ChangeLog\Parser\\');
108 | $instance = $factory->getInstance($this->config['parser'][$factoryName]['strategy']);
109 | $this->changeLog->setParser($instance);
110 | }
111 |
112 | protected function setRenderer($factoryName)
113 | {
114 | $factory = new GenericFactory('\ChangeLog\Renderer\\');
115 | $instance = $factory->getInstance($this->config['renderer'][$factoryName]['strategy']);
116 | $this->changeLog->setRenderer($instance);
117 | }
118 |
119 | protected function setOutput($factoryName)
120 | {
121 | $factory = new GenericFactory('\ChangeLog\IO\\');
122 | $instance = $factory->getInstance(
123 | $this->config['output'][$factoryName]['strategy'],
124 | $this->config['output'][$factoryName]['config']
125 | );
126 | $this->changeLog->setOutput($instance);
127 | }
128 |
129 | }
130 |
--------------------------------------------------------------------------------
/src/Release.php:
--------------------------------------------------------------------------------
1 | setName($name);
58 | }
59 |
60 | /**
61 | * @return string
62 | */
63 | public function getName()
64 | {
65 | return $this->name;
66 | }
67 |
68 | /**
69 | * @param string $name
70 | */
71 | public function setName($name)
72 | {
73 | $this->name = $name;
74 | }
75 |
76 | /**
77 | * @return boolean
78 | */
79 | public function isYanked()
80 | {
81 | return $this->yanked;
82 | }
83 |
84 | /**
85 | * @param boolean $yanked
86 | */
87 | public function setYanked($yanked)
88 | {
89 | $this->yanked = $yanked;
90 | }
91 |
92 | /**
93 | * @return string
94 | */
95 | public function getLink()
96 | {
97 | return $this->link;
98 | }
99 |
100 | /**
101 | * @param string $link
102 | */
103 | public function setLink($link)
104 | {
105 | $this->link = $link;
106 | }
107 |
108 | /**
109 | * Adds a change to the release.
110 | *
111 | * @param string $type
112 | * @param string $message
113 | */
114 | public function addChange($type, $message)
115 | {
116 | $this->changes[$type][] = $message;
117 | }
118 |
119 | /**
120 | * Sets all the changes for the given type
121 | *
122 | * @param string $type
123 | * @param string[] $changes
124 | */
125 | public function setChanges($type, $changes)
126 | {
127 | $this->changes[$type] = $changes;
128 | }
129 |
130 | /**
131 | * Returns all changes for the given type or null if there are no changes.
132 | *
133 | * @param string $type
134 | *
135 | * @return string[]|null
136 | */
137 | public function getChanges($type)
138 | {
139 | if ( ! isset($this->changes[$type]))
140 | {
141 | return null;
142 | }
143 |
144 | return $this->changes[$type];
145 | }
146 |
147 | /**
148 | * Returns all changes in the release indexed by type
149 | *
150 | * @return array
151 | */
152 | public function getAllChanges()
153 | {
154 | return $this->changes;
155 | }
156 |
157 | /**
158 | * Sets all the changes for the release, should be indexed by change type.
159 | *
160 | * @param string[] $changes
161 | */
162 | public function setAllChanges($changes)
163 | {
164 | $this->changes = $changes;
165 | }
166 |
167 | /**
168 | * @return DateTime
169 | */
170 | public function getDate()
171 | {
172 | return $this->date;
173 | }
174 |
175 | /**
176 | * @param DateTime $date
177 | */
178 | public function setDate(DateTime $date)
179 | {
180 | $this->date = $date;
181 | }
182 |
183 | /**
184 | * @return string
185 | */
186 | public function getLinkName()
187 | {
188 | return $this->linkName;
189 | }
190 |
191 | /**
192 | * @param string $linkName
193 | */
194 | public function setLinkName($linkName)
195 | {
196 | $this->linkName = $linkName;
197 | }
198 |
199 | }
200 |
--------------------------------------------------------------------------------
/tests/unit/Console/ReleaseTest.php:
--------------------------------------------------------------------------------
1 | add(new Release('release'));
27 |
28 | $command = $application->find('release');
29 | $this->commandTester = new CommandTester($command);
30 | }
31 |
32 | public function testMissingRelease()
33 | {
34 | $this->expectException(InvalidArgumentException::class);
35 |
36 | $this->commandTester->execute([
37 | '--config' => __DIR__.'/../../resources/changelog.config.php',
38 | ]);
39 | }
40 |
41 | public function testNoUnreleased()
42 | {
43 | $this->expectException(ReleaseNotFoundException::class);
44 |
45 | $this->commandTester->execute([
46 | 'release' => 'foobar',
47 | '--config' => __DIR__.'/../../resources/changelog.config_missing_unlreleased.php',
48 | ]);
49 | }
50 |
51 | public function testExistingRelease()
52 | {
53 | $this->expectException(ReleaseExistsException::class);
54 |
55 | $this->commandTester->execute([
56 | 'release' => '0.0.6',
57 | '--config' => __DIR__.'/../../resources/changelog.config.php',
58 | ]);
59 | }
60 |
61 | public function testRelease()
62 | {
63 | $outputPath = __DIR__ . '/../../_output/changelog.json';
64 | @unlink($outputPath);
65 |
66 | $this->commandTester->execute([
67 | 'release' => '1.0.0',
68 | '--config' => __DIR__.'/../../resources/changelog.config.php',
69 | ]);
70 |
71 | $this->assertFileExists($outputPath);
72 | $jsonContent = json_decode(file_get_contents($outputPath), true);
73 |
74 | $this->assertEquals('1.0.0', $jsonContent['releases']['1.0.0']['name']);
75 | $this->assertEquals(null, $jsonContent['releases']['1.0.0']['link']);
76 | $this->assertEquals(null, $jsonContent['releases']['1.0.0']['linkName']);
77 | }
78 |
79 | public function testReleaseWithLink()
80 | {
81 | $outputPath = __DIR__ . '/../../_output/changelog.json';
82 | @unlink($outputPath);
83 |
84 | $this->commandTester->execute([
85 | 'release' => '1.0.0',
86 | '--link' => 'http://foobar.com/release/1.0.0',
87 | '--config' => __DIR__.'/../../resources/changelog.config.php',
88 | ]);
89 |
90 | $this->assertFileExists($outputPath);
91 | $jsonContent = json_decode(file_get_contents($outputPath), true);
92 |
93 | $this->assertEquals('1.0.0', $jsonContent['releases']['1.0.0']['name']);
94 | $this->assertEquals('http://foobar.com/release/1.0.0', $jsonContent['releases']['1.0.0']['link']);
95 | $this->assertEquals('1.0.0', $jsonContent['releases']['1.0.0']['linkName']);
96 | }
97 |
98 | public function testReleaseWithName()
99 | {
100 | $outputPath = __DIR__ . '/../../_output/changelog.json';
101 | @unlink($outputPath);
102 |
103 | $this->commandTester->execute([
104 | 'release' => '1.0.0',
105 | '--link' => 'http://foobar.com/release/1.0.0',
106 | '--linkName' => 'hello',
107 | '--config' => __DIR__.'/../../resources/changelog.config.php',
108 | ]);
109 |
110 | $this->assertFileExists($outputPath);
111 | $jsonContent = json_decode(file_get_contents($outputPath), true);
112 |
113 | $this->assertEquals('1.0.0', $jsonContent['releases']['1.0.0']['name']);
114 | $this->assertEquals('http://foobar.com/release/1.0.0', $jsonContent['releases']['1.0.0']['link']);
115 | $this->assertEquals('hello', $jsonContent['releases']['1.0.0']['linkName']);
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | ## [Unreleased]
4 | ### Changed
5 | - Changed my mind and bumped min PHP version to 8.2 [#28](https://github.com/emlynwest/changelog/issues/28)
6 | - Converted CI to use GitHub actions [#29](https://github.com/emlynwest/changelog/issues/29)
7 | - Raised minimum php version to 8.1 + bare minimum code updates [#28](https://github.com/emlynwest/changelog/issues/28)
8 | - Updated composer packages to run with 8.1+ versions of packages [#28](https://github.com/emlynwest/changelog/issues/28)
9 | - Updated composer packages and fixed tests to run on 8.1 [#28](https://github.com/emlynwest/changelog/issues/28)
10 |
11 | ## [1.3.0]
12 | ### Added
13 | - Introduce command line merge command [#25](https://github.com/emlynwest/changelog/issues/25)
14 | - Build targets for PHP 7.1 and 7.2
15 |
16 | ### Removed
17 | - Build target for HHVM
18 |
19 | ## [1.2.0] 2016-04-23
20 | ### Added
21 | - Create release command line utility [#6](https://github.com/emlynwest/changelog/issues/6).
22 | - Create convert command line utility [#6](https://github.com/emlynwest/changelog/issues/6).
23 | - Create add command line utility [#6](https://github.com/emlynwest/changelog/issues/6).
24 | - Task to create .phar distributable.
25 |
26 | ### Fixed
27 | - Links are no longer parsed as a description.
28 | - Links are now parsed correctly.
29 | - No longer require `dev-master` for the `naneau/semver` package [#21](https://github.com/emlynwest/changelog/issues/21).
30 |
31 | ## [1.1.0]
32 | ### Added
33 | - Flysystem IO adaptor [#3](https://github.com/emlynwest/changelog/issues/3).
34 | - GitHub release reading as part of [#17](https://github.com/emlynwest/changelog/issues/17).
35 |
36 | ### Fixed
37 | - Fixes `KeepAChangeLog` behaving strangely with extra new lines [#19](https://github.com/emlynwest/changelog/issues/19).
38 | - Changed `IO\String` to `IO\Native`
39 |
40 | ## [1.0.0]
41 | ### Removed
42 | - `IO\File` no longer does an `is_file()` check to allow for remote url fetching [#13](https://github.com/emlynwest/changelog/issues/13).
43 |
44 | ## [0.4.0] - 2015-01-29
45 | ### Added
46 | - Remove a `Release` from a `Log` [#14](https://github.com/emlynwest/changelog/issues/14).
47 | - Added date field to `Release` and date parsing to `KeepAChangeLog` parser [#11](https://github.com/emlynwest/changelog/issues/11).
48 | - Added support to `KeepAChangeLog` to look for yanked releases [#10](https://github.com/emlynwest/changelog/issues/10).
49 | - Added messy link handling to `KeepAChangeLog` [#9](https://github.com/emlynwest/changelog/issues/9).
50 | - Json and XML renderer [#7](https://github.com/emlynwest/changelog/issues/7).
51 |
52 | ### Fixed
53 | - Fixed sorting releases with a release of the title "unreleased" [#15](https://github.com/emlynwest/changelog/issues/15).
54 | - Named links are now parsed and rendered correctly.
55 |
56 | ### Changed
57 | - Splits `Parser` into `Renderer`s and `Parser`s to better separate the functionality.
58 |
59 | ## [0.3.0] - 2015-01-25
60 | ### Added
61 | - `Release`s are now sorted when being added to a `Log` [#12](https://github.com/emlynwest/changelog/issues/12).
62 | - `Log`s can now be merged [#5](https://github.com/emlynwest/changelog/issues/5).
63 | - GitHub IO adaptor implemented [#4](https://github.com/emlynwest/changelog/issues/4).
64 |
65 | ### Changed
66 | - `ChangeLog` now throws exceptions if input/output are not set when calling `parse()` and `write()`.
67 |
68 | ## [0.2.0] - 2015-01-21
69 | ### Added
70 | - Implements array access for `Log` [#1](https://github.com/emlynwest/changelog/issues/1).
71 | - Added name param to Release constructor.
72 | - Added ability to write out logs to file [#2](https://github.com/emlynwest/changelog/issues/2).
73 |
74 | ### Changed
75 | - Renamed "providers" to "IO".
76 |
77 | ## [0.1.0] - 2015-01-18
78 | ### Added
79 | - Initial version.
80 |
81 | [Unreleased]: https://github.com/emlynwest/changelog
82 | [1.3.0]: https://github.com/emlynwest/changelog/releases/tag/1.3.0
83 | [1.2.0]: https://github.com/emlynwest/changelog/releases/tag/1.2.0
84 | [1.1.0]: https://github.com/emlynwest/changelog/releases/tag/1.1.0
85 | [1.0.0]: https://github.com/emlynwest/changelog/releases/tag/1.0.0
86 | [0.4.0]: https://github.com/emlynwest/changelog/releases/tag/0.4.0
87 | [0.3.0]: https://github.com/emlynwest/changelog/releases/tag/0.3.0
88 | [0.2.0]: https://github.com/emlynwest/changelog/releases/tag/0.2.0
89 | [0.1.0]: https://github.com/emlynwest/changelog/releases/tag/0.1.0
90 |
--------------------------------------------------------------------------------
/tests/unit/Parser/KeepAChangeLogTest.php:
--------------------------------------------------------------------------------
1 | parser = new KeepAChangeLog;
26 | }
27 |
28 | public function testBuildLog()
29 | {
30 | $desc1 = 'This is my description.';
31 | $desc2 = 'It has multiple lines.';
32 | $content = [
33 | '# Change log',
34 | $desc1,
35 | $desc2,
36 | ];
37 |
38 | $log = $this->parser->parse($content);
39 |
40 | $this->assertInstanceOf(
41 | 'ChangeLog\Log',
42 | $log
43 | );
44 |
45 | $this->assertEquals(
46 | 'Change log',
47 | $log->getTitle()
48 | );
49 |
50 | $this->assertEquals(
51 | $desc1."\n".$desc2,
52 | $log->getDescription()
53 | );
54 | }
55 |
56 | public function testBuildRelease()
57 | {
58 | $content = [
59 | '## 1.0.0',
60 | '### Fixes',
61 | ' - 1',
62 | '- 2',
63 | '-3',
64 | '',
65 | '### Added',
66 | '- a',
67 | ];
68 |
69 | $release = $this->parser->parseRelease($content);
70 |
71 | $this->assertInstanceOf(
72 | 'ChangeLog\Release',
73 | $release
74 | );
75 |
76 | $this->assertEquals(
77 | '1.0.0',
78 | $release->getName()
79 | );
80 |
81 | $changes = $release->getAllChanges();
82 |
83 | $this->assertArrayHasKey(
84 | 'Fixes',
85 | $changes
86 | );
87 |
88 | $this->assertArrayHasKey(
89 | 'Added',
90 | $changes
91 | );
92 |
93 | $this->assertEquals(
94 | ['1', '2', '3'],
95 | $changes['Fixes']
96 | );
97 |
98 | $this->assertEquals(
99 | ['a'],
100 | $changes['Added']
101 | );
102 | }
103 |
104 | public function testFullParse()
105 | {
106 | $content = [
107 | '# Change log',
108 | '',
109 | '## 1.0.0',
110 | '### Fixes',
111 | '- Issue 1',
112 | '- Issue 2',
113 | '',
114 | '## 0.4.0',
115 | '### Adds',
116 | '- Awesome new feature',
117 | ];
118 |
119 | $log = $this->parser->parse($content);
120 | $this->assertEquals(
121 | 'Change log',
122 | $log->getTitle()
123 | );
124 |
125 | $this->assertTrue(
126 | $log->hasRelease('1.0.0')
127 | );
128 | $this->assertTrue(
129 | $log->hasRelease('0.4.0')
130 | );
131 | }
132 |
133 | public function testDate()
134 | {
135 | $releaseName = '## 1.0.0 - 2015-01-25';
136 | $content = [$releaseName];
137 |
138 | $release = $this->parser->parseRelease($content);
139 |
140 | $this->assertEquals(
141 | '2015-01-25',
142 | $release->getDate()->format('Y-m-d')
143 | );
144 | }
145 |
146 | public function testYanked()
147 | {
148 | $releaseName = '## 1.0.0 - 2015-01-25 [YANKED]';
149 | $content = [$releaseName];
150 |
151 | $release = $this->parser->parseRelease($content);
152 |
153 | $this->assertTrue(
154 | $release->isYanked()
155 | );
156 |
157 | $this->assertEquals(
158 | '2015-01-25',
159 | $release->getDate()->format('Y-m-d')
160 | );
161 |
162 | $this->assertEquals(
163 | '1.0.0',
164 | $release->getName()
165 | );
166 |
167 | $releaseName = '## 1.0.0 - 2015-01-25 [yanked]';
168 | $content = [$releaseName];
169 |
170 | $release = $this->parser->parseRelease($content);
171 |
172 | $this->assertTrue(
173 | $release->isYanked()
174 | );
175 | }
176 |
177 | public function testParseLinks()
178 | {
179 | $content = [
180 | '# Change log',
181 | '',
182 | '## [1.1.0][a]',
183 | '',
184 | '## [1.0.0]',
185 | '',
186 | '[a]: http://google.com',
187 | '[1.0.0]: http://fuelphp.com',
188 | ];
189 |
190 | $log = $this->parser->parse($content);
191 |
192 | $this->assertEquals(
193 | 'http://google.com',
194 | $log->getRelease('1.1.0')->getLink()
195 | );
196 |
197 | $this->assertEquals(
198 | 'a',
199 | $log->getRelease('1.1.0')->getLinkName()
200 | );
201 |
202 | $this->assertEquals(
203 | 'http://fuelphp.com',
204 | $log->getRelease('1.0.0')->getLink()
205 | );
206 |
207 | $this->assertEmpty($log->getDescription());
208 | }
209 |
210 | }
211 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ChangeLog
2 |
3 | [](https://github.com/emlynwest/changelog/actions)
4 | [](https://scrutinizer-ci.com/g/emlynwest/changelog/)
5 | [](https://scrutinizer-ci.com/g/emlynwest/changelog/)
6 | [](https://packagist.org/packages/emlynwest/changelog)
7 |
8 | Quickly and easily modify change logs from a variety of sources.
9 |
10 | Currently the package only supports the [KeepAChangeLog] format of change logs.
11 |
12 | It is possible to read and write logs from/to:
13 |
14 | - File
15 | - Url (no support for output)
16 | - Native string
17 | - [Flysystem][flysystem]
18 | - GitHub repo via GitHub API (currently not for output as I've yet to find a sensible way to do this)
19 |
20 | Logs can be formatted into the [KeepAChangeLog] format, xml and json through the use of various render classes.
21 |
22 | ## Quick Examples
23 |
24 | ### Creating a log
25 |
26 | ```php
27 | setTitle('My Project Change Log');
32 | $log->setDescription('This is my project\'s change log. Any crazy stuff that happens will appear here.');
33 |
34 | // Create and add a new release.
35 | $release1 = new \ChangeLog\Release('1.0.0');
36 | $release1->addChange('Added', 'Awesome feature needed for release');
37 | $log->addRelease($release1);
38 |
39 | $release2 = new \ChangeLog\Release('0.3.0');
40 | $release2->addChange('Added', 'Finally added a change log');
41 | $release2->setChanges('Fixed', [
42 | 'Bug 1',
43 | 'Bug 2',
44 | 'Bug 3',
45 | ]);
46 | $log->addRelease($release2);
47 | ```
48 |
49 | **Note** releases are sorted in accordance to [Semantic Versioning](http://semver.org) automatically with the latest release at the top.
50 | It is expected that all release names follow this and the only exception to this is `unreleased` which will always be at
51 | the top of the release list.
52 |
53 | ### Parsing a log
54 |
55 | ```php
56 | 'path/to/changelog.md'
60 | ]);
61 |
62 | $parser = new \ChangeLog\Parser\KeepAChangeLog();
63 |
64 | $cl = new \ChangeLog\ChangeLog;
65 | $cl->setParser($parser);
66 | $cl->setInput($input);
67 |
68 | $log = $cl->parse();
69 |
70 | // Instance of ChangeLog\Log
71 | var_dump($log);
72 | ```
73 |
74 | ### Writing a log
75 |
76 | ```php
77 | 'path/to/changelog.md'
81 | ]);
82 |
83 | $renderer = new \ChangeLog\Renderer\KeepAChangeLog();
84 |
85 | $cl = new \ChangeLog\ChangeLog;
86 | $cl->setRenderer($renderer);
87 | $cl->setOutput($output);
88 |
89 | $log = new Log;
90 | // Build up the log file information here
91 |
92 | $cl->write($log);
93 | ```
94 |
95 | ### Merging Logs
96 |
97 | Logs can be merged together to create a single change log. This includes releases and their changes.
98 |
99 | ```php
100 | $log1 = new Log;
101 | // Add some releases or something
102 |
103 | $log2 = new Log;
104 | // Add some releases to this too
105 |
106 | $log1->mergeLog($log2);
107 | // $log1 now contains all releases and changes from $log2
108 | ```
109 |
110 | Depending on your use case it might be useful to create an empty log first and merge other logs into that.
111 |
112 | ## Command line utility
113 |
114 | Common actions can be performed from the command line using the `./vendor/bin/changelog` command or via the `changelog.phar`
115 | at [the releases page][releases].
116 |
117 | The command line utility expects a config file called `changelog.config.php` to exist in the working directory, or it
118 | can be specified with the global `--config` option. An example config file can be found in `changelog.config.example.php`
119 |
120 | All commands use the same four options to read, parse, render and finally output a change log. These all default to the
121 | "default" entry in their respective config arrays.
122 |
123 | ```
124 | --input[=INPUT] Config to use for input processor [default: "default"]
125 | --parser[=PARSER] Config to use for parser processor [default: "default"]
126 | --renderer[=RENDERER] Config to use for renderer processor [default: "default"]
127 | --output[=OUTPUT] Config to use for output processor [default: "default"]
128 | ```
129 |
130 | Eg: `changelog.phar --renderer=json` would use the `json` entry from the `renderer` entry of the config file to construct
131 | a `ChangeLog\Renderer\Json` object to use to create the end content.
132 |
133 | The current commands are:
134 | - Add: Adds a change to a release
135 | - Convert: Converts a release between formats. Simply runs the read, parse, render, write sequence.
136 | - Release: Converts the "unreleased" release into a real release. Can take names such as `major`, `minor`, `patch` to
137 | automatically create release numbers.
138 | - Merge: Merge multiple changelog into one.
139 |
140 | Check `changelog.phar help` for more information.
141 |
142 | ## Development
143 |
144 | Current plans for development can be found in the repo's [issue tracker][issues].
145 | If you wish to request extra functionality then open an issue or pull request.
146 |
147 | Feel free to report any issues on the [issue tracker][issues].
148 |
149 | ## Author
150 |
151 | ### Emlyn West
152 |
153 | - [GitHub]
154 | - Email: emlyn.west@gmail.com
155 |
156 | [KeepAChangeLog]: http://keepachangelog.com/
157 | [flysystem]: http://flysystem.thephpleague.com/
158 | [issues]: https://github.com/emlynwest/changelog/issues
159 | [GitHub]: https://github.com/emlynwest
160 | [releases]: https://github.com/emlynwest/changelog/releases
161 |
--------------------------------------------------------------------------------
/tests/unit/LogTest.php:
--------------------------------------------------------------------------------
1 | log = new Log;
26 | }
27 |
28 | public function testGetSetDescription()
29 | {
30 | $description = 'A log file that shows changes to the project.';
31 | $this->log->setDescription($description);
32 | $this->assertEquals(
33 | $description,
34 | $this->log->getDescription()
35 | );
36 | }
37 |
38 | public function testGetSetTitle()
39 | {
40 | $title = 'My Change Log';
41 | $this->log->setTitle($title);
42 | $this->assertEquals(
43 | $title,
44 | $this->log->getTitle()
45 | );
46 | }
47 |
48 | public function testGetSetRelease()
49 | {
50 | $name = '1.0.0';
51 | $release = new Release;
52 | $release->setName($name);
53 |
54 | $this->assertFalse(
55 | $this->log->hasRelease($name)
56 | );
57 | $this->assertNull(
58 | $this->log->getRelease($name)
59 | );
60 |
61 | $this->log->addRelease($release);
62 | $this->assertTrue(
63 | $this->log->hasRelease($name)
64 | );
65 | $this->assertEquals(
66 | $release,
67 | $this->log->getRelease($name)
68 | );
69 | $this->assertEquals(
70 | [$name => $release],
71 | $this->log->getReleases()
72 | );
73 | }
74 |
75 | public function testArrayAccess()
76 | {
77 | $release1 = new Release;
78 | $release1->setName('0.1.0');
79 | $release2 = new Release;
80 | $release2->setName('0.2.0');
81 |
82 | $log = new Log;
83 | $log->addRelease($release1);
84 | $log->addRelease($release2);
85 |
86 | $this->assertEquals(
87 | 2,
88 | count($log)
89 | );
90 |
91 | $releases = [];
92 | /** @var Release $release */
93 | foreach ($log as $release)
94 | {
95 | $releases[] = $release->getName();
96 | }
97 |
98 | $this->assertEquals(
99 | ['0.2.0', '0.1.0'],
100 | $releases
101 | );
102 | }
103 |
104 | public function testRevisionsAreStoredInOrder()
105 | {
106 | $releases = ['2.0.0', '2.1.0', '1.0.0-rc.1', '3.0.0-beta.1'];
107 | $expected = ['3.0.0-beta.1', '2.1.0', '2.0.0', '1.0.0-rc.1'];
108 |
109 | foreach ($releases as $releaseName)
110 | {
111 | $this->log->addRelease(new Release($releaseName));
112 | }
113 |
114 | $this->assertEquals(
115 | $expected,
116 | array_keys($this->log->getReleases())
117 | );
118 | }
119 |
120 | public function testMerge()
121 | {
122 | $thisRelease1 = new Release('1.0.0');
123 | $thisRelease1->setAllChanges([
124 | 'Added' => ['Added 1', 'Added 2'],
125 | 'Changed' => ['Changed 1'],
126 | ]);
127 | $this->log->addRelease($thisRelease1);
128 |
129 | $thisRelease1 = new Release('2.0.0');
130 | $this->log->addRelease($thisRelease1);
131 |
132 | $otherLog = new Log;
133 |
134 | $thisRelease3 = new Release('1.0.0');
135 | $thisRelease3->setAllChanges([
136 | 'Added' => ['Added 3', 'Added 4'],
137 | 'Removed' => ['Removed 1'],
138 | ]);
139 | $otherLog->addRelease($thisRelease3);
140 |
141 | $thisRelease4 = new Release('3.0.0');
142 | $otherLog->addRelease($thisRelease4);
143 |
144 | $this->log->mergeLog($otherLog);
145 |
146 | $this->assertTrue($this->log->hasRelease('1.0.0'));
147 | $this->assertTrue($this->log->hasRelease('2.0.0'));
148 | $this->assertTrue($this->log->hasRelease('3.0.0'));
149 |
150 | $mergedRelease = $this->log->getRelease('1.0.0');
151 | $this->assertEquals(
152 | [
153 | 'Added' => ['Added 1', 'Added 2', 'Added 3', 'Added 4'],
154 | 'Changed' => ['Changed 1'],
155 | 'Removed' => ['Removed 1'],
156 | ],
157 | $mergedRelease->getAllChanges()
158 | );
159 | }
160 |
161 | public function testRemoveRelease()
162 | {
163 | $name = '1.0.0';
164 | $release = new Release($name);
165 | $this->log->addRelease($release);
166 |
167 | $this->assertTrue(
168 | $this->log->hasRelease($name)
169 | );
170 |
171 | $this->log->removeRelease($name);
172 |
173 | $this->assertFalse(
174 | $this->log->hasRelease($name)
175 | );
176 | }
177 |
178 | /**
179 | * @link https://github.com/emlynwest/changelog/issues/15
180 | */
181 | public function testSortWithUnreleased()
182 | {
183 | $release1 = new Release('0.1.0');
184 | $release2 = new Release('Unreleased');
185 |
186 | $this->log->addRelease($release1);
187 | $this->log->addRelease($release2);
188 |
189 | $this->assertEquals(
190 | ['unreleased' => $release2, '0.1.0' => $release1],
191 | $this->log->getReleases()
192 | );
193 | }
194 |
195 | public function testGetLatestRelease()
196 | {
197 | $release1 = new Release('0.1.0');
198 | $release2 = new Release('Unreleased');
199 |
200 | $this->log->addRelease($release1);
201 | $this->log->addRelease($release2);
202 |
203 | $this->assertEquals(
204 | $release1,
205 | $this->log->getLatestRelease()
206 | );
207 | }
208 |
209 | public function testGetNextVersion()
210 | {
211 | $release1 = new Release('0.1.0');
212 |
213 | $this->log->addRelease($release1);
214 |
215 | $this->assertEquals(
216 | '0.1.1',
217 | $this->log->getNextVersion(Log::VERSION_PATCH)
218 | );
219 |
220 | $this->assertEquals(
221 | '0.2.0',
222 | $this->log->getNextVersion(Log::VERSION_MINOR)
223 | );
224 |
225 | $this->assertEquals(
226 | '1.1.0',
227 | $this->log->getNextVersion(Log::VERSION_MAJOR)
228 | );
229 |
230 | $this->assertEquals(
231 | 'foobar',
232 | $this->log->getNextVersion('foobar')
233 | );
234 | }
235 |
236 | }
237 |
--------------------------------------------------------------------------------
/src/Parser/KeepAChangeLog.php:
--------------------------------------------------------------------------------
1 | setTitle($this->trimHashes($line));
44 | }
45 | elseif (preg_match('/^##(?!#).+/', $line) === 1)
46 | {
47 | $release = $this->parseRelease($content);
48 | $log->addRelease($release);
49 | $bodyEnded = true;
50 | }
51 | elseif (preg_match('/^\[(.+)\]: (.+)/', $line, $matches))
52 | {
53 | if (count($matches) >= 3)
54 | {
55 | $links[$matches[1]] = $matches[2];
56 | }
57 | $bodyEnded = true;
58 | }
59 | elseif ( ! $bodyEnded)
60 | {
61 | $description[] = $line;
62 | }
63 |
64 | $line = next($content);
65 | }
66 |
67 | $log->setDescription(implode("\n", $description));
68 |
69 | // Assign the releases their real links
70 | $this->assignLinks($log, $links);
71 |
72 | return $log;
73 | }
74 |
75 | /**
76 | * Trims off whitespace and excess hashes from the start of a string.
77 | *
78 | * @param string $line
79 | *
80 | * @return string
81 | */
82 | public function trimHashes($line)
83 | {
84 | return ltrim($line, "\t\n\r\0\x0B# ");
85 | }
86 |
87 | /**
88 | * Returns true if $haystack starts with $needle.
89 | *
90 | * @param $haystack
91 | * @param $needle
92 | *
93 | * @return bool
94 | */
95 | public function startsWith($haystack, $needle)
96 | {
97 | return (substr($haystack, 0, strlen($needle)) === $needle);
98 | }
99 |
100 | /**
101 | * Builds a release.
102 | *
103 | * @param string[] $content
104 | *
105 | * @return Release
106 | */
107 | public function parseRelease(&$content)
108 | {
109 | $release = new Release;
110 | $types = [];
111 | $lastType = '';
112 | $nameSet = false;
113 |
114 | $line = current($content);
115 | while ($line !== false)
116 | {
117 | $line = ltrim($line);
118 |
119 | if ($this->startsWith($line, '###'))
120 | {
121 | $type = $this->trimHashes($line);
122 | $types[$type] = [];
123 | $lastType = $type;
124 | }
125 | elseif ($nameSet &&
126 | $this->startsWith($line, '##') ||
127 | $this->startsWith($line, '[')
128 | )
129 | {
130 | prev($content);
131 | break;
132 | }
133 | elseif ($this->startsWith($line, '##'))
134 | {
135 | $this->handleName($release, $line);
136 | $nameSet = true;
137 | }
138 | else
139 | {
140 | $change = ltrim($line, "\t\n\r\0\x0B -");
141 |
142 | if ($change !== '')
143 | {
144 | $types[$lastType][] = $change;
145 | }
146 | }
147 |
148 | $line = next($content);
149 | }
150 |
151 | $release->setAllChanges($types);
152 | return $release;
153 | }
154 |
155 | /**
156 | * Pulls out the needed information from a Release title and assigns that to the
157 | * given release.
158 | *
159 | * @param Release $release
160 | * @param string $line
161 | */
162 | protected function handleName(Release $release, $line)
163 | {
164 | $this->setName($release, $line);
165 | $this->setDate($release, $line);
166 | $this->setLink($release, $line);
167 | $this->setYanked($release, $line);
168 | }
169 |
170 | /**
171 | * Extracts and sets the name of the link if there is one.
172 | *
173 | * @param Release $release
174 | * @param string $line
175 | */
176 | protected function setLink(Release $release, $line)
177 | {
178 | $matches = [];
179 |
180 | if (preg_match('/^## \[([\w\.-\.]+)\](?:\[(\w+)\])?/', $line, $matches))
181 | {
182 | if (count($matches) >= 3)
183 | {
184 | $release->setLink($matches[2]);
185 | $release->setLinkName($matches[2]);
186 | }
187 | else
188 | {
189 | $release->setLink($matches[1]);
190 | }
191 | }
192 | }
193 |
194 | /**
195 | * Extracts and sets the yanked flag.
196 | *
197 | * @param Release $release
198 | * @param string $line
199 | */
200 | protected function setYanked(Release $release, $line)
201 | {
202 | if (preg_match('/\[YANKED\]$/i', $line))
203 | {
204 | $release->setYanked(true);
205 | }
206 | }
207 |
208 | /**
209 | * Extracts and sets the release Date.
210 | *
211 | * @param Release $release
212 | * @param string $line
213 | */
214 | protected function setDate(Release $release, $line)
215 | {
216 | $matches = [];
217 | if (preg_match('/[0-9]{4,}-[0-9]{2,}-[0-9]{2,}/', $line, $matches))
218 | {
219 | $date = DateTime::createFromFormat('Y-m-d', $matches[0]);
220 | if ($date)
221 | {
222 | $release->setDate($date);
223 | }
224 | }
225 | }
226 |
227 | /**
228 | * Extracts and sets the Release name.
229 | *
230 | * @param Release $release
231 | * @param string $line
232 | */
233 | protected function setName(Release $release, $line)
234 | {
235 | $matches = [];
236 | if (preg_match('/([\w\.-]{1,})/', $line, $matches))
237 | {
238 | $release->setName($matches[0]);
239 | }
240 | }
241 |
242 | /**
243 | * @param $log
244 | * @param $links
245 | *
246 | * @since
247 | */
248 | protected function assignLinks($log, $links)
249 | {
250 | /** @var Release $release */
251 | foreach ($log as $release)
252 | {
253 | $link = null;
254 | $linkName = $release->getLink();
255 | if (isset($links[$linkName]))
256 | {
257 | $link = $links[$linkName];
258 | }
259 | $release->setLink($link);
260 | }
261 | }
262 |
263 | }
264 |
--------------------------------------------------------------------------------
/src/Log.php:
--------------------------------------------------------------------------------
1 | releases;
50 | }
51 |
52 | /**
53 | * Gets the named release.
54 | *
55 | * @param string $name
56 | *
57 | * @return Release|null
58 | */
59 | public function getRelease($name)
60 | {
61 | $key = strtolower($name);
62 | if ( ! $this->hasRelease($key))
63 | {
64 | return null;
65 | }
66 |
67 | return $this->releases[$key];
68 | }
69 |
70 | /**
71 | * Adds a release to the Log.
72 | * Can be used to replace existing releases too.
73 | *
74 | * @param Release $release
75 | */
76 | public function addRelease(Release $release)
77 | {
78 | $name = strtolower($release->getName());
79 | $this->releases[$name] = $release;
80 | $this->sortReleases();
81 | }
82 |
83 | /**
84 | * Removes a release from the Log.
85 | *
86 | * @param string $name
87 | */
88 | public function removeRelease($name)
89 | {
90 | $key = strtolower($name);
91 | unset($this->releases[$key]);
92 | }
93 |
94 | /**
95 | * Checks if the Log has the named Release.
96 | *
97 | * @param string $name
98 | *
99 | * @return bool
100 | */
101 | public function hasRelease($name)
102 | {
103 | $key = strtolower($name);
104 | return isset($this->releases[$key]);
105 | }
106 |
107 | /**
108 | * @return string
109 | */
110 | public function getDescription()
111 | {
112 | return $this->description;
113 | }
114 |
115 | /**
116 | * @param string $description
117 | */
118 | public function setDescription($description)
119 | {
120 | $this->description = $description;
121 | }
122 |
123 | /**
124 | * @return string
125 | */
126 | public function getTitle()
127 | {
128 | return $this->title;
129 | }
130 |
131 | /**
132 | * @param string $title
133 | */
134 | public function setTitle($title)
135 | {
136 | $this->title = $title;
137 | }
138 |
139 | /**
140 | * {@inheritdoc}
141 | */
142 | public function getIterator()
143 | {
144 | return new ArrayIterator($this->releases);
145 | }
146 |
147 | /**
148 | * {@inheritdoc}
149 | */
150 | public function count()
151 | {
152 | return count($this->releases);
153 | }
154 |
155 | /**
156 | * Sorts the releases inside this log in accordance with semantic versioning, latest release first.
157 | */
158 | public function sortReleases()
159 | {
160 | // If there is an unreleased release pull that out and sort the rest
161 | $unreleased = null;
162 | if (isset($this->releases['unreleased']))
163 | {
164 | $unreleased = $this->releases['unreleased'];
165 | unset($this->releases['unreleased']);
166 | }
167 |
168 | $order = Sort::sort(array_keys($this->releases));
169 | $order = array_reverse($order);
170 |
171 | $newOrder = [];
172 | /** @var Version $version */
173 | foreach ($order as $version)
174 | {
175 | $index = $version->__toString();
176 | $newOrder[$index] = $this->releases[$index];
177 | }
178 |
179 | if ($unreleased !== null)
180 | {
181 | $newOrder = ['unreleased' => $unreleased] + $newOrder;
182 | }
183 |
184 | $this->releases = $newOrder;
185 | }
186 |
187 | /**
188 | * Merges another Log's releases with this log.
189 | *
190 | * @param Log $log
191 | */
192 | public function mergeLog(Log $log)
193 | {
194 | /** @var Release $release */
195 | foreach ($log as $release)
196 | {
197 | $name = $release->getName();
198 | if ($this->hasRelease($name))
199 | {
200 | // if it does exist then merge the changes
201 | $this->mergeRelease($log, $name);
202 | }
203 | else
204 | {
205 | // If the release does not exist add it
206 | $this->addRelease($release);
207 | }
208 | }
209 | }
210 |
211 | /**
212 | * Combines all changes of the name of the given release from the given log into this log.
213 | *
214 | * @param Log $log
215 | * @param string $name
216 | */
217 | protected function mergeRelease(Log $log, $name)
218 | {
219 | $myRelease = $this->getRelease($name);
220 | $theirRelease = $log->getRelease($name);
221 |
222 | $changes = $this->mergeChangesArrays(
223 | $theirRelease->getAllChanges(),
224 | $myRelease->getAllChanges()
225 | );
226 | $myRelease->setAllChanges($changes);
227 | }
228 |
229 | /**
230 | * Merges two sets of changes.
231 | *
232 | * @param array $left
233 | * @param array $right
234 | *
235 | * @return array
236 | */
237 | protected function mergeChangesArrays($left, $right)
238 | {
239 | $return = $left;
240 |
241 | foreach ($right as $type => $changes)
242 | {
243 | if (isset($left[$type]))
244 | {
245 | $return[$type] = array_merge($right[$type], $left[$type]);
246 | }
247 | else
248 | {
249 | $return[$type] = $changes;
250 | }
251 | }
252 |
253 | return $return;
254 | }
255 |
256 | /**
257 | * @return Release
258 | */
259 | public function getLatestRelease()
260 | {
261 | $releases = $this->releases;
262 |
263 | $release = array_shift($releases);
264 |
265 | if (count($this->releases) > 1 && strtolower($release->getName()) === 'unreleased')
266 | {
267 | $release = array_shift($releases);
268 | }
269 |
270 | return $release;
271 | }
272 |
273 | public function getNextVersion($type)
274 | {
275 | if (! in_array($type, [static::VERSION_MAJOR, static::VERSION_MINOR, static::VERSION_PATCH]))
276 | {
277 | return $type;
278 | }
279 |
280 | $latestRelease = $this->getLatestRelease();
281 |
282 | $version = $latestRelease->getName() === 'unreleased' ? '0.0.0' : $latestRelease->getName() ;
283 |
284 | $semver = Parser::parse($version);
285 | $patch = $semver->getPatch();
286 | $minor = $semver->getMinor();
287 | $major = $semver->getMajor();
288 |
289 | switch ($type)
290 | {
291 | case Log::VERSION_PATCH:
292 | $patch++;
293 | break;
294 | case Log::VERSION_MINOR:
295 | $minor++;
296 | break;
297 | case Log::VERSION_MAJOR:
298 | $major++;
299 | break;
300 | }
301 |
302 | return "$major.$minor.$patch";
303 | }
304 |
305 | }
306 |
--------------------------------------------------------------------------------
/tests/unit/UnitTester.php:
--------------------------------------------------------------------------------
1 | scenario->runStep(new \Codeception\Step\Action('assertEquals', func_get_args()));
45 | }
46 |
47 |
48 | /**
49 | * [!] Method is generated. Documentation taken from corresponding module.
50 | *
51 | * Checks that two variables are not equal
52 | *
53 | * @param $expected
54 | * @param $actual
55 | * @param string $message
56 | * @see \Codeception\Module\Asserts::assertNotEquals()
57 | */
58 | public function assertNotEquals($expected, $actual, $message = null) {
59 | return $this->scenario->runStep(new \Codeception\Step\Action('assertNotEquals', func_get_args()));
60 | }
61 |
62 |
63 | /**
64 | * [!] Method is generated. Documentation taken from corresponding module.
65 | *
66 | * Checks that expected is greater than actual
67 | *
68 | * @param $expected
69 | * @param $actual
70 | * @param string $message
71 | * @see \Codeception\Module\Asserts::assertGreaterThan()
72 | */
73 | public function assertGreaterThan($expected, $actual, $message = null) {
74 | return $this->scenario->runStep(new \Codeception\Step\Action('assertGreaterThan', func_get_args()));
75 | }
76 |
77 |
78 | /**
79 | * [!] Method is generated. Documentation taken from corresponding module.
80 | *
81 | * @deprecated
82 | * @see \Codeception\Module\Asserts::assertGreaterThen()
83 | */
84 | public function assertGreaterThen($expected, $actual, $message = null) {
85 | return $this->scenario->runStep(new \Codeception\Step\Action('assertGreaterThen', func_get_args()));
86 | }
87 |
88 |
89 | /**
90 | * [!] Method is generated. Documentation taken from corresponding module.
91 | *
92 | * Checks that expected is greater or equal than actual
93 | *
94 | * @param $expected
95 | * @param $actual
96 | * @param string $message
97 | * @see \Codeception\Module\Asserts::assertGreaterThanOrEqual()
98 | */
99 | public function assertGreaterThanOrEqual($expected, $actual, $message = null) {
100 | return $this->scenario->runStep(new \Codeception\Step\Action('assertGreaterThanOrEqual', func_get_args()));
101 | }
102 |
103 |
104 | /**
105 | * [!] Method is generated. Documentation taken from corresponding module.
106 | *
107 | * @deprecated
108 | * @see \Codeception\Module\Asserts::assertGreaterThenOrEqual()
109 | */
110 | public function assertGreaterThenOrEqual($expected, $actual, $message = null) {
111 | return $this->scenario->runStep(new \Codeception\Step\Action('assertGreaterThenOrEqual', func_get_args()));
112 | }
113 |
114 |
115 | /**
116 | * [!] Method is generated. Documentation taken from corresponding module.
117 | *
118 | * Checks that expected is less than actual
119 | *
120 | * @param $expected
121 | * @param $actual
122 | * @param string $message
123 | * @see \Codeception\Module\Asserts::assertLessThan()
124 | */
125 | public function assertLessThan($expected, $actual, $message = null) {
126 | return $this->scenario->runStep(new \Codeception\Step\Action('assertLessThan', func_get_args()));
127 | }
128 |
129 |
130 | /**
131 | * [!] Method is generated. Documentation taken from corresponding module.
132 | *
133 | * Checks that expected is less or equal than actual
134 | *
135 | * @param $expected
136 | * @param $actual
137 | * @param string $message
138 | * @see \Codeception\Module\Asserts::assertLessThanOrEqual()
139 | */
140 | public function assertLessThanOrEqual($expected, $actual, $message = null) {
141 | return $this->scenario->runStep(new \Codeception\Step\Action('assertLessThanOrEqual', func_get_args()));
142 | }
143 |
144 |
145 | /**
146 | * [!] Method is generated. Documentation taken from corresponding module.
147 | *
148 | * Checks that haystack contains needle
149 | *
150 | * @param $needle
151 | * @param $haystack
152 | * @param string $message
153 | * @see \Codeception\Module\Asserts::assertContains()
154 | */
155 | public function assertContains($needle, $haystack, $message = null) {
156 | return $this->scenario->runStep(new \Codeception\Step\Action('assertContains', func_get_args()));
157 | }
158 |
159 |
160 | /**
161 | * [!] Method is generated. Documentation taken from corresponding module.
162 | *
163 | * Checks that haystack doesn't contain needle.
164 | *
165 | * @param $needle
166 | * @param $haystack
167 | * @param string $message
168 | * @see \Codeception\Module\Asserts::assertNotContains()
169 | */
170 | public function assertNotContains($needle, $haystack, $message = null) {
171 | return $this->scenario->runStep(new \Codeception\Step\Action('assertNotContains', func_get_args()));
172 | }
173 |
174 |
175 | /**
176 | * [!] Method is generated. Documentation taken from corresponding module.
177 | *
178 | * Checks that variable is empty.
179 | *
180 | * @param $actual
181 | * @param string $message
182 | * @see \Codeception\Module\Asserts::assertEmpty()
183 | */
184 | public function assertEmpty($actual, $message = null) {
185 | return $this->scenario->runStep(new \Codeception\Step\Action('assertEmpty', func_get_args()));
186 | }
187 |
188 |
189 | /**
190 | * [!] Method is generated. Documentation taken from corresponding module.
191 | *
192 | * Checks that variable is not empty.
193 | *
194 | * @param $actual
195 | * @param string $message
196 | * @see \Codeception\Module\Asserts::assertNotEmpty()
197 | */
198 | public function assertNotEmpty($actual, $message = null) {
199 | return $this->scenario->runStep(new \Codeception\Step\Action('assertNotEmpty', func_get_args()));
200 | }
201 |
202 |
203 | /**
204 | * [!] Method is generated. Documentation taken from corresponding module.
205 | *
206 | * Checks that variable is NULL
207 | *
208 | * @param $actual
209 | * @param string $message
210 | * @see \Codeception\Module\Asserts::assertNull()
211 | */
212 | public function assertNull($actual, $message = null) {
213 | return $this->scenario->runStep(new \Codeception\Step\Action('assertNull', func_get_args()));
214 | }
215 |
216 |
217 | /**
218 | * [!] Method is generated. Documentation taken from corresponding module.
219 | *
220 | * Checks that variable is not NULL
221 | *
222 | * @param $actual
223 | * @param string $message
224 | * @see \Codeception\Module\Asserts::assertNotNull()
225 | */
226 | public function assertNotNull($actual, $message = null) {
227 | return $this->scenario->runStep(new \Codeception\Step\Action('assertNotNull', func_get_args()));
228 | }
229 |
230 |
231 | /**
232 | * [!] Method is generated. Documentation taken from corresponding module.
233 | *
234 | * Checks that condition is positive.
235 | *
236 | * @param $condition
237 | * @param string $message
238 | * @see \Codeception\Module\Asserts::assertTrue()
239 | */
240 | public function assertTrue($condition, $message = null) {
241 | return $this->scenario->runStep(new \Codeception\Step\Action('assertTrue', func_get_args()));
242 | }
243 |
244 |
245 | /**
246 | * [!] Method is generated. Documentation taken from corresponding module.
247 | *
248 | * Checks that condition is negative.
249 | *
250 | * @param $condition
251 | * @param string $message
252 | * @see \Codeception\Module\Asserts::assertFalse()
253 | */
254 | public function assertFalse($condition, $message = null) {
255 | return $this->scenario->runStep(new \Codeception\Step\Action('assertFalse', func_get_args()));
256 | }
257 |
258 |
259 | /**
260 | * [!] Method is generated. Documentation taken from corresponding module.
261 | *
262 | * Fails the test with message.
263 | *
264 | * @param $message
265 | * @see \Codeception\Module\Asserts::fail()
266 | */
267 | public function fail($message) {
268 | return $this->scenario->runStep(new \Codeception\Step\Action('fail', func_get_args()));
269 | }
270 |
271 |
272 | /**
273 | * [!] Method is generated. Documentation taken from corresponding module.
274 | *
275 | * Enters a directory In local filesystem.
276 | * Project root directory is used by default
277 | *
278 | * @param $path
279 | * @see \Codeception\Module\Filesystem::amInPath()
280 | */
281 | public function amInPath($path) {
282 | return $this->scenario->runStep(new \Codeception\Step\Condition('amInPath', func_get_args()));
283 | }
284 |
285 |
286 | /**
287 | * [!] Method is generated. Documentation taken from corresponding module.
288 | *
289 | * Opens a file and stores it's content.
290 | *
291 | * Usage:
292 | *
293 | * ``` php
294 | * openFile('composer.json');
296 | * $I->seeInThisFile('codeception/codeception');
297 | * ?>
298 | * ```
299 | *
300 | * @param $filename
301 | * @see \Codeception\Module\Filesystem::openFile()
302 | */
303 | public function openFile($filename) {
304 | return $this->scenario->runStep(new \Codeception\Step\Action('openFile', func_get_args()));
305 | }
306 |
307 |
308 | /**
309 | * [!] Method is generated. Documentation taken from corresponding module.
310 | *
311 | * Deletes a file
312 | *
313 | * ``` php
314 | * deleteFile('composer.lock');
316 | * ?>
317 | * ```
318 | *
319 | * @param $filename
320 | * @see \Codeception\Module\Filesystem::deleteFile()
321 | */
322 | public function deleteFile($filename) {
323 | return $this->scenario->runStep(new \Codeception\Step\Action('deleteFile', func_get_args()));
324 | }
325 |
326 |
327 | /**
328 | * [!] Method is generated. Documentation taken from corresponding module.
329 | *
330 | * Deletes directory with all subdirectories
331 | *
332 | * ``` php
333 | * deleteDir('vendor');
335 | * ?>
336 | * ```
337 | *
338 | * @param $dirname
339 | * @see \Codeception\Module\Filesystem::deleteDir()
340 | */
341 | public function deleteDir($dirname) {
342 | return $this->scenario->runStep(new \Codeception\Step\Action('deleteDir', func_get_args()));
343 | }
344 |
345 |
346 | /**
347 | * [!] Method is generated. Documentation taken from corresponding module.
348 | *
349 | * Copies directory with all contents
350 | *
351 | * ``` php
352 | * copyDir('vendor','old_vendor');
354 | * ?>
355 | * ```
356 | *
357 | * @param $src
358 | * @param $dst
359 | * @see \Codeception\Module\Filesystem::copyDir()
360 | */
361 | public function copyDir($src, $dst) {
362 | return $this->scenario->runStep(new \Codeception\Step\Action('copyDir', func_get_args()));
363 | }
364 |
365 |
366 | /**
367 | * [!] Method is generated. Documentation taken from corresponding module.
368 | *
369 | * Checks If opened file has `text` in it.
370 | *
371 | * Usage:
372 | *
373 | * ``` php
374 | * openFile('composer.json');
376 | * $I->seeInThisFile('codeception/codeception');
377 | * ?>
378 | * ```
379 | *
380 | * @param $text
381 | * Conditional Assertion: Test won't be stopped on fail
382 | * @see \Codeception\Module\Filesystem::seeInThisFile()
383 | */
384 | public function canSeeInThisFile($text) {
385 | return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeInThisFile', func_get_args()));
386 | }
387 | /**
388 | * [!] Method is generated. Documentation taken from corresponding module.
389 | *
390 | * Checks If opened file has `text` in it.
391 | *
392 | * Usage:
393 | *
394 | * ``` php
395 | * openFile('composer.json');
397 | * $I->seeInThisFile('codeception/codeception');
398 | * ?>
399 | * ```
400 | *
401 | * @param $text
402 | * @see \Codeception\Module\Filesystem::seeInThisFile()
403 | */
404 | public function seeInThisFile($text) {
405 | return $this->scenario->runStep(new \Codeception\Step\Assertion('seeInThisFile', func_get_args()));
406 | }
407 |
408 |
409 | /**
410 | * [!] Method is generated. Documentation taken from corresponding module.
411 | *
412 | * Checks the strict matching of file contents.
413 | * Unlike `seeInThisFile` will fail if file has something more than expected lines.
414 | * Better to use with HEREDOC strings.
415 | * Matching is done after removing "\r" chars from file content.
416 | *
417 | * ``` php
418 | * openFile('process.pid');
420 | * $I->seeFileContentsEqual('3192');
421 | * ?>
422 | * ```
423 | *
424 | * @param $text
425 | * Conditional Assertion: Test won't be stopped on fail
426 | * @see \Codeception\Module\Filesystem::seeFileContentsEqual()
427 | */
428 | public function canSeeFileContentsEqual($text) {
429 | return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeFileContentsEqual', func_get_args()));
430 | }
431 | /**
432 | * [!] Method is generated. Documentation taken from corresponding module.
433 | *
434 | * Checks the strict matching of file contents.
435 | * Unlike `seeInThisFile` will fail if file has something more than expected lines.
436 | * Better to use with HEREDOC strings.
437 | * Matching is done after removing "\r" chars from file content.
438 | *
439 | * ``` php
440 | * openFile('process.pid');
442 | * $I->seeFileContentsEqual('3192');
443 | * ?>
444 | * ```
445 | *
446 | * @param $text
447 | * @see \Codeception\Module\Filesystem::seeFileContentsEqual()
448 | */
449 | public function seeFileContentsEqual($text) {
450 | return $this->scenario->runStep(new \Codeception\Step\Assertion('seeFileContentsEqual', func_get_args()));
451 | }
452 |
453 |
454 | /**
455 | * [!] Method is generated. Documentation taken from corresponding module.
456 | *
457 | * Checks If opened file doesn't contain `text` in it
458 | *
459 | * ``` php
460 | * openFile('composer.json');
462 | * $I->dontSeeInThisFile('codeception/codeception');
463 | * ?>
464 | * ```
465 | *
466 | * @param $text
467 | * Conditional Assertion: Test won't be stopped on fail
468 | * @see \Codeception\Module\Filesystem::dontSeeInThisFile()
469 | */
470 | public function cantSeeInThisFile($text) {
471 | return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeInThisFile', func_get_args()));
472 | }
473 | /**
474 | * [!] Method is generated. Documentation taken from corresponding module.
475 | *
476 | * Checks If opened file doesn't contain `text` in it
477 | *
478 | * ``` php
479 | * openFile('composer.json');
481 | * $I->dontSeeInThisFile('codeception/codeception');
482 | * ?>
483 | * ```
484 | *
485 | * @param $text
486 | * @see \Codeception\Module\Filesystem::dontSeeInThisFile()
487 | */
488 | public function dontSeeInThisFile($text) {
489 | return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeInThisFile', func_get_args()));
490 | }
491 |
492 |
493 | /**
494 | * [!] Method is generated. Documentation taken from corresponding module.
495 | *
496 | * Deletes a file
497 | * @see \Codeception\Module\Filesystem::deleteThisFile()
498 | */
499 | public function deleteThisFile() {
500 | return $this->scenario->runStep(new \Codeception\Step\Action('deleteThisFile', func_get_args()));
501 | }
502 |
503 |
504 | /**
505 | * [!] Method is generated. Documentation taken from corresponding module.
506 | *
507 | * Checks if file exists in path.
508 | * Opens a file when it's exists
509 | *
510 | * ``` php
511 | * seeFileFound('UserModel.php','app/models');
513 | * ?>
514 | * ```
515 | *
516 | * @param $filename
517 | * @param string $path
518 | * Conditional Assertion: Test won't be stopped on fail
519 | * @see \Codeception\Module\Filesystem::seeFileFound()
520 | */
521 | public function canSeeFileFound($filename, $path = null) {
522 | return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeFileFound', func_get_args()));
523 | }
524 | /**
525 | * [!] Method is generated. Documentation taken from corresponding module.
526 | *
527 | * Checks if file exists in path.
528 | * Opens a file when it's exists
529 | *
530 | * ``` php
531 | * seeFileFound('UserModel.php','app/models');
533 | * ?>
534 | * ```
535 | *
536 | * @param $filename
537 | * @param string $path
538 | * @see \Codeception\Module\Filesystem::seeFileFound()
539 | */
540 | public function seeFileFound($filename, $path = null) {
541 | return $this->scenario->runStep(new \Codeception\Step\Assertion('seeFileFound', func_get_args()));
542 | }
543 |
544 |
545 | /**
546 | * [!] Method is generated. Documentation taken from corresponding module.
547 | *
548 | * Checks if file does not exists in path
549 | *
550 | * @param $filename
551 | * @param string $path
552 | * Conditional Assertion: Test won't be stopped on fail
553 | * @see \Codeception\Module\Filesystem::dontSeeFileFound()
554 | */
555 | public function cantSeeFileFound($filename, $path = null) {
556 | return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeFileFound', func_get_args()));
557 | }
558 | /**
559 | * [!] Method is generated. Documentation taken from corresponding module.
560 | *
561 | * Checks if file does not exists in path
562 | *
563 | * @param $filename
564 | * @param string $path
565 | * @see \Codeception\Module\Filesystem::dontSeeFileFound()
566 | */
567 | public function dontSeeFileFound($filename, $path = null) {
568 | return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeFileFound', func_get_args()));
569 | }
570 |
571 |
572 | /**
573 | * [!] Method is generated. Documentation taken from corresponding module.
574 | *
575 | * Erases directory contents
576 | *
577 | * ``` php
578 | * cleanDir('logs');
580 | * ?>
581 | * ```
582 | *
583 | * @param $dirname
584 | * @see \Codeception\Module\Filesystem::cleanDir()
585 | */
586 | public function cleanDir($dirname) {
587 | return $this->scenario->runStep(new \Codeception\Step\Action('cleanDir', func_get_args()));
588 | }
589 |
590 |
591 | /**
592 | * [!] Method is generated. Documentation taken from corresponding module.
593 | *
594 | * Saves contents to file
595 | *
596 | * @param $filename
597 | * @param $contents
598 | * @see \Codeception\Module\Filesystem::writeToFile()
599 | */
600 | public function writeToFile($filename, $contents) {
601 | return $this->scenario->runStep(new \Codeception\Step\Action('writeToFile', func_get_args()));
602 | }
603 | }
604 |
--------------------------------------------------------------------------------
/tests/_support/_generated/UnitTesterActions.php:
--------------------------------------------------------------------------------
1 | assertEquals(5, $element->getChildrenCount());
27 | * ```
28 | *
29 | * Floating-point example:
30 | * ```php
31 | * assertEquals(0.3, $calculator->add(0.1, 0.2), 'Calculator should add the two numbers correctly.', 0.01);
33 | * ```
34 | *
35 | * @param $expected
36 | * @param $actual
37 | * @param string $message
38 | * @param float $delta
39 | * @see \Codeception\Module\Asserts::assertEquals()
40 | */
41 | public function assertEquals($expected, $actual, $message = null, $delta = null) {
42 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertEquals', func_get_args()));
43 | }
44 |
45 |
46 | /**
47 | * [!] Method is generated. Documentation taken from corresponding module.
48 | *
49 | * Checks that two variables are not equal. If you're comparing floating-point values,
50 | * you can specify the optional "delta" parameter which dictates how great of a precision
51 | * error are you willing to tolerate in order to consider the two values not equal.
52 | *
53 | * Regular example:
54 | * ```php
55 | * assertNotEquals(0, $element->getChildrenCount());
57 | * ```
58 | *
59 | * Floating-point example:
60 | * ```php
61 | * assertNotEquals(0.4, $calculator->add(0.1, 0.2), 'Calculator should add the two numbers correctly.', 0.01);
63 | * ```
64 | *
65 | * @param $expected
66 | * @param $actual
67 | * @param string $message
68 | * @param float $delta
69 | * @see \Codeception\Module\Asserts::assertNotEquals()
70 | */
71 | public function assertNotEquals($expected, $actual, $message = null, $delta = null) {
72 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertNotEquals', func_get_args()));
73 | }
74 |
75 |
76 | /**
77 | * [!] Method is generated. Documentation taken from corresponding module.
78 | *
79 | * Checks that two variables are same
80 | *
81 | * @param $expected
82 | * @param $actual
83 | * @param string $message
84 | * @see \Codeception\Module\Asserts::assertSame()
85 | */
86 | public function assertSame($expected, $actual, $message = null) {
87 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertSame', func_get_args()));
88 | }
89 |
90 |
91 | /**
92 | * [!] Method is generated. Documentation taken from corresponding module.
93 | *
94 | * Checks that two variables are not same
95 | *
96 | * @param $expected
97 | * @param $actual
98 | * @param string $message
99 | * @see \Codeception\Module\Asserts::assertNotSame()
100 | */
101 | public function assertNotSame($expected, $actual, $message = null) {
102 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertNotSame', func_get_args()));
103 | }
104 |
105 |
106 | /**
107 | * [!] Method is generated. Documentation taken from corresponding module.
108 | *
109 | * Checks that actual is greater than expected
110 | *
111 | * @param $expected
112 | * @param $actual
113 | * @param string $message
114 | * @see \Codeception\Module\Asserts::assertGreaterThan()
115 | */
116 | public function assertGreaterThan($expected, $actual, $message = null) {
117 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertGreaterThan', func_get_args()));
118 | }
119 |
120 |
121 | /**
122 | * [!] Method is generated. Documentation taken from corresponding module.
123 | *
124 | * Checks that actual is greater or equal than expected
125 | *
126 | * @param $expected
127 | * @param $actual
128 | * @param string $message
129 | * @see \Codeception\Module\Asserts::assertGreaterThanOrEqual()
130 | */
131 | public function assertGreaterThanOrEqual($expected, $actual, $message = null) {
132 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertGreaterThanOrEqual', func_get_args()));
133 | }
134 |
135 |
136 | /**
137 | * [!] Method is generated. Documentation taken from corresponding module.
138 | *
139 | * Checks that actual is less than expected
140 | *
141 | * @param $expected
142 | * @param $actual
143 | * @param string $message
144 | * @see \Codeception\Module\Asserts::assertLessThan()
145 | */
146 | public function assertLessThan($expected, $actual, $message = null) {
147 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertLessThan', func_get_args()));
148 | }
149 |
150 |
151 | /**
152 | * [!] Method is generated. Documentation taken from corresponding module.
153 | *
154 | * Checks that actual is less or equal than expected
155 | *
156 | * @param $expected
157 | * @param $actual
158 | * @param string $message
159 | * @see \Codeception\Module\Asserts::assertLessThanOrEqual()
160 | */
161 | public function assertLessThanOrEqual($expected, $actual, $message = null) {
162 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertLessThanOrEqual', func_get_args()));
163 | }
164 |
165 |
166 | /**
167 | * [!] Method is generated. Documentation taken from corresponding module.
168 | *
169 | * Checks that haystack contains needle
170 | *
171 | * @param $needle
172 | * @param $haystack
173 | * @param string $message
174 | * @see \Codeception\Module\Asserts::assertContains()
175 | */
176 | public function assertContains($needle, $haystack, $message = null) {
177 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertContains', func_get_args()));
178 | }
179 |
180 |
181 | /**
182 | * [!] Method is generated. Documentation taken from corresponding module.
183 | *
184 | * Checks that haystack doesn't contain needle.
185 | *
186 | * @param $needle
187 | * @param $haystack
188 | * @param string $message
189 | * @see \Codeception\Module\Asserts::assertNotContains()
190 | */
191 | public function assertNotContains($needle, $haystack, $message = null) {
192 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertNotContains', func_get_args()));
193 | }
194 |
195 |
196 | /**
197 | * [!] Method is generated. Documentation taken from corresponding module.
198 | *
199 | * Checks that string match with pattern
200 | *
201 | * @param string $pattern
202 | * @param string $string
203 | * @param string $message
204 | * @see \Codeception\Module\Asserts::assertRegExp()
205 | */
206 | public function assertRegExp($pattern, $string, $message = null) {
207 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertRegExp', func_get_args()));
208 | }
209 |
210 |
211 | /**
212 | * [!] Method is generated. Documentation taken from corresponding module.
213 | *
214 | * Checks that string not match with pattern
215 | *
216 | * @param string $pattern
217 | * @param string $string
218 | * @param string $message
219 | * @see \Codeception\Module\Asserts::assertNotRegExp()
220 | */
221 | public function assertNotRegExp($pattern, $string, $message = null) {
222 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertNotRegExp', func_get_args()));
223 | }
224 |
225 |
226 | /**
227 | * [!] Method is generated. Documentation taken from corresponding module.
228 | *
229 | * Checks that a string starts with the given prefix.
230 | *
231 | * @param string $prefix
232 | * @param string $string
233 | * @param string $message
234 | * @see \Codeception\Module\Asserts::assertStringStartsWith()
235 | */
236 | public function assertStringStartsWith($prefix, $string, $message = null) {
237 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertStringStartsWith', func_get_args()));
238 | }
239 |
240 |
241 | /**
242 | * [!] Method is generated. Documentation taken from corresponding module.
243 | *
244 | * Checks that a string doesn't start with the given prefix.
245 | *
246 | * @param string $prefix
247 | * @param string $string
248 | * @param string $message
249 | * @see \Codeception\Module\Asserts::assertStringStartsNotWith()
250 | */
251 | public function assertStringStartsNotWith($prefix, $string, $message = null) {
252 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertStringStartsNotWith', func_get_args()));
253 | }
254 |
255 |
256 | /**
257 | * [!] Method is generated. Documentation taken from corresponding module.
258 | *
259 | * Checks that variable is empty.
260 | *
261 | * @param $actual
262 | * @param string $message
263 | * @see \Codeception\Module\Asserts::assertEmpty()
264 | */
265 | public function assertEmpty($actual, $message = null) {
266 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertEmpty', func_get_args()));
267 | }
268 |
269 |
270 | /**
271 | * [!] Method is generated. Documentation taken from corresponding module.
272 | *
273 | * Checks that variable is not empty.
274 | *
275 | * @param $actual
276 | * @param string $message
277 | * @see \Codeception\Module\Asserts::assertNotEmpty()
278 | */
279 | public function assertNotEmpty($actual, $message = null) {
280 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertNotEmpty', func_get_args()));
281 | }
282 |
283 |
284 | /**
285 | * [!] Method is generated. Documentation taken from corresponding module.
286 | *
287 | * Checks that variable is NULL
288 | *
289 | * @param $actual
290 | * @param string $message
291 | * @see \Codeception\Module\Asserts::assertNull()
292 | */
293 | public function assertNull($actual, $message = null) {
294 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertNull', func_get_args()));
295 | }
296 |
297 |
298 | /**
299 | * [!] Method is generated. Documentation taken from corresponding module.
300 | *
301 | * Checks that variable is not NULL
302 | *
303 | * @param $actual
304 | * @param string $message
305 | * @see \Codeception\Module\Asserts::assertNotNull()
306 | */
307 | public function assertNotNull($actual, $message = null) {
308 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertNotNull', func_get_args()));
309 | }
310 |
311 |
312 | /**
313 | * [!] Method is generated. Documentation taken from corresponding module.
314 | *
315 | * Checks that condition is positive.
316 | *
317 | * @param $condition
318 | * @param string $message
319 | * @see \Codeception\Module\Asserts::assertTrue()
320 | */
321 | public function assertTrue($condition, $message = null) {
322 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertTrue', func_get_args()));
323 | }
324 |
325 |
326 | /**
327 | * [!] Method is generated. Documentation taken from corresponding module.
328 | *
329 | * Checks that the condition is NOT true (everything but true)
330 | *
331 | * @param $condition
332 | * @param string $message
333 | * @see \Codeception\Module\Asserts::assertNotTrue()
334 | */
335 | public function assertNotTrue($condition, $message = null) {
336 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertNotTrue', func_get_args()));
337 | }
338 |
339 |
340 | /**
341 | * [!] Method is generated. Documentation taken from corresponding module.
342 | *
343 | * Checks that condition is negative.
344 | *
345 | * @param $condition
346 | * @param string $message
347 | * @see \Codeception\Module\Asserts::assertFalse()
348 | */
349 | public function assertFalse($condition, $message = null) {
350 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertFalse', func_get_args()));
351 | }
352 |
353 |
354 | /**
355 | * [!] Method is generated. Documentation taken from corresponding module.
356 | *
357 | * Checks that the condition is NOT false (everything but false)
358 | *
359 | * @param $condition
360 | * @param string $message
361 | * @see \Codeception\Module\Asserts::assertNotFalse()
362 | */
363 | public function assertNotFalse($condition, $message = null) {
364 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertNotFalse', func_get_args()));
365 | }
366 |
367 |
368 | /**
369 | * [!] Method is generated. Documentation taken from corresponding module.
370 | *
371 | * Checks if file exists
372 | *
373 | * @param string $filename
374 | * @param string $message
375 | * @see \Codeception\Module\Asserts::assertFileExists()
376 | */
377 | public function assertFileExists($filename, $message = null) {
378 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertFileExists', func_get_args()));
379 | }
380 |
381 |
382 | /**
383 | * [!] Method is generated. Documentation taken from corresponding module.
384 | *
385 | * Checks if file doesn't exist
386 | *
387 | * @param string $filename
388 | * @param string $message
389 | * @see \Codeception\Module\Asserts::assertFileNotExists()
390 | */
391 | public function assertFileNotExists($filename, $message = null) {
392 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertFileNotExists', func_get_args()));
393 | }
394 |
395 |
396 | /**
397 | * [!] Method is generated. Documentation taken from corresponding module.
398 | *
399 | * @param $expected
400 | * @param $actual
401 | * @param $description
402 | * @see \Codeception\Module\Asserts::assertGreaterOrEquals()
403 | */
404 | public function assertGreaterOrEquals($expected, $actual, $description = null) {
405 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertGreaterOrEquals', func_get_args()));
406 | }
407 |
408 |
409 | /**
410 | * [!] Method is generated. Documentation taken from corresponding module.
411 | *
412 | * @param $expected
413 | * @param $actual
414 | * @param $description
415 | * @see \Codeception\Module\Asserts::assertLessOrEquals()
416 | */
417 | public function assertLessOrEquals($expected, $actual, $description = null) {
418 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertLessOrEquals', func_get_args()));
419 | }
420 |
421 |
422 | /**
423 | * [!] Method is generated. Documentation taken from corresponding module.
424 | *
425 | * @param $actual
426 | * @param $description
427 | * @see \Codeception\Module\Asserts::assertIsEmpty()
428 | */
429 | public function assertIsEmpty($actual, $description = null) {
430 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertIsEmpty', func_get_args()));
431 | }
432 |
433 |
434 | /**
435 | * [!] Method is generated. Documentation taken from corresponding module.
436 | *
437 | * @param $key
438 | * @param $actual
439 | * @param $description
440 | * @see \Codeception\Module\Asserts::assertArrayHasKey()
441 | */
442 | public function assertArrayHasKey($key, $actual, $description = null) {
443 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertArrayHasKey', func_get_args()));
444 | }
445 |
446 |
447 | /**
448 | * [!] Method is generated. Documentation taken from corresponding module.
449 | *
450 | * @param $key
451 | * @param $actual
452 | * @param $description
453 | * @see \Codeception\Module\Asserts::assertArrayNotHasKey()
454 | */
455 | public function assertArrayNotHasKey($key, $actual, $description = null) {
456 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertArrayNotHasKey', func_get_args()));
457 | }
458 |
459 |
460 | /**
461 | * [!] Method is generated. Documentation taken from corresponding module.
462 | *
463 | * Checks that array contains subset.
464 | *
465 | * @param array $subset
466 | * @param array $array
467 | * @param bool $strict
468 | * @param string $message
469 | * @see \Codeception\Module\Asserts::assertArraySubset()
470 | */
471 | public function assertArraySubset($subset, $array, $strict = null, $message = null) {
472 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertArraySubset', func_get_args()));
473 | }
474 |
475 |
476 | /**
477 | * [!] Method is generated. Documentation taken from corresponding module.
478 | *
479 | * @param $expectedCount
480 | * @param $actual
481 | * @param $description
482 | * @see \Codeception\Module\Asserts::assertCount()
483 | */
484 | public function assertCount($expectedCount, $actual, $description = null) {
485 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertCount', func_get_args()));
486 | }
487 |
488 |
489 | /**
490 | * [!] Method is generated. Documentation taken from corresponding module.
491 | *
492 | * @param $class
493 | * @param $actual
494 | * @param $description
495 | * @see \Codeception\Module\Asserts::assertInstanceOf()
496 | */
497 | public function assertInstanceOf($class, $actual, $description = null) {
498 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertInstanceOf', func_get_args()));
499 | }
500 |
501 |
502 | /**
503 | * [!] Method is generated. Documentation taken from corresponding module.
504 | *
505 | * @param $class
506 | * @param $actual
507 | * @param $description
508 | * @see \Codeception\Module\Asserts::assertNotInstanceOf()
509 | */
510 | public function assertNotInstanceOf($class, $actual, $description = null) {
511 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertNotInstanceOf', func_get_args()));
512 | }
513 |
514 |
515 | /**
516 | * [!] Method is generated. Documentation taken from corresponding module.
517 | *
518 | * @param $type
519 | * @param $actual
520 | * @param $description
521 | * @see \Codeception\Module\Asserts::assertInternalType()
522 | */
523 | public function assertInternalType($type, $actual, $description = null) {
524 | return $this->getScenario()->runStep(new \Codeception\Step\Action('assertInternalType', func_get_args()));
525 | }
526 |
527 |
528 | /**
529 | * [!] Method is generated. Documentation taken from corresponding module.
530 | *
531 | * Fails the test with message.
532 | *
533 | * @param $message
534 | * @see \Codeception\Module\Asserts::fail()
535 | */
536 | public function fail($message) {
537 | return $this->getScenario()->runStep(new \Codeception\Step\Action('fail', func_get_args()));
538 | }
539 |
540 |
541 | /**
542 | * [!] Method is generated. Documentation taken from corresponding module.
543 | *
544 | * Handles and checks exception called inside callback function.
545 | * Either exception class name or exception instance should be provided.
546 | *
547 | * ```php
548 | * expectException(MyException::class, function() {
550 | * $this->doSomethingBad();
551 | * });
552 | *
553 | * $I->expectException(new MyException(), function() {
554 | * $this->doSomethingBad();
555 | * });
556 | * ```
557 | * If you want to check message or exception code, you can pass them with exception instance:
558 | * ```php
559 | * expectException(new MyException("Don't do bad things"), function() {
562 | * $this->doSomethingBad();
563 | * });
564 | * ```
565 | *
566 | * @param $exception string or \Exception
567 | * @param $callback
568 | *
569 | * @deprecated Use expectThrowable instead
570 | * @see \Codeception\Module\Asserts::expectException()
571 | */
572 | public function expectException($exception, $callback) {
573 | return $this->getScenario()->runStep(new \Codeception\Step\Action('expectException', func_get_args()));
574 | }
575 |
576 |
577 | /**
578 | * [!] Method is generated. Documentation taken from corresponding module.
579 | *
580 | * Handles and checks throwables (Exceptions/Errors) called inside the callback function.
581 | * Either throwable class name or throwable instance should be provided.
582 | *
583 | * ```php
584 | * expectThrowable(MyThrowable::class, function() {
586 | * $this->doSomethingBad();
587 | * });
588 | *
589 | * $I->expectThrowable(new MyException(), function() {
590 | * $this->doSomethingBad();
591 | * });
592 | * ```
593 | * If you want to check message or throwable code, you can pass them with throwable instance:
594 | * ```php
595 | * expectThrowable(new MyError("Don't do bad things"), function() {
598 | * $this->doSomethingBad();
599 | * });
600 | * ```
601 | *
602 | * @param $throwable string or \Throwable
603 | * @param $callback
604 | * @see \Codeception\Module\Asserts::expectThrowable()
605 | */
606 | public function expectThrowable($throwable, $callback) {
607 | return $this->getScenario()->runStep(new \Codeception\Step\Action('expectThrowable', func_get_args()));
608 | }
609 |
610 |
611 | /**
612 | * [!] Method is generated. Documentation taken from corresponding module.
613 | *
614 | * Enters a directory In local filesystem.
615 | * Project root directory is used by default
616 | *
617 | * @param string $path
618 | * @see \Codeception\Module\Filesystem::amInPath()
619 | */
620 | public function amInPath($path) {
621 | return $this->getScenario()->runStep(new \Codeception\Step\Condition('amInPath', func_get_args()));
622 | }
623 |
624 |
625 | /**
626 | * [!] Method is generated. Documentation taken from corresponding module.
627 | *
628 | * Opens a file and stores it's content.
629 | *
630 | * Usage:
631 | *
632 | * ``` php
633 | * openFile('composer.json');
635 | * $I->seeInThisFile('codeception/codeception');
636 | * ?>
637 | * ```
638 | *
639 | * @param string $filename
640 | * @see \Codeception\Module\Filesystem::openFile()
641 | */
642 | public function openFile($filename) {
643 | return $this->getScenario()->runStep(new \Codeception\Step\Action('openFile', func_get_args()));
644 | }
645 |
646 |
647 | /**
648 | * [!] Method is generated. Documentation taken from corresponding module.
649 | *
650 | * Deletes a file
651 | *
652 | * ``` php
653 | * deleteFile('composer.lock');
655 | * ?>
656 | * ```
657 | *
658 | * @param string $filename
659 | * @see \Codeception\Module\Filesystem::deleteFile()
660 | */
661 | public function deleteFile($filename) {
662 | return $this->getScenario()->runStep(new \Codeception\Step\Action('deleteFile', func_get_args()));
663 | }
664 |
665 |
666 | /**
667 | * [!] Method is generated. Documentation taken from corresponding module.
668 | *
669 | * Deletes directory with all subdirectories
670 | *
671 | * ``` php
672 | * deleteDir('vendor');
674 | * ?>
675 | * ```
676 | *
677 | * @param string $dirname
678 | * @see \Codeception\Module\Filesystem::deleteDir()
679 | */
680 | public function deleteDir($dirname) {
681 | return $this->getScenario()->runStep(new \Codeception\Step\Action('deleteDir', func_get_args()));
682 | }
683 |
684 |
685 | /**
686 | * [!] Method is generated. Documentation taken from corresponding module.
687 | *
688 | * Copies directory with all contents
689 | *
690 | * ``` php
691 | * copyDir('vendor','old_vendor');
693 | * ?>
694 | * ```
695 | *
696 | * @param string $src
697 | * @param string $dst
698 | * @see \Codeception\Module\Filesystem::copyDir()
699 | */
700 | public function copyDir($src, $dst) {
701 | return $this->getScenario()->runStep(new \Codeception\Step\Action('copyDir', func_get_args()));
702 | }
703 |
704 |
705 | /**
706 | * [!] Method is generated. Documentation taken from corresponding module.
707 | *
708 | * Checks If opened file has `text` in it.
709 | *
710 | * Usage:
711 | *
712 | * ``` php
713 | * openFile('composer.json');
715 | * $I->seeInThisFile('codeception/codeception');
716 | * ?>
717 | * ```
718 | *
719 | * @param string $text
720 | * Conditional Assertion: Test won't be stopped on fail
721 | * @see \Codeception\Module\Filesystem::seeInThisFile()
722 | */
723 | public function canSeeInThisFile($text) {
724 | return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeInThisFile', func_get_args()));
725 | }
726 | /**
727 | * [!] Method is generated. Documentation taken from corresponding module.
728 | *
729 | * Checks If opened file has `text` in it.
730 | *
731 | * Usage:
732 | *
733 | * ``` php
734 | * openFile('composer.json');
736 | * $I->seeInThisFile('codeception/codeception');
737 | * ?>
738 | * ```
739 | *
740 | * @param string $text
741 | * @see \Codeception\Module\Filesystem::seeInThisFile()
742 | */
743 | public function seeInThisFile($text) {
744 | return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeInThisFile', func_get_args()));
745 | }
746 |
747 |
748 | /**
749 | * [!] Method is generated. Documentation taken from corresponding module.
750 | *
751 | * Checks If opened file has the `number` of new lines.
752 | *
753 | * Usage:
754 | *
755 | * ``` php
756 | * openFile('composer.json');
758 | * $I->seeNumberNewLines(5);
759 | * ?>
760 | * ```
761 | *
762 | * @param int $number New lines
763 | * Conditional Assertion: Test won't be stopped on fail
764 | * @see \Codeception\Module\Filesystem::seeNumberNewLines()
765 | */
766 | public function canSeeNumberNewLines($number) {
767 | return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeNumberNewLines', func_get_args()));
768 | }
769 | /**
770 | * [!] Method is generated. Documentation taken from corresponding module.
771 | *
772 | * Checks If opened file has the `number` of new lines.
773 | *
774 | * Usage:
775 | *
776 | * ``` php
777 | * openFile('composer.json');
779 | * $I->seeNumberNewLines(5);
780 | * ?>
781 | * ```
782 | *
783 | * @param int $number New lines
784 | * @see \Codeception\Module\Filesystem::seeNumberNewLines()
785 | */
786 | public function seeNumberNewLines($number) {
787 | return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeNumberNewLines', func_get_args()));
788 | }
789 |
790 |
791 | /**
792 | * [!] Method is generated. Documentation taken from corresponding module.
793 | *
794 | * Checks that contents of currently opened file matches $regex
795 | *
796 | * @param string $regex
797 | * Conditional Assertion: Test won't be stopped on fail
798 | * @see \Codeception\Module\Filesystem::seeThisFileMatches()
799 | */
800 | public function canSeeThisFileMatches($regex) {
801 | return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeThisFileMatches', func_get_args()));
802 | }
803 | /**
804 | * [!] Method is generated. Documentation taken from corresponding module.
805 | *
806 | * Checks that contents of currently opened file matches $regex
807 | *
808 | * @param string $regex
809 | * @see \Codeception\Module\Filesystem::seeThisFileMatches()
810 | */
811 | public function seeThisFileMatches($regex) {
812 | return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeThisFileMatches', func_get_args()));
813 | }
814 |
815 |
816 | /**
817 | * [!] Method is generated. Documentation taken from corresponding module.
818 | *
819 | * Checks the strict matching of file contents.
820 | * Unlike `seeInThisFile` will fail if file has something more than expected lines.
821 | * Better to use with HEREDOC strings.
822 | * Matching is done after removing "\r" chars from file content.
823 | *
824 | * ``` php
825 | * openFile('process.pid');
827 | * $I->seeFileContentsEqual('3192');
828 | * ?>
829 | * ```
830 | *
831 | * @param string $text
832 | * Conditional Assertion: Test won't be stopped on fail
833 | * @see \Codeception\Module\Filesystem::seeFileContentsEqual()
834 | */
835 | public function canSeeFileContentsEqual($text) {
836 | return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeFileContentsEqual', func_get_args()));
837 | }
838 | /**
839 | * [!] Method is generated. Documentation taken from corresponding module.
840 | *
841 | * Checks the strict matching of file contents.
842 | * Unlike `seeInThisFile` will fail if file has something more than expected lines.
843 | * Better to use with HEREDOC strings.
844 | * Matching is done after removing "\r" chars from file content.
845 | *
846 | * ``` php
847 | * openFile('process.pid');
849 | * $I->seeFileContentsEqual('3192');
850 | * ?>
851 | * ```
852 | *
853 | * @param string $text
854 | * @see \Codeception\Module\Filesystem::seeFileContentsEqual()
855 | */
856 | public function seeFileContentsEqual($text) {
857 | return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeFileContentsEqual', func_get_args()));
858 | }
859 |
860 |
861 | /**
862 | * [!] Method is generated. Documentation taken from corresponding module.
863 | *
864 | * Checks If opened file doesn't contain `text` in it
865 | *
866 | * ``` php
867 | * openFile('composer.json');
869 | * $I->dontSeeInThisFile('codeception/codeception');
870 | * ?>
871 | * ```
872 | *
873 | * @param string $text
874 | * Conditional Assertion: Test won't be stopped on fail
875 | * @see \Codeception\Module\Filesystem::dontSeeInThisFile()
876 | */
877 | public function cantSeeInThisFile($text) {
878 | return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeInThisFile', func_get_args()));
879 | }
880 | /**
881 | * [!] Method is generated. Documentation taken from corresponding module.
882 | *
883 | * Checks If opened file doesn't contain `text` in it
884 | *
885 | * ``` php
886 | * openFile('composer.json');
888 | * $I->dontSeeInThisFile('codeception/codeception');
889 | * ?>
890 | * ```
891 | *
892 | * @param string $text
893 | * @see \Codeception\Module\Filesystem::dontSeeInThisFile()
894 | */
895 | public function dontSeeInThisFile($text) {
896 | return $this->getScenario()->runStep(new \Codeception\Step\Assertion('dontSeeInThisFile', func_get_args()));
897 | }
898 |
899 |
900 | /**
901 | * [!] Method is generated. Documentation taken from corresponding module.
902 | *
903 | * Deletes a file
904 | * @see \Codeception\Module\Filesystem::deleteThisFile()
905 | */
906 | public function deleteThisFile() {
907 | return $this->getScenario()->runStep(new \Codeception\Step\Action('deleteThisFile', func_get_args()));
908 | }
909 |
910 |
911 | /**
912 | * [!] Method is generated. Documentation taken from corresponding module.
913 | *
914 | * Checks if file exists in path.
915 | * Opens a file when it's exists
916 | *
917 | * ``` php
918 | * seeFileFound('UserModel.php','app/models');
920 | * ?>
921 | * ```
922 | *
923 | * @param string $filename
924 | * @param string $path
925 | * Conditional Assertion: Test won't be stopped on fail
926 | * @see \Codeception\Module\Filesystem::seeFileFound()
927 | */
928 | public function canSeeFileFound($filename, $path = null) {
929 | return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeFileFound', func_get_args()));
930 | }
931 | /**
932 | * [!] Method is generated. Documentation taken from corresponding module.
933 | *
934 | * Checks if file exists in path.
935 | * Opens a file when it's exists
936 | *
937 | * ``` php
938 | * seeFileFound('UserModel.php','app/models');
940 | * ?>
941 | * ```
942 | *
943 | * @param string $filename
944 | * @param string $path
945 | * @see \Codeception\Module\Filesystem::seeFileFound()
946 | */
947 | public function seeFileFound($filename, $path = null) {
948 | return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeFileFound', func_get_args()));
949 | }
950 |
951 |
952 | /**
953 | * [!] Method is generated. Documentation taken from corresponding module.
954 | *
955 | * Checks if file does not exist in path
956 | *
957 | * @param string $filename
958 | * @param string $path
959 | * Conditional Assertion: Test won't be stopped on fail
960 | * @see \Codeception\Module\Filesystem::dontSeeFileFound()
961 | */
962 | public function cantSeeFileFound($filename, $path = null) {
963 | return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeFileFound', func_get_args()));
964 | }
965 | /**
966 | * [!] Method is generated. Documentation taken from corresponding module.
967 | *
968 | * Checks if file does not exist in path
969 | *
970 | * @param string $filename
971 | * @param string $path
972 | * @see \Codeception\Module\Filesystem::dontSeeFileFound()
973 | */
974 | public function dontSeeFileFound($filename, $path = null) {
975 | return $this->getScenario()->runStep(new \Codeception\Step\Assertion('dontSeeFileFound', func_get_args()));
976 | }
977 |
978 |
979 | /**
980 | * [!] Method is generated. Documentation taken from corresponding module.
981 | *
982 | * Erases directory contents
983 | *
984 | * ``` php
985 | * cleanDir('logs');
987 | * ?>
988 | * ```
989 | *
990 | * @param string $dirname
991 | * @see \Codeception\Module\Filesystem::cleanDir()
992 | */
993 | public function cleanDir($dirname) {
994 | return $this->getScenario()->runStep(new \Codeception\Step\Action('cleanDir', func_get_args()));
995 | }
996 |
997 |
998 | /**
999 | * [!] Method is generated. Documentation taken from corresponding module.
1000 | *
1001 | * Saves contents to file
1002 | *
1003 | * @param string $filename
1004 | * @param string $contents
1005 | * @see \Codeception\Module\Filesystem::writeToFile()
1006 | */
1007 | public function writeToFile($filename, $contents) {
1008 | return $this->getScenario()->runStep(new \Codeception\Step\Action('writeToFile', func_get_args()));
1009 | }
1010 | }
1011 |
--------------------------------------------------------------------------------