├── .editorconfig ├── .github └── workflows │ ├── automerge.yml │ ├── on-release.yml │ └── quick-check.yml ├── .gitignore ├── .gitlab-ci.yml ├── .travis.yml ├── LICENSE ├── README.md ├── build.gradle.kts ├── config └── detekt.yml ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle.kts ├── src ├── main │ └── kotlin │ │ └── io │ │ └── github │ │ └── gciatto │ │ └── kt │ │ └── node │ │ ├── AbstractNodeDefaultTask.kt │ │ ├── AbstractNodeExecTask.kt │ │ ├── Bugs.kt │ │ ├── CopyRootProjectFilesTask.kt │ │ ├── FileLineTransformer.kt │ │ ├── JsonUtils.kt │ │ ├── LiftJsSourcesTask.kt │ │ ├── LiftPackageJsonTask.kt │ │ ├── NpmPublishExtension.kt │ │ ├── NpmPublishPlugin.kt │ │ ├── NpmPublishTask.kt │ │ ├── PackageJson.kt │ │ ├── People.kt │ │ ├── SetRegistryTask.kt │ │ └── SetTokenTask.kt └── test │ ├── kotlin │ └── io │ │ └── github │ │ └── gciatto │ │ └── kt │ │ └── node │ │ └── test │ │ ├── TestingDSL.kt │ │ └── Tests.kt │ └── resources │ └── io │ └── github │ └── gciatto │ └── kt │ └── node │ └── test │ ├── js │ ├── README.md │ ├── build.gradle │ ├── gradle.properties │ ├── settings.gradle │ ├── src │ │ └── main │ │ │ └── kotlin │ │ │ └── Hello.kt │ └── test.yaml │ ├── kt │ ├── build.gradle │ ├── settings.gradle │ └── test.yaml │ └── mpp │ ├── README.md │ ├── build.gradle │ ├── gradle.properties │ ├── settings.gradle │ ├── src │ └── commonMain │ │ └── kotlin │ │ └── Hello.kt │ └── test.yaml └── versions.properties /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{kt,kts}] 2 | disabled_rules=import-ordering 3 | 4 | -------------------------------------------------------------------------------- /.github/workflows/automerge.yml: -------------------------------------------------------------------------------- 1 | name: automerge 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | types: 8 | - labeled 9 | - unlabeled 10 | - synchronize 11 | - opened 12 | - edited 13 | - ready_for_review 14 | - reopened 15 | - unlocked 16 | pull_request_review: 17 | types: 18 | - submitted 19 | check_suite: 20 | types: 21 | - completed 22 | status: {} 23 | jobs: 24 | automerge: 25 | runs-on: ubuntu-latest 26 | steps: 27 | - name: automerge 28 | uses: "pascalgn/automerge-action@80acb0f883348dcfd0e526288f7d27a12b9333be" 29 | env: 30 | GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" 31 | MERGE_LABELS: "version-upgrade" 32 | MERGE_REMOVE_LABELS: "" 33 | MERGE_METHOD: "rebase" 34 | MERGE_COMMIT_MESSAGE: "pull-request-title" 35 | MERGE_FILTER_AUTHOR: "DanySK" 36 | MERGE_FORKS: "false" 37 | UPDATE_LABELS: "version-upgrade" 38 | UPDATE_METHOD: "rebase" 39 | -------------------------------------------------------------------------------- /.github/workflows/on-release.yml: -------------------------------------------------------------------------------- 1 | name: on-release 2 | on: 3 | push: 4 | tags: 5 | - '[0-9]+.[0-9]+.[0-9]+' 6 | env: 7 | jdk-version: openjdk@~1.15.0 8 | project-name: Kt NPM Publish 9 | workflow: release 10 | gradle-options: "--no-daemon --console=plain --stacktrace" 11 | jobs: 12 | setup: 13 | runs-on: ubuntu-latest 14 | steps: 15 | # - &cache_jdk 16 | - name: Cache JDK 17 | uses: actions/cache@v2 18 | with: 19 | path: ~/.jabba 20 | key: ${{ runner.os }}-jdk-${{ env.jdk-version }} 21 | restore-keys: | 22 | ${{ runner.os }}-jdk- 23 | 24 | # - &install_jdk 25 | - uses: battila7/jdk-via-jabba@v1 26 | name: Restore JDK 27 | with: 28 | jdk: ${{ env.jdk-version }} 29 | 30 | build: 31 | runs-on: ubuntu-latest 32 | needs: 33 | - setup 34 | steps: 35 | # - &checkout_code 36 | - name: Checkout code 37 | uses: actions/checkout@v2 38 | with: 39 | fetch-depth: 0 # all history 40 | 41 | - name: Get All Tags 42 | run: git fetch --tags -f 43 | 44 | # - *cache_jdk 45 | - name: Cache JDK 46 | uses: actions/cache@v2 47 | with: 48 | path: ~/.jabba 49 | key: ${{ runner.os }}-jdk-${{ env.jdk-version }} 50 | restore-keys: | 51 | ${{ runner.os }}-jdk- 52 | 53 | # - *install_jdk 54 | - uses: battila7/jdk-via-jabba@v1 55 | name: Restore JDK 56 | with: 57 | jdk: ${{ env.jdk-version }} 58 | 59 | # - &cache_gradle 60 | - name: Cache Gradle Data 61 | uses: actions/cache@v2 62 | with: 63 | path: | 64 | ~/.m2/repository 65 | ~/.gradle/caches 66 | ~/gradle/wrapper 67 | **/build 68 | **/.gradle 69 | key: ${{ runner.os }}-${{ env.workflow }}-gradle-${{ github.sha }}-build 70 | restore-keys: | 71 | ${{ runner.os }}-${{ env.workflow }}-gradle-${{ github.sha }}-build 72 | 73 | - name: Show Env 74 | run: ./gradlew --version 75 | 76 | - name: Setup Gradle 77 | run: ./gradlew ${{ env.gradle-options }} 78 | 79 | - name: Check Code Style 80 | run: ./gradlew ${{ env.gradle-options }} ktlintCheck 81 | 82 | - name: Archive KtLint Reports 83 | uses: actions/upload-artifact@v2 84 | if: failure() 85 | with: 86 | name: ktlint-reports 87 | path: '**/build/reports/ktlint' 88 | 89 | - name: Check for Bugs 90 | run: ./gradlew ${{ env.gradle-options }} detekt 91 | 92 | - name: Compile 93 | run: ./gradlew ${{ env.gradle-options }} assemble --parallel 94 | 95 | test: 96 | runs-on: ubuntu-latest 97 | needs: 98 | - build 99 | steps: 100 | # - *checkout_code 101 | - name: Checkout code 102 | uses: actions/checkout@v2 103 | with: 104 | fetch-depth: 0 # all history 105 | 106 | - name: Get All Tags 107 | run: git fetch --tags -f 108 | 109 | # - *cache_jdk 110 | - name: Cache JDK 111 | uses: actions/cache@v2 112 | with: 113 | path: ~/.jabba 114 | key: ${{ runner.os }}-jdk-${{ env.jdk-version }} 115 | restore-keys: | 116 | ${{ runner.os }}-jdk- 117 | 118 | # - *install_jdk 119 | - uses: battila7/jdk-via-jabba@v1 120 | name: Restore JDK 121 | with: 122 | jdk: ${{ env.jdk-version }} 123 | 124 | # - *cache_gradle 125 | - name: Cache Gradle Data 126 | uses: actions/cache@v2 127 | with: 128 | path: | 129 | ~/.m2/repository 130 | ~/.gradle/caches 131 | ~/gradle/wrapper 132 | **/build 133 | **/.gradle 134 | key: ${{ runner.os }}-${{ env.workflow }}-gradle-${{ github.sha }}-test 135 | restore-keys: | 136 | ${{ runner.os }}-${{ env.workflow }}-gradle-${{ github.sha }}-build 137 | 138 | - name: Test 139 | run: ./gradlew ${{ env.gradle-options }} test 140 | 141 | - name: Archive Test Reports 142 | uses: actions/upload-artifact@v2 143 | if: failure() || success() 144 | with: 145 | name: jvm-test-reports 146 | path: '**/build/reports/tests/test' 147 | 148 | prepare-artifacts: 149 | runs-on: ubuntu-latest 150 | needs: 151 | - test 152 | steps: 153 | # - *checkout_code 154 | - name: Checkout code 155 | uses: actions/checkout@v2 156 | with: 157 | fetch-depth: 0 # all history 158 | 159 | - name: Get All Tags 160 | run: git fetch --tags -f 161 | 162 | # - *cache_jdk 163 | - name: Cache JDK 164 | uses: actions/cache@v2 165 | with: 166 | path: ~/.jabba 167 | key: ${{ runner.os }}-jdk-${{ env.jdk-version }} 168 | restore-keys: | 169 | ${{ runner.os }}-jdk- 170 | 171 | # - *install_jdk 172 | - uses: battila7/jdk-via-jabba@v1 173 | name: Restore JDK 174 | with: 175 | jdk: ${{ env.jdk-version }} 176 | 177 | # - *cache_gradle 178 | - name: Cache Gradle Data 179 | uses: actions/cache@v2 180 | with: 181 | path: | 182 | ~/.m2/repository 183 | ~/.gradle/caches 184 | ~/gradle/wrapper 185 | **/build 186 | **/.gradle 187 | key: ${{ runner.os }}-${{ env.workflow }}-gradle-${{ github.sha }}-prepare 188 | restore-keys: | 189 | ${{ runner.os }}-${{ env.workflow }}-gradle-${{ github.sha }}-test 190 | 191 | - name: Generate Doc 192 | run: ./gradlew ${{ env.gradle-options }} dokkaHtml --parallel 193 | 194 | - name: Sign Archives 195 | run: ./gradlew ${{ env.gradle-options }} signJava signKotlin --parallel 196 | env: 197 | ORG_GRADLE_PROJECT_signingKey: ${{ secrets.SIGNING_KEY }} 198 | ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.SIGNING_PASSWORD }} 199 | ORG_GRADLE_PROJECT_mavenUsername: ${{ secrets.OSSRH_USERNAME }} 200 | ORG_GRADLE_PROJECT_mavenPassword: ${{ secrets.OSSRH_PASSWORD }} 201 | 202 | deploy: 203 | runs-on: ubuntu-latest 204 | needs: 205 | - prepare-artifacts 206 | env: 207 | ORG_GRADLE_PROJECT_signingKey: ${{ secrets.SIGNING_KEY }} 208 | ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.SIGNING_PASSWORD }} 209 | ORG_GRADLE_PROJECT_mavenUsername: ${{ secrets.OSSRH_USERNAME }} 210 | ORG_GRADLE_PROJECT_mavenPassword: ${{ secrets.OSSRH_PASSWORD }} 211 | steps: 212 | # - *checkout_code 213 | - name: Checkout code 214 | uses: actions/checkout@v2 215 | with: 216 | fetch-depth: 0 # all history 217 | 218 | - name: Get All Tags 219 | run: git fetch --tags -f 220 | 221 | # - *cache_jdk 222 | - name: Cache JDK 223 | uses: actions/cache@v2 224 | with: 225 | path: ~/.jabba 226 | key: ${{ runner.os }}-jdk-${{ env.jdk-version }} 227 | restore-keys: | 228 | ${{ runner.os }}-jdk- 229 | 230 | # - *install_jdk 231 | - uses: battila7/jdk-via-jabba@v1 232 | name: Restore JDK 233 | with: 234 | jdk: ${{ env.jdk-version }} 235 | 236 | # - *cache_gradle 237 | - name: Cache Gradle Data 238 | uses: actions/cache@v2 239 | with: 240 | path: | 241 | ~/.m2/repository 242 | ~/.gradle/caches 243 | ~/gradle/wrapper 244 | **/build 245 | **/.gradle 246 | key: ${{ runner.os }}-${{ env.workflow }}-gradle-${{ github.sha }}-maven-central 247 | restore-keys: | 248 | ${{ runner.os }}-${{ env.workflow }}-gradle-${{ github.sha }}-prepare 249 | ${{ runner.os }}-${{ env.workflow }}-gradle-${{ github.sha }}-maven- 250 | 251 | - name: Publish Gradle Plugin 252 | run: ./gradlew ${{ env.gradle-options }} publishPlugin ${{ env.gradle-secrets }} --parallel 253 | # if: contains(github.ref, 'master') 254 | env: 255 | gradle-secrets: "-Pgradle.publish.key=${{ secrets.GRADLE_KEY }} -Pgradle.publish.secret=${{ secrets.GRADLE_SECRET }}" 256 | 257 | - name: Publish on Maven Central Repo 258 | run: ./gradlew ${{ env.gradle-options }} publishJavaMavenPublicationToSonatypeRepository --parallel 259 | # if: contains(github.ref, 'master') 260 | -------------------------------------------------------------------------------- /.github/workflows/quick-check.yml: -------------------------------------------------------------------------------- 1 | name: quick-check 2 | on: 3 | push: 4 | branches: 5 | - '*' 6 | env: 7 | jdk-version: openjdk@~1.15.0 8 | project-name: Kt NPM Publish 9 | workflow: quick-check 10 | gradle-options: "--no-daemon --console=plain --stacktrace" 11 | jobs: 12 | setup: 13 | runs-on: ubuntu-latest 14 | steps: 15 | # - &cache_jdk 16 | - name: Cache JDK 17 | uses: actions/cache@v2 18 | with: 19 | path: ~/.jabba 20 | key: ${{ runner.os }}-jdk-${{ env.jdk-version }} 21 | restore-keys: | 22 | ${{ runner.os }}-jdk- 23 | 24 | # - &install_jdk 25 | - uses: battila7/jdk-via-jabba@v1 26 | name: Restore JDK 27 | with: 28 | jdk: ${{ env.jdk-version }} 29 | 30 | build: 31 | runs-on: ubuntu-latest 32 | needs: 33 | - setup 34 | steps: 35 | # - &checkout_code 36 | - name: Checkout code 37 | uses: actions/checkout@v2 38 | with: 39 | fetch-depth: 0 # all history 40 | 41 | - name: Get All Tags 42 | run: git fetch --tags -f 43 | 44 | # - *cache_jdk 45 | - name: Cache JDK 46 | uses: actions/cache@v2 47 | with: 48 | path: ~/.jabba 49 | key: ${{ runner.os }}-jdk-${{ env.jdk-version }} 50 | restore-keys: | 51 | ${{ runner.os }}-jdk- 52 | 53 | # - *install_jdk 54 | - uses: battila7/jdk-via-jabba@v1 55 | name: Restore JDK 56 | with: 57 | jdk: ${{ env.jdk-version }} 58 | 59 | # - &cache_gradle 60 | - name: Cache Gradle Data 61 | uses: actions/cache@v2 62 | with: 63 | path: | 64 | ~/.m2/repository 65 | ~/.gradle/caches 66 | ~/gradle/wrapper 67 | **/build 68 | **/.gradle 69 | key: ${{ runner.os }}-${{ env.workflow }}-gradle-${{ github.sha }}-build 70 | restore-keys: | 71 | ${{ runner.os }}-${{ env.workflow }}-gradle-${{ github.sha }}-build 72 | 73 | - name: Show Env 74 | run: ./gradlew --version 75 | 76 | - name: Setup Gradle 77 | run: ./gradlew ${{ env.gradle-options }} 78 | 79 | - name: Check Code Style 80 | run: ./gradlew ${{ env.gradle-options }} ktlintCheck 81 | 82 | - name: Archive KtLint Reports 83 | uses: actions/upload-artifact@v2 84 | if: failure() 85 | with: 86 | name: ktlint-reports 87 | path: '**/build/reports/ktlint' 88 | 89 | - name: Check for Bugs 90 | run: ./gradlew ${{ env.gradle-options }} detekt 91 | 92 | - name: Compile 93 | run: ./gradlew ${{ env.gradle-options }} assemble --parallel 94 | 95 | test: 96 | runs-on: ubuntu-latest 97 | needs: 98 | - build 99 | steps: 100 | # - *checkout_code 101 | - name: Checkout code 102 | uses: actions/checkout@v2 103 | with: 104 | fetch-depth: 0 # all history 105 | 106 | - name: Get All Tags 107 | run: git fetch --tags -f 108 | 109 | # - *cache_jdk 110 | - name: Cache JDK 111 | uses: actions/cache@v2 112 | with: 113 | path: ~/.jabba 114 | key: ${{ runner.os }}-jdk-${{ env.jdk-version }} 115 | restore-keys: | 116 | ${{ runner.os }}-jdk- 117 | 118 | # - *install_jdk 119 | - uses: battila7/jdk-via-jabba@v1 120 | name: Restore JDK 121 | with: 122 | jdk: ${{ env.jdk-version }} 123 | 124 | # - *cache_gradle 125 | - name: Cache Gradle Data 126 | uses: actions/cache@v2 127 | with: 128 | path: | 129 | ~/.m2/repository 130 | ~/.gradle/caches 131 | ~/gradle/wrapper 132 | **/build 133 | **/.gradle 134 | key: ${{ runner.os }}-${{ env.workflow }}-gradle-${{ github.sha }}-test 135 | restore-keys: | 136 | ${{ runner.os }}-${{ env.workflow }}-gradle-${{ github.sha }}-build 137 | 138 | - name: Test 139 | run: ./gradlew ${{ env.gradle-options }} test 140 | 141 | - name: Archive Test Reports 142 | uses: actions/upload-artifact@v2 143 | if: failure() || success() 144 | with: 145 | name: jvm-test-reports 146 | path: '**/build/reports/tests/test' 147 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle/ 2 | build/ 3 | .idea/ 4 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | image: pikalab/ci:ubuntu-jdk14-git-gradle-graphviz 2 | 3 | variables: 4 | GOPTS: "--no-daemon --console=plain" 5 | CI: "true" 6 | BEFORE_TASK: "" 7 | AFTER_TASK: "" 8 | GCMD: "./gradlew" 9 | CHECK_TASK: "ktlintCheck detekt" 10 | BUILD_TASK: "assemble" 11 | TEST_TASK: "test" 12 | SIGN_TASK: "signAllPublications --parallel" 13 | BINTRAY_TASK: "publishAllToBintray --parallel" 14 | CENTRAL_TASK: "publishAllPublicationsToMavenRepository --parallel" 15 | 16 | before_script: 17 | - chmod +x gradlew 18 | - source $HOME/.sdkman/bin/sdkman-init.sh 19 | 20 | cache: 21 | paths: 22 | - $HOME/.gradle/ 23 | - $HOME/.m2/ 24 | - gradle/ 25 | - .gradle/ 26 | - build/ 27 | 28 | Compile: 29 | stage: build 30 | script: 31 | - $GCMD $BEFORE_TASK $CHECK_TASK $AFTER_TASK $GOPTS 32 | - $GCMD $BEFORE_TASK $BUILD_TASK $AFTER_TASK $GOPTS 33 | only: 34 | - branches 35 | needs: [ ] 36 | 37 | Test: 38 | stage: test 39 | script: $GCMD $BEFORE_TASK $TEST_TASK $AFTER_TASK $GOPTS 40 | artifacts: 41 | reports: 42 | junit: "**/build/test-results/*.xml" 43 | only: 44 | - branches 45 | needs: 46 | - job: Compile 47 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | _reference_jdk: &reference_jdk 2 | JDK="adopt@1.8" 3 | 4 | _reference_build: &reference_build 5 | os: linux 6 | env: *reference_jdk 7 | 8 | git: 9 | depth: false 10 | autocrlf: input 11 | 12 | language: minimal 13 | 14 | os: 15 | - macos 16 | - windows 17 | - linux 18 | 19 | env: 20 | global: 21 | - GRAVIS_REPO="https://github.com/DanySK/Gravis-CI.git" 22 | - GRAVIS="$HOME/gravis" 23 | - TERM="dumb" 24 | matrix: 25 | - *reference_jdk 26 | - JDK="adopt-openj9@1.8" 27 | - JDK="adopt@1.11" 28 | - JDK="adopt-openj9@1.11" 29 | - JDK="adopt@" 30 | - JDK="adopt-openj9" 31 | 32 | stages: 33 | - base 34 | - test 35 | - name: deploy 36 | if: type != pull_request AND repo = DanySK/Template-for-Gradle-Plugins 37 | 38 | jobs: 39 | exclude: 40 | - <<: *reference_build 41 | stage: test 42 | include: 43 | - <<: *reference_build 44 | stage: base 45 | after_success: bash <(curl -s https://codecov.io/bash) 46 | script: 47 | - travis_retry ./gradlew clean check jacocoTestReport 48 | - <<: *reference_build 49 | stage: deploy 50 | install: 51 | - openssl aes-256-cbc -K $encrypted_f778b2e1574b_key -iv $encrypted_f778b2e1574b_iv -in secrets.asc.enc -out secrets.asc -d 52 | - export ORG_GRADLE_PROJECT_signingKey=$(cat secrets.asc) 53 | - rm secrets.asc 54 | script: 55 | - travis_retry ./gradlew dokka publishMavenCentralPublicationToMavenRepository 56 | after_success: 57 | # Uploading to the Gradle Plugin Portal now, as it fails in case of duplicates 58 | - travis_retry ./gradlew publishPlugin -Pgradle.publish.key=$GRADLE_PUBLISH_KEY -Pgradle.publish.secret=$GRADLE_PUBLISH_SECRET 59 | 60 | before_install: 61 | - travis_retry git clone --depth 1 $GRAVIS_REPO $GRAVIS 62 | - source $GRAVIS/install-jdk 63 | script: 64 | - travis_retry ./gradlew clean check 65 | before_cache: 66 | - $GRAVIS/clean-gradle-cache 67 | cache: 68 | directories: 69 | - $HOME/.gradle/caches/ 70 | - $HOME/.gradle/wrapper/ 71 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2020, Giovanni Ciatto. 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Publishing Kotlin Multi-Platform Projects to NPM 2 | 3 | A Gradle plugin letting developers upload Kotlin-JS or -MPP projects on NPM. 4 | It requires a Gradle project including one of the following plugins: 5 | - `org.jetbrains.kotlin.js` 6 | - `org.jetbrains.kotlin.multiplatform` 7 | 8 | In both cases, the plugin assumes a Node Js target has been added to your project, explicitly, via the syntax: 9 | ```kotlin 10 | kotlin { 11 | js { 12 | nodeJs { 13 | // ... 14 | } 15 | } 16 | } 17 | ``` 18 | 19 | The plugin does _not_ apply any of the aforementioned `org.jetbrains.kotlin.*` plugins behind the scenes. 20 | Thus, it is important to apply them accordingly. 21 | 22 | The basic configuration of the plugin is as follows: 23 | ```kotlin 24 | npmPublishing { 25 | token.set("") 26 | } 27 | ``` 28 | This adds a numbers of tasks to your project. 29 | The most relevant one is `:npmPublish` which essentially packs and uploads the JS project generated by the Kotlin plugin 30 | out of the Kotlin code. 31 | This task also includes any file in the root project's directory whose name matches `README*`, `CONTRIB*`, or `LICENSE*`. 32 | 33 | 35 | 36 | Users may override a number of properties within the `npmPublishing`, like for instance: 37 | ```kotlin 38 | npmPublishing { 39 | token.set("") 40 | 41 | registry.set("") // defaults to registry.npmjs.org 42 | } 43 | ``` 44 | 45 | The plugin may also _lift_ the `package.json` file generated by Kotlin, as well as any `.js` file, in a programmatic way. 46 | The lifting if performed before publication and it is aimed at customising the data published on the NPM registry. 47 | For instance, one may override any information generated by the Kotlin compiler, change the name of the generated project, 48 | and so on. 49 | 50 | Lifting is based on the `liftPackageJson` and `liftJsSources` methods which are available within the `npmPublishing` section. 51 | In particular, `liftPackageJson` accepts a lambda expression as input. 52 | Within that lambda expression, `this` refers to an object representing the current value of the generated `package.json` file. 53 | The user may update any field, and each modification will be reified into the `package.json` file. 54 | 55 | For instance, the following snippet adds a number a developer to the generated `package.json`, other than setting a few common metadata: 56 | ```kotlin 57 | npmPublishing { 58 | token.set("") 59 | 60 | liftPackageJson { 61 | people = mutableListOf(People("Developer Name", "Developer Email", "Developer Homepage")) 62 | homepage = "Project homepage" 63 | bugs = Bugs("Issues Web Page", "Issues Email Address") 64 | license = "Apache-2.0" 65 | } 66 | } 67 | ``` 68 | 69 | If you want to publish your project (say `test-js`) under the organization named `organization`, you should lift 70 | both the generated `package.json` and the generated `.js` files as follows: 71 | ```kotlin 72 | npmPublishing { 73 | token.set("") 74 | 75 | liftPackageJson { 76 | name = "@organization/$name" 77 | dependencies = dependencies?.mapKeys { (key, _) -> 78 | if (name in key) "@organization/$key" else key 79 | } 80 | } 81 | 82 | liftJsSources { file, i, line -> 83 | line.replace("'test-mpp", "'@organization/test-mpp") 84 | .replace("\"test-mpp", "\"@organization/test-mpp") 85 | } 86 | } 87 | ``` -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | import java.time.Duration 2 | 3 | import org.gradle.api.tasks.testing.logging.TestExceptionFormat 4 | import org.gradle.api.tasks.testing.logging.TestLogEvent 5 | 6 | plugins { 7 | jacoco 8 | `java-gradle-plugin` 9 | kotlin("jvm") 10 | `maven-publish` 11 | signing 12 | id("com.gradle.plugin-publish") 13 | id("io.gitlab.arturbosch.detekt") 14 | id("org.jetbrains.dokka") 15 | id("org.jlleitschuh.gradle.ktlint") 16 | id("org.danilopianini.git-sensitive-semantic-versioning") 17 | id("org.danilopianini.publish-on-central") 18 | id("de.marcphilipp.nexus-publish") 19 | } 20 | 21 | /* 22 | * Project information 23 | */ 24 | group = "io.github.gciatto" 25 | description = "A plugin easing the publishin of Kotlin JS/Multiplaftorm projects on NPM" 26 | inner class NpmPublishInfo { 27 | val longName = "Publish Kotlin projects on NPM" 28 | val website = "https://github.com/gciatto/kt-npm-publish" 29 | val scm = "git@github.com:gciatto/kt-npm-publish.git" 30 | val pluginImplementationClass = "$group.kt.node.NpmPublishPlugin" 31 | val tags = listOf("kotlin", "multi plaftorm", "js", "javascript", "publish", "npm", "gradle") 32 | val license = "Apache License, Version 2.0" 33 | val licenseUrl = "https://www.apache.org/licenses/LICENSE-2.0" 34 | } 35 | val info = NpmPublishInfo() 36 | 37 | gitSemVer { 38 | version = computeGitSemVer() 39 | } 40 | 41 | println("$group:$name v$version") 42 | 43 | repositories { 44 | mavenCentral() 45 | jcenter() 46 | mapOf( 47 | "kotlin/dokka" to setOf("org.jetbrains.dokka"), 48 | "kotlin/kotlinx.html" to setOf("org.jetbrains.kotlinx"), 49 | "arturbosch/code-analysis" to setOf("io.gitlab.arturbosch.detekt") 50 | ).forEach { (uriPart, groups) -> 51 | maven { 52 | url = uri("https://dl.bintray.com/$uriPart") 53 | content { groups.forEach { includeGroup(it) } } 54 | } 55 | } 56 | } 57 | 58 | dependencies { 59 | detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:_") 60 | api(gradleApi()) 61 | api(gradleKotlinDsl()) 62 | api("org.jetbrains.kotlin:kotlin-gradle-plugin:_") 63 | implementation(kotlin("stdlib-jdk8")) 64 | implementation("com.google.code.gson", "gson", "_") 65 | testImplementation(gradleTestKit()) 66 | testImplementation("com.uchuhimo:konf-yaml:_") 67 | testImplementation("io.github.classgraph:classgraph:_") 68 | testImplementation("io.kotest:kotest-runner-junit5:_") 69 | testImplementation("io.kotest:kotest-assertions-core-jvm:_") 70 | testImplementation("com.nhaarman.mockitokotlin2:mockito-kotlin:_") 71 | testImplementation("org.mockito:mockito-core:_") 72 | // testRuntimeOnly(files(createClasspathManifest)) 73 | } 74 | 75 | kotlin { 76 | target { 77 | compilations.all { 78 | kotlinOptions { 79 | allWarningsAsErrors = false 80 | // freeCompilerArgs = listOf("-XXLanguage:+InlineClasses", "-Xopt-in=kotlin.RequiresOptIn") 81 | jvmTarget = JavaVersion.VERSION_1_8.toString() 82 | } 83 | } 84 | } 85 | } 86 | 87 | java { 88 | targetCompatibility = JavaVersion.VERSION_1_8 89 | sourceCompatibility = JavaVersion.VERSION_1_8 90 | } 91 | 92 | tasks.test { 93 | useJUnitPlatform() 94 | testLogging { 95 | showStandardStreams = true 96 | showCauses = true 97 | showStackTraces = true 98 | events(*TestLogEvent.values()) 99 | exceptionFormat = TestExceptionFormat.FULL 100 | } 101 | } 102 | 103 | tasks.jacocoTestReport { 104 | reports { 105 | // Used by Codecov.io 106 | xml.isEnabled = true 107 | } 108 | } 109 | 110 | detekt { 111 | failFast = true 112 | buildUponDefaultConfig = true 113 | config = files("$projectDir/config/detekt.yml") 114 | reports { 115 | html.enabled = true 116 | xml.enabled = true 117 | txt.enabled = true 118 | } 119 | } 120 | 121 | pluginBundle { 122 | website = info.website 123 | vcsUrl = info.website 124 | tags = info.tags 125 | } 126 | 127 | gradlePlugin { 128 | plugins { 129 | create("NpmPublish") { 130 | id = "${rootProject.group}.${rootProject.name}" 131 | displayName = info.longName 132 | description = project.description 133 | implementationClass = info.pluginImplementationClass 134 | } 135 | } 136 | } 137 | 138 | val signingKey: String? by project 139 | val signingPassword: String? by project 140 | 141 | println( 142 | """ 143 | Signing Key: ${mask(signingKey)} 144 | Signing Passowrd: ${mask(signingPassword)} 145 | """.trimIndent() 146 | ) 147 | 148 | signing { 149 | useInMemoryPgpKeys(signingKey, signingPassword) 150 | } 151 | 152 | val mavenRepo: String by project 153 | val mavenUsername: String by project 154 | val mavenPassword: String by project 155 | 156 | println( 157 | """ 158 | Maven Repository: ${show(mavenRepo)} 159 | Maven Username: ${show(mavenUsername)} 160 | Maven Password: ${mask(mavenPassword)} 161 | """.trimIndent() 162 | ) 163 | 164 | publishing { 165 | repositories { 166 | maven(mavenRepo) { 167 | credentials { 168 | username = mavenUsername 169 | password = mavenPassword 170 | } 171 | } 172 | } 173 | publications { 174 | withType { 175 | val pubName = name 176 | pom { 177 | name.set(info.longName) 178 | description.set(project.description) 179 | packaging = "jar" 180 | url.set(info.website) 181 | if (pubName.contains("plugin", ignoreCase = true)) { 182 | licenses { 183 | license { 184 | name.set(info.license) 185 | url.set(info.licenseUrl) 186 | } 187 | } 188 | } 189 | scm { 190 | url.set(info.website) 191 | connection.set(info.scm) 192 | developerConnection.set(info.scm) 193 | } 194 | developers { 195 | developer { 196 | name.set("Giovanni Ciatto") 197 | email.set("giovanni.ciatto@gmail.com") 198 | url.set("https://about.me/gciatto") 199 | } 200 | } 201 | } 202 | } 203 | } 204 | } 205 | 206 | publishOnCentral { 207 | projectLongName = info.longName 208 | projectDescription = project.description ?: "No description provided" 209 | projectUrl = info.website 210 | scmConnection = info.scm 211 | licenseName = info.license 212 | licenseUrl = info.licenseUrl 213 | repository(mavenRepo) { 214 | user = mavenUsername 215 | password = mavenPassword 216 | } 217 | } 218 | 219 | nexusPublishing { 220 | repositories { 221 | sonatype { 222 | nexusUrl.set(uri(mavenRepo)) 223 | username.set(mavenUsername) 224 | password.set(mavenPassword) 225 | } 226 | } 227 | clientTimeout.set(Duration.ofMinutes(10)) 228 | } 229 | 230 | fun mask(string: String?): String = 231 | if (string.isNullOrBlank()) "" else "" 232 | 233 | fun show(string: String?): String = 234 | if (string.isNullOrBlank()) "" else string 235 | -------------------------------------------------------------------------------- /config/detekt.yml: -------------------------------------------------------------------------------- 1 | complexity: 2 | NestedBlockDepth: 3 | threshold: 5 4 | TooManyFunctions: 5 | ignorePrivate: true 6 | performance: 7 | SpreadOperator: 8 | active: false 9 | style: 10 | MagicNumber: 11 | ignoreNumbers: ["-1", "0", "1", "2", "3", "4", "10", "16", "32"] 12 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.console=plain 2 | systemProp.org.gradle.internal.http.connectionTimeout=180000 3 | systemProp.org.gradle.internal.http.socketTimeout=180000 4 | org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=2g 5 | 6 | #mavenRepo=https://oss.sonatype.org/service/local/staging/deploy/maven2/ 7 | mavenRepo=https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ 8 | mavenUsername= 9 | mavenPassword= 10 | 11 | signingKey= 12 | signingPassword= -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gciatto/kt-npm-publish/2db056208571d9b547dcdd223ceec812f81504c3/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | import de.fayard.dependencies.bootstrapRefreshVersionsAndDependencies 2 | import org.danilopianini.VersionAliases.justAdditionalAliases 3 | buildscript { 4 | repositories { 5 | gradlePluginPortal() 6 | mavenCentral() 7 | } 8 | dependencies { 9 | classpath("de.fayard:dependencies:0.+") 10 | classpath("org.danilopianini:refreshversions-aliases:0.+") 11 | } 12 | } 13 | bootstrapRefreshVersionsAndDependencies(justAdditionalAliases) 14 | rootProject.name = "kt-npm-publish" 15 | -------------------------------------------------------------------------------- /src/main/kotlin/io/github/gciatto/kt/node/AbstractNodeDefaultTask.kt: -------------------------------------------------------------------------------- 1 | package io.github.gciatto.kt.node 2 | 3 | import org.gradle.api.DefaultTask 4 | import org.gradle.api.provider.Property 5 | import org.gradle.api.tasks.Input 6 | import org.gradle.kotlin.dsl.property 7 | 8 | abstract class AbstractNodeDefaultTask : DefaultTask() { 9 | 10 | @Input 11 | protected val jsCompileTask: Property = project.objects.property() 12 | 13 | init { 14 | group = "nodeJs" 15 | dependsOn(jsCompileTask) 16 | } 17 | 18 | open fun defaultValuesFrom(extension: NpmPublishExtension) { 19 | jsCompileTask.set(extension.jsCompileTask) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/kotlin/io/github/gciatto/kt/node/AbstractNodeExecTask.kt: -------------------------------------------------------------------------------- 1 | package io.github.gciatto.kt.node 2 | 3 | import org.gradle.api.provider.Property 4 | import org.gradle.api.tasks.Exec 5 | import org.gradle.api.tasks.Input 6 | import org.gradle.api.tasks.TaskAction 7 | import org.gradle.kotlin.dsl.property 8 | import java.io.File 9 | 10 | abstract class AbstractNodeExecTask(requiresCompilation: Boolean = false) : Exec() { 11 | 12 | @Input 13 | protected val nodeSetupTask: Property = project.objects.property() 14 | 15 | @Input 16 | protected val jsCompileTask: Property = project.objects.property() 17 | 18 | @Input 19 | protected val node: Property = project.objects.property() 20 | 21 | @Input 22 | protected val npm: Property = project.objects.property() 23 | 24 | @Input 25 | protected val registry: Property = project.objects.property() 26 | 27 | init { 28 | group = "nodeJs" 29 | standardOutput = System.out 30 | errorOutput = System.err 31 | dependsOn(nodeSetupTask) 32 | if (requiresCompilation) { 33 | dependsOn(jsCompileTask) 34 | } 35 | } 36 | 37 | open fun defaultValuesFrom(extension: NpmPublishExtension) { 38 | nodeSetupTask.set(extension.nodeSetupTask) 39 | jsCompileTask.set(extension.jsCompileTask) 40 | node.set(extension.node) 41 | npm.set(extension.npm) 42 | registry.set(extension.registry) 43 | } 44 | 45 | @TaskAction 46 | override fun exec() { 47 | executable = node.get().absolutePath 48 | args(*setupArguments()) 49 | afterSetup() 50 | configSecurityWarning() 51 | super.exec() 52 | } 53 | 54 | protected abstract fun setupArguments(): Array 55 | 56 | protected open fun afterSetup() { 57 | println("Executing: ${commandLine.joinToString(" ")}") 58 | } 59 | 60 | private fun configSecurityWarning() { 61 | listOf(executable, args?.get(0)).forEach { 62 | if (it == null || !File(it).exists()) { 63 | System.err.println("[WARNING] [$path] Missing executable $it") 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/kotlin/io/github/gciatto/kt/node/Bugs.kt: -------------------------------------------------------------------------------- 1 | package io.github.gciatto.kt.node 2 | 3 | import com.google.gson.JsonElement 4 | import com.google.gson.JsonObject 5 | 6 | data class Bugs(var url: String? = null, var email: String? = null) { 7 | companion object { 8 | fun fromJson(element: JsonElement): Bugs = 9 | Bugs( 10 | element.getPropertyOrNull("url"), 11 | element.getPropertyOrNull("email") 12 | ) 13 | } 14 | 15 | fun toJson(): JsonObject { 16 | return JsonObject().also { obj -> 17 | url?.let { obj.addProperty("url", it) } 18 | email?.let { obj.addProperty("email", it) } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/kotlin/io/github/gciatto/kt/node/CopyRootProjectFilesTask.kt: -------------------------------------------------------------------------------- 1 | package io.github.gciatto.kt.node 2 | 3 | import org.gradle.api.provider.Property 4 | import org.gradle.api.tasks.Copy 5 | import org.gradle.api.tasks.Input 6 | import org.gradle.kotlin.dsl.property 7 | import java.io.File 8 | 9 | open class CopyRootProjectFilesTask : Copy() { 10 | 11 | @Input 12 | protected val jsCompileTask: Property = project.objects.property() 13 | 14 | @Input 15 | protected val packageJson: Property = project.objects.property() 16 | 17 | open fun defaultValuesFrom(extension: NpmPublishExtension) { 18 | jsCompileTask.set(extension.jsCompileTask) 19 | packageJson.set(extension.packageJson) 20 | } 21 | 22 | init { 23 | group = "nodeJs" 24 | dependsOn(jsCompileTask) 25 | inputs.files("README*", "CONTRIB*", "LICENSE*") 26 | outputs.files(packageJson) 27 | from(project.rootProject.projectDir) 28 | include("README*") 29 | include("CONTRIB*") 30 | include("LICENSE*") 31 | into(packageJson.map { it.parentFile }) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/kotlin/io/github/gciatto/kt/node/FileLineTransformer.kt: -------------------------------------------------------------------------------- 1 | package io.github.gciatto.kt.node 2 | 3 | import java.io.File 4 | 5 | typealias FileLineTransformer = (File, Int, String) -> String 6 | -------------------------------------------------------------------------------- /src/main/kotlin/io/github/gciatto/kt/node/JsonUtils.kt: -------------------------------------------------------------------------------- 1 | package io.github.gciatto.kt.node 2 | 3 | import com.google.gson.JsonArray 4 | import com.google.gson.JsonElement 5 | import com.google.gson.JsonObject 6 | import com.google.gson.JsonPrimitive 7 | 8 | fun String.toJson(): JsonPrimitive = JsonPrimitive(this) 9 | 10 | fun jsonArray(items: Iterable): JsonArray { 11 | val array = JsonArray() 12 | for (x in items) { 13 | array.add(x) 14 | } 15 | return array 16 | } 17 | 18 | fun jsonObject(vararg keys: Pair): JsonObject = 19 | jsonObject(mapOf(*keys)) 20 | 21 | fun jsonObject(keys: Map): JsonObject { 22 | val obj = JsonObject() 23 | for (kv in keys) { 24 | obj.addProperty(kv.key, kv.value) 25 | } 26 | return obj 27 | } 28 | 29 | fun JsonElement.getPropertyOrNull(key: String): String? { 30 | return getOrNull(key)?.asString 31 | } 32 | 33 | fun JsonElement.getOrNull(key: String): JsonElement? { 34 | if (this is JsonObject) { 35 | if (has(key)) { 36 | return get(key) 37 | } 38 | } 39 | return null 40 | } 41 | 42 | fun JsonElement.asPropertyMapOrNull(): MutableMap? { 43 | if (this is JsonObject) { 44 | return keySet().map { it to this@asPropertyMapOrNull[it].asString }.toMap(mutableMapOf()) 45 | } 46 | return null 47 | } 48 | 49 | fun JsonElement.asListOrNull(): MutableList? { 50 | if (this is JsonArray) { 51 | return this.map { it }.toMutableList() 52 | } 53 | return null 54 | } 55 | 56 | fun JsonElement.asPropertyListOrNull(): MutableList? { 57 | return asListOrNull()?.map { it.asString }?.toMutableList() 58 | } 59 | -------------------------------------------------------------------------------- /src/main/kotlin/io/github/gciatto/kt/node/LiftJsSourcesTask.kt: -------------------------------------------------------------------------------- 1 | package io.github.gciatto.kt.node 2 | 3 | import org.gradle.api.provider.Property 4 | import org.gradle.api.tasks.Input 5 | import org.gradle.api.tasks.TaskAction 6 | import org.gradle.internal.impldep.org.junit.experimental.categories.Categories.CategoryFilter.include 7 | import org.gradle.kotlin.dsl.listProperty 8 | import org.gradle.kotlin.dsl.property 9 | import java.io.BufferedWriter 10 | import java.io.File 11 | import java.io.OutputStreamWriter 12 | 13 | open class LiftJsSourcesTask : AbstractNodeDefaultTask() { 14 | 15 | @Input 16 | val liftingActions = project.objects.listProperty() 17 | 18 | @Input 19 | val jsSourcesDir: Property = project.objects.property() 20 | 21 | override fun defaultValuesFrom(extension: NpmPublishExtension) { 22 | super.defaultValuesFrom(extension) 23 | jsSourcesDir.set(extension.jsSourcesDir) 24 | liftingActions.set(extension.jsSourcesLiftingActions) 25 | } 26 | 27 | @TaskAction 28 | fun lift() { 29 | val jsSourcesDir = this.jsSourcesDir.get() 30 | if (!jsSourcesDir.exists() || !jsSourcesDir.isDirectory) { 31 | throw IllegalStateException("$jsSourcesDir is not a valid directory path") 32 | } 33 | for (file in project.fileTree(jsSourcesDir) { it.include("**/*.js") }) { 34 | val temp = temporaryDir.resolve("${file.nameWithoutExtension}-${file.hashCode()}.js") 35 | temp.createNewFile() 36 | BufferedWriter(OutputStreamWriter(temp.outputStream())).use { output -> 37 | file.useLines { 38 | for (indexedLine in it.withIndex()) { 39 | var line = indexedLine.value 40 | for (liftAction in liftingActions.getOrElse(emptyList())) { 41 | line = liftAction.invoke(file, indexedLine.index, line) 42 | } 43 | output.write(line) 44 | output.newLine() 45 | } 46 | } 47 | } 48 | file.delete() 49 | temp.renameTo(file) 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/kotlin/io/github/gciatto/kt/node/LiftPackageJsonTask.kt: -------------------------------------------------------------------------------- 1 | package io.github.gciatto.kt.node 2 | 3 | import com.google.gson.GsonBuilder 4 | import com.google.gson.JsonObject 5 | import org.gradle.api.Action 6 | import org.gradle.api.provider.Property 7 | import org.gradle.api.tasks.Input 8 | import org.gradle.api.tasks.TaskAction 9 | import org.gradle.kotlin.dsl.listProperty 10 | import org.gradle.kotlin.dsl.property 11 | import java.io.File 12 | import java.io.FileReader 13 | import java.io.FileWriter 14 | 15 | open class LiftPackageJsonTask : AbstractNodeDefaultTask() { 16 | 17 | private val gson = GsonBuilder().setPrettyPrinting().create() 18 | 19 | @Input 20 | protected val packageJsonFile: Property = project.objects.property() 21 | 22 | private var packageJson: PackageJson? = null 23 | 24 | private lateinit var packageJsonRaw: JsonObject 25 | 26 | private val liftingActions = project.objects.listProperty>() 27 | 28 | private val rawLiftingActions = project.objects.listProperty>() 29 | 30 | override fun defaultValuesFrom(extension: NpmPublishExtension) { 31 | super.defaultValuesFrom(extension) 32 | packageJsonFile.set(extension.packageJson) 33 | liftingActions.set(extension.packageJsonLiftingActions) 34 | rawLiftingActions.set(extension.packageJsonRawLiftingActions) 35 | } 36 | 37 | private lateinit var actualPackageJsonFile: File 38 | 39 | @TaskAction 40 | fun lift() { 41 | actualPackageJsonFile = packageJsonFile.get() 42 | if (!actualPackageJsonFile.exists()) { 43 | actualPackageJsonFile = actualPackageJsonFile.parentFile.resolve("pre-package.json") 44 | } 45 | if (!actualPackageJsonFile.exists()) { 46 | error("File ${packageJsonFile.get().path} does not exist") 47 | } 48 | resolve() 49 | performLifting() 50 | save() 51 | } 52 | 53 | private fun resolve() { 54 | packageJsonRaw = gson.fromJson(FileReader(actualPackageJsonFile), JsonObject::class.java) 55 | packageJson = try { 56 | PackageJson.fromJson(packageJsonRaw) 57 | } catch (_: Throwable) { 58 | System.err.println("Cannot parse $actualPackageJsonFile as a data class, use raw lifting") 59 | null 60 | } 61 | } 62 | 63 | private fun performLifting() { 64 | if (packageJson == null) { 65 | rawLiftingActions.getOrElse(emptyList()).forEach { it.execute(packageJsonRaw) } 66 | } else { 67 | liftingActions.getOrElse(emptyList()).forEach { it.execute(packageJson!!) } 68 | } 69 | } 70 | 71 | private fun save() { 72 | FileWriter(actualPackageJsonFile.parentFile.resolve("package.json")).use { 73 | gson.toJson(packageJson?.toJson() ?: packageJsonRaw, it) 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/kotlin/io/github/gciatto/kt/node/NpmPublishExtension.kt: -------------------------------------------------------------------------------- 1 | package io.github.gciatto.kt.node 2 | 3 | import com.google.gson.JsonObject 4 | import org.gradle.api.Action 5 | import org.gradle.api.Project 6 | import org.gradle.api.model.ObjectFactory 7 | import org.gradle.api.provider.Property 8 | import org.gradle.api.provider.Provider 9 | import org.gradle.api.provider.ProviderFactory 10 | import org.gradle.api.tasks.TaskCollection 11 | import org.gradle.kotlin.dsl.listProperty 12 | import org.gradle.kotlin.dsl.property 13 | import org.gradle.kotlin.dsl.withType 14 | import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsSetupTask 15 | import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinPackageJsonTask 16 | import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile 17 | import java.io.File 18 | 19 | open class NpmPublishExtension(objects: ObjectFactory, private val providers: ProviderFactory) { 20 | 21 | companion object { 22 | 23 | const val NAME = "npmPublishing" 24 | 25 | private val isWindows: Boolean 26 | get() = File.separatorChar == '\\' 27 | 28 | private const val npmScriptSubpath = "node_modules/npm/bin/npm-cli.js" 29 | 30 | private val possibleNodePaths: Sequence = 31 | sequenceOf("bin/node", "node").let { paths -> 32 | if (isWindows) { 33 | paths.map { "$it.exe" } + paths 34 | } else { 35 | paths 36 | } 37 | } 38 | 39 | private val possibleNpmPaths: Sequence = 40 | sequenceOf("lib/", "").map { it + npmScriptSubpath } 41 | } 42 | 43 | var verbose = false 44 | 45 | private val nodeRoot: Property = objects.property() 46 | 47 | val nodeSetupTask: Property = objects.property() 48 | 49 | val jsCompileTask: Property = objects.property() 50 | 51 | val packageJson: Property = objects.property() 52 | 53 | val token: Property = objects.property() 54 | 55 | val registry: Property = objects.property(String::class.java).also { 56 | it.set("registry.npmjs.org") 57 | } 58 | 59 | val node: Provider = nodeRoot.map { nodeRoot -> 60 | possibleNodePaths.map { nodeRoot.resolve(it) }.first { it.exists() } 61 | } 62 | 63 | val npm: Provider = nodeRoot.map { nodeRoot -> 64 | possibleNpmPaths.map { nodeRoot.resolve(it) }.first { it.exists() } 65 | } 66 | 67 | val npmProject: Provider = packageJson.map { it.parentFile } 68 | 69 | val jsSourcesDir: Property = objects.property(File::class.java).also { 70 | File("build/") 71 | } 72 | 73 | internal val packageJsonLiftingActions = objects.listProperty>() 74 | 75 | internal val packageJsonRawLiftingActions = objects.listProperty>() 76 | 77 | internal val jsSourcesLiftingActions = objects.listProperty() 78 | 79 | fun liftPackageJson(action: Action) { 80 | with(packageJsonLiftingActions) { 81 | add(action) 82 | } 83 | } 84 | 85 | fun liftPackageJsonRaw(action: Action) { 86 | with(packageJsonRawLiftingActions) { 87 | add(action) 88 | } 89 | } 90 | 91 | fun liftJsSources(lineTransformer: FileLineTransformer) { 92 | with(jsSourcesLiftingActions) { 93 | add(lineTransformer) 94 | } 95 | } 96 | 97 | internal fun warn(project: Project, message: () -> String) { 98 | if (verbose) { 99 | println("[WARNING] [${project.name}] [$NAME]: ${message()}") 100 | } 101 | } 102 | 103 | internal fun log(project: Project, message: () -> String) { 104 | if (verbose) { 105 | println("[${project.name}] [$NAME]: ${message()}") 106 | } 107 | } 108 | 109 | private val Project.nodeJsSetupTasks: TaskCollection 110 | get() = rootProject.tasks.withType() 111 | 112 | private fun defaultNodeRootValueFrom(project: Project) { 113 | project.nodeJsSetupTasks.all { nodeJsSetupTask -> 114 | nodeRoot.set( 115 | providers.provider { 116 | nodeJsSetupTask.destination.also { 117 | log(project) { 118 | "Inferred ${NpmPublishExtension::nodeRoot.name} from task ${nodeJsSetupTask.path}: $it" 119 | } 120 | } 121 | } 122 | ) 123 | } 124 | } 125 | 126 | private fun defaultNodeSetupTaskValueFrom(project: Project) { 127 | project.nodeJsSetupTasks.all { nodeJsSetupTask -> 128 | nodeSetupTask.set( 129 | providers.provider { 130 | nodeJsSetupTask.path.also { 131 | log(project) { 132 | "Inferred ${NpmPublishExtension::nodeSetupTask.name}: ${nodeJsSetupTask.path}" 133 | } 134 | } 135 | } 136 | ) 137 | } 138 | } 139 | 140 | private fun defaultPackageJsonValueFrom(project: Project) { 141 | project.tasks.withType() 142 | .matching { !it.name.contains("test", ignoreCase = true) } 143 | .all { packageJsonTask -> 144 | packageJson.set( 145 | providers.provider { 146 | try { 147 | packageJsonTask.packageJson.parentFile.resolve("package.json").also { 148 | log(project) { 149 | "Inferred ${NpmPublishExtension::packageJson.name} " + 150 | "from task ${packageJsonTask.path}: $it" 151 | } 152 | } 153 | } catch (_: UninitializedPropertyAccessException) { 154 | warn(project) { 155 | "Cannot infer ${NpmPublishExtension::packageJson.name} " + 156 | "from task ${packageJsonTask.path}" 157 | } 158 | null 159 | } 160 | } 161 | ) 162 | } 163 | } 164 | 165 | private val Project.mainKotlin2JsCompileTasks: TaskCollection 166 | get() = tasks.withType().matching { !it.name.contains("test", ignoreCase = true) } 167 | 168 | private fun defaultJsCompileTaskValueFrom(project: Project) { 169 | project.mainKotlin2JsCompileTasks.all { kt2JsCompileTask -> 170 | jsCompileTask.set( 171 | providers.provider { 172 | kt2JsCompileTask.path.also { 173 | log(project) { "Inferred ${NpmPublishExtension::jsCompileTask.name}: $it" } 174 | } 175 | } 176 | ) 177 | } 178 | } 179 | 180 | private fun defaultJsSourcesDirValueFrom(project: Project) { 181 | project.mainKotlin2JsCompileTasks.all { kt2JsCompileTask -> 182 | jsSourcesDir.set( 183 | providers.provider { 184 | kt2JsCompileTask.outputFile.parentFile.also { 185 | log(project) { 186 | "Inferred ${NpmPublishExtension::jsSourcesDir.name} " + 187 | "from task ${kt2JsCompileTask.path}: ${kt2JsCompileTask.outputFile.parentFile}" 188 | } 189 | } 190 | } 191 | ) 192 | } 193 | } 194 | 195 | fun defaultValuesFrom(project: Project) { 196 | defaultNodeRootValueFrom(project) 197 | defaultNodeSetupTaskValueFrom(project) 198 | defaultPackageJsonValueFrom(project) 199 | defaultJsCompileTaskValueFrom(project) 200 | defaultJsSourcesDirValueFrom(project) 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /src/main/kotlin/io/github/gciatto/kt/node/NpmPublishPlugin.kt: -------------------------------------------------------------------------------- 1 | package io.github.gciatto.kt.node 2 | 3 | import org.gradle.api.DefaultTask 4 | import org.gradle.api.Plugin 5 | import org.gradle.api.Project 6 | import org.gradle.api.Task 7 | import org.gradle.api.tasks.Exec 8 | import org.jetbrains.kotlin.gradle.targets.js.npm.PublicPackageJsonTask 9 | 10 | class NpmPublishPlugin : Plugin { 11 | 12 | private lateinit var extension: NpmPublishExtension 13 | 14 | private fun Project.createNpmLoginTask(name: String): DefaultTask { 15 | val setRegistryName = "${name}SetRegistry" 16 | val setRegistry = rootProject.tasks.maybeCreate(setRegistryName, SetRegistryTask::class.java).also { 17 | it.defaultValuesFrom(extension) 18 | } 19 | val setToken = rootProject.tasks.maybeCreate("${name}SetToken", SetTokenTask::class.java).also { 20 | it.defaultValuesFrom(extension) 21 | } 22 | setToken.dependsOn(setRegistry) 23 | return rootProject.tasks.maybeCreate(name, DefaultTask::class.java).also { 24 | it.group = "nodeJs" 25 | it.dependsOn(setRegistry) 26 | it.dependsOn(setToken) 27 | } 28 | } 29 | 30 | private fun Project.createNpmPublishTask(name: String): Exec { 31 | return tasks.maybeCreate(name, NpmPublishTask::class.java).also { 32 | it.defaultValuesFrom(extension) 33 | } 34 | } 35 | 36 | private fun Project.createCopyRootProjectFilesTask(name: String): Task { 37 | return tasks.maybeCreate(name, CopyRootProjectFilesTask::class.java).also { 38 | it.defaultValuesFrom(extension) 39 | } 40 | } 41 | 42 | private fun Project.createLiftJsSourceTask(name: String): DefaultTask { 43 | return tasks.maybeCreate(name, LiftJsSourcesTask::class.java).also { 44 | it.defaultValuesFrom(extension) 45 | } 46 | } 47 | 48 | private fun Project.createLiftPackageJsonTask(name: String): LiftPackageJsonTask { 49 | return tasks.maybeCreate(name, LiftPackageJsonTask::class.java).also { liftTask -> 50 | liftTask.defaultValuesFrom(extension) 51 | tasks.withType(PublicPackageJsonTask::class.java).matching { 52 | it.name.contains("test", ignoreCase = true).not() 53 | }.all { 54 | liftTask.dependsOn(it) 55 | extension.log(this) { 56 | "Found task ${it.path}: ${liftTask.path} will depend on it" 57 | } 58 | } 59 | } 60 | } 61 | 62 | override fun apply(target: Project) { 63 | extension = target.extensions.create(NpmPublishExtension.NAME, NpmPublishExtension::class.java) 64 | extension.verbose = target.findProperty(VERBOSE_PROPERTY)?.toString().toBoolean() 65 | extension.defaultValuesFrom(target) 66 | val login = target.createNpmLoginTask("npmLogin") 67 | val publish = target.createNpmPublishTask("npmPublish") 68 | val liftPackageJson = target.createLiftPackageJsonTask("liftPackageJson") 69 | val copy = target.createCopyRootProjectFilesTask("copyFilesNextToPackageJson") 70 | val liftJsSourcesTask = target.createLiftJsSourceTask("liftJsSources") 71 | publish.dependsOn(login) 72 | publish.dependsOn(liftPackageJson) 73 | publish.dependsOn(liftJsSourcesTask) 74 | liftPackageJson.dependsOn(copy) 75 | } 76 | 77 | companion object { 78 | const val VERBOSE_PROPERTY: String = "io.github.gciatto.kt-npm-publish.verbose" 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/kotlin/io/github/gciatto/kt/node/NpmPublishTask.kt: -------------------------------------------------------------------------------- 1 | package io.github.gciatto.kt.node 2 | 3 | import org.gradle.api.provider.Property 4 | import org.gradle.api.tasks.Input 5 | import org.gradle.kotlin.dsl.property 6 | import java.io.File 7 | 8 | open class NpmPublishTask : AbstractNodeExecTask(requiresCompilation = true) { 9 | override fun setupArguments(): Array { 10 | return arrayOf( 11 | npm.get().absolutePath, 12 | "publish", 13 | npmProject.get().absolutePath, 14 | "--access", 15 | "public" 16 | ) 17 | } 18 | 19 | @Input 20 | protected val npmProject: Property = project.objects.property() 21 | 22 | override fun defaultValuesFrom(extension: NpmPublishExtension) { 23 | super.defaultValuesFrom(extension) 24 | npmProject.set(extension.npmProject) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/kotlin/io/github/gciatto/kt/node/PackageJson.kt: -------------------------------------------------------------------------------- 1 | package io.github.gciatto.kt.node 2 | 3 | import com.google.gson.JsonElement 4 | import com.google.gson.JsonObject 5 | 6 | data class PackageJson( 7 | var name: String? = null, 8 | var main: String? = null, 9 | var version: String? = null, 10 | var dependencies: MutableMap? = null, 11 | var devDependencies: MutableMap? = null, 12 | var peerDependencies: MutableMap? = null, 13 | var homepage: String? = null, 14 | var bugs: Bugs? = null, 15 | var keywords: MutableList? = null, 16 | var people: MutableList? = null, 17 | var license: String? = null, 18 | var files: MutableList? = null, 19 | var bin: String? = null, 20 | var bins: MutableMap? = null 21 | ) { 22 | companion object { 23 | fun fromJson(element: JsonElement): PackageJson = 24 | PackageJson( 25 | name = element.getPropertyOrNull("name"), 26 | main = element.getPropertyOrNull("main"), 27 | version = element.getPropertyOrNull("version"), 28 | homepage = element.getPropertyOrNull("homepage"), 29 | bugs = element.getOrNull("bugs")?.let { Bugs.fromJson(it) }, 30 | license = element.getPropertyOrNull("license"), 31 | bin = element.getOrNull("bin")?.let { if (it.isJsonPrimitive) it.asString else null }, 32 | bins = element.getOrNull("bin")?.asPropertyMapOrNull(), 33 | dependencies = element.getOrNull("dependencies")?.asPropertyMapOrNull(), 34 | devDependencies = element.getOrNull("devDependencies")?.asPropertyMapOrNull(), 35 | peerDependencies = element.getOrNull("peerDependencies")?.asPropertyMapOrNull(), 36 | keywords = element.getOrNull("keywords")?.asPropertyListOrNull(), 37 | files = element.getOrNull("files")?.asPropertyListOrNull(), 38 | people = element.getOrNull("people")?.asListOrNull() 39 | ?.map { People.fromJson(it) }?.toMutableList() 40 | ) 41 | } 42 | 43 | fun toJson(): JsonObject { 44 | return JsonObject().also { 45 | it.addSimpleProperties() 46 | it.addComplexProperties() 47 | } 48 | } 49 | 50 | private fun JsonObject.addSimpleProperties() { 51 | name?.let { addProperty("name", it) } 52 | main?.let { addProperty("main", it) } 53 | version?.let { addProperty("version", it) } 54 | homepage?.let { addProperty("homepage", it) } 55 | license?.let { addProperty("license", it) } 56 | bugs?.let { add("bugs", it.toJson()) } 57 | bin?.let { addProperty("bin", it) } 58 | } 59 | 60 | private fun JsonObject.addComplexProperties() { 61 | keywords?.let { add("keywords", jsonArray(it.map(String::toJson))) } 62 | files?.let { add("files", jsonArray(it.map(String::toJson))) } 63 | people?.let { add("people", jsonArray(it.map(People::toJson))) } 64 | dependencies?.let { add("dependencies", jsonObject(it)) } 65 | devDependencies?.let { add("devDependencies", jsonObject(it)) } 66 | peerDependencies?.let { add("peerDependencies", jsonObject(it)) } 67 | bins?.let { add("bin", jsonObject(it)) } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/kotlin/io/github/gciatto/kt/node/People.kt: -------------------------------------------------------------------------------- 1 | package io.github.gciatto.kt.node 2 | 3 | import com.google.gson.JsonElement 4 | import com.google.gson.JsonObject 5 | 6 | data class People(var name: String? = null, var email: String? = null, var url: String? = null) { 7 | companion object { 8 | fun fromJson(element: JsonElement): People = 9 | People( 10 | element.getPropertyOrNull("name"), 11 | element.getPropertyOrNull("email"), 12 | element.getPropertyOrNull("url") 13 | ) 14 | } 15 | 16 | fun toJson(): JsonObject { 17 | return JsonObject().also { obj -> 18 | name?.let { obj.addProperty("name", it) } 19 | email?.let { obj.addProperty("email", it) } 20 | url?.let { obj.addProperty("url", it) } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/kotlin/io/github/gciatto/kt/node/SetRegistryTask.kt: -------------------------------------------------------------------------------- 1 | package io.github.gciatto.kt.node 2 | 3 | open class SetRegistryTask : AbstractNodeExecTask() { 4 | override fun setupArguments(): Array { 5 | return arrayOf( 6 | npm.get().absolutePath, 7 | "set", 8 | "registry", 9 | "https://${registry.get()}/" 10 | ) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/kotlin/io/github/gciatto/kt/node/SetTokenTask.kt: -------------------------------------------------------------------------------- 1 | package io.github.gciatto.kt.node 2 | 3 | import org.gradle.api.provider.Property 4 | import org.gradle.api.tasks.Input 5 | import org.gradle.kotlin.dsl.property 6 | 7 | open class SetTokenTask : AbstractNodeExecTask() { 8 | override fun setupArguments(): Array { 9 | return arrayOf( 10 | npm.get().absolutePath, 11 | "set", 12 | "//${registry.get()}/:_authToken", 13 | token.get() 14 | ) 15 | } 16 | 17 | @Input 18 | protected val token: Property = project.objects.property() 19 | 20 | override fun afterSetup() { 21 | println("Executing: ${commandLine.subList(0, commandLine.lastIndex).joinToString()} ") 22 | } 23 | 24 | override fun defaultValuesFrom(extension: NpmPublishExtension) { 25 | super.defaultValuesFrom(extension) 26 | token.set(extension.token) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/kotlin/io/github/gciatto/kt/node/test/TestingDSL.kt: -------------------------------------------------------------------------------- 1 | package io.github.gciatto.kt.node.test 2 | 3 | import com.uchuhimo.konf.ConfigSpec 4 | import java.io.File 5 | 6 | object Root : ConfigSpec("") { 7 | val tests by required>() 8 | } 9 | 10 | data class Test( 11 | val description: String, 12 | val configuration: Configuration, 13 | val expectation: Expectation 14 | ) 15 | 16 | data class Configuration(val tasks: List, val options: List = emptyList()) 17 | 18 | data class Expectation( 19 | val file_exists: List = emptyList(), 20 | val success: List = emptyList(), 21 | val failure: List = emptyList(), 22 | val output_contains: List = emptyList(), 23 | val output_matches: List = emptyList() 24 | ) 25 | 26 | data class ExistingFile(val name: String, val contents: List = emptyList(), val all: Boolean = true) { 27 | private val regexes by lazy { contents.map { Regex(it) } } 28 | private fun Sequence.matches(): Boolean = if (all) all { it } else any { it } 29 | fun isValid(root: File): Boolean { 30 | val actualFile = actualFile(root) 31 | val lines = actualFile.readLines() 32 | return regexes.asSequence().map { regex -> lines.any { regex.containsMatchIn(it) } }.matches() 33 | } 34 | 35 | val file: File get() = File(name) 36 | fun actualFile(root: File) = file.let { if (it.isAbsolute) it else root.resolve(it) } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/kotlin/io/github/gciatto/kt/node/test/Tests.kt: -------------------------------------------------------------------------------- 1 | package io.github.gciatto.kt.node.test 2 | 3 | import com.uchuhimo.konf.Config 4 | import com.uchuhimo.konf.source.yaml 5 | import io.github.classgraph.ClassGraph 6 | import io.kotest.core.spec.style.StringSpec 7 | import io.kotest.matchers.file.shouldBeAFile 8 | import io.kotest.matchers.file.shouldExist 9 | import io.kotest.matchers.shouldBe 10 | import io.kotest.matchers.string.shouldContain 11 | import org.gradle.internal.impldep.org.junit.rules.TemporaryFolder 12 | import org.gradle.testkit.runner.BuildResult 13 | import org.gradle.testkit.runner.GradleRunner 14 | import org.gradle.testkit.runner.TaskOutcome 15 | import org.slf4j.LoggerFactory 16 | import java.io.File 17 | 18 | class Tests : StringSpec({ 19 | // val pluginClasspathResource = ClassLoader.getSystemClassLoader() 20 | // .getResource("plugin-classpath.txt") 21 | // ?: throw IllegalStateException("Did not find plugin classpath resource, run \"testClasses\" build task.") 22 | // val classpath = pluginClasspathResource.openStream().bufferedReader().use { reader -> 23 | // reader.readLines().map { File(it) } 24 | // } 25 | val scan = ClassGraph() 26 | .enableAllInfo() 27 | .acceptPackages(Tests::class.java.`package`.name) 28 | .scan() 29 | scan.getResourcesWithLeafName("test.yaml") 30 | .flatMap { 31 | log.debug("Found test list in $it") 32 | val yamlFile = File(it.classpathElementFile.absolutePath + "/" + it.path) 33 | val testConfiguration = Config { 34 | addSpec(Root) 35 | }.from.yaml.inputStream(it.open()) 36 | testConfiguration[Root.tests].map { it to yamlFile.parentFile } 37 | }.forEach { (test, location) -> 38 | log.debug("Test to be executed: $test from $location") 39 | val testFolder = folder { 40 | location.copyRecursively(this.root) 41 | } 42 | log.debug("Test has been copied into $testFolder and is ready to get executed") 43 | test.description { 44 | val runner = GradleRunner.create() 45 | .withProjectDir(testFolder.root) 46 | .withPluginClasspath() 47 | // .also { println("Plugin Classpath:\n\t" + it.pluginClasspath.joinToString("\n\t")) } 48 | // .withPluginClasspath(classpath) 49 | .withDebug(true) 50 | .withArguments(test.configuration.tasks + test.configuration.options) 51 | val result = if (test.expectation.failure.isEmpty()) { 52 | runner.build() 53 | } else { 54 | runner.buildAndFail() 55 | } 56 | println(result.tasks) 57 | println(result.output) 58 | test.expectation.output_contains.forEach { 59 | result.output shouldContain it 60 | } 61 | test.expectation.output_matches.forEach { regexString -> 62 | val regex = Regex(regexString) 63 | result.output.lineSequence().anyShouldMatch(regex) 64 | } 65 | test.expectation.success.forEach { 66 | result.outcomeOf(it) shouldBe TaskOutcome.SUCCESS 67 | } 68 | test.expectation.failure.forEach { 69 | result.outcomeOf(it) shouldBe TaskOutcome.FAILED 70 | } 71 | test.expectation.file_exists.forEach { 72 | val file = it.actualFile(testFolder.root) 73 | file.shouldExist() 74 | file.shouldBeAFile() 75 | it.shouldBeValidWrt(testFolder.root) 76 | } 77 | } 78 | } 79 | }) { 80 | companion object { 81 | val log = LoggerFactory.getLogger(Tests::class.java) 82 | 83 | private fun BuildResult.outcomeOf(name: String) = task(":$name") 84 | ?.outcome 85 | ?: throw IllegalStateException("Task $name was not present among the executed tasks") 86 | 87 | private fun folder(closure: TemporaryFolder.() -> Unit) = TemporaryFolder().apply { 88 | create() 89 | closure() 90 | } 91 | 92 | private fun Sequence.anyShouldMatch(regex: Regex) { 93 | if (!any { regex.matches(it) }) { 94 | throw AssertionError("No line matches: ${regex.pattern}") 95 | } 96 | } 97 | 98 | private fun ExistingFile.shouldBeValidWrt(root: File) { 99 | if (!this.isValid(root)) { 100 | throw AssertionError( 101 | "File ${file.resolve(root)} should exist and contain " + 102 | (if (all) "all of" else "any of") + 103 | " the following lines: " + 104 | contents.joinToString { "`$it`" } 105 | ) 106 | } 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/test/resources/io/github/gciatto/kt/node/test/js/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gciatto/kt-npm-publish/2db056208571d9b547dcdd223ceec812f81504c3/src/test/resources/io/github/gciatto/kt/node/test/js/README.md -------------------------------------------------------------------------------- /src/test/resources/io/github/gciatto/kt/node/test/js/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "org.jetbrains.kotlin.js" version '1.4.20' 3 | id "io.github.gciatto.kt-npm-publish" 4 | } 5 | 6 | group 'org.example' 7 | version '1.0.0' 8 | 9 | repositories { 10 | mavenCentral() 11 | } 12 | 13 | dependencies { 14 | implementation "org.jetbrains.kotlin:kotlin-stdlib-js" 15 | testImplementation "org.jetbrains.kotlin:kotlin-test-js" 16 | } 17 | 18 | kotlin { 19 | js { 20 | nodejs () 21 | binaries.executable() 22 | } 23 | } 24 | 25 | npmPublishing { 26 | token.set("fake_token") 27 | 28 | liftPackageJson { 29 | version = '1.2.3' 30 | name = "@organization/$name" 31 | dependencies = dependencies.collectEntries { name, version -> 32 | if (version.startsWith("file:")) { 33 | [name, version.split('/').last()] 34 | } else { 35 | [name, version] 36 | } 37 | } 38 | } 39 | 40 | liftJsSources { file, i, line -> 41 | line.replace("'test-js", "'@organization/test-js") 42 | .replace("\"test-js", "\"@organization/test-js") 43 | } 44 | } -------------------------------------------------------------------------------- /src/test/resources/io/github/gciatto/kt/node/test/js/gradle.properties: -------------------------------------------------------------------------------- 1 | io.github.gciatto.kt-npm-publish.verbose=true -------------------------------------------------------------------------------- /src/test/resources/io/github/gciatto/kt/node/test/js/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = "test-js" -------------------------------------------------------------------------------- /src/test/resources/io/github/gciatto/kt/node/test/js/src/main/kotlin/Hello.kt: -------------------------------------------------------------------------------- 1 | fun hello() { 2 | println("hello") 3 | } -------------------------------------------------------------------------------- /src/test/resources/io/github/gciatto/kt/node/test/js/test.yaml: -------------------------------------------------------------------------------- 1 | tests: 2 | - description: "Kt-Js projects importing and configuring kt-npm-publish should be endowed with a number of tasks" 3 | configuration: 4 | tasks: tasks 5 | expectation: 6 | output_contains: 7 | - copyFilesNextToPackageJson 8 | - npmPublish 9 | - npmLogin 10 | - npmLoginSetRegistry 11 | - npmLoginSetToken 12 | - liftPackageJson 13 | - liftJsSources 14 | success: tasks 15 | 16 | - description: "Kt-Js projects importing kt-npm-publish should support npmLogin by only setting up the `token` property" 17 | configuration: 18 | tasks: npmLogin 19 | expectation: 20 | output_matches: 21 | - &inferred_nodeSetupTask 22 | "\\[test-js\\] \\[npmPublishing\\]: Inferred nodeSetupTask: :kotlinNodeJsSetup" 23 | - &inferred_jsCompileTask 24 | "\\[test-js\\] \\[npmPublishing\\]: Inferred jsCompileTask: :compileKotlinJs" 25 | - &inferred_nodeRoot 26 | "\\[test-js\\] \\[npmPublishing\\]: Inferred nodeRoot from task :kotlinNodeJsSetup: .*?/nodejs/node-v\\d+.\\d+.\\d+-[^\\s]+" 27 | success: npmLogin 28 | 29 | - description: "Kt-Js projects support compilation as an NPM project" 30 | configuration: 31 | tasks: compileKotlinJs 32 | expectation: 33 | success: compileKotlinJs 34 | file_exists: 35 | - name: &file_package_json 36 | "build/js/packages/test-js/package.json" 37 | contents: 38 | - '"version": "1\.0\.0"' 39 | - '"main": "kotlin/test-js\.js"' 40 | - '"name": "test-js"' 41 | - '"kotlin": "file:.*?/1.\d+.\d+"' 42 | - name: &file_generated_js 43 | "build/js/packages/test-js/kotlin/test-js.js" 44 | contents: 45 | - "this\\['test-js'\\]" 46 | - "require\\('kotlin'\\)" 47 | 48 | - description: "Kt-Js projects importing and configuring kt-npm-publish support lifting of generated package.json files" 49 | configuration: 50 | tasks: liftPackageJson 51 | expectation: 52 | output_matches: 53 | - &inferred_packageJson 54 | "\\[test-js\\] \\[npmPublishing\\]: Inferred packageJson from task :packageJson: .*?/build/js/packages/test-js/package.json" 55 | - *inferred_jsCompileTask 56 | success: liftPackageJson 57 | file_exists: 58 | - name: *file_package_json 59 | contents: 60 | - '"version": "1\.2\.3"' 61 | - '"main": "kotlin/test-js\.js"' 62 | - '"name": "@organization/test-js"' 63 | - '"kotlin": "1.\d+.\d+"' 64 | 65 | - description: "Kt-Js projects importing and configuring kt-npm-publish support lifting of generated .js files" 66 | configuration: 67 | tasks: liftJsSources 68 | expectation: 69 | output_matches: 70 | - *inferred_jsCompileTask 71 | - &inferred_jsSourcesDir 72 | "\\[test-js\\] \\[npmPublishing\\]: Inferred jsSourcesDir from task :compileKotlinJs: .*?/build/js/packages/test-js/kotlin" 73 | success: liftJsSources 74 | file_exists: 75 | - name: *file_generated_js 76 | contents: 77 | - "this\\['@organization/test-js'\\]" 78 | - "require\\('kotlin'\\)" 79 | 80 | - description: "Kt-Js projects importing and configuring kt-npm-publish support copying project files close to package.json" 81 | configuration: 82 | tasks: copyFilesNextToPackageJson 83 | expectation: 84 | output_matches: 85 | - *inferred_packageJson 86 | - *inferred_jsCompileTask 87 | success: copyFilesNextToPackageJson 88 | file_exists: 89 | - name: "build/js/packages/test-js/README.md" 90 | 91 | - description: "Kt-Js projects importing and configuring kt-npm-publish support publishing of JS projects on NPM" 92 | configuration: 93 | tasks: npmPublish 94 | expectation: 95 | output_matches: 96 | - *inferred_jsCompileTask 97 | - *inferred_jsSourcesDir 98 | - *inferred_packageJson 99 | - *inferred_nodeRoot 100 | - *inferred_nodeSetupTask 101 | output_contains: 102 | - 'npm ERR! 404 Not Found - PUT https://registry.npmjs.org/@organization%2ftest-js - Not found' 103 | failure: npmPublish 104 | -------------------------------------------------------------------------------- /src/test/resources/io/github/gciatto/kt/node/test/kt/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'org.jetbrains.kotlin.js' version '1.4.20' 3 | } 4 | 5 | group 'org.example' 6 | version '1.0-SNAPSHOT' 7 | 8 | repositories { 9 | mavenCentral() 10 | } 11 | 12 | dependencies { 13 | implementation "org.jetbrains.kotlin:kotlin-stdlib-js" 14 | testImplementation "org.jetbrains.kotlin:kotlin-test-js" 15 | } 16 | 17 | kotlin { 18 | js { 19 | nodejs { } 20 | binaries.executable() 21 | } 22 | } -------------------------------------------------------------------------------- /src/test/resources/io/github/gciatto/kt/node/test/kt/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = "test-kt" -------------------------------------------------------------------------------- /src/test/resources/io/github/gciatto/kt/node/test/kt/test.yaml: -------------------------------------------------------------------------------- 1 | tests: 2 | - description: "Kt projects work" 3 | configuration: 4 | tasks: help 5 | expectation: 6 | success: help -------------------------------------------------------------------------------- /src/test/resources/io/github/gciatto/kt/node/test/mpp/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gciatto/kt-npm-publish/2db056208571d9b547dcdd223ceec812f81504c3/src/test/resources/io/github/gciatto/kt/node/test/mpp/README.md -------------------------------------------------------------------------------- /src/test/resources/io/github/gciatto/kt/node/test/mpp/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'org.jetbrains.kotlin.multiplatform' version '1.4.20' 3 | id "io.github.gciatto.kt-npm-publish" 4 | } 5 | 6 | group 'org.example' 7 | version '1.0.0' 8 | 9 | repositories { 10 | mavenCentral() 11 | } 12 | 13 | kotlin { 14 | /* Targets configuration omitted. 15 | * To find out how to configure the targets, please follow the link: 16 | * https://kotlinlang.org/docs/reference/building-mpp-with-gradle.html#setting-up-targets */ 17 | jvm() 18 | 19 | js { 20 | nodejs() 21 | } 22 | 23 | sourceSets { 24 | commonMain { 25 | dependencies { 26 | implementation kotlin('stdlib-common') 27 | } 28 | } 29 | commonTest { 30 | dependencies { 31 | implementation kotlin('test-common') 32 | implementation kotlin('test-annotations-common') 33 | } 34 | } 35 | } 36 | } 37 | 38 | npmPublishing { 39 | token.set("fake_token") 40 | 41 | liftPackageJson { 42 | version = '1.2.3' 43 | name = "@organization/$name" 44 | dependencies = dependencies.collectEntries { name, version -> 45 | if (version.startsWith("file:")) { 46 | [name, version.split('/').last()] 47 | } else { 48 | [name, version] 49 | } 50 | } 51 | } 52 | 53 | liftJsSources { file, i, line -> 54 | line.replace("'test-mpp", "'@organization/test-mpp") 55 | .replace("\"test-mpp", "\"@organization/test-mpp") 56 | } 57 | } -------------------------------------------------------------------------------- /src/test/resources/io/github/gciatto/kt/node/test/mpp/gradle.properties: -------------------------------------------------------------------------------- 1 | io.github.gciatto.kt-npm-publish.verbose=true -------------------------------------------------------------------------------- /src/test/resources/io/github/gciatto/kt/node/test/mpp/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = "test-mpp" -------------------------------------------------------------------------------- /src/test/resources/io/github/gciatto/kt/node/test/mpp/src/commonMain/kotlin/Hello.kt: -------------------------------------------------------------------------------- 1 | fun hello() { 2 | println("hello") 3 | } -------------------------------------------------------------------------------- /src/test/resources/io/github/gciatto/kt/node/test/mpp/test.yaml: -------------------------------------------------------------------------------- 1 | tests: 2 | - description: "Kt-MPP projects importing and configuring kt-npm-publish should be endowed with a number of tasks" 3 | configuration: 4 | tasks: tasks 5 | expectation: 6 | output_contains: 7 | - copyFilesNextToPackageJson 8 | - npmPublish 9 | - npmLogin 10 | - npmLoginSetRegistry 11 | - npmLoginSetToken 12 | - liftPackageJson 13 | - liftJsSources 14 | success: tasks 15 | 16 | - description: "Kt-MPP projects importing kt-npm-publish should support npmLogin by only setting up the `token` property" 17 | configuration: 18 | tasks: npmLogin 19 | expectation: 20 | output_matches: 21 | - &inferred_nodeSetupTask 22 | "\\[test-mpp\\] \\[npmPublishing\\]: Inferred nodeSetupTask: :kotlinNodeJsSetup" 23 | - &inferred_jsCompileTask 24 | "\\[test-mpp\\] \\[npmPublishing\\]: Inferred jsCompileTask: :compileKotlinJs" 25 | - &inferred_nodeRoot 26 | "\\[test-mpp\\] \\[npmPublishing\\]: Inferred nodeRoot from task :kotlinNodeJsSetup: .*?/nodejs/node-v\\d+.\\d+.\\d+-[^\\s]+" 27 | success: npmLogin 28 | 29 | - description: "Kt-MPP projects support compilation as an NPM project" 30 | configuration: 31 | tasks: compileKotlinJs 32 | expectation: 33 | success: compileKotlinJs 34 | file_exists: 35 | - name: &file_package_json 36 | "build/js/packages/test-mpp/package.json" 37 | contents: 38 | - '"version": "1\.0\.0"' 39 | - '"main": "kotlin/test-mpp\.js"' 40 | - '"name": "test-mpp"' 41 | - '"kotlin": "file:.*?/1.\d+.\d+"' 42 | - name: &file_generated_js 43 | "build/js/packages/test-mpp/kotlin/test-mpp.js" 44 | contents: 45 | - "this\\['test-mpp'\\]" 46 | - "require\\('kotlin'\\)" 47 | 48 | - description: "Kt-MPP projects importing and configuring kt-npm-publish support lifting of generated package.json files" 49 | configuration: 50 | tasks: liftPackageJson 51 | expectation: 52 | output_matches: 53 | - &inferred_packageJson 54 | "\\[test-mpp\\] \\[npmPublishing\\]: Inferred packageJson from task :jsPackageJson: .*?/build/js/packages/test-mpp/package.json" 55 | - *inferred_jsCompileTask 56 | success: liftPackageJson 57 | file_exists: 58 | - name: *file_package_json 59 | contents: 60 | - '"version": "1\.2\.3"' 61 | - '"main": "kotlin/test-mpp\.js"' 62 | - '"name": "@organization/test-mpp"' 63 | - '"kotlin": "1.\d+.\d+"' 64 | 65 | - description: "Kt-MPP projects importing and configuring kt-npm-publish support lifting of generated .js files" 66 | configuration: 67 | tasks: liftJsSources 68 | expectation: 69 | output_matches: 70 | - *inferred_jsCompileTask 71 | - &inferred_jsSourcesDir 72 | "\\[test-mpp\\] \\[npmPublishing\\]: Inferred jsSourcesDir from task :compileKotlinJs: .*?/build/js/packages/test-mpp/kotlin" 73 | success: liftJsSources 74 | file_exists: 75 | - name: *file_generated_js 76 | contents: 77 | - "this\\['@organization/test-mpp'\\]" 78 | - "require\\('kotlin'\\)" 79 | 80 | - description: "Kt-MPP projects importing and configuring kt-npm-publish support copying project files close to package.json" 81 | configuration: 82 | tasks: copyFilesNextToPackageJson 83 | expectation: 84 | output_matches: 85 | - *inferred_packageJson 86 | - *inferred_jsCompileTask 87 | success: copyFilesNextToPackageJson 88 | file_exists: 89 | - name: "build/js/packages/test-mpp/README.md" 90 | 91 | - description: "Kt-MPP projects importing and configuring kt-npm-publish support publishing of JS projects on NPM" 92 | configuration: 93 | tasks: npmPublish 94 | expectation: 95 | output_matches: 96 | - *inferred_jsCompileTask 97 | - *inferred_jsSourcesDir 98 | - *inferred_packageJson 99 | - *inferred_nodeRoot 100 | - *inferred_nodeSetupTask 101 | output_contains: 102 | - 'npm ERR! 404 Not Found - PUT https://registry.npmjs.org/@organization%2ftest-mpp - Not found' 103 | failure: npmPublish 104 | -------------------------------------------------------------------------------- /versions.properties: -------------------------------------------------------------------------------- 1 | ## suppress inspection "SpellCheckingInspection" for whole file 2 | ## 3 | ## Dependencies and Plugin versions with their available updates 4 | ## Generated by $ ./gradlew refreshVersions 5 | ## Please, don't put extra comments in that file yet, keeping them is not supported yet. 6 | 7 | plugin.com.gradle.plugin-publish=0.15.0 8 | 9 | plugin.de.marcphilipp.nexus-publish=0.4.0 10 | 11 | plugin.io.gitlab.arturbosch.detekt=1.17.1 12 | 13 | plugin.org.danilopianini.git-sensitive-semantic-versioning=0.2.3 14 | 15 | plugin.org.danilopianini.publish-on-central=0.4.4 16 | 17 | plugin.org.jetbrains.dokka=version.dokka 18 | 19 | plugin.org.jetbrains.kotlin.js=version.kotlin 20 | 21 | plugin.org.jetbrains.kotlin.jvm=version.kotlin 22 | 23 | plugin.org.jetbrains.kotlin.multiplatform=version.kotlin 24 | 25 | plugin.org.jlleitschuh.gradle.ktlint=10.1.0 26 | 27 | version..konf=1.1.2 28 | 29 | version.com.google.code.gson..gson=2.8.7 30 | 31 | version.com.nhaarman.mockitokotlin2..mockito-kotlin=2.2.0 32 | 33 | version.dokka=1.4.30 34 | 35 | version.io.github.classgraph..classgraph=4.8.108 36 | 37 | 38 | version.io.gitlab.arturbosch.detekt..detekt-formatting=plugin.io.gitlab.arturbosch.detekt 39 | 40 | version.kotest=4.6.0 41 | 42 | version.kotlin=1.5.10 43 | 44 | version.org.jetbrains.dokka..dokka-gradle-plugin=version.dokka 45 | 46 | version.org.mockito..mockito-core=3.11.1 47 | --------------------------------------------------------------------------------