diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index f64b7d0..ce6538c 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -9,7 +9,7 @@ name: Java CI with Gradle on: pull_request: - branches: [ "develop" ] + branches: [ "develop", "main" ] jobs: build: @@ -41,11 +41,6 @@ jobs: jpackageImage -i --scan - - name: Upload built artifacts - uses: actions/upload-artifact@v2 - with: - name: ${{ matrix.os }}-jpackageImage - path: build/jpackage/MinecraftTimeMachine # NOTE: The Gradle Wrapper is the default and recommended way to run Gradle (https://docs.gradle.org/current/userguide/gradle_wrapper.html). # If your project does not have the Gradle Wrapper configured, you can use the following configuration to run Gradle with a specified version. diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 6a57db9..3d0b959 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -4,11 +4,43 @@ name: Bump version on: push: - branches: [ main ] + tags: + - 'v*' jobs: + + compile: + strategy: + matrix: + os: [ ubuntu-latest, windows-latest, macos-latest ] + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + - name: Set up Gradle + uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 + - name: Grant execution permission for wrapper file + run: chmod +x ./gradlew ./gradlew.bat + - name: Gradle build action + uses: gradle/gradle-build-action@v2 + with: + arguments: | + build + --scan + --refresh-dependencies + --no-build-cache + --rerun-tasks + release: + # This job needs the compile job so that any compile error prevents generating a redundant release + needs: compile + runs-on: ubuntu-latest permissions: contents: write @@ -21,16 +53,38 @@ jobs: uses: mathieudutour/github-tag-action@v6.1 with: github_token: ${{ secrets.GITHUB_TOKEN }} + dry_run: true + - name: Show release informations + id: diff + run: | + LATEST_TAG=$(git describe --tags --abbrev=0) + PREVIOUS_TAG=$(git describe --tags --abbrev=0 $LATEST_TAG^) + CHANGES=$(git log $PREVIOUS_TAG..$LATEST_TAG --pretty=format:"- %s (%an)" --no-merges) + echo "LATEST_TAG=$LATEST_TAG" + echo "PREVIOUS_TAG=$PREVIOUS_TAG" + echo "CHANGES=$CHANGES" + echo "::set-output name=changelog::$CHANGES" - name: Create a github release id: create_release uses: actions/create-release@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - tag_name: ${{ steps.tag_version.outputs.new_tag }} - release_name: Release ${{ steps.tag_version.outputs.new_tag }} - body: ${{ steps.tag_version.outputs.changelog }} - draft: false + tag_name: ${{ github.ref }} + release_name: Release ${{ github.ref }} + body: | + このリリースでの変更点: + + ${{ steps.diff.outputs.changelog }} + draft: true + + bash-artifact-upload: + # uses shadowJar task to provide the artifact + needs: release + + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 - name: Set up JDK 17 uses: actions/setup-java@v4 with: @@ -39,23 +93,19 @@ jobs: - name: Set up Gradle uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 - name: Grant execution permission for wrapper file - run: chmod +x ./gradlew ./gradlew.bat + run: chmod +x ./gradlew - name: Gradle build action uses: gradle/gradle-build-action@v2 with: arguments: | - jpackageImage - -i - --scan - - name: compress artifact - run: zip -r release.zip build/jpackage/MinecraftTimeMachine - - name: Upload Release Asset - id: upload-release-asset + shadowJar + --stacktrace + - name: upload artifact uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps - asset_path: ./release.zip - asset_name: release.zip - asset_content_type: application/zip + upload_url: ${{ needs.release.outputs.create_release.outputs.upload_url }} + asset_path: build/libs/mctimemachine-all.jar + asset_name: MinecraftTimeMachine-${{ github.ref }}-executable.jar + asset-content-type: application/java-archive diff --git a/NOTICE b/NOTICE index ad1b5e7..99b37a2 100644 --- a/NOTICE +++ b/NOTICE @@ -1373,3 +1373,417 @@ JDBC Driver for SQLite WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + +okhttp3 + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +jackson + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +GitHub API for Java + +The MIT License + +Details are available at https://github-api.kohsuke.org/licenses.html diff --git a/build.gradle.kts b/build.gradle.kts index 57025b1..5eebf8b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,11 +1,11 @@ plugins { java application - id("org.beryx.jlink") version "3.0.1" - id("org.openjfx.javafxplugin") version "0.1.0" - id("org.javamodularity.moduleplugin") version "1.8.15" + alias(libs.plugins.jlink) + alias(libs.plugins.moduleplugin) + alias(libs.plugins.shadow) + alias(libs.plugins.javafxpugin) id("org.jetbrains.kotlin.jvm") - id("com.github.johnrengelman.shadow") version "8.1.1" } group = "io.github.hizumiaoba" @@ -40,32 +40,32 @@ javafx { } dependencies { - implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") + implementation(libs.kotlin.stdlib) - implementation("ch.qos.logback:logback-classic:1.5.3") - implementation("com.google.guava:guava:33.0.0-jre") + implementation(libs.logback) + implementation(libs.guava) // https://mvnrepository.com/artifact/org.xerial/sqlite-jdbc - implementation("org.xerial:sqlite-jdbc:3.45.1.0") - implementation("org.projectlombok:lombok:${lombokVersion}") + implementation(libs.sqlite.jdbc) + implementation(libs.lombok) // https://mvnrepository.com/artifact/jakarta.annotation/jakarta.annotation-api - implementation("jakarta.annotation:jakarta.annotation-api:${jakartaVersion}") + implementation(libs.jakarta.annotation) // https://mvnrepository.com/artifact/com.melloware/jintellitype - implementation("com.melloware:jintellitype:1.4.1") + implementation(libs.jintelitype) + implementation(libs.gh.api) // test dependencies - testImplementation("org.junit.jupiter:junit-jupiter-api:${junitVersion}") - testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${junitVersion}") - testImplementation("com.google.truth:truth:1.4.2") + testImplementation(libs.bundles.testlibs) + testRuntimeOnly(libs.jupiter.engine) // annotation processor - annotationProcessor("org.projectlombok:lombok:${lombokVersion}") - testAnnotationProcessor("org.projectlombok:lombok:${lombokVersion}") - annotationProcessor("jakarta.annotation:jakarta.annotation-api:${jakartaVersion}") + annotationProcessor(libs.bundles.annotationProcess) + testAnnotationProcessor(libs.lombok) } tasks.shadowJar { minimize() + archiveFileName.set("${project.name}-all.jar") } tasks.withType { diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..1608900 --- /dev/null +++ b/gradle.properties @@ -0,0 +1 @@ +org.gradle.caching=true diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..52419ef --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,31 @@ +[versions] +junit = "5.10.2" +lombok = "1.18.32" +jakarta = "3.0.0" +jackson = "2.17.0" + +[libraries] +logback = { group = "ch.qos.logback", name = "logback-classic", version = "1.5.6" } +guava = { group = "com.google.guava", name = "guava", version = "33.2.0-jre" } +sqlite-jdbc = { group = "org.xerial", name = "sqlite-jdbc", version = "3.45.3.0" } +lombok = { group = "org.projectlombok", name = "lombok", version.ref = "lombok" } +jakarta-annotation = { group = "jakarta.annotation", name = "jakarta.annotation-api", version.ref = "jakarta" } +jintelitype = { group = "com.melloware", name = "jintellitype", version = "1.4.1" } +jupiter-api = { group = "org.junit.jupiter", name = "junit-jupiter-api", version.ref = "junit" } +jupiter-engine = { group = "org.junit.jupiter", name = "junit-jupiter-engine", version.ref = "junit" } +truth = { group = "com.google.truth", name = "truth", version = "1.4.2" } +kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib-jdk8", version = "1.9.23" } +gh-api = { group = "org.kohsuke", name = "github-api", version = "1.321" } + +[bundles] +# except for engine dependency, which is only needed for running tests +testlibs = ["jupiter-api", "truth"] +# convenience bundle for annotationProcessor +annotationProcess = ["lombok", "jakarta-annotation"] +# convenience bundle for jackson libraries + +[plugins] +jlink = { id = "org.beryx.jlink", version = "3.0.1" } +javafxpugin = { id = "org.openjfx.javafxplugin", version = "0.1.0" } +moduleplugin = { id = "org.javamodularity.moduleplugin", version = "1.8.15" } +shadow = { id = "com.github.johnrengelman.shadow", version = "8.1.1" } diff --git a/src/main/java/io/github/hizumiaoba/mctimemachine/MainController.java b/src/main/java/io/github/hizumiaoba/mctimemachine/MainController.java index cc7994b..efceeb9 100644 --- a/src/main/java/io/github/hizumiaoba/mctimemachine/MainController.java +++ b/src/main/java/io/github/hizumiaoba/mctimemachine/MainController.java @@ -24,14 +24,16 @@ import java.util.concurrent.TimeUnit; import javafx.application.Platform; import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.CheckBox; import javafx.scene.control.Spinner; import javafx.scene.control.SpinnerValueFactory.IntegerSpinnerValueFactory; import javafx.scene.control.TabPane; import javafx.scene.control.TextField; -import javafx.stage.DirectoryChooser; import javafx.stage.FileChooser; +import javafx.stage.Stage; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -301,47 +303,50 @@ void onOpenSavesFolderBtnClick() { @FXML void onSelectBackupSavingFolderBtnClick() { - DirectoryChooser dc = new DirectoryChooser(); - dc.setTitle("バックアップを保存するフォルダを選択してください。"); - dc.setInitialDirectory(new File(System.getProperty("user.home"))); - log.debug("awaiting for the user to select the backup saving folder."); - File f = dc.showDialog(null); + File f = openFileChooser("バックアップを保存するフォルダを選択してください。", + new File(System.getProperty("user.home"))); if (f == null) { - log.debug("Got nothing."); return; } - log.debug("Got the folder: {}", f.getAbsolutePath()); - backupSavingFolderPathField.setText(f.getAbsolutePath()); + assignPath(backupSavingFolderPathField, f); } @FXML - void onSelectLauncherExeBtnClick() { - FileChooser fc = new FileChooser(); - fc.setTitle("ランチャーの実行ファイルを選択してください。"); - fc.setInitialDirectory(new File(System.getProperty("user.home"))); - log.debug("awaiting for the user to select the executable file."); - File f = fc.showOpenDialog(null); + void onSelectSavesFolderBtnClick() { + File f = openFileChooser("\".minecraft/saves\"フォルダを選択してください。", + new File(System.getProperty("user.home"))); if (f == null) { - log.debug("Got nothing."); return; } - log.debug("Got the file: {}", f.getAbsolutePath()); - launcherExePathField.setText(f.getAbsolutePath()); + assignPath(savesFolderPathField, f); } @FXML - void onSelectSavesFolderBtnClick() { - DirectoryChooser dc = new DirectoryChooser(); - dc.setTitle("\".minecraft/saves\"フォルダを選択してください。"); - dc.setInitialDirectory(new File(System.getProperty("user.home"))); - log.debug("awaiting for the user to select the saves folder."); - File f = dc.showDialog(null); - if (f == null) { - log.debug("Got nothing."); - return; - } - log.debug("Got the folder: {}", f.getAbsolutePath()); - savesFolderPathField.setText(f.getAbsolutePath()); + void onSelectLauncherExeBtnClick() { + File f = openFileChooser("ランチャーの実行ファイルを選択してください。", + new File(System.getProperty("user.home"))); + if (f == null) { + return; + } + assignPath(launcherExePathField, f); + } + + private File openFileChooser(String title, File initialDir) { + FileChooser fc = new FileChooser(); + fc.setTitle(title); + fc.setInitialDirectory(initialDir); + log.debug("awaiting for the user to select the file."); + File f = fc.showOpenDialog(null); + if (f == null) { + log.debug("Got nothing."); + return null; + } + return f; + } + + private void assignPath(TextField injected, File target) { + log.debug("injecting the path: {}", target.getAbsolutePath()); + injected.setText(target.getAbsolutePath()); } @FXML @@ -391,6 +396,20 @@ void onSpecialBackupNowBtnClick() { }); } + @FXML + private Button checkVersionUpdateBtn; + + @FXML + void onCheckVersionUpdateBtnClick() throws IOException { + log.trace("Checking the latest version..."); + // open new dialog with `update.fxml` + FXMLLoader loader = new FXMLLoader( + MineCraftTimeMachineApplication.class.getResource("update.fxml")); + Stage updateDialogStage = new Stage(); + updateDialogStage.setScene(new Scene(loader.load())); + updateDialogStage.showAndWait(); + } + private void runConcurrentTask(ExecutorService service, Runnable task) { service.execute(task); } diff --git a/src/main/java/io/github/hizumiaoba/mctimemachine/MineCraftTimeMachineApplication.java b/src/main/java/io/github/hizumiaoba/mctimemachine/MineCraftTimeMachineApplication.java index 4fe639d..6e45e8f 100644 --- a/src/main/java/io/github/hizumiaoba/mctimemachine/MineCraftTimeMachineApplication.java +++ b/src/main/java/io/github/hizumiaoba/mctimemachine/MineCraftTimeMachineApplication.java @@ -1,6 +1,8 @@ package io.github.hizumiaoba.mctimemachine; import com.melloware.jintellitype.JIntellitype; +import io.github.hizumiaoba.mctimemachine.api.Suffix; +import io.github.hizumiaoba.mctimemachine.api.Version; import java.io.IOException; import javafx.application.Application; import javafx.fxml.FXMLLoader; @@ -10,6 +12,7 @@ import lombok.extern.slf4j.Slf4j; @Slf4j +@Version(major = 0, minor = 2, patch = 0, suffix = Suffix.ALPHA) public class MineCraftTimeMachineApplication extends Application { @Override diff --git a/src/main/java/io/github/hizumiaoba/mctimemachine/UpdateDialogController.java b/src/main/java/io/github/hizumiaoba/mctimemachine/UpdateDialogController.java new file mode 100644 index 0000000..23e6a3b --- /dev/null +++ b/src/main/java/io/github/hizumiaoba/mctimemachine/UpdateDialogController.java @@ -0,0 +1,87 @@ +package io.github.hizumiaoba.mctimemachine; + +import io.github.hizumiaoba.mctimemachine.api.ExceptionPopup; +import io.github.hizumiaoba.mctimemachine.api.Version; +import io.github.hizumiaoba.mctimemachine.internal.version.VersionHelper; +import io.github.hizumiaoba.mctimemachine.internal.version.VersionObj; +import java.awt.Desktop; +import java.io.IOException; +import java.net.URI; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.CheckBox; +import javafx.scene.control.Label; +import javafx.scene.control.ProgressBar; +import javafx.stage.Stage; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class UpdateDialogController { + + @FXML + private CheckBox chkIncludePrerelease; + + @FXML + private ProgressBar updateProgressBar; + + @FXML + private Label labelUpdateMessage; + + private VersionObj remoteLatest; + + @FXML + void onCheckUpdateBtnClick() { + log.info("Check update button clicked."); + chkIncludePrerelease.setDisable(true); + updateProgressBar.setProgress(0.0); + log.trace("Fetching remote latest version..."); + VersionObj clientVersion = VersionObj.parse(MineCraftTimeMachineApplication.class.getAnnotation( + Version.class)); + updateProgressBar.setProgress(0.15); + VersionHelper helper = new VersionHelper(clientVersion); + try { + this.remoteLatest = VersionHelper.getLatestRemoteVersion(chkIncludePrerelease.isSelected()); + updateProgressBar.setProgress(0.33); + log.info("Remote latest version: {}", remoteLatest.asStringNotation()); + log.trace("Client version: {}", clientVersion.asStringNotation()); + updateProgressBar.setProgress(0.67); + if (helper.checkLatest(remoteLatest, false)) { + log.info("Client is up-to-date."); + } else { + log.info("Client is outdated."); + } + } catch (IOException e) { + ExceptionPopup p = new ExceptionPopup(e, "最新バージョンを取得できませんでした。", + "UpdateDialogController#onCheckUpdateBtnClick"); + p.pop(); + } finally { + chkIncludePrerelease.setDisable(false); + updateProgressBar.setProgress(1.0); + labelUpdateMessage.setText(helper.constructUpdateMessage(remoteLatest, false)); + } + } + + @FXML + void onOpenReleasePageBtnClick() { + log.info("Open release page button clicked."); + try { + // construct GitHub release page URL with remoteLatest + URI uri = URI.create( + String.format("https://github.com/hizumiaoba/MineCraftTimeMachine/releases/tag/v%s", + remoteLatest.asStringNotation())); + log.info("Opening release page: {}", uri); + Desktop.getDesktop().browse(uri); + } catch (IOException e) { + ExceptionPopup p = new ExceptionPopup(e, "リリースページを開けませんでした。", + "UpdateDialogController#onOpenReleasePageBtnClick"); + p.pop(); + } + } + + @FXML + void onCloseBtnClick(ActionEvent e) { + log.info("Close button clicked."); + Stage stage = (Stage) updateProgressBar.getScene().getWindow(); + stage.close(); + } +} diff --git a/src/main/java/io/github/hizumiaoba/mctimemachine/api/Suffix.java b/src/main/java/io/github/hizumiaoba/mctimemachine/api/Suffix.java new file mode 100644 index 0000000..cd3a697 --- /dev/null +++ b/src/main/java/io/github/hizumiaoba/mctimemachine/api/Suffix.java @@ -0,0 +1,25 @@ +package io.github.hizumiaoba.mctimemachine.api; + +import lombok.Getter; + +@Getter +public enum Suffix { + NONE(""), + ALPHA("alpha"), + BETA("beta"); + + private final String suffix; + + Suffix(String suffix) { + this.suffix = suffix; + } + + public static Suffix parse(String suffix) { + for (Suffix s : values()) { + if (s.suffix.equals(suffix)) { + return s; + } + } + return NONE; + } +} diff --git a/src/main/java/io/github/hizumiaoba/mctimemachine/api/Version.java b/src/main/java/io/github/hizumiaoba/mctimemachine/api/Version.java new file mode 100644 index 0000000..7a56a06 --- /dev/null +++ b/src/main/java/io/github/hizumiaoba/mctimemachine/api/Version.java @@ -0,0 +1,16 @@ +package io.github.hizumiaoba.mctimemachine.api; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface Version { + + int major(); + + int minor(); + + int patch(); + + Suffix suffix() default Suffix.NONE; +} diff --git a/src/main/java/io/github/hizumiaoba/mctimemachine/internal/version/VersionHelper.java b/src/main/java/io/github/hizumiaoba/mctimemachine/internal/version/VersionHelper.java new file mode 100644 index 0000000..0c77b64 --- /dev/null +++ b/src/main/java/io/github/hizumiaoba/mctimemachine/internal/version/VersionHelper.java @@ -0,0 +1,79 @@ +package io.github.hizumiaoba.mctimemachine.internal.version; + +import io.github.hizumiaoba.mctimemachine.MineCraftTimeMachineApplication; +import io.github.hizumiaoba.mctimemachine.api.Version; +import java.io.IOException; +import java.util.List; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.kohsuke.github.GHRelease; +import org.kohsuke.github.GitHub; + +@RequiredArgsConstructor +@Slf4j +public class VersionHelper { + + private final VersionObj clientVersion; + + public boolean checkLatest(VersionObj remoteVersion, boolean ignoreSuffix) { + return getUpdateType(remoteVersion, ignoreSuffix).equals("latest"); + } + + private String getUpdateType(VersionObj remoteVersion, boolean ignoreSuffix) { + final boolean isMajorSame = clientVersion.getMajor() == remoteVersion.getMajor(); + final boolean isMinorSame = clientVersion.getMinor() == remoteVersion.getMinor(); + final boolean isPatchSame = clientVersion.getPatch() == remoteVersion.getPatch(); + final boolean isSuffixSame = + ignoreSuffix || clientVersion.getSuffix().equals(remoteVersion.getSuffix()); + if (isMajorSame && isMinorSame && isPatchSame && isSuffixSame) { + return "latest"; + } else if (isMajorSame && isMinorSame && isPatchSame) { + return "suffix"; + } else if (isMajorSame && isMinorSame) { + return "patch"; + } else if (isMajorSame) { + return "minor"; + } else { + return "major"; + } + } + + public static VersionObj getLatestRemoteVersion(boolean includePrerelease) throws IOException { + GitHub gh = GitHub.connectAnonymously(); + List releases = gh.getRepository("hizumiaoba/MineCraftTimeMachine") + .listReleases() + .toList() + .parallelStream().filter(r -> includePrerelease || !r.isPrerelease()) + .toList(); + if (releases.isEmpty()) { + // fall back client version so that no update prompt will be shown + log.warn( + "No available releases found with required precondition. Fallback to client version."); + return VersionObj.parse(MineCraftTimeMachineApplication.class.getAnnotation(Version.class)); + } + log.debug("Found {} releases", releases.size()); + log.trace("Latest release: {}", releases.get(0).getTagName()); + return VersionObj.parse(releases.get(0).getTagName()); + } + + public String constructUpdateMessage(VersionObj remoteVersion, boolean ignoreSuffix) { + final String updateType = getUpdateType(remoteVersion, ignoreSuffix); + final String remoteVersionString = remoteVersion.asStringNotation(); + final String clientVersionString = clientVersion.asStringNotation(); + final String clientVersionNotice = "現在のバージョンは" + clientVersionString + "です。"; + return switch (updateType) { + case "latest" -> "現在最新バージョンのソフトウェアを使用中です!最新こそ正義!"; + case "suffix" -> "新しい試験運用版のソフトウェアが利用可能です!未知への冒険へ、出発です! \n最新バージョン: " + + remoteVersionString + "。 " + clientVersionNotice; + case "patch" -> "新しいパッチリリースのソフトウェアが利用可能です!バグ修正などが含まれています! \n最新バージョン: " + + remoteVersionString + "。 " + clientVersionNotice; + case "minor" -> "新しいマイナーリリースのソフトウェアが利用可能です!新機能や小規模な機能の挙動改善が含まれています! \n最新バージョン: " + + remoteVersionString + "。 " + clientVersionNotice; + case "major" -> + "新しいメジャーリリースのソフトウェアが利用可能です!大規模な機能追加や大幅な仕様変更が含まれています!更新の際には互換性にご注意ください! \n最新バージョン: " + + remoteVersionString + "。 " + clientVersionNotice; + default -> + "更新の種類を特定できません。直接アップデートを確認してください。" + clientVersionNotice; + }; + } +} diff --git a/src/main/java/io/github/hizumiaoba/mctimemachine/internal/version/VersionObj.java b/src/main/java/io/github/hizumiaoba/mctimemachine/internal/version/VersionObj.java new file mode 100644 index 0000000..81d1ac8 --- /dev/null +++ b/src/main/java/io/github/hizumiaoba/mctimemachine/internal/version/VersionObj.java @@ -0,0 +1,44 @@ +package io.github.hizumiaoba.mctimemachine.internal.version; + +import io.github.hizumiaoba.mctimemachine.api.Suffix; +import io.github.hizumiaoba.mctimemachine.api.Version; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@Getter +public class VersionObj { + + private final int major; + private final int minor; + private final int patch; + private Suffix suffix; + + public static VersionObj parse(String versionNotation) { + // versionNotation should be "major.minor.patch" or "major.minor.patch-suffix" + // and may contain "v" prefix + String[] versionParts = versionNotation.replace("v", "").split("-"); + String[] versionNumbers = versionParts[0].split("\\."); + int major = Integer.parseInt(versionNumbers[0]); + int minor = Integer.parseInt(versionNumbers[1]); + int patch = Integer.parseInt(versionNumbers[2]); + Suffix suffix = versionParts.length > 1 ? Suffix.parse(versionParts[1]) : Suffix.NONE; + return new VersionObj(major, minor, patch, suffix); + } + + public static VersionObj parse(Version versionAnnotation) { + int major = versionAnnotation.major(); + int minor = versionAnnotation.minor(); + int patch = versionAnnotation.patch(); + Suffix suffix = versionAnnotation.suffix(); + return new VersionObj(major, minor, patch, suffix); + } + + public String asStringNotation() { + return String.format("%d.%d.%d%s", major, minor, patch, + Suffix.NONE.equals(suffix) ? "" : "-" + suffix.getSuffix()); + } +} diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 5f15def..7f8f889 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -10,6 +10,9 @@ requires lombok; requires annotations; requires jintellitype; + requires org.kohsuke.github.api; + requires com.fasterxml.jackson.core; + requires com.fasterxml.jackson.databind; opens io.github.hizumiaoba.mctimemachine to javafx.fxml; exports io.github.hizumiaoba.mctimemachine; diff --git a/src/main/resources/io/github/hizumiaoba/mctimemachine/main.fxml b/src/main/resources/io/github/hizumiaoba/mctimemachine/main.fxml index 441427b..c2c651a 100644 --- a/src/main/resources/io/github/hizumiaoba/mctimemachine/main.fxml +++ b/src/main/resources/io/github/hizumiaoba/mctimemachine/main.fxml @@ -46,7 +46,7 @@ @@ -113,6 +113,9 @@ mnemonicParsing="false" onAction="#onOpenRelatedFolderBtnClick" prefHeight="40.0" prefWidth="170.0" text="各種フォルダを開く" fx:id="openRelatedFolderBtn"/> +