diff --git a/.github/workflows/wpcloud.yml b/.github/workflows/wpcloud.yml new file mode 100644 index 0000000000000..e38e3a9a0f515 --- /dev/null +++ b/.github/workflows/wpcloud.yml @@ -0,0 +1,141 @@ +name: WPCloud Unit Testing for WPCOMSH + +on: + pull_request: + push: + branches: ['trunk', '*/branch-*'] +concurrency: + group: wpcloud-${{ github.event_name }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + name: Install the Monorepo and build wpcomsh + runs-on: ubuntu-latest + outputs: + wpcomsh: ${{ steps.changed.outputs.wpcomsh }} + steps: + - uses: actions/checkout@v4 + with: + # codecov.io requires a fetch depth > 1. + fetch-depth: 2 + + # For pull requests, list-changed-projects.sh needs the merge base. + # But it doesn't have to be checked out. + - name: Deepen to merge base + if: github.event_name == 'pull_request' + uses: ./.github/actions/deepen-to-merge-base + with: + checkout: false + + - name: Setup tools + uses: ./.github/actions/tool-setup + with: + php: ${{ matrix.php }} + node: ${{ matrix.node }} + - name: Monorepo install + run: | + echo "::group::Pnpm" + pnpm install + echo "::endgroup::" + - name: Detect if wpcomsh has changed + id: changed + run: | + CHANGED="$(EXTRA=test .github/files/list-changed-projects.sh)" + + # WPCOMSH_CHANGED="$(jq --argjson changed "$CHANGED" -n '$changed | has( "plugins/wpcomsh" ) ')" + WPCOMSH_CHANGED="true" + echo "wpcomsh=${WPCOMSH_CHANGED}" >> "$GITHUB_OUTPUT" + - name: Build wpcomsh + if: steps.changed.outputs.wpcomsh == 'true' + run: | + find . -path ./.github -prune -o -type f -print | sort > /tmp/before.txt + echo "::group::Installing and building wpcomsh" + pnpm jetpack build -v --deps plugins/wpcomsh + echo "::endgroup::" + + # We only want to save the files that were actually created or changed. + # But we can't just list them for actions/cache/save, "Argument list too long". + # So instead we delete all the unchanged files so we can tell actions/cache/save + # to save everything that's left. + git -c core.quotepath=off diff --name-only | sort > /tmp/changed.txt + if [[ -s /tmp/changed.txt ]]; then + grep -F -x -v -f /tmp/changed.txt /tmp/before.txt > /tmp/remove.txt + else + cp /tmp/before.txt /tmp/remove.txt + fi + xargs -d '\n' rm < /tmp/remove.txt + find . -type d -empty -delete + + - name: Save wpcomsh build cache + if: steps.changed.outputs.wpcomsh == 'true' + id: wpcomsh-build-cache-save + uses: actions/cache/save@v4 + with: + path: | + . + !./.github/ + key: ${{ github.sha }} + deploy: + name: Run PHPUnit on the WPCloud test site + runs-on: ubuntu-latest + needs: build + if: needs.build.outputs.wpcomsh == 'true' + steps: + - uses: actions/checkout@v4 + + - name: Restore wpcomsh build cache + id: wpcomsh-build-cache + uses: actions/cache/restore@v4 + with: + path: | + . + !./.github/ + key: ${{ github.sha }} + fail-on-cache-miss: true + + - name: Setup tools + uses: ./.github/actions/tool-setup + + - name: Install monorepo + run: | + pnpm install + + - name: Configure Github to be able to SSH to the Atomic site + run: | + echo "::group::Intializing" + + mkdir -vp ~/.ssh/ + chmod -v 700 ~/.ssh + + touch ~/.ssh/id_site + touch ~/.ssh/known_hosts + chmod 600 ~/.ssh/id_site + chmod 600 ~/.ssh/known_hosts + echo "$SSH_KEY" > ~/.ssh/id_site + echo "wrote ~/.ssh/id_site" + echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts + echo "wrote ~/.ssh/known_hosts" + + echo "::endgroup::" + + echo "::group::Transferring wpcomsh to the testing server" + pnpm jetpack rsync wpcomsh jetpackwpcomshtester.wordpress.com@sftp.wp.com:~/htdocs/wp-content/mu-plugins + scp -r projects/plugins/wpcomsh/bin jetpackwpcomshtester.wordpress.com@sftp.wp.com:/srv/htdocs/wp-content/mu-plugins/wpcomsh + scp -r projects/plugins/wpcomsh/tests jetpackwpcomshtester.wordpress.com@sftp.wp.com:/srv/htdocs/wp-content/mu-plugins/wpcomsh/ + scp projects/plugins/wpcomsh/phpunit.xml.dist jetpackwpcomshtester.wordpress.com@sftp.wp.com:/srv/htdocs/wp-content/mu-plugins/wpcomsh/ + + echo "::engroup::" + + echo "::group::execution" + ssh -i ~/.ssh/id_site jetpackwpcomshtester.wordpress.com@sftp.wp.com "~/htdocs/github-action-handler.sh" || CODE=$? + echo "::endgroup::" + + echo "::group::teardown" + rm -rvf ~/.ssh/ + echo "::endgroup::" + echo "Exiting with exit code $CODE" + exit $CODE + env: + SSH_KEY: ${{ secrets.UPDATEJETPACKSTAGING_SSH_KEY }} + SSH_KNOWN_HOSTS: ${{ secrets.UPDATEJETPACKSTAGING_SSH_KNOWN_HOSTS }} diff --git a/projects/plugins/wpcomsh/bin/install-wp-tests.sh b/projects/plugins/wpcomsh/bin/install-wp-tests.sh index c401896c91322..3cedfabb261f5 100755 --- a/projects/plugins/wpcomsh/bin/install-wp-tests.sh +++ b/projects/plugins/wpcomsh/bin/install-wp-tests.sh @@ -51,7 +51,7 @@ else fi WP_TESTS_TAG="tags/$LATEST_VERSION" fi -set -ex +set -e install_wp() { @@ -118,7 +118,7 @@ install_test_suite() { sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR/':" "$WP_TESTS_DIR"/wp-tests-config.php sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php - sed $ioption "s/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR"/wp-tests-config.php + sed $ioption "s/yourpasswordhere/${DB_PASS//\//\\/}/" "$WP_TESTS_DIR"/wp-tests-config.php sed $ioption "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR"/wp-tests-config.php fi diff --git a/projects/plugins/wpcomsh/changelog/add-wpcomsh-wpcloud-testing b/projects/plugins/wpcomsh/changelog/add-wpcomsh-wpcloud-testing new file mode 100644 index 0000000000000..71d30adf105d7 --- /dev/null +++ b/projects/plugins/wpcomsh/changelog/add-wpcomsh-wpcloud-testing @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +Fixed a database password escaping issue when installing tests. diff --git a/projects/plugins/wpcomsh/tests/bootstrap.php b/projects/plugins/wpcomsh/tests/bootstrap.php index 5e8955b9eeac1..ec4c191e095bd 100644 --- a/projects/plugins/wpcomsh/tests/bootstrap.php +++ b/projects/plugins/wpcomsh/tests/bootstrap.php @@ -5,9 +5,10 @@ * @package wpcomsh */ -$_tests_dir = getenv( 'WP_TESTS_DIR' ); -$_core_dir = getenv( 'WP_CORE_DIR' ); -$wp_branch = getenv( 'WP_BRANCH' ); +$_tests_dir = getenv( 'WP_TESTS_DIR' ); +$_core_dir = getenv( 'WP_CORE_DIR' ); +$_wp_content_dir = getenv( 'WP_CONTENT_DIR' ) ?? $_core_dir; +$wp_branch = getenv( 'WP_BRANCH' ); if ( ! $_tests_dir ) { if ( $wp_branch ) { @@ -26,7 +27,7 @@ } define( 'IS_ATOMIC', true ); -define( 'WPMU_PLUGIN_DIR', "{$_core_dir}wp-content/mu-plugins" ); +define( 'WPMU_PLUGIN_DIR', "{$_wp_content_dir}/mu-plugins" ); if ( ! file_exists( $_tests_dir . '/includes/functions.php' ) ) { echo "Could not find $_tests_dir/includes/functions.php, have you run bin/install-wp-tests.sh ?" . PHP_EOL; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped @@ -59,5 +60,16 @@ function _manually_load_plugin() { define( 'WP_TESTS_CONFIG_FILE_PATH', getenv( 'WP_TESTS_CONFIG_FILE_PATH' ) ); } +if ( ! function_exists( 'wp_cache_flush_runtime' ) ) { + /** + * Removes all cache items from the in-memory runtime cache. + * + * @return bool True on success, false on failure. + */ + function wp_cache_flush_runtime() { + return wp_cache_flush(); + } +} + // Start up the WP testing environment. require_once $_tests_dir . '/includes/bootstrap.php'; diff --git a/projects/plugins/wpcomsh/tests/lib/mocks/class-jetpack-options.php b/projects/plugins/wpcomsh/tests/lib/mocks/class-jetpack-options.php index 61d650cd6789e..c9aa896d3780c 100644 --- a/projects/plugins/wpcomsh/tests/lib/mocks/class-jetpack-options.php +++ b/projects/plugins/wpcomsh/tests/lib/mocks/class-jetpack-options.php @@ -24,5 +24,18 @@ class Jetpack_Options { public static function get_option( $option_name, $default = false ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.defaultFound return apply_filters( 'jetpack_options', get_option( $option_name, $default ), $option_name ); } + + /** + * Returns the requested option, and ensures it's autoloaded in the future. + * This does _not_ adjust the prefix in any way (does not prefix jetpack_%) + * + * @param string $name Option name. + * @param mixed $default (optional). + * + * @return mixed + */ + public static function get_option_and_ensure_autoload( $name, $default ) { + return self::get_option( $name, $default ); + } } }