Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# Changelog

## 3.0.1 - 2026-09-13

### Fixed

- Keyless demo mode now matches the demo endpoint on a path-segment boundary
(#23). It used a raw prefix match, `str_starts_with($path, '/v1/demo')`, so
any path whose characters merely began that way was treated as a demo call
and sent without the `Authorization` header.

### Internal

- PHPStan level 9 now runs in CI against `src/`, with the 14 errors it reported
fixed and no baseline (#24).

## 3.0.0 - 2026-09-13

### Breaking changes
Expand Down
2 changes: 1 addition & 1 deletion src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
*/
final class Client
{
public const VERSION = '3.0.0';
public const VERSION = '3.0.1';
public const DEFAULT_BASE_URL = 'https://api.oilpriceapi.com';
public const DEFAULT_TIMEOUT = 10.0;
public const DEFAULT_MAX_RETRIES = 3;
Expand Down
2 changes: 1 addition & 1 deletion tests/PublicClaimsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ public function testCanonicalDeveloperContractIsDiscoverable(): void
);
self::assertSame('oilpriceapi/oilpriceapi', $composer['name']);
self::assertSame('>=8.1', $composer['require']['php']);
self::assertSame('3.0.0', Client::VERSION);
self::assertSame('3.0.1', Client::VERSION);
self::assertSame('https://api.oilpriceapi.com', Client::DEFAULT_BASE_URL);

$readme = (string) file_get_contents($root . '/README.md');
Expand Down
23 changes: 20 additions & 3 deletions tests/VersioningTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public function testTopmostChangelogEntryMatchesTheShippedVersion(): void
*/
public function testChangelogDocumentsTheBreakingChange(): void
{
$entry = self::firstChangelogEntry();
$entry = self::breakingMajorEntry();

$this->assertMatchesRegularExpression(
'/###\s+Breaking changes/i',
Expand Down Expand Up @@ -189,9 +189,9 @@ public function testUserAgentCarriesTheSameVersion(): void
*/
private static function breakingChangesSection(): string
{
$entry = self::firstChangelogEntry();
$entry = self::breakingMajorEntry();
$start = strpos($entry, '### Breaking changes');
self::assertIsInt($start, 'The topmost entry has no "### Breaking changes" section.');
self::assertIsInt($start, 'The breaking major entry has no "### Breaking changes" section.');

$rest = substr($entry, $start + strlen('### Breaking changes'));
$next = strpos($rest, '###');
Expand All @@ -212,6 +212,23 @@ private static function firstChangelogHeading(): string
return trim($matches[1]);
}

/**
* The entry for the major that introduced the break (3.0.0), wherever it
* sits. Reading the topmost entry instead made every later patch or minor
* release fail these tests unless it re-listed 3.0.0's breaking changes,
* which would tell a reader upgrading from 3.0.0 that something new broke.
*/
private static function breakingMajorEntry(): string
{
$version = (self::LAST_BC_COMPATIBLE_MAJOR + 1) . '.0.0';
foreach (preg_split('/^## /m', self::changelog()) ?: [] as $entry) {
if (str_starts_with($entry, $version . ' ') || str_starts_with($entry, '[' . $version . ']')) {
return $entry;
}
}
self::fail(sprintf('CHANGELOG.md has no "## %s" entry.', $version));
}

private static function firstChangelogEntry(): string
{
$parts = preg_split('/^## /m', self::changelog());
Expand Down