diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 290e591e..084f7d6c 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -1,15 +1,12 @@ # This workflow will build a Java project with Gradle # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle -name: Java CI with Gradle +name: Build on: push: branches: - '**' - pull_request: - branches: - - '**' jobs: build: @@ -35,9 +32,11 @@ jobs: - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Build + env: + ARCLIGHT_FILES_TOKEN: ${{ secrets.ARCLIGHT_FILES_TOKEN }} run: | ./gradlew cleanBuild remapSpigotJar idea --no-daemon -i --stacktrace --refresh-dependencies - ./gradlew build collect --no-daemon -i --stacktrace + ./gradlew build collect uploadFiles --no-daemon -i --stacktrace - name: Upload Artifact uses: actions/upload-artifact@v2 with: diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml new file mode 100644 index 00000000..46092c18 --- /dev/null +++ b/.github/workflows/pr.yml @@ -0,0 +1,43 @@ +# This workflow will build a Java project with Gradle +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle + +name: Pull Request Check + +on: + pull_request: + branches: + - '**' + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 17 + uses: actions/setup-java@v1 + with: + java-version: '17' + - name: Cache Gradle User Files + uses: actions/cache@v1 + with: + path: ~/.gradle + key: ${{ runner.os }}-gradle-user-home + - name: Cache Gradle Files + uses: actions/cache@v1 + with: + path: ./.gradle + key: ${{ runner.os }}-gradle-file + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Build + run: | + ./gradlew cleanBuild remapSpigotJar idea --no-daemon -i --stacktrace --refresh-dependencies + ./gradlew build collect --no-daemon -i --stacktrace + - name: Upload Artifact + uses: actions/upload-artifact@v2 + with: + name: Arclight + path: ./build/libs/*.jar + diff --git a/build.gradle b/build.gradle index 50537df6..085fa392 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,5 @@ +import io.izzel.arclight.gradle.tasks.UploadFilesTask + allprojects { group 'io.izzel.arclight' version '1.0.6-SNAPSHOT' @@ -31,6 +33,25 @@ allprojects { task collect(type: Copy) { destinationDir = file('build/libs') - from project(':arclight-forge').file('build/libs') + from { project(':arclight-forge').tasks.jar.outputs } dependsOn { project(':arclight-forge').tasks.jar } } + +def gitBranch() { + def stdout = new ByteArrayOutputStream() + exec { + commandLine 'git', 'rev-parse', '--abbrev-ref', 'HEAD' + standardOutput = stdout + } + return stdout.toString().trim() +} + +tasks.register('uploadFiles', UploadFilesTask) { + mcVersion.set project.ext.minecraftVersion + version.set "${project.version}-${project.ext.gitHash}" + snapshot.set project.version.toString().endsWith("-SNAPSHOT") + gitHash.set project.ext.gitHash + branch.set gitBranch() + inputs.files tasks.collect.outputs.files + dependsOn(tasks.collect) +} diff --git a/buildSrc/src/main/groovy/io/izzel/arclight/gradle/tasks/UploadFilesTask.groovy b/buildSrc/src/main/groovy/io/izzel/arclight/gradle/tasks/UploadFilesTask.groovy new file mode 100644 index 00000000..014e3392 --- /dev/null +++ b/buildSrc/src/main/groovy/io/izzel/arclight/gradle/tasks/UploadFilesTask.groovy @@ -0,0 +1,112 @@ +package io.izzel.arclight.gradle.tasks + +import groovy.json.JsonOutput +import org.gradle.api.DefaultTask +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.TaskAction + +import java.nio.charset.StandardCharsets +import java.nio.file.Files +import java.security.MessageDigest +import java.util.function.Consumer + +abstract class UploadFilesTask extends DefaultTask { + + @Input + abstract Property getMcVersion() + + @Input + abstract Property getVersion() + + @Input + abstract Property getSnapshot() + + @Input + abstract Property getGitHash() + + @Input + abstract Property getBranch() + + @TaskAction + void run() { + for (def file in inputs.files.asFileTree.files) { + if (file.isFile()) { + try { + this.uploadOne(file) + } catch (Exception e) { + project.logger.error("Error uploading $file", e) + throw e + } + } + } + } + + private static final String OBJECTS = "https://files.hypoglycemia.icu/v1/objects/%s" + private static final String FILES = "https://files.hypoglycemia.icu/v1/files%s" + + private void uploadOne(File file) { + def sha1 = sha1(file) + def modloader = file.name.split('-')[1] + project.logger.lifecycle("Uploading {}, sha1 {}", file.name, sha1) + (new URL(OBJECTS.formatted(sha1)).openConnection() as HttpURLConnection).with { + it.setRequestMethod("PUT") + it.doOutput = true + it.addRequestProperty("X-Lightning-Sha1", sha1) + it.addRequestProperty("X-Lightning-Filename", file.name.replace(".jar", "-" + gitHash.get() + ".jar")) + it.addRequestProperty("AuthToken", System.getenv().ARCLIGHT_FILES_TOKEN) + it.addRequestProperty("Content-Type", "application/java-archive") + it.addRequestProperty("Content-Length", Files.size(file.toPath()).toString()) + it.setInstanceFollowRedirects(true) + it.connect() + using(it.outputStream) { + Files.copy(file.toPath(), it) + } + if (it.responseCode != 200) { + def reason = new String(it.inputStream.readAllBytes()) + project.logger.error(reason) + throw new Exception(reason) + } + } + link("/arclight/branches/${branch.get()}/versions-snapshot/${version.get()}/${modloader}", [type: 'object', value: sha1]) + link("/arclight/branches/${branch.get()}/latest-snapshot", [type: 'link', value: "/arclight/branches/${branch.get()}/versions-snapshot/${version.get()}", cache_seconds: 3600]) + if (!snapshot.get()) { + link("/arclight/branches/${branch.get()}/versions-stable/${version.get()}/${modloader}", [type: 'object', value: sha1]) + link("/arclight/branches/${branch.get()}/latest-stable", [type: 'link', value: "/arclight/branches/${branch.get()}/versions-stable/${version.get()}", cache_seconds: 86400]) + } + } + + private static void link(String path, Object payload) { + (new URL(FILES.formatted(path)).openConnection() as HttpURLConnection).with { + it.setRequestMethod("PUT") + it.doOutput = true + it.addRequestProperty("Content-Type", "application/json") + it.addRequestProperty("AuthToken", System.getenv().ARCLIGHT_FILES_TOKEN) + it.connect() + using(it.outputStream) { + it.write(JsonOutput.toJson(payload).getBytes(StandardCharsets.UTF_8)) + } + if (it.responseCode != 200) { + def reason = new String(it.inputStream.readAllBytes()) + project.logger.error(reason) + throw new Exception(reason) + } + } + } + + static void using(T closeable, Consumer consumer) { + try { + consumer.accept(closeable) + } finally { + closeable.close() + } + } + + static String sha1(File file) { + MessageDigest md = MessageDigest.getInstance('SHA-1') + file.eachByte 4096, { bytes, size -> + md.update(bytes, 0 as byte, size) + } + return md.digest().collect { String.format "%02x", it }.join() + } +}