From 30111c9917585e0225847a7609b99c681641a516 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Vannicatte?= Date: Thu, 5 May 2022 17:34:56 +0200 Subject: [PATCH] feat(script): variadic parameters (#472) --- .github/actions/restore-all/action.yml | 242 ---------------- .github/actions/restore-artifacts/action.yml | 80 ++++++ .github/actions/setup/action.yml | 32 +-- .github/workflows/check.yml | 267 +++++------------- playground/javascript/node/predict.ts | 7 +- scripts/buildClients.ts | 4 +- scripts/ci/codegen/spreadGeneration.ts | 5 +- scripts/ci/githubActions/createMatrix.ts | 148 +++++----- scripts/ci/githubActions/types.ts | 26 +- scripts/common.ts | 8 +- scripts/config.ts | 20 +- scripts/cts/utils.ts | 5 +- scripts/formatter.ts | 2 +- scripts/generate.ts | 9 +- scripts/index.ts | 87 +++--- scripts/playground.ts | 7 +- .../release/__tests__/process-release.test.ts | 8 +- scripts/release/process-release.ts | 41 +-- scripts/release/types.ts | 2 +- scripts/types.ts | 2 +- templates/javascript/api-single.mustache | 10 +- 21 files changed, 351 insertions(+), 661 deletions(-) delete mode 100644 .github/actions/restore-all/action.yml create mode 100644 .github/actions/restore-artifacts/action.yml diff --git a/.github/actions/restore-all/action.yml b/.github/actions/restore-all/action.yml deleted file mode 100644 index b7565e9b76..0000000000 --- a/.github/actions/restore-all/action.yml +++ /dev/null @@ -1,242 +0,0 @@ -name: Restore all artifacts - -description: | - When no input is given, artifacts are restored in the current directory, under their artifact `name`. - - This composite restore all of our artifacts, at their right path. - -runs: - using: composite - steps: - # Bundled specs - - name: spec-abtesting - uses: actions/download-artifact@v3 - with: - name: spec-abtesting - path: specs/bundled/ - - - name: spec-analytics - uses: actions/download-artifact@v3 - with: - name: spec-analytics - path: specs/bundled/ - - - name: spec-insights - uses: actions/download-artifact@v3 - with: - name: spec-insights - path: specs/bundled/ - - - name: spec-personalization - uses: actions/download-artifact@v3 - with: - name: spec-personalization - path: specs/bundled/ - - - name: spec-predict - uses: actions/download-artifact@v3 - with: - name: spec-predict - path: specs/bundled/ - - - name: spec-query-suggestions - uses: actions/download-artifact@v3 - with: - name: spec-query-suggestions - path: specs/bundled/ - - - name: spec-recommend - uses: actions/download-artifact@v3 - with: - name: spec-recommend - path: specs/bundled/ - - - name: spec-search - uses: actions/download-artifact@v3 - with: - name: spec-search - path: specs/bundled/ - - - name: spec-sources - uses: actions/download-artifact@v3 - with: - name: spec-sources - path: specs/bundled/ - - # JavaScript utils - - name: client-javascript-utils-client-common - uses: actions/download-artifact@v3 - with: - name: client-javascript-utils-client-common - path: clients/algoliasearch-client-javascript/packages/client-common/ - - - name: client-javascript-utils-requester-browser-xhr - uses: actions/download-artifact@v3 - with: - name: client-javascript-utils-requester-browser-xhr - path: clients/algoliasearch-client-javascript/packages/requester-browser-xhr/ - - - name: client-javascript-utils-requester-node-http - uses: actions/download-artifact@v3 - with: - name: client-javascript-utils-requester-node-http - path: clients/algoliasearch-client-javascript/packages/requester-node-http/ - - # JavaScript - - name: client-javascript-algoliasearch-lite - uses: actions/download-artifact@v3 - with: - name: client-javascript-algoliasearch-lite - path: clients/algoliasearch-client-javascript/packages/algoliasearch-lite/ - - - name: client-javascript-abtesting - uses: actions/download-artifact@v3 - with: - name: client-javascript-abtesting - path: clients/algoliasearch-client-javascript/packages/client-abtesting/ - - - name: client-javascript-analytics - uses: actions/download-artifact@v3 - with: - name: client-javascript-analytics - path: clients/algoliasearch-client-javascript/packages/client-analytics/ - - - name: client-javascript-insights - uses: actions/download-artifact@v3 - with: - name: client-javascript-insights - path: clients/algoliasearch-client-javascript/packages/client-insights/ - - - name: client-javascript-personalization - uses: actions/download-artifact@v3 - with: - name: client-javascript-personalization - path: clients/algoliasearch-client-javascript/packages/client-personalization/ - - - name: client-javascript-predict - uses: actions/download-artifact@v3 - with: - name: client-javascript-predict - path: clients/algoliasearch-client-javascript/packages/client-predict/ - - - name: client-javascript-query-suggestions - uses: actions/download-artifact@v3 - with: - name: client-javascript-query-suggestions - path: clients/algoliasearch-client-javascript/packages/client-query-suggestions/ - - - name: client-javascript-recommend - uses: actions/download-artifact@v3 - with: - name: client-javascript-recommend - path: clients/algoliasearch-client-javascript/packages/recommend/ - - - name: client-javascript-search - uses: actions/download-artifact@v3 - with: - name: client-javascript-search - path: clients/algoliasearch-client-javascript/packages/client-search/ - - - name: client-javascript-sources - uses: actions/download-artifact@v3 - with: - name: client-javascript-sources - path: clients/algoliasearch-client-javascript/packages/client-sources/ - - # PHP model and API - - name: client-php-abtesting - uses: actions/download-artifact@v3 - with: - name: client-php-abtesting - path: clients/algoliasearch-client-php/lib/ - - - name: client-php-analytics - uses: actions/download-artifact@v3 - with: - name: client-php-analytics - path: clients/algoliasearch-client-php/lib/ - - - name: client-php-insights - uses: actions/download-artifact@v3 - with: - name: client-php-insights - path: clients/algoliasearch-client-php/lib/ - - - name: client-php-personalization - uses: actions/download-artifact@v3 - with: - name: client-php-personalization - path: clients/algoliasearch-client-php/lib/ - - - name: client-php-query-suggestions - uses: actions/download-artifact@v3 - with: - name: client-php-query-suggestions - path: clients/algoliasearch-client-php/lib/ - - - name: client-php-recommend - uses: actions/download-artifact@v3 - with: - name: client-php-recommend - path: clients/algoliasearch-client-php/lib/ - - - name: client-php-search - uses: actions/download-artifact@v3 - with: - name: client-php-search - path: clients/algoliasearch-client-php/lib/ - - # Java model and API - - name: client-java-abtesting - uses: actions/download-artifact@v3 - with: - name: client-java-abtesting - path: clients/algoliasearch-client-java-2/algoliasearch-core/src/main/java/com/algolia/ - - - name: client-java-analytics - uses: actions/download-artifact@v3 - with: - name: client-java-analytics - path: clients/algoliasearch-client-java-2/algoliasearch-core/src/main/java/com/algolia/ - - - name: client-java-insights - uses: actions/download-artifact@v3 - with: - name: client-java-insights - path: clients/algoliasearch-client-java-2/algoliasearch-core/src/main/java/com/algolia/ - - - name: client-java-personalization - uses: actions/download-artifact@v3 - with: - name: client-java-personalization - path: clients/algoliasearch-client-java-2/algoliasearch-core/src/main/java/com/algolia/ - - - name: client-java-predict - uses: actions/download-artifact@v3 - with: - name: client-java-predict - path: clients/algoliasearch-client-java-2/algoliasearch-core/src/main/java/com/algolia/ - - - name: client-java-query-suggestions - uses: actions/download-artifact@v3 - with: - name: client-java-query-suggestions - path: clients/algoliasearch-client-java-2/algoliasearch-core/src/main/java/com/algolia/ - - - name: client-java-recommend - uses: actions/download-artifact@v3 - with: - name: client-java-recommend - path: clients/algoliasearch-client-java-2/algoliasearch-core/src/main/java/com/algolia/ - - - name: client-java-search - uses: actions/download-artifact@v3 - with: - name: client-java-search - path: clients/algoliasearch-client-java-2/algoliasearch-core/src/main/java/com/algolia/ - - - name: client-java-utils - uses: actions/download-artifact@v3 - with: - name: client-java-utils - path: clients/algoliasearch-client-java-2/ diff --git a/.github/actions/restore-artifacts/action.yml b/.github/actions/restore-artifacts/action.yml new file mode 100644 index 0000000000..6939096336 --- /dev/null +++ b/.github/actions/restore-artifacts/action.yml @@ -0,0 +1,80 @@ +name: Restore artifacts + +description: | + When no input is given, artifacts are restored in the current directory, under their artifact `name`. + + This composite restore all of our artifacts, at their right path. + +inputs: + type: + description: Type of artifacts to restore (`all` | `specs` | `utils`) + required: false + +runs: + using: composite + steps: + # Bundled specs + - name: specs + if: ${{ inputs.type == 'all' || inputs.type == 'specs' }} + uses: actions/download-artifact@v3 + with: + name: specs + path: specs/bundled/ + + # JavaScript utils + - name: client-javascript-utils-client-common + if: ${{ inputs.type == 'all' || inputs.type == 'utils' }} + uses: actions/download-artifact@v3 + with: + name: client-javascript-utils-client-common + path: clients/algoliasearch-client-javascript/packages/client-common/ + + - name: client-javascript-utils-requester-browser-xhr + if: ${{ inputs.type == 'all' || inputs.type == 'utils' }} + uses: actions/download-artifact@v3 + with: + name: client-javascript-utils-requester-browser-xhr + path: clients/algoliasearch-client-javascript/packages/requester-browser-xhr/ + + - name: client-javascript-utils-requester-node-http + if: ${{ inputs.type == 'all' || inputs.type == 'utils' }} + uses: actions/download-artifact@v3 + with: + name: client-javascript-utils-requester-node-http + path: clients/algoliasearch-client-javascript/packages/requester-node-http/ + + # JavaScript + - name: Download clients-javascript artifact + if: ${{ inputs.type == 'all' }} + uses: actions/download-artifact@v3 + with: + name: clients-javascript + + - name: Unzip clients-javascript artifact + if: ${{ inputs.type == 'all' }} + shell: bash + run: unzip -q -o clients-javascript.zip + + # PHP + - name: Download clients-php artifact + if: ${{ inputs.type == 'all' }} + uses: actions/download-artifact@v3 + with: + name: clients-php + + - name: Unzip clients-php artifact + if: ${{ inputs.type == 'all' }} + shell: bash + run: unzip -q -o clients-php.zip + + # Java + - name: Download clients-java artifact + if: ${{ inputs.type == 'all' }} + uses: actions/download-artifact@v3 + with: + name: clients-java + + - name: Unzip clients-java artifact + if: ${{ inputs.type == 'all' }} + shell: bash + run: unzip -q -o clients-java.zip diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 4bdaa5ffab..7501f55716 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -111,26 +111,12 @@ outputs: description: The generated `specs` matrix value: ${{ steps.spec-matrix.outputs.MATRIX }} - RUN_JAVASCRIPT: - description: Determine if the `client_javascript` job should run - value: ${{ steps.gen-matrix.outputs.RUN_JAVASCRIPT }} - JAVASCRIPT_MATRIX: - description: The generated `client_javascript` matrix - value: ${{ steps.gen-matrix.outputs.JAVASCRIPT_MATRIX }} - - RUN_JAVA: - description: Determine if the `client_java` job should run - value: ${{ steps.gen-matrix.outputs.RUN_JAVA }} - JAVA_MATRIX: - description: The generated `client_java` matrix - value: ${{ steps.gen-matrix.outputs.JAVA_MATRIX }} - - RUN_PHP: - description: Determine if the `client_php` job should run - value: ${{ steps.gen-matrix.outputs.RUN_PHP }} - PHP_MATRIX: - description: The generated `client_php` matrix - value: ${{ steps.gen-matrix.outputs.PHP_MATRIX }} + RUN_GEN: + description: Determine if the `client_gen` job should run + value: ${{ steps.gen-matrix.outputs.RUN_GEN }} + GEN_MATRIX: + description: The generated `client_gen` matrix + value: ${{ steps.gen-matrix.outputs.GEN_MATRIX }} RUN_JS_ALGOLIASEARCH: description: Determine if the `client-javascript-algoliasearch` job should run @@ -143,7 +129,7 @@ outputs: value: ${{ steps.diff.outputs.JS_COMMON_TESTS_CHANGED > 0 }} RUN_CTS: - description: Determine if the `cts` job should run + description: Determine if the `cts` jobs should run value: ${{ steps.diff.outputs.GITHUB_ACTIONS_CHANGED > 0 || steps.diff.outputs.SCRIPTS_CHANGED > 0 || @@ -158,6 +144,4 @@ outputs: description: Determine if the `codegen` job should run value: ${{ steps.spec-matrix.outputs.RUN_SPECS == 'true' || - steps.gen-matrix.outputs.RUN_JAVASCRIPT == 'true' || - steps.gen-matrix.outputs.RUN_JAVA == 'true' || - steps.gen-matrix.outputs.RUN_PHP == 'true' }} + steps.gen-matrix.outputs.RUN_GEN == 'true' }} diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 6357db4ca2..30ceedbf01 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -53,19 +53,12 @@ jobs: RUN_SPECS: ${{ steps.setup.outputs.RUN_SPECS }} SPECS_MATRIX: ${{ steps.setup.outputs.SPECS_MATRIX }} - RUN_JAVASCRIPT: ${{ steps.setup.outputs.RUN_JAVASCRIPT }} - JAVASCRIPT_MATRIX: ${{ steps.setup.outputs.JAVASCRIPT_MATRIX }} - - RUN_JAVA: ${{ steps.setup.outputs.RUN_JAVA }} - JAVA_MATRIX: ${{ steps.setup.outputs.JAVA_MATRIX }} - - RUN_PHP: ${{ steps.setup.outputs.RUN_PHP }} - PHP_MATRIX: ${{ steps.setup.outputs.PHP_MATRIX }} + RUN_GEN: ${{ steps.setup.outputs.RUN_GEN }} + GEN_MATRIX: ${{ steps.setup.outputs.GEN_MATRIX }} RUN_JS_ALGOLIASEARCH: ${{ steps.setup.outputs.RUN_JS_ALGOLIASEARCH }} RUN_JS_UTILS: ${{ steps.setup.outputs.RUN_JS_UTILS }} RUN_JS_TESTS: ${{ steps.setup.outputs.RUN_JS_TESTS }} - JS_MATRIX: ${{ steps.setup.outputs.JS_MATRIX }} RUN_CTS: ${{ steps.setup.outputs.RUN_CTS }} @@ -103,7 +96,7 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Cache '${{ matrix.client.name }}' bundled spec + - name: Cache bundled specs id: cache uses: actions/cache@v3 with: @@ -116,19 +109,15 @@ jobs: with: type: minimal - - name: Building '${{ matrix.client.name }}' spec - if: ${{ steps.cache.outputs.cache-hit != 'true' }} - run: yarn cli build specs ${{ matrix.client.name }} - - - name: Show diff for '${{ matrix.client.name }}' bundled spec + - name: Building specs if: ${{ steps.cache.outputs.cache-hit != 'true' }} - run: git --no-pager diff + run: yarn cli build specs ${{ matrix.client.toRun }} - - name: Store '${{ matrix.client.name }}' bundled spec + - name: Store bundled specs uses: actions/upload-artifact@v3 with: if-no-files-found: error - name: spec-${{ matrix.client.name }} + name: specs path: ${{ matrix.client.bundledPath }} client_javascript_utils: @@ -179,8 +168,8 @@ jobs: name: client-javascript-utils-${{ matrix.client }} path: clients/algoliasearch-client-javascript/packages/${{ matrix.client }} - client_javascript: - timeout-minutes: 10 + client_gen: + timeout-minutes: 15 runs-on: ubuntu-20.04 needs: - setup @@ -189,179 +178,86 @@ jobs: - client_javascript_utils if: | always() && - needs.setup.outputs.RUN_JAVASCRIPT == 'true' && + needs.setup.outputs.RUN_GEN == 'true' && !contains(needs.*.result, 'cancelled') && !contains(needs.*.result, 'failure') strategy: - matrix: ${{ fromJSON(needs.setup.outputs.JAVASCRIPT_MATRIX) }} + matrix: ${{ fromJSON(needs.setup.outputs.GEN_MATRIX) }} steps: - uses: actions/checkout@v2 - - name: Cache '${{ matrix.client.name }}' client folder + - name: Cache clients folder id: cache uses: actions/cache@v3 with: key: ${{ matrix.client.cacheKey }} path: ${{ matrix.client.path }} - - name: Download '${{ matrix.client.name }}' bundled spec + - name: Download bundled specs if: ${{ steps.cache.outputs.cache-hit != 'true' }} uses: actions/download-artifact@v3 with: - name: spec-${{ matrix.client.name }} + name: specs path: specs/bundled/ - - name: Setup - if: ${{ steps.cache.outputs.cache-hit != 'true' }} - uses: ./.github/actions/setup - - - name: Generate '${{ matrix.client.language }}' '${{ matrix.client.name }}' client - if: ${{ steps.cache.outputs.cache-hit != 'true' }} - run: yarn cli generate ${{ matrix.client.language }} ${{ matrix.client.name }} - - - name: Build '${{ matrix.client.language }}' '${{ matrix.client.name }}' client + - name: Download specs artifacts if: ${{ steps.cache.outputs.cache-hit != 'true' }} - run: yarn cli build clients ${{ matrix.client.language }} ${{ matrix.client.name }} - - - name: Show diff for '${{ matrix.client.name }}' client - if: ${{ steps.cache.outputs.cache-hit != 'true' }} - run: git --no-pager diff - - - name: Store ${{ matrix.client.name }}-${{ matrix.client.language }} client - uses: actions/upload-artifact@v3 + uses: ./.github/actions/restore-artifacts with: - if-no-files-found: error - name: client-${{matrix.client.language }}-${{ matrix.client.name }} - path: ${{ matrix.client.path }} + type: specs - client_java: - timeout-minutes: 10 - runs-on: ubuntu-20.04 - needs: - - setup - - specs - - scripts - if: | - always() && - needs.setup.outputs.RUN_JAVA == 'true' && - !contains(needs.*.result, 'cancelled') && - !contains(needs.*.result, 'failure') - strategy: - matrix: ${{ fromJSON(needs.setup.outputs.JAVA_MATRIX) }} - steps: - - uses: actions/checkout@v2 - - - name: Cache '${{ matrix.client.name }}' client API and Model - id: cache - uses: actions/cache@v3 + - name: Download JavaScript utils artifacts + if: ${{ matrix.client.language == 'javascript' && steps.cache.outputs.cache-hit != 'true' }} + uses: ./.github/actions/restore-artifacts with: - key: ${{ matrix.client.cacheKey }} - path: | - ${{ matrix.client.apiPath }} - ${{ matrix.client.modelPath }} - - - name: Download '${{ matrix.client.name }}' bundled spec - if: ${{ steps.cache.outputs.cache-hit != 'true' }} - uses: actions/download-artifact@v3 - with: - name: spec-${{ matrix.client.name }} - path: specs/bundled/ + type: utils - name: Setup if: ${{ steps.cache.outputs.cache-hit != 'true' }} uses: ./.github/actions/setup - - name: Generate '${{ matrix.client.language }}' '${{ matrix.client.name }}' client - if: ${{ steps.cache.outputs.cache-hit != 'true' }} - run: yarn cli generate ${{ matrix.client.language }} ${{ matrix.client.name }} - - - name: Build '${{ matrix.client.language }}' '${{ matrix.client.name }}' client + - name: Generate clients if: ${{ steps.cache.outputs.cache-hit != 'true' }} - run: yarn cli build clients ${{ matrix.client.language }} ${{ matrix.client.name }} + run: yarn cli generate ${{ matrix.client.language }} ${{ matrix.client.toRun }} - - name: Show diff for '${{ matrix.client.name }}' client - if: ${{ steps.cache.outputs.cache-hit != 'true' }} - run: git --no-pager diff + - name: Build clients + if: ${{ steps.cache.outputs.cache-hit != 'true' && matrix.client.language != 'php' }} + run: yarn cli build clients ${{ matrix.client.language }} ${{ matrix.client.toRun }} - - name: Store ${{ matrix.client.name }}-${{ matrix.client.language }} client - uses: actions/upload-artifact@v3 - with: - if-no-files-found: error - name: client-${{matrix.client.language }}-${{ matrix.client.name }} - path: | - ${{ matrix.client.modelPath }} - ${{ matrix.client.apiPath }} + - name: Clean CTS output before generate + if: ${{ needs.setup.outputs.RUN_CTS == 'true' }} + run: rm -rf ${{ matrix.client.testsOutputPath }} - - name: Store Java utils - uses: actions/upload-artifact@v3 - with: - if-no-files-found: error - name: client-java-utils - path: | - clients/algoliasearch-client-java-2/gradle - clients/algoliasearch-client-java-2/gradle* - clients/algoliasearch-client-java-2/algoliasearch-core/src/main/java/com/algolia/*.java + - name: Generate CTS + if: ${{ needs.setup.outputs.RUN_CTS == 'true' }} + run: yarn cli cts generate ${{ matrix.client.language }} ${{ matrix.client.toRun }} - client_php: - timeout-minutes: 10 - runs-on: ubuntu-20.04 - needs: - - setup - - specs - - scripts - if: | - always() && - needs.setup.outputs.RUN_PHP == 'true' && - !contains(needs.*.result, 'cancelled') && - !contains(needs.*.result, 'failure') - strategy: - matrix: ${{ fromJSON(needs.setup.outputs.PHP_MATRIX) }} - steps: - - uses: actions/checkout@v2 - - - name: Cache '${{ matrix.client.name }}' client API and Model - id: cache - uses: actions/cache@v3 - with: - key: ${{ matrix.client.cacheKey }} - path: | - ${{ matrix.client.apiPath }} - ${{ matrix.client.modelPath }} - - - name: Download '${{ matrix.client.name }}' bundled spec - if: ${{ steps.cache.outputs.cache-hit != 'true' }} - uses: actions/download-artifact@v3 - with: - name: spec-${{ matrix.client.name }} - path: specs/bundled/ - - - name: Setup - if: ${{ steps.cache.outputs.cache-hit != 'true' }} - uses: ./.github/actions/setup + - name: Check diff with pushed CTS + if: ${{ needs.setup.outputs.RUN_CTS == 'true' }} + run: | + git --no-pager diff + exit $(git diff --name-only --diff-filter=d ${{ matrix.client.testsOutputPath }} | wc -l) - - name: Generate '${{ matrix.client.language }}' '${{ matrix.client.name }}' client - if: ${{ steps.cache.outputs.cache-hit != 'true' }} - run: yarn cli generate ${{ matrix.client.language }} ${{ matrix.client.name }} + - name: Run CTS + if: ${{ needs.setup.outputs.RUN_CTS == 'true' }} + run: yarn cli cts run ${{ matrix.client.language }} - - name: Show diff for '${{ matrix.client.name }}' client - if: ${{ steps.cache.outputs.cache-hit != 'true' }} - run: git --no-pager diff + - name: Zip artifact before storing + run: zip -q -r clients-${{ matrix.client.language }}.zip ${{ matrix.client.path }} -x "${{ matrix.client.path }}/node_modules/.**" - - name: Store ${{ matrix.client.name }}-${{ matrix.client.language }} client + - name: Store ${{ matrix.client.language }} clients uses: actions/upload-artifact@v3 with: if-no-files-found: error - name: client-${{matrix.client.language }}-${{ matrix.client.name }} - path: | - ${{ matrix.client.modelPath }} - ${{ matrix.client.apiPath }} + name: clients-${{matrix.client.language }} + path: clients-${{matrix.client.language }}.zip client_javascript_algoliasearch: timeout-minutes: 10 runs-on: ubuntu-20.04 needs: - setup - - client_javascript + - client_gen if: | always() && needs.setup.outputs.RUN_JS_ALGOLIASEARCH == 'true' && @@ -380,26 +276,12 @@ jobs: )}} path: clients/algoliasearch-client-javascript/packages/algoliasearch/ - - name: Restore 'analytics' client + - name: Restore clients if: ${{ steps.cache.outputs.cache-hit != 'true' }} uses: actions/download-artifact@v3 with: - name: client-javascript-analytics - path: clients/algoliasearch-client-javascript/packages/client-analytics/ - - - name: Restore 'personalization' client - if: ${{ steps.cache.outputs.cache-hit != 'true' }} - uses: actions/download-artifact@v3 - with: - name: client-javascript-personalization - path: clients/algoliasearch-client-javascript/packages/client-personalization/ - - - name: Restore 'search' client - if: ${{ steps.cache.outputs.cache-hit != 'true' }} - uses: actions/download-artifact@v3 - with: - name: client-javascript-search - path: clients/algoliasearch-client-javascript/packages/client-search/ + name: clients-javascript + path: clients/algoliasearch-client-javascript/ - name: Setup if: ${{ steps.cache.outputs.cache-hit != 'true' }} @@ -411,17 +293,15 @@ jobs: if: ${{ steps.cache.outputs.cache-hit != 'true' }} run: yarn cli build clients javascript algoliasearch - cts: + codegen_on_pr: runs-on: ubuntu-20.04 - timeout-minutes: 20 + timeout-minutes: 10 needs: - setup - - client_javascript - - client_java - - client_php + - client_gen if: | always() && - needs.setup.outputs.RUN_CTS == 'true' && + needs.setup.outputs.RUN_CODEGEN == 'true' && !contains(needs.*.result, 'cancelled') && !contains(needs.*.result, 'failure') steps: @@ -431,11 +311,15 @@ jobs: ref: ${{ github.event.pull_request.head.ref }} token: ${{ secrets.TOKEN_GENERATE_BOT }} - - name: Download all the previously stored artifacts - uses: ./.github/actions/restore-all + - name: Download all artifacts + uses: ./.github/actions/restore-artifacts + with: + type: all - name: Setup uses: ./.github/actions/setup + with: + type: minimal - name: Push generated code to generated branch if: github.event_name == 'pull_request' @@ -445,41 +329,18 @@ jobs: GITHUB_TOKEN: ${{ secrets.TOKEN_GENERATE_BOT }} PR_NUMBER: ${{ github.event.number }} - - name: Check JavaScript client size - run: exit $(yarn workspace algoliasearch-client-javascript test:size | echo $?) - - # ----> This can be added once the PHP build for the CTS is fixed - # - name: Cache generated CTS - # id: cache - # uses: actions/cache@v3 - # with: - # path: tests/output - # key: ${{ hashFiles( 'tests/output/**' ) }} - - - name: Generate - # if: steps.cache.outputs.cache-hit != 'true' - run: yarn cli cts generate - - - name: Check diff with pushed CTS - # if: steps.cache.outputs.cache-hit != 'true' - run: | - git --no-pager diff - exit $(git status --porcelain ./tests/output | wc -l) - - - name: Run - run: yarn cli cts run - codegen_on_main: runs-on: ubuntu-20.04 timeout-minutes: 10 needs: - setup - - cts + - client_gen if: | always() && github.ref == 'refs/heads/main' && needs.setup.outputs.RUN_CODEGEN == 'true' && - needs.cts.result == 'success' + !contains(needs.*.result, 'cancelled') && + !contains(needs.*.result, 'failure') steps: - uses: actions/checkout@v2 with: @@ -488,7 +349,9 @@ jobs: token: ${{ secrets.TOKEN_GENERATE_BOT }} - name: Download all the previously stored artifacts - uses: ./.github/actions/restore-all + uses: ./.github/actions/restore-artifacts + with: + type: all - name: Setup uses: ./.github/actions/setup diff --git a/playground/javascript/node/predict.ts b/playground/javascript/node/predict.ts index a78f44b53a..b7d4410a54 100644 --- a/playground/javascript/node/predict.ts +++ b/playground/javascript/node/predict.ts @@ -4,10 +4,11 @@ import dotenv from 'dotenv'; dotenv.config({ path: '../../.env' }); -const appId = process.env.ALGOLIA_APPLICATION_ID || '**** APP_ID *****'; -const apiKey = process.env.ALGOLIA_SEARCH_KEY || '**** SEARCH_API_KEY *****'; +const appId = process.env.ALGOLIA_PREDICT_APP_ID || '**** APP_ID *****'; +const apiKey = + process.env.ALGOLIA_PREDICT_API_KEY || '**** PREDICT_API_KEY *****'; -const userId = process.env.USER_ID || 'user1'; +const userId = 'user1'; // Init client with appId and apiKey const client = predictClient(appId, apiKey); diff --git a/scripts/buildClients.ts b/scripts/buildClients.ts index 7a8a256149..2c45286458 100644 --- a/scripts/buildClients.ts +++ b/scripts/buildClients.ts @@ -1,4 +1,4 @@ -import { run } from './common'; +import { CI, run } from './common'; import { getLanguageFolder } from './config'; import { createSpinner } from './oraLog'; import type { Generator } from './types'; @@ -58,7 +58,7 @@ export async function buildClients( ): Promise { const langs = [...new Set(generators.map((gen) => gen.language))]; - if (langs.includes('javascript')) { + if (!CI && langs.includes('javascript')) { const spinner = createSpinner( "building 'JavaScript' utils", verbose diff --git a/scripts/ci/codegen/spreadGeneration.ts b/scripts/ci/codegen/spreadGeneration.ts index 12119c57af..1bfc537588 100644 --- a/scripts/ci/codegen/spreadGeneration.ts +++ b/scripts/ci/codegen/spreadGeneration.ts @@ -11,11 +11,12 @@ import { } from '../../common'; import { getLanguageFolder } from '../../config'; import { cloneRepository, configureGitHubAuthor } from '../../release/common'; +import type { Language } from '../../types'; import { getNbGitDiff } from '../utils'; import text from './text'; -export function decideWhereToSpread(commitMessage: string): string[] { +export function decideWhereToSpread(commitMessage: string): Language[] { if (commitMessage.startsWith('chore: release')) { return []; } @@ -26,7 +27,7 @@ export function decideWhereToSpread(commitMessage: string): string[] { return LANGUAGES; } - const scope = result[2]; + const scope = result[2] as Language; return LANGUAGES.includes(scope) ? [scope] : LANGUAGES; } diff --git a/scripts/ci/githubActions/createMatrix.ts b/scripts/ci/githubActions/createMatrix.ts index 758cf83fc5..f6b6dd3054 100644 --- a/scripts/ci/githubActions/createMatrix.ts +++ b/scripts/ci/githubActions/createMatrix.ts @@ -1,12 +1,11 @@ /* eslint-disable no-console */ import { CLIENTS, GENERATORS, LANGUAGES } from '../../common'; -import { getLanguageApiFolder, getLanguageModelFolder } from '../../config'; -import { camelize, createClientName } from '../../cts/utils'; +import { getLanguageFolder, getTestOutputFolder } from '../../config'; import type { Language } from '../../types'; import { getNbGitDiff } from '../utils'; import { DEPENDENCIES } from './setRunVariables'; -import type { CreateMatrix, ClientMatrix, Matrix, SpecMatrix } from './types'; +import type { ClientMatrix, CreateMatrix, Matrix, SpecMatrix } from './types'; import { computeCacheKey, isBaseChanged } from './utils'; // This empty matrix is required by the CI, otherwise it throws @@ -38,12 +37,24 @@ const MATRIX_DEPENDENCIES = { }, }; +type ToRunMatrix = { + path: string; + toRun: string[]; + cacheToCompute: string[]; +}; + async function getClientMatrix(baseBranch: string): Promise { - const matrix: Record> = { - java: { client: [] }, - php: { client: [] }, - javascript: { client: [] }, - }; + const matrix = LANGUAGES.reduce( + (curr, lang) => ({ + ...curr, + [lang]: { + path: getLanguageFolder(lang), + toRun: [], + cacheToCompute: [], + }, + }), + {} as Record + ); for (const { language, client, output } of Object.values(GENERATORS)) { // `algoliasearch` is an aggregation of generated clients. @@ -71,70 +82,59 @@ async function getClientMatrix(baseBranch: string): Promise { continue; } - const clientName = createClientName(client, language); - const camelizedClientName = camelize(client); - const pathToApi = `${output}/${getLanguageApiFolder(language)}`; - const pathToModel = `${output}/${getLanguageModelFolder(language)}`; - - const clientMatrix: ClientMatrix = { - language, - name: client, - path: output, + matrix[language].toRun.push(client); + matrix[language].cacheToCompute.push(`specs/bundled/${bundledSpec}.yml`); + } - configName: `${clientName}Config`, - apiName: `${clientName}Client`, + const clientMatrix: Matrix = { + client: [], + }; - apiPath: pathToApi, - modelPath: pathToModel, + // Set output variables for the CI + for (const language of LANGUAGES) { + if (matrix[language].toRun.length === 0) { + continue; + } - cacheKey: await computeCacheKey(`client-${client}`, [ - `specs/bundled/${bundledSpec}.yml`, + clientMatrix.client.push({ + language, + path: matrix[language].path, + toRun: matrix[language].toRun.join(' '), + cacheKey: await computeCacheKey(`clients-${language}`, [ + ...matrix[language].cacheToCompute, `templates/${language}`, `generators/src`, ]), - }; - - // While JavaScript have it's own package per client, other language have - // API and models in folders common to all clients, so we scope it. - switch (language) { - case 'java': - clientMatrix.apiPath = `${pathToApi}/${clientMatrix.apiName}.java`; - clientMatrix.modelPath = `${pathToModel}/${camelizedClientName}/`; - break; - case 'php': - clientMatrix.apiPath = `${pathToApi}/${clientMatrix.apiName}.php`; - clientMatrix.modelPath = `${pathToModel}/${clientName}/`; - break; - default: - break; - } - - matrix[language].client.push(clientMatrix); + testsOutputPath: `./tests/output/${language}/${getTestOutputFolder( + language + )}`, + }); } - // Set output variables for the CI - for (const language of LANGUAGES) { - const lang = language.toLocaleUpperCase(); - const shouldRun = matrix[language].client.length > 0; - - console.log(`::set-output name=RUN_${lang}::${shouldRun}`); - console.log( - `::set-output name=${lang}_MATRIX::${JSON.stringify( - shouldRun ? matrix[language] : EMPTY_MATRIX - )}` - ); - } + const shouldRun = clientMatrix.client.length > 0; + + console.log(`::set-output name=RUN_GEN::${shouldRun}`); + console.log( + `::set-output name=GEN_MATRIX::${JSON.stringify( + shouldRun ? clientMatrix : EMPTY_MATRIX + )}` + ); } async function getSpecMatrix(baseBranch: string): Promise { - const matrix: Matrix = { client: [] }; + const matrix: ToRunMatrix = { + path: 'specs/bundled', + toRun: [], + cacheToCompute: [], + }; for (const client of CLIENTS) { // The `algoliasearch-lite` spec is created by the `search` spec const bundledSpecName = client === 'algoliasearch-lite' ? 'search' : client; + const path = `specs/${bundledSpecName}`; const specChanges = await getNbGitDiff({ branch: baseBranch, - path: `specs/${bundledSpecName}`, + path, }); const baseChanged = await isBaseChanged( baseBranch, @@ -146,24 +146,34 @@ async function getSpecMatrix(baseBranch: string): Promise { continue; } - const path = `specs/${bundledSpecName}`; + matrix.toRun.push(client); + matrix.cacheToCompute.push(path); + } - matrix.client.push({ - name: client, - path, - bundledPath: `specs/bundled/${client}.yml`, - cacheKey: await computeCacheKey(`spec-${client}`, ['specs/common', path]), - }); + // We have nothing to run + if (matrix.toRun.length === 0) { + console.log('::set-output name=RUN_SPECS::false'); + console.log(`::set-output name=MATRIX::${JSON.stringify(EMPTY_MATRIX)}`); + + return; } - const shouldRun = matrix.client.length > 0; + const ciMatrix: Matrix = { + client: [ + { + path: matrix.path, + bundledPath: 'specs/bundled', + toRun: matrix.toRun.join(' '), + cacheKey: await computeCacheKey('specs', [ + ...matrix.cacheToCompute, + 'specs/common', + ]), + }, + ], + }; - console.log(`::set-output name=RUN_SPECS::${shouldRun}`); - console.log( - `::set-output name=MATRIX::${JSON.stringify( - shouldRun ? matrix : EMPTY_MATRIX - )}` - ); + console.log('::set-output name=RUN_SPECS::true'); + console.log(`::set-output name=MATRIX::${JSON.stringify(ciMatrix)}`); } /** diff --git a/scripts/ci/githubActions/types.ts b/scripts/ci/githubActions/types.ts index ce8b353462..648eb92c50 100644 --- a/scripts/ci/githubActions/types.ts +++ b/scripts/ci/githubActions/types.ts @@ -10,10 +10,6 @@ export type CreateMatrix = { }; type BaseMatrix = { - /** - * Name of the client. - */ - name: string; /** * Path to the file/folder being handled. */ @@ -22,6 +18,10 @@ type BaseMatrix = { * The computed cache key, used to restore files from the CI. */ cacheKey: string; + /** + * The list of clients to run in the CI. + */ + toRun: string; }; export type ClientMatrix = BaseMatrix & { @@ -29,24 +29,10 @@ export type ClientMatrix = BaseMatrix & { * The client language. */ language: string; - - /** - * The client name plus `Config` appended. With the casing corresponding to the language. - */ - configName: string; - /** - * The client name plus `Client` appended. With the casing corresponding to the language. - */ - apiName: string; - - /** - * Path to the `API` file/folder of the client, based on the language. - */ - apiPath: string; /** - * Path to the `Model` file/folder of the client, based on the language. + * The test output path to clean. */ - modelPath: string; + testsOutputPath: string; }; export type SpecMatrix = BaseMatrix & { diff --git a/scripts/common.ts b/scripts/common.ts index 48c4055cd6..5971686989 100644 --- a/scripts/common.ts +++ b/scripts/common.ts @@ -14,6 +14,7 @@ import type { CheckForCache, CheckForCacheOptions, Generator, + Language, RunOptions, } from './types'; @@ -87,7 +88,7 @@ export const CLIENTS = CLIENTS_JS.filter( export function splitGeneratorKey( generatorKey: string ): Pick { - const language = generatorKey.slice(0, generatorKey.indexOf('-')); + const language = generatorKey.slice(0, generatorKey.indexOf('-')) as Language; const client = generatorKey.slice(generatorKey.indexOf('-') + 1); return { language, client, key: generatorKey }; } @@ -125,7 +126,10 @@ export const getGitHubUrl: GitHubUrl = ( export function createGeneratorKey({ language, client, -}: Pick): string { +}: { + language: Language | 'all'; + client: string; +}): string { return `${language}-${client}`; } diff --git a/scripts/config.ts b/scripts/config.ts index 9cd43beabd..4d86c1615e 100644 --- a/scripts/config.ts +++ b/scripts/config.ts @@ -1,25 +1,27 @@ import clientsConfig from '../config/clients.config.json'; -export function getLanguageFolder(language: string): string { +import type { Language } from './types'; + +export function getLanguageFolder(language: Language): string { return clientsConfig[language].folder; } -export function getLanguageApiFolder(language: string): string { +export function getLanguageApiFolder(language: Language): string { return clientsConfig[language].apiFolder; } -export function getLanguageModelFolder(language: string): string { +export function getLanguageModelFolder(language: Language): string { return clientsConfig[language].modelFolder; } -export function getTestExtension(language: string): string | undefined { - return clientsConfig[language]?.tests?.extension; +export function getTestExtension(language: Language): string { + return clientsConfig[language].tests.extension; } -export function getTestOutputFolder(language: string): string | undefined { - return clientsConfig[language]?.tests?.outputFolder; +export function getTestOutputFolder(language: Language): string { + return clientsConfig[language].tests.outputFolder; } -export function getCustomGenerator(language: string): string | undefined { - return clientsConfig[language]?.customGenerator; +export function getCustomGenerator(language: Language): string { + return clientsConfig[language].customGenerator; } diff --git a/scripts/cts/utils.ts b/scripts/cts/utils.ts index 5871b9976d..d17665b5b3 100644 --- a/scripts/cts/utils.ts +++ b/scripts/cts/utils.ts @@ -3,6 +3,7 @@ import path from 'path'; import { exists, toAbsolutePath } from '../common'; import { getTestExtension, getTestOutputFolder } from '../config'; +import type { Language } from '../types'; export async function* walk( dir: string @@ -61,7 +62,7 @@ export async function createOutputDir({ language, testPath, }: { - language: string; + language: Language; testPath: string; }): Promise { await fsp.mkdir( @@ -79,7 +80,7 @@ export function getOutputPath({ client, testPath, }: { - language: string; + language: Language; client: string; testPath: string; }): string { diff --git a/scripts/formatter.ts b/scripts/formatter.ts index bc619656d3..26876b997f 100644 --- a/scripts/formatter.ts +++ b/scripts/formatter.ts @@ -13,7 +13,7 @@ export async function formatter( let cmd = ''; switch (language) { case 'javascript': - cmd = `yarn eslint --ext=ts,js ${folder} --fix || yarn eslint --ext=ts,js ${folder} --fix`; + cmd = `yarn eslint --ext=ts ${folder} --fix`; break; case 'java': cmd = `find ${folder} -type f -name "*.java" | xargs java --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ diff --git a/scripts/generate.ts b/scripts/generate.ts index f8676168b1..7eb5e024e1 100644 --- a/scripts/generate.ts +++ b/scripts/generate.ts @@ -65,17 +65,10 @@ export async function generate( await run('YARN_ENABLE_IMMUTABLE_INSTALLS=false yarn', { verbose }); } - if (CI && gen.language === 'javascript') { - // because the CI is parallelized, run the formatter for each client - await formatter(gen.language, gen.output, verbose); - } - spinner.succeed(); } for (const lang of langs) { - if (!(CI && lang === 'javascript')) { - await formatter(lang, getLanguageFolder(lang), verbose); - } + await formatter(lang, getLanguageFolder(lang), verbose); } } diff --git a/scripts/index.ts b/scripts/index.ts index 97dc0cab0a..f56f3e1b02 100644 --- a/scripts/index.ts +++ b/scripts/index.ts @@ -19,7 +19,7 @@ import { runCts } from './cts/runCts'; import { formatter } from './formatter'; import { generate } from './generate'; import { playground } from './playground'; -import type { Generator } from './types'; +import type { Generator, Language } from './types'; if (!CI && !DOCKER) { // eslint-disable-next-line no-console @@ -31,9 +31,9 @@ if (!CI && !DOCKER) { program.name('cli'); async function promptLanguage( - defaut: string | undefined, + defaut: Language | 'all' | undefined, interactive: boolean -): Promise { +): Promise { if (defaut) { return defaut; } @@ -53,15 +53,15 @@ async function promptLanguage( } async function promptClient( - defaut: string | undefined, + defaut: string[], interactive: boolean, clientList = CLIENTS -): Promise { - if (defaut) { +): Promise { + if (defaut.length > 0) { return defaut; } if (!interactive) { - return 'all'; + return ['all']; } const { client } = await inquirer.prompt([ { @@ -79,15 +79,17 @@ function generatorList({ language, client, clientList = CLIENTS, -}: Pick & { +}: { + language: Language | 'all'; + client: string[]; clientList?: string[]; }): Generator[] { let langsTodo = [language]; - let clientsTodo = [client]; + let clientsTodo = client; if (language === 'all') { langsTodo = LANGUAGES; } - if (client === 'all') { + if (client[0] === 'all') { clientsTodo = clientList; } @@ -109,14 +111,14 @@ program ) ) .addArgument( - new Argument('[client]', 'The client').choices(['all'].concat(CLIENTS)) + new Argument('[client...]', 'The client').choices(['all'].concat(CLIENTS)) ) .option('-v, --verbose', 'make the generation verbose') .option('-i, --interactive', 'open prompt to query parameters') .action( async ( - language: string | undefined, - client: string | undefined, + language: Language | 'all' | undefined, + client: string[], { verbose, interactive } ) => { language = await promptLanguage(language, interactive); @@ -137,7 +139,7 @@ buildCommand ) ) .addArgument( - new Argument('[client]', 'The client').choices( + new Argument('[client...]', 'The client').choices( ['all'].concat([...CLIENTS_JS_UTILS, ...CLIENTS_JS]) ) ) @@ -145,8 +147,8 @@ buildCommand .option('-i, --interactive', 'open prompt to query parameters') .action( async ( - language: string | undefined, - client: string | undefined, + language: Language | 'all' | undefined, + client: string[], { verbose, interactive } ) => { language = await promptLanguage(language, interactive); @@ -166,31 +168,23 @@ buildCommand .command('specs') .description('Build a specified spec') .addArgument( - new Argument('[client]', 'The client').choices(['all'].concat(CLIENTS)) - ) - .addArgument( - new Argument('[output-format]', 'The output format').choices([ - 'yml', - 'json', - ]) + new Argument('[client...]', 'The client').choices(['all'].concat(CLIENTS)) ) .option('-v, --verbose', 'make the verification verbose') .option('-i, --interactive', 'open prompt to query parameters') .option('-s, --skip-cache', 'skip cache checking to force building specs') + .option('-json, --output-json', 'outputs the spec in JSON instead of yml') .action( async ( - client: string | undefined, - outputFormat: 'json' | 'yml' | undefined, - { verbose, interactive, skipCache } + client: string[], + { verbose, interactive, skipCache, outputJson } ) => { client = await promptClient(client, interactive); - if (!outputFormat) { - outputFormat = 'yml'; - } + const outputFormat = outputJson ? 'json' : 'yml'; - let clientsTodo = [client]; - if (client === 'all') { + let clientsTodo = client; + if (client === ['all']) { clientsTodo = CLIENTS; } // ignore cache when building from cli @@ -209,14 +203,14 @@ ctsCommand ) ) .addArgument( - new Argument('[client]', 'The client').choices(['all'].concat(CLIENTS)) + new Argument('[client...]', 'The client').choices(['all'].concat(CLIENTS)) ) .option('-v, --verbose', 'make the generation verbose') .option('-i, --interactive', 'open prompt to query parameters') .action( async ( - language: string | undefined, - client: string | undefined, + language: Language | 'all' | undefined, + client: string[], { verbose, interactive } ) => { language = await promptLanguage(language, interactive); @@ -239,15 +233,20 @@ ctsCommand ) .option('-v, --verbose', 'make the generation verbose') .option('-i, --interactive', 'open prompt to query parameters') - .action(async (language: string | undefined, { verbose, interactive }) => { - language = await promptLanguage(language, interactive); + .action( + async ( + language: Language | 'all' | undefined, + { verbose, interactive } + ) => { + language = await promptLanguage(language, interactive); - let langsTodo = [language]; - if (language === 'all') { - langsTodo = LANGUAGES; + let langsTodo = [language]; + if (language === 'all') { + langsTodo = LANGUAGES; + } + await runCts(langsTodo, Boolean(verbose)); } - await runCts(langsTodo, Boolean(verbose)); - }); + ); program .command('playground') @@ -259,12 +258,12 @@ program .option('-i, --interactive', 'open prompt to query parameters') .action( async ( - language: string | undefined, - client: string | undefined, + language: Language | 'all' | undefined, + client: string, { interactive } ) => { language = await promptLanguage(language, interactive); - client = await promptClient(client, interactive); + client = (await promptClient([client], interactive))[0]; await playground({ language, diff --git a/scripts/playground.ts b/scripts/playground.ts index b7fd67eb13..65c7d402dd 100644 --- a/scripts/playground.ts +++ b/scripts/playground.ts @@ -1,10 +1,13 @@ import { run } from './common'; -import type { Generator } from './types'; +import type { Language } from './types'; export async function playground({ language, client, -}: Pick): Promise { +}: { + language: Language | 'all'; + client: string; +}): Promise { const verbose = true; switch (language) { case 'javascript': diff --git a/scripts/release/__tests__/process-release.test.ts b/scripts/release/__tests__/process-release.test.ts index a996f31a15..9b5dd78d55 100644 --- a/scripts/release/__tests__/process-release.test.ts +++ b/scripts/release/__tests__/process-release.test.ts @@ -13,10 +13,10 @@ describe('process release', () => { `); expect(Object.keys(versions)).toEqual(['javascript', 'php']); - expect(versions.javascript.current).toEqual('1.0.0'); - expect(versions.javascript.releaseType).toEqual('minor'); - expect(versions.php.current).toEqual('2.0.0'); - expect(versions.php.releaseType).toEqual('patch'); + expect(versions.javascript?.current).toEqual('1.0.0'); + expect(versions.javascript?.releaseType).toEqual('minor'); + expect(versions.php?.current).toEqual('2.0.0'); + expect(versions.php?.releaseType).toEqual('patch'); }); it('parses issue body correctly', () => { diff --git a/scripts/release/process-release.ts b/scripts/release/process-release.ts index 17d40ed0ad..35f744b3da 100755 --- a/scripts/release/process-release.ts +++ b/scripts/release/process-release.ts @@ -5,7 +5,6 @@ import dotenv from 'dotenv'; import execa from 'execa'; import { copy } from 'fs-extra'; import semver from 'semver'; -import type { ReleaseType } from 'semver'; import openapiConfig from '../../config/openapitools.json'; import { @@ -20,6 +19,7 @@ import { emptyDirExceptForDotGit, } from '../common'; import { getLanguageFolder } from '../config'; +import type { Language } from '../types'; import { RELEASED_TAG, @@ -40,7 +40,7 @@ import type { dotenv.config({ path: ROOT_ENV_PATH }); const BEFORE_CLIENT_GENERATION: { - [lang: string]: BeforeClientGenerationCommand; + [lang in Language]?: BeforeClientGenerationCommand; } = { javascript: async ({ releaseType, dir }) => { await run(`yarn release:bump ${releaseType}`, { cwd: dir }); @@ -94,7 +94,7 @@ export function getVersionsToRelease(issueBody: string): VersionsToRelease { } versionsToRelease[lang] = { current, - releaseType: releaseType as ReleaseType, + releaseType, }; }); @@ -104,11 +104,16 @@ export function getVersionsToRelease(issueBody: string): VersionsToRelease { async function updateOpenApiTools( versionsToRelease: VersionsToRelease ): Promise { - const nextUtilsPackageVersion = semver.inc( - openapiConfig['generator-cli'].generators[MAIN_PACKAGE.javascript] - .additionalProperties.utilsPackageVersion, - versionsToRelease.javascript?.releaseType - ); + let nextUtilsPackageVersion = ''; + + if (versionsToRelease.javascript) { + nextUtilsPackageVersion = + semver.inc( + openapiConfig['generator-cli'].generators[MAIN_PACKAGE.javascript] + .additionalProperties.utilsPackageVersion, + versionsToRelease.javascript.releaseType + ) || ''; + } Object.keys(openapiConfig['generator-cli'].generators).forEach((client) => { const lang = client.split('-')[0]; @@ -148,7 +153,7 @@ async function updateChangelog({ current, next, }: { - lang: string; + lang: Language; issueBody: string; current: string; next: string; @@ -222,10 +227,9 @@ async function processRelease(): Promise { await updateOpenApiTools(versionsToRelease); - const langsToRelease = Object.keys(versionsToRelease); - - for (const lang of langsToRelease) { - const { current, releaseType } = versionsToRelease[lang]; + for (const [lang, { current, releaseType }] of Object.entries( + versionsToRelease + )) { /* About bumping versions of JS clients: @@ -240,7 +244,7 @@ async function processRelease(): Promise { */ await BEFORE_CLIENT_GENERATION[lang]?.({ releaseType, - dir: toAbsolutePath(getLanguageFolder(lang)), + dir: toAbsolutePath(getLanguageFolder(lang as Language)), }); console.log(`Generating ${lang} client(s)...`); @@ -248,7 +252,7 @@ async function processRelease(): Promise { const next = semver.inc(current, releaseType); await updateChangelog({ - lang, + lang: lang as Language, issueBody, current, next: next!, @@ -257,14 +261,16 @@ async function processRelease(): Promise { // We push commits to each repository AFTER all the generations are done. // Otherwise, we will end up having broken release. - for (const lang of langsToRelease) { + for (const [lang, { current, releaseType }] of Object.entries( + versionsToRelease + )) { const { tempGitDir } = await cloneRepository({ lang, githubToken: process.env.GITHUB_TOKEN, tempDir: process.env.RUNNER_TEMP!, }); - const clientPath = toAbsolutePath(getLanguageFolder(lang)); + const clientPath = toAbsolutePath(getLanguageFolder(lang as Language)); await emptyDirExceptForDotGit(tempGitDir); await copy(clientPath, tempGitDir, { preserveTimestamps: true }); @@ -274,7 +280,6 @@ async function processRelease(): Promise { }); await run(`git add .`, { cwd: tempGitDir }); - const { current, releaseType } = versionsToRelease[lang]; const next = semver.inc(current, releaseType); const tag = formatGitTag({ lang, version: next! }); await gitCommit({ diff --git a/scripts/release/types.ts b/scripts/release/types.ts index f99f20fe84..56097d644e 100644 --- a/scripts/release/types.ts +++ b/scripts/release/types.ts @@ -31,7 +31,7 @@ export type Commit = | { error: 'unknown-language-scope' }; export type VersionsToRelease = { - [lang: string]: { + [lang in Language]?: { current: string; releaseType: ReleaseType; }; diff --git a/scripts/types.ts b/scripts/types.ts index b4b5a03d20..8e1ec44d99 100644 --- a/scripts/types.ts +++ b/scripts/types.ts @@ -1,7 +1,7 @@ import type config from '../config/clients.config.json'; export type Generator = Record & { - language: string; + language: Language; client: string; key: string; additionalProperties: AdditionalProperties; diff --git a/templates/javascript/api-single.mustache b/templates/javascript/api-single.mustache index 8409110960..a5d2c4f6dc 100644 --- a/templates/javascript/api-single.mustache +++ b/templates/javascript/api-single.mustache @@ -122,7 +122,7 @@ export function create{{capitalizedApiName}}(options: CreateClientOptions{{#hasR {{^bodyParams.0}} * @param {{nickname}} - The {{nickname}} object. {{#allParams}} - * @param {{nickname}}.{{paramName}} {{^description}}The {{paramName}} object.{{/description}}{{#description}}{{{description}}}{{/description}} + * @param {{nickname}}.{{paramName}} - {{^description}}The {{paramName}} object.{{/description}}{{#description}}{{{description}}}{{/description}} {{/allParams}} {{/bodyParams.0}} {{#bodyParams.0}} @@ -132,25 +132,25 @@ export function create{{capitalizedApiName}}(options: CreateClientOptions{{#hasR {{^bodyParams.1}} * @param {{nickname}} - The {{nickname}} object. {{#allParams}} - * @param {{nickname}}.{{paramName}} {{^description}}The {{paramName}} object.{{/description}}{{#description}}{{{description}}}{{/description}} + * @param {{nickname}}.{{paramName}} - {{^description}}The {{paramName}} object.{{/description}}{{#description}}{{{description}}}{{/description}} {{/allParams}} {{/bodyParams.1}} {{/bodyParams.0.isArray}} {{^bodyParams.0.isArray}} - * @param {{paramName}} {{^description}}The {{paramName}} object.{{/description}}{{#description}}{{{description}}}{{/description}} + * @param {{paramName}} - {{^description}}The {{paramName}} object.{{/description}}{{#description}}{{{description}}}{{/description}} {{/bodyParams.0.isArray}} {{/pathParams.0}} {{#pathParams.0}} * @param {{nickname}} - The {{nickname}} object. {{#allParams}} - * @param {{nickname}}.{{paramName}} {{^description}}The {{paramName}} object.{{/description}}{{#description}}{{{description}}}{{/description}} + * @param {{nickname}}.{{paramName}} - {{^description}}The {{paramName}} object.{{/description}}{{#description}}{{{description}}}{{/description}} {{/allParams}} {{/pathParams.0}} {{/queryParams.0}} {{#queryParams.0}} * @param {{nickname}} - The {{nickname}} object. {{#allParams}} - * @param {{nickname}}.{{paramName}} {{^description}}The {{paramName}} object.{{/description}}{{#description}}{{{description}}}{{/description}} + * @param {{nickname}}.{{paramName}} - {{^description}}The {{paramName}} object.{{/description}}{{#description}}{{{description}}}{{/description}} {{/allParams}} {{/queryParams.0}} {{/bodyParams.0}}