diff --git a/.github/actions/windows/prepare-build/action.yml b/.github/actions/windows/prepare-build/action.yml index 894545061..153c44bfa 100644 --- a/.github/actions/windows/prepare-build/action.yml +++ b/.github/actions/windows/prepare-build/action.yml @@ -41,7 +41,7 @@ runs: - name: Enable Developer Command Prompt uses: ilammy/msvc-dev-cmd@v1 with: - arch: ${{ matrix.arch }} + arch: ${{ inputs.arch }} toolset: ${{ steps.setup-php.outputs.toolset }} - name: phpize diff --git a/.github/workflows/build-windows-package.yml b/.github/workflows/build-windows-package.yml new file mode 100644 index 000000000..4de18d8d3 --- /dev/null +++ b/.github/workflows/build-windows-package.yml @@ -0,0 +1,122 @@ +name: "Build Windows Package" +run-name: "Build Windows Package for ${{ inputs.ref }} (PHP ${{ inputs.php }} ${{ inputs.arch }} ${{ inputs.ts }})" + +on: + workflow_call: + inputs: + version: + description: "The version being built" + type: string + required: true + ref: + description: "The git reference to build" + type: string + required: true + php: + description: "The PHP version to build for" + type: string + required: true + arch: + description: "The architecture to build for (x64 or x86)" + type: string + required: true + ts: + description: "Thread safety (ts or nts)" + type: string + required: true + upload_release_asset: + description: "Whether to upload a release asset" + type: boolean + default: false + +jobs: + build: + name: "Build DLL" + # windows-latest is required to use enableCrossOsArchive with Ubuntu in the + # next step. See https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cross-os-cache + runs-on: windows-latest + defaults: + run: + shell: cmd + + steps: + - uses: actions/checkout@v4 + with: + submodules: true + ref: ${{ inputs.ref }} + + - name: "Build Driver" + id: build-driver + uses: ./.github/actions/windows/build + with: + version: ${{ inputs.php }} + arch: ${{ inputs.arch }} + ts: ${{ inputs.ts }} + + - name: "Copy DLL and PDB files to CWD" + run: | + cp %BUILD_DIR%\php_mongodb.dll . + cp %BUILD_DIR%\php_mongodb.pdb . + env: + BUILD_DIR: ${{ steps.build-driver.outputs.build-dir }} + + - name: "Cache build artifacts for subsequent builds" + uses: actions/cache/save@v4 + with: + key: ${{ github.sha }}-${{ inputs.php }}-${{ inputs.ts }}-${{ inputs.arch }} + enableCrossOsArchive: true + path: | + php_mongodb.dll + php_mongodb.pdb + + sign-and-package: + environment: release + name: "Sign and create package" + needs: build + # ubuntu-latest is required to use enableCrossOsArchive + # See https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cross-os-cache + runs-on: "ubuntu-latest" + permissions: + id-token: write + + steps: + - name: "Generate token and checkout repository" + uses: mongodb-labs/drivers-github-tools/secure-checkout@v2 + with: + app_id: ${{ vars.APP_ID }} + private_key: ${{ secrets.APP_PRIVATE_KEY }} + ref: ${{ inputs.ref }} + + - name: "Set up drivers-github-tools" + uses: mongodb-labs/drivers-github-tools/setup@v2 + with: + aws_role_arn: ${{ secrets.AWS_ROLE_ARN }} + aws_region_name: ${{ vars.AWS_REGION_NAME }} + aws_secret_id: ${{ secrets.AWS_SECRET_ID }} + + - name: Restore cached build artifacts + id: cache-build-artifacts + uses: actions/cache/restore@v4 + with: + fail-on-cache-miss: true + key: ${{ github.sha }}-${{ inputs.php }}-${{ inputs.ts }}-${{ inputs.arch }} + enableCrossOsArchive: true + path: | + php_mongodb.dll + php_mongodb.pdb + + - name: "Create detached DLL signature" + uses: mongodb-labs/drivers-github-tools/gpg-sign@v2 + with: + filenames: php_mongodb.dll + + # Copy the signature file from the release asset directory to avoid directory issues in the ZIP file + - name: "Copy signature file" + run: cp ${RELEASE_ASSETS}/php_mongodb.dll.sig . + + - name: "Create and upload release asset" + if: ${{ inputs.upload_release_asset }} + run: | + ARCHIVE=php_mongodb-${{ inputs.version }}-${{ inputs.php }}-${{ inputs.ts }}-${{ inputs.arch }}.zip + zip ${ARCHIVE} php_mongodb.dll php_mongodb.dll.sig php_mongodb.pdb CREDITS CONTRIBUTING.md LICENSE README.md THIRD_PARTY_NOTICES + gh release upload ${{ inputs.version }} ${ARCHIVE} diff --git a/.github/workflows/commit-and-tag.sh b/.github/workflows/commit-and-tag.sh deleted file mode 100755 index fb6bf9978..000000000 --- a/.github/workflows/commit-and-tag.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash -set -e - -PACKAGE_VERSION=$1 -GPG_KEY_ID=$2 -TAG_MESSAGE_FILE=$3 - -gpgloader - -# Create signed "Package x.y.z" commit -echo "Create package commit" -git commit -m "Package ${PACKAGE_VERSION}" -s --gpg-sign=${GPG_KEY_ID} phongo_version.h - -# Create signed "Release x.y.z" tag -echo "Create release tag" -git tag -F ${TAG_MESSAGE_FILE} -s --local-user=${GPG_KEY_ID} ${PACKAGE_VERSION} diff --git a/.github/workflows/package-release.yml b/.github/workflows/package-release.yml index 4dfe8b8ec..c78b48cc2 100644 --- a/.github/workflows/package-release.yml +++ b/.github/workflows/package-release.yml @@ -1,10 +1,17 @@ name: "Package Release" -run-name: "Package Release ${{ github.ref_name }}" +run-name: "Package Release ${{ inputs.version }}" on: - push: - tags: - - "*" + workflow_call: + inputs: + version: + description: "The version being built" + type: string + required: true + ref: + description: "The git reference to build" + type: string + required: true jobs: build-pecl: @@ -13,25 +20,15 @@ jobs: runs-on: "ubuntu-latest" permissions: id-token: write + contents: write steps: - - name: "Create temporary app token" - uses: actions/create-github-app-token@v1 - id: app-token + - name: "Generate token and checkout repository" + uses: mongodb-labs/drivers-github-tools/secure-checkout@v2 with: - app-id: ${{ vars.APP_ID }} - private-key: ${{ secrets.APP_PRIVATE_KEY }} - - - name: "Store GitHub token in environment" - run: echo "GH_TOKEN=${{ steps.app-token.outputs.token }}" >> "$GITHUB_ENV" - shell: bash - - - name: "Checkout" - uses: "actions/checkout@v4" - with: - # Manually specify a ref. When actions/checkout is run for a tag without a ref, it looks up the underlying - # commit and specifically fetches this to the refs/tags/ ref, which denies us access to the tag message - ref: ${{ github.ref }} + app_id: ${{ vars.APP_ID }} + private_key: ${{ secrets.APP_PRIVATE_KEY }} + ref: ${{ inputs.ref }} submodules: true - name: "Set up drivers-github-tools" @@ -47,7 +44,13 @@ jobs: version: "8.3" - name: "Write changelog file for packaging" - run: git tag -l ${{ github.ref_name }} --format='%(contents)' > changelog + run: | + gh api \ + --method POST \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + /repos/${{ github.repository }}/releases/generate-notes \ + -f "tag_name=${{ inputs.version }}" --jq '.body' > changelog # This will fill in the release notes from the previously generated changelog - name: "Build package.xml" @@ -77,28 +80,20 @@ jobs: - name: "Copy signature file" run: cp ${RELEASE_ASSETS}/${{ env.PACKAGE_FILE }}.sig . - - name: "Upload artifacts" - uses: actions/upload-artifact@v4 - with: - name: ${{ env.PACKAGE_FILE }} - path: | - ${{ env.PACKAGE_FILE }} - ${{ env.PACKAGE_FILE }}.sig - retention-days: 3 - - name: "Upload release artifacts" - run: gh release upload ${{ github.ref_name }} ${{ env.PACKAGE_FILE }} ${{ env.PACKAGE_FILE }}.sig - continue-on-error: true + run: gh release upload ${{ inputs.version }} ${{ env.PACKAGE_FILE }} ${{ env.PACKAGE_FILE }}.sig build-windows: - name: "Create Windows package" - # windows-latest is required to use enableCrossOsArchive with Ubuntu in the - # next step. See https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cross-os-cache - runs-on: windows-latest - defaults: - run: - shell: cmd - + name: "Create Windows packages" + uses: ./.github/workflows/build-windows-package.yml + with: + version: ${{ inputs.version }} + ref: refs/tags/${{ inputs.version }} + php: ${{ matrix.php }} + arch: ${{ matrix.arch }} + ts: ${{ matrix.ts }} + upload_release_asset: true + secrets: inherit strategy: fail-fast: false matrix: @@ -106,113 +101,3 @@ jobs: php: [ "7.4", "8.0", "8.1", "8.2", "8.3" ] arch: [ x64, x86 ] ts: [ ts, nts ] - - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - - name: "Build Driver" - id: build-driver - uses: ./.github/actions/windows/build - with: - version: ${{ matrix.php }} - arch: ${{ matrix.arch }} - ts: ${{ matrix.ts }} - - - name: "Copy DLL and PDB files to CWD" - run: | - cp %BUILD_DIR%\php_mongodb.dll . - cp %BUILD_DIR%\php_mongodb.pdb . - env: - BUILD_DIR: ${{ steps.build-driver.outputs.build-dir }} - - - name: "Cache build artifacts for subsequent builds" - uses: actions/cache/save@v4 - with: - key: ${{ github.sha }}-${{ matrix.php }}-${{ matrix.ts }}-${{ matrix.arch }} - enableCrossOsArchive: true - path: | - php_mongodb.dll - php_mongodb.pdb - - sign-and-publish-windows: - environment: release - name: "Sign and Publish Windows package" - needs: [build-windows] - # ubuntu-latest is required to use enableCrossOsArchive - # See https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cross-os-cache - runs-on: "ubuntu-latest" - permissions: - id-token: write - - strategy: - fail-fast: false - matrix: - # Note: keep this in sync with the Windows matrix in windows-tests.yml - php: [ "7.4", "8.0", "8.1", "8.2", "8.3" ] - arch: [ x64, x86 ] - ts: [ ts, nts ] - - steps: - - name: "Create temporary app token" - uses: actions/create-github-app-token@v1 - id: app-token - with: - app-id: ${{ vars.APP_ID }} - private-key: ${{ secrets.APP_PRIVATE_KEY }} - - - name: "Store GitHub token in environment" - run: echo "GH_TOKEN=${{ steps.app-token.outputs.token }}" >> "$GITHUB_ENV" - shell: bash - - - uses: actions/checkout@v4 - - - name: "Set up drivers-github-tools" - uses: mongodb-labs/drivers-github-tools/setup@v2 - with: - aws_role_arn: ${{ secrets.AWS_ROLE_ARN }} - aws_region_name: ${{ vars.AWS_REGION_NAME }} - aws_secret_id: ${{ secrets.AWS_SECRET_ID }} - - - name: Restore cached build artifacts - id: cache-build-artifacts - uses: actions/cache/restore@v4 - with: - fail-on-cache-miss: true - key: ${{ github.sha }}-${{ matrix.php }}-${{ matrix.ts }}-${{ matrix.arch }} - enableCrossOsArchive: true - path: | - php_mongodb.dll - php_mongodb.pdb - - - name: "Create detached DLL signature" - uses: mongodb-labs/drivers-github-tools/gpg-sign@v2 - with: - filenames: php_mongodb.dll - - # Copy the signature file from the release asset directory to avoid directory issues in the ZIP file - - name: "Copy signature file" - run: cp ${RELEASE_ASSETS}/php_mongodb.dll.sig . - - - name: "Upload DLL and PDB files as build artifacts" - uses: actions/upload-artifact@v4 - with: - name: php_mongodb-${{ github.ref_name }}-${{ matrix.php }}-${{ matrix.ts }}-${{ matrix.arch }} - path: | - php_mongodb.dll - php_mongodb.dll.sig - php_mongodb.pdb - CREDITS - CONTRIBUTING.md - LICENSE - README.md - THIRD_PARTY_NOTICES - retention-days: 3 - - - name: "Create and upload release artifact" - run: | - ARCHIVE=php_mongodb-${{ github.ref_name }}-${{ matrix.php }}-${{ matrix.ts }}-${{ matrix.arch }}.zip - zip ${ARCHIVE} php_mongodb.dll php_mongodb.dll.sig php_mongodb.pdb CREDITS CONTRIBUTING.md LICENSE README.md THIRD_PARTY_NOTICES - gh release upload ${{ github.ref_name }} ${ARCHIVE} - continue-on-error: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b51d42a9e..f9bd36017 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -56,21 +56,12 @@ jobs: - name: "Create release output" run: echo '🎬 Release process for version ${{ inputs.version }} started by @${{ github.triggering_actor }}' >> $GITHUB_STEP_SUMMARY - - name: "Create temporary app token" - uses: actions/create-github-app-token@v1 - id: app-token - with: - app-id: ${{ vars.APP_ID }} - private-key: ${{ secrets.APP_PRIVATE_KEY }} - - - name: "Store GitHub token in environment" - run: echo "GH_TOKEN=${{ steps.app-token.outputs.token }}" >> "$GITHUB_ENV" - shell: bash - - - uses: actions/checkout@v4 + - name: "Generate token and checkout repository" + uses: mongodb-labs/drivers-github-tools/secure-checkout@v2 with: + app_id: ${{ vars.APP_ID }} + private_key: ${{ secrets.APP_PRIVATE_KEY }} submodules: true - token: ${{ env.GH_TOKEN }} - name: "Set up drivers-github-tools" uses: mongodb-labs/drivers-github-tools/setup@v2 @@ -102,37 +93,29 @@ jobs: # Preliminary checks done - commence the release process # - # Create a draft release with a changelog - # TODO: Consider using the API to generate changelog - - name: "Create draft release with generated changelog" - run: gh release create ${{ env.PACKAGE_VERSION }} --target ${{ github.ref_name }} --generate-notes --draft - - - name: "Read changelog from draft release" - run: gh release view ${{ env.PACKAGE_VERSION }} --json body --template '{{ .body }}' >> changelog - - - name: "Prepare tag message" - run: | - echo -e "Release ${PACKAGE_VERSION}\n" > tag-message - cat changelog >> tag-message - - # This step creates the "Package x.y.z" commit that will be the base of - # our tag and creates the release tag. This is run inside the container in - # order to create signed git artifacts - - name: "Create package commit and release tag" - uses: mongodb-labs/drivers-github-tools/git-sign@v2 + - name: "Create package commit" + uses: mongodb-labs/drivers-github-tools/bump-version@v2 with: - command: "$(pwd)/.github/workflows/commit-and-tag.sh ${{ env.PACKAGE_VERSION }} ${{ env.GPG_KEY_ID }} tag-message" - - # This step needs to happen outside of the container, as PHP is not - # available within. - - name: "Bump to next development release" - run: ./bin/update-release-version.php to-next-patch-dev + version: ${{ inputs.version }} + # Use get-version as a dummy as a version_bump_script is required + # We run the bump script manually earlier so we can sanity-check the version number and print nice output + version_bump_script: "./bin/update-release-version.php get-version" + commit_template: 'Package ${VERSION}' + # Don't push changes as we're creating a second commit later + push_commit: false + + - name: "Create release tag" + uses: mongodb-labs/drivers-github-tools/tag-version@v2 + with: + version: ${{ inputs.version }} + tag_message_template: 'Release ${VERSION}' - # Create a signed "back to -dev" commit, again inside the container - - name: "Create dev commit" - uses: mongodb-labs/drivers-github-tools/git-sign@v2 + - name: "Bump to next development release and commit" + uses: mongodb-labs/drivers-github-tools/bump-version@v2 with: - command: "git commit -m 'Back to -dev' -s --gpg-sign=${{ env.GPG_KEY_ID }} phongo_version.h" + version: ${{ inputs.version }} + version_bump_script: "./bin/update-release-version.php to-next-patch-dev" + commit_template: 'Back to -dev' # TODO: Manually merge using ours strategy. This avoids merge-up pull requests being created # Process is: @@ -141,25 +124,106 @@ jobs: # 3. push next branch # 4. switch back to release branch, then push - - name: "Push changes from release branch" - run: git push - - name: "Prepare release message" run: | cat > release-message <<'EOL' - ${{ format(env.default-release-message, env.PACKAGE_VERSION, inputs.jira-version-number) }} + ${{ format(env.default-release-message, inputs.version, inputs.jira-version-number) }} EOL - cat changelog >> release-message - - # Update release with correct release information - - name: "Update release information" - run: echo "RELEASE_URL=$(gh release edit ${{ env.PACKAGE_VERSION }} --title "${{ env.PACKAGE_VERSION }}" --notes-file release-message)" >> "$GITHUB_ENV" - # Pushing the release tag starts build processes that then produce artifacts for the release - - name: "Push release tag" - run: git push origin ${{ env.PACKAGE_VERSION }} + - name: "Create draft release" + run: echo "RELEASE_URL=$(gh release create ${{ inputs.version }} --target ${{ github.ref_name }} --title "${{ inputs.version }}" --notes-file release-message --draft)" >> "$GITHUB_ENV" - name: "Set summary" run: | echo '🚀 Created tag and drafted release for version [${{ inputs.version }}](${{ env.RELEASE_URL }})' >> $GITHUB_STEP_SUMMARY echo '✍️ You may now update the release notes and publish the release when ready' >> $GITHUB_STEP_SUMMARY + + static-analysis: + needs: prepare-release + name: "Run Static Analysis" + uses: ./.github/workflows/static-analysis.yml + with: + ref: refs/tags/${{ inputs.version }} + permissions: + security-events: write + id-token: write + + package-release: + needs: prepare-release + name: "Create Release Packages" + uses: ./.github/workflows/package-release.yml + with: + version: ${{ inputs.version }} + ref: refs/tags/${{ inputs.version }} + secrets: inherit + permissions: + id-token: write + contents: write + + publish-ssdlc-assets: + needs: + - static-analysis + - package-release + environment: release + name: "Publish SSDLC Assets" + runs-on: ubuntu-latest + permissions: + security-events: read + id-token: write + contents: write + + steps: + - name: "Generate token and checkout repository" + uses: mongodb-labs/drivers-github-tools/secure-checkout@v2 + with: + app_id: ${{ vars.APP_ID }} + private_key: ${{ secrets.APP_PRIVATE_KEY }} + ref: refs/tags/${{ inputs.version }} + + # Sets the S3_ASSETS environment variable used later + - name: "Set up drivers-github-tools" + uses: mongodb-labs/drivers-github-tools/setup@v2 + with: + aws_role_arn: ${{ secrets.AWS_ROLE_ARN }} + aws_region_name: ${{ vars.AWS_REGION_NAME }} + aws_secret_id: ${{ secrets.AWS_SECRET_ID }} + + - name: "Remove unnecessary files" + run: rm -f ${RELEASE_ASSETS}/release_run_id.txt + shell: bash + + - name: Download all release artifacts + run: gh release download ${{ inputs.version }} --dir ${{ env.RELEASE_ASSETS }} + + - name: "Generate authorized publication document" + uses: mongodb-labs/drivers-github-tools/authorized-pub@v2 + with: + product_name: "MongoDB PHP Driver (extension)" + release_version: ${{ inputs.version }} + filenames: "${{ env.RELEASE_ASSETS }}/*" + token: ${{ env.GH_TOKEN }} + + - name: "Download SBOM file from Silk" + uses: mongodb-labs/drivers-github-tools/sbom@v2 + with: + silk_asset_group: mongodb-php-driver-extension + + - name: "Upload SBOM as release artifact" + run: gh release upload ${{ inputs.version }} ${{ env.S3_ASSETS }}/cyclonedx.sbom.json + + - name: "Generate SARIF report from code scanning alerts" + uses: mongodb-labs/drivers-github-tools/code-scanning-export@v2 + with: + ref: ${{ inputs.version }} + output-file: ${{ env.S3_ASSETS }}/code-scanning-alerts.json + + - name: "Generate compliance report" + uses: mongodb-labs/drivers-github-tools/compliance-report@v2 + with: + token: ${{ env.GH_TOKEN }} + + - name: Upload S3 assets + uses: mongodb-labs/drivers-github-tools/upload-s3-assets@v2 + with: + version: ${{ inputs.version }} + product_name: mongo-php-driver diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index f2fbef5de..d77611839 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -12,8 +12,12 @@ on: - "v*.*" - "master" - "feature/*" - tags: - - "*" + workflow_call: + inputs: + ref: + description: "The git ref to check" + type: string + required: true jobs: semgrep: @@ -26,6 +30,7 @@ jobs: - name: "Checkout" uses: "actions/checkout@v4" with: + ref: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.ref }} submodules: true - name: "Scan" diff --git a/bin/update-release-version.php b/bin/update-release-version.php index f6d1adfba..79c7fe88e 100755 --- a/bin/update-release-version.php +++ b/bin/update-release-version.php @@ -140,7 +140,8 @@ function get_next_minor_version(array $versions): array ]; } -if ($argc !== 2) { +// Allow 2 arguments as the bump-version action always passes a version number, even when not needed +if (! in_array($argc, [2, 3])) { usage(); } @@ -149,6 +150,7 @@ function get_next_minor_version(array $versions): array switch ($argv[1] ?? null) { case 'get-version': echo $currentVersion['version']; + exit(0); case 'to-stable': @@ -170,4 +172,3 @@ function get_next_minor_version(array $versions): array write_release_version(VERSION_FILENAME, $newVersion); printf("Updated version number in version file from %s to %s\n", $currentVersion['version'], $newVersion['version']); -