Repository navigation
Update actions/cache action to v6 #13
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build and publish CleanerX | |
| on: | |
| push: | |
| branches: | |
| - main | |
| - 'experimental/**' | |
| - 'experimental-*' | |
| pull_request: | |
| branches: | |
| - main | |
| - 'experimental/**' | |
| - 'experimental-*' | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| env: | |
| MINI_PORTAL_URL: https://syntaxdevteam.pl | |
| jobs: | |
| detect: | |
| name: Detect changed products | |
| runs-on: ubuntu-latest | |
| outputs: | |
| matrix: ${{ steps.products.outputs.matrix }} | |
| has_changes: ${{ steps.products.outputs.has_changes }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Build product matrix | |
| id: products | |
| env: | |
| GITHUB_BEFORE: ${{ github.event.before }} | |
| GITHUB_AFTER: ${{ github.sha }} | |
| EVENT_NAME: ${{ github.event_name }} | |
| PR_BASE_SHA: ${{ github.event.pull_request.base.sha }} | |
| run: | | |
| python3 - <<'PY' >> "${GITHUB_OUTPUT}" | |
| import json | |
| import os | |
| import subprocess | |
| after = os.environ["GITHUB_AFTER"] | |
| before = os.environ.get("GITHUB_BEFORE", "") | |
| if os.environ.get("EVENT_NAME") == "pull_request": | |
| before = os.environ.get("PR_BASE_SHA", before) | |
| if os.environ.get("EVENT_NAME") == "workflow_dispatch" or not before or before == "0" * 40: | |
| changed = ["__all__"] | |
| else: | |
| raw = subprocess.check_output(["git", "diff", "--name-only", f"{before}..{after}"], text=True) | |
| changed = [line.strip() for line in raw.splitlines() if line.strip()] | |
| products = [ | |
| { | |
| "project": "cleanerx", | |
| "platform": "paper", | |
| "platform_family": "server", | |
| "gradle_project": ":CleanerX-Paper", | |
| "gradle_task": ":CleanerX-Paper:build", | |
| "jar_dir": "CleanerX-Paper/build/libs", | |
| "artifact_prefix": "CleanerX-Paper-", | |
| "version_source": "CleanerX-Paper/src/main/kotlin/pl/syntaxdevteam/cleanerx/loader/VersionChecker.kt", | |
| "paths": ["CleanerX-Paper/"], | |
| }, | |
| { | |
| "project": "cleanerx", | |
| "platform": "spigot", | |
| "platform_family": "server", | |
| "gradle_project": ":CleanerX-Spigot", | |
| "gradle_task": ":CleanerX-Spigot:build", | |
| "jar_dir": "CleanerX-Spigot/build/libs", | |
| "artifact_prefix": "CleanerX-Spigot-", | |
| "version_source": "CleanerX-Spigot/src/main/kotlin/pl/syntaxdevteam/cleanerx/loader/VersionChecker.kt", | |
| "paths": ["CleanerX-Spigot/"], | |
| }, | |
| ] | |
| shared = [ | |
| ".github/workflows/", | |
| "build.gradle.kts", | |
| "settings.gradle.kts", | |
| "gradle.properties", | |
| "gradle/", | |
| "gradlew", | |
| "gradlew.bat", | |
| ] | |
| def touches(prefixes): | |
| if "__all__" in changed: | |
| return True | |
| return any(path == prefix or path.startswith(prefix) for path in changed for prefix in prefixes) | |
| include_all = touches(shared) | |
| include = [] | |
| for product in products: | |
| if include_all or touches(product["paths"]): | |
| include.append({key: product[key] for key in ( | |
| "project", "platform", "platform_family", "gradle_project", "gradle_task", | |
| "jar_dir", "artifact_prefix", "version_source" | |
| )}) | |
| print("matrix=" + json.dumps({"include": include}, separators=(",", ":"))) | |
| print("has_changes=" + ("true" if include else "false")) | |
| PY | |
| verify: | |
| name: Verify repository | |
| runs-on: ubuntu-latest | |
| needs: detect | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Set up Java | |
| uses: actions/setup-java@v5 | |
| with: | |
| distribution: temurin | |
| java-version: "25" | |
| - name: Set up Gradle | |
| uses: gradle/actions/setup-gradle@v4 | |
| - name: Test all modules | |
| run: | | |
| chmod +x ./gradlew | |
| ./gradlew test --console=plain --no-daemon | |
| publish: | |
| name: Publish ${{ matrix.project }} / ${{ matrix.platform }} | |
| runs-on: ubuntu-latest | |
| needs: [detect, verify] | |
| if: github.event_name != 'pull_request' && needs.detect.outputs.has_changes == 'true' | |
| strategy: | |
| fail-fast: false | |
| matrix: ${{ fromJSON(needs.detect.outputs.matrix) }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set up Java | |
| uses: actions/setup-java@v5 | |
| with: | |
| distribution: temurin | |
| java-version: "25" | |
| - name: Set up Gradle | |
| uses: gradle/actions/setup-gradle@v4 | |
| - name: Build selected product | |
| run: | | |
| chmod +x ./gradlew | |
| ./gradlew "${{ matrix.gradle_task }}" --console=plain --no-daemon | |
| - name: Publish artifact to Build Explorer v2 | |
| env: | |
| BUILD_CI_TOKEN: ${{ secrets.BUILD_CI_TOKEN }} | |
| GITHUB_BEFORE: ${{ github.event.before }} | |
| GITHUB_AFTER: ${{ github.sha }} | |
| GITHUB_RUN_ID_VALUE: ${{ github.run_id }} | |
| GITHUB_RUN_NUMBER_VALUE: ${{ github.run_number }} | |
| GITHUB_REF_NAME_VALUE: ${{ github.ref_name }} | |
| BUILD_PROJECT: ${{ matrix.project }} | |
| BUILD_PLATFORM: ${{ matrix.platform }} | |
| BUILD_PLATFORM_FAMILY: ${{ matrix.platform_family }} | |
| BUILD_GRADLE_PROJECT: ${{ matrix.gradle_project }} | |
| BUILD_JAR_DIR: ${{ matrix.jar_dir }} | |
| BUILD_ARTIFACT_PREFIX: ${{ matrix.artifact_prefix }} | |
| BUILD_VERSION_SOURCE: ${{ matrix.version_source }} | |
| run: | | |
| set -euo pipefail | |
| if [ -z "${BUILD_CI_TOKEN}" ]; then echo "Missing BUILD_CI_TOKEN repository secret." >&2; exit 1; fi | |
| jar="$(python3 - <<'PY' | |
| from pathlib import Path | |
| import os, sys | |
| directory = Path(os.environ["BUILD_JAR_DIR"]) | |
| prefix = os.environ["BUILD_ARTIFACT_PREFIX"] | |
| excluded = ("-sources.jar", "-javadoc.jar", "-plain.jar", "-original.jar") | |
| candidates = [p for p in directory.glob("*.jar") if not p.name.endswith(excluded)] | |
| preferred = [p for p in candidates if p.name.startswith(prefix)] | |
| pool = preferred or candidates | |
| if not pool: sys.exit(1) | |
| print(max(pool, key=lambda p: p.stat().st_size)) | |
| PY | |
| )" | |
| if [ -z "${jar}" ]; then echo "No JAR found for ${BUILD_PROJECT}/${BUILD_PLATFORM}." >&2; exit 1; fi | |
| version="$(./gradlew -q "${BUILD_GRADLE_PROJECT}:properties" --console=plain --no-daemon | awk -F': ' '$1 == "version" {print $2; exit}' | tr -d '\r')" | |
| if [ -z "${version}" ] || [ "${version}" = "unspecified" ]; then version="${GITHUB_SHA::12}"; fi | |
| artifact_base="$(basename "${jar}" .jar)" | |
| artifact_upper="${artifact_base^^}" | |
| if [[ "${GITHUB_REF_NAME_VALUE}" == experimental/* || "${GITHUB_REF_NAME_VALUE}" == experimental-* ]]; then channel="wip" | |
| elif [[ "${artifact_upper}" == *"-WIP"* || "${artifact_upper}" == *"-PREALPHA"* || "${artifact_upper}" == *"-ALPHA"* ]]; then channel="wip" | |
| elif [[ "${artifact_upper}" == *"-DEV"* ]]; then channel="dev" | |
| elif [[ "${artifact_upper}" == *"-SNAPSHOT"* || "${artifact_upper}" == *"-BETA"* || "${artifact_upper}" == *"-RC"* ]]; then channel="snapshot" | |
| else channel="release"; fi | |
| game_versions="$(python3 - <<'PY' | |
| from pathlib import Path | |
| import json, os, re | |
| source = Path(os.environ["BUILD_VERSION_SOURCE"]) | |
| if not source.is_file(): raise SystemExit(f"VersionChecker source {source} does not exist.") | |
| text = source.read_text(encoding='utf-8') | |
| triples = re.findall(r"SemanticVersion\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)", text) | |
| versions = [".".join(parts) for parts in triples] | |
| if not versions: | |
| versions = re.findall(r'"(\d+(?:\.\d+){1,2})"', text) | |
| normalized, seen = [], set() | |
| for value in versions: | |
| parts = value.split('.') | |
| if len(parts) == 3 and parts[2] == '0': value = '.'.join(parts[:2]) | |
| if value not in seen: seen.add(value); normalized.append(value) | |
| if not normalized: raise SystemExit(f"No Minecraft versions found in {source}.") | |
| print(json.dumps(normalized, separators=(',', ':'))) | |
| PY | |
| )" | |
| if [ "${artifact_base%-${GITHUB_RUN_NUMBER_VALUE}}" != "${artifact_base}" ]; then filename="${artifact_base}.jar"; else filename="${artifact_base}-${GITHUB_RUN_NUMBER_VALUE}.jar"; fi | |
| sha256="$(sha256sum "${jar}" | awk '{print $1}')" | |
| size="$(stat -c%s "${jar}")" | |
| export BUILD_CHANNEL="${channel}" BUILD_GAME_VERSIONS="${game_versions}" BUILD_VERSION="${version}" BUILD_FILENAME="${filename}" BUILD_SHA256="${sha256}" BUILD_SIZE="${size}" | |
| echo "Build Explorer channel: ${BUILD_CHANNEL}" | |
| echo "Minecraft versions: ${BUILD_GAME_VERSIONS}" | |
| python3 - <<'PY' > build-info.json | |
| import json, os, subprocess | |
| from datetime import datetime, timezone | |
| before = os.environ.get('GITHUB_BEFORE', '') | |
| after = os.environ['GITHUB_AFTER'] | |
| rev_range = f"{before}..{after}" if before and before != '0' * 40 else after | |
| raw = subprocess.check_output(['git', 'log', '--format=%H%x1f%cI%x1f%s', rev_range], text=True).strip() | |
| commits = [] | |
| for line in raw.splitlines(): | |
| if line: | |
| sha, time, message = line.split('\x1f', 2) | |
| commits.append({'sha': sha, 'time': time, 'message': message}) | |
| payload = { | |
| 'id': int(os.environ['GITHUB_RUN_ID_VALUE']), | |
| 'time': datetime.now(timezone.utc).isoformat(), | |
| 'channel': os.environ['BUILD_CHANNEL'], | |
| 'platform': os.environ['BUILD_PLATFORM'], | |
| 'compatible_platforms': [os.environ['BUILD_PLATFORM']], | |
| 'platform_family': os.environ['BUILD_PLATFORM_FAMILY'], | |
| 'game_versions': json.loads(os.environ['BUILD_GAME_VERSIONS']), | |
| 'version': os.environ['BUILD_VERSION'], | |
| 'build_number': os.environ['GITHUB_RUN_NUMBER_VALUE'], | |
| 'branch': os.environ['GITHUB_REF_NAME_VALUE'], | |
| 'commit_sha': after, | |
| 'filename': os.environ['BUILD_FILENAME'], | |
| 'sha256': os.environ['BUILD_SHA256'], | |
| 'size': int(os.environ['BUILD_SIZE']), | |
| 'commits': commits[:100], | |
| } | |
| print(json.dumps(payload, ensure_ascii=False)) | |
| PY | |
| curl --fail-with-body \ | |
| -X POST "${MINI_PORTAL_URL}/api/v2/builds/ci/${BUILD_PROJECT}" \ | |
| -H "X-Build-Token: ${BUILD_CI_TOKEN}" \ | |
| -F "metadata=<build-info.json;type=application/json" \ | |
| -F "artifact=@${jar};filename=${filename};type=application/java-archive" |