diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
new file mode 100644
index 00000000000..560dcad5af7
--- /dev/null
+++ b/.git-blame-ignore-revs
@@ -0,0 +1,4 @@
+# .git-blame-ignore-revs
+
+# cleanup lang package - mostly renaming variables
+98abf5d7773df11c65d66e4e9485d0f1e3ef8821
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 191b0e340d9..5b930003730 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -1,12 +1,14 @@
version: 2
updates:
- package-ecosystem: "github-actions"
+ target-branch: "dev/patch"
directory: "/"
schedule:
interval: "weekly"
labels:
- "dependencies"
- package-ecosystem: "gradle"
+ target-branch: "dev/patch"
directory: "/"
schedule:
interval: "weekly"
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index ce87d77a996..698a65a0554 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -2,6 +2,6 @@
---
-**Target Minecraft Versions:**
-**Requirements:**
-**Related Issues:**
+**Target Minecraft Versions:** any
+**Requirements:** none
+**Related Issues:** none
diff --git a/.github/workflows/archive-docs.yml b/.github/workflows/archive-docs.yml
new file mode 100644
index 00000000000..e183f748d78
--- /dev/null
+++ b/.github/workflows/archive-docs.yml
@@ -0,0 +1,45 @@
+name: Archive documentation
+
+on:
+ release:
+ types: [published]
+ workflow_dispatch:
+
+jobs:
+ archive-docs:
+ if: "! contains(toJSON(github.event.commits.*.message), '[ci skip]')"
+ needs: release-docs
+ runs-on: ubuntu-latest
+ steps:
+ - name: Configure workflow
+ id: configuration
+ run: |
+ echo "BRANCH_NAME=${GITHUB_REF#refs/*/}" >> $GITHUB_OUTPUT
+ echo "DOCS_OUTPUT_DIR=${GITHUB_WORKSPACE}/skript-docs/docs/archives/${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
+ echo "DOCS_REPO_DIR=${GITHUB_WORKSPACE}/skript-docs" >> $GITHUB_OUTPUT
+ echo "SKRIPT_REPO_DIR=${GITHUB_WORKSPACE}/skript" >> $GITHUB_OUTPUT
+ - name: Checkout Skript
+ uses: actions/checkout@v4
+ with:
+ submodules: recursive
+ path: skript
+ - name: Setup documentation environment
+ uses: ./skript/.github/workflows/docs/setup-docs
+ with:
+ docs_deploy_key: ${{ secrets.DOCS_DEPLOY_KEY }}
+ docs_output_dir: ${{ steps.configuration.outputs.DOCS_OUTPUT_DIR }}
+ - name: Generate documentation
+ uses: ./skript/.github/workflows/docs/generate-docs
+ with:
+ docs_output_dir: ${{ steps.configuration.outputs.DOCS_OUTPUT_DIR }}
+ docs_repo_dir: ${{ steps.configuration.outputs.DOCS_REPO_DIR }}
+ skript_repo_dir: ${{ steps.configuration.outputs.SKRIPT_REPO_DIR }}
+ is_release: true
+ generate_javadocs: true
+ - name: Push archive documentation
+ uses: ./skript/.github/workflows/docs/push-docs
+ with:
+ docs_repo_dir: ${{ steps.configuration.outputs.DOCS_REPO_DIR }}
+ git_name: Archive Docs Bot
+ git_email: archivedocs@skriptlang.org
+ git_commit_message: "Update ${{ steps.configuration.outputs.BRANCH_NAME }} archive docs"
diff --git a/.github/workflows/cleanup-docs.yml b/.github/workflows/cleanup-docs.yml
new file mode 100644
index 00000000000..68d12e84dc1
--- /dev/null
+++ b/.github/workflows/cleanup-docs.yml
@@ -0,0 +1,39 @@
+name: Cleanup nightly documentation
+on: delete
+jobs:
+ cleanup-nightly-docs:
+ if: github.event.ref_type == 'branch'
+ runs-on: ubuntu-latest
+ steps:
+ - name: Configure workflow
+ id: configuration
+ env:
+ DELETED_BRANCH: ${{ github.event.ref }}
+ run: |
+ BRANCH_NAME="${DELETED_BRANCH#refs/*/}"
+ echo "BRANCH_NAME=${BRANCH_NAME}" >> $GITHUB_OUTPUT
+ echo "DOCS_OUTPUT_DIR=${GITHUB_WORKSPACE}/skript-docs/docs/nightly/${BRANCH_NAME}" >> $GITHUB_OUTPUT
+ echo "DOCS_REPO_DIR=${GITHUB_WORKSPACE}/skript-docs" >> $GITHUB_OUTPUT
+ - name: Checkout Skript
+ uses: actions/checkout@v4
+ with:
+ ref: ${{ github.event.repository.default_branch }}
+ submodules: recursive
+ path: skript
+ - name: Setup documentation environment
+ uses: ./skript/.github/workflows/docs/setup-docs
+ with:
+ docs_deploy_key: ${{ secrets.DOCS_DEPLOY_KEY }}
+ docs_output_dir: ${{ steps.configuration.outputs.DOCS_OUTPUT_DIR }}
+ - name: Cleanup nightly documentation
+ env:
+ DOCS_OUTPUT_DIR: ${{ steps.configuration.outputs.DOCS_OUTPUT_DIR }}
+ run: |
+ rm -rf ${DOCS_OUTPUT_DIR} || true
+ - name: Push nightly documentation cleanup
+ uses: ./skript/.github/workflows/docs/push-docs
+ with:
+ docs_repo_dir: ${{ steps.configuration.outputs.DOCS_REPO_DIR }}
+ git_name: Nightly Docs Bot
+ git_email: nightlydocs@skriptlang.org
+ git_commit_message: "Delete ${{ steps.configuration.outputs.BRANCH_NAME }} branch nightly docs"
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
deleted file mode 100644
index e41c4bf7692..00000000000
--- a/.github/workflows/docs.yml
+++ /dev/null
@@ -1,59 +0,0 @@
-name: Nightly Docs
-
-on:
- push:
- branches:
- - master
- - 'dev/**'
-
-jobs:
- docs:
- if: "! contains(toJSON(github.event.commits.*.message), '[ci skip]')"
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v3
- with:
- submodules: recursive
- path: skript
- - name: Set up JDK 17
- uses: actions/setup-java@v3
- with:
- java-version: '17'
- distribution: 'adopt'
- cache: gradle
- - name: Grant execute permission for gradlew
- run: chmod +x ./skript/gradlew
- - name: Checkout skript-docs
- uses: actions/checkout@v3
- with:
- repository: 'SkriptLang/skript-docs'
- path: skript-docs
- ssh-key: ${{ secrets.DOCS_DEPLOY_KEY }}
- - name: Setup documentation environment
- env:
- DOCS_DEPLOY_KEY: ${{ secrets.DOCS_DEPLOY_KEY }}
- run: |
- eval `ssh-agent`
- DOC_DIR="${GITHUB_WORKSPACE}/skript-docs/docs/nightly/${GITHUB_REF#refs/heads/}"
- rm -r ${DOC_DIR}/* || true
- echo "DOC_DIR=${DOC_DIR}" >> $GITHUB_ENV
- echo "SKRIPT_DOCS_TEMPLATE_DIR=${GITHUB_WORKSPACE}/skript-docs/doc-templates" >> $GITHUB_ENV
- echo "SKRIPT_DOCS_OUTPUT_DIR=${DOC_DIR}/" >> $GITHUB_ENV
- echo "$DOCS_DEPLOY_KEY" | tr -d '\r' | ssh-add - > /dev/null
- mkdir ~/.ssh
- ssh-keyscan www.github.com >> ~/.ssh/known_hosts
- - name: Build Skript and generate docs
- run: |
- cd ./skript
- ./gradlew clean genDocs javadoc
- mv "${GITHUB_WORKSPACE}/skript/build/docs/javadoc" "${DOC_DIR}/javadocs"
- cd ..
- - name: Push nightly docs
- if: success()
- run: |
- cd ./skript-docs
- git config user.email "nightlydocs@skriptlang.org"
- git config user.name "Nightly Docs Bot"
- git add docs/nightly
- git commit -m "Update nightly docs" || (echo "Nothing to push!" && exit 0)
- git push origin main
diff --git a/.github/workflows/docs/generate-docs/action.yml b/.github/workflows/docs/generate-docs/action.yml
new file mode 100644
index 00000000000..2470f852450
--- /dev/null
+++ b/.github/workflows/docs/generate-docs/action.yml
@@ -0,0 +1,109 @@
+name: Generate documentation
+
+inputs:
+ docs_output_dir:
+ description: "The directory to generate the documentation into"
+ required: true
+ type: string
+ docs_repo_dir:
+ description: "The skript-docs repository directory"
+ required: true
+ type: string
+ skript_repo_dir:
+ description: "The skript repository directory"
+ required: true
+ type: string
+ is_release:
+ description: "Designates whether to generate nightly or release documentation"
+ required: false
+ default: false
+ type: boolean
+ cleanup_pattern:
+ description: "A pattern designating which files to delete when cleaning the documentation output directory"
+ required: false
+ default: "*"
+ type: string
+ generate_javadocs:
+ description: "Designates whether to generate javadocs for this nightly documentation"
+ required: false
+ default: false
+ type: boolean
+
+outputs:
+ DOCS_CHANGED:
+ description: "Whether or not the documentation has changed since the last push"
+ value: ${{ steps.generate.outputs.DOCS_CHANGED }}
+
+runs:
+ using: 'composite'
+ steps:
+ - name: generate-docs
+ id: generate
+ shell: bash
+ env:
+ DOCS_OUTPUT_DIR: ${{ inputs.docs_output_dir }}
+ DOCS_REPO_DIR: ${{ inputs.docs_repo_dir }}
+ SKRIPT_REPO_DIR: ${{ inputs.skript_repo_dir }}
+ IS_RELEASE: ${{ inputs.is_release }}
+ CLEANUP_PATTERN: ${{ inputs.cleanup_pattern }}
+ GENERATE_JAVADOCS: ${{ inputs.generate_javadocs }}
+ run: |
+ replace_in_directory() {
+ find $1 -type f -exec sed -i -e "s/$2/$3/g" {} \;
+ }
+
+ # this should be replaced with a more reliable jq command,
+ # but it can't be right now because docs.json is actually not valid json.
+ get_skript_version_of_directory() {
+ grep skriptVersion "$1/docs.json" | cut -d\" -f 4
+ }
+
+ if [ -d "${DOCS_REPO_DIR}/docs/templates" ]
+ then
+ export SKRIPT_DOCS_TEMPLATE_DIR=${DOCS_REPO_DIR}/docs/templates
+ else # compatibility for older versions
+ export SKRIPT_DOCS_TEMPLATE_DIR=${DOCS_REPO_DIR}/doc-templates
+ fi
+
+ export SKRIPT_DOCS_OUTPUT_DIR=/tmp/generated-docs
+
+ cd $SKRIPT_REPO_DIR
+ if [[ "${IS_RELEASE}" == "true" ]]; then
+ ./gradlew genReleaseDocs javadoc
+ elif [[ "${GENERATE_JAVADOCS}" == "true" ]]; then
+ ./gradlew genNightlyDocs javadoc
+ else
+ ./gradlew genNightlyDocs
+ fi
+
+ if [ -d "${DOCS_OUTPUT_DIR}" ]; then
+ if [[ "${GENERATE_JAVADOCS}" == "true" ]] || [[ "${IS_RELEASE}" == "true" ]] ; then
+ mkdir -p "${SKRIPT_DOCS_OUTPUT_DIR}/javadocs" && cp -a "./build/docs/javadoc/." "$_"
+ fi
+
+ mkdir -p "/tmp/normalized-output-docs" && cp -a "${DOCS_OUTPUT_DIR}/." "$_"
+ mkdir -p "/tmp/normalized-generated-docs" && cp -a "${SKRIPT_DOCS_OUTPUT_DIR}/." "$_"
+
+ output_skript_version=$(get_skript_version_of_directory "/tmp/normalized-output-docs")
+ generated_skript_version=$(get_skript_version_of_directory "/tmp/normalized-generated-docs")
+
+ replace_in_directory "/tmp/normalized-output-docs" "${output_skript_version}" "Skript"
+ replace_in_directory "/tmp/normalized-generated-docs" "${generated_skript_version}" "Skript"
+
+ diff -qbr /tmp/normalized-output-docs /tmp/normalized-generated-docs || diff_exit_code=$?
+ # If diff exits with exit code 1, that means there were some differences
+ if [[ ${diff_exit_code} -eq 1 ]]; then
+ echo "DOCS_CHANGED=true" >> $GITHUB_OUTPUT
+ echo "Documentation has changed since last push"
+ else
+ echo "Documentation hasn't changed since last push"
+ fi
+ else
+ echo "DOCS_CHANGED=true" >> $GITHUB_OUTPUT
+ echo "No existing documentation found"
+ fi
+
+ rm -rf ${DOCS_OUTPUT_DIR}/${CLEANUP_PATTERN} || true
+ mkdir -p "${DOCS_OUTPUT_DIR}/" && cp -a "${SKRIPT_DOCS_OUTPUT_DIR}/." "$_"
+
+
diff --git a/.github/workflows/docs/push-docs/action.yml b/.github/workflows/docs/push-docs/action.yml
new file mode 100644
index 00000000000..477a4c46aa4
--- /dev/null
+++ b/.github/workflows/docs/push-docs/action.yml
@@ -0,0 +1,43 @@
+name: Push documentation
+
+inputs:
+ docs_repo_dir:
+ description: "The skript-docs repository directory"
+ required: true
+ type: string
+ git_email:
+ description: "The email to use for the Git commit"
+ required: true
+ type: string
+ git_name:
+ description: "The name to use for the Git commit"
+ required: true
+ type: string
+ git_commit_message:
+ description: "The message to use for the Git commit"
+ required: true
+ type: string
+
+runs:
+ using: 'composite'
+ steps:
+ - shell: bash
+ if: success()
+ env:
+ DOCS_REPO_DIR: ${{ inputs.docs_repo_dir }}
+ GIT_EMAIL: ${{ inputs.git_email }}
+ GIT_NAME: ${{ inputs.git_name }}
+ GIT_COMMIT_MESSAGE: ${{ inputs.git_commit_message }}
+ run: |
+ cd "${DOCS_REPO_DIR}"
+ git config user.name "${GIT_NAME}"
+ git config user.email "${GIT_EMAIL}"
+ git add -A
+ git commit -m "${GIT_COMMIT_MESSAGE}" || (echo "Nothing to push!" && exit 0)
+ # Attempt rebasing and pushing 5 times in case another job pushes before us
+ for i in 1 2 3 4 5
+ do
+ git pull --rebase -X theirs origin main
+ git push origin main && break
+ sleep 5
+ done
diff --git a/.github/workflows/docs/setup-docs/action.yml b/.github/workflows/docs/setup-docs/action.yml
new file mode 100644
index 00000000000..3f9fe050f47
--- /dev/null
+++ b/.github/workflows/docs/setup-docs/action.yml
@@ -0,0 +1,43 @@
+name: Setup documentation environment
+
+inputs:
+ docs_deploy_key:
+ description: "Deploy key for the skript-docs repo"
+ required: true
+ type: string
+ docs_output_dir:
+ description: "The directory to generate the documentation into"
+ required: true
+ type: string
+ cleanup_pattern:
+ description: "A pattern designating which files to delete when cleaning the documentation output directory"
+ required: false
+ default: "*"
+ type: string
+
+runs:
+ using: 'composite'
+ steps:
+ - name: Checkout skript-docs
+ uses: actions/checkout@v3
+ with:
+ repository: 'SkriptLang/skript-docs'
+ path: skript-docs
+ ssh-key: ${{ inputs.docs_deploy_key }}
+ - uses: actions/setup-java@v3
+ with:
+ java-version: '21'
+ distribution: 'adopt'
+ cache: gradle
+ - shell: bash
+ run: chmod +x ./skript/gradlew
+ - shell: bash
+ env:
+ DOCS_DEPLOY_KEY: ${{ inputs.docs_deploy_key }}
+ DOCS_OUTPUT_DIR: ${{ inputs.docs_output_dir }}
+ CLEANUP_PATTERN: ${{ inputs.cleanup_pattern }}
+ run: |
+ eval `ssh-agent`
+ echo "$DOCS_DEPLOY_KEY" | tr -d '\r' | ssh-add - > /dev/null
+ mkdir ~/.ssh
+ ssh-keyscan www.github.com >> ~/.ssh/known_hosts
diff --git a/.github/workflows/java-11-builds.yml b/.github/workflows/java-11-builds.yml
new file mode 100644
index 00000000000..443aa925d0c
--- /dev/null
+++ b/.github/workflows/java-11-builds.yml
@@ -0,0 +1,35 @@
+name: Java 11 CI (MC 1.13-1.16)
+
+on:
+ push:
+ branches:
+ - master
+ - 'dev/**'
+ pull_request:
+
+jobs:
+ build:
+ if: "! contains(toJSON(github.event.commits.*.message), '[ci skip]')"
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ submodules: recursive
+ - name: validate gradle wrapper
+ uses: gradle/wrapper-validation-action@v2
+ - name: Set up JDK 21
+ uses: actions/setup-java@v4
+ with:
+ java-version: '21'
+ distribution: 'adopt'
+ cache: gradle
+ - name: Grant execute permission for gradlew
+ run: chmod +x gradlew
+ - name: Build Skript and run test scripts
+ run: ./gradlew clean skriptTestJava11
+ - name: Upload Nightly Build
+ uses: actions/upload-artifact@v4
+ if: success()
+ with:
+ name: skript-nightly
+ path: build/libs/*
diff --git a/.github/workflows/java-17-builds.yml b/.github/workflows/java-17-builds.yml
index 67007d76d90..2ca6d6bde61 100644
--- a/.github/workflows/java-17-builds.yml
+++ b/.github/workflows/java-17-builds.yml
@@ -1,4 +1,4 @@
-name: Java 17 CI (MC 1.17+)
+name: Java 17 CI (MC 1.17-1.20.4)
on:
push:
@@ -12,13 +12,15 @@ jobs:
if: "! contains(toJSON(github.event.commits.*.message), '[ci skip]')"
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
submodules: recursive
- - name: Set up JDK 17
- uses: actions/setup-java@v3
+ - name: validate gradle wrapper
+ uses: gradle/wrapper-validation-action@v2
+ - name: Set up JDK 21
+ uses: actions/setup-java@v4
with:
- java-version: '17'
+ java-version: '21'
distribution: 'adopt'
cache: gradle
- name: Grant execute permission for gradlew
@@ -26,7 +28,7 @@ jobs:
- name: Build Skript and run test scripts
run: ./gradlew clean skriptTestJava17
- name: Upload Nightly Build
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
if: success()
with:
name: skript-nightly
diff --git a/.github/workflows/java-8-builds.yml b/.github/workflows/java-21-builds.yml
similarity index 64%
rename from .github/workflows/java-8-builds.yml
rename to .github/workflows/java-21-builds.yml
index adcd71fb09b..6c82f22ce78 100644
--- a/.github/workflows/java-8-builds.yml
+++ b/.github/workflows/java-21-builds.yml
@@ -1,4 +1,4 @@
-name: Java 8 CI (MC 1.13-1.16)
+name: Java 21 CI (MC 1.20.6+)
on:
push:
@@ -12,21 +12,23 @@ jobs:
if: "! contains(toJSON(github.event.commits.*.message), '[ci skip]')"
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
submodules: recursive
- - name: Set up JDK 17
- uses: actions/setup-java@v3
+ - name: validate gradle wrapper
+ uses: gradle/wrapper-validation-action@v2
+ - name: Set up JDK 21
+ uses: actions/setup-java@v4
with:
- java-version: '17'
+ java-version: '21'
distribution: 'adopt'
cache: gradle
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build Skript and run test scripts
- run: ./gradlew clean skriptTestJava8
+ run: ./gradlew clean skriptTestJava21
- name: Upload Nightly Build
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
if: success()
with:
name: skript-nightly
diff --git a/.github/workflows/junit-8-builds.yml b/.github/workflows/junit-11-builds.yml
similarity index 64%
rename from .github/workflows/junit-8-builds.yml
rename to .github/workflows/junit-11-builds.yml
index 93971c79624..cdf75e4c43a 100644
--- a/.github/workflows/junit-8-builds.yml
+++ b/.github/workflows/junit-11-builds.yml
@@ -12,16 +12,18 @@ jobs:
if: "! contains(toJSON(github.event.commits.*.message), '[ci skip]')"
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
submodules: recursive
- - name: Set up JDK 17
- uses: actions/setup-java@v3
+ - name: validate gradle wrapper
+ uses: gradle/wrapper-validation-action@v2
+ - name: Set up JDK 21
+ uses: actions/setup-java@v4
with:
- java-version: '17'
+ java-version: '21'
distribution: 'adopt'
cache: gradle
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build Skript and run JUnit
- run: ./gradlew clean JUnitJava8
+ run: ./gradlew clean JUnitJava11
diff --git a/.github/workflows/junit-17-builds.yml b/.github/workflows/junit-17-builds.yml
index eca1ebb9706..238bd9b132e 100644
--- a/.github/workflows/junit-17-builds.yml
+++ b/.github/workflows/junit-17-builds.yml
@@ -1,4 +1,4 @@
-name: JUnit (MC 1.17+)
+name: JUnit (MC 1.17-1.20.4)
on:
push:
@@ -12,13 +12,15 @@ jobs:
if: "! contains(toJSON(github.event.commits.*.message), '[ci skip]')"
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
submodules: recursive
- - name: Set up JDK 17
- uses: actions/setup-java@v3
+ - name: validate gradle wrapper
+ uses: gradle/wrapper-validation-action@v2
+ - name: Set up JDK 21
+ uses: actions/setup-java@v4
with:
- java-version: '17'
+ java-version: '21'
distribution: 'adopt'
cache: gradle
- name: Grant execute permission for gradlew
diff --git a/.github/workflows/junit-21-builds.disabled b/.github/workflows/junit-21-builds.disabled
new file mode 100644
index 00000000000..07bc5bebbeb
--- /dev/null
+++ b/.github/workflows/junit-21-builds.disabled
@@ -0,0 +1,31 @@
+# Disabled as EasyMock 5.2.0 is required for Java 21 support
+# However, we are currently using 5.0.1 (see https://github.com/SkriptLang/Skript/pull/6204#discussion_r1405302009)
+name: JUnit (MC 1.20.6+)
+
+on:
+ push:
+ branches:
+ - master
+ - 'dev/**'
+ pull_request:
+
+jobs:
+ build:
+ if: "! contains(toJSON(github.event.commits.*.message), '[ci skip]')"
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ submodules: recursive
+ - name: validate gradle wrapper
+ uses: gradle/wrapper-validation-action@v2
+ - name: Set up JDK 21
+ uses: actions/setup-java@v4
+ with:
+ java-version: '21'
+ distribution: 'adopt'
+ cache: gradle
+ - name: Grant execute permission for gradlew
+ run: chmod +x gradlew
+ - name: Build Skript and run JUnit
+ run: ./gradlew clean JUnitJava21
diff --git a/.github/workflows/nightly-docs.yml b/.github/workflows/nightly-docs.yml
new file mode 100644
index 00000000000..0d5cc824ad0
--- /dev/null
+++ b/.github/workflows/nightly-docs.yml
@@ -0,0 +1,61 @@
+name: Nightly documentation
+
+on:
+ push:
+ branches:
+ - 'dev/feature'
+ - 'dev/patch'
+ - 'enhancement/**'
+ - 'feature/**'
+ - 'fix/**'
+ tags-ignore:
+ - '**'
+
+jobs:
+ nightly-docs:
+ if: "!contains(toJSON(github.event.commits.*.message), '[ci skip]')"
+ runs-on: ubuntu-latest
+ steps:
+ - name: Configure workflow
+ id: configuration
+ env:
+ DOCS_DEPLOY_KEY: ${{ secrets.DOCS_DEPLOY_KEY }}
+ run: |
+ if [ -n "$DOCS_DEPLOY_KEY" ]
+ then
+ echo "DOCS_DEPLOY_KEY_PRESENT=true" >> $GITHUB_OUTPUT
+ else
+ echo "Secret 'DOCS_DEPLOY_KEY' not present. Exiting job."
+ fi
+ BRANCH_NAME="${GITHUB_REF#refs/*/}"
+ echo "BRANCH_NAME=${BRANCH_NAME}" >> $GITHUB_OUTPUT
+ echo "DOCS_OUTPUT_DIR=${GITHUB_WORKSPACE}/skript-docs/docs/nightly/${BRANCH_NAME}" >> $GITHUB_OUTPUT
+ echo "DOCS_REPO_DIR=${GITHUB_WORKSPACE}/skript-docs" >> $GITHUB_OUTPUT
+ echo "SKRIPT_REPO_DIR=${GITHUB_WORKSPACE}/skript" >> $GITHUB_OUTPUT
+ - name: Checkout Skript
+ uses: actions/checkout@v4
+ with:
+ submodules: recursive
+ path: skript
+ - name: Setup documentation environment
+ if: steps.configuration.outputs.DOCS_DEPLOY_KEY_PRESENT == 'true'
+ uses: ./skript/.github/workflows/docs/setup-docs
+ with:
+ docs_deploy_key: ${{ secrets.DOCS_DEPLOY_KEY }}
+ docs_output_dir: ${{ steps.configuration.outputs.DOCS_OUTPUT_DIR }}
+ - name: Generate documentation
+ id: generate
+ if: steps.configuration.outputs.DOCS_DEPLOY_KEY_PRESENT == 'true'
+ uses: ./skript/.github/workflows/docs/generate-docs
+ with:
+ docs_output_dir: ${{ steps.configuration.outputs.DOCS_OUTPUT_DIR }}
+ docs_repo_dir: ${{ steps.configuration.outputs.DOCS_REPO_DIR }}
+ skript_repo_dir: ${{ steps.configuration.outputs.SKRIPT_REPO_DIR }}
+ - name: Push nightly documentation
+ if: steps.generate.outputs.DOCS_CHANGED == 'true'
+ uses: ./skript/.github/workflows/docs/push-docs
+ with:
+ docs_repo_dir: ${{ steps.configuration.outputs.DOCS_REPO_DIR }}
+ git_name: Nightly Docs Bot
+ git_email: nightlydocs@skriptlang.org
+ git_commit_message: "Update ${{ steps.configuration.outputs.BRANCH_NAME }} branch nightly docs to ${{ github.repository }}@${{ github.sha }}"
diff --git a/.github/workflows/release-docs.yml b/.github/workflows/release-docs.yml
new file mode 100644
index 00000000000..9cfe198ba93
--- /dev/null
+++ b/.github/workflows/release-docs.yml
@@ -0,0 +1,45 @@
+name: Release documentation
+
+on:
+ release:
+ types: [published]
+ workflow_dispatch:
+
+jobs:
+ release-docs:
+ if: "! contains(toJSON(github.event.commits.*.message), '[ci skip]')"
+ runs-on: ubuntu-latest
+ steps:
+ - name: Configure workflow
+ id: configuration
+ run: |
+ echo "BRANCH_NAME=${GITHUB_REF#refs/*/}" >> $GITHUB_OUTPUT
+ echo "DOCS_OUTPUT_DIR=${GITHUB_WORKSPACE}/skript-docs/docs/" >> $GITHUB_OUTPUT
+ echo "DOCS_REPO_DIR=${GITHUB_WORKSPACE}/skript-docs" >> $GITHUB_OUTPUT
+ echo "SKRIPT_REPO_DIR=${GITHUB_WORKSPACE}/skript" >> $GITHUB_OUTPUT
+ - name: Checkout Skript
+ uses: actions/checkout@v4
+ with:
+ submodules: recursive
+ path: skript
+ - name: Setup documentation environment
+ uses: ./skript/.github/workflows/docs/setup-docs
+ with:
+ docs_deploy_key: ${{ secrets.DOCS_DEPLOY_KEY }}
+ docs_output_dir: ${{ steps.configuration.outputs.DOCS_OUTPUT_DIR }}
+ - name: Generate documentation
+ uses: ./skript/.github/workflows/docs/generate-docs
+ with:
+ docs_output_dir: ${{ steps.configuration.outputs.DOCS_OUTPUT_DIR }}
+ docs_repo_dir: ${{ steps.configuration.outputs.DOCS_REPO_DIR }}
+ skript_repo_dir: ${{ steps.configuration.outputs.SKRIPT_REPO_DIR }}
+ is_release: true
+ generate_javadocs: true
+ cleanup_pattern: "!(nightly|archives|templates)"
+ - name: Push release documentation
+ uses: ./skript/.github/workflows/docs/push-docs
+ with:
+ docs_repo_dir: ${{ steps.configuration.outputs.DOCS_REPO_DIR }}
+ git_name: Release Docs Bot
+ git_email: releasedocs@skriptlang.org
+ git_commit_message: "Update release docs to ${{ steps.configuration.outputs.BRANCH_NAME }}"
diff --git a/.github/workflows/repo.yml b/.github/workflows/repo.yml
index d7639b98a94..a04327ed64c 100644
--- a/.github/workflows/repo.yml
+++ b/.github/workflows/repo.yml
@@ -8,13 +8,15 @@ jobs:
publish:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
submodules: recursive
- - name: Set up JDK 17
- uses: actions/setup-java@v3
+ - name: validate gradle wrapper
+ uses: gradle/wrapper-validation-action@v2
+ - name: Set up JDK 21
+ uses: actions/setup-java@v4
with:
- java-version: '17'
+ java-version: '21'
distribution: 'adopt'
cache: gradle
- name: Publish Skript
diff --git a/.gitignore b/.gitignore
index fbddca8fd46..47df9cbc0de 100755
--- a/.gitignore
+++ b/.gitignore
@@ -223,3 +223,6 @@ gradle-app.setting
# TODO remove this in the future after some time since https://github.com/SkriptLang/Skript/pull/4979
# This ensures developers don't upload their old existing test_runners/ folder.
test_runners/
+
+## Mac MetaData
+**/.DS_Store
diff --git a/CLOCKWORK_RELEASE_MODEL.md b/CLOCKWORK_RELEASE_MODEL.md
new file mode 100644
index 00000000000..e5e086f62eb
--- /dev/null
+++ b/CLOCKWORK_RELEASE_MODEL.md
@@ -0,0 +1,294 @@
+# Clockwork Release Model
+
+## Table of Contents
+1. [Introduction](#introduction)
+ - [Preamble](#preamble)
+ - [Motivations](#motivations)
+ - [Goals](#goals)
+ - [Non-Goals](#non-goals)
+2. [Release Types](#release-types)
+ - [Feature Releases](#feature-releases)
+ - [Patch Releases](#patch-releases)
+ - [Pre-Releases](#pre-releases)
+ - [Emergency Patch Releases](#emergency-patch-releases)
+3. [Timetable](#timetable)
+ - [Major Version Schedule](#major-version-schedule)
+ - [Pre-Release Schedule](#pre-release-schedule)
+ - [Patch Schedule](#patch-schedule)
+4. [Content Curation](#content-curation)
+ - [Labels](#labels)
+ - [Branches](#branches)
+5. [Conclusion](#conclusion)
+ - [Paradigm Versions](#addendum-1-paradigm-versions)
+ - [Failure Standards](#addendum-2-failure-standards)
+
+## Introduction
+
+### Preamble
+
+This document defines the structure of future Skript releases, the kinds of material included in releases and the outline of the dates on which releases will be published.
+
+A 'release' is the publication of a verified and signed build artefact on the GitHub releases tab, made available for all users to download and install.
+
+This document does *not* cover the distribution or publication of artifacts built in other ways (e.g. privately, from a nightly action) or those not published from our GitHub (e.g. test builds shared in our public testing group).
+
+Plans for a new release model began in March 2023 and several models were discussed, with this being the final version agreed upon by the organisation's administrative group and approved by the core contributors.
+
+### Motivations
+
+The release cycle for the `2.7.0` version was significant in that it took an unusually long time and included an unusually-large number of additions and changes.
+
+While it was not the first version to have taken a long time to finalise and produce, it was distinct in that a lot of time had passed since the previous public build of Skript having been marked stable.
+
+Members of the organisation and the wider community identified several problems that resulted from this, some of which are (not exhaustively) detailed below:
+- 291 days had passed since the previous release
+ - Users were unable to benefit from bug fixes or new features produced during that time
+ - Although beta versions were released, these were marked unstable and were not fully tested
+- When the release arrived it contained a very large number of changes and additions
+ - Some users were unaware of changes that could not be extensively documented in the changelog or were buried in a large list
+ - Users who obtained a build elsewhere (e.g. direct download, automatic installer) may have been unaware of the scale of the changes
+- Several additions were made at short notice and without sufficient testing
+ - Some of these introduced problems that required fixes in a following `2.7.1` patch
+- Several features could not be completed in time and had to be dropped to a future `2.8.0` version
+ - One result of this was that any corrections or improvements made as part of these were not present in `2.7.0`
+ - Aspects of some of these larger-scale changes had to be re-created or cherry-picked for the `2.7.0` version
+- The release lacked a clear timetable or vision for what additions to include
+ - The initial timetable was not adhered to; plans were made for pre-releases to begin at the end of November 2022, which was delayed to early December in order to accommodate a large feature PR (which was eventually dropped to `2.8.0`)
+ - Delays persisted, and the final release took place 7 months later in September 2023
+ - There was no clear cut-off point for new features; feature pull requests were being included even up to 3 days before release
+
+Of these, the principle complaint is that the `2.7.0` version took a significant amount of time to finish and this had an adverse effect on the community and the wider ecosystem.
+
+### Goals
+
+Our release model has been designed to achieve the following goals:
+1. To reduce the delay between finishing new features and releasing them to the public.
+2. To significantly reduce the time between an issue being fixed and that fix being made public in a stable build.
+3. To reduce the risk of untested changes going into a release.
+4. To make the release timetable clear and accessible.
+5. To prevent a version being indefinitely delayed to accommodate additional changes.
+
+### Non-Goals
+
+This release model is not intended to change any of the following:
+- The content or feature-theme of a particular version.
+- The process for reviewing or approving changes.
+
+## Release Types
+
+This section details the different categories of version for release.
+
+The versioning will follow the form `A.B.C`, where `B` is a [feature version](#Feature-Releases) containing changes and additions, `C` is a [patch version](#Patch-Releases) containing only issue fixes, and `A` is reserved for major paradigmatic changes.
+
+### Feature Releases
+A 'feature' version (labelled `0.X.0`) may contain:
+- Additions to the language (syntax, grammar, structures)
+- Bug fixes
+- Developer API additions and changes
+- Breaking changes1
+
+All content added to a feature version must pass through the typical review process.
+Content must also have been included in a prior [pre-release](#Pre-Releases) for public testing.
+
+> 1 Breaking changes are to be avoided where possible but may be necessary, such as in a case where a significant improvement could be made to an existing feature but only by changing its structure somehow.
+> Such changes should be clearly labelled and well documented, preferably giving users ample notice.
+
+### Patch Releases
+A 'patch' version (labelled `0.0.X`) may contain:
+- Bug fixes
+- Non-impactful2 improvements to existing features
+- Changes to meta content (e.g. documentation)
+
+There may be **very rare** occasions when a breaking change is necessary in a patch release. These may occur if and only if: either a breaking change is required in order to fix an issue, and the issue is significant enough to need fixing in a patch rather than waiting for a major release, or an issue occurred with an inclusion in the version immediately-prior to this, which must be changed or reverted in some way.
+
+All content added to a patch version must pass through the typical review process.
+
+> 2 A non-impactful change is one in which there is no apparent difference to the user in how a feature is employed or what it does but that may have a material difference in areas such as performance, efficiency or machine resource usage.
+
+### Pre-Releases
+
+A 'pre-release' version (labelled `0.X.0-preY`) will contain all of the content expected to be in the feature release immediately following this.
+
+Pre-release versions are a final opportunity for testing and getting public feedback on changes before a major release, allowing time to identify and fix any issues before the proper release, rather than needing an immediate patch.
+
+The content of a pre-release should be identical to the content of the upcoming release -- barring any bug fixes -- and new content should never be included after a pre-release.
+
+### Emergency Patch Releases
+
+An 'emergency patch' version will be released if a critical security vulnerability is reported that the organisation feels prevents an immediate risk to the user base, such that it cannot wait for the subsequent patch.
+
+An emergency patch will be labelled as another patch version (`0.0.X`). It should be noted that an emergency patch will *not* disrupt the typical timetable detailed below.
+
+These kinds of releases may be published immediately and do not have to go through the typical reviewing and testing process. \
+They must never include content, additions or unnecessary changes.
+
+The only content permitted in an emergency patch is the material needed to fix the security risk.
+
+The exact nature of the security vulnerability (such as the means to reproduce it) should not be included in the notes surrounding the release.
+
+## Timetable
+
+The 'clockwork' release model follows a strict monthly cycle, with versions being released on exact dates.
+
+A table of (expected) dates is displayed below.
+
+| Date | Release Type | Example Version
Name |
+|----------|-----------------|-------------------------|
+| 1st Jan | Pre-release | 0.1.0-pre1 |
+| 15th Jan | Feature release | 0.1.0 |
+| 1st Feb | Patch | 0.1.1 |
+| 1st Mar | Patch | 0.1.2 |
+| 1st Apr | Patch | 0.1.3 |
+| 1st May | Patch | 0.1.4 |
+| 1st Jun | Patch | 0.1.5 |
+| 1st Jul | Pre-release | 0.2.0-pre1 |
+| 15th Jul | Feature release | 0.2.0 |
+| 1st Aug | Patch | 0.2.1 |
+| 1st Sep | Patch | 0.2.2 |
+| 1st Oct | Patch | 0.2.3 |
+| 1st Nov | Patch | 0.2.4 |
+| 1st Dec | Patch | 0.2.5 |
+
+An estimated 14 releases are expected per year, with 10 patches, 2 pre-releases and 2 feature-releases that immediately follow them.
+
+Please note that the actual number may differ from this in cases such as:
+- A version requiring multiple pre-releases to correct mistakes (`0.3.0-pre1`, `0.3.0-pre2`)
+- An emergency patch having to be released
+- No bug fixes being prepared in a month, meaning no patch is needed
+
+There is no fixed timetable for the circulation of unpublished builds to the public testing group or the addon developers group.
+
+### Major Version Schedule
+
+A [feature version](#feature-releases) will be released on the **15th of January** and the **15th of July**.
+
+This will include all finished content from the previous 6 months that was tested in the pre-release.
+
+Any features, additions or changes that were *not* ready or approved at the time of the pre-release may **not** be included in the feature release [according to goal 3](#goals). \
+The feature release must **not** be delayed to accomodate content that was not ready by the deadline [according to goal 5](#goals).
+
+If there is no content ready at the scheduled date of a feature release, the release will be skipped and a notice published explaining this.
+
+### Pre-Release Schedule
+
+A [pre-release](#pre-releases) will be released on the **1st of January** and the **1st of July**, leaving two weeks before the following release for public testing to occur.
+
+This pre-release may include all finished content from the previous 6 months.
+
+Any features, additions or changes that have *not* passed the review/approval process by the day of the pre-release may **not** be included in the pre-release [according to goal 3](#goals). \
+The pre-release must **not** be delayed to accomodate content that was not ready by the deadline [according to goal 5](#goals).
+
+If there is no content ready at the scheduled date of a pre-release, the entire feature-release will be skipped and a notice published explaining this.
+
+If issues are found requiring a new build be produced (e.g. the build fails to load, a core feature is non-functional, a fix was made but needs additional testing) then another version of the pre-release may be published.
+There is no limit on the number of pre-releases that can be published if required.
+
+### Patch Schedule
+
+A [patch](#patch-releases) will be released on the **1st** of every month (except January and July) containing any fixes prepared during the previous month(s).
+
+On the 1st of January and July the patch will be replaced by the pre-release.
+
+A patch should include all bug fixes from the previous month that have passed the review/approval process.
+
+Ideally, a patch build should be circulated in the public testing group prior to its release, but this is not a strict requirement.
+
+If there are no applicable bug fixes ready by the scheduled date of the patch then the month will be skipped and the patch will not take place. A public notice is not required to explain this.
+
+## Content Curation
+
+To help curate content on our GitHub repository we have designed a new branch model and accompanying labels for categorising contributions.
+
+### Labels
+
+We shall provide issue and pull request labels to help categorise changes to prevent contributions missing a release (or slipping into the incorrect kind of release).
+
+1. `patch-ready` \
+ to denote a pull request that has:
+ - passed the review/approval process
+ - is of the sufficient kind to be included in a monthly patch version
+2. `feature-ready` \
+ to denote a pull request that has:
+ - passed the review/approval process
+ - should wait for a biannual feature release
+ - is not suitable to be included in a patch
+
+### Branches
+
+We shall maintain three core branches: `dev/patch`, `dev/feature` and `master`, which function vertically3.
+
+We may also create legacy branches where necessary. \
+As an example, if a previous release, say `2.6.4` requires an emergency security update, a branch can be made from its release tag and the patch may directly target that branch (and be released).
+
+We may also maintain other assorted branches for individual features, for the purpose of group work or for experimentation. These are not detailed below.
+
+> 3 Changes are always made to the 'top' (working) branch and then this is merged downwards into the more stable branch below when required.
+>
+> Branches are never merged upwards.
+
+#### Patch
+
+Pull requests that only address issues or are otherwise suitable for a patch release should target the **`dev/patch` branch**. These may be merged whenever appropriate (i.e. all review and testing requirements have passed).
+
+At the time of the patch release, the **patch branch** will be merged downwards into the **master branch**, and a release will be created from the **master branch**.
+
+When a feature release occurs and all branches are merged into the master branch, the patch branch will be rebased off the current master commit, effectively bringing it up to speed with the new changes. \
+As an example, when feature version 0.5.0 releases, the patch branch will be at 0.4.5 and missing the new features, so must be rebased off the current release and catch up before changes for version 0.5.1 may be merged.
+
+#### Feature
+
+Pull requests that add features, make breaking changes or are otherwise unsuitable for a patch version should target the **`dev/feature` branch**. \
+These should be merged whenever appropriate (i.e. all review and testing requirements have passed), so that testing builds can be created and circulated in the public testing group.
+
+The **patch branch** may be merged downwards into the **feature branch** whenever appropriate (e.g. after changes have been made to it that may affect the state of contributions targeting the feature branch).
+
+The feature branch should __**never**__ be merged upwards into the patch branch4.
+
+The feature branch is only merged downwards into the master branch directly before a full feature release (i.e. after the pre-release and testing is complete.)
+
+Pre-releases are made directly from the feature branch5. At the end of the pre-release testing period the feature branch can be merged downwards into the master branch in order for the full release to be made.
+
+> 4 Merges only ever occur downwards. For the patch branch to see changes from the feature branch it must be rebased onto master branch after a feature release occurs.
+>
+> 5 Merging the branch down for the pre-release would introduce potentially-buggy, untested changes to the master branch.
+
+#### Master
+
+The **`master` branch** should reflect the most recent feature release.
+Pull requests should **never** directly target the master branch. Changes are made to one of the other branches (as applicable) and then that branch is merged downwards into the **master branch** only when it is time for a release.
+
+This means that any user building from the master branch is guaranteed to receive a safe, stable build of the quality that we would release.
+
+The master branch should never be merged upwards into the feature or patch branches. If these branches need to see changes from the master branch they must be rebased onto the latest master branch commit.
+
+## Conclusion
+
+It is our aim that this release model will address all of our goals and satisfy our motivations.
+
+Setting a strict and regular schedule ought to prevent too much time passing without a release, while also helping to prevent a single release from becoming bloated and overbearing.
+
+By including testing requirements and mandating public pre-releases we hope to solve the persistent issue of untested changes slipping into supposedly-stable versions.
+
+Finally, by scheduling regular patches we aim to reduce the time between a bug being 'fixed' by a contributor and the userbase being able to benefit from that fix. Keeping these patches as small, controlled releases allows us to mark them as 'stable' therefore letting the version reach a wider audience.
+
+### Addendum 1: Paradigm Versions
+
+Paradigmatic `X.0.0` versions were deliberately excluded from this proposal. \
+The reasoning behind this choice was that over 10 years have passed since the inception of major version`2.0.0` in 2012, the previous paradigmatic change.
+
+As of writing this document there are proposals and roadmaps for a version `3.0.0` but no timetable or predicted date on the horizon.
+
+This kind of version, were it to be released, would likely take the place of a typical feature release in the model calendar, i.e. occurring on the 15th of January or July. However, due to its potentially-significant nature it may require exceptional changes to the pre-release cycle.
+
+As details of such a version are neither known nor easy to predict, it has been left to the discretion of the future team to be decided when required.
+
+### Addendum 2: Failure Standards
+
+No proposal is complete without failure standards; this model can be deemed to have failed if, in two years' time:
+1. The delay between finishing new features and releasing them to the public has not been reduced.
+2. The delay between an issue being fixed and that fix being made public in a stable build has not been reduced.
+3. Untested features are being released in 'stable' builds.
+4. The release timetable is unclear or inaccessible.
+5. Versions are being indefinitely delayed to accommodate additional changes.
+
+Additionally, if this model is considered to have put an undue burden on the core development team, to the extent that it has hampered progress in a significant and measurable way, then it can be considered to have failed.
diff --git a/README.md b/README.md
index e23e1a288d2..b4ab6c4e48f 100644
--- a/README.md
+++ b/README.md
@@ -16,16 +16,18 @@ Skript requires **Spigot** to work. You heard it right, **CraftBukkit** does *no
**Paper**, which is a fork of Spigot, is recommended; it is required for some
parts of Skript to be available.
-Skript supports only the **latest** patch versions of Minecraft 1.9+.
+Skript supports only the **latest** patch versions of Minecraft 1.13+.
For example, this means that 1.16.5 is supported, but 1.16.4 is *not*.
Testing with all old patch versions is not feasible for us.
-Minecraft 1.8 and earlier are not, and will not be supported. New Minecraft
+Minecraft 1.12 and earlier are not, and will not be supported. New Minecraft
versions will be supported as soon as possible.
## Download
You can find the downloads for each version with their release notes in the [releases page](https://github.com/SkriptLang/Skript/releases).
+Two major feature updates are expected each year in January and July, with monthly patches occurring in between. For full details, please review our [release model](CLOCKWORK_RELEASE_MODEL.md).
+
## Documentation
Documentation is available [here](https://docs.skriptlang.org/) for the
latest version of Skript.
@@ -75,13 +77,15 @@ Skript has some tests written in Skript. Running them requires a Minecraft
server, but our build script will create one for you. Running the tests is easy:
```
-./gradlew (quickTest|skriptTest|skriptTestJava8|skriptTestJava17)
+./gradlew (quickTest|skriptTest|skriptTestJava11|skriptTestJava17|skriptTestJava21)
```
quickTest
runs the test suite on newest supported server version.
-skriptTestJava17
(1.17+) runs the tests on the latest supported Java version.
-skriptTestJava8
(1.13-1.16) runs the tests on the oldest supported Java version.
-skriptTest
runs both skriptTestJava8 and skriptTestJava17
+skriptTestJava21
(1.20.6+) runs the tests on Java 21 supported versions.
+skriptTestJava17
(1.17-1.20.4) runs the tests on Java 17 supported versions.
+skriptTestJava11
(1.13-1.16) runs the tests on Java 11 supported versions.
+skriptTest
runs the tests on all versions.
+That is, it runs skriptTestJava11, skriptTestJava17, and skriptTestJava21.
By running the tests, you agree to Mojang's End User License Agreement.
@@ -160,7 +164,7 @@ dependencies {
}
```
-An example of the version tag would be ```dev37c```.
+An example of the version tag would be ```2.8.5```.
> Note: If Gradle isn't able to resolve Skript's dependencies, just [disable the resolution of transitive dependencies](https://docs.gradle.org/current/userguide/resolution_rules.html#sec:disabling_resolution_transitive_dependencies) for Skript in your project.
diff --git a/build.gradle b/build.gradle
index 4ed4e1603be..486220cf22e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -5,7 +5,6 @@ import java.time.LocalTime
plugins {
id 'com.github.johnrengelman.shadow' version '8.1.1'
- id 'com.github.hierynomus.license' version '0.16.1'
id 'maven-publish'
id 'java'
}
@@ -20,6 +19,7 @@ allprojects {
maven { url 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' }
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
maven { url 'https://repo.papermc.io/repository/maven-public/' }
+ maven { url = 'https://s01.oss.sonatype.org/content/repositories/snapshots/' } // needed for paper adventure snapshot
maven { url 'https://ci.emc.gs/nexus/content/groups/aikar/' }
}
}
@@ -27,20 +27,20 @@ allprojects {
dependencies {
shadow group: 'io.papermc', name: 'paperlib', version: '1.0.8'
shadow group: 'org.bstats', name: 'bstats-bukkit', version: '3.0.2'
- shadow group: 'net.kyori', name: 'adventure-text-serializer-bungeecord', version: '4.3.0'
+ shadow group: 'net.kyori', name: 'adventure-text-serializer-bungeecord', version: '4.3.2'
- implementation group: 'io.papermc.paper', name: 'paper-api', version: '1.19.4-R0.1-SNAPSHOT'
+ implementation group: 'io.papermc.paper', name: 'paper-api', version: '1.21-R0.1-SNAPSHOT'
implementation group: 'org.eclipse.jdt', name: 'org.eclipse.jdt.annotation', version: '2.2.700'
implementation group: 'com.google.code.findbugs', name: 'findbugs', version: '3.0.1'
implementation group: 'com.sk89q.worldguard', name: 'worldguard-legacy', version: '7.0.0-SNAPSHOT'
- implementation group: 'net.milkbowl.vault', name: 'Vault', version: '1.7.1', {
+ implementation group: 'net.milkbowl.vault', name: 'Vault', version: '1.7.3', {
exclude group: 'org.bstats', module: 'bstats-bukkit'
}
implementation fileTree(dir: 'lib', include: '*.jar')
testShadow group: 'junit', name: 'junit', version: '4.13.2'
- testShadow group: 'org.easymock', name: 'easymock', version: '5.1.0'
+ testShadow group: 'org.easymock', name: 'easymock', version: '5.0.1'
}
task checkAliases {
@@ -54,23 +54,23 @@ task checkAliases {
}
task testJar(type: ShadowJar) {
- dependsOn(compileTestJava, licenseTest)
+ dependsOn(compileTestJava)
archiveFileName = 'Skript-JUnit.jar'
from sourceSets.test.output, sourceSets.main.output, project.configurations.testShadow
}
task jar(overwrite: true, type: ShadowJar) {
dependsOn checkAliases
- archiveFileName = jarName ? 'Skript.jar' : jarName
+ archiveFileName = jarName ? 'Skript-' + project.version + '.jar' : jarName
from sourceSets.main.output
}
task build(overwrite: true, type: ShadowJar) {
- archiveFileName = jarName ? 'Skript.jar' : jarName
+ archiveFileName = jarName ? 'Skript-' + project.version + '.jar' : jarName
from sourceSets.main.output
}
-// Excludes the tests for the build task. Should be using junit, junitJava17, junitJava8, skriptTest, quickTest.
+// Excludes the tests for the build task. Should be using junit, junitJava17, junitJava11, skriptTest, quickTest.
// We do not want tests to run for building. That's time consuming and annoying. Especially in development.
test {
exclude '**/*'
@@ -140,23 +140,6 @@ publishing {
}
}
-license {
- header file('licenseheader.txt')
- exclude('**/Metrics.java') // Not under GPLv3
- exclude('**/BurgerHelper.java') // Not exclusively GPLv3
- exclude('**/*.sk') // Sample scripts and maybe aliases
- exclude('**/*.lang') // Language files do not have headers (still under GPLv3)
- exclude('**/*.json') // JSON files do not have headers
-}
-
-javadoc {
- source = sourceSets.main.allJava
- classpath = configurations.compileClasspath
- options.encoding = 'UTF-8'
- // currently our javadoc has a lot of errors, so we need to suppress the linter
- options.addStringOption('Xdoclint:none', '-quiet')
-}
-
// Task to check that test scripts are named correctly
tasks.register('testNaming') {
doLast {
@@ -181,17 +164,31 @@ tasks.register('testNaming') {
}
enum Modifiers {
- DEV_MODE, GEN_DOCS, DEBUG, PROFILE, JUNIT
+ DEV_MODE, GEN_NIGHTLY_DOCS, GEN_RELEASE_DOCS, DEBUG, PROFILE, JUNIT
}
// Create a test task with given name, environments dir/file, dev mode and java version.
-void createTestTask(String name, String desc, String environments, int javaVersion, Modifiers... modifiers) {
+// -1 on the timeout means it'll be disabled.
+void createTestTask(String name, String desc, String environments, int javaVersion, long timeout, Modifiers... modifiers) {
+ if (timeout == 0)
+ timeout = 300000 // 5 minutes
boolean junit = modifiers.contains(Modifiers.JUNIT)
+ boolean releaseDocs = modifiers.contains(Modifiers.GEN_RELEASE_DOCS)
+ boolean docs = modifiers.contains(Modifiers.GEN_NIGHTLY_DOCS) || releaseDocs
+ def artifact = 'build' + File.separator + 'libs' + File.separator
+ if (junit) {
+ artifact += 'Skript-JUnit.jar'
+ } else if (releaseDocs) {
+ artifact += 'Skript-' + version + '.jar'
+ } else {
+ artifact += 'Skript-nightly.jar'
+ }
tasks.register(name, JavaExec) {
- description = desc;
- dependsOn licenseTest
+ description = desc
if (junit) {
dependsOn testJar
+ } else if (releaseDocs) {
+ dependsOn githubRelease, testNaming
} else {
dependsOn nightlyRelease, testNaming
}
@@ -203,21 +200,22 @@ void createTestTask(String name, String desc, String environments, int javaVersi
}
group = 'execution'
classpath = files([
- 'build' + File.separator + 'libs' + File.separator + (junit ? 'Skript-JUnit.jar' : 'Skript-nightly.jar'),
+ artifact,
project.configurations.runtimeClasspath.find { it.name.startsWith('gson') },
sourceSets.main.runtimeClasspath
])
main = 'ch.njol.skript.test.platform.PlatformMain'
args = [
'build/test_runners',
- junit ? 'src/test/skript/tests/junit' : 'src/test/skript/tests',
+ junit ? 'src/test/skript/junit' : 'src/test/skript/tests',
'src/test/resources/runner_data',
environments,
modifiers.contains(Modifiers.DEV_MODE),
- modifiers.contains(Modifiers.GEN_DOCS),
+ docs,
junit,
modifiers.contains(Modifiers.DEBUG),
- project.findProperty('verbosity') ?: "null"
+ project.findProperty('verbosity') ?: "null",
+ timeout
]
// Do first is used when throwing exceptions.
@@ -226,16 +224,23 @@ void createTestTask(String name, String desc, String environments, int javaVersi
if (!gradle.taskGraph.hasTask(":tasks") && !gradle.startParameter.dryRun && modifiers.contains(Modifiers.PROFILE)) {
if (!project.hasProperty('profiler'))
throw new MissingPropertyException('Add parameter -Pprofiler=', 'profiler', String.class)
-
+
args += '-agentpath:' + project.property('profiler') + '=port=8849,nowait'
}
}
}
}
-def latestEnv = 'java17/paper-1.19.4.json'
-def latestJava = 17
-def oldestJava = 8
+def java21 = 21
+def java17 = 17
+def java11 = 11
+
+def latestEnv = 'java21/paper-1.21.0.json'
+def latestJava = java21
+def oldestJava = java11
+
+def latestJUnitEnv = 'java17/paper-1.20.4.json'
+def latestJUnitJava = java17
java {
toolchain.languageVersion.set(JavaLanguageVersion.of(latestJava))
@@ -252,23 +257,28 @@ compileTestJava.options.encoding = 'UTF-8'
String environments = 'src/test/skript/environments/';
String env = project.property('testEnv') == null ? latestEnv : project.property('testEnv') + '.json'
int envJava = project.property('testEnvJavaVersion') == null ? latestJava : Integer.parseInt(project.property('testEnvJavaVersion') as String)
-createTestTask('quickTest', 'Runs tests on one environment being the latest supported Java and Minecraft.', environments + latestEnv, latestJava)
-createTestTask('skriptTestJava17', 'Runs tests on all Java 17 environments.', environments + 'java17', latestJava)
-createTestTask('skriptTestJava8', 'Runs tests on all Java 8 environments.', environments + 'java8', oldestJava)
-createTestTask('skriptTestDev', 'Runs testing server and uses \'system.in\' for command input, stop server to finish.', environments + env, envJava, Modifiers.DEV_MODE, Modifiers.DEBUG)
-createTestTask('skriptProfile', 'Starts the testing server with JProfiler support.', environments + latestEnv, latestJava, Modifiers.PROFILE)
-createTestTask('genDocs', 'Generates the Skript documentation website html files.', environments + env, envJava, Modifiers.GEN_DOCS)
+createTestTask('quickTest', 'Runs tests on one environment being the latest supported Java and Minecraft.', environments + latestEnv, latestJava, 0)
+createTestTask('skriptTestJava21', 'Runs tests on all Java 21 environments.', environments + 'java21', java21, 0)
+createTestTask('skriptTestJava17', 'Runs tests on all Java 17 environments.', environments + 'java17', java17, 0)
+createTestTask('skriptTestJava11', 'Runs tests on all Java 11 environments.', environments + 'java11', java11, 0)
+createTestTask('skriptTestDev', 'Runs testing server and uses \'system.in\' for command input, stop server to finish.', environments + env, envJava, 0, Modifiers.DEV_MODE, Modifiers.DEBUG)
+createTestTask('skriptProfile', 'Starts the testing server with JProfiler support.', environments + latestEnv, latestJava, -1, Modifiers.PROFILE)
+createTestTask('genNightlyDocs', 'Generates the Skript documentation website html files.', environments + env, envJava, 0, Modifiers.GEN_NIGHTLY_DOCS)
+createTestTask('genReleaseDocs', 'Generates the Skript documentation website html files for a release.', environments + env, envJava, 0, Modifiers.GEN_RELEASE_DOCS)
tasks.register('skriptTest') {
description = 'Runs tests on all environments.'
- dependsOn skriptTestJava8, skriptTestJava17
+ dependsOn skriptTestJava11, skriptTestJava17, skriptTestJava21
}
-createTestTask('JUnitQuick', 'Runs JUnit tests on one environment being the latest supported Java and Minecraft.', environments + latestEnv, latestJava, Modifiers.JUNIT)
-createTestTask('JUnitJava17', 'Runs JUnit tests on all Java 17 environments.', environments + 'java17', latestJava, Modifiers.JUNIT)
-createTestTask('JUnitJava8', 'Runs JUnit tests on all Java 8 environments.', environments + 'java8', oldestJava, Modifiers.JUNIT)
+createTestTask('JUnitQuick', 'Runs JUnit tests on one environment being the latest supported Java and Minecraft.', environments + latestJUnitEnv, latestJUnitJava, 0, Modifiers.JUNIT)
+// Disabled as EasyMock 5.2.0 is required for Java 21 support
+// However, we are currently using 5.0.1 (see https://github.com/SkriptLang/Skript/pull/6204#discussion_r1405302009)
+//createTestTask('JUnitJava21', 'Runs JUnit tests on all Java 21 environments.', environments + 'java21', java21, 0, Modifiers.JUNIT)
+createTestTask('JUnitJava17', 'Runs JUnit tests on all Java 17 environments.', environments + 'java17', java17, 0, Modifiers.JUNIT)
+createTestTask('JUnitJava11', 'Runs JUnit tests on all Java 11 environments.', environments + 'java11', java11, 0, Modifiers.JUNIT)
tasks.register('JUnit') {
description = 'Runs JUnit tests on all environments.'
- dependsOn JUnitJava8, JUnitJava17
+ dependsOn JUnitJava11, JUnitJava17//, JUnitJava21
}
// Build flavor configurations
@@ -277,10 +287,8 @@ task githubResources(type: ProcessResources) {
include '**'
version = project.property('version')
def channel = 'stable'
- if (version.contains('alpha'))
- channel = 'alpha'
- else if (version.contains('beta'))
- channel = 'beta'
+ if (version.contains('-'))
+ channel = 'prerelease'
filter ReplaceTokens, tokens: [
'version' : version,
'today' : '' + LocalTime.now(),
@@ -297,7 +305,7 @@ task githubResources(type: ProcessResources) {
task githubRelease(type: ShadowJar) {
from sourceSets.main.output
dependsOn githubResources
- archiveFileName = 'Skript-github.jar'
+ archiveFileName = 'Skript-' + version +'.jar'
manifest {
attributes(
'Name': 'ch/njol/skript',
@@ -312,10 +320,8 @@ task spigotResources(type: ProcessResources) {
include '**'
version = project.property('version')
def channel = 'stable'
- if (version.contains('alpha'))
- channel = 'alpha'
- else if (version.contains('beta'))
- channel = 'beta'
+ if (version.contains('-'))
+ channel = 'prerelease'
filter ReplaceTokens, tokens: [
'version' : version,
'today' : '' + LocalTime.now(),
@@ -351,8 +357,8 @@ task nightlyResources(type: ProcessResources) {
'version' : version,
'today' : '' + LocalTime.now(),
'release-flavor' : 'skriptlang-nightly', // SkriptLang build, automatically done by CI
- 'release-channel' : 'alpha', // No update checking, but these are VERY unstable
- 'release-updater' : 'ch.njol.skript.update.NoUpdateChecker', // No autoupdates for now
+ 'release-channel' : 'prerelease', // No update checking, but these are VERY unstable
+ 'release-updater' : 'ch.njol.skript.update.NoUpdateChecker', // No auto updates for now
'release-source' : '',
'release-download': 'null'
]
@@ -362,7 +368,7 @@ task nightlyResources(type: ProcessResources) {
task nightlyRelease(type: ShadowJar) {
from sourceSets.main.output
- dependsOn nightlyResources, licenseMain
+ dependsOn nightlyResources
archiveFileName = 'Skript-nightly.jar'
manifest {
attributes(
@@ -372,3 +378,25 @@ task nightlyRelease(type: ShadowJar) {
)
}
}
+
+javadoc {
+ mustRunAfter(tasks.withType(ProcessResources))
+ title = 'Skript ' + project.property('version')
+ source = sourceSets.main.allJava
+
+ exclude("ch/njol/skript/conditions/**")
+ exclude("ch/njol/skript/expressions/**")
+ exclude("ch/njol/skript/effects/**")
+ exclude("ch/njol/skript/events/**")
+ exclude("ch/njol/skript/sections/**")
+ exclude("ch/njol/skript/structures/**")
+ exclude("ch/njol/skript/lang/function/EffFunctionCall.java")
+ exclude("ch/njol/skript/lang/function/ExprFunctionCall.java")
+ exclude("ch/njol/skript/hooks/**")
+ exclude("ch/njol/skript/test/**")
+
+ classpath = configurations.compileClasspath + sourceSets.main.output
+ options.encoding = 'UTF-8'
+ // currently our javadoc has a lot of errors, so we need to suppress the linter
+ options.addStringOption('Xdoclint:none', '-quiet')
+}
diff --git a/code-conventions.md b/code-conventions.md
index 37ac182cd62..3bcf17c6c9f 100644
--- a/code-conventions.md
+++ b/code-conventions.md
@@ -66,6 +66,9 @@ With the exception of contacting our own resources (e.g. to check for updates) c
Code contributed must be licensed under GPLv3, by **you**.
We expect that any code you contribute is either owned by you or you have explicit permission to provide and license it to us.
+Licenses do not need to be printed in individual files (or packages) unless the licence applying to the code in
+that file (or package) deviates from the licence scope of its containing package.
+
Third party code (under a compatible licence) _may_ be accepted in the following cases:
- It is part of a public, freely-available library or resource.
- It is somehow necessary to your contribution, and you have been given permission to include it.
@@ -75,34 +78,61 @@ If we receive complaints regarding the licensing of a contribution we will forwa
If you have questions or complaints regarding the licensing or reproduction of a contribution you may contact us (the organisation) or the contributor of that code directly.
-If, in the future, we need to relicense contributed code, we will contact all contributors involved.
+If, in the future, we need to re-license contributed code, we will contact all contributors involved.
If we need to remove or alter contributed code due to a licensing issue we will attempt to notify its contributor.
## Code Style
### Formatting
+* Imports should be grouped together by type (e.g. all `java.lang...` imports together)
+ * Following the style of existing imports in a class is encouraged, but not required
+ * Wildcard `*` imports are permitted (as long as they do not interfere with existing imports), e.g. `java.lang.*`.
* Tabs, no spaces (unless in code imported from other projects)
-** No tabs/spaces in empty lines
+ - No tabs/spaces in empty lines
* No trailing whitespace
* At most 120 characters per line
- - In Javadoc/multiline comments, at most 80 characters per line
-* When statements consume multiple lines, all lines but first have two tabs of additional indentation
+ - In Javadoc/multiline comments, at most 80 characters per line
+* When statements consume multiple lines, all lines but the first have two tabs of additional indentation
+ - The exception to this is breaking up conditional statements (e.g. `if (x || y)`) where the
+ condition starts may be aligned
* Each class begins with an empty line
* No squeezing of multiple lines of code on a single line
* Separate method declarations with empty lines
- - Empty line after last method in a class is *not* required
- - Otherwise, empty line before and after method is a good rule of thumb
+ - Empty line after last method in a class is *not* required
+ - Otherwise, empty line before and after method is a good rule of thumb
* If fields have Javadoc, separate them with empty lines
* Use empty lines liberally inside methods to improve readability
* Use curly brackets to start and end most blocks
- - Only when a conditional block (if or else) contains a single statement, they may be omitted
- - When omitting brackets, still indent as if the code had brackets
- - Avoid omitting brackets if it produces hard-to-read code
+ - When a block contains a single statement, they may be omitted
+ - Brackets may not be omitted in a chain of other blocks that require brackets, e.g `if ... else {}`
+ - When omitting brackets, still indent as if the code had brackets
+ - Avoid omitting brackets if it produces hard-to-read or ambiguous code
+* Ternaries should be avoided where it makes the code complex or difficult to read
* Annotations for methods and classes are placed in lines before their declarations, one per line
-* When there are multiple annotations, place them in order:
- - @Override -> @Nullable -> @SuppressWarnings
- - For other annotations, doesn't matter; let your IDE decide
+ - Annotations for a structure go on the line before that structure
+ ```java
+ @Override
+ @SuppressWarnings("xyz")
+ public void myMethod() {
+ // Override goes above method because method is overriding
+ }
+ ```
+
+ - Annotations for the _value_ of a thing go before that value's type declaration
+ ```java
+ @Override
+ public @Nullable Object myMethod() {
+ // Nullable goes before Object because Object is Nullable
+ }
+ ```
+* When there are multiple annotations, it looks nicer to place them in length order (longest last)
+but this is not strictly required:
+ ```java
+ @Override
+ @Deprecated
+ @SuppressWarnings("xyz")
+ ```
* When splitting Strings into multiple lines the last part of the string must be (space character included) " " +
```java
String string = "example string " +
@@ -111,6 +141,7 @@ If we need to remove or alter contributed code due to a licensing issue we will
* When extending one of following classes: SimpleExpression, SimplePropertyExpression, Effect, Condition...
- Put overridden methods in order
+ - Put static registration before all methods
- SimpleExpression: init -> get/getAll -> acceptChange -> change -> setTime -> getTime -> isSingle -> getReturnType -> toString
- SimplePropertyExpression: -> init -> convert -> acceptChange -> change -> setTime -> getTime -> getReturnType -> getPropertyName
- Effect: init -> execute -> toString
@@ -127,9 +158,11 @@ If we need to remove or alter contributed code due to a licensing issue we will
- Static constant fields should be named in `UPPER_SNAKE_CASE`
* Localised messages should be named in `lower_snake_case`
- And that is the only place where snake_case is acceptable
-* Use prefixes only where their use has been already estabilished (such as `ExprSomeRandomThing`)
+* Use prefixes only where their use has been already established (such as `ExprSomeRandomThing`)
- Otherwise, use postfixes where necessary
- Common occurrences include: Struct (Structure), Sec (Section), EffSec (EffectSection), Eff (Effect), Cond (Condition), Expr (Expression)
+* Ensure variable/field names are descriptive. Avoid using shorthand names like `e`, or `c`
+ - e.g. Event should be `event`, not `e`. `e` is ambiguous and could mean a number of things
### Comments
* Prefer to comment *why* you're doing things instead of how you're doing them
@@ -161,33 +194,79 @@ Your comments should look something like these:
## Language Features
### Compatibility
-* Contributions should maintain Java 8 source/binary compatibility, even though compiling Skript requires Java 17
- - Users must not need JRE newer than version 8
-* Versions up to and including Java 17 should work too
+[//]: # (To be updated for 2.10 for Java 17)
+* Contributions should maintain Java 11 source/binary compatibility, even though compiling Skript requires Java 21
+ - Users must not need JRE newer than version 11
+* Versions up to and including Java 21 should work too
- Please avoid using unsafe reflection
* It is recommended to make fields final, if they are effectively final
-* Local variables and method parameters should not be declared final
+* Local variables and method parameters should not be declared final unless used in anonymous classes, lambdas
+or try-with-resources sections where their immutability is necessary
* Methods should be declared final only where necessary
* Use `@Override` whenever applicable
-
-### Nullness
+ - They may be omitted to prevent compilation errors when something overrides only
+ on a version-dependent basis (e.g. in Library XYZ version 2 we override `getX()` but in version 3 it's
+ gone, and we call it ourselves)
+
+### null-ness
+* We use **JetBrains** Annotations for specifying null-ness and method contracts.
+ * If editing a file using a different annotation set (e.g. Javax, Eclipse Sisu, Bukkit)
+ these should be replaced with their JetBrains equivalent.
+ * The semantics for JetBrains Annotations are strict _and should be observed!_
+ * Many IDEs have built-in compiler-level support for these, and can even be set to produce strict
+ errors when an annotation is misused; do not misuse them.
+ * **`@NotNull`**
+ * > An element annotated with NotNull claims null value is forbidden to return (for methods),
+ pass to (parameters) and hold (local variables and fields).
+ * Something is `@NotNull` iff it is never null from its inception (new X) to its garbage collection,
+ i.e. there is no point in time at which the value could ever be null.
+ * **`@Nullable`**
+ * > An element annotated with Nullable claims null value is perfectly valid to return (for methods),
+ > pass to (parameters) or hold in (local variables and fields).
+ >
+ > By convention, this annotation applied only when the value should always be checked
+ > against null because the developer could do nothing to prevent null from happening.
+ * Something is `@Nullable` iff there is _absolutely no way of determining_ (other than checking its
+ value `!= null`) whether it is null.
+ * In other words, if there is another way of knowing (e.g. you set it yourself, an `isPresent` method, etc.)
+ then it should not be marked nullable.
+ * **`@Contract`**
+ * The contract annotation should be used to express other behaviour (e.g. null depending on parameters).
* All fields, method parameters and their return values are non-null by default
- - Exceptions: Github API JSON mappings, Metrics
-* When something is nullable, mark it as so
-* Only ignore nullness errors when a variable is effectively non-null - if in doubt: check
- - Most common example is syntax elements, which are not initialised using a constructor
+ - Exceptions: GitHub API JSON mappings, Metrics
+* When ignoring warnings, use the no-inspection comment rather than a blanket suppression annotation
* Use assertions liberally: if you're sure something is not null, assert so to the compiler
- Makes finding bugs easier for developers
-* Assertions must **not** have side-effects - they may be skipped in real environments
+* Assertions must **not** have side-effects in non-test packages - they may be skipped in real environments
* Avoid checking non-null values for nullability
- Unless working around buggy addons, it is rarely necessary
- - This is why ignoring nullness errors is particularly dangerous
+ - This is why ignoring null-ness errors is particularly dangerous
+* Annotations on array types **must** be placed properly:
+ * Annotations on the array itself go before the array brackets
+ ```java
+ @Nullable Object @NotNull []
+ // a not-null array of nullable objects
+ ```
+ * Annotations on values inside the array go before the value declaration
+ ```java
+ @NotNull Object @Nullable []
+ // a nullable array of not-null objects
+ ```
+ * If this is not adhered to, an IDE may provide incorrect feedback.
### Assertions
Skript must run with assertations enabled; use them in your development environment. \
The JVM flag -ea
is used to enable them.
+## Code Complexity
+
+Dense, highly-complex code should be avoided to preserve readability and to help with future maintenance,
+especially within a single method body.
+
+There are many available metrics for measuring code complexity (for different purposes); [we have our own](https://stable.skriptlang.org/Radical_Complexity.pdf).
+There are no strict limits for code complexity, but you may be encouraged (or required) to reformat or break up methods
+into smaller, more manageable chunks. If in doubt, keep things simple.
## Minecraft Features
diff --git a/gradle.properties b/gradle.properties
index 220737a816b..469d1e072ce 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,6 +1,11 @@
+# Done to increase the memory available to gradle.
+# Ensure encoding is consistent across systems.
+org.gradle.jvmargs=-Xmx1G -Dfile.encoding=UTF-8
+org.gradle.parallel=true
+
groupid=ch.njol
name=skript
-version=2.7.0-beta2
+version=2.8.7
jarName=Skript.jar
-testEnv=java17/paper-1.19.4
-testEnvJavaVersion=17
+testEnv=java21/paper-1.21.0
+testEnvJavaVersion=21
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index ccebba7710d..7f93135c49b 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index fc10b601f7c..b82aa23a4f0 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
networkTimeout=10000
+validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index 79a61d421cc..0adc8e1a532 100755
--- a/gradlew
+++ b/gradlew
@@ -83,10 +83,8 @@ done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
-APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -133,10 +131,13 @@ location of your Java installation."
fi
else
JAVACMD=java
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
+ fi
fi
# Increase the maximum file descriptors if we can.
@@ -197,6 +198,10 @@ if "$cygwin" || "$msys" ; then
done
fi
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
diff --git a/licenseheader.txt b/licenseheader.txt
deleted file mode 100644
index 15be760be16..00000000000
--- a/licenseheader.txt
+++ /dev/null
@@ -1,16 +0,0 @@
- This file is part of Skript.
-
- Skript is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Skript is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Skript. If not, see .
-
-Copyright Peter Güttinger, SkriptLang team and contributors
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index 0a8d7b2d301..78b185aca4c 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,6 +1,6 @@
plugins {
- id 'org.gradle.toolchains.foojay-resolver-convention' version '0.5.0'
+ id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0'
}
rootProject.name = 'Skript'
diff --git a/skript-aliases b/skript-aliases
index fb9c3044e55..9ea857f6b7d 160000
--- a/skript-aliases
+++ b/skript-aliases
@@ -1 +1 @@
-Subproject commit fb9c3044e555667b4dc5558467608bd55fa32df0
+Subproject commit 9ea857f6b7dd1e4fc4a35a88149b9e463b537b06
diff --git a/src/main/java/ch/njol/skript/ScriptLoader.java b/src/main/java/ch/njol/skript/ScriptLoader.java
index 14cd0b3e628..afafa0b2def 100644
--- a/src/main/java/ch/njol/skript/ScriptLoader.java
+++ b/src/main/java/ch/njol/skript/ScriptLoader.java
@@ -60,8 +60,10 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.BlockingQueue;
@@ -490,7 +492,7 @@ private static CompletableFuture loadScripts(List configs, O
ScriptInfo scriptInfo = new ScriptInfo();
- List>> scripts = new ArrayList<>();
+ List scripts = new ArrayList<>();
List> scriptInfoFutures = new ArrayList<>();
for (Config config : configs) {
@@ -498,9 +500,9 @@ private static CompletableFuture loadScripts(List configs, O
throw new NullPointerException();
CompletableFuture future = makeFuture(() -> {
- NonNullPair