diff --git a/CHANGELOG.md b/CHANGELOG.md index f0cf4ce..fbe9d1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Documentation and governance +- Added Phase 2.7B repository governance evidence finalization: changed the GitHub default branch to `2.x`, activated repository rulesets for `master` and `2.x`, preserved `master` as the EvolvePHP 1 legacy line, required PR-based change on both branches, blocked deletion and force pushes, enforced strict/up-to-date required status checks on `2.x` for `Policy (PHP 8.4)`, `Workspace quality (PHP 8.4)` and `Workspace quality (PHP 8.5)`, and made no branch rename or deletion. - Added Phase 2.7A repository-owned branch-governance policy foundation for EvolvePHP 2 development on `2.x`, preserved EvolvePHP 1 maintenance on `master`, explicit separation of modern development and legacy maintenance, and preparation for a later default-branch and ruleset transition. - Added Phase 2.6 GitHub Actions CI foundation with a PHP 8.4/8.5 workspace quality matrix, separate PHP 8.4 root-policy job, lockfile-based workspace installation, immutable action pinning, and successful initial CI execution for the current workspace, tooling and package foundation. - Added Phase 2.5.1 README and metadata consistency cleanup, aligning the EvolvePHP 2 README hierarchy, correcting root Composer metadata, deduplicating stale RFC index narration, removing duplicated phase history, and clarifying workspace installation and compatibility guidance. diff --git a/README.md b/README.md index 0b7aea5..f6af64c 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # EvolvePHP 2 -`2.x` is the designated EvolvePHP 2 development branch. +`2.x` is the designated EvolvePHP 2 development branch and the GitHub default branch. `master` remains the preserved EvolvePHP 1 legacy branch for historical reference and explicitly approved legacy maintenance. EvolvePHP 2 development and proposed changes must not target `master`. -During Phase 2.7A, the current GitHub default branch remains `master` until the Phase 2.7 external transition. The live default-branch and ruleset transition is still pending external GitHub evidence. +Phase 2.7B completed the external governance transition. Repository rulesets actively protect both branch lines: `master` remains preserved, and `2.x` now receives default-branch development changes. EvolvePHP 2 is not an in-place refactor, replacement or rewrite of the EvolvePHP 1 runtime history. @@ -21,9 +21,12 @@ The EvolvePHP 2 line redesigns the framework as a modular package architecture w ## Current Status - EvolvePHP 2 development branch: `2.x` -- Current GitHub default during Phase 2.7A: `master` +- GitHub default branch: `2.x` - Legacy line: EvolvePHP 1 on `master` -- Governance transition: live default-branch and ruleset changes pending external verification +- Repository rulesets: active for `master` and `2.x` +- `master` ruleset: pull request requirement, deletion protection, force-push protection, required approvals remain zero, conversation resolution is required, and there are no bypass actors +- `2.x` ruleset: pull request requirement, deletion protection, force-push protection, required CI status checks, strict/up-to-date status-check policy, required approvals remain zero, conversation resolution is required, and there are no bypass actors +- Required `2.x` checks: `Policy (PHP 8.4)`, `Workspace quality (PHP 8.4)`, `Workspace quality (PHP 8.5)` - Runtime implementation: not yet complete - Package publication: packages are not yet published - PHP baseline: PHP 8.4 @@ -56,11 +59,13 @@ The legacy EvolvePHP 1 runtime files remain in the repository for preservation a ```bash git clone https://github.com/josiahking/evolvephp.git cd evolvephp -git switch 2.x +git branch --show-current composer --working-dir=workspace install composer --working-dir=workspace quality ``` +The normal clone path starts on `2.x` because it is the GitHub default branch. For an older local checkout, verify the branch with `git branch --show-current` and run `git switch 2.x` only when the checkout is not already on `2.x`. + The EvolvePHP 2 workspace owns dependency installation and quality checks. Use [workspace/README.md](workspace/README.md) for detailed Composer, PHPUnit, PHPStan, PHP-CS-Fixer and Deptrac guidance. ## Quality Checks @@ -85,7 +90,7 @@ EvolvePHP 1 has been used as the foundation of Africa Global Export Market, a li That production-use background belongs to the preserved EvolvePHP 1 history. New EvolvePHP 2 work happens separately on `2.x`, and EvolvePHP 2 changes must not target `master`. New production applications should not start from EvolvePHP 1 without a detailed security and compatibility review. -Phase 2.7A establishes repository-owned branch-governance policy only. `master` has not been renamed or deleted, no `main` branch has been created, and no `1.x` branch has been created. Any stable-release branch rename or promotion is deferred, and Phase 2.7 does not replace the legacy history. +Phase 2.7B completed the external governance transition without replacing history. `master` has not been renamed or deleted, no branch was renamed or deleted, no `main` branch has been created, and no `1.x` branch has been created. Any stable-release branch rename or promotion is deferred, and Phase 2.7 does not replace the legacy history. See the [legacy overview](docs/history/evolvephp-1-overview.md), [known risks and limitations](docs/history/known-risks-and-limitations.md), [support policy](SUPPORT.md) and [security policy](SECURITY.md). diff --git a/tests/Documentation/EvolvePhp2RepositoryGovernanceTest.php b/tests/Documentation/EvolvePhp2RepositoryGovernanceTest.php index aae78ee..f4d4061 100644 --- a/tests/Documentation/EvolvePhp2RepositoryGovernanceTest.php +++ b/tests/Documentation/EvolvePhp2RepositoryGovernanceTest.php @@ -11,15 +11,16 @@ protected function setUp(): void $this->root = dirname(__DIR__, 2); } - public function testReadmeDocumentsStageABranchIdentity() + public function testReadmeDocumentsFinalBranchIdentity() { $content = $this->readProjectFile('README.md'); $this->assertMatchesPattern('/2\.x.*designated EvolvePHP 2 development branch|designated EvolvePHP 2 development branch.*2\.x/is', $content); + $this->assertMatchesPattern('/2\.x.*GitHub default branch|GitHub default branch.*2\.x/is', $content); $this->assertMatchesPattern('/master.*preserved EvolvePHP 1 legacy branch|preserved EvolvePHP 1 legacy branch.*master/is', $content); $this->assertMatchesPattern('/EvolvePHP 2 changes.*must not target.*master|must not target.*master.*EvolvePHP 2 changes/is', $content); - $this->assertMatchesPattern('/current GitHub default.*master.*Phase 2\.7 external transition|Phase 2\.7 external transition.*current GitHub default.*master/is', $content); - $this->assertDoesNotMatchPattern($this->unsupportedDefaultBranchClaimPattern(), $content); + $this->assertMatchesPattern('/repository rulesets?.*protect.*branch lines|branch lines.*protect.*repository rulesets?/is', $content); + $this->assertDoesNotMatchPattern($this->staleTransitionPattern(), $content); } public function testAgentRulesDocumentVerifiedBaseBranchWorkflow() @@ -60,35 +61,45 @@ public function testCanonicalDocumentationKeepsStableCutoverDeferred() $this->assertMatchesPattern('/Phase 2\.7.*does not replace.*legacy history|legacy history.*not.*replaced.*Phase 2\.7/is', $content); } - public function testStageAEvidenceBoundaryIsDocumented() + public function testFinalGovernanceRulesetsAreDocumented() { $content = $this->readProjectFile('README.md') . "\n" . $this->readProjectFile('CHANGELOG.md'); - $this->assertMatchesPattern('/Phase 2\.7A.*repository-owned branch-governance policy|repository-owned branch-governance policy.*Phase 2\.7A/is', $content); - $this->assertMatchesPattern('/live default-branch.*ruleset.*pending external GitHub evidence|pending external GitHub evidence.*live default-branch.*ruleset/is', $content); - $this->assertDoesNotMatchPattern($this->unsupportedDefaultBranchClaimPattern(), $content); - $this->assertDoesNotMatchPattern('/branch protection is active|rulesets? (?:is|are) active|required checks (?:are|have been) enforced/i', $content); + $this->assertMatchesPattern('/Phase 2\.7B.*completed.*external governance transition|external governance transition.*completed.*Phase 2\.7B/is', $content); + $this->assertMatchesPattern('/repository rulesets? (?:are )?active|active repository rulesets?/i', $content); + $this->assertMatchesPattern('/master.*pull request.*deletion.*force-push|master.*force-push.*deletion.*pull request/is', $content); + $this->assertMatchesPattern('/2\.x.*pull request.*deletion.*force-push.*required CI status checks.*strict|2\.x.*strict.*required CI status checks.*force-push.*deletion.*pull request/is', $content); + $this->assertMatchesPattern('/required approvals.*zero|zero.*required approvals/i', $content); + $this->assertMatchesPattern('/conversation resolution.*required|required.*conversation resolution/i', $content); + $this->assertMatchesPattern('/no bypass actors|bypass actors.*none/i', $content); + $this->assertMatchesPattern('/Policy \(PHP 8\.4\)/', $content); + $this->assertMatchesPattern('/Workspace quality \(PHP 8\.4\)/', $content); + $this->assertMatchesPattern('/Workspace quality \(PHP 8\.5\)/', $content); + $this->assertDoesNotMatchPattern($this->staleTransitionPattern(), $content); + $this->assertDoesNotMatchPattern('/classic branch protection|branch protection is active/i', $content); $this->assertDoesNotMatchPattern('/master (?:was|has been) (?:renamed|deleted|replaced)/i', $content); } - public function testChangelogRecordsPolicyFoundationWithoutExternalSettingChange() + public function testChangelogRecordsFinalGovernanceEvidence() { $content = $this->readProjectFile('CHANGELOG.md'); $this->assertMatchesPattern('/Phase 2\.7A/i', $content); - $this->assertMatchesPattern('/branch-governance policy/i', $content); - $this->assertMatchesPattern('/EvolvePHP 2 development on `2\.x`/i', $content); - $this->assertMatchesPattern('/EvolvePHP 1 maintenance on `master`/i', $content); - $this->assertMatchesPattern('/later default-branch and ruleset transition/i', $content); - $this->assertDoesNotMatchPattern($this->unsupportedDefaultBranchClaimPattern(), $content); - $this->assertDoesNotMatchPattern('/branch protection is active|rulesets? (?:is|are) active|required checks (?:are|have been) enforced/i', $content); + $this->assertMatchesPattern('/Phase 2\.7B/i', $content); + $this->assertMatchesPattern('/GitHub default branch.*`2\.x`|`2\.x`.*GitHub default branch/i', $content); + $this->assertMatchesPattern('/repository rulesets?.*`master`.*`2\.x`|`master`.*`2\.x`.*repository rulesets?/is', $content); + $this->assertMatchesPattern('/preserved `master`.*EvolvePHP 1 legacy line|EvolvePHP 1 legacy line.*preserved `master`/i', $content); + $this->assertMatchesPattern('/PR-based change.*both branches|both branches.*PR-based change/i', $content); + $this->assertMatchesPattern('/block(?:s|ed)? deletion.*force pushes|force pushes.*block(?:s|ed)? deletion/i', $content); + $this->assertMatchesPattern('/strict.*up-to-date required status checks|up-to-date.*strict.*required status checks/i', $content); + $this->assertMatchesPattern('/Policy \(PHP 8\.4\).*Workspace quality \(PHP 8\.4\).*Workspace quality \(PHP 8\.5\)/is', $content); + $this->assertMatchesPattern('/no branch rename or deletion|no branch was renamed or deleted/i', $content); + $this->assertDoesNotMatchPattern('/classic branch protection|branch protection is active/i', $content); } - private function unsupportedDefaultBranchClaimPattern() + private function staleTransitionPattern() { - $branch = '2' . '\.x'; - - return '/' . $branch . ' is (?:now |already )?the (?:GitHub )?default branch|default branch (?:is|changed to) `?' . $branch . '/i'; + return '/current GitHub default.*master|default branch remains.*master|ruleset.*pending|default-branch.*pending|pending external GitHub evidence|live.*transition.*pending/i'; } private function readProjectFile($path)