diff --git a/.github/workflows/phpstan.yaml b/.github/workflows/phpstan.yaml new file mode 100644 index 0000000..6ee5e9e --- /dev/null +++ b/.github/workflows/phpstan.yaml @@ -0,0 +1,46 @@ +name: PHPStan +on: [workflow_dispatch, pull_request] + +env: + PLUGIN_CODE: StripeWebhook + PLUGIN_PACKAGE_NAME: 'ec-cube/stripewebhook' + +jobs: + phpstan: + name: PHPStan + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + eccube-versions: ['4.3'] + php-versions: [ '8.2' ] + database: [ 'mysql' ] + include: + - database: mysql + database_url: mysql://root:password@127.0.0.1:3306/eccube_db + database_server_version: 5.7 + database_charset: utf8mb4 + services: + mysql: + image: mysql:5.7 + env: + MYSQL_ROOT_PASSWORD: password + ports: + - 3306:3306 + options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + + - uses: kurozumi/eccube-plugin-phpstan@v1.0.5 + with: + plugin-code: ${{ env.PLUGIN_CODE }} + plugin-package-name: ${{ env.PLUGIN_PACKAGE_NAME }} + eccube-versions: ${{ matrix.eccube-versions }} + php-versions: ${{ matrix.php-versions }} + database-url: ${{ matrix.database_url }} + database-server-version: ${{ matrix.database_server_version }} + database-charset: ${{ matrix.database_charset }} diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 0000000..f67245b --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,71 @@ +name: CI/CD for EC-CUBE4 Plugin +on: [workflow_dispatch, pull_request] + +env: + PLUGIN_CODE: StripeWebhook + PLUGIN_PACKAGE_NAME: 'ec-cube/stripewebhook' + +jobs: + phpunit: + name: PHPUnit + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + eccube-versions: [ '4.3' ] + php-versions: [ '8.2', '8.3' ] + database: [ 'mysql', 'mysql8', 'pgsql' ] + include: + - database: mysql + database_url: mysql://root:password@127.0.0.1:3306/eccube_db + database_server_version: 5.7 + database_charset: utf8mb4 + - database: mysql8 + database_url: mysql://root:password@127.0.0.1:3308/eccube_db + database_server_version: 8 + database_charset: utf8mb4 + - database: pgsql + database_url: postgres://postgres:password@127.0.0.1:5432/eccube_db + database_server_version: 14 + database_charset: utf8 + + services: + mysql: + image: mysql:5.7 + env: + MYSQL_ROOT_PASSWORD: password + ports: + - 3306:3306 + options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 + mysql8: + image: mysql:8 + env: + MYSQL_ROOT_PASSWORD: password + ports: + - 3308:3306 + options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 + postgres: + image: postgres:11 + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: password + ports: + - 5432:5432 + # needed because the postgres container does not provide a healthcheck + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + + - uses: kurozumi/eccube-plugin-test@main + with: + plugin-code: ${{ env.PLUGIN_CODE }} + plugin-package-name: ${{ env.PLUGIN_PACKAGE_NAME }} + eccube-versions: ${{ matrix.eccube-versions }} + php-versions: ${{ matrix.php-versions }} + database-url: ${{ matrix.database_url }} + database-server-version: ${{ matrix.database_server_version }} + database-charset: ${{ matrix.database_charset }} diff --git a/README.md b/README.md index aba6532..eaea074 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ use Stripe\Checkout\Session; use Stripe\Event; use Stripe\Invoice; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\RemoteEvent\RemoteEvent; class StripeEventListener implements EventSubscriberInterface { diff --git a/RemoteEvent/Event/StripeEvent.php b/RemoteEvent/Event/StripeEvent.php index a074d8d..f257aa6 100644 --- a/RemoteEvent/Event/StripeEvent.php +++ b/RemoteEvent/Event/StripeEvent.php @@ -15,7 +15,7 @@ namespace Plugin\StripeWebhook\RemoteEvent\Event; -use Stripe\ApiResource; +use Stripe\StripeObject; use Symfony\Component\RemoteEvent\RemoteEvent; final class StripeEvent extends RemoteEvent @@ -24,12 +24,12 @@ public function __construct( private readonly string $name, private readonly string $id, private readonly array $payload, - private readonly ApiResource $resource + private readonly StripeObject $resource ) { parent::__construct($this->name, $this->id, $this->payload); } - public function getResource(): ApiResource + public function getResource(): StripeObject { return $this->resource; } diff --git a/Tests/Webhook/Fixtures/StripeEvent.json b/Tests/Webhook/Fixtures/StripeEvent.json new file mode 100644 index 0000000..6ded609 --- /dev/null +++ b/Tests/Webhook/Fixtures/StripeEvent.json @@ -0,0 +1,9 @@ +{ + "id": "event_id", + "data": { + "object": { + "object": "test" + } + }, + "type": "event_name" +} diff --git a/Tests/Webhook/Fixtures/StripeEvent.php b/Tests/Webhook/Fixtures/StripeEvent.php new file mode 100644 index 0000000..a566dfa --- /dev/null +++ b/Tests/Webhook/Fixtures/StripeEvent.php @@ -0,0 +1,19 @@ + 'test'], + resource: new Stripe\StripeObject() +); diff --git a/Tests/Webhook/StripeRequestParserTest.php b/Tests/Webhook/StripeRequestParserTest.php new file mode 100644 index 0000000..7646c1f --- /dev/null +++ b/Tests/Webhook/StripeRequestParserTest.php @@ -0,0 +1,61 @@ +createRequest($payload); + $parser = $this->createRequestParser(); + $wh = $parser->parse($request, $this->getSecret()); + + self::assertEquals($expected->getName(), $wh->getName()); + self::assertEquals($expected->getId(), $wh->getId()); + self::assertEquals($expected->getPayload(), $wh->getPayload()); + } + + protected function createRequestParser(): RequestParserInterface + { + return new StripeRequestParser(); + } + + protected function getSecret(): string + { + return 'STRIPE_SIGNING_SECRET'; + } + + protected function createRequest(string $payload): Request + { + $timestamp = time(); + $signedPayload = "{$timestamp}.{$payload}"; + $expectedSignature = \hash_hmac('sha256', $signedPayload, $this->getSecret()); + + return Request::create('/', 'POST', [], [], [], [ + 'Content-Type' => 'application/json', + 'HTTP_STRIPE_SIGNATURE' => "t={$timestamp},v1={$expectedSignature},v0=signature", + ], $payload); + } +} diff --git a/Tests/bootstrap.php b/Tests/bootstrap.php new file mode 100644 index 0000000..c2e431a --- /dev/null +++ b/Tests/bootstrap.php @@ -0,0 +1,21 @@ +usePutenv() + ->bootEnv($envFile); +} diff --git a/composer.json b/composer.json index 39d5968..89e98b0 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,7 @@ "type": "eccube-plugin", "require": { "ec-cube/plugin-installer": "^2.0", - "php": ">=8.1", + "php": ">=8.2", "symfony/webhook": "*", "symfony/remote-event": "*", "stripe/stripe-php": "*" diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..213da6d --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,2 @@ +parameters: + level: 1 diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..4f6646b --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + ./Tests + + + + + + + + + ./ + + ./Tests + ./Resource + ./PluginManager.php + + + + +