diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000000..e41741f364 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @pmmp/server-developers diff --git a/.github/ISSUE_TEMPLATE/api-change-request.md b/.github/ISSUE_TEMPLATE/api-change-request.md index 615ab12ef3..e3d24ea0ff 100644 --- a/.github/ISSUE_TEMPLATE/api-change-request.md +++ b/.github/ISSUE_TEMPLATE/api-change-request.md @@ -7,13 +7,13 @@ assignees: '' --- - -## Description + +## Problem description - -## Justification + +## Proposed solution -## Alternative methods +## Alternative solutions that don't require API changes diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 8a541dfecd..82fd81a1de 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,40 +1,32 @@ -## Introduction + -### Relevant issues - +### Related issues & PRs ## Changes ### API changes + ### Behavioural changes + ## Backwards compatibility + ## Follow-up - + ## Tests diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 518a26c705..97607ab8fa 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -3,7 +3,7 @@ updates: - package-ecosystem: composer directory: "/" schedule: - interval: daily + interval: weekly time: "10:00" open-pull-requests-limit: 10 ignore: @@ -12,6 +12,22 @@ updates: update-types: - "version-update:semver-major" - "version-update:semver-minor" + groups: + production-patch-updates: + dependency-type: production + patterns: + - "*" + update-types: + - "patch" + development-patch-updates: + dependency-type: development + patterns: + - "*" + update-types: + - "patch" + phpstan: + patterns: + - "phpstan/*" - package-ecosystem: gitsubmodule directory: "/" @@ -21,4 +37,4 @@ updates: - package-ecosystem: github-actions directory: "/" schedule: - interval: daily + interval: weekly diff --git a/.github/readme/pocketmine-dark.png b/.github/readme/legacy-pocketmine-dark.png similarity index 100% rename from .github/readme/pocketmine-dark.png rename to .github/readme/legacy-pocketmine-dark.png diff --git a/.github/readme/pocketmine.png b/.github/readme/legacy-pocketmine.png similarity index 100% rename from .github/readme/pocketmine.png rename to .github/readme/legacy-pocketmine.png diff --git a/.github/readme/pocketmine-dark-rgb.gif b/.github/readme/pocketmine-dark-rgb.gif new file mode 100644 index 0000000000..ccf6152a45 Binary files /dev/null and b/.github/readme/pocketmine-dark-rgb.gif differ diff --git a/.github/readme/pocketmine-rgb.gif b/.github/readme/pocketmine-rgb.gif new file mode 100644 index 0000000000..933891520b Binary files /dev/null and b/.github/readme/pocketmine-rgb.gif differ diff --git a/.github/workflows/build-docker-image.yml b/.github/workflows/build-docker-image.yml index 99e0fb5524..4325c63f28 100644 --- a/.github/workflows/build-docker-image.yml +++ b/.github/workflows/build-docker-image.yml @@ -12,16 +12,23 @@ jobs: steps: - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: Login to DockerHub - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Clone pmmp/PocketMine-Docker repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: pmmp/PocketMine-Docker fetch-depth: 1 @@ -30,68 +37,68 @@ jobs: id: tag-name run: | VERSION=$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{') - echo ::set-output name=TAG_NAME::$VERSION - echo ::set-output name=MAJOR::$(echo $VERSION | cut -d. -f1) - echo ::set-output name=MINOR::$(echo $VERSION | cut -d. -f1-2) + echo TAG_NAME=$VERSION >> $GITHUB_OUTPUT + echo MAJOR=$(echo $VERSION | cut -d. -f1) >> $GITHUB_OUTPUT + echo MINOR=$(echo $VERSION | cut -d. -f1-2) >> $GITHUB_OUTPUT - name: Download new release information run: curl -f -L ${{ github.server_url }}/${{ github.repository }}/releases/download/${{ steps.tag-name.outputs.TAG_NAME }}/build_info.json -o new_build_info.json - name: Detect channel id: channel - run: echo ::set-output name=CHANNEL::$(jq -r '.channel' new_build_info.json) + run: echo CHANNEL=$(jq -r '.channel' new_build_info.json) >> $GITHUB_OUTPUT - name: Get name of Docker repository name id: docker-repo-name - run: echo ::set-output name=NAME::$(echo "${GITHUB_REPOSITORY,,}") + run: echo NAME=$(echo "${GITHUB_REPOSITORY,,}") >> $GITHUB_OUTPUT - name: Build image for tag - uses: docker/build-push-action@v3.3.0 + uses: docker/build-push-action@v6.9.0 with: push: true context: ./pocketmine-mp tags: | ${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.TAG_NAME }} -# ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.TAG_NAME }} + ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.TAG_NAME }} build-args: | PMMP_TAG=${{ steps.tag-name.outputs.TAG_NAME }} PMMP_REPO=${{ github.repository }} - name: Build image for major tag if: steps.channel.outputs.CHANNEL == 'stable' - uses: docker/build-push-action@v3.3.0 + uses: docker/build-push-action@v6.9.0 with: push: true context: ./pocketmine-mp tags: | ${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MAJOR }} -# ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MAJOR }} + ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MAJOR }} build-args: | PMMP_TAG=${{ steps.tag-name.outputs.TAG_NAME }} PMMP_REPO=${{ github.repository }} - name: Build image for minor tag if: steps.channel.outputs.CHANNEL == 'stable' - uses: docker/build-push-action@v3.3.0 + uses: docker/build-push-action@v6.9.0 with: push: true context: ./pocketmine-mp tags: | ${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MINOR }} -# ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MINOR }} + ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MINOR }} build-args: | PMMP_TAG=${{ steps.tag-name.outputs.TAG_NAME }} PMMP_REPO=${{ github.repository }} - name: Build image for latest tag if: steps.channel.outputs.CHANNEL == 'stable' - uses: docker/build-push-action@v3.3.0 + uses: docker/build-push-action@v6.9.0 with: push: true context: ./pocketmine-mp tags: | ${{ steps.docker-repo-name.outputs.NAME }}:latest -# ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:latest + ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:latest build-args: | PMMP_TAG=${{ steps.tag-name.outputs.TAG_NAME }} PMMP_REPO=${{ github.repository }} diff --git a/.github/workflows/discord-release-embed.php b/.github/workflows/discord-release-embed.php index 41ef898789..5acffdf2e1 100644 --- a/.github/workflows/discord-release-embed.php +++ b/.github/workflows/discord-release-embed.php @@ -18,15 +18,21 @@ require dirname(__DIR__, 2) . '/vendor/autoload.php'; /** * @phpstan-return array */ -function generateDiscordEmbed(string $version, string $channel, string $description, string $detailsUrl, string $sourceUrl, string $pharDownloadUrl, string $buildLogUrl) : array{ +function generateDiscordEmbed(string $version, string $channel, string $description, string $detailsUrl, string $sourceUrl, string $pharDownloadUrl, string $buildLogUrl, int $newsPingRoleId, ?string $phpDownloadUrl) : array{ + if($phpDownloadUrl !== null){ + $phpEmbedLink = " | [PHP Binaries]($phpDownloadUrl)"; + }else{ + $phpEmbedLink = ""; + } return [ + "content" => "<@&$newsPingRoleId> New PocketMine-MP release: $version ($channel)", "embeds" => [ [ "title" => "New PocketMine-MP release: $version ($channel)", "description" => << $detailsUrl, "color" => $channel === "stable" ? 0x57ab5a : 0xc69026 @@ -35,11 +41,11 @@ DESCRIPTION, ]; } -if(count($argv) !== 5){ - fwrite(STDERR, "Required arguments: github repo, version, API token\n"); +if(count($argv) !== 6){ + fwrite(STDERR, "Required arguments: github repo, version, API token, webhook URL, ping role ID\n"); exit(1); } -[, $repo, $tagName, $token, $hookURL] = $argv; +[, $repo, $tagName, $token, $hookURL, $newsPingRoleId] = $argv; $result = Internet::getURL('https://api.github.com/repos/' . $repo . '/releases/tags/' . $tagName, extraHeaders: [ 'Authorization: token ' . $token @@ -83,10 +89,21 @@ $detailsUrl = $buildInfoJson["details_url"]; $sourceUrl = $buildInfoJson["source_url"]; $pharDownloadUrl = $buildInfoJson["download_url"]; $buildLogUrl = $buildInfoJson["build_log_url"]; +$phpBinaryUrl = $buildInfoJson["php_download_url"] ?? null; $description = $releaseInfoJson["body"]; -$discordPayload = generateDiscordEmbed($buildInfoJson["base_version"], $buildInfoJson["channel"], $description, $detailsUrl, $sourceUrl, $pharDownloadUrl, $buildLogUrl); +$discordPayload = generateDiscordEmbed( + $buildInfoJson["base_version"], + $buildInfoJson["channel"], + $description, + $detailsUrl, + $sourceUrl, + $pharDownloadUrl, + $buildLogUrl, + (int) $newsPingRoleId, + $phpBinaryUrl +); $response = Internet::postURL( $hookURL, diff --git a/.github/workflows/discord-release-notify.yml b/.github/workflows/discord-release-notify.yml index 595b7374a5..8d0add224e 100644 --- a/.github/workflows/discord-release-notify.yml +++ b/.github/workflows/discord-release-notify.yml @@ -10,15 +10,15 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup PHP and tools - uses: shivammathur/setup-php@2.23.0 + uses: shivammathur/setup-php@2.31.1 with: - php-version: 8.0 + php-version: 8.2 - name: Restore Composer package cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ~/.cache/composer/files @@ -32,7 +32,7 @@ jobs: - name: Get actual tag name id: tag-name - run: echo ::set-output name=TAG_NAME::$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{') + run: echo TAG_NAME=$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{') >> $GITHUB_OUTPUT - name: Run webhook post script - run: php .github/workflows/discord-release-embed.php ${{ github.repository }} ${{ steps.tag-name.outputs.TAG_NAME }} ${{ github.token }} ${{ secrets.DISCORD_RELEASE_WEBHOOK }} + run: php .github/workflows/discord-release-embed.php ${{ github.repository }} ${{ steps.tag-name.outputs.TAG_NAME }} ${{ github.token }} ${{ secrets.DISCORD_RELEASE_WEBHOOK }} ${{ secrets.DISCORD_NEWS_PING_ROLE_ID }} diff --git a/.github/workflows/draft-release-from-pr.yml b/.github/workflows/draft-release-from-pr.yml new file mode 100644 index 0000000000..8a347853bb --- /dev/null +++ b/.github/workflows/draft-release-from-pr.yml @@ -0,0 +1,65 @@ +name: Draft release from PR + +on: + #presume that pull_request_target is safe at this point, since the PR was approved and merged + #we need write access to prepare the release & create comments + pull_request_target: + types: + - closed + branches: + - stable + - minor-next + - major-next + - "legacy/*" + paths: + - "src/VersionInfo.php" + +jobs: + check: + name: Check release + uses: ./.github/workflows/draft-release-pr-check.yml + + draft: + name: Create GitHub draft release + needs: [check] + if: needs.check.outputs.valid == 'true' + + uses: ./.github/workflows/draft-release.yml + + post-draft-url-comment: + name: Post draft release URL as comment + needs: [draft] + + runs-on: ubuntu-20.04 + + steps: + - name: Post draft release URL on PR + uses: thollander/actions-comment-pull-request@v3 + with: + message: "[Draft release ${{ needs.draft.outputs.version }}](${{ needs.draft.outputs.draft-url }}) has been created for commit ${{ github.sha }}. Please review and publish it." + + trigger-post-release-workflow: + name: Trigger post-release RestrictedActions workflow + # Not sure if needs is actually needed here + needs: [check] + if: needs.check.outputs.valid == 'true' + + runs-on: ubuntu-20.04 + + steps: + - name: Generate access token + id: generate-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ vars.RESTRICTED_ACTIONS_DISPATCH_ID }} + private-key: ${{ secrets.RESTRICTED_ACTIONS_DISPATCH_KEY }} + owner: ${{ github.repository_owner }} + repositories: RestrictedActions + + - name: Dispatch post-release restricted action + uses: peter-evans/repository-dispatch@v3 + with: + token: ${{ steps.generate-token.outputs.token }} + repository: ${{ github.repository_owner }}/RestrictedActions + event-type: pocketmine_mp_post_release + client-payload: '{"branch": "${{ github.ref }}"}' diff --git a/.github/workflows/draft-release-from-tag.yml b/.github/workflows/draft-release-from-tag.yml new file mode 100644 index 0000000000..f7a5df5444 --- /dev/null +++ b/.github/workflows/draft-release-from-tag.yml @@ -0,0 +1,13 @@ +#Allows creating a release by pushing a tag +#This might be useful for retroactive releases +name: Draft release from git tag + +on: + push: + tags: "*" + +jobs: + draft: + name: Create GitHub draft release + if: "startsWith(github.event.head_commit.message, 'Release ')" + uses: ./.github/workflows/draft-release.yml diff --git a/.github/workflows/draft-release-pr-check.yml b/.github/workflows/draft-release-pr-check.yml new file mode 100644 index 0000000000..4c8d0f6854 --- /dev/null +++ b/.github/workflows/draft-release-pr-check.yml @@ -0,0 +1,111 @@ +name: Release PR checks + +on: + #do checks on every PR update + pull_request: + branches: + - stable + - minor-next + - major-next + - "legacy/*" + paths: + - "src/VersionInfo.php" + + #allow this workflow to be invoked on PR merge, prior to creating the release + workflow_call: + outputs: + valid: + description: Whether this commit is valid for release + value: ${{ jobs.check-intent.outputs.valid && jobs.check-validity.result == 'success' }} + +permissions: + contents: read #for user access check + +jobs: + check-intent: + name: Check release trigger + runs-on: ubuntu-20.04 + + outputs: + valid: ${{ steps.validate.outputs.DEV_BUILD == 'false' }} + + steps: + - uses: actions/checkout@v4 + + - name: Check IS_DEVELOPMENT_BUILD flag + id: validate + run: | + echo DEV_BUILD=$(sed -n "s/^\s*public const IS_DEVELOPMENT_BUILD = \(true\|false\);$/\1/p" src/VersionInfo.php) >> $GITHUB_OUTPUT + + check-validity: + name: Validate release info + needs: [check-intent] + #don't do these checks if this isn't a release - we don't want to generate unnecessary failed statuses + if: needs.check-intent.outputs.valid == 'true' + + runs-on: ubuntu-20.04 + + steps: + - uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@2.31.1 + with: + php-version: 8.2 + + - name: Restore Composer package cache + uses: actions/cache@v4 + with: + path: | + ~/.cache/composer/files + ~/.cache/composer/vcs + key: "composer-v2-cache-${{ hashFiles('./composer.lock') }}" + restore-keys: | + composer-v2-cache- + + - name: Install Composer dependencies + run: composer install --no-dev --prefer-dist --no-interaction --ignore-platform-reqs + + - name: Check author permissions + id: check-permission + uses: actions-cool/check-user-permission@v2 + with: + token: ${{ secrets.GITHUB_TOKEN }} + require: write + username: ${{ github.event.pull_request.user.login }} + #technically this would be fine for dependabot but generally bots don't count as team members + check-bot: true + + - name: Abort if user permissions are insufficient + #user doesn't have permission or is a bot + if: steps.check-permission.outputs.require-result != 'true' || steps.check-permission.outputs.check-result != 'false' + run: | + echo "::error::This user is not authorized to trigger releases" + exit 1 + + - name: Check changelog file is present + id: file-presence + run: | + CHANGELOG_FILE="changelogs/$(php build/dump-version-info.php changelog_file_name)" + if [ ! -f "${{ github.workspace }}/$CHANGELOG_FILE" ]; then + echo "::error::$CHANGELOG_FILE does not exist" + exit 1 + fi + echo FILE="$CHANGELOG_FILE" >> $GITHUB_OUTPUT + + - name: Check header is present in changelog file + run: | + FILE="${{ steps.file-presence.outputs.FILE }}" + VERSION="$(php build/dump-version-info.php base_version)" + if ! grep -Fqx "# $VERSION" "${{ github.workspace }}/$FILE"; then + echo "::error::Header for $VERSION not found in $FILE" + exit 1 + fi + + - name: Check version is valid for the selected channel + run: | + CHANNEL="$(php build/dump-version-info.php channel)" + if [ "$(php build/dump-version-info.php suffix_valid)" != "true" ]; then + echo "::error::Version $(php build/dump-version-info.php base_version) is not allowed on the $CHANNEL channel" + exit 1 + fi diff --git a/.github/workflows/draft-release.yml b/.github/workflows/draft-release.yml index f73bc5f28c..cd1841e4f1 100644 --- a/.github/workflows/draft-release.yml +++ b/.github/workflows/draft-release.yml @@ -1,29 +1,41 @@ name: Draft release on: - push: - tags: "*" + workflow_call: + outputs: + draft-url: + description: 'The URL of the draft release' + value: ${{ jobs.draft.outputs.draft-url }} + version: + description: 'PocketMine-MP version' + value: ${{ jobs.draft.outputs.version }} jobs: draft: name: Create GitHub draft release - if: "startsWith(github.event.head_commit.message, 'Release ')" + runs-on: ubuntu-20.04 strategy: fail-fast: false + matrix: + php-version: [8.2] + + outputs: + draft-url: ${{ steps.create-draft.outputs.html_url }} + version: ${{ steps.get-pm-version.outputs.PM_VERSION }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - name: Setup PHP - uses: shivammathur/setup-php@2.23.0 + uses: shivammathur/setup-php@2.31.1 with: - php-version: 8.0 + php-version: ${{ matrix.php-version }} - name: Restore Composer package cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ~/.cache/composer/files @@ -40,7 +52,7 @@ jobs: run: | BUILD_NUMBER=$((2000+$GITHUB_RUN_NUMBER)) #to stay above jenkins echo "Build number: $BUILD_NUMBER" - echo ::set-output name=BUILD_NUMBER::$BUILD_NUMBER + echo BUILD_NUMBER=$BUILD_NUMBER >> $GITHUB_OUTPUT - name: Minify BedrockData JSON files run: php vendor/pocketmine/bedrock-data/.minify_json.php @@ -51,33 +63,57 @@ jobs: - name: Get PocketMine-MP release version id: get-pm-version run: | - echo ::set-output name=PM_VERSION::$(php -r 'require "vendor/autoload.php"; echo \pocketmine\VersionInfo::BASE_VERSION;') - echo ::set-output name=MCPE_VERSION::$(php -r 'require "vendor/autoload.php"; echo \pocketmine\network\mcpe\protocol\ProtocolInfo::MINECRAFT_VERSION_NETWORK;') - echo ::set-output name=PM_VERSION_SHORT::$(php -r 'require "vendor/autoload.php"; $v = explode(".", \pocketmine\VersionInfo::BASE_VERSION); array_pop($v); echo implode(".", $v);') - echo ::set-output name=PM_VERSION_MD::$(php -r 'require "vendor/autoload.php"; echo str_replace(".", "", \pocketmine\VersionInfo::BASE_VERSION);') + echo PM_VERSION=$(php build/dump-version-info.php base_version) >> $GITHUB_OUTPUT + echo PM_MAJOR=$(php build/dump-version-info.php major_version) >> $GITHUB_OUTPUT + echo MCPE_VERSION=$(php build/dump-version-info.php mcpe_version) >> $GITHUB_OUTPUT + echo CHANGELOG_FILE_NAME=$(php build/dump-version-info.php changelog_file_name) >> $GITHUB_OUTPUT + echo CHANGELOG_MD_HEADER=$(php build/dump-version-info.php changelog_md_header) >> $GITHUB_OUTPUT + echo PRERELEASE=$(php build/dump-version-info.php prerelease) >> $GITHUB_OUTPUT + + - name: Generate PHP binary download URL + id: php-binary-url + run: | + echo PHP_BINARY_URL="${{ github.server_url }}/${{ github.repository_owner }}/PHP-Binaries/releases/tag/pm${{ steps.get-pm-version.outputs.PM_MAJOR }}-php-${{ matrix.php-version }}-latest" >> $GITHUB_OUTPUT - name: Generate build info - run: php build/generate-build-info-json.php ${{ github.sha }} ${{ steps.get-pm-version.outputs.PM_VERSION }} ${{ github.repository }} ${{ steps.build-number.outputs.BUILD_NUMBER }} ${{ github.run_id }} > build_info.json + run: | + php build/generate-build-info-json.php \ + ${{ github.sha }} \ + ${{ steps.get-pm-version.outputs.PM_VERSION }} \ + ${{ github.repository }} \ + ${{ steps.build-number.outputs.BUILD_NUMBER }} \ + ${{ github.run_id }} \ + ${{ steps.php-binary-url.outputs.PHP_BINARY_URL }} \ + > build_info.json + + - name: Generate core permission doc for doc.pmmp.io + run: php tools/generate-permission-doc.php rst - name: Upload release artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: release_artifacts path: | ${{ github.workspace }}/PocketMine-MP.phar ${{ github.workspace }}/start.* ${{ github.workspace }}/build_info.json + ${{ github.workspace }}/core-permissions.rst - name: Create draft release - uses: ncipollo/release-action@v1.12.0 + uses: ncipollo/release-action@v1.14.0 + id: create-draft with: - artifacts: ${{ github.workspace }}/PocketMine-MP.phar,${{ github.workspace }}/start.*,${{ github.workspace }}/build_info.json + artifacts: ${{ github.workspace }}/PocketMine-MP.phar,${{ github.workspace }}/start.*,${{ github.workspace }}/build_info.json,${{ github.workspace }}/core-permissions.rst commit: ${{ github.sha }} draft: true + prerelease: ${{ steps.get-pm-version.outputs.PRERELEASE }} name: PocketMine-MP ${{ steps.get-pm-version.outputs.PM_VERSION }} tag: ${{ steps.get-pm-version.outputs.PM_VERSION }} token: ${{ secrets.GITHUB_TOKEN }} + skipIfReleaseExists: true #for release PRs, tags will be created on release publish and trigger the tag release workflow - don't create a second draft body: | **For Minecraft: Bedrock Edition ${{ steps.get-pm-version.outputs.MCPE_VERSION }}** - Please see the [changelogs](${{ github.server_url }}/${{ github.repository }}/blob/${{ steps.get-pm-version.outputs.PM_VERSION }}/changelogs/${{ steps.get-pm-version.outputs.PM_VERSION_SHORT }}.md#${{ steps.get-pm-version.outputs.PM_VERSION_MD }}) for details. + Please see the [changelogs](${{ github.server_url }}/${{ github.repository }}/blob/${{ steps.get-pm-version.outputs.PM_VERSION }}/changelogs/${{ steps.get-pm-version.outputs.CHANGELOG_FILE_NAME }}#${{ steps.get-pm-version.outputs.CHANGELOG_MD_HEADER }}) for details. + + :information_source: Download the recommended PHP binary [here](${{ steps.php-binary-url.outputs.PHP_BINARY_URL }}). diff --git a/.github/workflows/main-php-matrix.yml b/.github/workflows/main-php-matrix.yml new file mode 100644 index 0000000000..e26f7c3187 --- /dev/null +++ b/.github/workflows/main-php-matrix.yml @@ -0,0 +1,156 @@ +name: CI (all supported PHP versions) + +on: + workflow_call: + inputs: + php: + description: 'PHP version in X.Y format' + required: true + type: string + + #these are parameterized to ease updating + pm-version-major: + description: 'PocketMine-MP major version' + default: 5 + type: number + image: + description: 'Runner image to use' + default: 'ubuntu-20.04' + type: string + +jobs: + phpstan: + name: PHPStan analysis + runs-on: ${{ inputs.image }} + + strategy: + fail-fast: false + + steps: + - uses: actions/checkout@v4 + + - name: Setup PHP + uses: pmmp/setup-php-action@3.2.0 + with: + php-version: ${{ inputs.php }} + install-path: "./bin" + pm-version-major: ${{ inputs.pm-version-major }} + + - name: Restore Composer package cache + uses: actions/cache@v4 + with: + path: | + ~/.cache/composer/files + ~/.cache/composer/vcs + key: "composer-v2-cache-${{ inputs.php }}-${{ hashFiles('./composer.lock') }}" + restore-keys: | + composer-v2-cache- + + - name: Install Composer dependencies + run: composer install --prefer-dist --no-interaction + + - name: Run PHPStan + run: ./vendor/bin/phpstan analyze --no-progress --memory-limit=2G + + phpunit: + name: PHPUnit tests + runs-on: ${{ inputs.image }} + strategy: + fail-fast: false + + steps: + - uses: actions/checkout@v4 + + - name: Setup PHP + uses: pmmp/setup-php-action@3.2.0 + with: + php-version: ${{ inputs.php }} + install-path: "./bin" + pm-version-major: ${{ inputs.pm-version-major }} + + - name: Restore Composer package cache + uses: actions/cache@v4 + with: + path: | + ~/.cache/composer/files + ~/.cache/composer/vcs + key: "composer-v2-cache-${{ inputs.php }}-${{ hashFiles('./composer.lock') }}" + restore-keys: | + composer-v2-cache- + + - name: Install Composer dependencies + run: composer install --prefer-dist --no-interaction + + - name: Run PHPUnit tests + run: ./vendor/bin/phpunit --bootstrap vendor/autoload.php --fail-on-warning tests/phpunit + + integration: + name: Integration tests + runs-on: ${{ inputs.image }} + strategy: + fail-fast: false + + steps: + - uses: actions/checkout@v4 + with: + submodules: true + + - name: Setup PHP + uses: pmmp/setup-php-action@3.2.0 + with: + php-version: ${{ inputs.php }} + install-path: "./bin" + pm-version-major: ${{ inputs.pm-version-major }} + + - name: Restore Composer package cache + uses: actions/cache@v4 + with: + path: | + ~/.cache/composer/files + ~/.cache/composer/vcs + key: "composer-v2-cache-${{ inputs.php }}-${{ hashFiles('./composer.lock') }}" + restore-keys: | + composer-v2-cache- + + - name: Install Composer dependencies + run: composer install --no-dev --prefer-dist --no-interaction + + - name: Run integration tests + run: ./tests/travis.sh -t4 + + codegen: + name: Generated Code consistency checks + runs-on: ${{ inputs.image }} + strategy: + fail-fast: false + + steps: + - uses: actions/checkout@v4 + + - name: Setup PHP + uses: pmmp/setup-php-action@3.2.0 + with: + php-version: ${{ inputs.php }} + install-path: "./bin" + pm-version-major: ${{ inputs.pm-version-major }} + + - name: Restore Composer package cache + uses: actions/cache@v4 + with: + path: | + ~/.cache/composer/files + ~/.cache/composer/vcs + key: "composer-v2-cache-${{ inputs.php }}-${{ hashFiles('./composer.lock') }}" + restore-keys: | + composer-v2-cache- + + - name: Install Composer dependencies + run: composer install --no-dev --prefer-dist --no-interaction + + - name: Update generated code + run: composer update-codegen + + - name: Verify code is unchanged + run: | + git diff + git diff --quiet diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a24e3db203..b5a9740b5c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -6,184 +6,17 @@ on: workflow_dispatch: jobs: - build-php: - name: Prepare PHP - runs-on: ${{ matrix.image }} - - strategy: - matrix: - image: [ubuntu-20.04] - php: [8.0.23, 8.1.10] - - steps: - - name: Build and prepare PHP cache - uses: pmmp/setup-php-action@82a44d659bf5046612c69f036af3e14dc32e3fa8 - with: - php-version: ${{ matrix.php }} - install-path: "./bin" - - phpstan: - name: PHPStan analysis - needs: build-php - runs-on: ${{ matrix.image }} - + all-php-versions: + name: PHP ${{ matrix.php }} strategy: fail-fast: false matrix: - image: [ubuntu-20.04] - php: [8.0.23, 8.1.10] + php: ["8.1", "8.2", "8.3"] - steps: - - uses: actions/checkout@v3 - - - name: Setup PHP - uses: pmmp/setup-php-action@82a44d659bf5046612c69f036af3e14dc32e3fa8 - with: - php-version: ${{ matrix.php }} - install-path: "./bin" - - - name: Install Composer - run: curl -sS https://getcomposer.org/installer | php - - - name: Restore Composer package cache - uses: actions/cache@v3 - with: - path: | - ~/.cache/composer/files - ~/.cache/composer/vcs - key: "composer-v2-cache-${{ matrix.php }}-${{ hashFiles('./composer.lock') }}" - restore-keys: | - composer-v2-cache- - - - name: Install Composer dependencies - run: php composer.phar install --prefer-dist --no-interaction - - - name: Run PHPStan - run: ./vendor/bin/phpstan analyze --no-progress --memory-limit=2G - - phpunit: - name: PHPUnit tests - needs: build-php - runs-on: ${{ matrix.image }} - strategy: - fail-fast: false - matrix: - image: [ubuntu-20.04] - php: [8.0.23, 8.1.10] - - steps: - - uses: actions/checkout@v3 - - - name: Setup PHP - uses: pmmp/setup-php-action@82a44d659bf5046612c69f036af3e14dc32e3fa8 - with: - php-version: ${{ matrix.php }} - install-path: "./bin" - - - name: Install Composer - run: curl -sS https://getcomposer.org/installer | php - - - name: Restore Composer package cache - uses: actions/cache@v3 - with: - path: | - ~/.cache/composer/files - ~/.cache/composer/vcs - key: "composer-v2-cache-${{ matrix.php }}-${{ hashFiles('./composer.lock') }}" - restore-keys: | - composer-v2-cache- - - - name: Install Composer dependencies - run: php composer.phar install --prefer-dist --no-interaction - - - name: Run PHPUnit tests - run: ./vendor/bin/phpunit --bootstrap vendor/autoload.php --fail-on-warning tests/phpunit - - integration: - name: Integration tests - needs: build-php - runs-on: ${{ matrix.image }} - strategy: - fail-fast: false - matrix: - image: [ubuntu-20.04] - php: [8.0.23, 8.1.10] - - steps: - - uses: actions/checkout@v3 - with: - submodules: true - - - name: Setup PHP - uses: pmmp/setup-php-action@82a44d659bf5046612c69f036af3e14dc32e3fa8 - with: - php-version: ${{ matrix.php }} - install-path: "./bin" - - - name: Install Composer - run: curl -sS https://getcomposer.org/installer | php - - - name: Restore Composer package cache - uses: actions/cache@v3 - with: - path: | - ~/.cache/composer/files - ~/.cache/composer/vcs - key: "composer-v2-cache-${{ matrix.php }}-${{ hashFiles('./composer.lock') }}" - restore-keys: | - composer-v2-cache- - - - name: Install Composer dependencies - run: php composer.phar install --no-dev --prefer-dist --no-interaction - - - name: Run integration tests - run: ./tests/travis.sh -t4 - - codegen: - name: Generated Code consistency checks - needs: build-php - runs-on: ${{ matrix.image }} - strategy: - fail-fast: false - matrix: - image: [ubuntu-20.04] - php: [8.0.23, 8.1.10] - - steps: - - uses: actions/checkout@v3 - - - name: Setup PHP - uses: pmmp/setup-php-action@82a44d659bf5046612c69f036af3e14dc32e3fa8 - with: - php-version: ${{ matrix.php }} - install-path: "./bin" - - - name: Install Composer - run: curl -sS https://getcomposer.org/installer | php - - - name: Restore Composer package cache - uses: actions/cache@v3 - with: - path: | - ~/.cache/composer/files - ~/.cache/composer/vcs - key: "composer-v2-cache-${{ matrix.php }}-${{ hashFiles('./composer.lock') }}" - restore-keys: | - composer-v2-cache- - - - name: Install Composer dependencies - run: php composer.phar install --no-dev --prefer-dist --no-interaction - - - name: Regenerate registry annotations - run: php build/generate-registry-annotations.php src - - - name: Regenerate KnownTranslation APIs - run: php build/generate-known-translation-apis.php - - - name: Verify code is unchanged - run: | - git diff - git diff --quiet + uses: ./.github/workflows/main-php-matrix.yml + with: + php: ${{ matrix.php }} + secrets: inherit codestyle: name: Code Style checks @@ -192,15 +25,27 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup PHP and tools - uses: shivammathur/setup-php@2.23.0 + uses: shivammathur/setup-php@2.31.1 with: - php-version: 8.0 - tools: php-cs-fixer:3.11 + php-version: 8.2 + tools: php-cs-fixer:3.49 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Run PHP-CS-Fixer run: php-cs-fixer fix --dry-run --diff --ansi + + shellcheck: + name: ShellCheck + runs-on: ubuntu-20.04 + strategy: + fail-fast: false + + steps: + - uses: actions/checkout@v4 + + - name: Run ShellCheck + uses: ludeeus/action-shellcheck@2.0.0 diff --git a/.github/workflows/pr-remove-waiting-label.yml b/.github/workflows/pr-remove-waiting-label.yml new file mode 100644 index 0000000000..eb46043bdd --- /dev/null +++ b/.github/workflows/pr-remove-waiting-label.yml @@ -0,0 +1,33 @@ +name: Remove waiting label from PRs + +on: + pull_request_target: + types: synchronize + +jobs: + delabel: + name: Remove label + runs-on: ubuntu-latest + + steps: + - name: Remove label + uses: actions/github-script@v7 + with: + github-token: ${{ github.token }} + script: | + const [owner, repo] = context.payload.repository.full_name.split('/'); + try { + await github.rest.issues.removeLabel({ + owner: owner, + repo: repo, + issue_number: context.payload.number, + name: "Status: Waiting on Author", + }); + } catch (error) { + if (error.status === 404) { + //probably label wasn't set on the issue + console.log('Failed to remove label (probably label isn\'t on the PR): ' + error.message); + } else { + throw error; + } + } diff --git a/.github/workflows/support.yml b/.github/workflows/support.yml index fe726dfef1..68da365cb5 100644 --- a/.github/workflows/support.yml +++ b/.github/workflows/support.yml @@ -8,7 +8,7 @@ jobs: support: runs-on: ubuntu-latest steps: - - uses: dessant/support-requests@v3 + - uses: dessant/support-requests@v4 with: github-token: ${{ github.token }} support-label: "Support request" diff --git a/.github/workflows/team-pr-auto-approve.yml b/.github/workflows/team-pr-auto-approve.yml new file mode 100644 index 0000000000..0c2fdd81c0 --- /dev/null +++ b/.github/workflows/team-pr-auto-approve.yml @@ -0,0 +1,38 @@ +#Due to GitHub awkwardness, it's not easy to reduce the review requirement for collaborators. +#Our policy is that 2 collaborators should be aware of every change. +#For outside PRs, this means 2 collaborator reviews. +#For PRs made by collaborators, this means 1 reviewer + the author. +#We trust that collaborators don't need as much oversight. +name: Auto approve collaborator PRs + +on: + pull_request_target: + types: + - opened + - reopened + - ready_for_review + - synchronize + +jobs: + dispatch: + name: Request approval + runs-on: ubuntu-latest + if: '! github.event.pull_request.draft' + + steps: + - name: Generate access token + id: generate-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ vars.RESTRICTED_ACTIONS_DISPATCH_ID }} + private-key: ${{ secrets.RESTRICTED_ACTIONS_DISPATCH_KEY }} + owner: ${{ github.repository_owner }} + repositories: RestrictedActions + + - name: Dispatch restricted action + uses: peter-evans/repository-dispatch@v3 + with: + token: ${{ steps.generate-token.outputs.token }} + repository: ${{ github.repository_owner }}/RestrictedActions + event-type: auto_approve_collaborator_pr + client-payload: '{"repo": "${{ github.repository }}", "pull_request_id": "${{ github.event.pull_request.number }}", "reviewer_id": "0" }' diff --git a/.github/workflows/update-php-versions.php b/.github/workflows/update-php-versions.php deleted file mode 100644 index 7ff7985665..0000000000 --- a/.github/workflows/update-php-versions.php +++ /dev/null @@ -1,50 +0,0 @@ -> $GITHUB_OUTPUT - name: Download new release information run: curl -f -L ${{ github.server_url }}/${{ github.repository }}/releases/download/${{ steps.tag-name.outputs.TAG_NAME }}/build_info.json -o new_build_info.json - - name: Detect channel + - name: Detect channels id: channel - run: echo ::set-output name=CHANNEL::$(jq -r '.channel' new_build_info.json) - - - name: Copy release information run: | - cp new_build_info.json channels/${{ steps.channel.outputs.CHANNEL }}.json + CHANNEL=$(jq -r '.channel' new_build_info.json) + VERSION=${{ steps.tag-name.outputs.TAG_NAME }} + echo CHANNEL=$CHANNEL >> $GITHUB_OUTPUT + if [ "$CHANNEL" == "stable" ]; then + echo MAJOR=$(echo $VERSION | cut -d. -f1) >> $GITHUB_OUTPUT + echo MINOR=$(echo $VERSION | cut -d. -f1-2) >> $GITHUB_OUTPUT + else + echo MAJOR=$(echo $VERSION | cut -d. -f1)-$CHANNEL >> $GITHUB_OUTPUT + echo MINOR=$(echo $VERSION | cut -d. -f1-2)-$CHANNEL >> $GITHUB_OUTPUT + fi + + - name: Update channel info + run: | + function version_id() { + major=$(echo $1 | cut -d. -f1) + minor=$(echo $1 | cut -d. -f2) + patch=$(echo $1 | cut -d. -f3) + echo $(((major * 1000000) + (minor * 1000) + patch)) + } + + function update_channel() { + local target_file_name="$1" + local new_file_name="$2" + + local old_version_id + local new_version_id + + if [ ! -f "$target_file_name" ]; then + echo "Creating channel file: $target_file_name" + cp "$new_file_name" "$target_file_name" + else + old_version_id=$(version_id "$(jq -r '.base_version' "$target_file_name")") + new_version_id=$(version_id "$(jq -r '.base_version' "$new_file_name")") + + echo "Old version ID: $old_version_id" + echo "New version ID: $new_version_id" + + if [ $new_version_id -ge $old_version_id ]; then #suffixed versions will have the same version ID - assume they'll always be newer + echo "Updating channel file: $target_file_name ($old_version_id -> $new_version_id)" + cp "$new_file_name" "$target_file_name" + else + echo "Version $new_version_id is less than $old_version_id, not updating channel file: $target_file_name" + fi + fi + } + + update_channel "channels/${{ steps.channel.outputs.CHANNEL }}.json" "new_build_info.json" + update_channel "channels/${{ steps.channel.outputs.MAJOR }}.json" "new_build_info.json" + update_channel "channels/${{ steps.channel.outputs.MINOR }}.json" "new_build_info.json" rm new_build_info.json - name: Commit changes diff --git a/.gitignore b/.gitignore index 13c3473764..6456250a6d 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,6 @@ Documentation/* # php-cs-fixer /.php_cs.cache /.php-cs-fixer.cache + +# install-local-protocol.sh +/composer-local-protocol.* diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index c3fac9558d..466a1a3a40 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -30,6 +30,13 @@