From 4b1841fa9d46a7c0084ab7dffe321178785eb693 Mon Sep 17 00:00:00 2001 From: Don MacAskill Date: Mon, 10 Nov 2025 14:09:16 -0800 Subject: [PATCH 01/14] Create Kiro spec for automating Windows releases --- .../workflows/example_php_windows_builder.yml | 63 +++ .../windows-automated-releases/design.md | 456 ++++++++++++++++++ .../requirements.md | 90 ++++ .../specs/windows-automated-releases/tasks.md | 81 ++++ 4 files changed, 690 insertions(+) create mode 100644 .github/workflows/example_php_windows_builder.yml create mode 100644 .kiro/specs/windows-automated-releases/design.md create mode 100644 .kiro/specs/windows-automated-releases/requirements.md create mode 100644 .kiro/specs/windows-automated-releases/tasks.md diff --git a/.github/workflows/example_php_windows_builder.yml b/.github/workflows/example_php_windows_builder.yml new file mode 100644 index 0000000..2796ba9 --- /dev/null +++ b/.github/workflows/example_php_windows_builder.yml @@ -0,0 +1,63 @@ +# This is an EXAMPLE workflow to build a PHP extension for Windows using GitHub Actions and must be modified prior to use. +# It comes from `php-windows-builder` found at https://github.com/php/php-windows-builder + +name: Build extension +on: + # When a new tag is pushed, we can build, and upload the DLLs to it. + push: + # branches: ['**'] # Uncomment this to run on push to a branch + tags: ['*'] + # create: # Uncomment this to run on tag/branch creation + # pull_request: # Uncomment this to run on pull requests + +permissions: + contents: write + +jobs: + # This job generates a matrix of PHP versions, architectures, and thread safety options + # This is done by reading the constraints from composer.json or the package.xml file. + # Please refer to https://github.com/php/php-windows-builder#get-the-job-matrix-to-build-a-php-extension + get-extension-matrix: + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.extension-matrix.outputs.matrix }} + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Get the extension matrix + id: extension-matrix + uses: php/php-windows-builder/extension-matrix@v1 + + # This job builds the extension on Windows using the matrix generated from the previous job. + build: + needs: get-extension-matrix + runs-on: ${{ matrix.os }} + strategy: + matrix: ${{fromJson(needs.get-extension-matrix.outputs.matrix)}} + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Build the extension + uses: php/php-windows-builder/extension@v1 + with: + # Always specify the php-version, arch, and ts as they are required inputs. + # Please refer to https://github.com/php/php-windows-builder#build-a-php-extension + php-version: ${{ matrix.php-version }} + arch: ${{ matrix.arch }} + ts: ${{ matrix.ts }} + + # This job uploads the build artifacts to the immutable GitHub release it creates. + release: + runs-on: ubuntu-latest + needs: build + if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') }} + steps: + - name: Upload artifact to the release + uses: php/php-windows-builder/release@v1 + with: + release: ${{ github.ref }} + token: ${{ secrets.GITHUB_TOKEN }} + # Uncomment the line below to create a draft release + # draft: 'true' \ No newline at end of file diff --git a/.kiro/specs/windows-automated-releases/design.md b/.kiro/specs/windows-automated-releases/design.md new file mode 100644 index 0000000..6179e6d --- /dev/null +++ b/.kiro/specs/windows-automated-releases/design.md @@ -0,0 +1,456 @@ +# Design Document + +## Overview + +This design implements automated Windows release building for the crc_fast PHP extension using GitHub Actions. The solution consists of two main components: + +1. **Updated Test Workflow**: Modify the existing test workflow to use immutable releases of the crc_fast library instead of building from the main branch +2. **New Release Workflow**: Create a new workflow that triggers on version tags, builds Windows DLLs for multiple PHP configurations, and creates draft releases with artifacts + +The design leverages the existing `php-windows-builder` GitHub Action infrastructure and follows GitHub Actions best practices for artifact management and release creation. + +## Architecture + +### Workflow Dependency Chain + +``` +Push Tag (N.N.N) + ↓ +Test Workflow (tests.yaml) + ↓ (on success) +Release Workflow (windows-release.yaml) + ↓ +Draft Release Created with DLL Artifacts +``` + +### Component Interaction + +``` +┌─────────────────────────────────────────────────────────────┐ +│ GitHub Actions Trigger │ +│ (Tag push matching N.N.N) │ +└────────────────────────────┬────────────────────────────────┘ + │ + ↓ +┌─────────────────────────────────────────────────────────────┐ +│ Test Workflow │ +│ ┌────────────────────────────────────────────────────────┐ │ +│ │ 1. Download crc_fast library release (v1.7.0+) │ │ +│ │ 2. Extract library files │ │ +│ │ 3. Build PHP extension │ │ +│ │ 4. Run tests │ │ +│ └────────────────────────────────────────────────────────┘ │ +└────────────────────────────┬────────────────────────────────┘ + │ (on success) + ↓ +┌─────────────────────────────────────────────────────────────┐ +│ Release Workflow │ +│ ┌────────────────────────────────────────────────────────┐ │ +│ │ Job 1: Generate Extension Matrix │ │ +│ │ - Read composer.json/package.xml │ │ +│ │ - Output matrix of PHP versions/arch/ts │ │ +│ └────────────────────────────────────────────────────────┘ │ +│ ↓ │ +│ ┌────────────────────────────────────────────────────────┐ │ +│ │ Job 2: Build (Matrix) │ │ +│ │ - Download crc_fast Windows library release │ │ +│ │ - Extract to build directory │ │ +│ │ - Build extension using php-windows-builder │ │ +│ │ - Upload DLL artifacts │ │ +│ └────────────────────────────────────────────────────────┘ │ +│ ↓ │ +│ ┌────────────────────────────────────────────────────────┐ │ +│ │ Job 3: Create Draft Release │ │ +│ │ - Download all build artifacts │ │ +│ │ - Create draft GitHub release │ │ +│ │ - Upload DLL files to release │ │ +│ └────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────┘ +``` + +## Components and Interfaces + +### 1. Test Workflow Updates (.github/workflows/tests.yaml) + +**Purpose**: Modify the existing test workflow to use immutable crc_fast library releases + +**Changes Required**: +- Replace the `Checkout crc_fast library` step that clones the repository +- Add a step to download the latest release artifact from `awesomized/crc-fast-rust` +- Add a step to extract the downloaded artifact to the expected directory structure +- Remove the Rust toolchain installation and cargo build steps +- Update the library copy steps to work with pre-built artifacts + +**Interface with crc_fast Releases**: +- GitHub API endpoint: `https://api.github.com/repos/awesomized/crc-fast-rust/releases/latest` +- Expected artifact naming: `libcrc_fast-{version}-{platform}-{arch}.tar.gz` or similar +- Required files after extraction: + - `libcrc_fast.so` (Linux shared library) + - `libcrc_fast.h` (C header file) + +### 2. Release Workflow (.github/workflows/windows-release.yaml) + +**Purpose**: Build Windows DLLs and create draft releases + +**Job 1: get-extension-matrix** +- **Condition**: Only runs if workflow was triggered by a tag push matching N.N.N pattern +- **Input**: Repository files (composer.json or package.xml) +- **Action**: `php/php-windows-builder/extension-matrix@v1` +- **Output**: JSON matrix of build configurations +- **Matrix dimensions**: + - `php-version`: Array of PHP versions (e.g., ["8.1", "8.2", "8.3"]) + - `arch`: Array of architectures (e.g., ["x64", "x86"]) + - `ts`: Array of thread safety options (e.g., ["ts", "nts"]) + - `os`: Windows runner OS (pinned version for stability, e.g., "windows-2022") + +**Job 2: build** +- **Dependencies**: Requires `get-extension-matrix` job completion +- **Runs on**: Windows runners (pinned to windows-2022 for stability and backwards compatibility) +- **Steps**: + 1. Checkout repository + 2. Download crc_fast Windows library release + - Use GitHub API or direct download from releases + - Target: Latest release or specific version (1.7.0+) + - Artifact pattern: `crc-fast-{version}-windows-{arch}.zip` + - Map PHP arch to library arch: x64 → x86_64, x86 → x86_64 (32-bit uses 64-bit lib), arm64 → aarch64 + 3. Extract library files + - Extract to a known location (e.g., `C:\crc_fast`) + - Verify presence of required files: + - `include/libcrc_fast.h` + - `lib/crc_fast.lib` (static library) + 4. Build extension + - Use `php/php-windows-builder/extension@v1` + - Pass matrix parameters: php-version, arch, ts + - Pass crc_fast library path via build arguments + 5. Upload artifacts + - Artifact name pattern: `php_crc_fast-{php-version}-{arch}-{ts}.dll` + - Retention: Until release job completes + +**Job 3: release** +- **Dependencies**: Requires `build` job completion +- **Steps**: + 1. Download all build artifacts + 2. Create draft release + - Use `php/php-windows-builder/release@v1` with `draft: true` + - Release name: Tag name (e.g., "1.0.0") + - Tag: `github.ref` + 3. Upload DLL files to release + - All artifacts from build job + - Maintain naming convention for easy identification + +### 3. Integration with php-windows-builder + +**Extension Matrix Action**: +- Reads PHP version constraints from `composer.json` +- Generates matrix based on supported PHP versions +- Outputs JSON for use in build job matrix strategy + +**Extension Build Action**: +- Inputs: + - `php-version`: PHP version to build against + - `arch`: Architecture (x64 or x86) + - `ts`: Thread safety (ts or nts) + - Additional inputs for library paths (if needed) +- Process: + - Sets up PHP SDK build environment + - Runs `buildconf` in PHP source + - Runs `configure` with extension enabled + - Runs `nmake` to build + - Collects DLL artifacts +- Outputs: + - Built DLL file as GitHub Actions artifact + +**Release Action**: +- Inputs: + - `release`: GitHub ref (tag) + - `token`: GitHub token for API access + - `draft`: Set to 'true' for draft releases +- Process: + - Downloads all artifacts from previous jobs + - Creates GitHub release via API + - Uploads artifacts to release +- Outputs: + - Release URL + +## Data Models + +### Workflow Trigger Event +```yaml +on: + workflow_run: + workflows: ["Tests"] + types: [completed] + +# The workflow checks if the triggering event was a tag push +# matching N.N.N pattern before executing any jobs +``` + +### Build Matrix Structure +```json +{ + "include": [ + { + "php-version": "8.1", + "arch": "x64", + "ts": "ts", + "os": "windows-2022" + }, + { + "php-version": "8.1", + "arch": "x64", + "ts": "nts", + "os": "windows-2022" + }, + // ... additional combinations + ] +} +``` + +### Artifact Naming Convention +``` +php_crc_fast-{php-version}-{arch}-{ts}.dll + +Examples: +- php_crc_fast-8.1-x64-ts.dll +- php_crc_fast-8.2-x64-nts.dll +- php_crc_fast-8.3-x86-ts.dll +``` + +### crc_fast Library Release Structure +``` +crc-fast-{version}-windows-{arch}.zip + +Examples: +- crc-fast-1.7.0-windows-x86_64.zip +- crc-fast-1.7.0-windows-aarch64.zip + +Expected contents after extraction: +├── include/ +│ └── libcrc_fast.h +└── lib/ + └── crc_fast.lib +``` + +## Error Handling + +### Test Workflow Error Scenarios + +1. **Library Download Failure** + - **Detection**: HTTP error or missing release + - **Handling**: Fail workflow with clear error message + - **Message**: "Failed to download crc_fast library release v{version}" + +2. **Library Extraction Failure** + - **Detection**: Missing expected files after extraction + - **Handling**: Fail workflow with file listing + - **Message**: "Required library files not found: {missing_files}" + +3. **Build Failure** + - **Detection**: Non-zero exit code from make + - **Handling**: Fail workflow, preserve build logs + - **Message**: Standard make error output + +### Release Workflow Error Scenarios + +1. **Matrix Generation Failure** + - **Detection**: Empty or invalid matrix output + - **Handling**: Fail workflow before build job starts + - **Message**: "Failed to generate build matrix from composer.json" + +2. **Library Download Failure (Windows)** + - **Detection**: HTTP error or missing Windows release artifact + - **Handling**: Fail specific matrix build, continue others + - **Message**: "Failed to download Windows crc_fast library for {arch}" + +3. **Build Failure (Specific Configuration)** + - **Detection**: Non-zero exit code from php-windows-builder + - **Handling**: Mark matrix item as failed, continue others + - **Message**: Build action error output + - **Result**: Release created with available DLLs, failed builds noted + +4. **Release Creation Failure** + - **Detection**: GitHub API error + - **Handling**: Fail release job, preserve artifacts + - **Message**: "Failed to create GitHub release: {api_error}" + - **Recovery**: Artifacts remain available for manual release creation + +5. **Artifact Upload Failure** + - **Detection**: Upload error for specific DLL + - **Handling**: Log error, continue with other artifacts + - **Message**: "Failed to upload {dll_name} to release" + +### Workflow Dependency Failures + +1. **Test Workflow Failure** + - **Detection**: `workflow_run.conclusion != 'success'` + - **Handling**: Skip release workflow entirely + - **Message**: Workflow not triggered (no error message needed) + +2. **Non-Tag Push** + - **Detection**: Workflow triggered but not from a tag push matching N.N.N + - **Handling**: Skip entire workflow (no jobs execute) + - **Message**: No message (expected behavior) + +## Testing Strategy + +### Test Workflow Validation + +1. **Unit-level Testing** + - Verify library download step works with mock releases + - Verify extraction produces expected directory structure + - Verify existing tests still pass with pre-built library + +2. **Integration Testing** + - Test complete workflow on a feature branch + - Verify all test cases pass + - Compare performance with previous build-from-source approach + +3. **Regression Testing** + - Ensure all existing tests continue to pass + - Verify test output matches previous results + - Check that test execution time is reduced + +### Release Workflow Validation + +1. **Matrix Generation Testing** + - Verify matrix includes all expected PHP versions + - Verify matrix includes both architectures (x64, x86) + - Verify matrix includes both thread safety options (ts, nts) + - Test with different composer.json constraints + +2. **Build Testing** + - Test build for each matrix combination individually + - Verify DLL artifacts are created + - Verify DLL files are valid Windows PE files + - Test loading DLL in corresponding PHP version + +3. **Release Creation Testing** + - Test draft release creation with mock artifacts + - Verify all artifacts are attached to release + - Verify release is marked as draft + - Verify release can be edited and published manually + +4. **End-to-End Testing** + - Create a test tag (e.g., 0.0.1-test) + - Verify test workflow runs and passes + - Verify release workflow triggers after test success + - Verify draft release is created with all DLLs + - Verify DLLs can be downloaded and loaded + - Clean up test release + +### Error Scenario Testing + +1. **Library Download Failures** + - Test with invalid version number + - Test with missing release artifact + - Verify error messages are clear + +2. **Build Failures** + - Test with intentionally broken code + - Verify partial failures don't block other builds + - Verify artifacts from successful builds are still uploaded + +3. **Release Failures** + - Test with invalid GitHub token + - Test with duplicate release tag + - Verify artifacts are preserved for manual recovery + +### Validation Criteria + +1. **Test Workflow Success Criteria** + - All tests pass with pre-built library + - Workflow execution time is reduced (no Rust compilation) + - Library version is clearly logged in workflow output + +2. **Release Workflow Success Criteria** + - Draft release is created for version tags + - All expected DLL variants are attached + - DLLs are correctly named and organized + - Release is not automatically published + +3. **Quality Criteria** + - Built DLLs match locally-built versions (same functionality) + - DLLs load successfully in target PHP versions + - Extension functions work correctly in all configurations + - No regressions in test suite + +## Implementation Notes + +### crc_fast Library Release Discovery + +The crc_fast library releases can be accessed via: +- GitHub Releases page: `https://github.com/awesomized/crc-fast-rust/releases` +- GitHub API: `https://api.github.com/repos/awesomized/crc-fast-rust/releases/latest` +- Direct download: `https://github.com/awesomized/crc-fast-rust/releases/download/{tag}/{artifact}` + +Artifact naming patterns: +- Linux: `libcrc_fast-{version}-linux-{arch}.tar.gz` (to be verified) +- Windows: `crc-fast-{version}-windows-{arch}.zip` + - x64 architecture: `crc-fast-{version}-windows-x86_64.zip` + - ARM64 architecture: `crc-fast-{version}-windows-aarch64.zip` + +### Windows Build Environment + +The php-windows-builder action handles: +- PHP SDK setup +- Visual Studio toolchain configuration +- PHP source download and configuration +- Extension compilation +- Artifact collection + +**Windows Runner Version**: The workflow uses `windows-2022` instead of `windows-latest` to ensure: +- Predictable build environment across releases +- Maximum backwards compatibility with older Windows versions +- Protection against breaking changes when GitHub updates "latest" +- Consistent toolchain versions (Visual Studio, Windows SDK) + +The extension's `config.w32` file must properly locate the crc_fast library. This may require: +- Environment variables set by the workflow +- Command-line arguments passed to configure +- Hardcoded paths in the workflow (less flexible) + +### Draft Release Workflow + +Draft releases allow: +- Human review before publication +- Editing release notes +- Adding additional documentation +- Verifying DLL integrity +- Testing downloads before public release + +The maintainer workflow: +1. Tag is pushed +2. Workflows run automatically +3. Draft release appears in GitHub Releases +4. Maintainer reviews DLLs and release notes +5. Maintainer edits release description +6. Maintainer publishes release + +### Workflow Permissions + +Required permissions for release workflow: +```yaml +permissions: + contents: write # For creating releases and uploading assets + actions: read # For downloading artifacts from build job +``` + +### Caching Strategy + +Consider caching: +- PHP SDK downloads (handled by php-windows-builder) +- crc_fast library downloads (cache by version) +- Composer dependencies (if needed) + +Cache keys should include: +- Library version +- Architecture +- OS version + +### Monitoring and Notifications + +Consider adding: +- Workflow status badges in README +- Slack/email notifications on workflow failures +- Metrics tracking for build times +- Success rate monitoring for matrix builds diff --git a/.kiro/specs/windows-automated-releases/requirements.md b/.kiro/specs/windows-automated-releases/requirements.md new file mode 100644 index 0000000..162e19f --- /dev/null +++ b/.kiro/specs/windows-automated-releases/requirements.md @@ -0,0 +1,90 @@ +# Requirements Document + +## Introduction + +This feature enables automated building and releasing of Windows DLL artifacts for the crc_fast PHP extension through GitHub Actions. The workflow will trigger on version tags, build the extension for multiple PHP versions and architectures, create a draft GitHub release, and attach the compiled DLL artifacts. The system must use immutable releases of the crc_fast Rust library dependency rather than building from the main branch. + +## Glossary + +- **Release Workflow**: The GitHub Actions workflow that builds Windows DLLs and creates draft releases +- **Test Workflow**: The existing GitHub Actions workflow that runs tests on the extension +- **crc_fast Library**: The Rust library dependency (libcrc_fast) that provides CRC calculation functionality +- **DLL Artifact**: The compiled Windows dynamic-link library file for the PHP extension +- **Draft Release**: A GitHub release that is created but not published, allowing human review before making it public +- **Version Tag**: A Git tag matching the pattern N.N.N (e.g., 1.0.0, 2.1.3) that triggers the release workflow +- **Immutable Release**: A specific tagged version of a dependency that does not change over time +- **Extension Matrix**: A set of PHP versions, architectures, and thread safety options to build against + +## Requirements + +### Requirement 1 + +**User Story:** As a maintainer, I want the release workflow to trigger only on version tags after tests pass, so that only validated code is built and released + +#### Acceptance Criteria + +1. WHEN a Git tag matching the pattern N.N.N is pushed, THE Release Workflow SHALL trigger after the Test Workflow completes successfully +2. THE Release Workflow SHALL NOT trigger on branch pushes +3. THE Release Workflow SHALL NOT trigger on pull requests +4. WHEN the Test Workflow fails, THE Release Workflow SHALL NOT execute +5. THE Release Workflow SHALL have write permissions for repository contents to create releases + +### Requirement 2 + +**User Story:** As a maintainer, I want the Test Workflow to use immutable releases of the crc_fast library, so that test results are reproducible and not affected by changes in the main branch + +#### Acceptance Criteria + +1. THE Test Workflow SHALL download a specific tagged release of the crc_fast library instead of checking out the main branch +2. THE Test Workflow SHALL use version 1.7.0 or later of the crc_fast library +3. THE Test Workflow SHALL download pre-built library artifacts from the crc_fast GitHub releases +4. WHEN the library download fails, THE Test Workflow SHALL fail with a clear error message +5. THE Test Workflow SHALL extract the downloaded library files to the expected directory structure + +### Requirement 3 + +**User Story:** As a maintainer, I want the release workflow to download and use pre-built crc_fast library releases, so that build times are faster and more reliable than building from source + +#### Acceptance Criteria + +1. THE Release Workflow SHALL download the latest tagged release of the crc_fast library from GitHub +2. THE Release Workflow SHALL download Windows-specific pre-built library artifacts +3. THE Release Workflow SHALL extract the library files to the correct directory structure for the PHP build system +4. WHEN the library download fails, THE Release Workflow SHALL fail with a clear error message +5. THE Release Workflow SHALL verify the required library files (header and lib files) are present after extraction + +### Requirement 4 + +**User Story:** As a maintainer, I want the release workflow to build DLLs for multiple PHP versions and architectures, so that users on different PHP configurations can use the extension + +#### Acceptance Criteria + +1. THE Release Workflow SHALL generate a build matrix based on the extension's PHP version constraints +2. THE Release Workflow SHALL build the extension for each combination of PHP version, architecture, and thread safety option in the matrix +3. THE Release Workflow SHALL use the php-windows-builder GitHub Action for building +4. WHEN a build fails for any matrix combination, THE Release Workflow SHALL report the failure but continue building other combinations +5. THE Release Workflow SHALL produce DLL artifacts for each successful build + +### Requirement 5 + +**User Story:** As a maintainer, I want the release workflow to create a draft GitHub release with DLL artifacts attached, so that I can review and edit the release before publishing it to users + +#### Acceptance Criteria + +1. WHEN all builds complete, THE Release Workflow SHALL create a draft GitHub release +2. THE Release Workflow SHALL name the release using the version tag that triggered the workflow +3. THE Release Workflow SHALL upload all built DLL artifacts to the draft release +4. THE Release Workflow SHALL NOT automatically publish the release +5. THE Release Workflow SHALL allow the maintainer to manually review, edit, and publish the release through the GitHub interface + +### Requirement 6 + +**User Story:** As a maintainer, I want the release workflow to follow the same build configuration as local Windows builds, so that CI-built DLLs behave identically to locally-built ones + +#### Acceptance Criteria + +1. THE Release Workflow SHALL use the config.w32 build configuration file +2. THE Release Workflow SHALL compile with C++17 standard support +3. THE Release Workflow SHALL define ZEND_ENABLE_STATIC_TSRMLS_CACHE=1 during compilation +4. THE Release Workflow SHALL define CRC_FAST_EXCEPTIONS=0 during compilation +5. THE Release Workflow SHALL define CRC_FAST_DEVELOPMENT_CHECKS=0 during compilation diff --git a/.kiro/specs/windows-automated-releases/tasks.md b/.kiro/specs/windows-automated-releases/tasks.md new file mode 100644 index 0000000..ad195f7 --- /dev/null +++ b/.kiro/specs/windows-automated-releases/tasks.md @@ -0,0 +1,81 @@ +# Implementation Plan + +- [ ] 1. Update Test Workflow to use immutable crc_fast library releases + - Modify `.github/workflows/tests.yaml` to download pre-built library artifacts instead of building from source + - Replace the repository checkout step with a release download step + - Remove Rust toolchain installation and cargo build steps + - Update library file copy steps to work with extracted release artifacts + - _Requirements: 2.1, 2.2, 2.3, 2.4, 2.5_ + +- [ ] 2. Create Windows Release Workflow file structure + - Create `.github/workflows/windows-release.yaml` file + - Configure workflow to trigger on `workflow_run` completion of Tests workflow + - Set up workflow permissions for contents write and actions read + - Add condition to check if triggering event was a tag push matching N.N.N pattern + - _Requirements: 1.1, 1.2, 1.3, 1.4, 1.5_ + +- [ ] 3. Implement extension matrix generation job +- [ ] 3.1 Create get-extension-matrix job + - Configure job to run on ubuntu-latest + - Add condition to only run on tag pushes matching N.N.N + - Use `php/php-windows-builder/extension-matrix@v1` action + - Define matrix output for use by build job + - _Requirements: 4.1, 4.2_ + +- [ ] 4. Implement Windows build job with crc_fast library integration +- [ ] 4.1 Set up build job matrix configuration + - Configure job to depend on get-extension-matrix + - Set up matrix strategy using output from matrix job + - Pin runner to windows-2022 for stability + - _Requirements: 4.1, 4.2, 4.3, 6.1, 6.2, 6.3, 6.4, 6.5_ + +- [ ] 4.2 Add crc_fast library download and extraction steps + - Add step to download crc-fast Windows release artifact from GitHub + - Map PHP architecture to library architecture (x64→x86_64, arm64→aarch64) + - Extract library files to build directory + - Verify presence of required header and lib files + - _Requirements: 3.1, 3.2, 3.3, 3.4, 3.5_ + +- [ ] 4.3 Configure extension build with php-windows-builder + - Use `php/php-windows-builder/extension@v1` action + - Pass matrix parameters (php-version, arch, ts) + - Configure library path for config.w32 to find crc_fast + - Upload built DLL artifacts with descriptive names + - _Requirements: 4.4, 4.5, 6.1, 6.2, 6.3, 6.4, 6.5_ + +- [ ] 5. Implement draft release creation job +- [ ] 5.1 Create release job with artifact collection + - Configure job to depend on build job completion + - Run on ubuntu-latest + - Download all DLL artifacts from build job + - _Requirements: 5.1, 5.2, 5.3_ + +- [ ] 5.2 Create draft release with DLL uploads + - Use `php/php-windows-builder/release@v1` action with draft: true + - Set release name to tag name + - Upload all DLL artifacts to the draft release + - Ensure release is not automatically published + - _Requirements: 5.1, 5.2, 5.3, 5.4, 5.5_ + +- [ ]* 6. Test and validate workflows +- [ ]* 6.1 Test updated Test Workflow + - Create a test branch and verify test workflow runs successfully + - Verify library download and extraction works correctly + - Confirm all existing tests pass with pre-built library + - _Requirements: 2.1, 2.2, 2.3, 2.4, 2.5_ + +- [ ]* 6.2 Test Release Workflow with test tag + - Create a test tag (e.g., 0.0.1-test) to trigger workflow + - Verify workflow only runs after tests pass + - Verify matrix generation produces expected configurations + - Verify builds complete for all matrix combinations + - Verify draft release is created with all DLL artifacts + - _Requirements: 1.1, 1.2, 1.3, 1.4, 4.1, 4.2, 4.3, 4.4, 4.5, 5.1, 5.2, 5.3, 5.4, 5.5_ + +- [ ]* 6.3 Validate DLL artifacts + - Download DLLs from draft release + - Verify DLL files are valid Windows PE files + - Test loading DLLs in corresponding PHP versions + - Verify extension functions work correctly + - Clean up test release after validation + - _Requirements: 4.5, 5.3, 6.1, 6.2, 6.3, 6.4, 6.5_ From d0475dff3c275efd2be8d2e8a228ccb67179f055 Mon Sep 17 00:00:00 2001 From: Don MacAskill Date: Mon, 10 Nov 2025 15:31:55 -0800 Subject: [PATCH 02/14] Update Test Workflow to use immutable crc_fast library releases --- .github/workflows/tests.yaml | 77 ++++++++++++------- .../specs/windows-automated-releases/tasks.md | 2 +- 2 files changed, 49 insertions(+), 30 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index c3074a1..837453c 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -14,35 +14,54 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 # not pinning to commit since this is a GitHub action, which we trust - - name: Checkout crc_fast library - uses: actions/checkout@v4 # not pinning to commit since this is a GitHub action, which we trust - with: - repository: awesomized/crc-fast-rust - path: lib-crc-fast - - id: cache-cargo - name: Cache Rust Cargo toolchain - uses: actions/cache@v4 # not pinning to commit since this is a GitHub action, which we trust - with: - path: | - ~/.cargo/bin/ - ~/.cargo/registry/index/ - ~/.cargo/registry/cache/ - ~/.cargo/git/db/ - target/ - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-release - - if: ${{ steps.cache-cargo.outputs.cache-hit != 'true' }} - name: Install Rust toolchain - uses: actions-rs/toolchain@v1 # not pinning to commit since this is an archived GitHub action, which we trust - with: - profile: minimal - toolchain: stable - override: true - - name: Build crc_fast library - run: cd lib-crc-fast && cargo build --release - - name: Copy shared library - run: mkdir lib && cp lib-crc-fast/target/release/libcrc_fast.so lib/ - - name: Copy C/C++ header - run: mkdir include && cp lib-crc-fast/libcrc_fast.h include/ + - name: Download crc_fast library release + run: | + ARCH="x86_64" + PLATFORM="linux" + + # Fetch the latest release version + echo "Fetching latest crc_fast library release..." + LATEST_RELEASE=$(curl -sL https://api.github.com/repos/awesomized/crc-fast-rust/releases/latest | grep '"tag_name":' | sed -E 's/.*"tag_name": "([^"]+)".*/\1/') + + if [ -z "$LATEST_RELEASE" ]; then + echo "Error: Failed to fetch latest release version" + exit 1 + fi + + echo "Latest release: ${LATEST_RELEASE}" + + ARTIFACT_NAME="crc-fast-${LATEST_RELEASE}-${PLATFORM}-${ARCH}.tar.gz" + DOWNLOAD_URL="https://github.com/awesomized/crc-fast-rust/releases/download/${LATEST_RELEASE}/${ARTIFACT_NAME}" + + echo "Downloading crc_fast library ${LATEST_RELEASE} for ${PLATFORM}-${ARCH}" + curl -sL -o crc-fast.tar.gz "${DOWNLOAD_URL}" || { + echo "Error: Failed to download crc_fast library release ${LATEST_RELEASE}" + exit 1 + } + + # Save version for next step + echo "CRC_FAST_VERSION=${LATEST_RELEASE}" >> $GITHUB_ENV + - name: Extract crc_fast library + run: | + tar -xzf crc-fast.tar.gz + EXTRACT_DIR="crc-fast-${CRC_FAST_VERSION}-linux-x86_64" + + # Verify required files exist + if [ ! -f "${EXTRACT_DIR}/include/libcrc_fast.h" ]; then + echo "Error: Required header file not found: ${EXTRACT_DIR}/include/libcrc_fast.h" + exit 1 + fi + if [ ! -f "${EXTRACT_DIR}/lib/libcrc_fast.so" ]; then + echo "Error: Required library file not found: ${EXTRACT_DIR}/lib/libcrc_fast.so" + exit 1 + fi + + # Copy files to expected locations + mkdir -p lib include + cp "${EXTRACT_DIR}/lib/libcrc_fast.so" lib/ + cp "${EXTRACT_DIR}/include/libcrc_fast.h" include/ + + echo "Successfully extracted crc_fast library ${CRC_FAST_VERSION}" - name: Phpize run: phpize - name: Configure diff --git a/.kiro/specs/windows-automated-releases/tasks.md b/.kiro/specs/windows-automated-releases/tasks.md index ad195f7..cd893f8 100644 --- a/.kiro/specs/windows-automated-releases/tasks.md +++ b/.kiro/specs/windows-automated-releases/tasks.md @@ -1,6 +1,6 @@ # Implementation Plan -- [ ] 1. Update Test Workflow to use immutable crc_fast library releases +- [x] 1. Update Test Workflow to use immutable crc_fast library releases - Modify `.github/workflows/tests.yaml` to download pre-built library artifacts instead of building from source - Replace the repository checkout step with a release download step - Remove Rust toolchain installation and cargo build steps From 1cd3e83b9f224c713980ad3d206dafc89bd40653 Mon Sep 17 00:00:00 2001 From: Don MacAskill Date: Mon, 10 Nov 2025 15:33:43 -0800 Subject: [PATCH 03/14] Create Windows Release Workflow file structure --- .github/workflows/windows-release.yaml | 43 +++++++++++++++++++ .../specs/windows-automated-releases/tasks.md | 2 +- 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/windows-release.yaml diff --git a/.github/workflows/windows-release.yaml b/.github/workflows/windows-release.yaml new file mode 100644 index 0000000..ae4ed7e --- /dev/null +++ b/.github/workflows/windows-release.yaml @@ -0,0 +1,43 @@ +name: Windows Release + +on: + workflow_run: + workflows: ["Tests"] + types: [completed] + +permissions: + contents: write # For creating releases and uploading assets + actions: read # For downloading artifacts from build job + +jobs: + # Check if this workflow should run (only on successful test runs triggered by version tags) + check-trigger: + runs-on: ubuntu-latest + if: | + github.event.workflow_run.conclusion == 'success' && + github.event.workflow_run.event == 'push' && + startsWith(github.event.workflow_run.head_branch, 'refs/tags/') && + contains(github.event.workflow_run.head_branch, '.') + outputs: + should_run: ${{ steps.check.outputs.should_run }} + tag_name: ${{ steps.check.outputs.tag_name }} + steps: + - name: Check if triggered by version tag + id: check + run: | + # Extract tag name from the branch ref + TAG_REF="${{ github.event.workflow_run.head_branch }}" + TAG_NAME="${TAG_REF#refs/tags/}" + + echo "Tag reference: ${TAG_REF}" + echo "Tag name: ${TAG_NAME}" + + # Check if tag matches N.N.N pattern (semantic version) + if [[ "${TAG_NAME}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "Valid version tag detected: ${TAG_NAME}" + echo "should_run=true" >> $GITHUB_OUTPUT + echo "tag_name=${TAG_NAME}" >> $GITHUB_OUTPUT + else + echo "Not a valid version tag (N.N.N pattern): ${TAG_NAME}" + echo "should_run=false" >> $GITHUB_OUTPUT + fi diff --git a/.kiro/specs/windows-automated-releases/tasks.md b/.kiro/specs/windows-automated-releases/tasks.md index cd893f8..6aaa6f5 100644 --- a/.kiro/specs/windows-automated-releases/tasks.md +++ b/.kiro/specs/windows-automated-releases/tasks.md @@ -7,7 +7,7 @@ - Update library file copy steps to work with extracted release artifacts - _Requirements: 2.1, 2.2, 2.3, 2.4, 2.5_ -- [ ] 2. Create Windows Release Workflow file structure +- [x] 2. Create Windows Release Workflow file structure - Create `.github/workflows/windows-release.yaml` file - Configure workflow to trigger on `workflow_run` completion of Tests workflow - Set up workflow permissions for contents write and actions read From 9675e5916a63850ef9895dd5e7a2ac97e0b20d76 Mon Sep 17 00:00:00 2001 From: Don MacAskill Date: Mon, 10 Nov 2025 15:41:36 -0800 Subject: [PATCH 04/14] Implement extension matrix generation job --- .github/workflows/windows-release.yaml | 16 ++++++++++++++++ .kiro/specs/windows-automated-releases/tasks.md | 4 ++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/.github/workflows/windows-release.yaml b/.github/workflows/windows-release.yaml index ae4ed7e..ec44bae 100644 --- a/.github/workflows/windows-release.yaml +++ b/.github/workflows/windows-release.yaml @@ -41,3 +41,19 @@ jobs: echo "Not a valid version tag (N.N.N pattern): ${TAG_NAME}" echo "should_run=false" >> $GITHUB_OUTPUT fi + + get-extension-matrix: + runs-on: ubuntu-latest + needs: check-trigger + if: needs.check-trigger.outputs.should_run == 'true' + outputs: + matrix: ${{ steps.extension-matrix.outputs.matrix }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + ref: ${{ needs.check-trigger.outputs.tag_name }} + + - name: Generate extension build matrix + id: extension-matrix + uses: php/php-windows-builder/extension-matrix@v1 diff --git a/.kiro/specs/windows-automated-releases/tasks.md b/.kiro/specs/windows-automated-releases/tasks.md index 6aaa6f5..96a2a3e 100644 --- a/.kiro/specs/windows-automated-releases/tasks.md +++ b/.kiro/specs/windows-automated-releases/tasks.md @@ -14,8 +14,8 @@ - Add condition to check if triggering event was a tag push matching N.N.N pattern - _Requirements: 1.1, 1.2, 1.3, 1.4, 1.5_ -- [ ] 3. Implement extension matrix generation job -- [ ] 3.1 Create get-extension-matrix job +- [x] 3. Implement extension matrix generation job +- [x] 3.1 Create get-extension-matrix job - Configure job to run on ubuntu-latest - Add condition to only run on tag pushes matching N.N.N - Use `php/php-windows-builder/extension-matrix@v1` action From e43d7af898952e68ab15cf91e5e3f6b783388afb Mon Sep 17 00:00:00 2001 From: Don MacAskill Date: Mon, 10 Nov 2025 15:45:17 -0800 Subject: [PATCH 05/14] Set up build job matrix configuration --- .github/workflows/windows-release.yaml | 12 ++++++++++++ .kiro/specs/windows-automated-releases/tasks.md | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/workflows/windows-release.yaml b/.github/workflows/windows-release.yaml index ec44bae..86f987e 100644 --- a/.github/workflows/windows-release.yaml +++ b/.github/workflows/windows-release.yaml @@ -57,3 +57,15 @@ jobs: - name: Generate extension build matrix id: extension-matrix uses: php/php-windows-builder/extension-matrix@v1 + + build: + runs-on: windows-2022 + needs: get-extension-matrix + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.get-extension-matrix.outputs.matrix) }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + ref: ${{ needs.check-trigger.outputs.tag_name }} diff --git a/.kiro/specs/windows-automated-releases/tasks.md b/.kiro/specs/windows-automated-releases/tasks.md index 96a2a3e..8d1f2c5 100644 --- a/.kiro/specs/windows-automated-releases/tasks.md +++ b/.kiro/specs/windows-automated-releases/tasks.md @@ -23,7 +23,7 @@ - _Requirements: 4.1, 4.2_ - [ ] 4. Implement Windows build job with crc_fast library integration -- [ ] 4.1 Set up build job matrix configuration +- [x] 4.1 Set up build job matrix configuration - Configure job to depend on get-extension-matrix - Set up matrix strategy using output from matrix job - Pin runner to windows-2022 for stability From 968e3baa442af23ccc8f9a63f58ad9693be1d13e Mon Sep 17 00:00:00 2001 From: Don MacAskill Date: Mon, 10 Nov 2025 15:51:07 -0800 Subject: [PATCH 06/14] Add crc_fast library download and extraction steps --- .github/workflows/windows-release.yaml | 116 +++++++++++++++++- .../specs/windows-automated-releases/tasks.md | 2 +- 2 files changed, 116 insertions(+), 2 deletions(-) diff --git a/.github/workflows/windows-release.yaml b/.github/workflows/windows-release.yaml index 86f987e..d180067 100644 --- a/.github/workflows/windows-release.yaml +++ b/.github/workflows/windows-release.yaml @@ -60,7 +60,7 @@ jobs: build: runs-on: windows-2022 - needs: get-extension-matrix + needs: [check-trigger, get-extension-matrix] strategy: fail-fast: false matrix: ${{ fromJson(needs.get-extension-matrix.outputs.matrix) }} @@ -69,3 +69,117 @@ jobs: uses: actions/checkout@v4 with: ref: ${{ needs.check-trigger.outputs.tag_name }} + + - name: Map PHP architecture to library architecture + id: map-arch + shell: pwsh + run: | + $phpArch = "${{ matrix.arch }}" + + # Check if architecture is supported + if ($phpArch -eq "x86") { + echo "ERROR: 32-bit x86 builds are not supported" + echo "The crc_fast library does not provide 32-bit Windows releases" + echo "Supported architectures: x64, arm64" + exit 1 + } + + $libArch = switch ($phpArch) { + "x64" { "x86_64" } + "arm64" { "aarch64" } + default { "x86_64" } + } + echo "lib_arch=$libArch" >> $env:GITHUB_OUTPUT + echo "Mapped PHP arch '$phpArch' to library arch '$libArch'" + + - name: Download crc_fast Windows library release + shell: pwsh + run: | + $libArch = "${{ steps.map-arch.outputs.lib_arch }}" + + # Get the latest release information from GitHub API + $releaseUrl = "https://api.github.com/repos/awesomized/crc-fast-rust/releases/latest" + $release = Invoke-RestMethod -Uri $releaseUrl -Headers @{ + "Accept" = "application/vnd.github+json" + "User-Agent" = "GitHub-Actions" + } + + $version = $release.tag_name + echo "Latest crc_fast library version: $version" + + # Find the Windows artifact for the target architecture + $artifactName = "crc-fast-$version-windows-$libArch.zip" + $asset = $release.assets | Where-Object { $_.name -eq $artifactName } + + if (-not $asset) { + echo "ERROR: Could not find artifact '$artifactName' in release $version" + echo "Available assets:" + $release.assets | ForEach-Object { echo " - $($_.name)" } + exit 1 + } + + $downloadUrl = $asset.browser_download_url + echo "Downloading from: $downloadUrl" + + # Download the artifact + $outputPath = "crc_fast_lib.zip" + Invoke-WebRequest -Uri $downloadUrl -OutFile $outputPath -Headers @{ + "Accept" = "application/octet-stream" + "User-Agent" = "GitHub-Actions" + } + + if (-not (Test-Path $outputPath)) { + echo "ERROR: Failed to download crc_fast library" + exit 1 + } + + echo "Successfully downloaded crc_fast library ($([math]::Round((Get-Item $outputPath).Length / 1MB, 2)) MB)" + + - name: Extract crc_fast library files + shell: pwsh + run: | + $extractPath = "C:\crc_fast" + + # Create extraction directory + New-Item -ItemType Directory -Force -Path $extractPath | Out-Null + + # Extract the zip file + echo "Extracting crc_fast library to $extractPath" + Expand-Archive -Path "crc_fast_lib.zip" -DestinationPath $extractPath -Force + + # List extracted contents for debugging + echo "Extracted contents:" + Get-ChildItem -Recurse $extractPath | ForEach-Object { echo " $($_.FullName)" } + + - name: Verify required library files + shell: pwsh + run: | + $extractPath = "C:\crc_fast" + $requiredFiles = @( + "include\libcrc_fast.h", + "lib\crc_fast.lib" + ) + + $missingFiles = @() + foreach ($file in $requiredFiles) { + $fullPath = Join-Path $extractPath $file + if (-not (Test-Path $fullPath)) { + $missingFiles += $file + echo "MISSING: $file" + } else { + echo "FOUND: $file" + } + } + + if ($missingFiles.Count -gt 0) { + echo "" + echo "ERROR: Required library files not found after extraction:" + $missingFiles | ForEach-Object { echo " - $_" } + echo "" + echo "Directory structure:" + Get-ChildItem -Recurse $extractPath | ForEach-Object { echo " $($_.FullName)" } + exit 1 + } + + echo "" + echo "All required library files verified successfully" diff --git a/.kiro/specs/windows-automated-releases/tasks.md b/.kiro/specs/windows-automated-releases/tasks.md index 8d1f2c5..94ce1dc 100644 --- a/.kiro/specs/windows-automated-releases/tasks.md +++ b/.kiro/specs/windows-automated-releases/tasks.md @@ -29,7 +29,7 @@ - Pin runner to windows-2022 for stability - _Requirements: 4.1, 4.2, 4.3, 6.1, 6.2, 6.3, 6.4, 6.5_ -- [ ] 4.2 Add crc_fast library download and extraction steps +- [x] 4.2 Add crc_fast library download and extraction steps - Add step to download crc-fast Windows release artifact from GitHub - Map PHP architecture to library architecture (x64→x86_64, arm64→aarch64) - Extract library files to build directory From 8871bbdf07878d36aa0967da89805ef5db0acd69 Mon Sep 17 00:00:00 2001 From: Don MacAskill Date: Mon, 10 Nov 2025 15:53:06 -0800 Subject: [PATCH 07/14] Configure extension build with php-windows-builder --- .github/workflows/windows-release.yaml | 16 ++++++++++++++++ .kiro/specs/windows-automated-releases/tasks.md | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/.github/workflows/windows-release.yaml b/.github/workflows/windows-release.yaml index d180067..ea59909 100644 --- a/.github/workflows/windows-release.yaml +++ b/.github/workflows/windows-release.yaml @@ -183,3 +183,19 @@ jobs: echo "" echo "All required library files verified successfully" + + - name: Build extension with php-windows-builder + uses: php/php-windows-builder/extension@v1 + with: + php-version: ${{ matrix.php-version }} + arch: ${{ matrix.arch }} + ts: ${{ matrix.ts }} + args: --with-crc-fast=C:\crc_fast + + - name: Upload DLL artifact + uses: actions/upload-artifact@v4 + with: + name: php_crc_fast-${{ matrix.php-version }}-${{ matrix.arch }}-${{ matrix.ts }} + path: | + ${{ matrix.arch }}/Release*/php_crc_fast.dll + if-no-files-found: error diff --git a/.kiro/specs/windows-automated-releases/tasks.md b/.kiro/specs/windows-automated-releases/tasks.md index 94ce1dc..4a98d2e 100644 --- a/.kiro/specs/windows-automated-releases/tasks.md +++ b/.kiro/specs/windows-automated-releases/tasks.md @@ -36,7 +36,7 @@ - Verify presence of required header and lib files - _Requirements: 3.1, 3.2, 3.3, 3.4, 3.5_ -- [ ] 4.3 Configure extension build with php-windows-builder +- [x] 4.3 Configure extension build with php-windows-builder - Use `php/php-windows-builder/extension@v1` action - Pass matrix parameters (php-version, arch, ts) - Configure library path for config.w32 to find crc_fast From 0edf93b674241f5e6544d3a473d871038b45e723 Mon Sep 17 00:00:00 2001 From: Don MacAskill Date: Mon, 10 Nov 2025 15:54:14 -0800 Subject: [PATCH 08/14] Create release job with artifact collection --- .github/workflows/windows-release.yaml | 12 ++++++++++++ .kiro/specs/windows-automated-releases/tasks.md | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/workflows/windows-release.yaml b/.github/workflows/windows-release.yaml index ea59909..74f7e59 100644 --- a/.github/workflows/windows-release.yaml +++ b/.github/workflows/windows-release.yaml @@ -199,3 +199,15 @@ jobs: path: | ${{ matrix.arch }}/Release*/php_crc_fast.dll if-no-files-found: error + + release: + runs-on: ubuntu-latest + needs: [check-trigger, build] + if: needs.check-trigger.outputs.should_run == 'true' + steps: + - name: Download all DLL artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + pattern: php_crc_fast-* + merge-multiple: false diff --git a/.kiro/specs/windows-automated-releases/tasks.md b/.kiro/specs/windows-automated-releases/tasks.md index 4a98d2e..b8f1bbf 100644 --- a/.kiro/specs/windows-automated-releases/tasks.md +++ b/.kiro/specs/windows-automated-releases/tasks.md @@ -44,7 +44,7 @@ - _Requirements: 4.4, 4.5, 6.1, 6.2, 6.3, 6.4, 6.5_ - [ ] 5. Implement draft release creation job -- [ ] 5.1 Create release job with artifact collection +- [x] 5.1 Create release job with artifact collection - Configure job to depend on build job completion - Run on ubuntu-latest - Download all DLL artifacts from build job From c9c64960fb2cc67023b087cc6d1b6cbb58e7b464 Mon Sep 17 00:00:00 2001 From: Don MacAskill Date: Mon, 10 Nov 2025 16:01:26 -0800 Subject: [PATCH 09/14] Create draft release with DLL uploads --- .github/workflows/windows-release.yaml | 8 ++++++++ .kiro/specs/windows-automated-releases/tasks.md | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/windows-release.yaml b/.github/workflows/windows-release.yaml index 74f7e59..f82a09a 100644 --- a/.github/workflows/windows-release.yaml +++ b/.github/workflows/windows-release.yaml @@ -211,3 +211,11 @@ jobs: path: artifacts pattern: php_crc_fast-* merge-multiple: false + + - name: Create draft release with DLL uploads + uses: php/php-windows-builder/release@v1 + with: + release: ${{ needs.check-trigger.outputs.tag_name }} + token: ${{ secrets.GITHUB_TOKEN }} + draft: true + artifacts: artifacts/**/*.dll diff --git a/.kiro/specs/windows-automated-releases/tasks.md b/.kiro/specs/windows-automated-releases/tasks.md index b8f1bbf..bbab79f 100644 --- a/.kiro/specs/windows-automated-releases/tasks.md +++ b/.kiro/specs/windows-automated-releases/tasks.md @@ -43,14 +43,14 @@ - Upload built DLL artifacts with descriptive names - _Requirements: 4.4, 4.5, 6.1, 6.2, 6.3, 6.4, 6.5_ -- [ ] 5. Implement draft release creation job +- [x] 5. Implement draft release creation job - [x] 5.1 Create release job with artifact collection - Configure job to depend on build job completion - Run on ubuntu-latest - Download all DLL artifacts from build job - _Requirements: 5.1, 5.2, 5.3_ -- [ ] 5.2 Create draft release with DLL uploads +- [x] 5.2 Create draft release with DLL uploads - Use `php/php-windows-builder/release@v1` action with draft: true - Set release name to tag name - Upload all DLL artifacts to the draft release From b8946d7c85619c47780584e9cce123df4ee0933f Mon Sep 17 00:00:00 2001 From: Don MacAskill Date: Mon, 10 Nov 2025 16:09:18 -0800 Subject: [PATCH 10/14] Enable workflow_dispatch --- .github/workflows/windows-release.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/windows-release.yaml b/.github/workflows/windows-release.yaml index f82a09a..faab8fb 100644 --- a/.github/workflows/windows-release.yaml +++ b/.github/workflows/windows-release.yaml @@ -1,6 +1,8 @@ name: Windows Release on: + workflow_dispatch: + # used when called manually. workflow_run: workflows: ["Tests"] types: [completed] From 59d410a8efc2ec738fb91fa4690107182122c387 Mon Sep 17 00:00:00 2001 From: Don MacAskill Date: Mon, 10 Nov 2025 16:15:42 -0800 Subject: [PATCH 11/14] Remove example workflow --- .../workflows/example_php_windows_builder.yml | 63 ------------------- 1 file changed, 63 deletions(-) delete mode 100644 .github/workflows/example_php_windows_builder.yml diff --git a/.github/workflows/example_php_windows_builder.yml b/.github/workflows/example_php_windows_builder.yml deleted file mode 100644 index 2796ba9..0000000 --- a/.github/workflows/example_php_windows_builder.yml +++ /dev/null @@ -1,63 +0,0 @@ -# This is an EXAMPLE workflow to build a PHP extension for Windows using GitHub Actions and must be modified prior to use. -# It comes from `php-windows-builder` found at https://github.com/php/php-windows-builder - -name: Build extension -on: - # When a new tag is pushed, we can build, and upload the DLLs to it. - push: - # branches: ['**'] # Uncomment this to run on push to a branch - tags: ['*'] - # create: # Uncomment this to run on tag/branch creation - # pull_request: # Uncomment this to run on pull requests - -permissions: - contents: write - -jobs: - # This job generates a matrix of PHP versions, architectures, and thread safety options - # This is done by reading the constraints from composer.json or the package.xml file. - # Please refer to https://github.com/php/php-windows-builder#get-the-job-matrix-to-build-a-php-extension - get-extension-matrix: - runs-on: ubuntu-latest - outputs: - matrix: ${{ steps.extension-matrix.outputs.matrix }} - steps: - - name: Checkout - uses: actions/checkout@v5 - - - name: Get the extension matrix - id: extension-matrix - uses: php/php-windows-builder/extension-matrix@v1 - - # This job builds the extension on Windows using the matrix generated from the previous job. - build: - needs: get-extension-matrix - runs-on: ${{ matrix.os }} - strategy: - matrix: ${{fromJson(needs.get-extension-matrix.outputs.matrix)}} - steps: - - name: Checkout - uses: actions/checkout@v5 - - - name: Build the extension - uses: php/php-windows-builder/extension@v1 - with: - # Always specify the php-version, arch, and ts as they are required inputs. - # Please refer to https://github.com/php/php-windows-builder#build-a-php-extension - php-version: ${{ matrix.php-version }} - arch: ${{ matrix.arch }} - ts: ${{ matrix.ts }} - - # This job uploads the build artifacts to the immutable GitHub release it creates. - release: - runs-on: ubuntu-latest - needs: build - if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') }} - steps: - - name: Upload artifact to the release - uses: php/php-windows-builder/release@v1 - with: - release: ${{ github.ref }} - token: ${{ secrets.GITHUB_TOKEN }} - # Uncomment the line below to create a draft release - # draft: 'true' \ No newline at end of file From 5abecf1959bf2c8f9ba7de744a1871ee468c6a0a Mon Sep 17 00:00:00 2001 From: Don MacAskill Date: Mon, 10 Nov 2025 16:19:19 -0800 Subject: [PATCH 12/14] WIP. Debug Windows Release workflow WIP. Debug Windows Release workflow. WIP. Debug Windows Release workflow. WIP. Debug Windows Release workflow --- .github/workflows/windows-release.yaml | 75 +++++++++++++++++++------- 1 file changed, 55 insertions(+), 20 deletions(-) diff --git a/.github/workflows/windows-release.yaml b/.github/workflows/windows-release.yaml index faab8fb..32139e8 100644 --- a/.github/workflows/windows-release.yaml +++ b/.github/workflows/windows-release.yaml @@ -15,32 +15,38 @@ jobs: # Check if this workflow should run (only on successful test runs triggered by version tags) check-trigger: runs-on: ubuntu-latest - if: | - github.event.workflow_run.conclusion == 'success' && - github.event.workflow_run.event == 'push' && - startsWith(github.event.workflow_run.head_branch, 'refs/tags/') && - contains(github.event.workflow_run.head_branch, '.') + if: github.event.workflow_run.conclusion == 'success' outputs: should_run: ${{ steps.check.outputs.should_run }} tag_name: ${{ steps.check.outputs.tag_name }} steps: + - name: Debug workflow_run event + run: | + echo "Event name: ${{ github.event.workflow_run.event }}" + echo "Head branch: ${{ github.event.workflow_run.head_branch }}" + echo "Head SHA: ${{ github.event.workflow_run.head_sha }}" + echo "Conclusion: ${{ github.event.workflow_run.conclusion }}" + echo "Full event context:" + echo '${{ toJson(github.event.workflow_run) }}' + - name: Check if triggered by version tag id: check run: | - # Extract tag name from the branch ref - TAG_REF="${{ github.event.workflow_run.head_branch }}" - TAG_NAME="${TAG_REF#refs/tags/}" + # The head_branch contains the tag name directly (e.g., "0.0.1"), not "refs/tags/0.0.1" + # when the workflow is triggered by a tag push + HEAD_BRANCH="${{ github.event.workflow_run.head_branch }}" + EVENT_TYPE="${{ github.event.workflow_run.event }}" - echo "Tag reference: ${TAG_REF}" - echo "Tag name: ${TAG_NAME}" + echo "Event type: ${EVENT_TYPE}" + echo "Head branch: ${HEAD_BRANCH}" - # Check if tag matches N.N.N pattern (semantic version) - if [[ "${TAG_NAME}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then - echo "Valid version tag detected: ${TAG_NAME}" + # Check if this was triggered by a push event and the branch name looks like a version tag + if [[ "${EVENT_TYPE}" == "push" ]] && [[ "${HEAD_BRANCH}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "Valid version tag detected: ${HEAD_BRANCH}" echo "should_run=true" >> $GITHUB_OUTPUT - echo "tag_name=${TAG_NAME}" >> $GITHUB_OUTPUT + echo "tag_name=${HEAD_BRANCH}" >> $GITHUB_OUTPUT else - echo "Not a valid version tag (N.N.N pattern): ${TAG_NAME}" + echo "Not a valid version tag push. Event: ${EVENT_TYPE}, Branch: ${HEAD_BRANCH}" echo "should_run=false" >> $GITHUB_OUTPUT fi @@ -56,9 +62,20 @@ jobs: with: ref: ${{ needs.check-trigger.outputs.tag_name }} + - name: Debug - Show composer.json + run: | + echo "=== composer.json contents ===" + cat composer.json + echo "" + echo "=== PHP version requirement ===" + grep -A 1 '"require"' composer.json + - name: Generate extension build matrix id: extension-matrix uses: php/php-windows-builder/extension-matrix@v1 + with: + arch-list: 'x64, arm64' + php-version-list: "8.1, 8.2, 8.3, 8.4" # reading from composer.json doesn't seem to work? build: runs-on: windows-2022 @@ -141,16 +158,34 @@ jobs: shell: pwsh run: | $extractPath = "C:\crc_fast" + $tempExtractPath = "C:\crc_fast_temp" + + # Create temporary extraction directory + New-Item -ItemType Directory -Force -Path $tempExtractPath | Out-Null + + # Extract the zip file to temp location + echo "Extracting crc_fast library to temporary location" + Expand-Archive -Path "crc_fast_lib.zip" -DestinationPath $tempExtractPath -Force + + # Find the versioned subdirectory (e.g., crc-fast-1.7.0-windows-x86_64) + $versionedDir = Get-ChildItem -Path $tempExtractPath -Directory | Select-Object -First 1 + + if (-not $versionedDir) { + echo "ERROR: No subdirectory found after extraction" + exit 1 + } + + echo "Found versioned directory: $($versionedDir.Name)" - # Create extraction directory + # Move contents from versioned directory to final location New-Item -ItemType Directory -Force -Path $extractPath | Out-Null + Move-Item -Path "$($versionedDir.FullName)\*" -Destination $extractPath -Force - # Extract the zip file - echo "Extracting crc_fast library to $extractPath" - Expand-Archive -Path "crc_fast_lib.zip" -DestinationPath $extractPath -Force + # Clean up temp directory + Remove-Item -Recurse -Force $tempExtractPath # List extracted contents for debugging - echo "Extracted contents:" + echo "Final directory structure:" Get-ChildItem -Recurse $extractPath | ForEach-Object { echo " $($_.FullName)" } - name: Verify required library files From c4ae5aafb4bb1ca4f6757fb3ec9b52d8a4d8733a Mon Sep 17 00:00:00 2001 From: Don MacAskill Date: Mon, 10 Nov 2025 19:42:02 -0800 Subject: [PATCH 13/14] Update .github/workflows/windows-release.yaml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/windows-release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/windows-release.yaml b/.github/workflows/windows-release.yaml index 32139e8..6638f44 100644 --- a/.github/workflows/windows-release.yaml +++ b/.github/workflows/windows-release.yaml @@ -15,7 +15,7 @@ jobs: # Check if this workflow should run (only on successful test runs triggered by version tags) check-trigger: runs-on: ubuntu-latest - if: github.event.workflow_run.conclusion == 'success' + if: github.event.workflow_run.conclusion == 'success' || github.event_name == 'workflow_dispatch' outputs: should_run: ${{ steps.check.outputs.should_run }} tag_name: ${{ steps.check.outputs.tag_name }} From 63da98e340a5ea89735ee8ad0108ec7c666d6e32 Mon Sep 17 00:00:00 2001 From: Don MacAskill Date: Mon, 10 Nov 2025 19:46:27 -0800 Subject: [PATCH 14/14] Apply GitHub Copilot suggestions From https://github.com/awesomized/crc-fast-php-ext/pull/3 --- .github/workflows/tests.yaml | 6 +++--- .github/workflows/windows-release.yaml | 12 +++++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 837453c..87f0807 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -21,8 +21,8 @@ jobs: # Fetch the latest release version echo "Fetching latest crc_fast library release..." - LATEST_RELEASE=$(curl -sL https://api.github.com/repos/awesomized/crc-fast-rust/releases/latest | grep '"tag_name":' | sed -E 's/.*"tag_name": "([^"]+)".*/\1/') - + LATEST_RELEASE=$(curl -sL https://api.github.com/repos/awesomized/crc-fast-rust/releases/latest | jq -r .tag_name) + if [ -z "$LATEST_RELEASE" ]; then echo "Error: Failed to fetch latest release version" exit 1 @@ -35,7 +35,7 @@ jobs: echo "Downloading crc_fast library ${LATEST_RELEASE} for ${PLATFORM}-${ARCH}" curl -sL -o crc-fast.tar.gz "${DOWNLOAD_URL}" || { - echo "Error: Failed to download crc_fast library release ${LATEST_RELEASE}" + echo "Error: Failed to download crc_fast library release ${LATEST_RELEASE} from ${DOWNLOAD_URL}" exit 1 } diff --git a/.github/workflows/windows-release.yaml b/.github/workflows/windows-release.yaml index 6638f44..81a1cf8 100644 --- a/.github/workflows/windows-release.yaml +++ b/.github/workflows/windows-release.yaml @@ -168,13 +168,19 @@ jobs: Expand-Archive -Path "crc_fast_lib.zip" -DestinationPath $tempExtractPath -Force # Find the versioned subdirectory (e.g., crc-fast-1.7.0-windows-x86_64) - $versionedDir = Get-ChildItem -Path $tempExtractPath -Directory | Select-Object -First 1 + $dirs = Get-ChildItem -Path $tempExtractPath -Directory - if (-not $versionedDir) { + if ($dirs.Count -eq 0) { echo "ERROR: No subdirectory found after extraction" exit 1 + } elseif ($dirs.Count -gt 1) { + echo "ERROR: Multiple subdirectories found after extraction. Expected only one." + $dirs | ForEach-Object { echo " $($_.FullName)" } + exit 1 } + $versionedDir = $dirs[0] + echo "Found versioned directory: $($versionedDir.Name)" # Move contents from versioned directory to final location @@ -234,7 +240,7 @@ jobs: with: name: php_crc_fast-${{ matrix.php-version }}-${{ matrix.arch }}-${{ matrix.ts }} path: | - ${{ matrix.arch }}/Release*/php_crc_fast.dll + ${{ matrix.arch }}/${{ matrix.ts == 'ts' && 'Release_TS' || 'Release' }}/php_crc_fast.dll if-no-files-found: error release: