diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..d13affe361 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Ensure all Java files use LF. +*.java eol=lf diff --git a/.github/workflows/daily-build-2201.3.x.yml b/.github/workflows/daily-build-2201.3.x.yml index f24274e414..ad03327d82 100644 --- a/.github/workflows/daily-build-2201.3.x.yml +++ b/.github/workflows/daily-build-2201.3.x.yml @@ -13,11 +13,11 @@ jobs: steps: - name: Checkout Repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: ref: 2201.3.x - name: Set up JDK 11 - uses: actions/setup-java@v2 + uses: actions/setup-java@v3 with: distribution: 'temurin' java-version: '11' @@ -125,7 +125,7 @@ jobs: env: TEST_MODE_ACTIVE: true - name: Checkout docker repo - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: repository: ballerina-platform/module-ballerina-docker path: module-ballerina-docker diff --git a/.github/workflows/daily-build-2201.4.x.yml b/.github/workflows/daily-build-2201.4.x.yml index 700e1938cc..4d4fe88564 100644 --- a/.github/workflows/daily-build-2201.4.x.yml +++ b/.github/workflows/daily-build-2201.4.x.yml @@ -13,11 +13,11 @@ jobs: steps: - name: Checkout Repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: ref: 2201.4.x - name: Set up JDK 11 - uses: actions/setup-java@v2 + uses: actions/setup-java@v3 with: distribution: 'temurin' java-version: '11' @@ -125,7 +125,7 @@ jobs: env: TEST_MODE_ACTIVE: true - name: Checkout docker repo - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: repository: ballerina-platform/module-ballerina-docker path: module-ballerina-docker @@ -221,11 +221,11 @@ jobs: steps: - name: Checkout Repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: ref: 2201.4.x - name: Set up JDK 11 - uses: actions/setup-java@v2 + uses: actions/setup-java@v3 with: distribution: 'temurin' java-version: '11' diff --git a/.github/workflows/daily-build-2201.5.x.yml b/.github/workflows/daily-build-2201.5.x.yml index 74ca8ec155..bf1d4dbd31 100644 --- a/.github/workflows/daily-build-2201.5.x.yml +++ b/.github/workflows/daily-build-2201.5.x.yml @@ -13,11 +13,11 @@ jobs: steps: - name: Checkout Repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: ref: 2201.5.x - name: Set up JDK 11 - uses: actions/setup-java@v2 + uses: actions/setup-java@v3 with: distribution: 'temurin' java-version: '11' diff --git a/.github/workflows/daily-build-2201.6.x.yml b/.github/workflows/daily-build-2201.6.x.yml index 95c951995f..5568f81747 100644 --- a/.github/workflows/daily-build-2201.6.x.yml +++ b/.github/workflows/daily-build-2201.6.x.yml @@ -13,11 +13,11 @@ jobs: steps: - name: Checkout Repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: ref: 2201.6.x - name: Set up JDK 11 - uses: actions/setup-java@v2 + uses: actions/setup-java@v3 with: distribution: 'temurin' java-version: '11' @@ -130,7 +130,7 @@ jobs: env: TEST_MODE_ACTIVE: true - name: Checkout docker repo - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: repository: ballerina-platform/module-ballerina-docker path: module-ballerina-docker diff --git a/.github/workflows/daily-build-2201.7.x.yml b/.github/workflows/daily-build-2201.7.x.yml new file mode 100644 index 0000000000..5e6efca2fc --- /dev/null +++ b/.github/workflows/daily-build-2201.7.x.yml @@ -0,0 +1,475 @@ +name: Daily build (2201.7.x) + +on: + workflow_dispatch: + schedule: + - cron: '0 2 * * *' # 07:30 in LK time (GMT+5:30) + +jobs: + ubuntu-build: + + runs-on: ubuntu-latest + if: github.repository_owner == 'ballerina-platform' + + steps: + - name: Checkout Repository + uses: actions/checkout@v3 + with: + ref: 2201.7.x + - name: Set up JDK 11 + uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: '11' + - name: Get daily docker version + id: version + run: echo "::set-output name=version::$(date +'%Y-%m-%d')" + - name: Get project version + id: project-version + run: | + SHORT_VERSION=$((grep -w "version" | cut -d= -f2 | cut -d- -f1 | xargs) < gradle.properties) + DIST_VERSION=$((grep -w "version" | cut -d= -f2 | xargs) < gradle.properties) + LANG_VERSION=$((grep -w "ballerinaLangVersion" | cut -d= -f2 | cut -d- -f1 | xargs) < gradle.properties) + CODE_NAME=$((grep -w 'codeName' | cut -d= -f2) < gradle.properties) + RELEASE_VERSION=$DIST_VERSION-$CODE_NAME + echo "::set-output name=version::$RELEASE_VERSION" + echo "::set-output name=sversion::$SHORT_VERSION" + echo "::set-output name=langversion::$LANG_VERSION" + - name: Build with Gradle + env: + packageUser: ${{ github.actor }} + packagePAT: ${{ secrets.GITHUB_TOKEN }} + devCentralToken: ${{ secrets.BALLERINA_DEV_CENTRAL_ACCESS_TOKEN }} + ballerinaBotWorkflow: $ {{ secrets.BALLERINA_BOT_WORKFLOW }} + TEST_MODE_ACTIVE: true + run: ./gradlew clean build --stacktrace --scan --console=plain --no-daemon --continue -x project-api-tests:test + - name: Create linux-deb + id: run_installers_deb + run: | + cd installers/linux-deb + ./build-ballerina-linux-deb-x64.sh -v ${{ steps.project-version.outputs.version }} -p ./../../ballerina/build/distributions + echo "Created linux-deb successfully" + - name: Create linux-rpm + id: run_installers_rpm + run: | + cd installers/linux-rpm + ./build-ballerina-linux-rpm-x64.sh -v ${{ steps.project-version.outputs.version }} -p ./../../ballerina/build/distributions + echo "Created linux-rpm successfully" + - name: Generate Hashes + run: | + openssl dgst -sha256 -out ballerina-${{ steps.project-version.outputs.version }}-linux-x64.deb.sha256 installers/linux-deb/target/ballerina-*-linux-x64.deb + openssl dgst -sha256 -out ballerina-${{ steps.project-version.outputs.version }}-linux-x64.rpm.sha256 installers/linux-rpm/rpmbuild/RPMS/x86_64/ballerina-*-linux-x64.rpm + openssl dgst -sha256 -out ballerina-${{ steps.project-version.outputs.version }}.zip.sha256 ballerina/build/distributions/ballerina-${{ steps.project-version.outputs.version }}.zip + openssl dgst -sha256 -out ballerina-${{ steps.project-version.outputs.sversion }}.zip.sha256 ballerina/build/distributions/ballerina-${{ steps.project-version.outputs.sversion }}.zip + - name: Archive Ballerina ZIP + uses: actions/upload-artifact@v2 + with: + name: Ballerina ZIP + path: ballerina/build/distributions/ballerina-*-swan-lake.zip + - name: Archive Ballerina Short Name ZIP + uses: actions/upload-artifact@v2 + with: + name: Ballerina Short Name ZIP + path: ballerina/build/distributions/ballerina-${{ steps.project-version.outputs.sversion }}.zip + - name: Archive Linux deb + uses: actions/upload-artifact@v2 + with: + name: Linux Installer deb + path: installers/linux-deb/target/ballerina-*-linux-x64.deb + - name: Archive Linux rpm + uses: actions/upload-artifact@v2 + with: + name: Linux Installer rpm + path: installers/linux-rpm/rpmbuild/RPMS/x86_64/ballerina-*-linux-x64.rpm + - name: Archive MacOS Installer ZIP + uses: actions/upload-artifact@v2 + with: + name: MacOS Installer ZIP + path: ballerina/build/distributions/ballerina-*-macos.zip + - name: Archive MacOS-ARM Installer ZIP + uses: actions/upload-artifact@v2 + with: + name: MacOS-ARM Installer ZIP + path: ballerina/build/distributions/ballerina-*-macos-arm.zip + - name: Archive Windows Installer ZIP + uses: actions/upload-artifact@v2 + with: + name: Windows Installer ZIP + path: ballerina/build/distributions/ballerina-*-windows.zip + - name: Archive Linux deb Hashes + uses: actions/upload-artifact@v2 + with: + name: Linux deb Hashes + path: ballerina-${{ steps.project-version.outputs.version }}-linux-x64.deb.sha256 + - name: Archive Linux rpm Hashes + uses: actions/upload-artifact@v2 + with: + name: Linux rpm Hashes + path: ballerina-${{ steps.project-version.outputs.version }}-linux-x64.rpm.sha256 + - name: Archive Ballerina Zip Hashes + uses: actions/upload-artifact@v2 + with: + name: Ballerina Zip Hashes + path: ballerina-${{ steps.project-version.outputs.version }}.zip.sha256 + - name: Archive Ballerina Short Name Hashes + uses: actions/upload-artifact@v2 + with: + name: Ballerina Short Name Hashes + path: ballerina-${{ steps.project-version.outputs.sversion }}.zip.sha256 + - name: Install Ballerina DEB + run: sudo dpkg -i installers/linux-deb/target/ballerina-*-linux-x64.deb + - name: Update Installer Test Configs + run: | + DISPLAY_TEXT=${{ steps.project-version.outputs.langversion }} + SWAN_LAKE_LATEST_VERSION="swan-lake-"+$DISPLAY_TEXT + perl -pi -e "s/^\s*swan-lake-latest-version-display-text=.*/swan-lake-latest-version-display-text=$DISPLAY_TEXT/" ballerina-test-automation/gradle.properties + perl -pi -e "s/^\s*swan-lake-latest-version=.*/swan-lake-latest-version=$SWAN_LAKE_LATEST_VERSION/" ballerina-test-automation/gradle.properties + - name: Run Installer Tests + working-directory: ./ballerina-test-automation/installer-test + run: ./../gradlew build --stacktrace -scan --console=plain --no-daemon -DballerinaInstalled=true + env: + TEST_MODE_ACTIVE: true + - name: Checkout docker repo + uses: actions/checkout@v3 + with: + repository: ballerina-platform/module-ballerina-docker + path: module-ballerina-docker + - name: Copy zip artifact + run: cp ballerina/build/distributions/ballerina-22*.zip module-ballerina-docker/base/docker/ + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKER_HUB_USER }} + password: ${{ secrets.DOCKER_HUB_TOKEN }} + - name: Build the docker image + id: docker_build + uses: docker/build-push-action@v2 + with: + context: module-ballerina-docker/base/docker/ + load: true + push: false + tags: ballerina/ballerina:nightly-test + build-args: | + BALLERINA_DIST=ballerina-${{ steps.project-version.outputs.sversion }}.zip + - name: Run Trivy vulnerability scanner + uses: aquasecurity/trivy-action@master + with: + image-ref: 'ballerina/ballerina:nightly-test' + skip-dirs: 'ballerina/runtime/examples' + format: 'table' + exit-code: '1' + timeout: "10m0s" + - name: Build and push + uses: docker/build-push-action@v2 + with: + context: module-ballerina-docker/base/docker/ + push: true + tags: ballerina/ballerina:nightly-2201.7.x + build-args: | + BALLERINA_DIST=ballerina-${{ steps.project-version.outputs.sversion }}.zip + - name: Image digest + run: echo ${{ steps.docker_build.outputs.digest }} + - name: Copy deb artifact + run: cp installers/linux-deb/target/ballerina-*-linux-x64.deb module-ballerina-docker/base/devcontainer/ + - name: Build the dev container docker image + id: docker_build_devcontainer + uses: docker/build-push-action@v2 + with: + context: module-ballerina-docker/base/devcontainer/ + load: true + push: false + tags: ballerina/ballerina-devcontainer:nightly-test + build-args: | + BALLERINA_DIST=ballerina-${{ steps.project-version.outputs.version }}-linux-x64.deb + - name: Run Trivy vulnerability scanner for dev container docker image + uses: aquasecurity/trivy-action@master + with: + image-ref: 'ballerina/ballerina-devcontainer:nightly-test' + skip-dirs: 'ballerina/runtime/examples' + format: 'table' + exit-code: '1' + timeout: "10m0s" + - name: Build and push dev container image + uses: docker/build-push-action@v2 + with: + context: module-ballerina-docker/base/devcontainer/ + push: true + tags: ballerina/ballerina-devcontainer:nightly-2201.7.x + build-args: | + BALLERINA_DIST=ballerina-${{ steps.project-version.outputs.version }}-linux-x64.deb + - name: Notify failure + if: ${{ failure() }} + run: | + curl -X POST \ + 'https://api.github.com/repos/ballerina-platform/ballerina-release/dispatches' \ + -H 'Accept: application/vnd.github.v3+json' \ + -H 'Authorization: Bearer ${{ secrets.BALLERINA_BOT_TOKEN }}' \ + --data "{ + \"event_type\": \"notify-build-failure\", + \"client_payload\": { + \"repoName\": \"ballerina-distribution\", + \"branch\": \"2201.7.x\" + } + }" + outputs: + project-version: ${{ steps.project-version.outputs.version }} + lang-version: ${{ steps.project-version.outputs.langversion }} + + project-api-tests: + + runs-on: ubuntu-latest + if: github.repository_owner == 'ballerina-platform' + + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + with: + ref: 2201.7.x + - name: Set up JDK 11 + uses: actions/setup-java@v2 + with: + distribution: 'temurin' + java-version: '11' + - name: Build with Gradle + env: + packageUser: ${{ github.actor }} + packagePAT: ${{ secrets.GITHUB_TOKEN }} + devCentralToken: ${{ secrets.BALLERINA_DEV_CENTRAL_ACCESS_TOKEN }} + ballerinaBotWorkflow: $ {{ secrets.BALLERINA_BOT_WORKFLOW }} + TEST_MODE_ACTIVE: true + run: ./gradlew :project-api-tests:test --stacktrace --scan --console=plain --no-daemon --continue + + windows-build: + + runs-on: windows-latest + if: github.repository_owner == 'ballerina-platform' + + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + with: + ref: 2201.7.x + - name: Set up JDK 11 + uses: actions/setup-java@v2 + with: + distribution: 'temurin' + java-version: '11' + - name: Build with Gradle + env: + packageUser: ${{ github.actor }} + packagePAT: ${{ secrets.GITHUB_TOKEN }} + devCentralToken: ${{ secrets.BALLERINA_DEV_CENTRAL_ACCESS_TOKEN }} + ballerinaBotWorkflow: $ {{ secrets.BALLERINA_BOT_WORKFLOW }} + TEST_MODE_ACTIVE: true + run: ./gradlew.bat clean build --stacktrace --scan --console=plain --no-daemon -x test + + ubuntu-rpm-installer-test: + needs: ubuntu-build + runs-on: ubuntu-latest + container: centos:latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + with: + ref: 2201.7.x + - name: Set up JDK 11 + uses: actions/setup-java@v2 + with: + distribution: 'temurin' + java-version: '11' + - name: Setup Files + run: | + cd /etc/yum.repos.d/ + sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* + sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-* + - name: Download Ballerina rpm Installer + uses: actions/download-artifact@v2 + with: + name: Linux Installer rpm + - name: Install Ballerina RPM + run: | + rpm -ivh ballerina-*-linux-x64.rpm + - name: Update Installer Test Configs + run: | + DISPLAY_TEXT=${{ needs.ubuntu-build.outputs.lang-version }} + SWAN_LAKE_LATEST_VERSION="swan-lake-"+$DISPLAY_TEXT + sed -i -e "s/swan-lake-latest-version-display-text=.*/swan-lake-latest-version-display-text=$DISPLAY_TEXT/" ballerina-test-automation/gradle.properties + sed -i -e "s/swan-lake-latest-version=.*/swan-lake-latest-version=$SWAN_LAKE_LATEST_VERSION/" ballerina-test-automation/gradle.properties + - name: Run Installer Tests + working-directory: ./ballerina-test-automation/installer-test + run: ./../gradlew build --stacktrace -scan --console=plain --no-daemon -DballerinaInstalled=true + env: + TEST_MODE_ACTIVE: true + + macos-installer-build: + + needs: ubuntu-build + runs-on: macos-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + with: + ref: 2201.7.x + - name: Download MacOS Intaller Zip + uses: actions/download-artifact@v2 + with: + name: MacOS Installer ZIP + - name: Create macos-pkg + id: run_installers_pkg + run: | + cd installers/mac + ./build-ballerina-macos-x64.sh -v ${{ needs.ubuntu-build.outputs.project-version }} -p ./../../ + echo "Created macos-pkg successfully" + - name: Generate Hashes + run: | + openssl dgst -sha256 -out ballerina-${{ needs.ubuntu-build.outputs.project-version }}-macos-x64.pkg.sha256 installers/mac/target/pkg/ballerina-*-macos-x64.pkg + - name: Archive MacOS pkg Hashes + uses: actions/upload-artifact@v2 + with: + name: MacOS pkg Hashes + path: ballerina-${{ needs.ubuntu-build.outputs.project-version }}-macos-x64.pkg.sha256 + - name: Archive MacOS pkg + uses: actions/upload-artifact@v2 + with: + name: MacOS Installer pkg + path: installers/mac/target/pkg/ballerina-*-macos-x64.pkg + - name: Install Ballerina PKG + run: sudo installer -pkg installers/mac/target/pkg/ballerina-*-macos-x64.pkg -target / + - name: Update Installer Test Configs + run: | + DISPLAY_TEXT=${{ needs.ubuntu-build.outputs.lang-version }} + SWAN_LAKE_LATEST_VERSION="swan-lake-"+$DISPLAY_TEXT + perl -pi -e "s/^\s*swan-lake-latest-version-display-text=.*/swan-lake-latest-version-display-text=$DISPLAY_TEXT/" ballerina-test-automation/gradle.properties + perl -pi -e "s/^\s*swan-lake-latest-version=.*/swan-lake-latest-version=$SWAN_LAKE_LATEST_VERSION/" ballerina-test-automation/gradle.properties + - name: Run Installer Tests + working-directory: ./ballerina-test-automation/installer-test + run: ./../gradlew build --stacktrace -scan --console=plain --no-daemon -DballerinaInstalled=true + env: + TEST_MODE_ACTIVE: true + + macos-arm-installer-build: + + needs: ubuntu-build + runs-on: macos-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + - name: Set up JDK 11 + uses: actions/setup-java@v2 + with: + distribution: 'temurin' + java-version: '11' + - name: Download MacOS-ARM Intaller Zip + uses: actions/download-artifact@v2 + with: + name: MacOS-ARM Installer ZIP + - name: Create macos-arm-pkg + id: run_installers_arm_pkg + run: | + cd installers/mac + ./build-ballerina-macos-x64.sh -v ${{ needs.ubuntu-build.outputs.project-version }} -p ./../../ -a arm + echo "Created macos-arm-pkg successfully" + - name: Generate Hashes + run: | + openssl dgst -sha256 -out ballerina-${{ needs.ubuntu-build.outputs.project-version }}-macos-arm-x64.pkg.sha256 installers/mac/target/pkg/ballerina-*-macos-arm-x64.pkg + - name: Archive MacOS-ARM pkg Hashes + uses: actions/upload-artifact@v2 + with: + name: MacOS-ARM pkg Hashes + path: ballerina-${{ needs.ubuntu-build.outputs.project-version }}-macos-arm-x64.pkg.sha256 + - name: Archive MacOS-ARM pkg + uses: actions/upload-artifact@v2 + with: + name: MacOS Installer ARM pkg + path: installers/mac/target/pkg/ballerina-*-macos-arm-x64.pkg + + windows-installer-build: + + needs: ubuntu-build + runs-on: windows-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + with: + ref: 2201.7.x + - uses: actions/setup-dotnet@v1 + with: + dotnet-version: '2.1.x' + - name: Install GUID Generator + run: dotnet tool install -g dotnet-guid --version 0.5.2 + - name: Download Windows Intaller Zip + uses: actions/download-artifact@v2 + with: + name: Windows Installer ZIP + - name: Create windows-msi + id: run_installers_msi + run: | + $env:Path += ";C:\Program Files (x86)\WiX Toolset v3.11\bin" + move installers\windows .\ + ren windows w + cd w + .\build-ballerina-windows-x64.bat --version ${{ needs.ubuntu-build.outputs.project-version }} --path .\..\ + echo "Created windows-msi successfully" + - name: Generate Hashes + run: | + openssl dgst -sha256 -out ballerina-${{ needs.ubuntu-build.outputs.project-version }}-windows-x64.msi.sha256 w\target\msi\ballerina-*-windows-x64.msi + - name: Archive Windows msi Hashes + uses: actions/upload-artifact@v2 + with: + name: Windows msi Hashes + path: ballerina-${{ needs.ubuntu-build.outputs.project-version }}-windows-x64.msi.sha256 + - name: Archive Windows msi + uses: actions/upload-artifact@v2 + with: + name: Windows Installer msi + path: w\target\msi\ballerina-*-windows-x64.msi + - name: Install Ballerina msi + run: msiexec /i w\target\msi\ballerina-${{ needs.ubuntu-build.outputs.project-version }}-windows-x64.msi /quiet /qr + shell: cmd + - name: Update Installer Test Configs + run: | + set DISPLAY_TEXT=${{ needs.ubuntu-build.outputs.lang-version }} + set SWAN_LAKE_LATEST_VERSION=swan-lake-%DISPLAY_TEXT% + perl -pi -e "s/^\s*swan-lake-latest-version-display-text=.*/swan-lake-latest-version-display-text=%DISPLAY_TEXT%/" ballerina-test-automation/gradle.properties + perl -pi -e "s/^\s*swan-lake-latest-version=.*/swan-lake-latest-version=%SWAN_LAKE_LATEST_VERSION%/" ballerina-test-automation/gradle.properties + shell: cmd + - name: Run Installer Tests + working-directory: .\ballerina-test-automation\installer-test + run: | + $env:Path += ";C:\Program Files\Ballerina\bin" + .\..\gradlew build --stacktrace -scan --console=plain --no-daemon -DballerinaInstalled=true + env: + TEST_MODE_ACTIVE: true + + trigger-notifications: + + needs: [ubuntu-build, macos-installer-build, windows-installer-build] + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + with: + ref: 2201.7.x + - name: Invoke Connector Ballerina Version Bump + run: | + ballerinaVersion=$((grep -w 'ballerinaLangVersion' | cut -d= -f2) < gradle.properties) + echo "Triggering connectors dependency bumps..." && \ + curl -X POST \ + https://api.github.com/repos/ballerina-platform/ballerina-release/dispatches \ + -H 'Accept: application/vnd.github.v3+json' \ + -H 'Authorization: token ${{ secrets.BALLERINA_BOT_TOKEN }}' \ + --data "{ + \"event_type\": \"connector-update\", + \"client_payload\": { + \"ballerinaVersion\": \"$ballerinaVersion\" + } + }" diff --git a/.github/workflows/daily-build-2201.8.x.yml b/.github/workflows/daily-build-2201.8.x.yml new file mode 100644 index 0000000000..23a6fc5d29 --- /dev/null +++ b/.github/workflows/daily-build-2201.8.x.yml @@ -0,0 +1,480 @@ +name: Daily build (2201.8.x) + +on: + workflow_dispatch: + schedule: + - cron: '0 2 * * *' # 07:30 in LK time (GMT+5:30) + +jobs: + ubuntu-build: + + runs-on: ubuntu-latest + if: github.repository_owner == 'ballerina-platform' + + steps: + - name: Checkout Repository + uses: actions/checkout@v3 + with: + ref: 2201.8.x + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: '17.0.7' + - name: Get daily docker version + id: version + run: echo "::set-output name=version::$(date +'%Y-%m-%d')" + - name: Get project version + id: project-version + run: | + SHORT_VERSION=$((grep -w "version" | cut -d= -f2 | cut -d- -f1 | xargs) < gradle.properties) + DIST_VERSION=$((grep -w "version" | cut -d= -f2 | xargs) < gradle.properties) + LANG_VERSION=$((grep -w "ballerinaLangVersion" | cut -d= -f2 | cut -d- -f1 | xargs) < gradle.properties) + CODE_NAME=$((grep -w 'codeName' | cut -d= -f2) < gradle.properties) + RELEASE_VERSION=$DIST_VERSION-$CODE_NAME + echo "::set-output name=version::$RELEASE_VERSION" + echo "::set-output name=sversion::$SHORT_VERSION" + echo "::set-output name=langversion::$LANG_VERSION" + - name: Build with Gradle + env: + packageUser: ${{ github.actor }} + packagePAT: ${{ secrets.GITHUB_TOKEN }} + devCentralToken: ${{ secrets.BALLERINA_DEV_CENTRAL_ACCESS_TOKEN }} + ballerinaBotWorkflow: $ {{ secrets.BALLERINA_BOT_WORKFLOW }} + TEST_MODE_ACTIVE: true + run: ./gradlew clean build --stacktrace --scan --console=plain --no-daemon --continue -x project-api-tests:test + - name: Create linux-deb + id: run_installers_deb + run: | + cd installers/linux-deb + ./build-ballerina-linux-deb-x64.sh -v ${{ steps.project-version.outputs.version }} -p ./../../ballerina/build/distributions + echo "Created linux-deb successfully" + - name: Create linux-rpm + id: run_installers_rpm + run: | + cd installers/linux-rpm + ./build-ballerina-linux-rpm-x64.sh -v ${{ steps.project-version.outputs.version }} -p ./../../ballerina/build/distributions + echo "Created linux-rpm successfully" + - name: Generate Hashes + run: | + openssl dgst -sha256 -out ballerina-${{ steps.project-version.outputs.version }}-linux-x64.deb.sha256 installers/linux-deb/target/ballerina-*-linux-x64.deb + openssl dgst -sha256 -out ballerina-${{ steps.project-version.outputs.version }}-linux-x64.rpm.sha256 installers/linux-rpm/rpmbuild/RPMS/x86_64/ballerina-*-linux-x64.rpm + openssl dgst -sha256 -out ballerina-${{ steps.project-version.outputs.version }}.zip.sha256 ballerina/build/distributions/ballerina-${{ steps.project-version.outputs.version }}.zip + openssl dgst -sha256 -out ballerina-${{ steps.project-version.outputs.sversion }}.zip.sha256 ballerina/build/distributions/ballerina-${{ steps.project-version.outputs.sversion }}.zip + - name: Archive Ballerina ZIP + uses: actions/upload-artifact@v2 + with: + name: Ballerina ZIP + path: ballerina/build/distributions/ballerina-*-swan-lake.zip + - name: Archive Ballerina Short Name ZIP + uses: actions/upload-artifact@v2 + with: + name: Ballerina Short Name ZIP + path: ballerina/build/distributions/ballerina-${{ steps.project-version.outputs.sversion }}.zip + - name: Archive Linux deb + uses: actions/upload-artifact@v2 + with: + name: Linux Installer deb + path: installers/linux-deb/target/ballerina-*-linux-x64.deb + - name: Archive Linux rpm + uses: actions/upload-artifact@v2 + with: + name: Linux Installer rpm + path: installers/linux-rpm/rpmbuild/RPMS/x86_64/ballerina-*-linux-x64.rpm + - name: Archive MacOS Installer ZIP + uses: actions/upload-artifact@v2 + with: + name: MacOS Installer ZIP + path: ballerina/build/distributions/ballerina-*-macos.zip + - name: Archive MacOS-ARM Installer ZIP + uses: actions/upload-artifact@v2 + with: + name: MacOS-ARM Installer ZIP + path: ballerina/build/distributions/ballerina-*-macos-arm.zip + - name: Archive Windows Installer ZIP + uses: actions/upload-artifact@v2 + with: + name: Windows Installer ZIP + path: ballerina/build/distributions/ballerina-*-windows.zip + - name: Archive Linux deb Hashes + uses: actions/upload-artifact@v2 + with: + name: Linux deb Hashes + path: ballerina-${{ steps.project-version.outputs.version }}-linux-x64.deb.sha256 + - name: Archive Linux rpm Hashes + uses: actions/upload-artifact@v2 + with: + name: Linux rpm Hashes + path: ballerina-${{ steps.project-version.outputs.version }}-linux-x64.rpm.sha256 + - name: Archive Ballerina Zip Hashes + uses: actions/upload-artifact@v2 + with: + name: Ballerina Zip Hashes + path: ballerina-${{ steps.project-version.outputs.version }}.zip.sha256 + - name: Archive Ballerina Short Name Hashes + uses: actions/upload-artifact@v2 + with: + name: Ballerina Short Name Hashes + path: ballerina-${{ steps.project-version.outputs.sversion }}.zip.sha256 + - name: Install Ballerina DEB + run: sudo dpkg -i installers/linux-deb/target/ballerina-*-linux-x64.deb + - name: Update Installer Test Configs + run: | + DISPLAY_TEXT=${{ steps.project-version.outputs.langversion }} + SWAN_LAKE_LATEST_VERSION="swan-lake-"+$DISPLAY_TEXT + perl -pi -e "s/^\s*swan-lake-latest-version-display-text=.*/swan-lake-latest-version-display-text=$DISPLAY_TEXT/" ballerina-test-automation/gradle.properties + perl -pi -e "s/^\s*swan-lake-latest-version=.*/swan-lake-latest-version=$SWAN_LAKE_LATEST_VERSION/" ballerina-test-automation/gradle.properties + - name: Run Installer Tests + working-directory: ./ballerina-test-automation/installer-test + run: ./../gradlew build --stacktrace -scan --console=plain --no-daemon -DballerinaInstalled=true + env: + TEST_MODE_ACTIVE: true + - name: Checkout docker repo + uses: actions/checkout@v3 + with: + repository: ballerina-platform/module-ballerina-docker + path: module-ballerina-docker + - name: Copy zip artifact + run: cp ballerina/build/distributions/ballerina-22*.zip module-ballerina-docker/base/docker/ + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKER_HUB_USER }} + password: ${{ secrets.DOCKER_HUB_TOKEN }} + - name: Build the docker image + id: docker_build + uses: docker/build-push-action@v2 + with: + context: module-ballerina-docker/base/docker/ + load: true + push: false + tags: ballerina/ballerina:nightly-test + build-args: | + BALLERINA_DIST=ballerina-${{ steps.project-version.outputs.sversion }}.zip + - name: Run Trivy vulnerability scanner + uses: aquasecurity/trivy-action@master + with: + image-ref: 'ballerina/ballerina:nightly-test' + skip-dirs: 'ballerina/runtime/examples' + format: 'table' + exit-code: '1' + timeout: "10m0s" + - name: Build and push + uses: docker/build-push-action@v2 + with: + context: module-ballerina-docker/base/docker/ + push: true + tags: ballerina/ballerina:nightly-2201.8.x + build-args: | + BALLERINA_DIST=ballerina-${{ steps.project-version.outputs.sversion }}.zip + - name: Image digest + run: echo ${{ steps.docker_build.outputs.digest }} + - name: Copy deb artifact + run: cp installers/linux-deb/target/ballerina-*-linux-x64.deb module-ballerina-docker/base/devcontainer/ + - name: Build the dev container docker image + id: docker_build_devcontainer + uses: docker/build-push-action@v2 + with: + context: module-ballerina-docker/base/devcontainer/ + load: true + push: false + tags: ballerina/ballerina-devcontainer:nightly-test + build-args: | + BALLERINA_DIST=ballerina-${{ steps.project-version.outputs.version }}-linux-x64.deb + - name: Run Trivy vulnerability scanner for dev container docker image + uses: aquasecurity/trivy-action@master + with: + image-ref: 'ballerina/ballerina-devcontainer:nightly-test' + skip-dirs: 'ballerina/runtime/examples' + format: 'table' + exit-code: '1' + timeout: "10m0s" + - name: Build and push dev container image + uses: docker/build-push-action@v2 + with: + context: module-ballerina-docker/base/devcontainer/ + push: true + tags: ballerina/ballerina-devcontainer:nightly-2201.8.x + build-args: | + BALLERINA_DIST=ballerina-${{ steps.project-version.outputs.version }}-linux-x64.deb + - name: Notify failure + if: ${{ failure() }} + run: | + curl -X POST \ + 'https://api.github.com/repos/ballerina-platform/ballerina-release/dispatches' \ + -H 'Accept: application/vnd.github.v3+json' \ + -H 'Authorization: Bearer ${{ secrets.BALLERINA_BOT_TOKEN }}' \ + --data "{ + \"event_type\": \"notify-build-failure\", + \"client_payload\": { + \"repoName\": \"ballerina-distribution\", + \"branch\": \"2201.8.x\" + } + }" + outputs: + project-version: ${{ steps.project-version.outputs.version }} + lang-version: ${{ steps.project-version.outputs.langversion }} + + project-api-tests: + + runs-on: ubuntu-latest + if: github.repository_owner == 'ballerina-platform' + + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + with: + ref: 2201.8.x + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: '17.0.7' + - name: Build with Gradle + env: + packageUser: ${{ github.actor }} + packagePAT: ${{ secrets.GITHUB_TOKEN }} + devCentralToken: ${{ secrets.BALLERINA_DEV_CENTRAL_ACCESS_TOKEN }} + ballerinaBotWorkflow: $ {{ secrets.BALLERINA_BOT_WORKFLOW }} + TEST_MODE_ACTIVE: true + run: ./gradlew :project-api-tests:test --stacktrace --scan --console=plain --no-daemon --continue + + windows-build: + + runs-on: windows-latest + if: github.repository_owner == 'ballerina-platform' + + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + with: + ref: 2201.8.x + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: '17.0.7' + - name: Build with Gradle + env: + packageUser: ${{ github.actor }} + packagePAT: ${{ secrets.GITHUB_TOKEN }} + devCentralToken: ${{ secrets.BALLERINA_DEV_CENTRAL_ACCESS_TOKEN }} + ballerinaBotWorkflow: $ {{ secrets.BALLERINA_BOT_WORKFLOW }} + TEST_MODE_ACTIVE: true + run: ./gradlew.bat clean build --stacktrace --scan --console=plain --no-daemon -x test + + ubuntu-rpm-installer-test: + needs: ubuntu-build + runs-on: ubuntu-latest + container: centos:latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + with: + ref: 2201.8.x + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: '17.0.7' + - name: Setup Files + run: | + cd /etc/yum.repos.d/ + sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* + sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-* + - name: Download Ballerina rpm Installer + uses: actions/download-artifact@v2 + with: + name: Linux Installer rpm + - name: Install Ballerina RPM + run: | + rpm -ivh ballerina-*-linux-x64.rpm + - name: Update Installer Test Configs + run: | + DISPLAY_TEXT=${{ needs.ubuntu-build.outputs.lang-version }} + SWAN_LAKE_LATEST_VERSION="swan-lake-"+$DISPLAY_TEXT + sed -i -e "s/swan-lake-latest-version-display-text=.*/swan-lake-latest-version-display-text=$DISPLAY_TEXT/" ballerina-test-automation/gradle.properties + sed -i -e "s/swan-lake-latest-version=.*/swan-lake-latest-version=$SWAN_LAKE_LATEST_VERSION/" ballerina-test-automation/gradle.properties + - name: Run Installer Tests + working-directory: ./ballerina-test-automation/installer-test + run: ./../gradlew build --stacktrace -scan --console=plain --no-daemon -DballerinaInstalled=true + env: + TEST_MODE_ACTIVE: true + + macos-installer-build: + + needs: ubuntu-build + runs-on: macos-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + with: + ref: 2201.8.x + - name: Download MacOS Intaller Zip + uses: actions/download-artifact@v2 + with: + name: MacOS Installer ZIP + - name: Create macos-pkg + id: run_installers_pkg + run: | + cd installers/mac + ./build-ballerina-macos-x64.sh -v ${{ needs.ubuntu-build.outputs.project-version }} -p ./../../ + echo "Created macos-pkg successfully" + - name: Generate Hashes + run: | + openssl dgst -sha256 -out ballerina-${{ needs.ubuntu-build.outputs.project-version }}-macos-x64.pkg.sha256 installers/mac/target/pkg/ballerina-*-macos-x64.pkg + - name: Archive MacOS pkg Hashes + uses: actions/upload-artifact@v2 + with: + name: MacOS pkg Hashes + path: ballerina-${{ needs.ubuntu-build.outputs.project-version }}-macos-x64.pkg.sha256 + - name: Archive MacOS pkg + uses: actions/upload-artifact@v2 + with: + name: MacOS Installer pkg + path: installers/mac/target/pkg/ballerina-*-macos-x64.pkg + - name: Install Ballerina PKG + run: sudo installer -pkg installers/mac/target/pkg/ballerina-*-macos-x64.pkg -target / + - name: Update Installer Test Configs + run: | + DISPLAY_TEXT=${{ needs.ubuntu-build.outputs.lang-version }} + SWAN_LAKE_LATEST_VERSION="swan-lake-"+$DISPLAY_TEXT + perl -pi -e "s/^\s*swan-lake-latest-version-display-text=.*/swan-lake-latest-version-display-text=$DISPLAY_TEXT/" ballerina-test-automation/gradle.properties + perl -pi -e "s/^\s*swan-lake-latest-version=.*/swan-lake-latest-version=$SWAN_LAKE_LATEST_VERSION/" ballerina-test-automation/gradle.properties + - name: Run Installer Tests + working-directory: ./ballerina-test-automation/installer-test + run: ./../gradlew build --stacktrace -scan --console=plain --no-daemon -DballerinaInstalled=true + env: + TEST_MODE_ACTIVE: true + + macos-arm-installer-build: + + needs: ubuntu-build + runs-on: macos-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: '17.0.7' + - name: Download MacOS-ARM Intaller Zip + uses: actions/download-artifact@v2 + with: + name: MacOS-ARM Installer ZIP + - name: Create macos-arm-pkg + id: run_installers_arm_pkg + run: | + cd installers/mac + ./build-ballerina-macos-x64.sh -v ${{ needs.ubuntu-build.outputs.project-version }} -p ./../../ -a arm + echo "Created macos-arm-pkg successfully" + - name: Generate Hashes + run: | + openssl dgst -sha256 -out ballerina-${{ needs.ubuntu-build.outputs.project-version }}-macos-arm-x64.pkg.sha256 installers/mac/target/pkg/ballerina-*-macos-arm-x64.pkg + - name: Archive MacOS-ARM pkg Hashes + uses: actions/upload-artifact@v2 + with: + name: MacOS-ARM pkg Hashes + path: ballerina-${{ needs.ubuntu-build.outputs.project-version }}-macos-arm-x64.pkg.sha256 + - name: Archive MacOS-ARM pkg + uses: actions/upload-artifact@v2 + with: + name: MacOS Installer ARM pkg + path: installers/mac/target/pkg/ballerina-*-macos-arm-x64.pkg + + windows-installer-build: + + needs: ubuntu-build + runs-on: windows-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + with: + ref: 2201.8.x + - name: Set up JDK 17 + uses: actions/setup-java@v2 + with: + distribution: 'temurin' + java-version: '17.0.7' + - uses: actions/setup-dotnet@v1 + with: + dotnet-version: '2.1.x' + - name: Install GUID Generator + run: dotnet tool install -g dotnet-guid --version 0.5.2 + - name: Download Windows Intaller Zip + uses: actions/download-artifact@v2 + with: + name: Windows Installer ZIP + - name: Create windows-msi + id: run_installers_msi + run: | + $env:Path += ";C:\Program Files (x86)\WiX Toolset v3.11\bin" + move installers\windows .\ + ren windows w + cd w + .\build-ballerina-windows-x64.bat --version ${{ needs.ubuntu-build.outputs.project-version }} --path .\..\ + echo "Created windows-msi successfully" + - name: Generate Hashes + run: | + openssl dgst -sha256 -out ballerina-${{ needs.ubuntu-build.outputs.project-version }}-windows-x64.msi.sha256 w\target\msi\ballerina-*-windows-x64.msi + - name: Archive Windows msi Hashes + uses: actions/upload-artifact@v2 + with: + name: Windows msi Hashes + path: ballerina-${{ needs.ubuntu-build.outputs.project-version }}-windows-x64.msi.sha256 + - name: Archive Windows msi + uses: actions/upload-artifact@v2 + with: + name: Windows Installer msi + path: w\target\msi\ballerina-*-windows-x64.msi + - name: Install Ballerina msi + run: msiexec /i w\target\msi\ballerina-${{ needs.ubuntu-build.outputs.project-version }}-windows-x64.msi /quiet /qr + shell: cmd + - name: Update Installer Test Configs + run: | + set DISPLAY_TEXT=${{ needs.ubuntu-build.outputs.lang-version }} + set SWAN_LAKE_LATEST_VERSION=swan-lake-%DISPLAY_TEXT% + perl -pi -e "s/^\s*swan-lake-latest-version-display-text=.*/swan-lake-latest-version-display-text=%DISPLAY_TEXT%/" ballerina-test-automation/gradle.properties + perl -pi -e "s/^\s*swan-lake-latest-version=.*/swan-lake-latest-version=%SWAN_LAKE_LATEST_VERSION%/" ballerina-test-automation/gradle.properties + shell: cmd + - name: Run Installer Tests + working-directory: .\ballerina-test-automation\installer-test + run: | + $env:Path += ";C:\Program Files\Ballerina\bin" + .\..\gradlew build --stacktrace -scan --console=plain --no-daemon -DballerinaInstalled=true + env: + TEST_MODE_ACTIVE: true + + trigger-notifications: + + needs: [ubuntu-build, macos-installer-build, windows-installer-build] + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + with: + ref: 2201.8.x + - name: Invoke Connector Ballerina Version Bump + run: | + ballerinaVersion=$((grep -w 'ballerinaLangVersion' | cut -d= -f2) < gradle.properties) + echo "Triggering connectors dependency bumps..." && \ + curl -X POST \ + https://api.github.com/repos/ballerina-platform/ballerina-release/dispatches \ + -H 'Accept: application/vnd.github.v3+json' \ + -H 'Authorization: token ${{ secrets.BALLERINA_BOT_TOKEN }}' \ + --data "{ + \"event_type\": \"connector-update\", + \"client_payload\": { + \"ballerinaVersion\": \"$ballerinaVersion\" + } + }" diff --git a/.github/workflows/daily-build.yml b/.github/workflows/daily-build.yml index 5f5dd49008..d55b6e6b74 100644 --- a/.github/workflows/daily-build.yml +++ b/.github/workflows/daily-build.yml @@ -13,12 +13,12 @@ jobs: steps: - name: Checkout Repository - uses: actions/checkout@v2 - - name: Set up JDK 11 - uses: actions/setup-java@v2 + uses: actions/checkout@v3 + - name: Set up JDK 17 + uses: actions/setup-java@v3 with: distribution: 'temurin' - java-version: '11' + java-version: '17.0.7' - name: Get daily docker version id: version run: echo "::set-output name=version::$(date +'%Y-%m-%d')" @@ -225,11 +225,11 @@ jobs: steps: - name: Checkout Repository uses: actions/checkout@v2 - - name: Set up JDK 11 + - name: Set up JDK 17 uses: actions/setup-java@v2 with: distribution: 'temurin' - java-version: '11' + java-version: '17.0.7' - name: Build with Gradle env: packageUser: ${{ github.actor }} @@ -246,11 +246,11 @@ jobs: steps: - name: Checkout Repository uses: actions/checkout@v2 - - name: Set up JDK 11 + - name: Set up JDK 17 uses: actions/setup-java@v2 with: distribution: 'temurin' - java-version: '11' + java-version: '17.0.7' - name: Build with Gradle env: packageUser: ${{ github.actor }} @@ -268,11 +268,11 @@ jobs: steps: - name: Checkout Repository uses: actions/checkout@v2 - - name: Set up JDK 11 + - name: Set up JDK 17 uses: actions/setup-java@v2 with: distribution: 'temurin' - java-version: '11' + java-version: '17.0.7' - name: Setup Files run: | cd /etc/yum.repos.d/ @@ -305,11 +305,11 @@ jobs: steps: - name: Checkout Repository uses: actions/checkout@v2 - - name: Set up JDK 11 + - name: Set up JDK 17 uses: actions/setup-java@v2 with: distribution: 'temurin' - java-version: '11' + java-version: '17.0.7' - name: Download MacOS Intaller Zip uses: actions/download-artifact@v2 with: @@ -355,11 +355,11 @@ jobs: steps: - name: Checkout Repository uses: actions/checkout@v2 - - name: Set up JDK 11 + - name: Set up JDK 17 uses: actions/setup-java@v2 with: distribution: 'temurin' - java-version: '11' + java-version: '17.0.7' - name: Download MacOS-ARM Intaller Zip uses: actions/download-artifact@v2 with: @@ -392,11 +392,11 @@ jobs: steps: - name: Checkout Repository uses: actions/checkout@v2 - - name: Set up JDK 11 + - name: Set up JDK 17 uses: actions/setup-java@v2 with: distribution: 'temurin' - java-version: '11' + java-version: '17.0.7' - uses: actions/setup-dotnet@v1 with: dotnet-version: '2.1.x' diff --git a/.github/workflows/fossa_scan.yml b/.github/workflows/fossa_scan.yml new file mode 100644 index 0000000000..651f73a635 --- /dev/null +++ b/.github/workflows/fossa_scan.yml @@ -0,0 +1,16 @@ +name: Fossa Scan +on: + workflow_dispatch: + schedule: + - cron: '30 18 * * *' # 00:00 in LK time (GMT+5:30) +jobs: + fossa-scan: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: fossas/fossa-action@main + env: + packageUser: ${{ secrets.BALLERINA_BOT_USERNAME }} + packagePAT: ${{ secrets.BALLERINA_BOT_TOKEN }} + with: + api-key: ${{secrets.FOSSA_APIKEY}} diff --git a/.github/workflows/language_server_simulator_fhir.yml b/.github/workflows/language_server_simulator_fhir.yml new file mode 100644 index 0000000000..ac7cd8b4d4 --- /dev/null +++ b/.github/workflows/language_server_simulator_fhir.yml @@ -0,0 +1,82 @@ +name: Language Server Simulator on FHIR + +on: + schedule: + - cron: '0 */12 * * *' + workflow_dispatch: + +jobs: + run_simulator: + name: Run LS Simulator + runs-on: ubuntu-latest + timeout-minutes: 240 + strategy: + fail-fast: false + matrix: + branch: [ "master" ] + skipGenerators: [ "", "IMPORT_STATEMENT" ] + + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + with: + ref: ${{ matrix.branch }} + + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: '17.0.7' + + - name: Initialize sub-modules + run: git submodule update --init + + - name: Build with Gradle + timeout-minutes: 180 + env: + packageUser: ${{ github.actor }} + packagePAT: ${{ secrets.GITHUB_TOKEN }} + run: | + export DISPLAY=':99.0' + /usr/bin/Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & + ./gradlew clean :language-server-simulator:runLSSimulatorOnFHIR -Dls.simulation.skipGenerators=${{ matrix.skipGenerators }} + + - name: Check Simulation Failure + run: if test -f dump.hprof; then exit 1; else exit 0; fi + + - name: Analyze Heap Dump If Exists + if: failure() + run: | + if test -f dump.hprof; then echo "Heap sump exists. Analyzing..."; else exit 0; fi + wget https://ftp.jaist.ac.jp/pub/eclipse/mat/1.12.0/rcp/MemoryAnalyzer-1.12.0.20210602-linux.gtk.x86_64.zip + unzip MemoryAnalyzer-1.12.0.20210602-linux.gtk.x86_64.zip + ./mat/ParseHeapDump.sh ./dump.hprof org.eclipse.mat.api:suspects + + - name: Upload Heap Dumps + uses: actions/upload-artifact@v2 + if: always() + with: + name: heap_dump-${{ matrix.branch }}.hprof + path: '*.hprof' + + - name: Upload Leaks Suspects + uses: actions/upload-artifact@v2 + if: failure() + with: + name: Leak_Suspects-${{ matrix.branch }} + path: 'dump_Leak_Suspects.zip' + + - name: Notify failure + if: failure() + run: | + curl -X POST \ + 'https://api.github.com/repos/ballerina-platform/ballerina-release/dispatches' \ + -H 'Accept: application/vnd.github.v3+json' \ + -H 'Authorization: Bearer ${{ secrets.BALLERINA_BOT_TOKEN }}' \ + --data "{ + \"event_type\": \"notify-simulator-failure\", + \"client_payload\": { + \"branch\": \"${{ matrix.branch }}\", + \"runId\":\"${{ github.run_id }}\" + } + }" diff --git a/.github/workflows/language_server_simulator_nballerina.yml b/.github/workflows/language_server_simulator_nballerina.yml new file mode 100644 index 0000000000..f47be491ab --- /dev/null +++ b/.github/workflows/language_server_simulator_nballerina.yml @@ -0,0 +1,82 @@ +name: Language Server Simulator on nBallerina + +on: + schedule: + - cron: '0 */12 * * *' + workflow_dispatch: + +jobs: + run_simulator: + name: Run LS Simulator + runs-on: ubuntu-latest + timeout-minutes: 240 + strategy: + fail-fast: false + matrix: + branch: [ "master" ] + skipGenerators: [ "", "IMPORT_STATEMENT" ] + + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + with: + ref: ${{ matrix.branch }} + + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: '17.0.7' + + - name: Initialize sub-modules + run: git submodule update --init + + - name: Build with Gradle + timeout-minutes: 180 + env: + packageUser: ${{ github.actor }} + packagePAT: ${{ secrets.GITHUB_TOKEN }} + run: | + export DISPLAY=':99.0' + /usr/bin/Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & + ./gradlew clean :language-server-simulator:runLSSimulatorOnnBallerina -Dls.simulation.skipGenerators=${{ matrix.skipGenerators }} + + - name: Check Simulation Failure + run: if test -f dump.hprof; then exit 1; else exit 0; fi + + - name: Analyze Heap Dump If Exists + if: failure() + run: | + if test -f dump.hprof; then echo "Heap sump exists. Analyzing..."; else exit 0; fi + wget https://ftp.jaist.ac.jp/pub/eclipse/mat/1.12.0/rcp/MemoryAnalyzer-1.12.0.20210602-linux.gtk.x86_64.zip + unzip MemoryAnalyzer-1.12.0.20210602-linux.gtk.x86_64.zip + ./mat/ParseHeapDump.sh ./dump.hprof org.eclipse.mat.api:suspects + + - name: Upload Heap Dumps + uses: actions/upload-artifact@v2 + if: always() + with: + name: heap_dump-${{ matrix.branch }}.hprof + path: '*.hprof' + + - name: Upload Leaks Suspects + uses: actions/upload-artifact@v2 + if: failure() + with: + name: Leak_Suspects-${{ matrix.branch }} + path: 'dump_Leak_Suspects.zip' + + - name: Notify failure + if: failure() + run: | + curl -X POST \ + 'https://api.github.com/repos/ballerina-platform/ballerina-release/dispatches' \ + -H 'Accept: application/vnd.github.v3+json' \ + -H 'Authorization: Bearer ${{ secrets.BALLERINA_BOT_TOKEN }}' \ + --data "{ + \"event_type\": \"notify-simulator-failure\", + \"client_payload\": { + \"branch\": \"${{ matrix.branch }}\", + \"runId\":\"${{ github.run_id }}\" + } + }" diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8ca65a422d..b36e3c2bc7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -18,12 +18,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Repository - uses: actions/checkout@v2 - - name: Set up JDK 11 - uses: actions/setup-java@v2 + uses: actions/checkout@v3 + - name: Set up JDK 17 + uses: actions/setup-java@v3 with: distribution: 'temurin' - java-version: '11' + java-version: '17.0.7' - name: Get project version id: project-version run: | diff --git a/.github/workflows/publish-release-artifacts-1.2.x.yml b/.github/workflows/publish-release-artifacts-1.2.x.yml index 7bf54447c2..ec48cc5093 100644 --- a/.github/workflows/publish-release-artifacts-1.2.x.yml +++ b/.github/workflows/publish-release-artifacts-1.2.x.yml @@ -16,10 +16,10 @@ jobs: steps: - name: Checkout Repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Set up JDK 8 - uses: actions/setup-java@v2 + uses: actions/setup-java@v3 with: distribution: 'temurin' java-version: '8' diff --git a/.github/workflows/publish-release-artifacts.yml b/.github/workflows/publish-release-artifacts.yml index 80856a16af..5ee607ec5f 100644 --- a/.github/workflows/publish-release-artifacts.yml +++ b/.github/workflows/publish-release-artifacts.yml @@ -16,13 +16,13 @@ jobs: steps: - name: Checkout Repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 - - name: Set up JDK 11 - uses: actions/setup-java@v2 + - name: Set up JDK 17 + uses: actions/setup-java@v3 with: distribution: 'temurin' - java-version: '11' + java-version: '17.0.7' - name: Set version env variable id: set-version diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index f2ac040e19..0c5bc553d7 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -12,18 +12,22 @@ on: required: false default: '' +permissions: + id-token: write + contents: write + jobs: publish-release: name: Publish Release runs-on: ubuntu-latest steps: - name: Checkout Repository - uses: actions/checkout@v2 - - name: Set up JDK 11 - uses: actions/setup-java@v2 + uses: actions/checkout@v3 + - name: Set up JDK 17 + uses: actions/setup-java@v3 with: distribution: 'temurin' - java-version: '11' + java-version: '17.0.7' - name: Set version env variable id: version-set run: | @@ -72,7 +76,7 @@ jobs: ./gradlew build -Pversion=${VERSION} ./gradlew release -Prelease.useAutomaticVersion=true -x test - name: Checkout docker repo - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: repository: ballerina-platform/module-ballerina-docker path: module-ballerina-docker @@ -105,6 +109,43 @@ jobs: format: 'table' exit-code: '1' timeout: "10m0s" + - name: cosign-installer + uses: sigstore/cosign-installer@v3.0.3 + - name: Set up Node.js + uses: actions/setup-node@v2 + with: + node-version: '14' + - name: Install GitHub CLI + run: | + npm install -g github-cli + gh --version + - name: Get Markdown file + id: file-url + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh repo view ballerina-platform/ballerina-dev-website --json url --jq '.clone_url' + gh api repos/ballerina-platform/ballerina-dev-website/contents/downloads/verify-ballerina-artifacts.md -H 'Accept: application/vnd.github.v3.raw' > release_notes.md + sed -i '1,10d' release_notes.md + - name: Retrieve Branch + id: retrieve-branch + run: | + branchName=$(echo ${{ github.ref }} | cut -d'/' -f3) + echo "::set-output name=branchName::$branchName" + - name: Update Markdown file + run: | + if ${{ github.event.inputs.isPreRelease }} == 'true'; then + echo "" > release_notes.md; + else sed -i 's/{{ version }}/${{ steps.version-set.outputs.taggedVersion }}/g' release_notes.md; sed -i 's/{{ branch }}/${{ steps.retrieve-branch.outputs.branchName }}/g' release_notes.md; fi + - name: Read release notes from file + id: release_notes + uses: actions/github-script@v4 + with: + github-token: ${{ secrets.BALLERINA_BOT_TOKEN }} + script: | + const fs = require('fs'); + const releaseNotes = fs.readFileSync('release_notes.md', 'utf8'); + core.setOutput('notes', releaseNotes); - name: Create release id: create_release uses: actions/create-release@v1 @@ -113,6 +154,7 @@ jobs: with: tag_name: "v${{ steps.version-set.outputs.taggedVersion }}" release_name: ${{ steps.version-set.outputs.taggedVersion }} + body: ${{ steps.release_notes.outputs.notes }} draft: false prerelease: ${{ github.event.inputs.isPreRelease }} - name: Create linux-deb Installer @@ -121,18 +163,44 @@ jobs: cd installers/linux-deb ./build-ballerina-linux-deb-x64.sh -v ${{ steps.version-set.outputs.longVersion }} -p ./../../ballerina/build/distributions echo "Created linux-deb successfully" + - name: Sign the linux-deb installer + run: | + cosign sign-blob installers/linux-deb/target/ballerina-${{ steps.version-set.outputs.longVersion }}-linux-x64.deb --output-certificate ballerina-${{ steps.version-set.outputs.longVersion }}-linux-x64.deb.pem --output-signature ballerina-${{ steps.version-set.outputs.longVersion }}-linux-x64.deb.sig --yes + - name: Verify the linux-deb installer + run: | + cosign verify-blob installers/linux-deb/target/ballerina-${{ steps.version-set.outputs.longVersion }}-linux-x64.deb --certificate ballerina-${{ steps.version-set.outputs.longVersion }}-linux-x64.deb.pem --signature ballerina-${{ steps.version-set.outputs.longVersion }}-linux-x64.deb.sig --certificate-identity=https://github.com/ballerina-platform/ballerina-distribution/.github/workflows/publish-release.yml@${{ github.ref }} --certificate-oidc-issuer=https://token.actions.githubusercontent.com - name: Create linux-rpm Installer id: run_installers_rpm run: | cd installers/linux-rpm ./build-ballerina-linux-rpm-x64.sh -v ${{ steps.version-set.outputs.longVersion }} -p ./../../ballerina/build/distributions echo "Created linux-rpm successfully" + - name: Sign the linux-rpm installer + run: | + cosign sign-blob installers/linux-rpm/rpmbuild/RPMS/x86_64/ballerina-${{ steps.version-set.outputs.longVersion }}-linux-x64.rpm --output-certificate ballerina-${{ steps.version-set.outputs.longVersion }}-linux-x64.rpm.pem --output-signature ballerina-${{ steps.version-set.outputs.longVersion }}-linux-x64.rpm.sig --yes + - name: Verify the linux-rpm installer + run: | + cosign verify-blob installers/linux-rpm/rpmbuild/RPMS/x86_64/ballerina-${{ steps.version-set.outputs.longVersion }}-linux-x64.rpm --certificate ballerina-${{ steps.version-set.outputs.longVersion }}-linux-x64.rpm.pem --signature ballerina-${{ steps.version-set.outputs.longVersion }}-linux-x64.rpm.sig --certificate-identity=https://github.com/ballerina-platform/ballerina-distribution/.github/workflows/publish-release.yml@${{ github.ref }} --certificate-oidc-issuer=https://token.actions.githubusercontent.com - name: Generate Hashes run: | openssl dgst -sha256 -out ballerina-${{ steps.version-set.outputs.longVersion }}-linux-x64.deb.sha256 installers/linux-deb/target/ballerina-*-linux-x64.deb openssl dgst -sha256 -out ballerina-${{ steps.version-set.outputs.longVersion }}-linux-x64.rpm.sha256 installers/linux-rpm/rpmbuild/RPMS/x86_64/ballerina-*-linux-x64.rpm openssl dgst -sha256 -out ballerina-${{ steps.version-set.outputs.longVersion }}.zip.sha256 ballerina/build/distributions/ballerina-${{ steps.version-set.outputs.longVersion }}.zip openssl dgst -sha256 -out ballerina-${{ steps.version-set.outputs.sversion }}.zip.sha256 ballerina/build/distributions/ballerina-${{ steps.version-set.outputs.sversion }}.zip + - name: Sign the zip artifacts + run: | + cosign sign-blob ballerina/build/distributions/ballerina-${{ steps.version-set.outputs.longVersion }}.zip --output-certificate ballerina-${{ steps.version-set.outputs.longVersion }}.pem --output-signature ballerina-${{ steps.version-set.outputs.longVersion }}.sig --yes + cosign sign-blob ballerina/build/distributions/ballerina-${{ steps.version-set.outputs.sversion }}.zip --output-certificate ballerina-${{ steps.version-set.outputs.sversion }}.pem --output-signature ballerina-${{ steps.version-set.outputs.sversion }}.sig --yes + cosign sign-blob ballerina/build/distributions/ballerina-${{ steps.version-set.outputs.longVersion }}-macos.zip --output-certificate ballerina-${{ steps.version-set.outputs.longVersion }}-macos.pem --output-signature ballerina-${{ steps.version-set.outputs.longVersion }}-macos.sig --yes + cosign sign-blob ballerina/build/distributions/ballerina-${{ steps.version-set.outputs.longVersion }}-macos-arm.zip --output-certificate ballerina-${{ steps.version-set.outputs.longVersion }}-macos-arm.pem --output-signature ballerina-${{ steps.version-set.outputs.longVersion }}-macos-arm.sig --yes + cosign sign-blob ballerina/build/distributions/ballerina-${{ steps.version-set.outputs.longVersion }}-windows.zip --output-certificate ballerina-${{ steps.version-set.outputs.longVersion }}-windows.pem --output-signature ballerina-${{ steps.version-set.outputs.longVersion }}-windows.sig --yes + - name: Verify the zip artifacts + run: | + cosign verify-blob ballerina/build/distributions/ballerina-${{ steps.version-set.outputs.longVersion }}.zip --certificate ballerina-${{ steps.version-set.outputs.longVersion }}.pem --signature ballerina-${{ steps.version-set.outputs.longVersion }}.sig --certificate-identity=https://github.com/ballerina-platform/ballerina-distribution/.github/workflows/publish-release.yml@${{ github.ref }} --certificate-oidc-issuer=https://token.actions.githubusercontent.com + cosign verify-blob ballerina/build/distributions/ballerina-${{ steps.version-set.outputs.sversion }}.zip --certificate ballerina-${{ steps.version-set.outputs.sversion }}.pem --signature ballerina-${{ steps.version-set.outputs.sversion }}.sig --certificate-identity=https://github.com/ballerina-platform/ballerina-distribution/.github/workflows/publish-release.yml@${{ github.ref }} --certificate-oidc-issuer=https://token.actions.githubusercontent.com + cosign verify-blob ballerina/build/distributions/ballerina-${{ steps.version-set.outputs.longVersion }}-macos.zip --certificate ballerina-${{ steps.version-set.outputs.longVersion }}-macos.pem --signature ballerina-${{ steps.version-set.outputs.longVersion }}-macos.sig --certificate-identity=https://github.com/ballerina-platform/ballerina-distribution/.github/workflows/publish-release.yml@${{ github.ref }} --certificate-oidc-issuer=https://token.actions.githubusercontent.com + cosign verify-blob ballerina/build/distributions/ballerina-${{ steps.version-set.outputs.longVersion }}-macos-arm.zip --certificate ballerina-${{ steps.version-set.outputs.longVersion }}-macos-arm.pem --signature ballerina-${{ steps.version-set.outputs.longVersion }}-macos-arm.sig --certificate-identity=https://github.com/ballerina-platform/ballerina-distribution/.github/workflows/publish-release.yml@${{ github.ref }} --certificate-oidc-issuer=https://token.actions.githubusercontent.com + cosign verify-blob ballerina/build/distributions/ballerina-${{ steps.version-set.outputs.longVersion }}-windows.zip --certificate ballerina-${{ steps.version-set.outputs.longVersion }}-windows.pem --signature ballerina-${{ steps.version-set.outputs.longVersion }}-windows.sig --certificate-identity=https://github.com/ballerina-platform/ballerina-distribution/.github/workflows/publish-release.yml@${{ github.ref }} --certificate-oidc-issuer=https://token.actions.githubusercontent.com - name: Upload zip artifacts uses: actions/upload-release-asset@v1 env: @@ -142,6 +210,24 @@ jobs: asset_name: ballerina-${{ steps.version-set.outputs.longVersion }}.zip asset_path: ballerina/build/distributions/ballerina-${{ steps.version-set.outputs.longVersion }}.zip asset_content_type: application/octet-stream + - name: Upload zip artifact's Certificate + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.BALLERINA_BOT_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_name: ballerina-${{ steps.version-set.outputs.longVersion }}.pem + asset_path: ./ballerina-${{ steps.version-set.outputs.longVersion }}.pem + asset_content_type: application/octet-stream + - name: Upload zip artifact's Signature + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.BALLERINA_BOT_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_name: ballerina-${{ steps.version-set.outputs.longVersion }}.sig + asset_path: ./ballerina-${{ steps.version-set.outputs.longVersion }}.sig + asset_content_type: application/octet-stream - name: Upload zip without tool artifacts uses: actions/upload-release-asset@v1 env: @@ -151,6 +237,24 @@ jobs: asset_name: ballerina-${{ steps.version-set.outputs.sversion }}.zip asset_path: ballerina/build/distributions/ballerina-${{ steps.version-set.outputs.sversion }}.zip asset_content_type: application/octet-stream + - name: Upload zip without tool artifact's Certificate + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.BALLERINA_BOT_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_name: ballerina-${{ steps.version-set.outputs.sversion }}.pem + asset_path: ./ballerina-${{ steps.version-set.outputs.sversion }}.pem + asset_content_type: application/octet-stream + - name: Upload zip without tool artifact's Signature + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.BALLERINA_BOT_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_name: ballerina-${{ steps.version-set.outputs.sversion }}.sig + asset_path: ./ballerina-${{ steps.version-set.outputs.sversion }}.sig + asset_content_type: application/octet-stream - name: Upload Linux deb Installer uses: actions/upload-release-asset@v1 env: @@ -160,6 +264,24 @@ jobs: asset_name: ballerina-${{ steps.version-set.outputs.longVersion }}-linux-x64.deb asset_path: installers/linux-deb/target/ballerina-${{ steps.version-set.outputs.longVersion }}-linux-x64.deb asset_content_type: application/octet-stream + - name: Upload Linux deb Installer's Certificate + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.BALLERINA_BOT_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_name: ballerina-${{ steps.version-set.outputs.longVersion }}-linux-x64.deb.pem + asset_path: ./ballerina-${{ steps.version-set.outputs.longVersion }}-linux-x64.deb.pem + asset_content_type: application/octet-stream + - name: Upload Linux deb Installer's Signature + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.BALLERINA_BOT_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_name: ballerina-${{ steps.version-set.outputs.longVersion }}-linux-x64.deb.sig + asset_path: ./ballerina-${{ steps.version-set.outputs.longVersion }}-linux-x64.deb.sig + asset_content_type: application/octet-stream - name: Upload Linux rpm Installer uses: actions/upload-release-asset@v1 env: @@ -169,6 +291,24 @@ jobs: asset_name: ballerina-${{ steps.version-set.outputs.longVersion }}-linux-x64.rpm asset_path: installers/linux-rpm/rpmbuild/RPMS/x86_64/ballerina-${{ steps.version-set.outputs.longVersion }}-linux-x64.rpm asset_content_type: application/octet-stream + - name: Upload Linux rpm Installer's Certificate + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.BALLERINA_BOT_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_name: ballerina-${{ steps.version-set.outputs.longVersion }}-linux-x64.rpm.pem + asset_path: ./ballerina-${{ steps.version-set.outputs.longVersion }}-linux-x64.rpm.pem + asset_content_type: application/octet-stream + - name: Upload Linux rpm Installer's Signature + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.BALLERINA_BOT_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_name: ballerina-${{ steps.version-set.outputs.longVersion }}-linux-x64.rpm.sig + asset_path: ./ballerina-${{ steps.version-set.outputs.longVersion }}-linux-x64.rpm.sig + asset_content_type: application/octet-stream - name: Upload MacOS zip artifacts uses: actions/upload-release-asset@v1 env: @@ -178,6 +318,24 @@ jobs: asset_name: ballerina-${{ steps.version-set.outputs.longVersion }}-macos.zip asset_path: ballerina/build/distributions/ballerina-${{ steps.version-set.outputs.longVersion }}-macos.zip asset_content_type: application/octet-stream + - name: Upload MacOS zip artifact's Certificate + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.BALLERINA_BOT_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_name: ballerina-${{ steps.version-set.outputs.longVersion }}-macos.pem + asset_path: ./ballerina-${{ steps.version-set.outputs.longVersion }}-macos.pem + asset_content_type: application/octet-stream + - name: Upload MacOS zip artifact's Signature + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.BALLERINA_BOT_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_name: ballerina-${{ steps.version-set.outputs.longVersion }}-macos.sig + asset_path: ./ballerina-${{ steps.version-set.outputs.longVersion }}-macos.sig + asset_content_type: application/octet-stream - name: Upload MacOS-ARM zip artifacts uses: actions/upload-release-asset@v1 env: @@ -187,6 +345,24 @@ jobs: asset_name: ballerina-${{ steps.version-set.outputs.longVersion }}-macos-arm.zip asset_path: ballerina/build/distributions/ballerina-${{ steps.version-set.outputs.longVersion }}-macos-arm.zip asset_content_type: application/octet-stream + - name: Upload MacOS-ARM zip artifact's Certificate + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.BALLERINA_BOT_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_name: ballerina-${{ steps.version-set.outputs.longVersion }}-macos-arm.pem + asset_path: ./ballerina-${{ steps.version-set.outputs.longVersion }}-macos-arm.pem + asset_content_type: application/octet-stream + - name: Upload MacOS-ARM zip artifact's Signature + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.BALLERINA_BOT_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_name: ballerina-${{ steps.version-set.outputs.longVersion }}-macos-arm.sig + asset_path: ./ballerina-${{ steps.version-set.outputs.longVersion }}-macos-arm.sig + asset_content_type: application/octet-stream - name: Upload Windows zip artifacts uses: actions/upload-release-asset@v1 env: @@ -196,6 +372,24 @@ jobs: asset_name: ballerina-${{ steps.version-set.outputs.longVersion }}-windows.zip asset_path: ballerina/build/distributions/ballerina-${{ steps.version-set.outputs.longVersion }}-windows.zip asset_content_type: application/octet-stream + - name: Upload Windows zip artifact's Certificate + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.BALLERINA_BOT_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_name: ballerina-${{ steps.version-set.outputs.longVersion }}-windows.pem + asset_path: ./ballerina-${{ steps.version-set.outputs.longVersion }}-windows.pem + asset_content_type: application/octet-stream + - name: Upload Windows zip artifact's Signature + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.BALLERINA_BOT_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_name: ballerina-${{ steps.version-set.outputs.longVersion }}-windows.sig + asset_path: ./ballerina-${{ steps.version-set.outputs.longVersion }}-windows.sig + asset_content_type: application/octet-stream - name: Upload Linux deb Hashes uses: actions/upload-release-asset@v1 env: @@ -252,20 +446,28 @@ jobs: steps: - name: Checkout Repository uses: actions/checkout@v2 - - name: Set up JDK 11 + - name: Set up JDK 17 uses: actions/setup-java@v2 with: distribution: 'temurin' - java-version: '11' + java-version: '17.0.7' - name: Download MacOS Intaller Zip run: | wget https://github.com/ballerina-platform/ballerina-distribution/releases/download/v${{ needs.publish-release.outputs.release-version }}/ballerina-${{ needs.publish-release.outputs.project-version }}-macos.zip + - name: cosign-installer + uses: sigstore/cosign-installer@v3.0.3 - name: Create macos-pkg Installer id: run_installers_pkg run: | cd installers/mac ./build-ballerina-macos-x64.sh -v ${{ needs.publish-release.outputs.project-version }} -p ./../../ echo "Created macos-pkg successfully" + - name: Sign the MacOS installer + run: | + cosign sign-blob installers/mac/target/pkg/ballerina-${{ needs.publish-release.outputs.project-version }}-macos-x64.pkg --output-certificate ballerina-${{ needs.publish-release.outputs.project-version }}-macos-x64.pkg.pem --output-signature ballerina-${{ needs.publish-release.outputs.project-version }}-macos-x64.pkg.sig --yes + - name: Verify the MacOS installer + run: | + cosign verify-blob installers/mac/target/pkg/ballerina-${{ needs.publish-release.outputs.project-version }}-macos-x64.pkg --certificate ballerina-${{ needs.publish-release.outputs.project-version }}-macos-x64.pkg.pem --signature ballerina-${{ needs.publish-release.outputs.project-version }}-macos-x64.pkg.sig --certificate-identity=https://github.com/ballerina-platform/ballerina-distribution/.github/workflows/publish-release.yml@${{ github.ref }} --certificate-oidc-issuer=https://token.actions.githubusercontent.com - name: Generate Hashes run: | openssl dgst -sha256 -out ballerina-${{ needs.publish-release.outputs.project-version }}-macos-x64.pkg.sha256 installers/mac/target/pkg/ballerina-${{ needs.publish-release.outputs.project-version }}-macos-x64.pkg @@ -287,6 +489,24 @@ jobs: asset_name: ballerina-${{ needs.publish-release.outputs.project-version }}-macos-x64.pkg asset_path: installers/mac/target/pkg/ballerina-${{ needs.publish-release.outputs.project-version }}-macos-x64.pkg asset_content_type: application/octet-stream + - name: Upload MacOS installer's Certificate + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.BALLERINA_BOT_TOKEN }} + with: + upload_url: ${{ needs.publish-release.outputs.upload-asset-url }} + asset_name: ballerina-${{ needs.publish-release.outputs.project-version }}-macos-x64.pkg.pem + asset_path: ./ballerina-${{ needs.publish-release.outputs.project-version }}-macos-x64.pkg.pem + asset_content_type: application/octet-stream + - name: Upload MacOS installer's Signature + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.BALLERINA_BOT_TOKEN }} + with: + upload_url: ${{ needs.publish-release.outputs.upload-asset-url }} + asset_name: ballerina-${{ needs.publish-release.outputs.project-version }}-macos-x64.pkg.sig + asset_path: ./ballerina-${{ needs.publish-release.outputs.project-version }}-macos-x64.pkg.sig + asset_content_type: application/octet-stream - name: Download MacOS-ARM Intaller Zip run: | wget https://github.com/ballerina-platform/ballerina-distribution/releases/download/v${{ needs.publish-release.outputs.release-version }}/ballerina-${{ needs.publish-release.outputs.project-version }}-macos-arm.zip @@ -296,6 +516,12 @@ jobs: cd installers/mac ./build-ballerina-macos-x64.sh -v ${{ needs.publish-release.outputs.project-version }} -p ./../../ -a arm echo "Created macos-arm-pkg successfully" + - name: Sign the MacOS-ARM installer + run: | + cosign sign-blob installers/mac/target/pkg/ballerina-${{ needs.publish-release.outputs.project-version }}-macos-arm-x64.pkg --output-certificate ballerina-${{ needs.publish-release.outputs.project-version }}-macos-arm-x64.pkg.pem --output-signature ballerina-${{ needs.publish-release.outputs.project-version }}-macos-arm-x64.pkg.sig --yes + - name: Verify the MacOS-ARM installer + run: | + cosign verify-blob installers/mac/target/pkg/ballerina-${{ needs.publish-release.outputs.project-version }}-macos-arm-x64.pkg --certificate ballerina-${{ needs.publish-release.outputs.project-version }}-macos-arm-x64.pkg.pem --signature ballerina-${{ needs.publish-release.outputs.project-version }}-macos-arm-x64.pkg.sig --certificate-identity=https://github.com/ballerina-platform/ballerina-distribution/.github/workflows/publish-release.yml@${{ github.ref }} --certificate-oidc-issuer=https://token.actions.githubusercontent.com - name: Generate Hashes run: | openssl dgst -sha256 -out ballerina-${{ needs.publish-release.outputs.project-version }}-macos-arm-x64.pkg.sha256 installers/mac/target/pkg/ballerina-${{ needs.publish-release.outputs.project-version }}-macos-arm-x64.pkg @@ -317,6 +543,24 @@ jobs: asset_name: ballerina-${{ needs.publish-release.outputs.project-version }}-macos-arm-x64.pkg asset_path: installers/mac/target/pkg/ballerina-${{ needs.publish-release.outputs.project-version }}-macos-arm-x64.pkg asset_content_type: application/octet-stream + - name: Upload MacOS-ARM installer's Certificate + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.BALLERINA_BOT_TOKEN }} + with: + upload_url: ${{ needs.publish-release.outputs.upload-asset-url }} + asset_name: ballerina-${{ needs.publish-release.outputs.project-version }}-macos-arm-x64.pkg.pem + asset_path: ./ballerina-${{ needs.publish-release.outputs.project-version }}-macos-arm-x64.pkg.pem + asset_content_type: application/octet-stream + - name: Upload MacOS-ARM installer's Signature + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.BALLERINA_BOT_TOKEN }} + with: + upload_url: ${{ needs.publish-release.outputs.upload-asset-url }} + asset_name: ballerina-${{ needs.publish-release.outputs.project-version }}-macos-arm-x64.pkg.sig + asset_path: ./ballerina-${{ needs.publish-release.outputs.project-version }}-macos-arm-x64.pkg.sig + asset_content_type: application/octet-stream windows-installer-build: name: Windows Installer Build @@ -326,11 +570,11 @@ jobs: steps: - name: Checkout Repository uses: actions/checkout@v2 - - name: Set up JDK 11 + - name: Set up JDK 17 uses: actions/setup-java@v2 with: distribution: 'temurin' - java-version: '11' + java-version: '17.0.7' - uses: actions/setup-dotnet@v1 with: dotnet-version: '2.1.x' @@ -341,6 +585,8 @@ jobs: - name: Download Windows Intaller Zip run: | wget https://github.com/ballerina-platform/ballerina-distribution/releases/download/v${{ needs.publish-release.outputs.release-version }}/ballerina-${{ needs.publish-release.outputs.project-version }}-windows.zip + - name: cosign-installer + uses: sigstore/cosign-installer@v3.0.3 - name: Create windows-msi Installer id: run_installers_msi run: | @@ -350,6 +596,12 @@ jobs: cd w .\build-ballerina-windows-x64.bat --version ${{ needs.publish-release.outputs.project-version }} --path .\..\ echo "Created windows-msi successfully" + - name: Sign the Windows installer + run: | + cosign sign-blob w\target\msi\ballerina-${{ needs.publish-release.outputs.project-version }}-windows-x64.msi --output-certificate ballerina-${{ needs.publish-release.outputs.project-version }}-windows-x64.msi.pem --output-signature ballerina-${{ needs.publish-release.outputs.project-version }}-windows-x64.msi.sig --yes + - name: Verify the Windows installer + run: | + cosign verify-blob w\target\msi\ballerina-${{ needs.publish-release.outputs.project-version }}-windows-x64.msi --certificate ballerina-${{ needs.publish-release.outputs.project-version }}-windows-x64.msi.pem --signature ballerina-${{ needs.publish-release.outputs.project-version }}-windows-x64.msi.sig --certificate-identity=https://github.com/ballerina-platform/ballerina-distribution/.github/workflows/publish-release.yml@${{ github.ref }} --certificate-oidc-issuer=https://token.actions.githubusercontent.com - name: Generate Hashes run: | openssl dgst -sha256 -out ballerina-${{ needs.publish-release.outputs.project-version }}-windows-x64.msi.sha256 w\target\msi\ballerina-${{ needs.publish-release.outputs.project-version }}-windows-x64.msi @@ -371,6 +623,24 @@ jobs: asset_name: ballerina-${{ needs.publish-release.outputs.project-version }}-windows-x64.msi asset_path: w\target\msi\ballerina-${{ needs.publish-release.outputs.project-version }}-windows-x64.msi asset_content_type: application/octet-stream + - name: Upload Windows installer's Certificate + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.BALLERINA_BOT_TOKEN }} + with: + upload_url: ${{ needs.publish-release.outputs.upload-asset-url }} + asset_name: ballerina-${{ needs.publish-release.outputs.project-version }}-windows-x64.msi.pem + asset_path: ./ballerina-${{ needs.publish-release.outputs.project-version }}-windows-x64.msi.pem + asset_content_type: application/octet-stream + - name: Upload Windows installer's Signature + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.BALLERINA_BOT_TOKEN }} + with: + upload_url: ${{ needs.publish-release.outputs.upload-asset-url }} + asset_name: ballerina-${{ needs.publish-release.outputs.project-version }}-windows-x64.msi.sig + asset_path: ./ballerina-${{ needs.publish-release.outputs.project-version }}-windows-x64.msi.sig + asset_content_type: application/octet-stream - name: Install Ballerina msi run: msiexec /i w\target\msi\ballerina-${{ needs.publish-release.outputs.project-version }}-windows-x64.msi /quiet /qr shell: cmd @@ -379,3 +649,4 @@ jobs: run: | $env:Path += ";C:\Program Files\Ballerina\bin" .\..\gradlew build --stacktrace -scan --console=plain --no-daemon -DballerinaInstalled=true + \ No newline at end of file diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 36bac09fa1..87da042fb2 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -17,12 +17,12 @@ jobs: cancel-in-progress: true steps: - name: Checkout Repository - uses: actions/checkout@v2 - - name: Set up JDK 11 - uses: actions/setup-java@v2 + uses: actions/checkout@v3 + - name: Set up JDK 17 + uses: actions/setup-java@v3 with: distribution: 'temurin' - java-version: '11' + java-version: '17.0.7' - name: Build Ballerina Distribution env: packageUser: ${{ github.actor }} @@ -39,12 +39,12 @@ jobs: cancel-in-progress: true steps: - name: Checkout Repository - uses: actions/checkout@v2 - - name: Set up JDK 11 - uses: actions/setup-java@v2 + uses: actions/checkout@v3 + - name: Set up JDK 17 + uses: actions/setup-java@v3 with: distribution: 'temurin' - java-version: '11' + java-version: '17.0.7' - name: Build Ballerina Distribution env: packageUser: ${{ github.actor }} @@ -60,12 +60,12 @@ jobs: cancel-in-progress: true steps: - name: Checkout Repository - uses: actions/checkout@v2 - - name: Set up JDK 11 - uses: actions/setup-java@v2 + uses: actions/checkout@v3 + - name: Set up JDK 17 + uses: actions/setup-java@v3 with: distribution: 'temurin' - java-version: '11' + java-version: '17.0.7' - name: Build Ballerina Distribution env: packageUser: ${{ github.actor }} diff --git a/.github/workflows/sign-installers.yml b/.github/workflows/sign-installers.yml new file mode 100644 index 0000000000..71b3b7973e --- /dev/null +++ b/.github/workflows/sign-installers.yml @@ -0,0 +1,71 @@ +name: Sign release artifacts + +on: + workflow_dispatch: + inputs: + versionName: + description: 'Specify the Version name eg: 2201.6.0' + required: true + default: '' + +permissions: + id-token: write + contents: write + +jobs: + sign-release: + name: Sign release artifacts + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v3 + - name: cosign-installer + uses: sigstore/cosign-installer@v3.0.3 + - name: Install Node + uses: actions/setup-node@v2 + with: + node-version: '14' + - name: Install GitHub CLI + run: | + npm install -g github-cli + - name: Retrieve MacOS Installer + run: + | + wget https://github.com/ballerina-platform/ballerina-distribution/releases/download/v${{ github.event.inputs.versionName }}/ballerina-${{ github.event.inputs.versionName }}-swan-lake-macos-x64.pkg + - name: Sign the MacOS Installer + run: | + cosign sign-blob ballerina-${{ github.event.inputs.versionName }}-swan-lake-macos-x64.pkg --output-certificate ballerina-${{ github.event.inputs.versionName }}-swan-lake-macos-x64.pkg.pem --output-signature ballerina-${{ github.event.inputs.versionName }}-swan-lake-macos-x64.pkg.sig --yes + - name: Verify the MacOS Installer + run: | + cosign verify-blob ballerina-${{ github.event.inputs.versionName }}-swan-lake-macos-x64.pkg --certificate ballerina-${{ github.event.inputs.versionName }}-swan-lake-macos-x64.pkg.pem --signature ballerina-${{ github.event.inputs.versionName }}-swan-lake-macos-x64.pkg.sig --certificate-identity=https://github.com/ballerina-platform/ballerina-distribution/.github/workflows/sign-installers.yml@${{ github.ref }} --certificate-oidc-issuer=https://token.actions.githubusercontent.com + - name: Retrieve MacOS-ARM Installer + run: + | + wget https://github.com/ballerina-platform/ballerina-distribution/releases/download/v${{ github.event.inputs.versionName }}/ballerina-${{ github.event.inputs.versionName }}-swan-lake-macos-arm-x64.pkg + - name: Sign the MacOS-ARM Installer + run: | + cosign sign-blob ballerina-${{ github.event.inputs.versionName }}-swan-lake-macos-arm-x64.pkg --output-certificate ballerina-${{ github.event.inputs.versionName }}-swan-lake-macos-arm-x64.pkg.pem --output-signature ballerina-${{ github.event.inputs.versionName }}-swan-lake-macos-arm-x64.pkg.sig --yes + - name: Verify the MacOS-ARM Installer + run: | + cosign verify-blob ballerina-${{ github.event.inputs.versionName }}-swan-lake-macos-arm-x64.pkg --certificate ballerina-${{ github.event.inputs.versionName }}-swan-lake-macos-arm-x64.pkg.pem --signature ballerina-${{ github.event.inputs.versionName }}-swan-lake-macos-arm-x64.pkg.sig --certificate-identity=https://github.com/ballerina-platform/ballerina-distribution/.github/workflows/sign-installers.yml@${{ github.ref }} --certificate-oidc-issuer=https://token.actions.githubusercontent.com + - name: Retrieve Windows Installer + run: + | + wget https://github.com/ballerina-platform/ballerina-distribution/releases/download/v${{ github.event.inputs.versionName }}/ballerina-${{ github.event.inputs.versionName }}-swan-lake-windows-x64.msi + - name: Sign the Windows Installer + run: | + cosign sign-blob ballerina-${{ github.event.inputs.versionName }}-swan-lake-windows-x64.msi --output-certificate ballerina-${{ github.event.inputs.versionName }}-swan-lake-windows-x64.msi.pem --output-signature ballerina-${{ github.event.inputs.versionName }}-swan-lake-windows-x64.msi.sig --yes + - name: Verify the Windows Installer + run: | + cosign verify-blob ballerina-${{ github.event.inputs.versionName }}-swan-lake-windows-x64.msi --certificate ballerina-${{ github.event.inputs.versionName }}-swan-lake-windows-x64.msi.pem --signature ballerina-${{ github.event.inputs.versionName }}-swan-lake-windows-x64.msi.sig --certificate-identity=https://github.com/ballerina-platform/ballerina-distribution/.github/workflows/sign-installers.yml@${{ github.ref }} --certificate-oidc-issuer=https://token.actions.githubusercontent.com + - name: Upload Installers' Verification Files + env: + GH_TOKEN : ${{ secrets.BALLERINA_BOT_TOKEN }} + run: | + gh release upload v${{ github.event.inputs.versionName }} ./ballerina-${{ github.event.inputs.versionName }}-swan-lake-macos-x64.pkg.pem --clobber + gh release upload v${{ github.event.inputs.versionName }} ./ballerina-${{ github.event.inputs.versionName }}-swan-lake-macos-x64.pkg.sig --clobber + gh release upload v${{ github.event.inputs.versionName }} ./ballerina-${{ github.event.inputs.versionName }}-swan-lake-macos-arm-x64.pkg.pem --clobber + gh release upload v${{ github.event.inputs.versionName }} ./ballerina-${{ github.event.inputs.versionName }}-swan-lake-macos-arm-x64.pkg.sig --clobber + gh release upload v${{ github.event.inputs.versionName }} ./ballerina-${{ github.event.inputs.versionName }}-swan-lake-windows-x64.msi.pem --clobber + gh release upload v${{ github.event.inputs.versionName }} ./ballerina-${{ github.event.inputs.versionName }}-swan-lake-windows-x64.msi.sig --clobber + \ No newline at end of file diff --git a/.github/workflows/test-installers.yml b/.github/workflows/test-installers.yml index 990a2f5ac2..81a518d12a 100644 --- a/.github/workflows/test-installers.yml +++ b/.github/workflows/test-installers.yml @@ -17,7 +17,7 @@ jobs: steps: - name: Checkout Repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Set Version id: set-version run: | diff --git a/.trivyignore b/.trivyignore index 4f18c70616..eed62a1178 100644 --- a/.trivyignore +++ b/.trivyignore @@ -1,12 +1,6 @@ +# False positive CVE-2020-7768 +CVE-2023-2976 CVE-2021-3737 CVE-2021-3997 -CVE-2022-42003 -CVE-2022-40151 -CVE-2022-40152 -CVE-2022-40153 -CVE-2022-40154 -CVE-2022-40155 -CVE-2022-40156 -CVE-2022-41854 -CVE-2022-1471 +CVE-2023-39017 diff --git a/README.md b/README.md index 973c54c0b6..dd8de827d5 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Alternatively, you can install Ballerina from the source using the following ins #### Prerequisites -* JDK11 ([Adopt OpenJDK11](https://adoptopenjdk.net/) or any other OpenJDK distribution) +* JDK17 ([Adopt OpenJDK17](https://adoptopenjdk.net/) or any other OpenJDK distribution) #### Building the source diff --git a/ballerina-test-automation/gradle.properties b/ballerina-test-automation/gradle.properties index 1df4c7f68a..0449033261 100644 --- a/ballerina-test-automation/gradle.properties +++ b/ballerina-test-automation/gradle.properties @@ -1,6 +1,6 @@ -swan-lake-latest-version=swan-lake-2201.5.0 -swan-lake-latest-spec-version=2022R4 -swan-lake-latest-version-display-text=2201.5.0 +swan-lake-latest-version=swan-lake-2201.8.0 +swan-lake-latest-spec-version=2023R1 +swan-lake-latest-version-display-text=2201.8.0 swan-lake-latest-tool-version=1.3.15 latest-tool-version=1.3.15 1-x-channel-latest-version=1.2.13 diff --git a/ballerina-test-automation/installer-test/build.gradle b/ballerina-test-automation/installer-test/build.gradle index a085a03803..ceeba7490a 100644 --- a/ballerina-test-automation/installer-test/build.gradle +++ b/ballerina-test-automation/installer-test/build.gradle @@ -42,7 +42,6 @@ configurations { } task testJar(type: Jar) { - classifier = 'test' from sourceSets.test.output } diff --git a/ballerina-test-automation/test-automation/src/main/java/io/ballerina/test/Utils.java b/ballerina-test-automation/test-automation/src/main/java/io/ballerina/test/Utils.java index ae5309cab8..f44e2ecfe2 100644 --- a/ballerina-test-automation/test-automation/src/main/java/io/ballerina/test/Utils.java +++ b/ballerina-test-automation/test-automation/src/main/java/io/ballerina/test/Utils.java @@ -39,23 +39,7 @@ public class Utils { System.getenv("BALLERINA_STAGING_UPDATE")); public static final PrintStream OUT = System.out; - private static TrustManager[] trustAllCerts = new TrustManager[]{ - new X509TrustManager() { - public java.security.cert.X509Certificate[] getAcceptedIssuers() { - return null; - } - - public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) { - //No need to implement. - } - - public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) { - //No need to implement. - } - } - }; - - public static final String DISTRIBUTION_LOCATION = "http://dist-dev.ballerina.io/downloads/"; + public static final String DISTRIBUTION_LOCATION = "https://dist-dev.ballerina.io/downloads/"; public static void downloadFile(String version, String installerName) { OUT.println("Downloading " + installerName); @@ -63,10 +47,6 @@ public static void downloadFile(String version, String installerName) { String destination = getUserHome(); File output = new File(destination + File.separator + installerName); if (!output.exists()) { - SSLContext sc = SSLContext.getInstance("SSL"); - sc.init(null, trustAllCerts, new java.security.SecureRandom()); - HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); - HttpURLConnection conn = (HttpURLConnection) new URL( DISTRIBUTION_LOCATION + version + "/" + installerName).openConnection(); conn.setRequestProperty("content-type", "binary/data"); diff --git a/ballerina-test/src/test/java/org/ballerinalang/distribution/test/BallerinaCommandTest.java b/ballerina-test/src/test/java/org/ballerinalang/distribution/test/BallerinaCommandTest.java index 841080d7c9..4ccd9be433 100644 --- a/ballerina-test/src/test/java/org/ballerinalang/distribution/test/BallerinaCommandTest.java +++ b/ballerina-test/src/test/java/org/ballerinalang/distribution/test/BallerinaCommandTest.java @@ -103,7 +103,7 @@ public void testDistCommands() throws IOException { actualOutput = TestUtils.executeCommand(path + " dist pull slp7"); Assert.assertTrue(actualOutput.contains("Fetching the 'slp7' distribution from the remote server...")); Assert.assertTrue(actualOutput.contains("Fetching the dependencies for 'slp7' from the remote server...")); - Assert.assertTrue(actualOutput.contains("Downloading jdk-11.0.8+10-jre")); + Assert.assertTrue(actualOutput.contains("Downloading jdk-17.0.7+7-jre")); Assert.assertTrue(actualOutput.contains("'slp7' successfully set as the active distribution")); TestUtils.testInstallation(path, "swan-lake-preview7", "v2020-09-22", TOOL_VERSION, "Preview 7"); diff --git a/ballerina-test/src/test/java/org/ballerinalang/distribution/test/OpenAPIDistributionArtifactCheck.java b/ballerina-test/src/test/java/org/ballerinalang/distribution/test/OpenAPIDistributionArtifactCheck.java index 59dbb038cc..85d696058d 100644 --- a/ballerina-test/src/test/java/org/ballerinalang/distribution/test/OpenAPIDistributionArtifactCheck.java +++ b/ballerina-test/src/test/java/org/ballerinalang/distribution/test/OpenAPIDistributionArtifactCheck.java @@ -52,7 +52,7 @@ public void openapiAnnotationExistsTest() { .resolve("cache") .resolve("ballerina") .resolve("openapi") - .resolve("1.6.0") + .resolve("1.8.0") .resolve("bir"); Path jarPath = TEST_DISTRIBUTION_PATH @@ -61,8 +61,8 @@ public void openapiAnnotationExistsTest() { .resolve("cache") .resolve("ballerina") .resolve("openapi") - .resolve("1.6.0") - .resolve("java11"); + .resolve("1.8.0") + .resolve("java17"); Path balaPath = TEST_DISTRIBUTION_PATH .resolve(DIST_NAME) @@ -70,10 +70,10 @@ public void openapiAnnotationExistsTest() { .resolve("bala") .resolve("ballerina") .resolve("openapi") - .resolve("1.6.0") - .resolve("java11") + .resolve("1.8.0") + .resolve("java17") .resolve("platform") - .resolve("java11"); + .resolve("java17"); Path breLibPath = TEST_DISTRIBUTION_PATH .resolve(DIST_NAME) @@ -95,7 +95,7 @@ public void openapiAnnotationExistsTest() { Assert.assertTrue(Files.exists(birPath)); Assert.assertTrue(Files.exists(balaPath)); - Assert.assertTrue(Files.exists(jarPath.resolve("ballerina-openapi-1.6.0.jar"))); + Assert.assertTrue(Files.exists(jarPath.resolve("ballerina-openapi-1.8.0.jar"))); Assert.assertNotNull(TestUtils.findFileOrDirectory(breLibPath, "openapi-cli-")); Assert.assertNotNull(TestUtils.findFileOrDirectory(breLibPath, "openapi-validator-")); Assert.assertNotNull(TestUtils.findFileOrDirectory(breLibPath, "openapi-bal-service-")); diff --git a/ballerina-test/src/test/resources/openapi/expected/client.bal b/ballerina-test/src/test/resources/openapi/expected/client.bal index 7d0ce1858a..51348a0dfd 100644 --- a/ballerina-test/src/test/resources/openapi/expected/client.bal +++ b/ballerina-test/src/test/resources/openapi/expected/client.bal @@ -1,3 +1,6 @@ +// AUTO-GENERATED FILE. DO NOT MODIFY. +// This file is auto-generated by the Ballerina OpenAPI tool. + import ballerina/http; # The Stripe REST API. Please see https://stripe.com/docs/api for more details. diff --git a/ballerina-test/src/test/resources/openapi/expected/filtered_tags.bal b/ballerina-test/src/test/resources/openapi/expected/filtered_tags.bal index efbe11b782..0ae81c7422 100644 --- a/ballerina-test/src/test/resources/openapi/expected/filtered_tags.bal +++ b/ballerina-test/src/test/resources/openapi/expected/filtered_tags.bal @@ -1,3 +1,6 @@ +// AUTO-GENERATED FILE. +// This file is auto-generated by the Ballerina OpenAPI tool. + import ballerina/http; listener http:Listener ep0 = new (80, config = {host: "petstore.openapi.io"}); @@ -9,6 +12,6 @@ service /v1 on ep0 { # + return - returns can be any of following types # Pets (An paged array of pets) # http:Response (unexpected error) - resource function get pets(int? 'limit) returns Pets|http:Response { + resource function get pets(int:Signed32? 'limit) returns Pets|http:Response { } } diff --git a/ballerina-test/src/test/resources/openapi/expected/types.bal b/ballerina-test/src/test/resources/openapi/expected/types.bal index 259cb4ff2b..68ab1456e2 100644 --- a/ballerina-test/src/test/resources/openapi/expected/types.bal +++ b/ballerina-test/src/test/resources/openapi/expected/types.bal @@ -1,5 +1,8 @@ -import ballerina/http; +// AUTO-GENERATED FILE. DO NOT MODIFY. +// This file is auto-generated by the Ballerina OpenAPI tool. + import ballerina/constraint; +import ballerina/http; # Provides a set of configurations for controlling the behaviours when communicating with a remote HTTP endpoint. @display {label: "Connection Config"} diff --git a/ballerina-test/src/test/resources/openapi/expected/utils.bal b/ballerina-test/src/test/resources/openapi/expected/utils.bal index e1f2566974..c4918d7353 100644 --- a/ballerina-test/src/test/resources/openapi/expected/utils.bal +++ b/ballerina-test/src/test/resources/openapi/expected/utils.bal @@ -1,3 +1,6 @@ +// AUTO-GENERATED FILE. DO NOT MODIFY. +// This file is auto-generated by the Ballerina OpenAPI tool. + import ballerina/url; type SimpleBasicType string|boolean|int|float|decimal; diff --git a/ballerina/LICENSE b/ballerina/LICENSE index 6fb042b90c..bdd532fab0 100644 --- a/ballerina/LICENSE +++ b/ballerina/LICENSE @@ -12,347 +12,368 @@ At the bottom of this file is a table that shows what each license indicated below is and where the actual text of the license can be found. -Name Type License +Name Type License _________________________________________________________________________________________________________________________________________________ -ballerina-command-1.3.11.jar jar apache2 -table-2201.4.0.jar jar apache2 -commons-text-1.10.0.jar bundle apache2 -floatingpoint-2201.4.0.jar jar apache2 -graphql-cli-0.4.0.jar jar mit -ballerina-linter-2201.4.0.jar jar apache2 -openapi-build-extension-1.4.0.jar jar apache2 -compiler-0.8.9.jar jar apache2 -ballerina-metrics-extension-2201.4.0.jar jar apache2 -identifier-util-2201.4.0.jar jar apache2 -gson-2.8.9.jar jar apache2 -org.wso2.carbon.metrics.core-2.3.7.jar bundle apache2 -woodstox-core-asl-4.4.1.jar bundle apache2 -org.jacoco.core-0.8.5.jar bundle epl2 -transactions-5.0.8.jar jar apache2 -value-2201.4.0.jar jar apache2 -broker-auth-0.970.0.jar bundle apache2 -staxon-core-1.2.0.wso2v2.jar bundle apache2 -ballerina-bindgen-2201.4.0.jar jar apache2 -formatter-cli-2201.4.0.jar jar apache2 -javax.mail-1.6.2.jar bundle cddl1 -geronimo-activation_1.1_spec-1.1.jar bundle apache2 -openapi-bal-service-1.4.0.jar jar apache2 -broker-rest-runner-0.970.0.jar bundle apache2 -netty-transport-native-epoll-4.1.77.Final.jar bundle apache2 -jackson-dataformat-yaml-2.13.2.jar bundle apache2 -netty-handler-4.1.77.Final.jar bundle apache2 -protoc-cli-0.1.0.jar jar apache2 -asm-analysis-7.1.jar bundle bsd -jballerina.java-2201.4.0.jar jar apache2 -persist-cli-0.1.0.jar jar apache2 -netty-resolver-4.1.77.Final.jar bundle apache2 -axiom-impl-1.4.0.jar bundle apache2 -stream-2201.4.0.jar jar apache2 -commons-beanutils-1.9.4.jar bundle apache2 -jackson-databind-2.14.0.jar bundle apache2 -kotlin-stdlib-common-1.6.0.jar jar apache2 -asm-tree-7.2.jar bundle bsd3 -function-2201.4.0.jar jar apache2 -syntax-api-calls-gen-2201.4.0.jar jar apache2 -org.jacoco.report-0.8.5.jar bundle epl2 -openapi-extension-1.4.0.jar jar apache2 -jaxen-1.1.6.jar bundle apache2 -transactions-jta-5.0.8.jar jar apache2 -jackson-annotations-2.13.2.jar bundle apache2 -observability-symbol-collector-2201.4.0.jar jar apache2 -commons-collections-3.2.2.jar bundle apache2 -package-semantic-analyzer-1.0.0.jar jar apache2 -regexp-2201.4.0.jar jar apache2 -kraal-0.0.16.jar jar mit -commons-codec-1.14.jar bundle apache2 -ballerina-lang-2201.4.0.jar jar apache2 -asm-commons-7.2.jar bundle bsd3 -broker-core-0.970.5.jar bundle apache2 -decimal-2201.4.0.jar jar apache2 -array-2201.4.0.jar jar apache2 -asm-7.2.jar bundle bsd3 -jackson-datatype-jsr310-2.13.2.jar bundle apache2 -testerina-runtime-2201.4.0.jar jar apache2 -netty-buffer-4.1.77.Final.jar bundle apache2 -commons-compress-1.21.jar bundle apache2 -query-2201.4.0.jar jar apache2 -ballerina-tools-api-2201.4.0.jar jar apache2 -openapi-validator-1.4.0.jar jar apache2 -testerina-core-2201.4.0.jar jar apache2 -netty-codec-4.1.77.Final.jar bundle apache2 -jaeger-thrift-0.31.0.jar jar apache2 -integer-2201.4.0.jar jar apache2 -shell-core-2201.4.0.jar jar apache2 -graphql-schema-file-generator-0.4.0.jar jar apache2 -jboss-logging-3.3.1.Final.jar bundle apache2 -java-diff-utils-4.5.jar bundle apache2 -typedesc-2201.4.0.jar jar apache2 -atomikos-util-5.0.8.jar jar apache2 -snakeyaml-1.32.jar bundle apache2 -ballerina-rt-2201.4.0.jar jar apache2 -org.wso2.transport.http.netty-6.3.11.jar bundle apache2 -language-server-commons-2201.4.0.jar jar apache2 -jackson-core-2.13.2.jar bundle apache2 -jaeger-core-0.31.0.jar jar apache2 -stax2-api-4.2.1.jar bundle bsd -geronimo-stax-api_1.0_spec-1.0.1.jar bundle apache2 -jzlib-1.1.3.jar jar bsd -central-client-2201.4.0.jar jar apache2 -progressbar-0.7.4.jar jar mit -geronimo-json_1.0_spec-1.0-alpha-1.jar bundle apache2 -formatter-core-2201.4.0.jar jar apache2 -datamapper-extension-2.2.0.jar jar apache2 -netty-handler-proxy-4.1.77.Final.jar bundle apache2 -toml-parser-2201.4.0.jar jar apache2 -openapi-core-1.4.0.jar jar apache2 -picocli-4.0.1.jar bundle apache2 -ballerina-parser-2201.4.0.jar jar apache2 -quartz-jobs-2.3.0.jar jar apache2 -architecture-model-generator-plugin-0.10.8.jar jar apache2 -broker-coordination-0.970.0.jar bundle apache2 -org.wso2.carbon.messaging-2.3.7.jar bundle apache2 -diagram-util-2201.4.0.jar jar apache2 -netty-codec-http2-4.1.77.Final.jar bundle apache2 -metrics-core-4.1.7.jar bundle apache2 -object-2201.4.0.jar jar apache2 -bool-2201.4.0.jar jar apache2 -future-2201.4.0.jar jar apache2 -ballerina-io-internal-2201.4.0.jar jar apache2 -javax.transaction-api-1.3.jar bundle cddl1 -asm-util-7.1.jar bundle bsd -shell-cli-2201.4.0.jar jar apache2 -error-2201.4.0.jar jar apache2 -netty-transport-native-kqueue-4.1.77.Final.jar bundle apache2 -org.wso2.carbon.core-5.1.0.jar bundle apache2 -ballerina-cli-2201.4.0.jar jar apache2 -semver-checker-core-2201.4.0.jar jar apache2 -netty-codec-http-4.1.86.Final.jar bundle apache2 -annotations-2201.4.0.jar jar apache2 -docerina-2201.4.0.jar jar apache2 -openapi-cli-1.4.0.jar jar apache2 -jline-3.11.0.jar bundle bsd3 -commons-pool-1.5.6.wso2v1.jar bundle apache2 -javacpp-1.4.2.jar jar apache2 -handlebars-4.0.6.jar bundle apache2 -architecture-model-generator-core-0.10.8.jar jar apache2 -HikariCP-3.3.1.jar bundle apache2 -org.wso2.transport.local-file-system-6.0.55.jar bundle apache2 -map-2201.4.0.jar jar apache2 -jacocoagent.jar jar apache2 -maven-resolver-2201.4.0.jar jar apache2 -transactions-api-5.0.8.jar jar apache2 -quartz-2.3.2.jar bundle apache2 -string-2201.4.0.jar jar apache2 -transaction-2201.4.0.jar jar apache2 -netty-common-4.1.77.Final.jar bundle apache2 -axiom-api-1.4.0.jar bundle apache2 -semver-checker-cli-2201.4.0.jar jar apache2 -xml-2201.4.0.jar jar apache2 -broker-common-0.970.5.jar bundle apache2 -asyncapi-cli-0.4.0.jar jar apache2 -kotlin-stdlib-1.6.0.jar jar apache2 -netty-transport-4.1.77.Final.jar bundle apache2 -okio-2.2.2.jar jar apache2 -okhttp-3.14.0.jar jar apache2 -configurable-schema-generator-2201.4.0.jar jar apache2 -org.wso2.securevault-1.0.0-wso2v2.jar bundle apache2 -org.eclipse.lsp4j.jsonrpc-0.12.0.jar bundle epl2 -debug-adapter-cli-2201.4.0.jar jar apache2 -java-semver-0.9.0.jar jar mit -commons-io-2.7.jar bundle apache2 -debug-adapter-core-2201.4.0.jar jar apache2 -org.eclipse.lsp4j.debug-0.12.0.jar bundle epl2 -org.eclipse.lsp4j.jsonrpc.debug-0.12.0.jar bundle epl2 -bal-shell-service-2201.4.0.jar jar apache2 -architecture-model-generator-ls-extension-0.10.8.jar jar apache2 -language-server-cli-2201.4.0.jar jar apache2 -ballerinalang-data-mapper-2201.4.0.jar jar apache2 -language-server-core-2201.4.0.jar jar apache2 -json-to-record-converter-2201.4.0.jar jar apache2 -trigger-service-2201.4.0.jar jar apache2 -guava-30.0-jre.jar bundle apache2 -performance-analyzer-services-2201.4.0.jar jar apache2 -language-server-stdio-launcher-2201.4.0.jar jar apache2 -openapi-ls-extension-1.4.0.jar jar apache2 -org.eclipse.lsp4j-0.12.0.jar bundle epl2 -partial-parser-2201.4.0.jar jar apache2 -cloud-tooling-2.5.0.jar jar apache2 -transaction-native-1.4.0.jar jar apache2 -observe-internal-native-1.0.5.jar jar apache2 -jwt-native-2.6.0.jar jar apache2 -ftp-compiler-plugin-2.6.0.jar jar apache2 -commons-vfs2-2.8.0.jar bundle apache2 -jsch-0.1.54.jar jar bsd -commons-net-3.9.0.jar bundle apache2 -ftp-native-2.6.0.jar jar apache2 -crypto-native-2.3.0.jar jar apache2 -bcpkix-jdk15on-1.69.jar bundle bouncy -bcprov-jdk15on-1.69.jar bundle bouncy -websocket-compiler-plugin-2.6.0.jar jar apache2 -netty-resolver-4.1.86.Final.jar bundle apache2 -netty-handler-4.1.86.Final.jar bundle apache2 -mime-native-2.6.0.jar jar apache2 -netty-buffer-4.1.86.Final.jar bundle apache2 -constraint-native-1.1.0.jar jar apache2 -netty-codec-4.1.86.Final.jar bundle apache2 -http-native-2.6.0.jar jar apache2 -netty-handler-proxy-4.1.86.Final.jar bundle apache2 -websocket-native-2.6.0.jar jar apache2 -netty-transport-4.1.86.Final.jar bundle apache2 -netty-common-4.1.86.Final.jar bundle apache2 -cache-compiler-plugin-3.4.0.jar jar apache2 -cache-native-3.4.0.jar jar apache2 -testerina-compiler-plugin-0.1.0.jar jar apache2 -udp-compiler-plugin-1.6.0.jar jar apache2 -udp-native-1.6.0.jar jar apache2 -file-compiler-plugin-1.6.0.jar jar apache2 -file-native-1.6.0.jar jar apache2 -grpc-compiler-plugin-1.6.0.jar jar apache2 -grpc-native-1.6.0.jar jar apache2 -protobuf-java-3.20.3.jar bundle bsd3 -netty-tcnative-boringssl-static-2.0.54.Final-linux-aarch_64.jar bundle apache2 -proto-google-common-protos-1.17.0.jar jar apache2 -netty-tcnative-boringssl-static-2.0.54.Final-osx-x86_64.jar bundle apache2 -netty-tcnative-boringssl-static-2.0.54.Final-linux-x86_64.jar bundle apache2 -netty-tcnative-boringssl-static-2.0.54.Final-windows-x86_64.jar bundle apache2 -netty-tcnative-classes-2.0.54.Final.jar bundle apache2 -netty-codec-http2-4.1.86.Final.jar bundle apache2 -netty-tcnative-boringssl-static-2.0.54.Final-osx-aarch_64.jar bundle apache2 -netty-tcnative-boringssl-static-2.0.54.Final.jar bundle apache2 -auth-native-2.6.0.jar jar apache2 -protobuf-java-util-3.21.7.jar bundle bsd3 -protobuf-java-3.21.7.jar bundle bsd3 -io-native-1.4.0.jar jar apache2 -oauth2-native-2.6.0.jar jar apache2 -url-native-2.2.3.jar jar apache2 -time-native-2.2.3.jar jar apache2 -opentelemetry-sdk-testing-1.0.0.jar jar apache2 -observe-native-1.0.6.jar jar apache2 -opentelemetry-semconv-1.0.0-alpha.jar jar apache2 -opentelemetry-sdk-trace-1.0.0.jar jar apache2 -opentelemetry-sdk-common-1.0.0.jar jar apache2 -tcp-compiler-plugin-1.6.0.jar jar apache2 -netty-codec-socks-4.1.86.Final.jar bundle apache2 -lz4-1.3.0.jar bundle apache2 -netty-transport-native-unix-common-4.1.86.Final.jar bundle apache2 -tcp-native-1.6.0.jar jar apache2 -jboss-marshalling-2.0.5.Final.jar jar apache2 -http-compiler-plugin-2.6.0.jar jar apache2 -mimepull-1.9.11.jar bundle edl1 -graphql-compiler-plugin-1.6.0.jar jar apache2 -graphql-commons-1.6.0.jar jar apache2 -graphql-native-1.6.0.jar jar apache2 -cloud-compiler-plugin-2.5.0.jar jar apache2 -task-native-2.3.0.jar jar apache2 -log-compiler-plugin-2.6.0.jar jar apache2 -log-native-2.6.0.jar jar apache2 -jakarta.activation-1.2.2.jar bundle edl1 -os-test-utils-1.6.0.jar jar apache2 -os-native-1.6.0.jar jar apache2 -websubhub-compiler-plugin-1.6.0.jar jar apache2 -websubhub-native-1.6.0.jar jar apache2 -xmlresolver-4.5.2.jar jar apache2 -xslt-native-2.4.0.jar jar apache2 -Saxon-HE-11.4.jar jar mpl10 -persist-compiler-plugin-0.1.0.jar jar apache2 -xmldata-compiler-plugin-2.4.0.jar jar apache2 -xmldata-native-2.4.0.jar jar apache2 -protobuf-native-1.3.2.jar jar apache2 -email-compiler-plugin-2.6.0.jar jar apache2 -greenmail-1.5.11.jar bundle apache2 -email-native-2.6.0.jar jar apache2 -constraint-compiler-plugin-1.1.0.jar jar apache2 -websub-compiler-plugin-2.6.0.jar jar apache2 -websub-native-2.6.0.jar jar apache2 -sql-compiler-plugin-1.7.0.jar jar apache2 -sql-native-1.7.0.jar jar apache2 -ballerinai-transaction-0.0.0.jar jar apache2 -ballerinai-observe-0.0.0.jar jar apache2 -ballerina-lang.object-0.0.0.jar jar apache2 -ballerina-jwt-2.6.0.jar jar apache2 -ballerina-lang.boolean-0.0.0.jar jar apache2 -ballerina-lang.xml-0.0.0.jar jar apache2 -ballerina-ftp-2.6.0.jar jar apache2 -ballerina-crypto-2.3.0.jar jar apache2 -ballerina-lang.array-0.0.0.jar jar apache2 -ballerina-websocket-2.6.0.jar jar apache2 -ballerina-cache-3.4.0.jar jar apache2 -ballerina-test-0.0.0.jar jar apache2 -ballerina-lang.transaction-0.0.0.jar jar apache2 -ballerina-udp-1.6.0.jar jar apache2 -ballerina-file-1.6.0.jar jar apache2 -ballerina-grpc-1.6.0.jar jar apache2 -ballerina-grpc.types.timestamp-1.6.0.jar jar apache2 -ballerina-grpc.types.any-1.6.0.jar jar apache2 -ballerina-grpc.types.duration-1.6.0.jar jar apache2 -ballerina-grpc.types.struct-1.6.0.jar jar apache2 -ballerina-grpc.types.wrappers-1.6.0.jar jar apache2 -ballerina-auth-2.6.0.jar jar apache2 -ballerina-lang.__internal-0.0.0.jar jar apache2 -ballerina-jballerina.java-0.0.0.jar jar apache2 -ballerina-lang.string-0.0.0.jar jar apache2 -ballerina-io-1.4.0.jar jar apache2 -ballerina-oauth2-2.6.0.jar jar apache2 -ballerina-lang.future-0.0.0.jar jar apache2 -ballerina-regex-1.3.2.jar jar apache2 -ballerina-lang.value-0.0.0.jar jar apache2 -ballerina-openapi-1.4.0.jar jar apache2 -ballerina-url-2.2.3.jar jar apache2 -ballerina-time-2.2.3.jar jar apache2 -ballerina-observe-1.0.6.jar jar apache2 -ballerina-observe.mockextension-1.0.6.jar jar apache2 -ballerina-lang.float-0.0.0.jar jar apache2 -ballerina-jballerina.java.arrays-1.2.3.jar jar apache2 -ballerina-tcp-1.6.0.jar jar apache2 -ballerina-lang.decimal-0.0.0.jar jar apache2 -ballerina-http-2.6.0.jar jar apache2 -ballerina-graphql-1.6.0.jar jar apache2 -ballerina-graphql.parser-1.6.0.jar jar apache2 -ballerina-cloud-2.5.0.jar jar apache2 -ballerina-task-2.3.0.jar jar apache2 -ballerina-lang.table-0.0.0.jar jar apache2 -ballerina-lang.regexp-0.0.0.jar jar apache2 -ballerina-lang.annotations-0.0.0.jar jar apache2 -ballerina-log-2.6.0.jar jar apache2 -ballerina-mime-2.6.0.jar jar apache2 -ballerina-os-1.6.0.jar jar apache2 -ballerina-lang.stream-0.0.0.jar jar apache2 -ballerina-lang.error-0.0.0.jar jar apache2 -ballerina-websubhub-1.6.0.jar jar apache2 -ballerina-xslt-2.4.0.jar jar apache2 -ballerina-random-1.3.1.jar jar apache2 -ballerina-lang.typedesc-0.0.0.jar jar apache2 -ballerina-uuid-1.4.0.jar jar apache2 -ballerina-lang.function-0.0.0.jar jar apache2 -ballerina-persist-0.1.0.jar jar apache2 -ballerina-xmldata-2.4.0.jar jar apache2 -ballerina-protobuf.types.wrappers-1.3.2.jar jar apache2 -ballerina-protobuf.types.timestamp-1.3.2.jar jar apache2 -ballerina-protobuf.types.any-1.3.2.jar jar apache2 -ballerina-protobuf.types.struct-1.3.2.jar jar apache2 -ballerina-protobuf.types.empty-1.3.2.jar jar apache2 -ballerina-protobuf-1.3.2.jar jar apache2 -ballerina-protobuf.types.duration-1.3.2.jar jar apache2 -ballerina-lang.map-0.0.0.jar jar apache2 -ballerina-email-2.6.0.jar jar apache2 -ballerina-lang.query-0.0.0.jar jar apache2 -ballerina-lang.int-0.0.0.jar jar apache2 -ballerina-lang.runtime-0.0.0.jar jar apache2 -ballerina-constraint-1.1.0.jar jar apache2 -ballerina-websub-2.6.0.jar jar apache2 -ballerina-sql-1.7.0.jar jar apache2 +ballerina-command-1.3.15.jar jar apache2 +transaction-2201.6.0.jar jar apache2 +commons-text-1.10.0.jar bundle apache2 +compiler-0.8.9.jar jar apache2 +gson-2.8.9.jar bundle apache2 +query-2201.6.0.jar jar apache2 +org.wso2.carbon.metrics.core-2.3.7.jar bundle apache2 +docerina-2201.6.0.jar jar apache2 +org.jacoco.core-0.8.5.jar bundle epl2 +transactions-5.0.8.jar jar apache2 +jballerina.java-2201.6.0.jar jar apache2 +ballerina-io-internal-2201.6.0.jar jar apache2 +diagram-util-2201.6.0.jar jar apache2 +broker-auth-0.970.0.jar bundle apache2 +ballerina-linter-2201.6.0.jar jar apache2 +staxon-core-1.2.0.wso2v2.jar bundle apache2 +asyncapi-cli-0.6.0.jar jar apache2 +javax.mail-1.6.2.jar bundle cddl1 +geronimo-activation_1.1_spec-1.1.jar bundle apache2 +graphql-model-generator-core-1.1.0.jar jar apache2 +openapi-extension-1.6.0.jar jar apache2 +object-2201.6.0.jar jar apache2 +broker-rest-runner-0.970.0.jar bundle apache2 +netty-transport-native-epoll-4.1.77.Final.jar bundle apache2 +observability-symbol-collector-2201.6.0.jar jar apache2 +toml-parser-2201.6.0.jar jar apache2 + mit +integer-2201.6.0.jar jar apache2 +runtime-2201.6.0.jar jar apache2 +openapi-build-extension-1.6.0.jar jar apache2 +jackson-dataformat-yaml-2.13.2.jar bundle apache2 +netty-handler-4.1.77.Final.jar bundle apache2 +xml-2201.6.0.jar jar apache2 +asm-analysis-7.1.jar bundle bsd +netty-resolver-4.1.77.Final.jar bundle apache2 +central-client-2201.6.0.jar jar apache2 +axiom-impl-1.4.0.jar bundle apache2 +commons-beanutils-1.9.4.jar bundle apache2 +jackson-databind-2.14.0.jar bundle apache2 +ballerina-bindgen-2201.6.0.jar jar apache2 +kotlin-stdlib-common-1.6.0.jar jar apache2 +asm-tree-7.2.jar bundle bsd3 +ballerina-lang-2201.6.0.jar jar apache2 +ballerina-rt-2201.6.0.jar jar apache2 +org.jacoco.report-0.8.5.jar bundle epl2 +jaxen-1.1.6.jar bundle apache2 +table-2201.6.0.jar jar apache2 +transactions-jta-5.0.8.jar jar apache2 +jackson-annotations-2.13.2.jar bundle apache2 +function-2201.6.0.jar jar apache2 +maven-resolver-2201.6.0.jar jar apache2 +commons-collections-3.2.2.jar bundle apache2 +package-semantic-analyzer-1.0.0.jar jar apache2 +kraal-0.0.16.jar jar mit +annotations-2201.6.0.jar jar apache2 +commons-codec-1.14.jar bundle apache2 +identifier-util-2201.6.0.jar jar apache2 +value-2201.6.0.jar jar apache2 +language-server-commons-2201.6.0.jar jar apache2 +asm-commons-7.2.jar bundle bsd3 +broker-core-0.970.5.jar bundle apache2 +protoc-cli-0.1.1.jar jar apache2 +floatingpoint-2201.6.0.jar jar apache2 +error-2201.6.0.jar jar apache2 +asm-7.2.jar bundle bsd3 +testerina-runtime-2201.6.0.jar jar apache2 +jackson-datatype-jsr310-2.13.2.jar bundle apache2 +semver-checker-cli-2201.6.0.jar jar apache2 +shell-core-2201.6.0.jar jar apache2 +openapi-bal-service-1.6.0.jar jar apache2 +netty-buffer-4.1.77.Final.jar bundle apache2 +commons-compress-1.21.jar bundle apache2 +array-2201.6.0.jar jar apache2 +architecture-model-generator-plugin-1.1.0.jar jar apache2 +string-2201.6.0.jar jar apache2 +netty-codec-4.1.77.Final.jar bundle apache2 +jaeger-thrift-0.31.0.jar jar apache2 +typedesc-2201.6.0.jar jar apache2 +graphql-cli-0.6.0.jar jar mit +jboss-logging-3.3.1.Final.jar bundle apache2 +java-diff-utils-4.5.jar bundle apache2 +atomikos-util-5.0.8.jar jar apache2 +map-2201.6.0.jar jar apache2 +snakeyaml-1.32.jar bundle apache2 +formatter-core-2201.6.0.jar jar apache2 +org.wso2.transport.http.netty-6.3.11.jar bundle apache2 +jackson-core-2.13.2.jar bundle apache2 +jaeger-core-0.31.0.jar jar apache2 +stax2-api-4.2.1.jar bundle bsd +geronimo-stax-api_1.0_spec-1.0.1.jar bundle apache2 +future-2201.6.0.jar jar apache2 +jzlib-1.1.3.jar jar bsd +progressbar-0.7.4.jar jar mit +geronimo-json_1.0_spec-1.0-alpha-1.jar bundle apache2 +ballerina-cli-2201.6.0.jar jar apache2 +netty-handler-proxy-4.1.77.Final.jar bundle apache2 +picocli-4.0.1.jar bundle apache2 +quartz-jobs-2.3.0.jar jar apache2 +broker-coordination-0.970.0.jar bundle apache2 +org.wso2.carbon.messaging-2.3.7.jar bundle apache2 +formatter-cli-2201.6.0.jar jar apache2 +openapi-validator-1.6.0.jar jar apache2 +netty-codec-http2-4.1.77.Final.jar bundle apache2 +datamapper-extension-2.2.0.jar jar apache2 +decimal-2201.6.0.jar jar apache2 +ballerina-tools-api-2201.6.0.jar jar apache2 +semver-checker-core-2201.6.0.jar jar apache2 +metrics-core-4.1.7.jar bundle apache2 +configurable-schema-generator-2201.6.0.jar jar apache2 +javax.transaction-api-1.3.jar bundle cddl1 +asm-util-7.1.jar bundle bsd +ballerina-parser-2201.6.0.jar jar apache2 +netty-transport-native-kqueue-4.1.77.Final.jar bundle apache2 +stream-2201.6.0.jar jar apache2 +org.wso2.carbon.core-5.1.0.jar bundle apache2 +woodstox-core-6.5.0.jar bundle apache2 +netty-codec-http-4.1.86.Final.jar bundle apache2 +openapi-cli-1.6.0.jar jar apache2 +architecture-model-generator-core-1.1.0.jar jar apache2 +regexp-2201.6.0.jar jar apache2 +jline-3.11.0.jar bundle bsd3 +commons-pool-1.5.6.wso2v1.jar bundle apache2 +javacpp-1.4.2.jar jar apache2 +handlebars-4.0.6.jar bundle apache2 +testerina-core-2201.6.0.jar jar apache2 +HikariCP-3.3.1.jar bundle apache2 +org.wso2.transport.local-file-system-6.0.55.jar bundle apache2 +jacocoagent.jar jar apache2 +transactions-api-5.0.8.jar jar apache2 +quartz-2.3.2.jar bundle apache2 +openapi-core-1.6.0.jar jar apache2 +netty-common-4.1.77.Final.jar bundle apache2 +ballerina-metrics-extension-2201.6.0.jar jar apache2 +axiom-api-1.4.0.jar bundle apache2 +shell-cli-2201.6.0.jar jar apache2 +broker-common-0.970.5.jar bundle apache2 +syntax-api-calls-gen-2201.6.0.jar jar apache2 +persist-cli-1.0.0.jar jar apache2 +kotlin-stdlib-1.6.0.jar jar apache2 +netty-transport-4.1.77.Final.jar bundle apache2 +graphql-schema-file-generator-0.6.0.jar jar apache2 +okio-2.2.2.jar jar apache2 +bool-2201.6.0.jar jar apache2 +okhttp-3.14.0.jar jar apache2 +org.wso2.securevault-1.0.0-wso2v2.jar bundle apache2 +org.eclipse.lsp4j.jsonrpc-0.12.0.jar bundle epl2 +debug-adapter-core-2201.6.0.jar jar apache2 +debug-adapter-cli-2201.6.0.jar jar apache2 +java-semver-0.9.0.jar jar mit +commons-io-2.7.jar bundle apache2 +org.eclipse.lsp4j.debug-0.12.0.jar bundle epl2 +org.eclipse.lsp4j.jsonrpc.debug-0.12.0.jar bundle epl2 +ballerinalang-data-mapper-2201.6.0.jar jar apache2 +architecture-model-generator-ls-extension-1.1.0.jar jar apache2 +bal-shell-service-2201.6.0.jar jar apache2 +graphql-model-generator-ls-extension-1.1.0.jar jar apache2 +guava-30.0-jre.jar bundle apache2 +openapi-ls-extension-1.6.0.jar jar apache2 +org.eclipse.lsp4j.jsonrpc-0.15.0.jar bundle apache2 +language-server-cli-2201.6.0.jar jar apache2 +trigger-service-2201.6.0.jar jar apache2 +json-to-record-converter-2201.6.0.jar jar apache2 +org.eclipse.lsp4j-0.15.0.jar bundle apache2 +cloud-tooling-2.7.0.jar jar apache2 +performance-analyzer-services-2201.6.0.jar jar apache2 +language-server-stdio-launcher-2201.6.0.jar jar apache2 +partial-parser-2201.6.0.jar jar apache2 +language-server-core-2201.6.0.jar jar apache2 +transaction-native-1.6.0.jar jar apache2 +observe-internal-native-1.0.6.jar jar apache2 +jwt-native-2.8.0.jar jar apache2 +ftp-compiler-plugin-2.7.1.jar jar apache2 +commons-vfs2-2.8.0.jar bundle apache2 +jsch-0.1.54.jar jar bsd +ftp-native-2.7.1.jar jar apache2 +commons-net-3.9.0.jar bundle apache2 +crypto-native-2.3.1.jar jar apache2 +bcpkix-jdk15on-1.69.jar bundle bouncy +bcprov-jdk15on-1.69.jar bundle bouncy +websocket-compiler-plugin-2.8.0.jar jar apache2 +netty-resolver-4.1.86.Final.jar bundle apache2 +netty-handler-4.1.86.Final.jar bundle apache2 +netty-buffer-4.1.86.Final.jar bundle apache2 +netty-codec-4.1.86.Final.jar bundle apache2 +websocket-native-2.8.0.jar jar apache2 +netty-handler-proxy-4.1.86.Final.jar bundle apache2 +constraint-native-1.2.0.jar jar apache2 +mime-native-2.7.1.jar jar apache2 +netty-transport-4.1.86.Final.jar bundle apache2 +http-native-2.8.0.jar jar apache2 +netty-common-4.1.86.Final.jar bundle apache2 +cache-compiler-plugin-3.5.0.jar jar apache2 +cache-native-3.5.0.jar jar apache2 +testerina-compiler-plugin-0.1.0.jar jar apache2 +udp-compiler-plugin-1.7.1.jar jar apache2 +udp-native-1.7.1.jar jar apache2 +file-compiler-plugin-1.7.1.jar jar apache2 +file-native-1.7.1.jar jar apache2 +grpc-compiler-plugin-1.8.0.jar jar apache2 +protobuf-java-3.20.3.jar bundle bsd3 +netty-tcnative-boringssl-static-2.0.54.Final-linux-aarch_64.jar bundle apache2 +proto-google-common-protos-1.17.0.jar jar apache2 +netty-transport-native-unix-common-4.1.86.Final.jar bundle apache2 +netty-tcnative-boringssl-static-2.0.54.Final-osx-x86_64.jar bundle apache2 +netty-tcnative-boringssl-static-2.0.54.Final-linux-x86_64.jar bundle apache2 +netty-tcnative-boringssl-static-2.0.54.Final-windows-x86_64.jar bundle apache2 +grpc-native-1.8.0.jar jar apache2 +netty-tcnative-classes-2.0.54.Final.jar bundle apache2 +ballerina-parser-2201.5.0.jar jar apache2 +netty-codec-http2-4.1.86.Final.jar bundle apache2 +formatter-core-2201.5.0.jar jar apache2 +netty-tcnative-boringssl-static-2.0.54.Final-osx-aarch_64.jar bundle apache2 +netty-tcnative-boringssl-static-2.0.54.Final.jar bundle apache2 +auth-native-2.8.0.jar jar apache2 +io-native-1.4.1.jar jar apache2 +oauth2-native-2.8.0.jar jar apache2 +url-native-2.2.3.jar jar apache2 +time-native-2.2.4.jar jar apache2 +opentelemetry-sdk-testing-1.0.0.jar jar apache2 +observe-native-1.0.7.jar jar apache2 +opentelemetry-semconv-1.0.0-alpha.jar jar apache2 +opentelemetry-sdk-trace-1.0.0.jar jar apache2 +opentelemetry-sdk-common-1.0.0.jar jar apache2 +tcp-compiler-plugin-1.7.1.jar jar apache2 +netty-codec-socks-4.1.86.Final.jar bundle apache2 +lz4-1.3.0.jar bundle apache2 +tcp-native-1.7.1.jar jar apache2 +jboss-marshalling-2.0.5.Final.jar jar apache2 +http-compiler-plugin-2.8.0.jar jar apache2 +mimepull-1.9.11.jar bundle edl1 +graphql-compiler-plugin-1.8.0.jar jar apache2 +graphql-commons-1.8.0.jar jar apache2 +graphql-native-1.8.0.jar jar apache2 +cloud-compiler-plugin-2.7.0.jar jar apache2 +task-native-2.3.2.jar jar apache2 +log-compiler-plugin-2.7.1.jar jar apache2 +log-native-2.7.1.jar jar apache2 +jakarta.activation-1.2.2.jar bundle edl1 +io-native-1.4.0.jar jar apache2 +os-native-1.6.0.jar jar apache2 +os-test-utils-1.6.0.jar jar apache2 +websubhub-compiler-plugin-1.8.0.jar jar apache2 +websubhub-native-1.8.0.jar jar apache2 +xmlresolver-4.5.2.jar jar apache2 +Saxon-HE-11.4.jar jar mpl10 +xslt-native-2.4.0.jar jar apache2 +persist-compiler-plugin-1.0.0.jar jar apache2 +persist-native-1.0.0.jar jar apache2 +xmldata-compiler-plugin-2.5.0.jar jar apache2 +xmldata-native-2.5.0.jar jar apache2 +protobuf-native-1.4.0.jar jar apache2 +email-compiler-plugin-2.7.1.jar jar apache2 +greenmail-1.5.11.jar bundle apache2 +email-native-2.7.1.jar jar apache2 +constraint-compiler-plugin-1.2.0.jar jar apache2 +websub-compiler-plugin-2.8.0.jar jar apache2 +websub-native-2.8.0.jar jar apache2 +sql-compiler-plugin-1.9.0.jar jar apache2 +sql-native-1.9.0.jar jar apache2 +ballerinai-transaction-0.0.0.jar jar apache2 +ballerinai-observe-0.0.0.jar jar apache2 +ballerina-lang.object-0.0.0.jar jar apache2 +ballerina-jwt-2.8.0.jar jar apache2 +ballerina-lang.boolean-0.0.0.jar jar apache2 +ballerina-lang.xml-0.0.0.jar jar apache2 +ballerina-edi-1.0.1.jar jar apache2 +ballerina-ftp-2.7.1.jar jar apache2 +ballerina-crypto-2.3.1.jar jar apache2 +ballerina-lang.array-0.0.0.jar jar apache2 +ballerina-toml.writer-0.3.0.jar jar apache2 +ballerina-toml.lexer-0.3.0.jar jar apache2 +ballerina-toml.parser-0.3.0.jar jar apache2 +ballerina-toml-0.3.0.jar jar apache2 +ballerina-websocket-2.8.0.jar jar apache2 +ballerina-math.vector-1.0.1.jar jar apache2 +ballerina-cache-3.5.0.jar jar apache2 +ballerina-test-0.0.0.jar jar apache2 +ballerina-lang.transaction-0.0.0.jar jar apache2 +ballerina-udp-1.7.1.jar jar apache2 +ballerina-file-1.7.1.jar jar apache2 +ballerina-grpc.types.struct-1.8.0.jar jar apache2 +ballerina-grpc.types.wrappers-1.8.0.jar jar apache2 +ballerina-grpc.types.any-1.8.0.jar jar apache2 +ballerina-grpc.types.duration-1.8.0.jar jar apache2 +ballerina-grpc.types.timestamp-1.8.0.jar jar apache2 +ballerina-grpc-1.8.0.jar jar apache2 +ballerina-auth-2.8.0.jar jar apache2 +ballerina-lang.__internal-0.0.0.jar jar apache2 +ballerina-jballerina.java-0.0.0.jar jar apache2 +ballerina-lang.string-0.0.0.jar jar apache2 +ballerina-io-1.4.1.jar jar apache2 +ballerina-oauth2-2.8.0.jar jar apache2 +ballerina-lang.future-0.0.0.jar jar apache2 +ballerina-regex-1.4.3.jar jar apache2 +ballerina-lang.value-0.0.0.jar jar apache2 +ballerina-openapi-1.6.0.jar jar apache2 +ballerina-url-2.2.3.jar jar apache2 +ballerina-time-2.2.4.jar jar apache2 +ballerina-observe-1.0.7.jar jar apache2 +ballerina-observe.mockextension-1.0.7.jar jar apache2 +ballerina-lang.float-0.0.0.jar jar apache2 +ballerina-jballerina.java.arrays-1.2.3.jar jar apache2 +ballerina-tcp-1.7.1.jar jar apache2 +ballerina-lang.decimal-0.0.0.jar jar apache2 +ballerina-http-2.8.0.jar jar apache2 +ballerina-graphql.parser-1.8.0.jar jar apache2 +ballerina-graphql.subgraph-1.8.0.jar jar apache2 +ballerina-graphql-1.8.0.jar jar apache2 +ballerina-cloud-2.7.0.jar jar apache2 +ballerina-task-2.3.2.jar jar apache2 +ballerina-lang.table-0.0.0.jar jar apache2 +ballerina-lang.regexp-0.0.0.jar jar apache2 +ballerina-lang.annotations-0.0.0.jar jar apache2 +ballerina-yaml.common-0.3.0.jar jar apache2 +ballerina-yaml-0.3.0.jar jar apache2 +ballerina-yaml.composer-0.3.0.jar jar apache2 +ballerina-yaml.schema-0.3.0.jar jar apache2 +ballerina-yaml.serializer-0.3.0.jar jar apache2 +ballerina-yaml.lexer-0.3.0.jar jar apache2 +ballerina-yaml.parser-0.3.0.jar jar apache2 +ballerina-yaml.emitter-0.3.0.jar jar apache2 +ballerina-log-2.7.1.jar jar apache2 +ballerina-mime-2.7.1.jar jar apache2 +ballerina-os-1.6.0.jar jar apache2 +ballerina-lang.stream-0.0.0.jar jar apache2 +ballerina-lang.error-0.0.0.jar jar apache2 +ballerina-websubhub-1.8.0.jar jar apache2 +ballerina-xslt-2.4.0.jar jar apache2 +ballerina-random-1.3.1.jar jar apache2 +ballerina-lang.typedesc-0.0.0.jar jar apache2 +ballerina-uuid-1.5.1.jar jar apache2 +ballerina-lang.function-0.0.0.jar jar apache2 +ballerina-persist-1.0.0.jar jar apache2 +ballerina-xmldata-2.5.0.jar jar apache2 +ballerina-protobuf.types.timestamp-1.4.0.jar jar apache2 +ballerina-protobuf.types.wrappers-1.4.0.jar jar apache2 +ballerina-protobuf.types.duration-1.4.0.jar jar apache2 +ballerina-protobuf-1.4.0.jar jar apache2 +ballerina-protobuf.types.empty-1.4.0.jar jar apache2 +ballerina-protobuf.types.struct-1.4.0.jar jar apache2 +ballerina-protobuf.types.any-1.4.0.jar jar apache2 +ballerina-lang.map-0.0.0.jar jar apache2 +ballerina-email-2.7.1.jar jar apache2 +ballerina-lang.query-0.0.0.jar jar apache2 +ballerina-lang.int-0.0.0.jar jar apache2 +ballerina-lang.runtime-0.0.0.jar jar apache2 +ballerina-constraint-1.2.0.jar jar apache2 +ballerina-websub-2.8.0.jar jar apache2 +ballerina-sql-1.9.0.jar jar apache2 The license types used by the above libraries and their information is given below: apache2 Apache License Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.html -mit MIT License - http://www.opensource.org/licenses/mit-license.php epl2 Eclipse Public License Version 2.0 https://www.eclipse.org/legal/epl-2.0/ cddl1 Common Development and Distribution License http://www.opensource.org/licenses/cddl1.php +mit MIT License + http://www.opensource.org/licenses/mit-license.php bsd Berkeley License http://www.opensource.org/licenses/bsd-license.php bsd3 Berkeley License - 3 @@ -362,4 +383,4 @@ bouncy Bouncy Castle License edl1 Eclipse Distribution License Version 1.0 http://www.eclipse.org/org/documents/edl-v10.php mpl10 Mozilla Public License Version 1.0 - http://www.mozilla.org/MPL/ \ No newline at end of file + http://www.mozilla.org/MPL/ diff --git a/ballerina/build.gradle b/ballerina/build.gradle index da8450c02f..cd4e21605c 100644 --- a/ballerina/build.gradle +++ b/ballerina/build.gradle @@ -58,7 +58,7 @@ task unpackBallerinaJre(type: Download) { "${jreBaseURL}/ballerina-jre-linux-64-${ballerinaJreVersion}.zip", "${jreBaseURL}/ballerina-jre-macos-64-${ballerinaJreVersion}.zip", "${jreBaseURL}/ballerina-jre-macos-arm-64-${ballerinaJreVersion}.zip", - "${jreBaseURL}/ballerina-jre-windows-64-${ballerinaJreVersion}.zip" + "${jreBaseURL}/ballerina-jre-win-64-${ballerinaJreVersion}.zip" ]) onlyIfModified true dest "${jreLocation}" @@ -168,7 +168,7 @@ task extractJreForMacArm(type: Copy) { task extractJreForWindows(type: Copy) { group = "extract_jre" - from zipTree { "${jreLocation}/ballerina-jre-windows-64-${ballerinaJreVersion}.zip" } + from zipTree { "${jreLocation}/ballerina-jre-win-64-${ballerinaJreVersion}.zip" } into("${buildDir}/target/extracted-jre-windows") } @@ -284,8 +284,10 @@ task combineDocs(type: Exec) { task packageDist(type: Zip) { group = "package_distribution" description = 'Ballerina Tools Distribution Assembly' - baseName = "${distributionName}" - ext { parentDir = "${baseName}-${shortVersion}" } + ext { + baseName = "${distributionName}" + parentDir = "${baseName}-${shortVersion}" + } archiveFileName = "${baseName}-${shortVersion}.zip" entryCompression = ZipEntryCompression.DEFLATED @@ -327,8 +329,10 @@ task packageDist(type: Zip) { task packageDistZip(type: Zip) { group = "package_distribution" description = 'Ballerina Distribution Assembly' - baseName = "${distributionName}-${version}" - ext { parentDir = "${baseName}-${codeName}" } + ext { + baseName = "${distributionName}-${version}" + parentDir = "${baseName}-${codeName}" + } archiveFileName = "${distributionName}-${version}-${codeName}.zip" entryCompression = ZipEntryCompression.DEFLATED @@ -410,12 +414,14 @@ task packageDistZip(type: Zip) { task packageDistLinux(type: Zip) { group = "package_distribution" description = 'Ballerina Linux Distribution Assembly' - baseName = "${distributionName}-${version}" - ext { parentDir = "${baseName}-${codeName}-linux" } + ext { + baseName = "${distributionName}-${version}" + parentDir = "${baseName}-${codeName}-linux" + } archiveFileName = "${parentDir}.zip" entryCompression = ZipEntryCompression.DEFLATED - into("${parentDir}/dependencies/${dependencyJREVersion}") { + into("${parentDir}/dependencies") { from "build/target/extracted-jre-linux" fileMode = 0755 } @@ -497,12 +503,14 @@ task packageDistLinux(type: Zip) { task packageDistMac(type: Zip) { group = "package_distribution" description = 'Ballerina MacOS Distribution Assembly' - baseName = "${distributionName}-${version}" - ext { parentDir = "${baseName}-${codeName}-macos" } + ext { + baseName = "${distributionName}-${version}" + parentDir = "${baseName}-${codeName}-macos" + } archiveFileName = "${parentDir}.zip" entryCompression = ZipEntryCompression.DEFLATED - into("${parentDir}/dependencies/${dependencyJREVersion}") { + into("${parentDir}/dependencies") { from "build/target/extracted-jre-macos" fileMode = 0755 } @@ -580,12 +588,14 @@ task packageDistMac(type: Zip) { task packageDistMacArm(type: Zip) { group = "package_distribution" description = 'Ballerina MacOS-ARM Distribution Assembly' - baseName = "${distributionName}-${version}" - ext { parentDir = "${baseName}-${codeName}-macos-arm" } + ext { + baseName = "${distributionName}-${version}" + parentDir = "${baseName}-${codeName}-macos-arm" + } archiveFileName = "${parentDir}.zip" entryCompression = ZipEntryCompression.DEFLATED - into("${parentDir}/dependencies/${dependencyJREVersion}") { + into("${parentDir}/dependencies") { from "build/target/extracted-jre-macos-arm" fileMode = 0755 } @@ -663,12 +673,14 @@ task packageDistMacArm(type: Zip) { task packageDistWindows(type: Zip) { group = "package_distribution" description = 'Ballerina Windows Distribution Assembly' - baseName = "${distributionName}-${version}" - ext { parentDir = "${baseName}-${codeName}-windows" } + ext { + baseName = "${distributionName}-${version}" + parentDir = "${baseName}-${codeName}-windows" + } archiveFileName = "${parentDir}.zip" entryCompression = ZipEntryCompression.DEFLATED - into("${parentDir}/dependencies/${dependencyJREVersion}") { + into("${parentDir}/dependencies") { from "build/target/extracted-jre-windows" fileMode = 0755 } @@ -1292,7 +1304,7 @@ task testDevToolsIntegration() { task generateCache(dependsOn: ':cache-generator:build') { doFirst { - download { + download.run { src "https://raw.githubusercontent.com/ballerina-platform/ballerina-release/${balstdlibBranch}/dependabot/resources/extensions.json" dest "${project.rootDir}/ballerina/build/target/" } @@ -1373,7 +1385,7 @@ task generateCache(dependsOn: ':cache-generator:build') { def moduleName = dependency.module_name[i].toString() + "-ballerina-zip" if ( sortedLibs.contains(moduleName) ) { if ( !dependencyMap["${moduleName}"].contains(dependency.version[i].toString())) - dependencyMap["${moduleName}"].add(dependency.version[i].toString()) + dependencyMap["${moduleName}"].add(dependency.version[i].toString()) } } } @@ -1475,6 +1487,7 @@ packageDist.dependsOn combineDocs packageDist.dependsOn generateCache packageDistZip.dependsOn packageDist packageDistLinux.dependsOn packageDistZip +packageDistLinux.dependsOn unzipDistForTests packageDistMac.dependsOn packageDistLinux packageDistMacArm.dependsOn packageDistMac packageDistWindows.dependsOn packageDistMacArm diff --git a/build.gradle b/build.gradle index 0d3f5d8e7e..141ac02e7d 100644 --- a/build.gradle +++ b/build.gradle @@ -17,10 +17,10 @@ plugins { id 'base' id 'maven-publish' - id 'net.researchgate.release' version '2.6.0' - id 'de.undercouch.download' version '4.1.1' - id "com.github.johnrengelman.shadow" version "5.2.0" - id "com.github.spotbugs" version "4.0.5" + id 'net.researchgate.release' version '2.8.0' + id 'de.undercouch.download' version '5.4.0' + id "com.github.johnrengelman.shadow" version "8.1.1" + id "com.github.spotbugs" version "5.0.14" } description = 'Ballerina - Tools - Parent' @@ -34,12 +34,12 @@ ext { ballerinaCommandVersion = project.ballerinaCommandVersion picocliVersion = "4.0.1" - testngVersion = "6.14.3" + testngVersion = "7.6.1" netLingalaZip4jVersion = "2.8.0" commonsIoVersion = "2.6" commonsLang3Version = "3.9" lsp4jDebugVersion = "0.7.1" - puppycrawlCheckstyleVersion = "8.18" + puppycrawlCheckstyleVersion = "10.12.1" } allprojects { @@ -71,8 +71,8 @@ allprojects { subprojects { apply plugin: 'java' - sourceCompatibility = 11 - targetCompatibility = 11 + sourceCompatibility = 17 + targetCompatibility = 17 tasks.withType(JavaCompile) { options.encoding = 'UTF-8' } @@ -148,7 +148,6 @@ subprojects { ballerinaStdLibs "io.ballerina.stdlib:io-ballerina:${stdlibIoVersion}" ballerinaStdLibs "io.ballerina.stdlib:jballerina.java.arrays-ballerina:${stdlibJavaArraysVersion}" ballerinaStdLibs "io.ballerina.stdlib:random-ballerina:${stdlibRandomVersion}" - ballerinaStdLibs "io.ballerina.stdlib:regex-ballerina:${stdlibRegexVersion}" ballerinaStdLibs "io.ballerina.stdlib:time-ballerina:${stdlibTimeVersion}" ballerinaStdLibs "io.ballerina.stdlib:url-ballerina:${stdlibUrlVersion}" ballerinaStdLibs "io.ballerina.stdlib:xmldata-ballerina:${stdlibXmldataVersion}" @@ -162,6 +161,7 @@ subprojects { ballerinaStdLibs "io.ballerina.stdlib:file-ballerina:${stdlibFileVersion}" ballerinaStdLibs "io.ballerina.stdlib:ftp-ballerina:${stdlibFtpVersion}" ballerinaStdLibs "io.ballerina.stdlib:mime-ballerina:${stdlibMimeVersion}" + ballerinaStdLibs "io.ballerina.stdlib:mqtt-ballerina:${stdlibMqttVersion}" ballerinaStdLibs "io.ballerina.stdlib:tcp-ballerina:${stdlibTcpVersion}" ballerinaStdLibs "io.ballerina.stdlib:udp-ballerina:${stdlibUdpVersion}" ballerinaStdLibs "io.ballerina.stdlib:uuid-ballerina:${stdlibUuidVersion}" @@ -183,8 +183,10 @@ subprojects { ballerinaStdLibs "io.ballerina.stdlib:persist-ballerina:${stdlibPersistVersion}" ballerinaStdLibs "io.ballerina.stdlib:yaml-ballerina:${stdlibYamlVersion}" ballerinaStdLibs "io.ballerina.stdlib:toml-ballerina:${stdlibTomlVersion}" + ballerinaStdLibs "io.ballerina.stdlib:soap-ballerina:${stdlibSoapVersion}" ballerinaStdLibs "io.ballerina.stdlib:observe-ballerina:${observeVersion}" ballerinaStdLibs "io.ballerina.stdlib:math.vector-ballerina:${stdlibMathVectorVersion}" + ballerinaStdLibs "io.ballerina.stdlib:edi-ballerina:${stdlibEdiVersion}" /* Ballerina Persist Tool */ ballerinaStdLibs "io.ballerina:persist-tools:${persistToolVersion}" diff --git a/cache-generator/src/main/java/io/ballerina/gencache/cmd/GenCacheCmd.java b/cache-generator/src/main/java/io/ballerina/gencache/cmd/GenCacheCmd.java index 4530f397ad..41665c8595 100644 --- a/cache-generator/src/main/java/io/ballerina/gencache/cmd/GenCacheCmd.java +++ b/cache-generator/src/main/java/io/ballerina/gencache/cmd/GenCacheCmd.java @@ -21,6 +21,7 @@ import io.ballerina.projects.*; import io.ballerina.projects.bala.BalaProject; import io.ballerina.projects.repos.FileSystemCache; +import io.ballerina.tools.diagnostics.Diagnostic; import picocli.CommandLine; import java.io.PrintStream; @@ -36,9 +37,9 @@ public class GenCacheCmd implements BLauncherCmd{ private static final String CMD_NAME = "gencache"; private PrintStream outStream; + private PrintStream errStream; private boolean exitWhenFinish; private static final String BALLERINA_HOME_KEY = "ballerina.home"; - private String balaPath; private String workingDir; @@ -46,7 +47,8 @@ public class GenCacheCmd implements BLauncherCmd{ private List argList; public GenCacheCmd() { - this.outStream = System.err; + this.outStream = System.out; + this.errStream = System.err; this.exitWhenFinish = true; } @@ -56,14 +58,14 @@ public void execute() { workingDir = argList.get(1); if ( balaPath == null || workingDir == null ) { - outStream.println("missing input options"); + errStream.println("missing input options"); exitError(this.exitWhenFinish); return; } try { - System.out.println(workingDir); - System.out.println(balaPath); + outStream.println(workingDir); + outStream.println(balaPath); Path jBalToolsPath = Paths.get( workingDir); Path repo = jBalToolsPath.resolve( "repo"); Path modulePath = Paths.get(balaPath); @@ -72,14 +74,25 @@ public void execute() { defaultBuilder.addCompilationCacheFactory(new FileSystemCache.FileSystemCacheFactory(repo.resolve("cache"))); Project balaProject = BalaProject.loadProject(defaultBuilder, modulePath); PackageCompilation packageCompilation = balaProject.currentPackage().getCompilation(); - JBallerinaBackend.from(packageCompilation, JvmTarget.JAVA_11); + DiagnosticResult diagnosticResult = packageCompilation.diagnosticResult(); + for (Diagnostic diagnostic : diagnosticResult.diagnostics()) { + outStream.println(diagnostic.toString()); + } + if (diagnosticResult.hasErrors()) { + return; + } + JBallerinaBackend jBallerinaBackend = JBallerinaBackend.from(packageCompilation, JvmTarget.JAVA_17); + diagnosticResult = jBallerinaBackend.diagnosticResult(); + for (Diagnostic diagnostic : diagnosticResult.diagnostics()) { + outStream.println(diagnostic.toString()); + } //TODO : Remove when regeneration is not required } catch (Error e) { //TODO : Ignore Error and continue generation as regeneration will be done - System.out.println("Error occurred " + balaPath + " " + e); + outStream.println("Error occurred " + balaPath + " " + e); } catch (Exception e) { //TODO : Ignore Exception and continue generation as regeneration will be done - System.out.println("Exception occurred " + balaPath + " " + e); + outStream.println("Exception occurred " + balaPath + " " + e); } } diff --git a/config/checkstyle/build.gradle b/config/checkstyle/build.gradle index 04696c96da..b40eeb73f7 100644 --- a/config/checkstyle/build.gradle +++ b/config/checkstyle/build.gradle @@ -21,8 +21,8 @@ plugins { task downloadMultipleFiles(type: Download) { src([ - 'https://raw.githubusercontent.com/wso2/code-quality-tools/v1.3/checkstyle/checkstyle.xml', - 'https://raw.githubusercontent.com/wso2/code-quality-tools/v1.3/checkstyle/suppressions.xml' + 'https://raw.githubusercontent.com/wso2/code-quality-tools/v1.4/checkstyle/jdk-17/checkstyle.xml', + 'https://raw.githubusercontent.com/wso2/code-quality-tools/v1.4/checkstyle/jdk-17/suppressions.xml' ]) overwrite false onlyIfNewer true diff --git a/devtools-integration-tests/src/test/java/org/ballerina/devtools/debug/ExpressionEvaluationTest.java b/devtools-integration-tests/src/test/java/org/ballerina/devtools/debug/ExpressionEvaluationTest.java index 27b87e81b6..aa7774b0d1 100644 --- a/devtools-integration-tests/src/test/java/org/ballerina/devtools/debug/ExpressionEvaluationTest.java +++ b/devtools-integration-tests/src/test/java/org/ballerina/devtools/debug/ExpressionEvaluationTest.java @@ -70,7 +70,7 @@ protected void prepareForEvaluation() throws BallerinaTestException { debugTestRunner.addBreakPoint(new BallerinaTestDebugPoint(debugTestRunner.testEntryFilePath, 24)); debugTestRunner.initDebugSession(DebugUtils.DebuggeeExecutionKind.RUN); - Pair debugHitInfo = debugTestRunner.waitForDebugHit(25000); + Pair debugHitInfo = debugTestRunner.waitForDebugHit(35000); this.context = debugHitInfo.getRight(); } } diff --git a/devtools-integration-tests/src/test/resources/testng.xml b/devtools-integration-tests/src/test/resources/testng.xml index f0b49fb7a0..be5055e339 100644 --- a/devtools-integration-tests/src/test/resources/testng.xml +++ b/devtools-integration-tests/src/test/resources/testng.xml @@ -22,7 +22,7 @@ - + diff --git a/dist-repo-builder/src/main/java/io/ballerina/dist/DistRepoBuilder.java b/dist-repo-builder/src/main/java/io/ballerina/dist/DistRepoBuilder.java index 628656d4e6..86e312c7ec 100644 --- a/dist-repo-builder/src/main/java/io/ballerina/dist/DistRepoBuilder.java +++ b/dist-repo-builder/src/main/java/io/ballerina/dist/DistRepoBuilder.java @@ -135,7 +135,7 @@ private static boolean validateCache(Path bala, Path repo) { valid = false; } // Check if module jar exists - Path jar = repo.resolve("cache").resolve(orgName).resolve(moduleName).resolve(version).resolve("java11") + Path jar = repo.resolve("cache").resolve(orgName).resolve(moduleName).resolve(version).resolve("java17") .resolve(getJarName(orgName, moduleName, version)); if (!Files.exists(jar)) { System.out.println("Jar missing for package :" + orgName + "/" + moduleName); diff --git a/docs/build-ballerina-from-source.md b/docs/build-ballerina-from-source.md index 0ec58d8361..76ed149bbd 100644 --- a/docs/build-ballerina-from-source.md +++ b/docs/build-ballerina-from-source.md @@ -11,7 +11,7 @@ Follow the steps below to set up the prerequisites. -1. Download and [set up](https://adoptopenjdk.net/installation.html) OpenJDK 11 ([Adopt OpenJDK](https://adoptopenjdk.net/) or any other OpenJDK distribution). +1. Download and [set up](https://adoptopenjdk.net/installation.html) OpenJDK 17 ([Adopt OpenJDK](https://adoptopenjdk.net/) or any other OpenJDK distribution). >**Info:** You can also use [Oracle JDK](https://www.oracle.com/java/technologies/javase-downloads.html). diff --git a/examples/aggregation/aggregation.bal b/examples/aggregation/aggregation.bal new file mode 100644 index 0000000000..c7451256f3 --- /dev/null +++ b/examples/aggregation/aggregation.bal @@ -0,0 +1,37 @@ +import ballerina/io; + +public function main() returns error? { + var orders = [ + {orderId: 1, itemName: "A", price: 23.4, quantity: 2}, + {orderId: 1, itemName: "A", price: 20.4, quantity: 1}, + {orderId: 2, itemName: "B", price: 21.5, quantity: 3}, + {orderId: 1, itemName: "B", price: 21.5, quantity: 3} + ]; + + var items = from var {orderId, itemName} in orders + // The `group by` clause create groups for each `orderId`. + // The `itemName` is a non-grouping key and it becomes a sequence variable. + group by orderId + select [itemName]; + + // List of items per `orderId` + io:println(items); + + var quantities = from var {itemName, quantity} in orders + // The `group by` clause create groups for each `itemName`. + // The `quantity` is a non-grouping key and it becomes a sequence variable. + group by itemName + select {itemName, quantity: sum(quantity)}; + + // List of quantity per item + io:println(quantities); + + var income = from var {price, quantity} in orders + let var totPrice = price*quantity + // The `collect` clause creates a single group and all variables become + // non-grouping keys + collect sum(totPrice); + + // Total Income from orders + io:println(income); +} diff --git a/examples/aggregation/aggregation.md b/examples/aggregation/aggregation.md new file mode 100644 index 0000000000..ff5b269936 --- /dev/null +++ b/examples/aggregation/aggregation.md @@ -0,0 +1,21 @@ +# Aggregation + +The `group by` clause in the query expression can group the elements in a collection. Grouping happens based on the grouping keys provided in `group by` clause. For each group, grouping keys are unique. All other variables other than grouping keys are called non-grouping keys. For each group, non-grouping keys become sequence variables. Those variables can be used as a list or an argument to a rest parameter of a langlib function. + +The `collect` clause collects the collection into one group. All the variables become aggregated variables and those variables can be used as a list or an argument to a rest parameter of a langlib function same as in `group by`. + +::: code aggregation.bal ::: + +::: out aggregation.out ::: + +## Related links +- [Query expressions](/learn/by-example/query-expressions) +- [Let clause in query expression](/learn/by-example/let-clause) +- [Limit clause in query expression](/learn/by-example/limit-clause) +- [Joining iterable objects using query](/learn/by-example/joining-iterable-objects) +- [Querying tables](/learn/by-example/querying-tables) +- [Create maps with query expression](/learn/by-example/create-maps-with-query) +- [Create tables with query expression](/learn/by-example/create-tables-with-query) +- [Create streams with query expression](/learn/by-example/create-streams-with-query) +- [On conflict clause in query expression](/learn/by-example/on-conflict-clause) +- [Nested query expressions](/learn/by-example/nested-query-expressions) diff --git a/examples/aggregation/aggregation.metatags b/examples/aggregation/aggregation.metatags new file mode 100644 index 0000000000..e6146e8607 --- /dev/null +++ b/examples/aggregation/aggregation.metatags @@ -0,0 +1,2 @@ +description: This BBE demonstrates how to group a collection, how to handle non grouping keys. +keywords: ballerina, ballerina by example, bbe, group, non-grouping keys, aggregate, collect diff --git a/examples/aggregation/aggregation.out b/examples/aggregation/aggregation.out new file mode 100644 index 0000000000..2636263ed2 --- /dev/null +++ b/examples/aggregation/aggregation.out @@ -0,0 +1,4 @@ +$ bal run aggregation.bal +[["A","A","B"],["B"]] +[{"itemName":"A","quantity":3},{"itemName":"B","quantity":6}] +196.2 diff --git a/examples/aws-lambda-deployment/aws_deploy.out b/examples/aws-lambda-deployment/aws_deploy.out deleted file mode 100644 index 9903c8e992..0000000000 --- a/examples/aws-lambda-deployment/aws_deploy.out +++ /dev/null @@ -1,3 +0,0 @@ -$ aws lambda create-function --function-name echo --zip-file fileb://aws-ballerina-lambda-functions.zip --handler aws_lambda_deployment.echo --runtime provided --role arn:aws:iam::908363916111:role/lambda-role--layers arn:aws:lambda:us-west-1:134633749276:layer:ballerina-jre11:6 --memory-size 512 --timeout 10 -$ aws lambda create-function --function-name uuid --zip-file fileb://aws-ballerina-lambda-functions.zip --handler aws_lambda_deployment.uuid --runtime provided --role arn:aws:iam::908363916111:role/lambda-role--layers arn:aws:lambda:us-west-1:134633749276:layer:ballerina-jre11:6 --memory-size 512 --timeout 10 -$ aws lambda create-function --function-name ctxinfo --zip-file fileb://aws-ballerina-lambda-functions.zip --handler aws_lambda_deployment.ctxinfo --runtime provided --role arn:aws:iam::908363916111:role/lambda-role --layers arn:aws:lambda:us-west-1:134633749276:layer:ballerina-jre11:6 --memory-size 512 --timeout 10 diff --git a/examples/aws-lambda-deployment/aws_lambda_deployment.bal b/examples/aws-lambda-deployment/aws_lambda_deployment.bal deleted file mode 100644 index 54109b090e..0000000000 --- a/examples/aws-lambda-deployment/aws_lambda_deployment.bal +++ /dev/null @@ -1,27 +0,0 @@ -import ballerinax/awslambda; -import ballerina/io; - -// The `@awslambda:Function` annotation marks a function to generate an AWS Lambda function. -@awslambda:Function -public function echo(awslambda:Context ctx, json input) returns json { - return input; -} - -// The `awslambda:Context` object contains request execution context information. -@awslambda:Function -public function ctxinfo(awslambda:Context ctx, json input) returns json|error { - return { - RequestID: ctx.getRequestId(), - DeadlineMS: ctx.getDeadlineMs(), - InvokedFunctionArn: ctx.getInvokedFunctionArn(), - TraceID: ctx.getTraceId(), - RemainingExecTime: ctx.getRemainingExecutionTime() - }; -} - -// If you know the external service that's being used for the function, you can use the built-in types such as -// `S3Event`, `DynamoDBEvent`, `SESEvent` etc. for data binding. -@awslambda:Function -public function notifyS3(awslambda:Context ctx, awslambda:S3Event event) { - io:println(event.Records[0].s3.'object.key); -} diff --git a/examples/aws-lambda-deployment/aws_lambda_deployment.md b/examples/aws-lambda-deployment/aws_lambda_deployment.md deleted file mode 100644 index 5f2e2311fd..0000000000 --- a/examples/aws-lambda-deployment/aws_lambda_deployment.md +++ /dev/null @@ -1,23 +0,0 @@ -# AWS Lambda - -AWS Lambda is an event driven, serverless computing platform. Ballerina functions can be deployed in AWS Lambda by annotating a Ballerina function with "@awslambda:Function", which should have the function signature `function (awslambda:Context, json|EventType) returns json|error`. - -For more information, see the [AWS Lambda Deployment Guide](/learn/run-in-the-cloud/function-as-a-service/aws-lambda/). - -::: code aws_lambda_deployment.bal ::: - -Create a ballerina package and replace the content of the generated ballerina file with the content above. -::: out bal_new.out ::: - -Build the Ballerina program to generate the AWS Lambda artifacts -::: out bal_build.out ::: - -Execute the AWS CLI commands to create and publish the functions; and set your respective AWS `$LAMBDA_ROLE_ARN`, `$REGION_ID`, and `$FUNCTION_NAME` values. -For instructions on getting the value for the`$LAMBDA_ROLE_ARN`, see [AWS Lambda deployment](/learn/run-in-the-cloud/function-as-a-service/aws-lambda/). -::: out aws_deploy.out ::: - -Invoke the functions. -::: out invoke_functions.out ::: - -To invoke the `notifyS3` function, it needs to be registered in the S3 bucket. -For registration and execution details, see [AWS Lambda deployment](/learn/run-in-the-cloud/function-as-a-service/aws-lambda/). diff --git a/examples/aws-lambda-deployment/bal_new.out b/examples/aws-lambda-deployment/bal_new.out deleted file mode 100644 index ac3b9157cc..0000000000 --- a/examples/aws-lambda-deployment/bal_new.out +++ /dev/null @@ -1 +0,0 @@ -$ bal new aws_lambda_deployment diff --git a/examples/aws-lambda-dynamodb-trigger/aws-lambda-dynamodb-trigger.bal b/examples/aws-lambda-dynamodb-trigger/aws-lambda-dynamodb-trigger.bal new file mode 100644 index 0000000000..bdee82d5b4 --- /dev/null +++ b/examples/aws-lambda-dynamodb-trigger/aws-lambda-dynamodb-trigger.bal @@ -0,0 +1,9 @@ +import ballerina/io; +import ballerinax/aws.lambda; + +@lambda:Function +public function dynamoDBTrigger(lambda:Context ctx, + lambda:DynamoDBEvent event) returns json { + io:println(event.Records[0].dynamodb.Keys.toString()); + return event.Records[0].dynamodb.Keys.toString(); +} diff --git a/examples/aws-lambda-dynamodb-trigger/aws-lambda-dynamodb-trigger.md b/examples/aws-lambda-dynamodb-trigger/aws-lambda-dynamodb-trigger.md new file mode 100644 index 0000000000..907c94682b --- /dev/null +++ b/examples/aws-lambda-dynamodb-trigger/aws-lambda-dynamodb-trigger.md @@ -0,0 +1,50 @@ +# AWS Lambda - DynamoDB trigger + +This example creates a function, which will be executed for each entry added to a database in the [DynamoDB](https://aws.amazon.com/dynamodb/). + +For more information, see the [AWS Lambda learn guide](https://ballerina.io/learn/aws-lambda/). + +## Set up the prerequisites + +For instructions, see [Set up the prerequisites](https://ballerina.io/learn/aws-lambda/#set-up-the-prerequisites). + +## Write the function + +Follow the steps below to write the function. + +1. Execute the command below to create a new Ballerina package. + +::: out bal_new.out ::: + +2. Replace the content of the generated Ballerina file with the content below. + +::: code aws-lambda-dynamodb-trigger.bal ::: + +## Build the function + +Execute the command below to generate the AWS Lambda artifacts. + +::: out bal_build.out ::: + +## Deploy the function + +Execute the AWS CLI command given by the compiler to create and publish the functions by replacing the respective AWS `$LAMBDA_ROLE_ARN`, `$REGION_ID`, and `$FUNCTION_NAME` values given in the command with your values. + +::: out aws_deploy.out ::: + +## Invoke the function + +Follow the instructions below to create a DynamoDB table for invoking this function. + +1. In the IAM Console, click the corresponding role in the list, and click **Add permissions**. +2. Select **attach policies** from the drop-down menu, and add the **AWSLambdaDynamoDBExecutionRole** to the role. +3. Go to [DynamoDB](https://console.aws.amazon.com/dynamodbv2), and from the drop-down menu at the top RHS of the screen, select the **AWS region** in which you created the user and role. +4. Click **Create Table**, enter a table name and a partition key, and create the table (if you already have a table created, you can skip this step). +5. Click on the DynamoDB table you created, and then click the **Exports and streams** tab. +6. Click **Turn on** under **DynamoDB stream details**, select **Key attributes only** for the event type, and click **Turn on stream**. +8. Under the **Trigger** section, click **Create trigger**, select the `dynamoDBTrigger` from the drop-down, and click **Create trigger**. +9. Click **Explore table items**, and click **Create items** under the **Items returned** section. +10. Enter a value under the **Attributes** section to add an entry to the DynamoDB table to invoke the Lambda function, and click **Create item**. +11. Click the **Monitor** tab of the Lambda function in the AWS Management Console, and click **View CloudWatch logs** to check the logs via CloudWatch. +11. Under **Log streams** in CloudWatch, click on the topmost stream in the list and verify the object name in the logs. +12. Go to the AWS Lambda function and check the logs via CloudWatch to see the object identifier in the logs. diff --git a/examples/aws-lambda-dynamodb-trigger/aws-lambda-dynamodb-trigger.metatags b/examples/aws-lambda-dynamodb-trigger/aws-lambda-dynamodb-trigger.metatags new file mode 100644 index 0000000000..ad99d516d2 --- /dev/null +++ b/examples/aws-lambda-dynamodb-trigger/aws-lambda-dynamodb-trigger.metatags @@ -0,0 +1,2 @@ +description: This example creates a function, which will be executed for each entry added to a database in the DynamoDB. +keywords: ballerina, ballerina by example, aws lambda, dynamodb, serverless, cloud, function as a service diff --git a/examples/aws-lambda-dynamodb-trigger/aws_deploy.out b/examples/aws-lambda-dynamodb-trigger/aws_deploy.out new file mode 100644 index 0000000000..0069df5061 --- /dev/null +++ b/examples/aws-lambda-dynamodb-trigger/aws_deploy.out @@ -0,0 +1 @@ +$ aws lambda create-function --function-name dynamoDBTrigger --zip-file fileb://aws-ballerina-lambda-functions.zip --handler aws-lambda-dynamodb-trigger.dynamoDBTrigger --runtime provided --role arn:aws:iam::908363916111:role/lambda-role--layers arn:aws:lambda:us-west-1:134633749276:layer:ballerina-jre11:6 --memory-size 512 --timeout 10 diff --git a/examples/aws-lambda-dynamodb-trigger/bal_build.out b/examples/aws-lambda-dynamodb-trigger/bal_build.out new file mode 100644 index 0000000000..8d1335858f --- /dev/null +++ b/examples/aws-lambda-dynamodb-trigger/bal_build.out @@ -0,0 +1,12 @@ +$ bal build +Compiling source + wso2/aws_lambda_dynamodb_trigger:0.1.0 + +Generating executable + @awslambda:Function: dynamoDBTrigger + + Run the following command to deploy each Ballerina AWS Lambda function: + aws lambda create-function --function-name $FUNCTION_NAME --zip-file fileb:///aws-lambda-s3-trigger/target/bin/aws-ballerina-lambda-functions.zip --handler aws-lambda-dynamodb-trigger.$FUNCTION_NAME --runtime provided --role $LAMBDA_ROLE_ARN --layers arn:aws:lambda:$REGION_ID:134633749276:layer:ballerina-jre11:6 --memory-size 512 --timeout 10 + + Run the following command to re-deploy an updated Ballerina AWS Lambda function: + aws lambda update-function-code --function-name $FUNCTION_NAME --zip-file fileb://aws-ballerina-lambda-functions.zip diff --git a/examples/aws-lambda-dynamodb-trigger/bal_new.out b/examples/aws-lambda-dynamodb-trigger/bal_new.out new file mode 100644 index 0000000000..2bbc070e53 --- /dev/null +++ b/examples/aws-lambda-dynamodb-trigger/bal_new.out @@ -0,0 +1,2 @@ +$ bal new aws_lambda_dynamodb_trigger +Created new package 'aws_lambda_dynamodb_trigger' at /Users/wso2/aws_lambda_dynamodb_trigger. diff --git a/examples/aws-lambda-execution-context/aws-lambda-execution-context.bal b/examples/aws-lambda-execution-context/aws-lambda-execution-context.bal new file mode 100644 index 0000000000..4cd08f4dd6 --- /dev/null +++ b/examples/aws-lambda-execution-context/aws-lambda-execution-context.bal @@ -0,0 +1,13 @@ +import ballerinax/aws.lambda; + +// The `lambda:Context` object contains request execution context information. +@lambda:Function +public function ctxinfo(lambda:Context ctx, json input) returns json|error { + return { + RequestID: ctx.getRequestId(), + DeadlineMS: ctx.getDeadlineMs(), + InvokedFunctionArn: ctx.getInvokedFunctionArn(), + TraceID: ctx.getTraceId(), + RemainingExecTime: ctx.getRemainingExecutionTime() + }; +} diff --git a/examples/aws-lambda-execution-context/aws-lambda-execution-context.md b/examples/aws-lambda-execution-context/aws-lambda-execution-context.md new file mode 100644 index 0000000000..987ef42aac --- /dev/null +++ b/examples/aws-lambda-execution-context/aws-lambda-execution-context.md @@ -0,0 +1,39 @@ +# AWS Lambda - Execution context + +The example below demonstrates how the execution context information of an AWS function can be retrieved. + +For more information, see the [AWS Lambda learn guide](https://ballerina.io/learn/aws-lambda/). + +## Set up the prerequisites + +For instructions, see [Set up the prerequisites](https://ballerina.io/learn/aws-lambda/#set-up-the-prerequisites). + +## Write the function + +Follow the steps below to write the function. + +1. Execute the command below to create a new Ballerina package. + +::: out bal_new.out ::: + +2. Replace the content of the generated Ballerina file with the content below. + +::: code aws-lambda-execution-context.bal ::: + +## Build the function + +Execute the command below to generate the AWS Lambda artifacts. + +::: out bal_build.out ::: + +## Deploy the function + +Execute the AWS CLI command given by the compiler to create and publish the functions by replacing the respective AWS `$LAMBDA_ROLE_ARN`, `$REGION_ID`, and `$FUNCTION_NAME` values given in the command with your values. + +::: out aws_deploy.out ::: + +## Invoke the function + +Execute the commands below to invoke the function. + +::: out invoke_functions.out ::: diff --git a/examples/aws-lambda-execution-context/aws-lambda-execution-context.metatags b/examples/aws-lambda-execution-context/aws-lambda-execution-context.metatags new file mode 100644 index 0000000000..d75a357ce1 --- /dev/null +++ b/examples/aws-lambda-execution-context/aws-lambda-execution-context.metatags @@ -0,0 +1,2 @@ +description: The example below demonstrates how the execution context information of an AWS function can be retrieved. +keywords: ballerina, ballerina by example, aws lambda, execution context, serverless, cloud, function as a service diff --git a/examples/aws-lambda-execution-context/aws_deploy.out b/examples/aws-lambda-execution-context/aws_deploy.out new file mode 100644 index 0000000000..b92d5109ed --- /dev/null +++ b/examples/aws-lambda-execution-context/aws_deploy.out @@ -0,0 +1 @@ +$ aws lambda create-function --function-name ctxinfo --zip-file fileb://aws-ballerina-lambda-functions.zip --handler aws-lambda-execution-context.ctxinfo --runtime provided --role arn:aws:iam::908363916111:role/lambda-role --layers arn:aws:lambda:us-west-1:134633749276:layer:ballerina-jre11:6 --memory-size 512 --timeout 10 diff --git a/examples/aws-lambda-execution-context/bal_build.out b/examples/aws-lambda-execution-context/bal_build.out new file mode 100644 index 0000000000..2abd4d890e --- /dev/null +++ b/examples/aws-lambda-execution-context/bal_build.out @@ -0,0 +1,12 @@ +$ bal build +Compiling source + wso2/aws_lambda_execution_context:0.1.0 + +Generating executable + @awslambda:Function: ctxinfo + + Run the following command to deploy each Ballerina AWS Lambda function: + aws lambda create-function --function-name $FUNCTION_NAME --zip-file fileb:///aws-lambda-execution-context/target/bin/aws-ballerina-lambda-functions.zip --handler aws_lambda_deployment.$FUNCTION_NAME --runtime provided --role $LAMBDA_ROLE_ARN --layers arn:aws:lambda:$REGION_ID:134633749276:layer:ballerina-jre11:6 --memory-size 512 --timeout 10 + + Run the following command to re-deploy an updated Ballerina AWS Lambda function: + aws lambda update-function-code --function-name $FUNCTION_NAME --zip-file fileb://aws-ballerina-lambda-functions.zip diff --git a/examples/aws-lambda-execution-context/bal_new.out b/examples/aws-lambda-execution-context/bal_new.out new file mode 100644 index 0000000000..5e3fa2223c --- /dev/null +++ b/examples/aws-lambda-execution-context/bal_new.out @@ -0,0 +1,2 @@ +$ bal new aws_lambda_execution_context +Created new package 'aws_lambda_execution_context' at /Users/wso2/aws_lambda_execution_context. diff --git a/examples/aws-lambda-deployment/invoke_functions.out b/examples/aws-lambda-execution-context/invoke_functions.out similarity index 71% rename from examples/aws-lambda-deployment/invoke_functions.out rename to examples/aws-lambda-execution-context/invoke_functions.out index d182a6dafb..0361f200e5 100644 --- a/examples/aws-lambda-deployment/invoke_functions.out +++ b/examples/aws-lambda-execution-context/invoke_functions.out @@ -1,12 +1,4 @@ $ echo '{"MESSAGE":"HELLO"}' > input.json -$ aws lambda invoke --function-name echo --payload fileb://input.json echo-response.txt -{ -"ExecutedVersion": "$LATEST", -"StatusCode": 200 -} -$ cat echo-response.txt -{"MESSAGE":"HELLO"} - $ aws lambda invoke --function-name ctxinfo ctxinfo-response.txt { "ExecutedVersion": "$LATEST", diff --git a/examples/aws-lambda-hello-world/aws-lambda-hello-world.bal b/examples/aws-lambda-hello-world/aws-lambda-hello-world.bal new file mode 100644 index 0000000000..df22a7c2b5 --- /dev/null +++ b/examples/aws-lambda-hello-world/aws-lambda-hello-world.bal @@ -0,0 +1,9 @@ +import ballerina/io; +import ballerinax/aws.lambda; + +// The `@lambda:Function` annotation marks a function to generate an AWS Lambda function. +@lambda:Function +public function echo(lambda:Context ctx, json input) returns json { + io:println(input.toJsonString()); + return input; +} diff --git a/examples/aws-lambda-hello-world/aws-lambda-hello-world.md b/examples/aws-lambda-hello-world/aws-lambda-hello-world.md new file mode 100644 index 0000000000..2ce419737b --- /dev/null +++ b/examples/aws-lambda-hello-world/aws-lambda-hello-world.md @@ -0,0 +1,39 @@ +# AWS Lambda - Hello world + +This example demonstrates how to write a simple echo function in AWS Lambda. + +For more information, see the [AWS Lambda learn guide](https://ballerina.io/learn/aws-lambda/). + +## Set up the prerequisites + +For instructions, see [Set up the prerequisites](https://ballerina.io/learn/aws-lambda/#set-up-the-prerequisites). + +## Write the function + +Follow the steps below to write the function. + +1. Execute the command below to create a new Ballerina package. + +::: out bal_new.out ::: + +2. Replace the content of the generated Ballerina file with the content below. + +::: code aws-lambda-hello-world.bal ::: + +## Build the function + +Execute the command below to generate the AWS Lambda artifacts. + +::: out bal_build.out ::: + +## Deploy the function + +Execute the AWS CLI command given by the compiler to create and publish the functions by replacing the respective AWS `$LAMBDA_ROLE_ARN`, `$REGION_ID`, and `$FUNCTION_NAME` values given in the command with your values. + +::: out aws_deploy.out ::: + +## Invoke the function + +Execute the commands below to invoke the function. + +::: out invoke_functions.out ::: diff --git a/examples/aws-lambda-hello-world/aws-lambda-hello-world.metatags b/examples/aws-lambda-hello-world/aws-lambda-hello-world.metatags new file mode 100644 index 0000000000..8bb3559706 --- /dev/null +++ b/examples/aws-lambda-hello-world/aws-lambda-hello-world.metatags @@ -0,0 +1,2 @@ +description: This example demonstrates how to write a simple echo function in AWS Lambda. +keywords: ballerina, ballerina by example, serverless, aws lambda, cloud, function as a service diff --git a/examples/aws-lambda-hello-world/aws_deploy.out b/examples/aws-lambda-hello-world/aws_deploy.out new file mode 100644 index 0000000000..1ea510bb00 --- /dev/null +++ b/examples/aws-lambda-hello-world/aws_deploy.out @@ -0,0 +1 @@ +$ aws lambda create-function --function-name echo --zip-file fileb://aws-ballerina-lambda-functions.zip --handler aws-lambda-hello-world.echo --runtime provided --role arn:aws:iam::908363916111:role/lambda-role--layers arn:aws:lambda:us-west-1:134633749276:layer:ballerina-jre11:6 --memory-size 512 --timeout 10 diff --git a/examples/aws-lambda-hello-world/bal_build.out b/examples/aws-lambda-hello-world/bal_build.out new file mode 100644 index 0000000000..ccb4bc0004 --- /dev/null +++ b/examples/aws-lambda-hello-world/bal_build.out @@ -0,0 +1,12 @@ +$ bal build +Compiling source + wso2/aws_lambda_hello_world:0.1.0 + +Generating executable + @awslambda:Function: echo + + Run the following command to deploy each Ballerina AWS Lambda function: + aws lambda create-function --function-name $FUNCTION_NAME --zip-file fileb:///aws-lambda-hello-world/target/bin/aws-ballerina-lambda-functions.zip --handler aws-lambda-hello-world.$FUNCTION_NAME --runtime provided --role $LAMBDA_ROLE_ARN --layers arn:aws:lambda:$REGION_ID:134633749276:layer:ballerina-jre11:6 --memory-size 512 --timeout 10 + + Run the following command to re-deploy an updated Ballerina AWS Lambda function: + aws lambda update-function-code --function-name $FUNCTION_NAME --zip-file fileb://aws-ballerina-lambda-functions.zip diff --git a/examples/aws-lambda-hello-world/bal_new.out b/examples/aws-lambda-hello-world/bal_new.out new file mode 100644 index 0000000000..cc5e2c7b20 --- /dev/null +++ b/examples/aws-lambda-hello-world/bal_new.out @@ -0,0 +1,2 @@ +$ bal new aws_lambda_hello_world +Created new package 'aws_lambda_hello_world' at /Users/wso2/aws_lambda_hello_world. diff --git a/examples/aws-lambda-hello-world/invoke_functions.out b/examples/aws-lambda-hello-world/invoke_functions.out new file mode 100644 index 0000000000..c45754e688 --- /dev/null +++ b/examples/aws-lambda-hello-world/invoke_functions.out @@ -0,0 +1,8 @@ +$ echo '{"MESSAGE":"HELLO"}' > input.json +$ aws lambda invoke --function-name echo --payload fileb://input.json echo-response.txt +{ +"ExecutedVersion": "$LATEST", +"StatusCode": 200 +} +$ cat echo-response.txt +{"MESSAGE":"HELLO"} diff --git a/examples/aws-lambda-s3-trigger/aws-lambda-s3-trigger.bal b/examples/aws-lambda-s3-trigger/aws-lambda-s3-trigger.bal new file mode 100644 index 0000000000..853ad43a20 --- /dev/null +++ b/examples/aws-lambda-s3-trigger/aws-lambda-s3-trigger.bal @@ -0,0 +1,9 @@ +import ballerina/io; +import ballerinax/aws.lambda; + +@lambda:Function +public function s3Trigger(lambda:Context ctx, + lambda:S3Event event) returns json { + io:println(event.Records[0].s3.'object.key); + return event.Records[0].s3.'object.key; +} diff --git a/examples/aws-lambda-s3-trigger/aws-lambda-s3-trigger.md b/examples/aws-lambda-s3-trigger/aws-lambda-s3-trigger.md new file mode 100644 index 0000000000..bbb5194bd2 --- /dev/null +++ b/examples/aws-lambda-s3-trigger/aws-lambda-s3-trigger.md @@ -0,0 +1,50 @@ +# AWS Lambda - S3 trigger + +This example creates a function, which will be executed for each object creation in AWS S3. + +For more information, see the [AWS Lambda learn guide](https://ballerina.io/learn/aws-lambda/). + +## Set up the prerequisites + +For instructions, see [Set up the prerequisites](https://ballerina.io/learn/aws-lambda/#set-up-the-prerequisites). + +## Write the function + +Follow the steps below to write the function. + +1. Execute the command below to create a new Ballerina package. + +::: out bal_new.out ::: + +2. Replace the content of the generated Ballerina file with the content below. + +::: code aws-lambda-s3-trigger.bal ::: + +## Build the function + +Execute the command below to generate the AWS Lambda artifacts. + +::: out bal_build.out ::: + +## Deploy the function + +Execute the AWS CLI command given by the compiler to create and publish the functions by replacing the respective AWS `$LAMBDA_ROLE_ARN`, `$REGION_ID`, and `$FUNCTION_NAME` values given in the command with your values. + +::: out aws_deploy.out ::: + +## Invoke the function + +Follow the instructions below to create an S3 bucket in AWS for invoking this function. + +1. Go to the [AWS S3](https://s3.console.aws.amazon.com/s3/) portal and create a bucket. + >**Note:** Make sure to select the same **AWS region** in which you created the AWS user and role when creating the S3 bucket. +2. Click on the created bucket, go to the **Properties** tab, and click **Create event notification** under the **Event notifications** section. +3. Enable **All object create events** under event types. +4. Under the **Destination** section, select the AWS Lambda function (i.e., `s3Trigger` in this example) from the dropdown. +5. Select the created bucket under the **Buckets** list, click **Upload**, and upload an object to the S3 bucket. +6. Under the **Functions** list of the AWS Management Console, click the AWS Lambda function, and click the **Monitor** tab. +7. If you get a **Missing permissions** notice at the top, click the **Open the IAM Console** in it. +8. In the IAM Console, click the corresponding role in the list, and click **Add permissions**. +9. Select **attach policies** from the drop-down menu, and add the **AWSLambdaBasicExecutionRole** to the role. +10. Click the **Monitor** tab of the Lambda function in the AWS Management Console, and click **View CloudWatch logs** to check the logs via CloudWatch. +11. Under **Log streams** in CloudWatch, click on the topmost stream in the list and verify the object name in the logs. diff --git a/examples/aws-lambda-s3-trigger/aws-lambda-s3-trigger.metatags b/examples/aws-lambda-s3-trigger/aws-lambda-s3-trigger.metatags new file mode 100644 index 0000000000..17fd5bcb3c --- /dev/null +++ b/examples/aws-lambda-s3-trigger/aws-lambda-s3-trigger.metatags @@ -0,0 +1,2 @@ +description: This example creates a function, which will be executed for each object creation in AWS S3. +keywords: ballerina, ballerina by example, aws lambda, s3, trigger, serverless, cloud, function as a service diff --git a/examples/aws-lambda-s3-trigger/aws_deploy.out b/examples/aws-lambda-s3-trigger/aws_deploy.out new file mode 100644 index 0000000000..b1b14c6f1a --- /dev/null +++ b/examples/aws-lambda-s3-trigger/aws_deploy.out @@ -0,0 +1 @@ +$ aws lambda create-function --function-name s3Trigger --zip-file fileb://aws-ballerina-lambda-functions.zip --handler aws-lambda-s3-trigger.s3Trigger --runtime provided --role arn:aws:iam::908363916111:role/lambda-role--layers arn:aws:lambda:us-west-1:134633749276:layer:ballerina-jre11:6 --memory-size 512 --timeout 10 diff --git a/examples/aws-lambda-deployment/bal_build.out b/examples/aws-lambda-s3-trigger/bal_build.out similarity index 64% rename from examples/aws-lambda-deployment/bal_build.out rename to examples/aws-lambda-s3-trigger/bal_build.out index 28d6ec11dc..71a62ffa3c 100644 --- a/examples/aws-lambda-deployment/bal_build.out +++ b/examples/aws-lambda-s3-trigger/bal_build.out @@ -1,12 +1,12 @@ $ bal build Compiling source - wso2/aws_lambda_deployment:0.1.0 + wso2/aws_lambda_s3_trigger:0.1.0 Generating executable - @awslambda:Function: echo, ctxinfo, notifyS3 + @awslambda:Function: s3Trigger Run the following command to deploy each Ballerina AWS Lambda function: - aws lambda create-function --function-name $FUNCTION_NAME --zip-file fileb:///aws_lambda_deployment/target/bin/aws-ballerina-lambda-functions.zip --handler aws_lambda_deployment.$FUNCTION_NAME --runtime provided --role $LAMBDA_ROLE_ARN --layers arn:aws:lambda:$REGION_ID:134633749276:layer:ballerina-jre11:6 --memory-size 512 --timeout 10 + aws lambda create-function --function-name $FUNCTION_NAME --zip-file fileb:///aws-lambda-s3-trigger/target/bin/aws-ballerina-lambda-functions.zip --handler aws-lambda-s3-trigger.$FUNCTION_NAME --runtime provided --role $LAMBDA_ROLE_ARN --layers arn:aws:lambda:$REGION_ID:134633749276:layer:ballerina-jre11:6 --memory-size 512 --timeout 10 Run the following command to re-deploy an updated Ballerina AWS Lambda function: aws lambda update-function-code --function-name $FUNCTION_NAME --zip-file fileb://aws-ballerina-lambda-functions.zip diff --git a/examples/aws-lambda-s3-trigger/bal_new.out b/examples/aws-lambda-s3-trigger/bal_new.out new file mode 100644 index 0000000000..034b5c68fc --- /dev/null +++ b/examples/aws-lambda-s3-trigger/bal_new.out @@ -0,0 +1,2 @@ +$ bal new aws_lambda_s3_trigger +Created new package 'aws_lambda_s3_trigger' at /Users/wso2/aws_lambda_s3_trigger. diff --git a/examples/azure-functions-cosmosdb-trigger/az_deploy.out b/examples/azure-functions-cosmosdb-trigger/az_deploy.out new file mode 100644 index 0000000000..5edea3c11e --- /dev/null +++ b/examples/azure-functions-cosmosdb-trigger/az_deploy.out @@ -0,0 +1,9 @@ +$ func azure functionapp publish --script-root target/azure_functions +Getting site publishing info... +Creating archive for current directory... +Uploading 32.71 MB [##############################################################################] +Upload completed successfully. +Deployment completed successfully. +Syncing triggers... +Functions in : + cosmos - [cosmosDBTrigger] diff --git a/examples/azure-functions-cosmosdb-trigger/azure-functions-cosmosdb-trigger.bal b/examples/azure-functions-cosmosdb-trigger/azure-functions-cosmosdb-trigger.bal new file mode 100644 index 0000000000..55a4342db2 --- /dev/null +++ b/examples/azure-functions-cosmosdb-trigger/azure-functions-cosmosdb-trigger.bal @@ -0,0 +1,18 @@ +import ballerina/io; +import ballerinax/azure.functions; + +public type DBEntry record { + string id; + string name; +}; + +@functions:CosmosDBTrigger {connectionStringSetting: "CosmosDBConnection", databaseName: "db1", collectionName: "c1"} +listener functions:CosmosDBListener cosmosEp = new (); + +service "cosmos" on cosmosEp { + remote function onUpdate(DBEntry[] entries) returns @functions:QueueOutput {queueName: "people"} string { + string name = entries[0].name; + io:println(entries.toJsonString()); + return "Hello, " + name; + } +} diff --git a/examples/azure-functions-cosmosdb-trigger/azure-functions-cosmosdb-trigger.md b/examples/azure-functions-cosmosdb-trigger/azure-functions-cosmosdb-trigger.md new file mode 100644 index 0000000000..40a531dbef --- /dev/null +++ b/examples/azure-functions-cosmosdb-trigger/azure-functions-cosmosdb-trigger.md @@ -0,0 +1,61 @@ +# Azure Functions - Cosmos DB trigger + +This example demonstrates using a Cosmos DB trigger to invoke an Azure function and a queue output binding to write an entry to a queue. + +For more information, see the [Azure Functions deployment guide](https://ballerina.io/learn/azure-functions/). + +## Set up the prerequisites + +Follow the steps below to create a Cosmos DB and a queue to make use of those services later in this example. + +1. Set up the [general prerequisites](https://ballerina.io/learn/azure-functions/#set-up-the-prerequisites). +2. Create the queue in the [HTTP trigger](/learn/by-example/azure-functions/http-trigger/) example to resue it in this one. +3. In the [**Azure Cosmos DB** service of the Azure Portal](https://portal.azure.com/#create/Microsoft.DocumentDB), click **Create**, and select **Azure Cosmos DB for NoSQL**. +4. Enter an account name and a resource group name, and click **Review + Create**, and then, click **Create**. +5. Once the database is created, go to the **Data Explorer**, and select **Create Container**. +6. Enter `db1` as the Database ID, `c1` as the collection ID, and click **Ok**. + >**Note:** If you want to change these values, change them in the code as well. +6. Go to the **Keys** tab of the Cosmos DB page. +7. Copy the value of the `PRIMARY CONNECTION STRING`. +8. Click the **Configuration** tab on the function app page. +9. Select **New Application Setting**, and paste the data you copied above as the value. + >**Tip:** For the key, use the value of the `connectionStringSetting` key and save. + + Example application settings are as follows. + + - Name - `CosmosDBConnection` + - Value - `AccountEndpoint=https://db-cosmos.documents.azure.com:443/;AccountKey=12345asda;` + +Now, as all the infrastructure required is up and running and configured, start building and deploying the Azure function. + +## Write the function + +Follow the steps below to write the function. + +1. Execute the command below to create a new Ballerina package. + +::: out bal_new.out ::: + +2. Replace the content of the generated Ballerina file with the content below. + +::: code azure-functions-cosmosdb-trigger.bal ::: + +## Build the function + +Execute the command below to generate the Azure Functions artifacts. + +::: out bal_build.out ::: + +## Deploy the function + +Execute the Azure CLI command given by the compiler to create and publish the functions by replacing `` with your respective function app name. + +## Invoke the function + +Once the function is deployed, add an item to the collection. + +1. Navigate to the collection created in the **Data Explorer**. +2. Click **New Item** to add a new item to the collection. +3. Go to the queue page and observe the added new entry. + +>**Info:** Additionally, for debugging purposes, view the logs under the **Logs stream** in the function app. diff --git a/examples/azure-functions-cosmosdb-trigger/azure-functions-cosmosdb-trigger.metatags b/examples/azure-functions-cosmosdb-trigger/azure-functions-cosmosdb-trigger.metatags new file mode 100644 index 0000000000..8a9cb7e4cf --- /dev/null +++ b/examples/azure-functions-cosmosdb-trigger/azure-functions-cosmosdb-trigger.metatags @@ -0,0 +1,2 @@ +description: This example demonstrates using a Cosmos DB trigger to invoke an AWS Lambda function and a queue output binding to write an entry to a queue. +keywords: ballerina, ballerina by example, aws lambda, cosmos db, trigger, serverless, cloud, function as a service diff --git a/examples/azure-functions-cosmosdb-trigger/bal_build.out b/examples/azure-functions-cosmosdb-trigger/bal_build.out new file mode 100644 index 0000000000..c7efe8869d --- /dev/null +++ b/examples/azure-functions-cosmosdb-trigger/bal_build.out @@ -0,0 +1,15 @@ +$ bal build --cloud="azure_functions" +Compiling source + wso2/azure_functions_cosmosdb_trigger:0.1.0 + +Generating executable + + @azure.functions:Function: cosmos + + Execute the command below to deploy the function locally: + $ func start --script-root target/azure_functions --java + + Execute the command below to deploy Ballerina Azure Functions: + $ func azure functionapp publish --script-root target/azure_functions + + target/bin/azure_functions_cosmosdb_trigger.jar diff --git a/examples/azure-functions-cosmosdb-trigger/bal_new.out b/examples/azure-functions-cosmosdb-trigger/bal_new.out new file mode 100644 index 0000000000..cebe5b2e9e --- /dev/null +++ b/examples/azure-functions-cosmosdb-trigger/bal_new.out @@ -0,0 +1,2 @@ +$ bal new azure_functions_cosmosdb_trigger +Created new package 'azure_functions_cosmosdb_trigger' at /Users/wso2/azure_functions_cosmosdb_trigger. diff --git a/examples/azure-functions-deployment/az_deploy.out b/examples/azure-functions-deployment/az_deploy.out deleted file mode 100644 index 968f927b8e..0000000000 --- a/examples/azure-functions-deployment/az_deploy.out +++ /dev/null @@ -1,12 +0,0 @@ -$ func azure functionapp publish bal-bbe --script-root target/azure_functions -Getting site publishing info... -Creating archive for current directory... -Uploading 28.67 MB [##############################################################################] -Upload completed successfully. -Deployment completed successfully. -Syncing triggers... -Functions in bal-bbe: - get-hello - [httpTrigger] - Invoke url: https://bal-bbe.azurewebsites.net/hello - - timer - [timerTrigger] diff --git a/examples/azure-functions-deployment/azure_functions_deployment.bal b/examples/azure-functions-deployment/azure_functions_deployment.bal deleted file mode 100644 index 8c9c37e2aa..0000000000 --- a/examples/azure-functions-deployment/azure_functions_deployment.bal +++ /dev/null @@ -1,19 +0,0 @@ -import ballerinax/azure_functions as af; - -// This function gets triggered by an HTTP call with the name query parameter and returns a processed HTTP output to the caller. -service / on new af:HttpListener() { - resource function get hello(string name) returns string { - return "Hello, " + name + "!"; - } -} - -// This function gets executed every 10 seconds by the Azure Functions app. Once the function is executed, the timer -// details will be stored in the selected queue storage for every invocation. -@af:TimerTrigger {schedule: "*/10 * * * * *"} -listener af:TimerListener timerListener = new af:TimerListener(); - -service "timer" on timerListener { - remote function onTrigger(af:TimerMetadata metadata) returns @af:QueueOutput {queueName: "queue3"} string|error { - return "Message Status, " + metadata.IsPastDue.toString(); - } -} diff --git a/examples/azure-functions-deployment/azure_functions_deployment.md b/examples/azure-functions-deployment/azure_functions_deployment.md deleted file mode 100644 index ecf26ab6b4..0000000000 --- a/examples/azure-functions-deployment/azure_functions_deployment.md +++ /dev/null @@ -1,21 +0,0 @@ -# Azure Functions - -Azure Functions is an event driven, serverless computing platform. Azure Functions can be written from Ballerina using the listeners and services provided by Azure Functions package. You can view the code examples below. - -For more information, see the [Azure deployment guide](/learn/run-in-the-cloud/function-as-a-service/azure-functions/). - -::: code azure_functions_deployment.bal ::: - -Create a Ballerina package and replace the content of the generated BAL file with the content above. -::: out bal_new.out ::: - -Build the Ballerina program to generate the Azure Functions artifacts. -::: out bal_build.out ::: - -Execute the Azure CLI command given by the compiler to publish the functions (replace the sample app name given in the command with your respective Azure ``). -::: out az_deploy.out ::: - -Invoke the `HTTP Trigger` functions. -::: out execute_function.out ::: - -The `timer` function is triggered by the Azure Functions app from a timer. You can check the queue storage to see the output. For more information on the infrastructure, see [Azure Functions deployment](/learn/run-in-the-cloud/function-as-a-service/azure-functions/). diff --git a/examples/azure-functions-deployment/bal_build.out b/examples/azure-functions-deployment/bal_build.out deleted file mode 100644 index cc1448aa34..0000000000 --- a/examples/azure-functions-deployment/bal_build.out +++ /dev/null @@ -1,14 +0,0 @@ -$ bal build --cloud="azure_functions" -Compiling source - wso2/azure_functions_deployment:0.1.0 - -Generating executable - @azure_functions:Function: timer, get-hello - - Execute the command below to deploy the function locally. - func start --script-root target/azure_functions --java - - Execute the command below to deploy Ballerina Azure Functions. - func azure functionapp publish --script-root target/azure_functions - - target/bin/azure_functions_deployment.jar diff --git a/examples/azure-functions-deployment/bal_new.out b/examples/azure-functions-deployment/bal_new.out deleted file mode 100644 index 9f1771644c..0000000000 --- a/examples/azure-functions-deployment/bal_new.out +++ /dev/null @@ -1 +0,0 @@ -$ bal new azure_functions_deployment diff --git a/examples/azure-functions-deployment/execute_function.out b/examples/azure-functions-deployment/execute_function.out deleted file mode 100644 index 0da4052046..0000000000 --- a/examples/azure-functions-deployment/execute_function.out +++ /dev/null @@ -1,2 +0,0 @@ -$ curl https://bal-bbe.azurewebsites.net/hello\?name\=Jack -Hello, Jack! diff --git a/examples/azure-functions-hello-world/az_deploy.out b/examples/azure-functions-hello-world/az_deploy.out new file mode 100644 index 0000000000..f037f88bfb --- /dev/null +++ b/examples/azure-functions-hello-world/az_deploy.out @@ -0,0 +1,10 @@ +$ func azure functionapp publish --script-root target/azure_functions +Getting site publishing info... +Creating archive for current directory... +Uploading 32.69 MB [##############################################################################] +Upload completed successfully. +Deployment completed successfully. +Syncing triggers... +Functions in : + get-hello - [httpTrigger] + Invoke url: https://azurecosmosdbfunctionapp.azurewebsites.net/hello diff --git a/examples/azure-functions-hello-world/azure-functions-hello-world.bal b/examples/azure-functions-hello-world/azure-functions-hello-world.bal new file mode 100644 index 0000000000..cdbcd2da1f --- /dev/null +++ b/examples/azure-functions-hello-world/azure-functions-hello-world.bal @@ -0,0 +1,9 @@ +import ballerinax/azure.functions; + +// This function gets triggered by an HTTP call with the name query parameter and +// returns a processed HTTP output to the caller. +service / on new functions:HttpListener() { + resource function get hello(string name) returns string { + return string `Hello, ${name}!`; + } +} diff --git a/examples/azure-functions-hello-world/azure-functions-hello-world.md b/examples/azure-functions-hello-world/azure-functions-hello-world.md new file mode 100644 index 0000000000..7a5f179acb --- /dev/null +++ b/examples/azure-functions-hello-world/azure-functions-hello-world.md @@ -0,0 +1,45 @@ +# Azure Functions - Hello world + +This example demonstrates how to write a simple echo function in Azure Functions. + +In Ballerina, triggers are represented by listeners. When the `af:HttpListener` gets attached to the service, it implies that the function is an HTTP Trigger. The resource method behaves exactly the same as a service written from `ballerina/http`. It supports the `http:Payload` and `http:Header` annotations for parameters. Input binding annotations can be used to annotate parameters to make use of external services in Azure. If no annotations are specified for a parameter, it is identified as a query parameter. + +Output bindings are defined in the return type definition. For services with the `HttpListener` attachment, `HttpOutput` is the default output binding. You can override the default behavior by specifying them explicitly in the return type. + +In the code sample shown above, it has an empty service path and resource path named `hello`. The accessor is `get`. It expects a request with a query parameter for the field name. The required artifact generation and data binding will be handled by the `ballerinax/azure_functions` package automatically. + +For more information, see the [Azure deployment guide](https://ballerina.io/learn/azure-functions/). + +## Set up the prerequisites + +For instructions, see [Set up the prerequisites](https://ballerina.io/learn/azure-functions/#set-up-the-prerequisites). + +## Write the function + +Follow the steps below to write the function. + +1. Execute the command below to create a new Ballerina package. + +::: out bal_new.out ::: + +2. Replace the content of the generated Ballerina file with the content below. + +::: code azure-functions-hello-world.bal ::: + +## Build the function + +Execute the command below to generate the Azure Functions artifacts. + +::: out bal_build.out ::: + +## Deploy the function + +Execute the Azure CLI command given by the compiler to create and publish the functions by replacing `` with your respective function app name. + +::: out az_deploy.out ::: + +## Invoke the function + +Execute the command below to invoke the function by replacing `` with your respective function app name. + +::: out execute_function.out ::: diff --git a/examples/azure-functions-hello-world/azure-functions-hello-world.metatags b/examples/azure-functions-hello-world/azure-functions-hello-world.metatags new file mode 100644 index 0000000000..94c8e451fe --- /dev/null +++ b/examples/azure-functions-hello-world/azure-functions-hello-world.metatags @@ -0,0 +1,2 @@ +description: This example demonstrates how to write a hello world function with http trigger and output in Azure Functions. +keywords: ballerina, ballerina by example, azure functions, function as a service, serverless diff --git a/examples/azure-functions-hello-world/bal_build.out b/examples/azure-functions-hello-world/bal_build.out new file mode 100644 index 0000000000..c0ae9bfb3a --- /dev/null +++ b/examples/azure-functions-hello-world/bal_build.out @@ -0,0 +1,15 @@ +$ bal build --cloud="azure_functions" +Compiling source + wso2/azure_functions_hello_world:0.1.0 + +Generating executable + + @azure.functions:Function: get-hello + + Execute the command below to deploy the function locally: + $ func start --script-root target/azure_functions --java + + Execute the command below to deploy Ballerina Azure Functions: + $ func azure functionapp publish --script-root target/azure_functions + + target/bin/azure_functions_hello_world.jar diff --git a/examples/azure-functions-hello-world/bal_new.out b/examples/azure-functions-hello-world/bal_new.out new file mode 100644 index 0000000000..8ae62e5014 --- /dev/null +++ b/examples/azure-functions-hello-world/bal_new.out @@ -0,0 +1,2 @@ +$ bal new azure_functions_hello_world +Created new package 'azure_functions_hello_world' at /Users/wso2/azure_functions_hello_world. diff --git a/examples/azure-functions-hello-world/execute_function.out b/examples/azure-functions-hello-world/execute_function.out new file mode 100644 index 0000000000..00c4c87894 --- /dev/null +++ b/examples/azure-functions-hello-world/execute_function.out @@ -0,0 +1,2 @@ +$ curl https://.azurewebsites.net/hello\?name\=Jack +Hello, Jack! diff --git a/examples/azure-functions-http-trigger-with-queue/az_deploy.out b/examples/azure-functions-http-trigger-with-queue/az_deploy.out new file mode 100644 index 0000000000..b70f73af37 --- /dev/null +++ b/examples/azure-functions-http-trigger-with-queue/az_deploy.out @@ -0,0 +1,10 @@ +$ func azure functionapp publish --script-root target/azure_functions +Getting site publishing info... +Creating archive for current directory... +Uploading 32.71 MB [##############################################################################] +Upload completed successfully. +Deployment completed successfully. +Syncing triggers... +Functions in : + post-queue - [httpTrigger] + Invoke url: https://azurecosmosdbfunctionapp.azurewebsites.net/queue diff --git a/examples/azure-functions-http-trigger-with-queue/azure-functions-http-trigger-with-queue.bal b/examples/azure-functions-http-trigger-with-queue/azure-functions-http-trigger-with-queue.bal new file mode 100644 index 0000000000..4a25222428 --- /dev/null +++ b/examples/azure-functions-http-trigger-with-queue/azure-functions-http-trigger-with-queue.bal @@ -0,0 +1,18 @@ +import ballerina/http; +import ballerinax/azure.functions; + +public type Person record { + string name; + int age; +}; + +service / on new functions:HttpListener() { + resource function post queue(@http:Payload Person person) returns + [@functions:HttpOutput http:Created, @functions:QueueOutput {queueName: "people"} + string] { + http:Created httpRes = { + body: person.name + " Added to the Queue!" + }; + return [httpRes, string `${person.name} is ${person.age.toString()} years old.`]; + } +} diff --git a/examples/azure-functions-http-trigger-with-queue/azure-functions-http-trigger-with-queue.md b/examples/azure-functions-http-trigger-with-queue/azure-functions-http-trigger-with-queue.md new file mode 100644 index 0000000000..e4d54b4450 --- /dev/null +++ b/examples/azure-functions-http-trigger-with-queue/azure-functions-http-trigger-with-queue.md @@ -0,0 +1,44 @@ +# Azure Functions - HTTP trigger with queue + +This example demonstrates using an HTTP trigger to invoke an Azure function with multiple output bindings to return the HTTP response and queue output binding to write an entry to a queue. + +For more information, see the [Azure Functions deployment guide](https://ballerina.io/learn/azure-functions/). + +## Set up the prerequisites + +1. Set up the [general prerequisites](https://ballerina.io/learn/azure-functions/#set-up-the-prerequisites). +2. In the AWS Portal, click **Storage accounts** to create a queue to hold the outputs of the function. +2. From the list, click on the storage account entry that corresponds with your function app. +3. Click **Queues** in the sidebar, and click **+ Queue**. +4. Enter a name in the **Add queue** pop-up, and click **Add**. + >**Note:** For the **Queue name**, enter the same value of the `queueName` property in the `QueueOutput` annotation in the [Ballerina source below](https://ballerina.io/learn/by-example/azure-functions-trigger/#write-the-function) + +## Write the function + +Follow the steps below to write the function. + +1. Execute the command below to create a new Ballerina package. + +::: out bal_new.out ::: + +2. Replace the content of the generated Ballerina file with the content below. + +::: code azure-functions-http-trigger-with-queue.bal ::: + +## Build the function + +Execute the command below to generate the Azure Functions artifacts. + +::: out bal_build.out ::: + +## Deploy the function + +Execute the Azure CLI command given by the compiler to create and publish the functions by replacing `` with your respective function app name. + +## Invoke the function + +Execute the command below by replacing `` with your respective function app name to invoke the function. + +::: out execute_function.out ::: + +>**Tip:** Refresh the page of the `people` queue in the Azure portal and view the entry added with the message text: `Jack is 21 years old.` diff --git a/examples/azure-functions-http-trigger-with-queue/azure-functions-http-trigger-with-queue.metatags b/examples/azure-functions-http-trigger-with-queue/azure-functions-http-trigger-with-queue.metatags new file mode 100644 index 0000000000..bfb22ffc2f --- /dev/null +++ b/examples/azure-functions-http-trigger-with-queue/azure-functions-http-trigger-with-queue.metatags @@ -0,0 +1,2 @@ +description: This example demonstrates using an HTTP trigger to invoke an Azure function with multiple output bindings to return the HTTP response and queue output binding to write an entry to a queue. +keywords: ballerina, ballerina by example, aws lambda, http, trigger, serverless, cloud, function as a service diff --git a/examples/azure-functions-http-trigger-with-queue/bal_build.out b/examples/azure-functions-http-trigger-with-queue/bal_build.out new file mode 100644 index 0000000000..c6374c68c9 --- /dev/null +++ b/examples/azure-functions-http-trigger-with-queue/bal_build.out @@ -0,0 +1,15 @@ +$ bal build --cloud="azure_functions" +Compiling source + wso2/azure_functions_http_trigger_with_queue:0.1.0 + +Generating executable + + @azure.functions:Function: post-queue + + Execute the command below to deploy the function locally: + $ func start --script-root target/azure_functions --java + + Execute the command below to deploy Ballerina Azure Functions: + $ func azure functionapp publish --script-root target/azure_functions + + target/bin/azure_functions_http_trigger_with_queue.jar diff --git a/examples/azure-functions-http-trigger-with-queue/bal_new.out b/examples/azure-functions-http-trigger-with-queue/bal_new.out new file mode 100644 index 0000000000..0e8bdbeaa7 --- /dev/null +++ b/examples/azure-functions-http-trigger-with-queue/bal_new.out @@ -0,0 +1,2 @@ +$ bal new azure_functions_http_trigger_with_queue +Created new package 'azure_functions_http_trigger_with_queue' at /Users/wso2/azure_functions_http_trigger_with_queue. diff --git a/examples/azure-functions-http-trigger-with-queue/execute_function.out b/examples/azure-functions-http-trigger-with-queue/execute_function.out new file mode 100644 index 0000000000..168340bfc7 --- /dev/null +++ b/examples/azure-functions-http-trigger-with-queue/execute_function.out @@ -0,0 +1,5 @@ +$ curl --header "Content-Type: application/json" \ + --request POST \ + --data '{"name":"Jack","age":21}' \ + "https://.azurewebsites.net/queue" +Jack Added to the Queue! diff --git a/examples/azure-functions-timer-trigger/az_deploy.out b/examples/azure-functions-timer-trigger/az_deploy.out new file mode 100644 index 0000000000..d23cb3204c --- /dev/null +++ b/examples/azure-functions-timer-trigger/az_deploy.out @@ -0,0 +1,9 @@ +$ func azure functionapp publish --script-root target/azure_functions +Getting site publishing info... +Creating archive for current directory... +Uploading 32.7 MB [###############################################################################] +Upload completed successfully. +Deployment completed successfully. +Syncing triggers... +Functions in : + timer - [timerTrigger] diff --git a/examples/azure-functions-timer-trigger/azure-functions-timer-trigger.bal b/examples/azure-functions-timer-trigger/azure-functions-timer-trigger.bal new file mode 100644 index 0000000000..a775938ba2 --- /dev/null +++ b/examples/azure-functions-timer-trigger/azure-functions-timer-trigger.bal @@ -0,0 +1,15 @@ +import ballerina/time; +import ballerinax/azure.functions; + +// This function gets executed every 10 seconds by the Azure Functions app. Once the function is executed, the timer +// details will be stored in the selected queue storage for every invocation. +@functions:TimerTrigger {schedule: "*/10 * * * * *"} +listener functions:TimerListener timerListener = new functions:TimerListener(); + +service "timer" on timerListener { + remote function onTrigger(functions:TimerMetadata metadata) returns + @functions:QueueOutput {queueName: "timer-queue"} string|error { + time:Utc utc = time:utcNow(); + return "Hello from timer: " + time:utcToEmailString(utc); + } +} diff --git a/examples/azure-functions-timer-trigger/azure-functions-timer-trigger.md b/examples/azure-functions-timer-trigger/azure-functions-timer-trigger.md new file mode 100644 index 0000000000..6cddd29af7 --- /dev/null +++ b/examples/azure-functions-timer-trigger/azure-functions-timer-trigger.md @@ -0,0 +1,41 @@ +# Azure Functions - Timer trigger + +This example demonstrates how a function can be scheduled to execute periodically by the Azure Functions app. Once the function is executed, the timer details will be stored in the selected queue storage for every invocation. + +For more information, see the [Azure deployment guide](https://ballerina.io/learn/azure-functions/). + +## Set up the prerequisites + +For instructions, see [Set up the prerequisites](https://ballerina.io/learn/azure-functions/#set-up-the-prerequisites). + +## Write the function + +Follow the steps below to write the function. + +1. Execute the command below to create a new Ballerina package. + +::: out bal_new.out ::: + +2. Replace the content of the generated Ballerina file with the content below. + +::: code azure-functions-timer-trigger.bal ::: + +## Build the function + +Execute the command below to generate the Azure Functions artifacts. + +::: out bal_build.out ::: + +## Deploy the function + +Execute the Azure CLI command given by the compiler to create and publish the functions by replacing `` with your respective function app name. + +## Invoke the function + +The `timer` function is triggered by the Azure Functions app from a timer. Follow the steps below to verify the output in the queue storage of the function app. + +1. In the AWS Portal, click **Storage accounts** to view the created queue. +2. From the list, click on the storage account entry that corresponds with your function app. +3. Click ***Queues***, and click on the **queue3** queue. +4. You view the output below getting logged every 10 seconds. + `Hello from timer: ` diff --git a/examples/azure-functions-timer-trigger/azure-functions-timer-trigger.metatags b/examples/azure-functions-timer-trigger/azure-functions-timer-trigger.metatags new file mode 100644 index 0000000000..6646778ffd --- /dev/null +++ b/examples/azure-functions-timer-trigger/azure-functions-timer-trigger.metatags @@ -0,0 +1,2 @@ +description: This example demonstrates how a function can be scheduled to execute periodically by the Azure Functions app. +keywords: ballerina, ballerina by example, aws lambda, timer, trigger, serverless, cloud, function as a service diff --git a/examples/azure-functions-timer-trigger/bal_build.out b/examples/azure-functions-timer-trigger/bal_build.out new file mode 100644 index 0000000000..b6244e8963 --- /dev/null +++ b/examples/azure-functions-timer-trigger/bal_build.out @@ -0,0 +1,15 @@ +$ bal build --cloud="azure_functions" +Compiling source + wso2/azure_functions_timer_trigger:0.1.0 + +Generating executable + + @azure.functions:Function: timer + + Execute the command below to deploy the function locally: + $ func start --script-root target/azure_functions --java + + Execute the command below to deploy Ballerina Azure Functions: + $ func azure functionapp publish --script-root target/azure_functions + + target/bin/azure_functions_timer_trigger.jar diff --git a/examples/azure-functions-timer-trigger/bal_new.out b/examples/azure-functions-timer-trigger/bal_new.out new file mode 100644 index 0000000000..d6d81b0cd3 --- /dev/null +++ b/examples/azure-functions-timer-trigger/bal_new.out @@ -0,0 +1,2 @@ +$ bal new azure_functions_timer_trigger +Created new package 'azure_functions_timer_trigger' at /Users/wso2/azure_functions_timer_trigger. diff --git a/examples/c2c-docker-deployment/c2c_docker_deployment.md b/examples/c2c-docker-deployment/c2c_docker_deployment.md index aa26d55d08..d2affc808c 100644 --- a/examples/c2c-docker-deployment/c2c_docker_deployment.md +++ b/examples/c2c-docker-deployment/c2c_docker_deployment.md @@ -1,7 +1,7 @@ # Docker Ballerina supports generating Docker artifacts from code without any additional configuration. This simplifies the experience of developing and deploying Ballerina code in the cloud. Code to Cloud builds the containers and required artifacts by deriving the required values from the code. If you want to override the default values taken by the compiler, you can use a `Cloud.toml` file. -For more information, see [Code to Cloud Deployment](/learn/run-in-the-cloud/code-to-cloud/code-to-cloud-deployment/). +For more information, see [Code to Cloud Deployment](/learn/code-to-cloud-deployment/). ::: code c2c_docker_deployment.bal ::: diff --git a/examples/c2c-k8s-deployment/c2c_k8s_deployment.md b/examples/c2c-k8s-deployment/c2c_k8s_deployment.md index e897513ead..9ac12bb57e 100644 --- a/examples/c2c-k8s-deployment/c2c_k8s_deployment.md +++ b/examples/c2c-k8s-deployment/c2c_k8s_deployment.md @@ -1,7 +1,7 @@ # Kubernetes Ballerina supports generating Kubernetes artifacts from code without any additional configuration. This simplifies the experience of developing and deploying Ballerina code in the cloud. Code to Cloud builds the containers and required artifacts by deriving the required values from the code. If you want to override the default values taken by the compiler, you can use a `Cloud.toml` file. -For more information, see [Code to Cloud Deployment](/learn/run-in-the-cloud/code-to-cloud/code-to-cloud-deployment/). +For more information, see [Code to Cloud Deployment](/learn/code-to-cloud-deployment/). ::: code c2c_k8s_deployment.bal ::: diff --git a/examples/configurable-variables/configurable_variables.md b/examples/configurable-variables/configurable_variables.md index 89a99e5713..2d43fd239a 100644 --- a/examples/configurable-variables/configurable_variables.md +++ b/examples/configurable-variables/configurable_variables.md @@ -2,7 +2,7 @@ A module-level variable can be declared as configurable. The initializer of a configurable variable can be overridden at runtime (e.g., by a TOML file). A variable for which a configuration is required can use an initializer of `?`. The type of a configurable variable must be a subtype of `anydata`. -For more information, see [Configure a sample Ballerina service](/learn/configure-ballerina-programs/configure-a-sample-ballerina-service/). +For more information, see [Configure a sample Ballerina service](/learn/configure-a-sample-ballerina-service/). ::: code configurable_variables.bal ::: diff --git a/examples/configuring-via-cli/configuring_via_cli.md b/examples/configuring-via-cli/configuring_via_cli.md index 3ba918800a..21c732f632 100644 --- a/examples/configuring-via-cli/configuring_via_cli.md +++ b/examples/configuring-via-cli/configuring_via_cli.md @@ -5,7 +5,7 @@ The values of the configurable variables can be configured through the command-l The command-line-based configuration is only supported for configurable variables of types `int`, `byte`, `float`, `boolean`, `string`, `decimal`, `enum`, and `xml`. The `-Ckey=value` syntax can be used to provide values through the command-line parameters. -For more information, see [Configure via command-line arguments](/learn/configure-ballerina-programs/provide-values-to-configurable-variables/#provide-via-command-line-arguments/). +For more information, see [Configure via command-line arguments](/learn/provide-values-to-configurable-variables/#provide-via-command-line-arguments/). ::: code configuring_via_cli.bal ::: diff --git a/examples/configuring-via-toml/configuring-via-toml.md b/examples/configuring-via-toml/configuring-via-toml.md index 79a25b9311..8d96d2ed29 100644 --- a/examples/configuring-via-toml/configuring-via-toml.md +++ b/examples/configuring-via-toml/configuring-via-toml.md @@ -6,7 +6,7 @@ The file location can be specified through an environment variable with the name An environment variable with the name `BAL_CONFIG_DATA` can be used to provide the configuration file content instead of a separate file. -For more information, see [Configure via TOML syntax](/learn/configure-ballerina-programs/provide-values-to-configurable-variables/#provide-via-toml-syntax/). +For more information, see [Configure via TOML syntax](/learn/provide-values-to-configurable-variables/#provide-via-toml-syntax/). ::: code configuring_via_toml.bal ::: diff --git a/examples/const-and-final/const_and_final.bal b/examples/const-and-final/const_and_final.bal index 9b3a537307..0f7b601f9a 100644 --- a/examples/const-and-final/const_and_final.bal +++ b/examples/const-and-final/const_and_final.bal @@ -1,15 +1,22 @@ import ballerina/io; +const int MAX_VALUE = 1000; + // Constants can be defined without the type. Then, the type is inferred from the right-hand side. -const MAX_VALUE = 1000; const URL = "https://ballerina.io"; -// The value for variable `msg` can only be assigned once. +// Mapping and list constants can also be defined. +const HTTP_OK = {httpCode: 200, message: "OK"}; +const ERROR_CODES = [200, 202, 400]; + +// The value for the `msg` variable can only be assigned once. final string msg = loadMessage(); public function main() { io:println(MAX_VALUE); io:println(URL); + io:println(HTTP_OK); + io:println(ERROR_CODES); io:println(msg); } diff --git a/examples/const-and-final/const_and_final.metatags b/examples/const-and-final/const_and_final.metatags index f2088bce39..588b1b9ae4 100644 --- a/examples/const-and-final/const_and_final.metatags +++ b/examples/const-and-final/const_and_final.metatags @@ -1,2 +1,2 @@ -description: This BBE demonstrates how const and final values are used in Ballerina. -keywords: ballerina, ballerina by example, bbe, const, final +description: This BBE demonstrates how `const` and `final` values are used in Ballerina. +keywords: ballerina, ballerina by example, bbe, const, final, map const, list const diff --git a/examples/const-and-final/const_and_final.out b/examples/const-and-final/const_and_final.out index f05491beea..76497199b7 100644 --- a/examples/const-and-final/const_and_final.out +++ b/examples/const-and-final/const_and_final.out @@ -1,4 +1,6 @@ $ bal run const_and_final 1000 https://ballerina.io +{"httpCode":200,"message":"OK"} +[200,202,400] Hello World diff --git a/examples/custom-prefetch-methods/custom_prefetch_methods.bal b/examples/custom-prefetch-methods/custom_prefetch_methods.bal new file mode 100644 index 0000000000..8594179502 --- /dev/null +++ b/examples/custom-prefetch-methods/custom_prefetch_methods.bal @@ -0,0 +1,86 @@ +import ballerina/graphql; +import ballerina/graphql.dataloader; +import ballerina/http; + +public type Book record {| + int id; + string title; +|}; + +type BookRow record {| + readonly int id; + string title; + int author; +|}; + +type AuthorRow record {| + readonly int id; + string name; +|}; + +final readonly & table key(id) authorTable = table [ + {id: 1, name: "J.K. Rowling"}, + {id: 2, name: "Stephen King"} +]; + +final readonly & table key(id) bookTable = table [ + {id: 1, title: "Harry Potter and the Sorcerer's Stone", author: 1}, + {id: 2, title: "The Shining", author: 2}, + {id: 3, title: "Harry Potter and the Chamber of Secrets", author: 1}, + {id: 4, title: "It", author: 2}, + {id: 5, title: "Harry Potter and the Prisoner of Azkaban", author: 1}, + {id: 6, title: "The Stand", author: 2} +]; + +isolated function bookLoaderFunction(readonly & anydata[] ids) returns BookRow[][]|error { + final readonly & int[] keys = check ids.ensureType(); + return keys.'map(isolated function(readonly & int key) returns BookRow[] { + return bookTable.'filter(book => book.author == key).toArray(); + }); +} + +@graphql:ServiceConfig { + contextInit: isolated function(http:RequestContext requestContext, http:Request request) + returns graphql:Context { + graphql:Context ctx = new; + ctx.registerDataLoader("bookLoader", new dataloader:DefaultDataLoader(bookLoaderFunction)); + return ctx; + } +} +service /graphql on new graphql:Listener(9090) { + resource function get authors() returns Author[] { + return from AuthorRow authorRow in authorTable + select new (authorRow); + } +} + +public isolated distinct service class Author { + private final readonly & AuthorRow author; + + isolated function init(readonly & AuthorRow author) { + self.author = author; + } + + isolated resource function get name() returns string { + return self.author.name; + } + + // Define a prefetch function with a custom name. + isolated function prefetchBooks(graphql:Context ctx) { + dataloader:DataLoader bookLoader = ctx.getDataLoader("bookLoader"); + bookLoader.add(self.author.id); + } + + // Annotate the resource function to use a prefetch function having a custom name. + // This configuration instructs the GraphQL engine to call the `prefetchBooks` function + // before calling the `books` resource function. + @graphql:ResourceConfig { + prefetchMethodName: "prefetchBooks" + } + isolated resource function get books(graphql:Context ctx) returns Book[]|error { + dataloader:DataLoader bookLoader = ctx.getDataLoader("bookLoader"); + BookRow[] bookrows = check bookLoader.get(self.author.id); + return from BookRow bookRow in bookrows + select {id: bookRow.id, title: bookRow.title}; + } +} diff --git a/examples/custom-prefetch-methods/custom_prefetch_methods.client.out b/examples/custom-prefetch-methods/custom_prefetch_methods.client.out new file mode 100644 index 0000000000..3a16d20b53 --- /dev/null +++ b/examples/custom-prefetch-methods/custom_prefetch_methods.client.out @@ -0,0 +1,2 @@ +$ curl 'http://localhost:9090/graphql' -H 'Content-Type: application/json' -d '{"query": "{ authors { name books { title } } }"}' +{"data":{"authors":[{"name":"J.K. Rowling", "books":[{"title":"Harry Potter and the Sorcerer's Stone"}, {"title":"Harry Potter and the Chamber of Secrets"}, {"title":"Harry Potter and the Prisoner of Azkaban"}]}, {"name":"Stephen King", "books":[{"title":"The Shining"}, {"title":"It"}, {"title":"The Stand"}]}]}} diff --git a/examples/custom-prefetch-methods/custom_prefetch_methods.graphql b/examples/custom-prefetch-methods/custom_prefetch_methods.graphql new file mode 100644 index 0000000000..97a0423ea1 --- /dev/null +++ b/examples/custom-prefetch-methods/custom_prefetch_methods.graphql @@ -0,0 +1,8 @@ +{ + authors { + name + books { + title + } + } +} diff --git a/examples/custom-prefetch-methods/custom_prefetch_methods.md b/examples/custom-prefetch-methods/custom_prefetch_methods.md new file mode 100644 index 0000000000..b6ba475a84 --- /dev/null +++ b/examples/custom-prefetch-methods/custom_prefetch_methods.md @@ -0,0 +1,24 @@ +# GraphQL service - Custom prefetch methods + +A prefetch method in the context of Ballerina GraphQL is a method that is invoked before the actual resolver method. By default the prefetch method name has the convention of having the prefix `pre` followed by the resolver method name. + +If you want to use a custom prefetch method, the `prefetchMethodName` field of the `graphql:ResourceConfig` annotation can be used to override the default prefetch method name. This configuration is useful when the Query and Mutation operations have fields with the same name, and when it is required to use different prefetch methods for each field. To override the default prefetch method name, annotate the target field with the `graphql:ResourceConfig` annotation and specify the prefetch method name as the value of the `prefetchMethodName` field. + +::: code custom_prefetch_methods.bal ::: + +Run the service by executing the following command. + +::: out custom_prefetch_methods.server.out ::: + +Send the following document to the GraphQL endpoint to test the service. + +::: code custom_prefetch_methods.graphql ::: + +To send the document, execute the following cURL command in a separate terminal. + +::: out custom_prefetch_methods.client.out ::: + +## Related links +- [`graphql:ResourceConfig` annotation - API documentation](https://lib.ballerina.io/ballerina/graphql/latest#ResourceConfig) +- [Prefetch Method Name Configuration - Specification](/spec/graphql/#722-prefetch-method-name-configuration) +- [The `prefetch` Method - Specification](/spec/graphql/#10633-define-the-corresponding-prefetch-method) diff --git a/examples/custom-prefetch-methods/custom_prefetch_methods.metatags b/examples/custom-prefetch-methods/custom_prefetch_methods.metatags new file mode 100644 index 0000000000..69f768f8ff --- /dev/null +++ b/examples/custom-prefetch-methods/custom_prefetch_methods.metatags @@ -0,0 +1,2 @@ +description: BBE on overriding a default prefetch method name. +keywords: ballerina, ballerina by example, bbe, graphql, dataloader, prefetch method diff --git a/examples/custom-prefetch-methods/custom_prefetch_methods.server.out b/examples/custom-prefetch-methods/custom_prefetch_methods.server.out new file mode 100644 index 0000000000..d8d75f81aa --- /dev/null +++ b/examples/custom-prefetch-methods/custom_prefetch_methods.server.out @@ -0,0 +1 @@ +$ bal run graphql_prefetch_config.bal diff --git a/examples/docker-hello-world/Cloud.toml b/examples/docker-hello-world/Cloud.toml new file mode 100644 index 0000000000..f83062215c --- /dev/null +++ b/examples/docker-hello-world/Cloud.toml @@ -0,0 +1,4 @@ +[container.image] +repository="wso2inc" +name="hello" +tag="v0.1.0" diff --git a/examples/docker-hello-world/build_output.out b/examples/docker-hello-world/build_output.out new file mode 100644 index 0000000000..0be7c484d3 --- /dev/null +++ b/examples/docker-hello-world/build_output.out @@ -0,0 +1,13 @@ +$ bal build --cloud="docker" + +Compiling source + wso2/hello:0.1.0 + +Generating executable + +Generating artifacts... + + @kubernetes:Docker - complete 2/2 + + Execute the below command to run the generated Docker image: + docker run -d -p 9090:9090 wso2inc/hello:v0.1.0 diff --git a/examples/docker-hello-world/docker-hello-world.bal b/examples/docker-hello-world/docker-hello-world.bal new file mode 100644 index 0000000000..d120a0d143 --- /dev/null +++ b/examples/docker-hello-world/docker-hello-world.bal @@ -0,0 +1,11 @@ +import ballerina/http; + +// This code is completely focused on the business logic and it does not depend on the deployment. + +listener http:Listener helloEP = new(9090); + +service http:Service /helloWorld on helloEP { + resource function get sayHello() returns string { + return "Hello from Docker!"; + } +} diff --git a/examples/docker-hello-world/docker-hello-world.md b/examples/docker-hello-world/docker-hello-world.md new file mode 100644 index 0000000000..94ff99fe52 --- /dev/null +++ b/examples/docker-hello-world/docker-hello-world.md @@ -0,0 +1,23 @@ +# Docker - Hello world + +Ballerina supports generating Docker artifacts from code without any additional configuration. This simplifies the experience of developing and deploying Ballerina code in the cloud. Code to Cloud builds the containers and required artifacts by deriving the required values from the code. If you want to override the default values taken by the compiler, you can use a `Cloud.toml` file. +For more information, see [Code to Cloud Deployment](/learn/code-to-cloud-deployment/). + +::: code docker-hello-world.bal ::: + +Before you build the package, you need to override some default values taken by the compiler. To do this, create a file named `Cloud.toml` in the package directory, and add the content below to it. +For all the supported key value properties, see [Code to Cloud specification](https://github.com/ballerina-platform/ballerina-spec/blob/master/c2c/code-to-cloud-spec.md). + +::: code Cloud.toml ::: + +Execute the `bal build` command to build the Ballerina package. Code to Cloud generates only one container per package. +::: out build_output.out ::: + +Verify if the Docker image is generated. +::: out docker_images.out ::: + +Run the generated Docker image. +::: out docker_run.out ::: + +Invoke the service. +::: out execute_curl.out::: diff --git a/examples/docker-hello-world/docker_images.out b/examples/docker-hello-world/docker_images.out new file mode 100644 index 0000000000..654c17ba99 --- /dev/null +++ b/examples/docker-hello-world/docker_images.out @@ -0,0 +1,4 @@ +$ docker images + +REPOSITORY TAG IMAGE ID CREATED SIZE +wso2inc/hello v0.1.0 60d95f0928b2 About a minute ago 228MB diff --git a/examples/docker-hello-world/docker_run.out b/examples/docker-hello-world/docker_run.out new file mode 100644 index 0000000000..7649d4881b --- /dev/null +++ b/examples/docker-hello-world/docker_run.out @@ -0,0 +1,2 @@ +$ docker run -d -p 9090:9090 wso2inc/hello:v0.1.0 +c04194eb0b4d0d78cbc8ca55e0527d381d8ab4a1a68f8ea5dd3770a0845d5fbb diff --git a/examples/docker-hello-world/execute_curl.out b/examples/docker-hello-world/execute_curl.out new file mode 100644 index 0000000000..e59778411c --- /dev/null +++ b/examples/docker-hello-world/execute_curl.out @@ -0,0 +1,2 @@ +$ curl http://localhost:9090/helloWorld/sayHello +Hello from Docker! diff --git a/examples/edi-to-record/bal_project.out b/examples/edi-to-record/bal_project.out new file mode 100644 index 0000000000..565a506a1d --- /dev/null +++ b/examples/edi-to-record/bal_project.out @@ -0,0 +1,3 @@ +$ bal new edi_to_record +$ cd edi_to_record +$ bal add sorder diff --git a/examples/edi-to-record/codegen_command.out b/examples/edi-to-record/codegen_command.out new file mode 100644 index 0000000000..f7bbc95816 --- /dev/null +++ b/examples/edi-to-record/codegen_command.out @@ -0,0 +1 @@ +$ bal edi codegen -s resources/simple_order_schema.json -o modules/sorder/sorder.bal diff --git a/examples/edi-to-record/edi_to_record.bal b/examples/edi-to-record/edi_to_record.bal new file mode 100644 index 0000000000..9c61fd9586 --- /dev/null +++ b/examples/edi-to-record/edi_to_record.bal @@ -0,0 +1,12 @@ +import ballerina/io; +import edi_to_record.sorder; + +public function main() returns error? { + string ediText = check io:fileReadString("resources/order.edi"); + sorder:SimpleOrder simpleOrder = check sorder:fromEdiString(ediText); + io:println("Order Id: ", simpleOrder.header.orderId); + + foreach sorder:Items_Type item in simpleOrder.items { + io:println("Item: ", item.item, ", Quantity: ", item.quantity); + } +} diff --git a/examples/edi-to-record/edi_to_record.md b/examples/edi-to-record/edi_to_record.md new file mode 100644 index 0000000000..9078f4365a --- /dev/null +++ b/examples/edi-to-record/edi_to_record.md @@ -0,0 +1,37 @@ +# EDI to record conversion + +EDI is a widely used message format for business-to-business (B2B) communications. Ballerina simplifies working with EDI data by converting them to Ballerina records, so that all operations related to Ballerina records can be applied on EDI data as well (e.g. transforming EDI data, writing EDI data to databases, transering EDI data over various network protocols, etc.). + +First, it is necessary to write a schema for the EDI data type that needs to be processed. Below is a simple EDI schema for sales order data. According to the schema, data must begin with a `HDR` segment followed by zero or more `ITM` segments. `HDR` segment contains four fields: `code`, `orderId`, `organization`, and `date`. `ITM` segment has three fields: `code`, `item`, and `quantity`. + +::: code schema.json ::: + +Below is an example EDI text that can be parsed using the above schema. + +::: code order.edi ::: + +Create a new Ballerina project named `edi_to_record` and create a module named `sorder` inside that project by using the below commands. + +::: code bal_project.out ::: + +Create a new folder named `resources` in the root of the project and copy the schema file into it. At this point, directory structure of the project would look like below: + +::: out package_structure.out ::: + +Get the EDI tool from the Ballerina central using the below command: + +::: out tool_pull_command.out ::: + +Run the below command from the project root directory to generate the Ballerina parser for the above schema. + +::: out codegen_command.out ::: + +>Note that it is recommended to place generated code for each EDI schema in a separate module in order to avoid conflicts. + +Write a Ballerina program by using generated methods and records to work with EDI data. + +::: code edi_to_record.bal ::: + +Run the program using the command below: + +::: out output.out ::: diff --git a/examples/edi-to-record/edi_to_record.metatags b/examples/edi-to-record/edi_to_record.metatags new file mode 100644 index 0000000000..33710f74dc --- /dev/null +++ b/examples/edi-to-record/edi_to_record.metatags @@ -0,0 +1,2 @@ +description: This BBE demonstrates how convert EDI text into Ballerina records based on an EDI schema. +keywords: ballerina, ballerina by example, bbe, edi, electronic data interchange, b2b, integration diff --git a/examples/edi-to-record/order.edi b/examples/edi-to-record/order.edi new file mode 100644 index 0000000000..dca0ac9e56 --- /dev/null +++ b/examples/edi-to-record/order.edi @@ -0,0 +1,6 @@ +HDR*ORDER_1201*ABC_Store*2008-01-01~ +ITM*A-250*12~ +ITM*A-45*100~ +ITM*D-10*58~ +ITM*K-80*250~ +ITM*T-46*28~ diff --git a/examples/edi-to-record/output.out b/examples/edi-to-record/output.out new file mode 100644 index 0000000000..7ce0dbdbed --- /dev/null +++ b/examples/edi-to-record/output.out @@ -0,0 +1,7 @@ +$ bal run +Order Id: ORDER_1201 +Item: A-250, Quantity: 12 +Item: A-45, Quantity: 100 +Item: D-10, Quantity: 58 +Item: K-80, Quantity: 250 +Item: T-46, Quantity: 28 diff --git a/examples/edi-to-record/package_structure.out b/examples/edi-to-record/package_structure.out new file mode 100644 index 0000000000..7e01bf46fa --- /dev/null +++ b/examples/edi-to-record/package_structure.out @@ -0,0 +1,13 @@ +└── edi_to_record + ├── Ballerina.toml + ├── Dependencies.toml + ├── main.bal + ├── modules + │   └── sorder + │   ├── Module.md + │   ├── resources + │   ├── sorder.bal + │   └── tests + │   └── lib_test.bal + └── resources + └── simple_order_schema.json diff --git a/examples/edi-to-record/schema.json b/examples/edi-to-record/schema.json new file mode 100644 index 0000000000..a3e8eea20a --- /dev/null +++ b/examples/edi-to-record/schema.json @@ -0,0 +1,18 @@ +{ + "name": "SimpleOrder", + "delimiters" : {"segment" : "~", "field" : "*", "component": ":", "repetition": "^"}, + "segments" : [ + { + "code": "HDR", + "tag" : "header", + "minOccurances": 1, + "fields" : [{"tag": "code"}, {"tag" : "orderId", "required": true}, {"tag" : "organization"}, {"tag" : "date"}] + }, + { + "code": "ITM", + "tag" : "items", + "maxOccurances" : -1, + "fields" : [{"tag": "code"}, {"tag" : "item", "required": true}, {"tag" : "quantity", "required": true, "dataType" : "int"}] + } + ] +} diff --git a/examples/edi-to-record/tool_pull_command.out b/examples/edi-to-record/tool_pull_command.out new file mode 100644 index 0000000000..8cdb63f178 --- /dev/null +++ b/examples/edi-to-record/tool_pull_command.out @@ -0,0 +1 @@ +$ bal tool pull edi diff --git a/examples/function-types/function_types.bal b/examples/function-types/function_types.bal index 3235819d32..224555d948 100644 --- a/examples/function-types/function_types.bal +++ b/examples/function-types/function_types.bal @@ -14,7 +14,7 @@ public function main() { io:println(evenFunc1(5)); io:println(evenFunc1(6)); - // Type of the `evenFunc1` variable is the `function(int num = 5) returns boolean` function type. + // Type of the `evenFunc2` variable is the `function (int num = 5) returns boolean` function type. function (int num = 5) returns boolean evenFunc2 = isEven; // Invoke the function with the default value defined in the function type. diff --git a/examples/graphql-client-error-handling/graphql_client_error_handling.md b/examples/graphql-client-error-handling/graphql_client_error_handling.md index 4e48d61c4a..08c312f748 100644 --- a/examples/graphql-client-error-handling/graphql_client_error_handling.md +++ b/examples/graphql-client-error-handling/graphql_client_error_handling.md @@ -13,4 +13,4 @@ Run the client program by executing the following command. ## Related links - [`graphql:ClientError` error - API documentation](https://lib.ballerina.io/ballerina/graphql/latest#ClientError) -- [GraphQL client error handling - Specification](/spec/graphql/#255-client-error-handling) +- [GraphQL client error handling - Specification](/spec/graphql/#63-client-error-handling) diff --git a/examples/graphql-client-security-basic-auth/graphql_client_security_basic_auth.md b/examples/graphql-client-security-basic-auth/graphql_client_security_basic_auth.md index 19112c40b7..f1a8c25e89 100644 --- a/examples/graphql-client-security-basic-auth/graphql_client_security_basic_auth.md +++ b/examples/graphql-client-security-basic-auth/graphql_client_security_basic_auth.md @@ -14,4 +14,4 @@ Run the client program by executing the following command. ## Related links - [`graphql:CredentialsConfig` record - API documentation](https://lib.ballerina.io/ballerina/graphql/latest#CredentialsConfig) - [`auth` module - API documentation](https://lib.ballerina.io/ballerina/auth/latest/) -- [GraphQL client basic authentication - Specification](/spec/graphql/#1221-basic-authentication) +- [GraphQL client basic authentication - Specification](/spec/graphql/#821-basic-authentication) diff --git a/examples/graphql-client-security-mutual-ssl/graphql_client_security_mutual_ssl.md b/examples/graphql-client-security-mutual-ssl/graphql_client_security_mutual_ssl.md index 0787e65790..7859100bf6 100644 --- a/examples/graphql-client-security-mutual-ssl/graphql_client_security_mutual_ssl.md +++ b/examples/graphql-client-security-mutual-ssl/graphql_client_security_mutual_ssl.md @@ -13,4 +13,4 @@ Run the client program by executing the following command. ## Related links - [`graphql:ClientSecureSocket` record - API documentation](https://lib.ballerina.io/ballerina/graphql/latest#ClientSecureSocket) -- [GraphQL client mutual SSL - Specification](/spec/graphql/#12322-mutual-ssl) +- [GraphQL client mutual SSL - Specification](/spec/graphql/#8322-mutual-ssl) diff --git a/examples/graphql-client-security-oauth2-password-grant-type/graphql_client_security_oauth2_password_grant_type.md b/examples/graphql-client-security-oauth2-password-grant-type/graphql_client_security_oauth2_password_grant_type.md index efcaca7052..eaeac0b2da 100644 --- a/examples/graphql-client-security-oauth2-password-grant-type/graphql_client_security_oauth2_password_grant_type.md +++ b/examples/graphql-client-security-oauth2-password-grant-type/graphql_client_security_oauth2_password_grant_type.md @@ -14,4 +14,4 @@ Run the client program by executing the command below. ## Related links - [`graphql:OAuth2PasswordGrantConfig` record - API documentation](https://lib.ballerina.io/ballerina/graphql/latest#OAuth2PasswordGrantConfig) - [`oauth2` module - API documentation](https://lib.ballerina.io/ballerina/oauth2/latest/) -- [GraphQL client OAuth2 password grant type - Specification](/spec/graphql/#12242-password-grant-type) +- [GraphQL client OAuth2 password grant type - Specification](/spec/graphql/#8242-password-grant-type) diff --git a/examples/graphql-client-security-self-signed-jwt-authentication/graphql_client_security_self_signed_jwt_authentication.md b/examples/graphql-client-security-self-signed-jwt-authentication/graphql_client_security_self_signed_jwt_authentication.md index ad209bb24e..3aebd64b4a 100644 --- a/examples/graphql-client-security-self-signed-jwt-authentication/graphql_client_security_self_signed_jwt_authentication.md +++ b/examples/graphql-client-security-self-signed-jwt-authentication/graphql_client_security_self_signed_jwt_authentication.md @@ -14,4 +14,4 @@ Run the client program by executing the command below. ## Related links - [`graphql:JwtIssuerConfig` record - API documentation](https://lib.ballerina.io/ballerina/graphql/latest#JwtIssuerConfig) - [`jwt` module - API documentation](https://lib.ballerina.io/ballerina/jwt/latest/) -- [GraphQL client self signed JWT authentication - Specification](/spec/graphql/#1223-self-signed-jwt-authentication) +- [GraphQL client self signed JWT authentication - Specification](/spec/graphql/#823-self-signed-jwt-authentication) diff --git a/examples/graphql-client-security-ssl-tls/graphql_client_security_ssl_tls.md b/examples/graphql-client-security-ssl-tls/graphql_client_security_ssl_tls.md index b7488a2ec7..bcb1192dfe 100644 --- a/examples/graphql-client-security-ssl-tls/graphql_client_security_ssl_tls.md +++ b/examples/graphql-client-security-ssl-tls/graphql_client_security_ssl_tls.md @@ -13,4 +13,4 @@ Run the client program by executing the following command. ## Related links - [`graphql:ClientSecureSocket` record - API documentation](https://lib.ballerina.io/ballerina/graphql/latest#ClientSecureSocket) -- [GraphQL client SSL/TLS - Specification](/spec/graphql/#12321-ssltls) +- [GraphQL client SSL/TLS - Specification](/spec/graphql/#8311-ssltls) diff --git a/examples/graphql-context/graphql_context.md b/examples/graphql-context/graphql_context.md index b7d11f47ad..5d82991fec 100644 --- a/examples/graphql-context/graphql_context.md +++ b/examples/graphql-context/graphql_context.md @@ -27,4 +27,4 @@ Now, send the same document with the `scope` header value set to `unknown`. This ## Related links - [`graphql:Context` object - API documentation](https://lib.ballerina.io/ballerina/graphql/latest#Context) -- [GraphQL context - Specification](/spec/graphql/#8-context-object) +- [GraphQL context - Specification](/spec/graphql/#101-context-object) diff --git a/examples/graphql-dataloader/graphql_dataloader.bal b/examples/graphql-dataloader/graphql_dataloader.bal new file mode 100644 index 0000000000..99246efbfc --- /dev/null +++ b/examples/graphql-dataloader/graphql_dataloader.bal @@ -0,0 +1,95 @@ +import ballerina/graphql; +import ballerina/graphql.dataloader; +import ballerina/http; +import ballerina/log; + +public type Book record {| + int id; + string title; +|}; + +type BookRow record {| + readonly int id; + string title; + int author; +|}; + +type AuthorRow record {| + readonly int id; + string name; +|}; + +final readonly & table key(id) authorTable = table [ + {id: 1, name: "J.K. Rowling"}, + {id: 2, name: "Stephen King"} +]; + +final readonly & table key(id) bookTable = table [ + {id: 1, title: "Harry Potter and the Sorcerer's Stone", author: 1}, + {id: 2, title: "The Shining", author: 2}, + {id: 3, title: "Harry Potter and the Chamber of Secrets", author: 1}, + {id: 4, title: "It", author: 2}, + {id: 5, title: "Harry Potter and the Prisoner of Azkaban", author: 1}, + {id: 6, title: "The Stand", author: 2} +]; + +// Implement the `batch load` function for the data loader. +// This function handles fetching data in batches. The primary keys of the data to be loaded +// will be provided as the values of the `ids` parameter to the batch load function. The expected output +// of this function is an array of results in which each element in the result array corresponds +// to a primary key from the `ids` array. +isolated function bookLoaderFunction(readonly & anydata[] ids) returns BookRow[][]|error { + final readonly & int[] keys = check ids.ensureType(); + log:printInfo("executing bookLoaderFunction", keys = keys); + // Implement the batching logic. + return keys.'map(isolated function(readonly & int key) returns BookRow[] { + return bookTable.'filter(book => book.author == key).toArray(); + }); +} + +@graphql:ServiceConfig { + contextInit: isolated function(http:RequestContext requestContext, http:Request request) + returns graphql:Context { + graphql:Context ctx = new; + // Register the dataloader with the context using a unique name. + // A defult implementation of the dataloader is used here. + ctx.registerDataLoader("bookLoader", new dataloader:DefaultDataLoader(bookLoaderFunction)); + return ctx; + } +} +service /graphql on new graphql:Listener(9090) { + resource function get authors() returns Author[] { + return from AuthorRow authorRow in authorTable + select new (authorRow); + } +} + +public isolated distinct service class Author { + private final readonly & AuthorRow author; + + isolated function init(readonly & AuthorRow author) { + self.author = author; + } + + isolated resource function get name() returns string { + return self.author.name; + } + + // Define a prefetch function. + isolated function preBooks(graphql:Context ctx) { + // Obtain the dataloader from the context using the unique name. + // Providing an invalid name here will lead to a panic. + dataloader:DataLoader bookLoader = ctx.getDataLoader("bookLoader"); + // Add the primary key of the data to be fetched to the dataloader. + bookLoader.add(self.author.id); + } + + isolated resource function get books(graphql:Context ctx) returns Book[]|error { + // Obtain the dataloader from the context using the unique name. + dataloader:DataLoader bookLoader = ctx.getDataLoader("bookLoader"); + // Obtain the data from the dataloader using the primary key of the data. + BookRow[] bookrows = check bookLoader.get(self.author.id); + return from BookRow bookRow in bookrows + select {id: bookRow.id, title: bookRow.title}; + } +} diff --git a/examples/graphql-dataloader/graphql_dataloader.client.out b/examples/graphql-dataloader/graphql_dataloader.client.out new file mode 100644 index 0000000000..3a16d20b53 --- /dev/null +++ b/examples/graphql-dataloader/graphql_dataloader.client.out @@ -0,0 +1,2 @@ +$ curl 'http://localhost:9090/graphql' -H 'Content-Type: application/json' -d '{"query": "{ authors { name books { title } } }"}' +{"data":{"authors":[{"name":"J.K. Rowling", "books":[{"title":"Harry Potter and the Sorcerer's Stone"}, {"title":"Harry Potter and the Chamber of Secrets"}, {"title":"Harry Potter and the Prisoner of Azkaban"}]}, {"name":"Stephen King", "books":[{"title":"The Shining"}, {"title":"It"}, {"title":"The Stand"}]}]}} diff --git a/examples/graphql-dataloader/graphql_dataloader.graphql b/examples/graphql-dataloader/graphql_dataloader.graphql new file mode 100644 index 0000000000..97a0423ea1 --- /dev/null +++ b/examples/graphql-dataloader/graphql_dataloader.graphql @@ -0,0 +1,8 @@ +{ + authors { + name + books { + title + } + } +} diff --git a/examples/graphql-dataloader/graphql_dataloader.md b/examples/graphql-dataloader/graphql_dataloader.md new file mode 100644 index 0000000000..ccc2399758 --- /dev/null +++ b/examples/graphql-dataloader/graphql_dataloader.md @@ -0,0 +1,24 @@ +# GraphQL service - Dataloader + +The Ballerina GraphQL module provides the capability to batch and cache data fetching from data sources using the `graphql.dataloader` submodule. To leverage this functionality in a GraphQL service, you must register data loaders through the `graphql:Context` object and implement the corresponding prefetch method logic and resolver method logic. + +A prefetch method, in the context of Ballerina GraphQL, is a method that is invoked before the actual resolver method. By default, the prefetch method name follows the convention of having the prefix `pre`, followed by the resolver method name. The use of `graphql.dataloader` avoids excessive data fetching, effectively addressing the GraphQL N+1 problem. + +::: code graphql_dataloader.bal ::: + +Run the service by executing the following command. + +::: out graphql_dataloader.server.out ::: + +Send the following document to the GraphQL endpoint to test the service. + +::: code graphql_dataloader.graphql ::: + +To send the document, execute the following cURL command in a separate terminal. + +::: out graphql_dataloader.client.out ::: + +## Related links +- [`garaphql.dataloader` module - API documentation](https://lib.ballerina.io/ballerina/graphql.dataloader/latest) +- [DataLoader - Specification](/spec/graphql/#106-dataloader) +- [Utilizing multiple dataloaders in a graphql service](/spec/graphql/#example-utilizing-multiple-dataloaders-in-a-graphql-service) diff --git a/examples/graphql-dataloader/graphql_dataloader.metatags b/examples/graphql-dataloader/graphql_dataloader.metatags new file mode 100644 index 0000000000..3d5de1577b --- /dev/null +++ b/examples/graphql-dataloader/graphql_dataloader.metatags @@ -0,0 +1,2 @@ +description: BBE on how to engage dataloaders with GraphQL service +keywords: ballerina, ballerina by example, bbe, graphql, dataloader, batching, caching diff --git a/examples/graphql-dataloader/graphql_dataloader.server.out b/examples/graphql-dataloader/graphql_dataloader.server.out new file mode 100644 index 0000000000..b5728fd891 --- /dev/null +++ b/examples/graphql-dataloader/graphql_dataloader.server.out @@ -0,0 +1,2 @@ +$ bal run graphql_dataloader.bal +time = 2023-08-08T13:58:40.479+05:30 level = INFO module = "" message = "executing bookLoaderFunction" keys = [1,2] diff --git a/examples/graphql-field-interceptors/graphql_field_interceptors.md b/examples/graphql-field-interceptors/graphql_field_interceptors.md index 3a84260756..0677296c23 100644 --- a/examples/graphql-field-interceptors/graphql_field_interceptors.md +++ b/examples/graphql-field-interceptors/graphql_field_interceptors.md @@ -22,4 +22,4 @@ To send the document, execute the following cURL command in a separate terminal. ## Related links - [`graphql:Interceptor` object - API documentation](https://lib.ballerina.io/ballerina/graphql/latest#Interceptor) -- [GraphQL interceptors - Specification](/spec/graphql/#11-interceptors) +- [GraphQL field interceptors - Specification](/spec/graphql/#10332-field-interceptors) diff --git a/examples/graphql-file-upload/graphql_file_upload.md b/examples/graphql-file-upload/graphql_file_upload.md index f8024b3b7e..068bc0c291 100644 --- a/examples/graphql-file-upload/graphql_file_upload.md +++ b/examples/graphql-file-upload/graphql_file_upload.md @@ -25,4 +25,4 @@ This will create a directory `uploads` where the service is running, and then sa ## Related links - [`graphql:Upload` record - API documentation](https://lib.ballerina.io/ballerina/graphql/latest#Upload) - [GraphQL multipart request specification](https://github.com/jaydenseric/graphql-multipart-request-spec) -- [GraphQL file upload - Specification](/spec/graphql/#6-file-upload) +- [GraphQL file upload - Specification](/spec/graphql/#104-file-upload) diff --git a/examples/graphql-graphiql/graphql_graphiql.md b/examples/graphql-graphiql/graphql_graphiql.md index c3cbcd939e..18df839583 100644 --- a/examples/graphql-graphiql/graphql_graphiql.md +++ b/examples/graphql-graphiql/graphql_graphiql.md @@ -17,5 +17,5 @@ To access the GraphiQL client, open a browser and access `http://localhost:9090/ ## Related links - [`graphql:ServiceConfig` annotation - API documentation](https://lib.ballerina.io/ballerina/graphql/latest#ServiceConfig) - [`graphql:GraphiQL` record - API documentation](https://lib.ballerina.io/ballerina/graphql/latest#Graphiql) -- [GraphQL GraphiQL client - Configuration](/spec/graphql/#1015-graphiql-configurations) -- [GraphQL GraphiQL client - Specification](/spec/graphql/#141-graphiql-client) +- [GraphQL GraphiQL client - Specification](/spec/graphql/#91-graphiql-client) +- [GraphQL GraphiQL client configuration - Specification](/spec/graphql/#715-graphiql-configurations) diff --git a/examples/graphql-input-constraint-validation/graphql_input_constraint_validation.bal b/examples/graphql-input-constraint-validation/graphql_input_constraint_validation.bal new file mode 100644 index 0000000000..930061a1a6 --- /dev/null +++ b/examples/graphql-input-constraint-validation/graphql_input_constraint_validation.bal @@ -0,0 +1,27 @@ +import ballerina/constraint; +import ballerina/graphql; + +public type Profile record {| + // Define constraints for the fields + @constraint:String { + maxLength: 5 + } + string name; + + @constraint:Int { + minValue: 0 + } + int age; + + @constraint:Float { + maxValue: 3.0 + } + float height; +|}; + +service /graphql on new graphql:Listener(9090) { + + resource function get name(Profile profile) returns string { + return profile.name; + } +} diff --git a/examples/graphql-input-constraint-validation/graphql_input_constraint_validation.client.out b/examples/graphql-input-constraint-validation/graphql_input_constraint_validation.client.out new file mode 100644 index 0000000000..0c599c451b --- /dev/null +++ b/examples/graphql-input-constraint-validation/graphql_input_constraint_validation.client.out @@ -0,0 +1,2 @@ +curl -X POST -H "Content-type: application/json" -d '{ "query": "query{ name(profile:{name:\"Harry Potter\", age: -4, height:6})}" }' 'http://localhost:9090/graphql' +{"errors":[{"message":"Input validation failed in the field \"name\": Validation failed for '$.age:minValue','$.height:maxValue','$.name:maxLength' constraint(s).", "locations":[{"line":1, "column":8}], "path":["name"]}], "data":null} diff --git a/examples/graphql-input-constraint-validation/graphql_input_constraint_validation.graphql b/examples/graphql-input-constraint-validation/graphql_input_constraint_validation.graphql new file mode 100644 index 0000000000..e6c451c715 --- /dev/null +++ b/examples/graphql-input-constraint-validation/graphql_input_constraint_validation.graphql @@ -0,0 +1,3 @@ +{ + name(profile: {name: "Harry Potter", age: -4, height: 6}) +} diff --git a/examples/graphql-input-constraint-validation/graphql_input_constraint_validation.md b/examples/graphql-input-constraint-validation/graphql_input_constraint_validation.md new file mode 100644 index 0000000000..7e3334d31c --- /dev/null +++ b/examples/graphql-input-constraint-validation/graphql_input_constraint_validation.md @@ -0,0 +1,25 @@ +# GraphQL service - Input constraint validation + +GraphQL input constraint validation allows you to define and enforce constraints on input arguments. These constraints ensure that the provided input values meet certain criteria before they are processed. The input constraints can be configured using the `@constraint` annotation provided by the Ballerina constraint package. The constraint validation can be enabled or disabled using the `validation` field in the `graphql:ServiceConfig`. By default, the validation field is set to `true`. + +::: code graphql_input_constraint_validation.bal ::: + +Run the service by executing the following command. + +::: out graphql_input_constraint_validation.server.out ::: + +Send the following document to the GraphQL endpoint to test the service. + +::: code graphql_input_constraint_validation.graphql ::: + +To send the document, execute the following cURL command in a separate terminal. + +::: out graphql_input_constraint_validation.client.out ::: + +>**Tip:** You can invoke the above service via the [GraphQL client](/learn/by-example/graphql-client-query-endpoint/). + +## Related links +- [Constraint annotation - API documentation](https://lib.ballerina.io/ballerina/constraint/latest#Annotations) +- [GraphQL constraint config - Specification](/spec/graphql/#718-constraint-configurations) +- [`constraint` module - API documentation](https://lib.ballerina.io/ballerina/constraint/latest) +- [`graphql` module - API documentation](https://lib.ballerina.io/ballerina/graphql/latest) diff --git a/examples/graphql-input-constraint-validation/graphql_input_constraint_validation.metatags b/examples/graphql-input-constraint-validation/graphql_input_constraint_validation.metatags new file mode 100644 index 0000000000..91702e62da --- /dev/null +++ b/examples/graphql-input-constraint-validation/graphql_input_constraint_validation.metatags @@ -0,0 +1,2 @@ +description: A GraphQL service endpoint written in Ballerina. +keywords: ballerina, ballerina by example, bbe, graphql, graphql input constraint validation, graphql constraint validation diff --git a/examples/graphql-input-constraint-validation/graphql_input_constraint_validation.server.out b/examples/graphql-input-constraint-validation/graphql_input_constraint_validation.server.out new file mode 100644 index 0000000000..a817f59c0e --- /dev/null +++ b/examples/graphql-input-constraint-validation/graphql_input_constraint_validation.server.out @@ -0,0 +1 @@ +$ bal run graphql_input_constraint_validation.bal diff --git a/examples/graphql-interceptor-configurations/graphql_interceptor_configurations.md b/examples/graphql-interceptor-configurations/graphql_interceptor_configurations.md index 8be707e01f..2b6508c842 100644 --- a/examples/graphql-interceptor-configurations/graphql_interceptor_configurations.md +++ b/examples/graphql-interceptor-configurations/graphql_interceptor_configurations.md @@ -25,4 +25,5 @@ To send the document, execute the following cURL command in a separate terminal. ## Related links - [`graphql:InterceptorConfig` annotation - API documentation](https://lib.ballerina.io/ballerina/graphql/latest#InterceptorConfig) -- [GraphQL interceptors - Specification](/spec/graphql/#11-interceptors) +- [GraphQL interceptor configuration - Specification](/spec/graphql/#73-interceptor-configuration) +- [GraphQL interceptors - Specification](/spec/graphql/#103-interceptors) diff --git a/examples/graphql-service-basic-auth-file-user-store/graphql_service_basic_auth_file_user_store.md b/examples/graphql-service-basic-auth-file-user-store/graphql_service_basic_auth_file_user_store.md index 83cb181695..a327c62154 100644 --- a/examples/graphql-service-basic-auth-file-user-store/graphql_service_basic_auth_file_user_store.md +++ b/examples/graphql-service-basic-auth-file-user-store/graphql_service_basic_auth_file_user_store.md @@ -20,4 +20,4 @@ Run the service by executing the command below. - [`graphql:ServiceConfig` annotation - API documentation](https://lib.ballerina.io/ballerina/graphql/latest#ServiceConfig) - [`graphql:FileUserStoreConfigWithScopes` record - API documentation](https://lib.ballerina.io/ballerina/graphql/latest#FileUserStoreConfigWithScopes) - [`auth` module - API documentation](https://lib.ballerina.io/ballerina/auth/latest/) -- [GraphQL service basic authentication - file user store - Specification](/spec/graphql/#12111-basic-authentication---file-user-store) +- [GraphQL service basic authentication - file user store - Specification](/spec/graphql/#8111-basic-authentication---file-user-store) diff --git a/examples/graphql-service-basic-auth-ldap-user-store/graphql_service_basic_auth_ldap_user_store.md b/examples/graphql-service-basic-auth-ldap-user-store/graphql_service_basic_auth_ldap_user_store.md index dec50f0e3c..2eba39022a 100644 --- a/examples/graphql-service-basic-auth-ldap-user-store/graphql_service_basic_auth_ldap_user_store.md +++ b/examples/graphql-service-basic-auth-ldap-user-store/graphql_service_basic_auth_ldap_user_store.md @@ -19,4 +19,4 @@ Run the service by executing the command below. - [`graphql:ServiceConfig` annotation - API documentation](https://lib.ballerina.io/ballerina/graphql/latest#ServiceConfig) - [`graphql:LdapUserStoreConfigWithScopes` record - API documentation](https://lib.ballerina.io/ballerina/graphql/latest#LdapUserStoreConfigWithScopes) - [`auth` module - API documentation](https://lib.ballerina.io/ballerina/auth/latest/) -- [GraphQL service basic authentication - LDAP user store - Specification](/spec/graphql/#12112-basic-authentication---ldap-user-store) +- [GraphQL service basic authentication - LDAP user store - Specification](/spec/graphql/#8112-basic-authentication---ldap-user-store) diff --git a/examples/graphql-service-error-handling/graphql_service_error_handling.md b/examples/graphql-service-error-handling/graphql_service_error_handling.md index 06b8962b77..286f95a277 100644 --- a/examples/graphql-service-error-handling/graphql_service_error_handling.md +++ b/examples/graphql-service-error-handling/graphql_service_error_handling.md @@ -32,4 +32,4 @@ Check the response to see how the `data` field is set to null due to propagating ## Related links - [`graphql` module - API documentation](https://lib.ballerina.io/ballerina/graphql/latest) -- [GraphQL error handling - Specification](/spec/graphql/#72-service-error-handling) +- [GraphQL error handling - Specification](/spec/graphql/#62-service-error-handling) diff --git a/examples/graphql-service-field-object/graphql_service_field_object.md b/examples/graphql-service-field-object/graphql_service_field_object.md index 8b7fce5754..434a5cfbd9 100644 --- a/examples/graphql-service-field-object/graphql_service_field_object.md +++ b/examples/graphql-service-field-object/graphql_service_field_object.md @@ -41,4 +41,4 @@ This will print a log message in the server terminal similar to the following lo ## Related links - [`graphql:Field` object - API documentation](https://lib.ballerina.io/ballerina/graphql/latest#Field) -- [GraphQL field - Specification](/spec/graphql/#9-field-object) +- [GraphQL field - Specification](/spec/graphql/#102-field-object) diff --git a/examples/graphql-service-interceptors/graphql_service_interceptors.md b/examples/graphql-service-interceptors/graphql_service_interceptors.md index dc1b207bbc..34f7aab36e 100644 --- a/examples/graphql-service-interceptors/graphql_service_interceptors.md +++ b/examples/graphql-service-interceptors/graphql_service_interceptors.md @@ -22,4 +22,4 @@ To send the document, execute the following cURL command in a separate terminal. ## Related links - [`graphql:Interceptor` object - API documentation](https://lib.ballerina.io/ballerina/graphql/latest#Interceptor) -- [GraphQL interceptors - Specification](/spec/graphql/#11-interceptors) +- [GraphQL service interceptors - Specification](/spec/graphql/#10331-service-interceptors) diff --git a/examples/graphql-service-jwt-auth/graphql_service_jwt_auth.md b/examples/graphql-service-jwt-auth/graphql_service_jwt_auth.md index 2628d12ebe..afc068d380 100644 --- a/examples/graphql-service-jwt-auth/graphql_service_jwt_auth.md +++ b/examples/graphql-service-jwt-auth/graphql_service_jwt_auth.md @@ -14,4 +14,4 @@ Run the service by executing the command below. - [`graphql:ServiceConfig` annotation - API documentation](https://lib.ballerina.io/ballerina/graphql/latest#ServiceConfig) - [`graphql:JwtValidatorConfigWithScopes` record - API documentation](https://lib.ballerina.io/ballerina/graphql/latest#JwtValidatorConfigWithScopes) - [`jwt` module - API documentation](https://lib.ballerina.io/ballerina/jwt/latest/) -- [GraphQL service JWT authentication - Specification](/spec/graphql/#12113-jwt-authentication) +- [GraphQL service JWT authentication - Specification](/spec/graphql/#8113-jwt-authentication) diff --git a/examples/graphql-service-mutual-ssl/graphql_service_mutual_ssl.md b/examples/graphql-service-mutual-ssl/graphql_service_mutual_ssl.md index d5f3d2b557..4a4fcfc646 100644 --- a/examples/graphql-service-mutual-ssl/graphql_service_mutual_ssl.md +++ b/examples/graphql-service-mutual-ssl/graphql_service_mutual_ssl.md @@ -13,4 +13,4 @@ Run the service by executing the command below. ## Related links - [`graphql:ListenerConfiguration` record - API documentation](https://lib.ballerina.io/ballerina/graphql/latest#ListenerConfiguration) - [`graphql:ListenerSecureSocket` record - API documentation](https://lib.ballerina.io/ballerina/graphql/latest#ListenerSecureSocket) -- [GraphQL service mutual SSL - Specification](/spec/graphql/#12312-mutual-ssl) +- [GraphQL service mutual SSL - Specification](/spec/graphql/#8312-mutual-ssl) diff --git a/examples/graphql-service-oauth2/graphql_service_oauth2.md b/examples/graphql-service-oauth2/graphql_service_oauth2.md index c44981e0a8..7c95fb0740 100644 --- a/examples/graphql-service-oauth2/graphql_service_oauth2.md +++ b/examples/graphql-service-oauth2/graphql_service_oauth2.md @@ -17,4 +17,4 @@ Run the service by executing the command below. - [`graphql:ServiceConfig` annotation - API documentation](https://lib.ballerina.io/ballerina/graphql/latest#ServiceConfig) - [`graphql:OAuth2IntrospectionConfigWithScopes` record - API documentation](https://lib.ballerina.io/ballerina/graphql/latest#OAuth2IntrospectionConfigWithScopes) - [`oauth2` module - API documentation](https://lib.ballerina.io/ballerina/oauth2/latest/) -- [GraphQL service OAuth2 - Specification](/spec/graphql/#12114-oauth2) +- [GraphQL service OAuth2 - Specification](/spec/graphql/#8114-oauth2) diff --git a/examples/graphql-service-ssl-tls/graphql_service_ssl_tls.md b/examples/graphql-service-ssl-tls/graphql_service_ssl_tls.md index 465c6812ac..6c4c2a9363 100644 --- a/examples/graphql-service-ssl-tls/graphql_service_ssl_tls.md +++ b/examples/graphql-service-ssl-tls/graphql_service_ssl_tls.md @@ -13,4 +13,4 @@ Run the service by executing the command below. ## Related links - [`graphql:ListenerConfiguration` record - API documentation](https://lib.ballerina.io/ballerina/graphql/latest#ListenerConfiguration) - [`graphql:ListenerSecureSocket` record - API documentation](https://lib.ballerina.io/ballerina/graphql/latest#ListenerSecureSocket) -- [GraphQL service SSL/TLS - Specification](/spec/graphql/#12311-ssltls) +- [GraphQL service SSL/TLS - Specification](/spec/graphql/#8311-ssltls) diff --git a/examples/grpc-client-bidirectional-streaming/grpc_bidirectional_streaming.md b/examples/grpc-client-bidirectional-streaming/grpc_bidirectional_streaming.md index 1d8a602e4c..7ad7620b0a 100644 --- a/examples/grpc-client-bidirectional-streaming/grpc_bidirectional_streaming.md +++ b/examples/grpc-client-bidirectional-streaming/grpc_bidirectional_streaming.md @@ -34,4 +34,4 @@ Once you run the command, the `grpc_bidirectional_streaming_pb.bal` file gets ge ## Related links - [`grpc` module - API documentation](https://lib.ballerina.io/ballerina/grpc/latest) - [gRPC client bidirectional streaming - Specification](/spec/grpc/#44-bidirectional-streaming-rpc) -- [Ballerina protocol buffers guide](/learn/cli-documentation/grpc/) \ No newline at end of file +- [gRPC tool](/learn/grpc-tool/) \ No newline at end of file diff --git a/examples/grpc-client-client-streaming/grpc_client_streaming.md b/examples/grpc-client-client-streaming/grpc_client_streaming.md index 430e050b57..e89c182648 100644 --- a/examples/grpc-client-client-streaming/grpc_client_streaming.md +++ b/examples/grpc-client-client-streaming/grpc_client_streaming.md @@ -34,4 +34,4 @@ Once you run the command, the `grpc_client_streaming_pb.bal` file gets generated ## Related links - [`grpc` module - API documentation](https://lib.ballerina.io/ballerina/grpc/latest) - [gRPC client client-side streaming - Specification](/spec/grpc/#43-client-streaming-rpc) -- [Ballerina protocol buffers guide](/learn/cli-documentation/grpc/) +- [gRPC tool](/learn/grpc-tool/) diff --git a/examples/grpc-client-server-streaming/grpc_server_streaming.md b/examples/grpc-client-server-streaming/grpc_server_streaming.md index befd47d949..619da71a49 100644 --- a/examples/grpc-client-server-streaming/grpc_server_streaming.md +++ b/examples/grpc-client-server-streaming/grpc_server_streaming.md @@ -34,4 +34,4 @@ Once you run the command, the `grpc_server_streaming_pb.bal` file gets generated ## Related links - [`grpc` module - API documentation](https://lib.ballerina.io/ballerina/grpc/latest) - [gRPC client server-side streaming - Specification](/spec/grpc/#42-server-streaming-rpc) -- [Ballerina protocol buffers guide](/learn/cli-documentation/grpc/) +- [gRPC tool](/learn/grpc-tool/) diff --git a/examples/grpc-client-simple/grpc_client_simple.md b/examples/grpc-client-simple/grpc_client_simple.md index 086fbc0d58..7630e83605 100644 --- a/examples/grpc-client-simple/grpc_client_simple.md +++ b/examples/grpc-client-simple/grpc_client_simple.md @@ -34,4 +34,4 @@ Once you run the command, the `grpc_simple_pb.bal` file gets generated inside th ## Related links - [`grpc` module - API documentation](https://lib.ballerina.io/ballerina/grpc/latest) - [gRPC client simple RPC - Specification](/spec/grpc/#41-simple-rpc) -- [Ballerina protocol buffers guide](/learn/cli-documentation/grpc/) +- [gRPC tool](/learn/grpc-tool/) diff --git a/examples/grpc-service-bidirectional-streaming/grpc_bidirectional_streaming.md b/examples/grpc-service-bidirectional-streaming/grpc_bidirectional_streaming.md index 2a80fd1581..af151011a8 100644 --- a/examples/grpc-service-bidirectional-streaming/grpc_bidirectional_streaming.md +++ b/examples/grpc-service-bidirectional-streaming/grpc_bidirectional_streaming.md @@ -33,4 +33,4 @@ Once you run the command, the `grpc_bidirectional_streaming_pb.bal` file gets ge ## Related links - [`grpc` module - API documentation](https://lib.ballerina.io/ballerina/grpc/latest) - [gRPC service bidirectional streaming - Specification](/spec/grpc/#44-bidirectional-streaming-rpc) -- [Ballerina protocol buffers guide](/learn/cli-documentation/grpc/) +- [gRPC tool](/learn/grpc-tool/) diff --git a/examples/grpc-service-client-streaming/grpc_client_streaming.md b/examples/grpc-service-client-streaming/grpc_client_streaming.md index 75c0a43239..1f089c726a 100644 --- a/examples/grpc-service-client-streaming/grpc_client_streaming.md +++ b/examples/grpc-service-client-streaming/grpc_client_streaming.md @@ -33,4 +33,4 @@ Once you run the command, the `grpc_client_streaming_pb.bal` file gets generated ## Related links - [`grpc` module - API documentation](https://lib.ballerina.io/ballerina/grpc/latest) - [gRPC service client-side streaming - Specification](/spec/grpc/#43-client-streaming-rpc) -- [Ballerina protocol buffers guide](/learn/cli-documentation/grpc/) +- [gRPC tool](/learn/grpc-tool/) diff --git a/examples/grpc-service-server-streaming/grpc_server_streaming.md b/examples/grpc-service-server-streaming/grpc_server_streaming.md index ccfda13832..4a7cccddbf 100644 --- a/examples/grpc-service-server-streaming/grpc_server_streaming.md +++ b/examples/grpc-service-server-streaming/grpc_server_streaming.md @@ -33,4 +33,4 @@ Once you run the command, the `grpc_server_streaming_pb.bal` file gets generated ## Related links - [`grpc` module - API documentation](https://lib.ballerina.io/ballerina/grpc/latest) - [gRPC service server-side streaming - Specification](/spec/grpc/#42-server-streaming-rpc) -- [Ballerina protocol buffers guide](/learn/cli-documentation/grpc/) +- [gRPC tool](/learn/grpc-tool/) diff --git a/examples/grpc-service-simple/grpc_service_simple.md b/examples/grpc-service-simple/grpc_service_simple.md index aa1a73f85d..8f29bdf927 100644 --- a/examples/grpc-service-simple/grpc_service_simple.md +++ b/examples/grpc-service-simple/grpc_service_simple.md @@ -33,4 +33,4 @@ Once you run the command, the `grpc_simple_pb.bal` file gets generated inside th ## Related links - [`grpc` module - API documentation](https://lib.ballerina.io/ballerina/grpc/latest) - [gRPC service simple RPC - Specification](/spec/grpc/#41-simple-rpc) -- [Ballerina protocol buffers guide](/learn/cli-documentation/grpc/) +- [gRPC tool](/learn/grpc-tool/) diff --git a/examples/http-default-error-handling/http_default_error_handling.client.out b/examples/http-default-error-handling/http_default_error_handling.client.out index 1573d84d28..bf4aa1feec 100644 --- a/examples/http-default-error-handling/http_default_error_handling.client.out +++ b/examples/http-default-error-handling/http_default_error_handling.client.out @@ -1,17 +1,18 @@ $ curl -v localhost:9090/artist -* Trying ::1... +* Trying 127.0.0.1:9090... * TCP_NODELAY set -* Connected to localhost (::1) port 9090 (#0) +* Connected to localhost (127.0.0.1) port 9090 (#0) > GET /artist HTTP/1.1 > Host: localhost:9090 -> User-Agent: curl/7.64.1 +> User-Agent: curl/7.68.0 > Accept: */* -> +> +* Mark bundle as not supporting multiuse < HTTP/1.1 502 Bad Gateway -< content-type: text/plain -< content-length: 35 +< content-type: application/json +< content-length: 210 < server: ballerina -< date: Wed, 21 Dec 2022 13:30:30 +0530 -< +< date: Fri, 16 Jun 2023 10:40:52 +0530 +< * Connection #0 to host localhost left intact -Something wrong with the connection +{"timestamp":"2023-06-16T05:10:52.220224Z", "status":502, "reason":"Bad Gateway", "message":"Something wrong with the connection: Connection refused: localhost/127.0.0.1:9091", "path":"/artist", "method":"GET"} diff --git a/examples/http-error-handling/http_error_handling.bal b/examples/http-error-handling/http_error_handling.bal index 0eb5ce3132..46aabece0e 100644 --- a/examples/http-error-handling/http_error_handling.bal +++ b/examples/http-error-handling/http_error_handling.bal @@ -28,20 +28,17 @@ service class ResponseErrorInterceptor { } } -// Creates a new `ResponseErrorInterceptor`. -ResponseErrorInterceptor responseErrorInterceptor = new; - -// A `ResponseErrorInterceptor` can be configured at the listener level or -// service level. Listener-level error interceptors can handle any error associated -// with the listener, whereas, service-level error interceptors can only handle -// errors occurred during the service execution. -listener http:Listener interceptorListener = new (9090, - // To handle all of the errors, the `ResponseErrorInterceptor` is added as a first - // interceptor as it has to be executed last. - interceptors = [responseErrorInterceptor] -); - -service / on interceptorListener { +// Engage interceptors at the service level using an `http:InterceptableService`. The base path of the +// interceptor services is the same as the target service. Hence, they will be executed only for +// this particular service. +service http:InterceptableService / on new http:Listener(9090) { + + // Service-level error interceptors can handle errors occurred during the service execution. + public function createInterceptors() returns ResponseErrorInterceptor { + // To handle all of the errors, the `ResponseErrorInterceptor` is added as a first + // interceptor as it has to be executed last. + return new ResponseErrorInterceptor(); + } // If the request does not have an`x-api-version` header, then an error will be returned // and the execution will jump to the nearest `ResponseErrorInterceptor`. diff --git a/examples/http-interceptor-error-handling/http_interceptor_error_handling.bal b/examples/http-interceptor-error-handling/http_interceptor_error_handling.bal index a34847b662..b0692aa796 100644 --- a/examples/http-interceptor-error-handling/http_interceptor_error_handling.bal +++ b/examples/http-interceptor-error-handling/http_interceptor_error_handling.bal @@ -27,8 +27,6 @@ service class RequestInterceptor { } } -RequestInterceptor requestInterceptor = new; - // A `RequestErrorInterceptor` service class implementation. It allows intercepting // the error that occurred in the request path and handle it accordingly. // A `RequestErrorInterceptor` service class can have only one resource function. @@ -50,16 +48,13 @@ service class RequestErrorInterceptor { } } -// Creates a new `RequestErrorInterceptor`. -RequestErrorInterceptor requestErrorInterceptor = new; - -listener http:Listener interceptorListener = new (9090, - // To handle all of the errors in the request path, the `RequestErrorInterceptor` - // is added as the last interceptor as it has to be executed last. - interceptors = [requestInterceptor, requestErrorInterceptor] -); +service http:InterceptableService / on new http:Listener(9090) { -service / on interceptorListener { + public function createInterceptors() returns [RequestInterceptor, RequestErrorInterceptor] { + // To handle all of the errors in the request path, the `RequestErrorInterceptor` + // is added as the last interceptor as it has to be executed last. + return [new RequestInterceptor(), new RequestErrorInterceptor()]; + } resource function get albums() returns Album[] { return albums.toArray(); diff --git a/examples/http-request-interceptor/http_request_interceptor.bal b/examples/http-request-interceptor/http_request_interceptor.bal index 48a04b2f81..3eed636610 100644 --- a/examples/http-request-interceptor/http_request_interceptor.bal +++ b/examples/http-request-interceptor/http_request_interceptor.bal @@ -34,19 +34,17 @@ service class RequestInterceptor { } } -// Interceptors can also be engaged at the listener level. In this case, the `RequestInterceptors` -// can have only the default path. -listener http:Listener interceptorListener = new (9090); +// Engage interceptors at the service level using an `http:InterceptableService`. The interceptors +// will inherit the basepath of the service. +service http:InterceptableService / on new http:Listener(9090) { -// Engage interceptors at the service level using `http:InterceptableService`. The base path of the -// interceptor services is the same as the target service. Hence, they will be executed only for -// this particular service. -service http:InterceptableService / on interceptorListener { - - // Creates the interceptor pipeline. The function can return a single interceptor or an array of interceptors as the interceptor pipeline. If the interceptor pipeline is an array, then the request interceptor services will be executed from head to tail. + // Creates the interceptor pipeline. The function can return a single interceptor or an array of + // interceptors as the interceptor pipeline. If the interceptor pipeline is an array, then, the + // request interceptor services will be executed from head to tail. public function createInterceptors() returns RequestInterceptor { return new RequestInterceptor(); } + resource function get albums() returns Album[] { return albums.toArray(); } diff --git a/examples/http-request-interceptor/http_request_interceptor.md b/examples/http-request-interceptor/http_request_interceptor.md index 0206b17786..8c7da965c9 100644 --- a/examples/http-request-interceptor/http_request_interceptor.md +++ b/examples/http-request-interceptor/http_request_interceptor.md @@ -2,9 +2,9 @@ The `http:RequestInterceptor` is used to intercept the request and execute custom logic. A `RequestInterceptor` is a service object with only one resource method, which is executed before dispatching the request to the actual resource in the target service. This resource method can have parameters just like a usual resource method in an `http:Service`. -A `RequestInterceptor` can be created from a service class, which includes the `http:RequestInterceptor` service type. Then, this service object can be engaged at the listener level by using the `interceptors` field in the `http:ListenerConfiguration` or at the service level by declaring a `http:InterceptableService` object. +A `RequestInterceptor` can be created from a service class, which includes the `http:RequestInterceptor` service type. Then, this service object can be engaged at the service level by declaring an `http:InterceptableService` object. -These accept an interceptor service object or an array of interceptor service objects as an interceptor pipeline, and the interceptors are executed in the order in which they are placed in the pipeline. Use `RequestInterceptors` to execute common logic such as logging, header manipulation, state publishing, etc., for inbound requests. +This accepts an interceptor service object or an array of interceptor service objects as an interceptor pipeline, and the interceptors are executed in the order in which they are placed in the pipeline. Use `RequestInterceptors` to execute common logic such as logging, header manipulation, state publishing, etc., for inbound requests. ::: code http_request_interceptor.bal ::: diff --git a/examples/http-response-interceptor/http_response_interceptor.bal b/examples/http-response-interceptor/http_response_interceptor.bal index bb75cbd089..a93d154470 100644 --- a/examples/http-response-interceptor/http_response_interceptor.bal +++ b/examples/http-response-interceptor/http_response_interceptor.bal @@ -29,14 +29,17 @@ service class ResponseInterceptor { } } -// Engage interceptors at the listener level. Response interceptor services will be executed from -// tail to head. -listener http:Listener interceptorListener = new (9090, - // This interceptor pipeline will be executed for all of the services attached to this listener. - interceptors = [new ResponseInterceptor()] -); +// Engage interceptors at the service level using an `http:InterceptableService`. The base path of the +// interceptor services is the same as the target service. Hence, they will be executed only for +// this particular service. +service http:InterceptableService / on new http:Listener(9090) { -service / on interceptorListener { + // Creates the interceptor pipeline. The function can return a single interceptor or an array of + // interceptors as the interceptor pipeline. If the interceptor pipeline is an array, then, the + // request interceptor services will be executed from head to tail. + public function createInterceptors() returns ResponseInterceptor { + return new ResponseInterceptor(); + } resource function get albums() returns Album[] { return albums.toArray(); diff --git a/examples/http-response-interceptor/http_response_interceptor.md b/examples/http-response-interceptor/http_response_interceptor.md index b4e1f56d48..eaa804f2db 100644 --- a/examples/http-response-interceptor/http_response_interceptor.md +++ b/examples/http-response-interceptor/http_response_interceptor.md @@ -2,7 +2,7 @@ The `http:ResponseInterceptor` is used to intercept the response and execute custom logic. A `ResponseInterceptor` is a service object with a remote method called `interceptResponse`, which is executed before dispatching the response to the client. A `ResponseInterceptor` can be created from a service class, which includes the `http:ResponseInterceptor` service type. -This service object can be engaged at the listener level by using the `interceptors` field in the `http:ListenerConfiguration` or at the service level by declaring a `http:InterceptableService` object. These accept an interceptor service object or an array of interceptor service objects as an interceptor pipeline and the interceptors are executed in the order in which they are placed in the pipeline. +This service object can be engaged at the service level by declaring an `http:InterceptableService` object. This accepts an interceptor service object or an array of interceptor service objects as an interceptor pipeline and the interceptors are executed in the order in which they are placed in the pipeline. Use `ResponseInterceptors` to execute common logic such as logging, header manipulation, state publishing, etc., for all outbound responses. diff --git a/examples/http-service-payload-constraint-validation/tests/http_service_payload_constraint_validation.bal b/examples/http-service-payload-constraint-validation/tests/http_service_payload_constraint_validation.bal index b138afd6ee..8fdd098c58 100644 --- a/examples/http-service-payload-constraint-validation/tests/http_service_payload_constraint_validation.bal +++ b/examples/http-service-payload-constraint-validation/tests/http_service_payload_constraint_validation.bal @@ -7,7 +7,12 @@ function testFunc() returns error? { Album|error response = httpEndpoint->post("/albums", {title:"Sarah Vaughan and Clifford Brown", artist:"Sarah Vaughan"}); if response is http:Error { test:assertEquals(response.detail()["statusCode"], 400); - test:assertEquals(response.detail()["body"], "payload validation failed: Validation failed for '$.title:maxLength' constraint(s)."); + http:ErrorPayload errorResponse = check response.detail()["body"].ensureType(); + test:assertEquals(errorResponse.message, "payload validation failed: Validation failed for '$.title:maxLength' constraint(s)."); + test:assertEquals(errorResponse.status, 400); + test:assertEquals(errorResponse.reason, "Bad Request"); + test:assertEquals(errorResponse.path, "/albums"); + test:assertEquals(errorResponse.method, "POST"); } else { test:assertFail("Expected an error"); } diff --git a/examples/index.json b/examples/index.json index 2a2f1b97b7..7c75165f49 100644 --- a/examples/index.json +++ b/examples/index.json @@ -932,6 +932,13 @@ "verifyBuild": true, "verifyOutput": true, "isLearnByExample": true + }, + { + "name": "Aggregation", + "url": "aggregation", + "verifyBuild": true, + "verifyOutput": true, + "isLearnByExample": true } ] }, @@ -2459,6 +2466,14 @@ "disablePlayground": true, "isLearnByExample": false }, + { + "name": "Input constraint validation", + "url": "graphql-input-constraint-validation", + "verifyBuild": true, + "verifyOutput": false, + "disablePlayground": true, + "isLearnByExample": false + }, { "name": "File upload", "url": "graphql-file-upload", @@ -2478,6 +2493,29 @@ } ] }, + { + "title": " GraphQL service advanced", + "column": 1, + "category": "Network libraries", + "samples": [ + { + "name": "Dataloader", + "url": "graphql-dataloader", + "verifyBuild": true, + "verifyOutput": false, + "disablePlayground": true, + "isLearnByExample": false + }, + { + "name": "Custom prefetch methods", + "url": "custom-prefetch-methods", + "verifyBuild": true, + "verifyOutput": false, + "disablePlayground": true, + "isLearnByExample": false + } + ] + }, { "title": "GraphQL client", "column": 1, @@ -3152,13 +3190,22 @@ "isLearnByExample": false }, { - "name": "Constraint validation", + "name": "Constraint validations", "url": "nats-service-constraint-validation", "verifyBuild": false, "verifyOutput": false, "disableVerificationReason": "Includes ballerinax components", "disablePlayground": true, "isLearnByExample": false + }, + { + "name": "Consume JetStream message", + "url": "nats-jetstream-sub", + "verifyBuild": false, + "verifyOutput": false, + "disableVerificationReason": "Includes ballerinax components", + "disablePlayground": true, + "isLearnByExample": false } ] }, @@ -3184,6 +3231,15 @@ "disableVerificationReason": "Includes ballerinax components", "disablePlayground": true, "isLearnByExample": false + }, + { + "name": "Publish message", + "url": "nats-jetstream-pub", + "verifyBuild": false, + "verifyOutput": false, + "disableVerificationReason": "Includes ballerinax components", + "disablePlayground": true, + "isLearnByExample": false } ] }, @@ -3945,7 +4001,7 @@ { "name": "Cryptographic operations", "url": "security-crypto", - "verifyBuild": true, + "verifyBuild": false, "verifyOutput": false, "disablePlayground": true, "isLearnByExample": false @@ -4058,6 +4114,29 @@ } ] }, + { + "title": "EDI", + "column": 1, + "category": "Common libraries", + "samples": [ + { + "name": "EDI to record conversion", + "url": "edi-to-record", + "verifyBuild": false, + "verifyOutput": false, + "disableVerificationReason": "Includes generated code", + "isLearnByExample": false + }, + { + "name": "Record to EDI conversion", + "url": "record-to-edi", + "verifyBuild": false, + "verifyOutput": false, + "disableVerificationReason": "Includes generated code", + "isLearnByExample": false + } + ] + }, { "title": "File", "column": 2, @@ -4185,20 +4264,6 @@ } ] }, - { - "title": "Regex", - "column": 3, - "category": "Common libraries", - "samples": [ - { - "name": "Regular expressions", - "url": "regular-expressions", - "verifyBuild": true, - "verifyOutput": true, - "isLearnByExample": false - } - ] - }, { "title": "OS", "column": 3, @@ -4389,55 +4454,5 @@ "isLearnByExample": false } ] - }, - { - "title": "Code to Cloud", - "column": 0, - "category": "Deployment", - "samples": [ - { - "name": "Docker", - "url": "c2c-docker-deployment", - "verifyBuild": true, - "verifyOutput": false, - "disableVerificationReason": "Needs prerequisite condition", - "disablePlayground": true, - "isLearnByExample": false - }, - { - "name": "Kubernetes", - "url": "c2c-k8s-deployment", - "verifyBuild": true, - "verifyOutput": false, - "disableVerificationReason": "Needs prerequisite condition", - "disablePlayground": true, - "isLearnByExample": false - } - ] - }, - { - "title": "Function as a Service", - "column": 1, - "category": "Deployment", - "samples": [ - { - "name": "Azure Functions", - "url": "azure-functions-deployment", - "verifyBuild": false, - "verifyOutput": false, - "disableVerificationReason": "Needs prerequisite condition", - "disablePlayground": true, - "isLearnByExample": false - }, - { - "name": "AWS Lambda", - "url": "aws-lambda-deployment", - "verifyBuild": false, - "verifyOutput": false, - "disableVerificationReason": "Needs prerequisite condition", - "disablePlayground": true, - "isLearnByExample": false - } - ] } ] diff --git a/examples/kafka-consumer-constraint-validation/kafka_consumer_constraint_validation.bal b/examples/kafka-consumer-constraint-validation/kafka_consumer_constraint_validation.bal index a9eb5a1919..61a9e01cfa 100755 --- a/examples/kafka-consumer-constraint-validation/kafka_consumer_constraint_validation.bal +++ b/examples/kafka-consumer-constraint-validation/kafka_consumer_constraint_validation.bal @@ -2,7 +2,7 @@ import ballerina/constraint; import ballerinax/kafka; import ballerina/io; -public type Order record { +type Order record { int orderId; // Add a constraint to only allow string values of length between 30 and 1. @constraint:String {maxLength: 30, minLength: 1} @@ -19,7 +19,7 @@ public function main() returns error? { while true { Order[] orders = check orderConsumer->pollPayload(15); - check from Order 'order in orders + from Order 'order in orders where 'order.isValid do { io:println(string `Received valid order for ${'order.productName}`); diff --git a/examples/kafka-consumer-consumer-record-data-binding/kafka_consumer_consumer_record_data_binding.bal b/examples/kafka-consumer-consumer-record-data-binding/kafka_consumer_consumer_record_data_binding.bal index e370b96208..61ce07d232 100755 --- a/examples/kafka-consumer-consumer-record-data-binding/kafka_consumer_consumer_record_data_binding.bal +++ b/examples/kafka-consumer-consumer-record-data-binding/kafka_consumer_consumer_record_data_binding.bal @@ -1,7 +1,7 @@ import ballerinax/kafka; import ballerina/io; -public type Order readonly & record { +type Order readonly & record { int orderId; string productName; decimal price; @@ -9,7 +9,7 @@ public type Order readonly & record { }; // Create a subtype of `kafka:AnydataConsumerRecord`. -public type OrderConsumerRecord record {| +type OrderConsumerRecord record {| *kafka:AnydataConsumerRecord; Order value; |}; @@ -23,7 +23,7 @@ public function main() returns error? { while true { // Polls the consumer for order records. OrderConsumerRecord[] records = check orderConsumer->poll(15); - check from OrderConsumerRecord orderRecord in records + from OrderConsumerRecord orderRecord in records where orderRecord.value.isValid do { io:println(string `Received valid order for ${orderRecord.value.productName}`); diff --git a/examples/kafka-consumer-payload-data-binding/kafka_consumer_payload_data_binding.bal b/examples/kafka-consumer-payload-data-binding/kafka_consumer_payload_data_binding.bal index ff81399e3d..178fa839d4 100755 --- a/examples/kafka-consumer-payload-data-binding/kafka_consumer_payload_data_binding.bal +++ b/examples/kafka-consumer-payload-data-binding/kafka_consumer_payload_data_binding.bal @@ -1,7 +1,7 @@ import ballerinax/kafka; import ballerina/io; -public type Order readonly & record { +type Order readonly & record { int orderId; string productName; decimal price; @@ -17,7 +17,7 @@ public function main() returns error? { while true { // Polls the consumer for payload. Order[] orders = check orderConsumer->pollPayload(15); - check from Order 'order in orders + from Order 'order in orders where 'order.isValid do { io:println(string `Received valid order for ${'order.productName}`); diff --git a/examples/kafka-consumer-sasl/kafka_consumer_sasl.bal b/examples/kafka-consumer-sasl/kafka_consumer_sasl.bal index f7bf2d4acc..0cc9f6ec24 100644 --- a/examples/kafka-consumer-sasl/kafka_consumer_sasl.bal +++ b/examples/kafka-consumer-sasl/kafka_consumer_sasl.bal @@ -1,7 +1,7 @@ import ballerinax/kafka; import ballerina/io; -public type Order readonly & record { +type Order readonly & record { int orderId; string productName; decimal price; @@ -27,7 +27,7 @@ public function main() returns error? { // Polls the consumer for payload. Order[] orders = check orderConsumer->pollPayload(1); - check from Order 'order in orders + from Order 'order in orders where 'order.isValid do { io:println(string `Received valid order for ${'order.productName}`); diff --git a/examples/kafka-consumer-ssl/kafka_consumer_ssl.bal b/examples/kafka-consumer-ssl/kafka_consumer_ssl.bal index a087a425d8..4149a1b482 100644 --- a/examples/kafka-consumer-ssl/kafka_consumer_ssl.bal +++ b/examples/kafka-consumer-ssl/kafka_consumer_ssl.bal @@ -1,7 +1,7 @@ import ballerinax/kafka; import ballerina/io; -public type Order readonly & record { +type Order readonly & record { int orderId; string productName; decimal price; @@ -27,7 +27,7 @@ public function main() returns error? { // Polls the consumer for payload. Order[] orders = check orderConsumer->pollPayload(1); - check from Order 'order in orders + from Order 'order in orders where 'order.isValid do { io:println(string `Received valid order for ${'order.productName}`); diff --git a/examples/kafka-producer-produce-message/kafka_producer_produce_message.bal b/examples/kafka-producer-produce-message/kafka_producer_produce_message.bal index 852c954a36..32c4ca2d02 100755 --- a/examples/kafka-producer-produce-message/kafka_producer_produce_message.bal +++ b/examples/kafka-producer-produce-message/kafka_producer_produce_message.bal @@ -1,7 +1,7 @@ import ballerinax/kafka; import ballerina/http; -public type Order readonly & record { +type Order readonly & record { int orderId; string productName; decimal price; @@ -15,7 +15,7 @@ service / on new http:Listener(9090) { self.orderProducer = check new (kafka:DEFAULT_URL); } - resource function post orders(@http:Payload anydata newOrder) returns http:Accepted|error { + resource function post orders(Order newOrder) returns http:Accepted|error { check self.orderProducer->send({ topic: "order-topic", value: newOrder diff --git a/examples/kafka-producer-sasl/kafka_producer_sasl.bal b/examples/kafka-producer-sasl/kafka_producer_sasl.bal index 114d27c06e..b92f6d93d9 100644 --- a/examples/kafka-producer-sasl/kafka_producer_sasl.bal +++ b/examples/kafka-producer-sasl/kafka_producer_sasl.bal @@ -1,7 +1,7 @@ import ballerina/http; import ballerinax/kafka; -public type Order readonly & record { +type Order readonly & record { int orderId; string productName; decimal price; diff --git a/examples/kafka-producer-ssl/kafka_producer_ssl.bal b/examples/kafka-producer-ssl/kafka_producer_ssl.bal index 836c77df10..a31df975ee 100644 --- a/examples/kafka-producer-ssl/kafka_producer_ssl.bal +++ b/examples/kafka-producer-ssl/kafka_producer_ssl.bal @@ -1,7 +1,7 @@ import ballerina/http; import ballerinax/kafka; -public type Order readonly & record { +type Order readonly & record { int orderId; string productName; decimal price; diff --git a/examples/kafka-service-constraint-validation/kafka_service_constraint_validation.bal b/examples/kafka-service-constraint-validation/kafka_service_constraint_validation.bal index 8f3ee2187a..c9fcb0b800 100755 --- a/examples/kafka-service-constraint-validation/kafka_service_constraint_validation.bal +++ b/examples/kafka-service-constraint-validation/kafka_service_constraint_validation.bal @@ -2,7 +2,7 @@ import ballerina/constraint; import ballerinax/kafka; import ballerina/log; -public type Order record { +type Order record { int orderId; // Add a constraint to only allow string values of length between 30 and 1. @constraint:String {maxLength: 30, minLength: 1} @@ -18,8 +18,8 @@ listener kafka:Listener orderListener = new (kafka:DEFAULT_URL, { service on orderListener { - remote function onConsumerRecord(Order[] orders) returns error? { - check from Order 'order in orders + remote function onConsumerRecord(Order[] orders) { + from Order 'order in orders where 'order.isValid do { log:printInfo(string `Received valid order for ${'order.productName}`); diff --git a/examples/kafka-service-consume-message/kafka_service_consume_message.bal b/examples/kafka-service-consume-message/kafka_service_consume_message.bal index a5b300d502..a4ecee763e 100755 --- a/examples/kafka-service-consume-message/kafka_service_consume_message.bal +++ b/examples/kafka-service-consume-message/kafka_service_consume_message.bal @@ -1,7 +1,7 @@ import ballerinax/kafka; import ballerina/log; -public type Order readonly & record { +type Order readonly & record { int orderId; string productName; decimal price; @@ -15,9 +15,9 @@ listener kafka:Listener orderListener = new (kafka:DEFAULT_URL, { service on orderListener { - remote function onConsumerRecord(Order[] orders) returns error? { + remote function onConsumerRecord(Order[] orders) { // The set of orders received by the service are processed one by one. - check from Order 'order in orders + from Order 'order in orders where 'order.isValid do { log:printInfo(string `Received valid order for ${'order.productName}`); diff --git a/examples/kafka-service-error-handling/kafka_service_error_handling.bal b/examples/kafka-service-error-handling/kafka_service_error_handling.bal index 441a7e9cd4..16e4ed0cef 100755 --- a/examples/kafka-service-error-handling/kafka_service_error_handling.bal +++ b/examples/kafka-service-error-handling/kafka_service_error_handling.bal @@ -1,7 +1,7 @@ import ballerinax/kafka; import ballerina/log; -public type Order readonly & record { +type Order readonly & record { int orderId; string productName; decimal price; @@ -17,9 +17,9 @@ listener kafka:Listener orderListener = new (kafka:DEFAULT_URL, { service on orderListener { - remote function onConsumerRecord(Order[] orders) returns error? { + remote function onConsumerRecord(Order[] orders) { // The set of orders received by the service are processed one by one. - check from Order 'order in orders + from Order 'order in orders where 'order.isValid do { log:printInfo(string `Received valid order for ${'order.productName}`); @@ -42,4 +42,5 @@ service on orderListener { } else { log:printError("An error occured", 'error); } + } } diff --git a/examples/kafka-service-sasl/kafka_service_sasl.bal b/examples/kafka-service-sasl/kafka_service_sasl.bal index 3ffe68ec3e..cf13033665 100755 --- a/examples/kafka-service-sasl/kafka_service_sasl.bal +++ b/examples/kafka-service-sasl/kafka_service_sasl.bal @@ -1,7 +1,7 @@ import ballerinax/kafka; import ballerina/log; -public type Order readonly & record { +type Order readonly & record { int orderId; string productName; decimal price; @@ -26,8 +26,8 @@ listener kafka:Listener orderListener = new ("localhost:9093", { service on orderListener { - remote function onConsumerRecord(Order[] orders) returns error? { - check from Order 'order in orders + remote function onConsumerRecord(Order[] orders) { + from Order 'order in orders where 'order.isValid do { log:printInfo(string `Received valid order for ${'order.productName}`); diff --git a/examples/kafka-service-ssl/kafka_service_ssl.bal b/examples/kafka-service-ssl/kafka_service_ssl.bal index 69eab4e340..06650632b7 100755 --- a/examples/kafka-service-ssl/kafka_service_ssl.bal +++ b/examples/kafka-service-ssl/kafka_service_ssl.bal @@ -1,7 +1,7 @@ import ballerinax/kafka; import ballerina/log; -public type Order readonly & record { +type Order readonly & record { int orderId; string productName; decimal price; @@ -25,8 +25,8 @@ listener kafka:Listener orderListener = new ("localhost:9094", { service on orderListener { - remote function onConsumerRecord(Order[] orders) returns error? { - check from Order 'order in orders + remote function onConsumerRecord(Order[] orders) { + from Order 'order in orders where 'order.isValid do { log:printInfo(string `Received valid order for ${'order.productName}`); diff --git a/examples/kubernetes-hello-world/Cloud.toml b/examples/kubernetes-hello-world/Cloud.toml new file mode 100644 index 0000000000..f83062215c --- /dev/null +++ b/examples/kubernetes-hello-world/Cloud.toml @@ -0,0 +1,4 @@ +[container.image] +repository="wso2inc" +name="hello" +tag="v0.1.0" diff --git a/examples/kubernetes-hello-world/build_output.out b/examples/kubernetes-hello-world/build_output.out new file mode 100644 index 0000000000..0be2042599 --- /dev/null +++ b/examples/kubernetes-hello-world/build_output.out @@ -0,0 +1,19 @@ +$ bal build --cloud="k8s" + +Compiling source + wso2/hello:0.1.0 + +Generating executable + +Generating artifacts... + + @kubernetes:Service - complete 1/1 + @kubernetes:Deployment - complete 1/1 + @kubernetes:HPA - complete 1/1 + @kubernetes:Docker - complete 2/2 + + Execute the below command to deploy the Kubernetes artifacts: + kubectl apply -f /home/anjana/bbe-make/k8s/target/kubernetes/hello + + Execute the below command to access service via NodePort: + kubectl expose deployment hello-deployment --type=NodePort --name=hello-svc-local diff --git a/examples/kubernetes-hello-world/docker_push.out b/examples/kubernetes-hello-world/docker_push.out new file mode 100644 index 0000000000..aae0d47703 --- /dev/null +++ b/examples/kubernetes-hello-world/docker_push.out @@ -0,0 +1 @@ +$ docker push wso2inc/hello:v0.1.0 diff --git a/examples/kubernetes-hello-world/execute_curl.out b/examples/kubernetes-hello-world/execute_curl.out new file mode 100644 index 0000000000..29bc34a7d5 --- /dev/null +++ b/examples/kubernetes-hello-world/execute_curl.out @@ -0,0 +1,2 @@ +$ curl http://192.168.49.2:31360/helloWorld/sayHello +Hello from Kubernetes! diff --git a/examples/kubernetes-hello-world/kubectl_apply.out b/examples/kubernetes-hello-world/kubectl_apply.out new file mode 100644 index 0000000000..c1e37d3d30 --- /dev/null +++ b/examples/kubernetes-hello-world/kubectl_apply.out @@ -0,0 +1,4 @@ +$ kubectl apply -f /home/wso2/project/target/kubernetes/hello-0.1.0 +service/helloep-svc created +deployment.apps/wso2-hello-0--deployment created +horizontalpodautoscaler.autoscaling/wso2-hello-0--hpa created diff --git a/examples/kubernetes-hello-world/kubectl_expose.out b/examples/kubernetes-hello-world/kubectl_expose.out new file mode 100644 index 0000000000..dcb2bf50c9 --- /dev/null +++ b/examples/kubernetes-hello-world/kubectl_expose.out @@ -0,0 +1,2 @@ +$ kubectl expose deployment hello-deployment --type=NodePort --name=hello-svc-local +service/hello-svc-local exposed diff --git a/examples/kubernetes-hello-world/kubectl_pods.out b/examples/kubernetes-hello-world/kubectl_pods.out new file mode 100644 index 0000000000..35026982d3 --- /dev/null +++ b/examples/kubernetes-hello-world/kubectl_pods.out @@ -0,0 +1,3 @@ +$ kubectl get pods +NAME READY STATUS RESTARTS AGE +wso2-hello-0--deployment-7d4d56457b-7jlzx 1/1 Running 0 57s diff --git a/examples/kubernetes-hello-world/kubectl_svc.out b/examples/kubernetes-hello-world/kubectl_svc.out new file mode 100644 index 0000000000..cffd7dcaaa --- /dev/null +++ b/examples/kubernetes-hello-world/kubectl_svc.out @@ -0,0 +1,4 @@ +$ kubectl get svc +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +hello-svc ClusterIP 10.97.140.84 9090/TCP 13m +hello-svc-local NodePort 10.108.87.21 9090:31360/TCP 2m18s diff --git a/examples/kubernetes-hello-world/kubernetes-hello-world.bal b/examples/kubernetes-hello-world/kubernetes-hello-world.bal new file mode 100644 index 0000000000..739c8159e8 --- /dev/null +++ b/examples/kubernetes-hello-world/kubernetes-hello-world.bal @@ -0,0 +1,11 @@ +import ballerina/http; + +// This code is completely focused on the business logic and it does not depend on the deployment. + +listener http:Listener helloEP = new(9090); + +service http:Service /helloWorld on helloEP { + resource function get sayHello() returns string { + return "Hello from Kubernetes!"; + } +} diff --git a/examples/kubernetes-hello-world/kubernetes-hello-world.md b/examples/kubernetes-hello-world/kubernetes-hello-world.md new file mode 100644 index 0000000000..2d849a0683 --- /dev/null +++ b/examples/kubernetes-hello-world/kubernetes-hello-world.md @@ -0,0 +1,35 @@ +# Kubernetes - Hello world + +Ballerina supports generating Kubernetes artifacts from code without any additional configuration. This simplifies the experience of developing and deploying Ballerina code in the cloud. Code to Cloud builds the containers and required artifacts by deriving the required values from the code. If you want to override the default values taken by the compiler, you can use a `Cloud.toml` file. +For more information, see [Code to Cloud deployment](/learn/code-to-cloud-deployment/). + +::: code kubernetes-hello-world.bal ::: + +Before you build the package, you need to override some default values taken by the compiler. To do this, create a filed named `Cloud.toml` in the package directory, and add the content below to it. +For all the supported key value properties, see [Code to Cloud Specification](https://github.com/ballerina-platform/ballerina-spec/blob/master/c2c/code-to-cloud-spec.md). + +::: code Cloud.toml ::: + +Execute the `bal build` command to build the Ballerina package. Code to Cloud generates only one container per package. +::: out build_output.out ::: + +Push the created Docker image to Docker Hub. +::: out docker_push.out ::: + +Create the deployment using the Kubernetes artifacts. +::: out kubectl_apply.out ::: + +Verify the Kubernetes pods. +::: out kubectl_pods.out ::: + +Expose via NodePort to test in the developer environment. +::: out kubectl_expose.out ::: + +Get the External IP and port of the Kubernetes service. +::: out kubectl_svc.out ::: + +If the External IP of the `hello-svc-local` service is ``, you need to follow cluster-specific steps to obtain the external IP. If you are using Minikube, you can use the `minikube ip` command to obtain the IP. +::: out minikube_ip.out ::: + +Access the deployed service via cURL. +::: out execute_curl.out ::: diff --git a/examples/kubernetes-hello-world/minikube_ip.out b/examples/kubernetes-hello-world/minikube_ip.out new file mode 100644 index 0000000000..449c37eb24 --- /dev/null +++ b/examples/kubernetes-hello-world/minikube_ip.out @@ -0,0 +1,2 @@ +$ minikube ip +192.168.49.2 diff --git a/examples/nats-jetstream-pub/nats_jetstream_pub.bal b/examples/nats-jetstream-pub/nats_jetstream_pub.bal new file mode 100644 index 0000000000..db4235b772 --- /dev/null +++ b/examples/nats-jetstream-pub/nats_jetstream_pub.bal @@ -0,0 +1,38 @@ +import ballerina/http; +import ballerinax/nats; + +type Order readonly & record { + int orderId; + string productName; + decimal price; + boolean isValid; +}; + +service / on new http:Listener(9092) { + private final string SUBJECT_NAME = "orders"; + private final nats:JetStreamClient orderClient; + + function init() returns error? { + // Initiate a NATS client passing the URL of the NATS broker. + nats:Client natsClient = check new (nats:DEFAULT_URL); + + // Initiate the NATS `JetStreamClient` at the start of the service. This will be used + // throughout the lifetime of the service. + self.orderClient = check new (natsClient); + nats:StreamConfiguration config = { + name: "demo", + subjects: [self.SUBJECT_NAME], + storageType: nats:MEMORY + }; + _ = check self.orderClient->addStream(config); + } + + resource function post orders(Order newOrder) returns http:Accepted|error { + // Produce a message to the specified subject. + check self.orderClient->publishMessage({ + subject: self.SUBJECT_NAME, + content: newOrder.toString().toBytes() + }); + return http:ACCEPTED; + } +} diff --git a/examples/nats-jetstream-pub/nats_jetstream_pub.client.out b/examples/nats-jetstream-pub/nats_jetstream_pub.client.out new file mode 100644 index 0000000000..b13e03a2e6 --- /dev/null +++ b/examples/nats-jetstream-pub/nats_jetstream_pub.client.out @@ -0,0 +1 @@ +$ curl http://localhost:9092/orders -H "Content-type:application/json" -d "{\"orderId\": 1, \"productName\": \"Sport shoe\", \"price\": 27.5, \"isValid\": true}" diff --git a/examples/nats-jetstream-pub/nats_jetstream_pub.md b/examples/nats-jetstream-pub/nats_jetstream_pub.md new file mode 100644 index 0000000000..1af04eea49 --- /dev/null +++ b/examples/nats-jetstream-pub/nats_jetstream_pub.md @@ -0,0 +1,20 @@ +# NATS JetStream client - Publish message + +The `nats:JetStreamClient` allows you to publish messages to a specific subject. To create a `nats:JetStreamClient`, you need to provide a valid instance of the `nats:Client`. Before publishing messages, you should call the `addStream` function to configure the stream. This function requires a `nats:JetStreamConfiguration` object with the `name`, `subjects`, and `storageType` values. To publish messages, you can use the `publishMessage` method, which takes the message content and subject as arguments. This method allows you to send messages that can be received by one or more subscribers. + +::: code nats_jetstream_pub.bal ::: + +## Prerequisites +- Start an instance of the [NATS JetStream server](https://docs.nats.io/running-a-nats-service/configuration/resource_management). +- Run the NATS JetStream service given in the [NATS JetStream service - Consume message](/learn/by-example/nats-jetstream-sub/) example. + +Run the client program by executing the following command. + +::: out nats_jetstream_pub.server.out ::: + +Invoke the service by executing the following cURL command in a new terminal. + +::: out nats_jetstream_pub.client.out ::: + +## Related links +- [`nats:JetStreamClient` client object - API documentation](https://lib.ballerina.io/ballerinax/nats/latest/clients/JetStreamClient) diff --git a/examples/nats-jetstream-pub/nats_jetstream_pub.metatags b/examples/nats-jetstream-pub/nats_jetstream_pub.metatags new file mode 100644 index 0000000000..361ee38951 --- /dev/null +++ b/examples/nats-jetstream-pub/nats_jetstream_pub.metatags @@ -0,0 +1,2 @@ +description: BBE on producing and consuming a message from a subject in the NATS JetStream server using Ballerina. +keywords: ballerina, ballerina by example, bbe, nats, jetstream, server, publish, subscribe diff --git a/examples/nats-jetstream-pub/nats_jetstream_pub.server.out b/examples/nats-jetstream-pub/nats_jetstream_pub.server.out new file mode 100644 index 0000000000..31d98c6b7f --- /dev/null +++ b/examples/nats-jetstream-pub/nats_jetstream_pub.server.out @@ -0,0 +1 @@ +$ bal run nats_jetstream_pub.bal diff --git a/examples/nats-jetstream-sub/nats_jestream_sub.bal b/examples/nats-jetstream-sub/nats_jestream_sub.bal new file mode 100644 index 0000000000..13c26f7d20 --- /dev/null +++ b/examples/nats-jetstream-sub/nats_jestream_sub.bal @@ -0,0 +1,32 @@ +import ballerina/log; +import ballerinax/nats; + +type Order readonly & record { + int orderId; + string productName; + decimal price; + boolean isValid; +}; + +// Initiate a NATS client passing the URL of the NATS broker. +nats:Client natsClient = check new (nats:DEFAULT_URL); + +// Initialize a NATS JetStream listener. +listener nats:JetStreamListener subscription = new (natsClient); +const string SUBJECT_NAME = "orders"; + +@nats:StreamServiceConfig { + subject: SUBJECT_NAME, + autoAck: false +} +// Bind the consumer to listen to the messages published to the 'orders' subject. +service nats:JetStreamService on subscription { + remote function onMessage(nats:JetStreamMessage message) returns error? { + string stringContent = check string:fromBytes(message.content); + json jsonContent = check stringContent.fromJsonString(); + Order 'order = check jsonContent.cloneWithType(); + if 'order.isValid { + log:printInfo(string `Received valid order for ${'order.productName}`); + } + } +} diff --git a/examples/nats-jetstream-sub/nats_jestream_sub.md b/examples/nats-jetstream-sub/nats_jestream_sub.md new file mode 100644 index 0000000000..678a23ce79 --- /dev/null +++ b/examples/nats-jetstream-sub/nats_jestream_sub.md @@ -0,0 +1,17 @@ +# NATS JetStream service - Consume message + +The `nats:JetStreamService` listens to a specified subject for incoming messages. Whenever a publisher sends a message to that subject, any active service listening to it will receive the message. You need to provide an instance of the `nats:Client` to create a `nats:JetStreamListener`. Once you have a `nats:JetStreamListener`, you can attach a `nats:JetStreamService` to it in order to listen to a specific subject and consume incoming messages. The subject to listen to can be either specified as the service path or provided in the `subject` field of the `nats:StreamServiceConfig`. This setup allows you to effectively listen to messages sent to a particular subject. + +::: code nats_jestream_sub.bal ::: + +## Prerequisites +- Start an instance of the [NATS JetStream server](https://docs.nats.io/running-a-nats-service/configuration/resource_management). + +Run the service by executing the following command. + +::: out nats_jestream_sub.out ::: + +>**Tip:** You can invoke the above service via the [NATS JetStream client](/learn/by-example/nats-jetstream-pub/). + +## Related links +- [`nats` package - API documentation](https://lib.ballerina.io/ballerinax/nats/latest) diff --git a/examples/nats-jetstream-sub/nats_jestream_sub.metatags b/examples/nats-jetstream-sub/nats_jestream_sub.metatags new file mode 100644 index 0000000000..361ee38951 --- /dev/null +++ b/examples/nats-jetstream-sub/nats_jestream_sub.metatags @@ -0,0 +1,2 @@ +description: BBE on producing and consuming a message from a subject in the NATS JetStream server using Ballerina. +keywords: ballerina, ballerina by example, bbe, nats, jetstream, server, publish, subscribe diff --git a/examples/nats-jetstream-sub/nats_jestream_sub.out b/examples/nats-jetstream-sub/nats_jestream_sub.out new file mode 100644 index 0000000000..f9126c710a --- /dev/null +++ b/examples/nats-jetstream-sub/nats_jestream_sub.out @@ -0,0 +1,2 @@ +$ bal run nats_jetstream_sub.bal +time = 2023-06-20T20:17:28.026+05:30 level = INFO module = "" message = "Received valid order for Sport shoe" diff --git a/examples/object-type-inclusion/object_type_inclusion.bal b/examples/object-type-inclusion/object_type_inclusion.bal index 57bbcd6ff0..0aefa6e92d 100644 --- a/examples/object-type-inclusion/object_type_inclusion.bal +++ b/examples/object-type-inclusion/object_type_inclusion.bal @@ -18,7 +18,7 @@ type Person object { class Engineer { // The `Engineer` class includes the `Person` object type. - // Therefore, it has to implement both the `clone()` and `draw()` methods. + // Therefore, it has to implement both the `clone()` and `getName()` methods. *Person; function init(string name) { diff --git a/examples/raw-templates/Ballerina.toml b/examples/raw-templates/Ballerina.toml index 755a5b3df2..f687b9038e 100644 --- a/examples/raw-templates/Ballerina.toml +++ b/examples/raw-templates/Ballerina.toml @@ -1,2 +1,2 @@ -[[platform.java11.dependency]] +[[platform.java17.dependency]] path = "h2-2.1.210.jar" diff --git a/examples/record-to-edi/bal_project.out b/examples/record-to-edi/bal_project.out new file mode 100644 index 0000000000..6539f8142d --- /dev/null +++ b/examples/record-to-edi/bal_project.out @@ -0,0 +1,3 @@ +$ bal new record_to_edi +$ cd record_to_edi +$ bal add sorder diff --git a/examples/record-to-edi/codegen_command.out b/examples/record-to-edi/codegen_command.out new file mode 100644 index 0000000000..f7bbc95816 --- /dev/null +++ b/examples/record-to-edi/codegen_command.out @@ -0,0 +1 @@ +$ bal edi codegen -s resources/simple_order_schema.json -o modules/sorder/sorder.bal diff --git a/examples/record-to-edi/output.out b/examples/record-to-edi/output.out new file mode 100644 index 0000000000..443106e4d9 --- /dev/null +++ b/examples/record-to-edi/output.out @@ -0,0 +1,5 @@ +$ bal run +HDR*ORDER_200*HMart*17-05-2023~ +ITM*A680*15~ +ITM*A530*2~ +ITM*A500*4~ diff --git a/examples/record-to-edi/package_structure.out b/examples/record-to-edi/package_structure.out new file mode 100644 index 0000000000..10a926ee9e --- /dev/null +++ b/examples/record-to-edi/package_structure.out @@ -0,0 +1,13 @@ +└── record_to_edi + ├── Ballerina.toml + ├── Dependencies.toml + ├── main.bal + ├── modules + │   └── sorder + │   ├── Module.md + │   ├── resources + │   ├── sorder.bal + │   └── tests + │   └── lib_test.bal + └── resources + └── simple_order_schema.json diff --git a/examples/record-to-edi/record_to_edi.bal b/examples/record-to-edi/record_to_edi.bal new file mode 100644 index 0000000000..e448614d77 --- /dev/null +++ b/examples/record-to-edi/record_to_edi.bal @@ -0,0 +1,12 @@ +import ballerina/io; +import record_to_edi.sorder; + +public function main() returns error? { + sorder:SimpleOrder simpleOrder = + {header: {code: "HDR", orderId: "ORDER_200", organization: "HMart", date: "17-05-2023"}}; + simpleOrder.items.push({code: "ITM", item: "A680", quantity: 15}); + simpleOrder.items.push({code: "ITM", item: "A530", quantity: 2}); + simpleOrder.items.push({code: "ITM", item: "A500", quantity: 4}); + string ediText = check sorder:toEdiString(simpleOrder); + io:println(ediText); +} diff --git a/examples/record-to-edi/record_to_edi.md b/examples/record-to-edi/record_to_edi.md new file mode 100644 index 0000000000..89bc86415d --- /dev/null +++ b/examples/record-to-edi/record_to_edi.md @@ -0,0 +1,31 @@ +# Record to EDI conversion + +Same EDI schema and generated code used in EDI to record conversion example can be used to convert Ballerina records of type SimpleOrder to EDI. + +::: code schema.json ::: + +Create a new Ballerina project named `record_to_edi` and create a module named `sorder` inside that project by using the below commands. + +::: code bal_project.out ::: + +Create a new folder named `resources` in the root of the project and copy the schema file into it. At this point, directory structure of the project would look like below: + +::: out package_structure.out ::: + +Get the EDI tool from the Ballerina central using the below command: + +::: out tool_pull_command.out ::: + +Run the below command from the project root directory to generate the Ballerina parser for the above schema. + +::: out codegen_command.out ::: + +>Note that it is recommended to place generated code for each EDI schema in a separate module in order to avoid conflicts. + +Write a Ballerina program by using generated methods and records to convert Ballerina records to EDI. + +::: code record_to_edi.bal ::: + +Run the program using the command below: + +::: out output.out ::: diff --git a/examples/record-to-edi/record_to_edi.metatags b/examples/record-to-edi/record_to_edi.metatags new file mode 100644 index 0000000000..823613f563 --- /dev/null +++ b/examples/record-to-edi/record_to_edi.metatags @@ -0,0 +1,2 @@ +description: This BBE demonstrates how convert Ballerina records into EDI text based on an EDI schema. +keywords: ballerina, ballerina by example, bbe, edi, electronic data interchange, b2b, integration diff --git a/examples/record-to-edi/schema.json b/examples/record-to-edi/schema.json new file mode 100644 index 0000000000..a3e8eea20a --- /dev/null +++ b/examples/record-to-edi/schema.json @@ -0,0 +1,18 @@ +{ + "name": "SimpleOrder", + "delimiters" : {"segment" : "~", "field" : "*", "component": ":", "repetition": "^"}, + "segments" : [ + { + "code": "HDR", + "tag" : "header", + "minOccurances": 1, + "fields" : [{"tag": "code"}, {"tag" : "orderId", "required": true}, {"tag" : "organization"}, {"tag" : "date"}] + }, + { + "code": "ITM", + "tag" : "items", + "maxOccurances" : -1, + "fields" : [{"tag": "code"}, {"tag" : "item", "required": true}, {"tag" : "quantity", "required": true, "dataType" : "int"}] + } + ] +} diff --git a/examples/record-to-edi/tool_pull_command.out b/examples/record-to-edi/tool_pull_command.out new file mode 100644 index 0000000000..8cdb63f178 --- /dev/null +++ b/examples/record-to-edi/tool_pull_command.out @@ -0,0 +1 @@ +$ bal tool pull edi diff --git a/examples/regular-expressions/regular_expressions.bal b/examples/regular-expressions/regular_expressions.bal deleted file mode 100644 index d8533367f2..0000000000 --- a/examples/regular-expressions/regular_expressions.bal +++ /dev/null @@ -1,26 +0,0 @@ -import ballerina/io; -import ballerina/regex; - -public function main() { - - // Checks whether the given string matches the provided regex. - boolean isMatched = regex:matches("This Should Match", "Th.*ch"); - io:println("Is the given string matched with the original string: ", - isMatched); - - // Replaces each occurrence of the substrings, which match the provided - // regular expression from the given original string value with the - // provided replacement string. - string new_string = regex:replaceAll("Ballerina is great", "\\s+", "_"); - io:println("Replaced string: ", new_string); - - // Replaces the first substring that matches the given regular expression - // with the provided `replacement` string. - new_string = regex:replace("ReplacethisthisTextThis", "this", " "); - io:println("String after replacing first Match: ", new_string); - - // Retrieves an array of strings by splitting a string using the provided - // delimiter. - string[] names = regex:split("amal, kamal, nimal, sunimal", ","); - io:println("No of names: ", names.length()); -} diff --git a/examples/regular-expressions/regular_expressions.md b/examples/regular-expressions/regular_expressions.md deleted file mode 100644 index ffc72bc592..0000000000 --- a/examples/regular-expressions/regular_expressions.md +++ /dev/null @@ -1,13 +0,0 @@ -# Regular expressions - -The `regex` library provides functionalities for searching, splitting, and replacing the set of characters of the string by using the `regular expression`. - -For more information on the underlying module, see the [`regex` module](https://lib.ballerina.io/ballerina/regex/latest/). - ->**Deprecation Notice:** This library is deprecated and will no longer be maintained or updated. Instead, it is recommended to use the [`ballerina/lang.regexp`](https://lib.ballerina.io/ballerina/lang.regexp/latest) library for continued support and updates. For more information, see the new [RegExp type example](/learn/by-example/regexp-type), [RegExp operations example](/learn/by-example/regexp-operations), and [Regular expressions feature guide](/learn/distinctive-language-features/advanced-general-purpose-language-features/#regular-expressions). - -::: code regular_expressions.bal ::: - -To run this sample, use the `bal run` command. - -::: out regular_expressions.out ::: diff --git a/examples/regular-expressions/regular_expressions.metatags b/examples/regular-expressions/regular_expressions.metatags deleted file mode 100644 index 87205dc001..0000000000 --- a/examples/regular-expressions/regular_expressions.metatags +++ /dev/null @@ -1,2 +0,0 @@ -description: This BBE shows how to manipulate Strings with regex expression in Ballerina. -keywords: ballerina, ballerina by example, BBE, string, regex diff --git a/examples/regular-expressions/regular_expressions.out b/examples/regular-expressions/regular_expressions.out deleted file mode 100644 index 4e1ec13767..0000000000 --- a/examples/regular-expressions/regular_expressions.out +++ /dev/null @@ -1,5 +0,0 @@ -$ bal run regex_expressions.bal -Is the given string matched with the original string: true -Replaced string: Ballerina_is_great -String after replacing first Match: Replace thisTextThis -No of names: 4 diff --git a/examples/stop-handler/stop_handler.client.out b/examples/stop-handler/stop_handler.client.out index c9034a00e2..08c1a4bde7 100644 --- a/examples/stop-handler/stop_handler.client.out +++ b/examples/stop-handler/stop_handler.client.out @@ -1,3 +1,2 @@ -# Invoke the service using cURL to add a fruit item. $ curl http://localhost:9090/addToBasket -d 'Guava' ["Apple", "Orange", "Guava"] diff --git a/examples/stop-handler/stop_handler.md b/examples/stop-handler/stop_handler.md index 4bea2219d6..7cccce26c3 100644 --- a/examples/stop-handler/stop_handler.md +++ b/examples/stop-handler/stop_handler.md @@ -1,10 +1,14 @@ # `StopHandler` -The `StopHandler` registers a function that will be called during the graceful shutdown. -This example demonstrates how to register a function that will be executed at the end of the program. +A `StopHandler` is a function that is registered at runtime with a module and invoked during graceful shutdown. +This example demonstrates how to register a `StopHandler` that will be executed at the end of the program. ::: code stop_handler.bal ::: -::: out stop_handler.client.out ::: +Navigate to the directory that contains the 'stop_handler.bal' file, and run the 'bal run' command. ::: out stop_handler.server.out ::: + +Invoke the service by executing the following cURL command in a new terminal to add a fruit item. + +::: out stop_handler.client.out ::: diff --git a/examples/stop-handler/stop_handler.server.out b/examples/stop-handler/stop_handler.server.out index 2b049db64c..191e06e938 100644 --- a/examples/stop-handler/stop_handler.server.out +++ b/examples/stop-handler/stop_handler.server.out @@ -1,10 +1,8 @@ -# Navigate to the directory that contains the -# 'stop_handler.bal' file, and run the 'bal run' command below. - $ bal run stop_handler.bal - -# Send the interrupt signal SIGINT to terminate the current process. -Ctrl+c initial items in fruit basket: ["Apple","Orange"] + +# Invoke the service using cURL command as mentioned below in a new terminal. after adding a fruit item: ["Apple","Orange","Guava"] + +# Send the interrupt signal SIGINT (Ctrl+C) to terminate the current process. after removing all fruit items: [] diff --git a/gradle.properties b/gradle.properties index 17c2ea6666..a798179064 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,92 +1,96 @@ org.gradle.caching=true group=org.ballerinalang # During the release workflow, the following will get bumped automatically -version=2201.6.0-SNAPSHOT +version=2201.8.0-SNAPSHOT codeName=swan-lake -ballerinaLangVersion=2201.6.0-20230528-002600-217853c5 -ballerinaJreVersion=1.1.0 -dependencyJREVersion=jdk-11.0.18+10-jre -specVersion=2022R4 + +ballerinaLangVersion=2201.8.0-20230830-220400-8a7556d8 +ballerinaJreVersion=2.0.0 +dependencyJREVersion=jdk-17.0.7+7-jre +specVersion=2023R1 slf4jVersion=1.7.30 balstdlibBranch=master +devIdpUrl=https://dev.api.asgardeo.io/oauth2/token/.well-known/openid-configuration # Stdlib Level 01 -stdlibConstraintVersion=1.1.0 -stdlibIoVersion=1.4.0 -stdlibJavaArraysVersion=1.2.3 -stdlibRegexVersion=1.4.3 -stdlibTimeVersion=2.2.4 -stdlibUrlVersion=2.2.3 -stdlibXmldataVersion=2.4.3 -observeVersion=1.0.7 -stdlibMathVectorVersion=1.0.1-20230529-131300-5c49593 +stdlibConstraintVersion=1.4.0-20230831-142400-50e4023 +stdlibIoVersion=1.6.0-20230831-135000-049f91a +stdlibJavaArraysVersion=1.4.0-20230831-135000-d7ceba6 +stdlibTimeVersion=2.4.0-20230831-134800-62143cd +stdlibUrlVersion=2.4.0-20230831-134600-aab5a12 +stdlibXmldataVersion=2.7.0-20230831-135200-52e14b9 +observeVersion=1.2.0-20230831-133600-6d16df4 +stdlibMathVectorVersion=1.0.2-20230831-133300-710fabf + # Stdlib Level 02 -stdlibCryptoVersion=2.3.0 -stdlibLogVersion=2.7.1-20230426-134900-2076e24 -stdlibOsVersion=1.6.0 -stdlibProtobufVersion=1.3.2 -stdlibRandomVersion=1.3.1 -stdlibTaskVersion=2.3.2 -stdlibXsltVersion=2.4.0 -observeInternalVersion=1.0.6 +stdlibCryptoVersion=2.5.0-20230831-142400-f4a0d9f +stdlibLogVersion=2.9.0-20230831-153100-9b73447 +stdlibOsVersion=1.8.0-20230831-142200-cb96913 +stdlibProtobufVersion=1.6.0-20230831-142300-81163ab +stdlibRandomVersion=1.5.0-20230831-142400-d71749f +stdlibTaskVersion=2.5.0-20230831-142600-ec5194a +stdlibXsltVersion=2.6.0-20230831-142600-0c84131 +observeInternalVersion=1.2.0-20230831-141400-b3bbdc2 # Stdlib Level 03 -stdlibCacheVersion=3.4.0 -stdlibFileVersion=1.7.1-20230426-145900-748058d -stdlibFtpVersion=2.7.0 -stdlibMimeVersion=2.7.1-20230426-174700-fa17cd3 -stdlibTcpVersion=1.7.0 -stdlibUdpVersion=1.7.0 -stdlibUuidVersion=1.5.1-20230426-134700-1b44f72 +stdlibCacheVersion=3.7.0-20230831-151700-7e2b0fa +stdlibFileVersion=1.9.0-20230831-160900-252d078 +stdlibFtpVersion=2.9.0-20230831-160900-d76961a +stdlibMimeVersion=2.9.0-20230831-160900-6ecc648 +stdlibTcpVersion=1.9.0-20230831-161800-3d4658f +stdlibUdpVersion=1.9.0-20230831-161200-acbdce0 +stdlibUuidVersion=1.7.0-20230831-151800-012c311 # Stdlib Level 04 -stdlibAuthVersion=2.7.1-20230426-151300-6b9f314 -stdlibEmailVersion=2.7.0 -stdlibJwtVersion=2.7.1-20230427-123000-f1f10bf -stdlibOAuth2Version=2.7.1-20230426-163900-b9c951b +stdlibAuthVersion=2.10.0-20230831-160500-17532df +stdlibEdiVersion=1.0.7-20230831-164800-d8fd1c1 +stdlibEmailVersion=2.9.0-20230831-170300-2a02c2b +stdlibJwtVersion=2.10.0-20230831-160800-b5db938 +stdlibMqttVersion=1.0.0-20230831-160600-42fa522 +stdlibOAuth2Version=2.10.0-20230831-161200-a4a83a6 +stdlibTomlVersion=0.5.0-20230831-170000-244ddb6 +stdlibYamlVersion=0.5.0-20230831-170000-94fddca # Stdlib Level 05 -stdlibHttpVersion=2.7.1-20230504-113400-c4f8055 +stdlibHttpVersion=2.10.0-20230831-195300-180df44 # Stdlib Level 06 -stdlibGrpcVersion=1.7.1-20230510-201900-dd60eae -stdlibTransactionVersion=1.5.0 -stdlibWebsocketVersion=2.7.2-20230518-092600-1304f23 -stdlibWebsubVersion=2.7.0 -stdlibWebsubhubVersion=1.7.0 +stdlibGrpcVersion=1.10.0-20230831-221200-3f0bada +stdlibSoapVersion=0.2.0-20230831-210000-4b8659f +stdlibTransactionVersion=1.8.0-20230831-210400-57edb68 +stdlibWebsocketVersion=2.10.0-20230831-212500-7bd0f7e +stdlibWebsubVersion=2.10.0-20230831-211200-c6f33c4 +stdlibWebsubhubVersion=1.10.0-20230831-210000-695f161 # Stdlib Level 07 -stdlibGraphqlVersion=1.8.0-20230518-105600-d7d892d -stdlibSqlVersion=1.8.1-20230517-130300-fd0b0e5 +stdlibGraphqlVersion=1.10.0-20230831-232100-bb5b601 +stdlibSqlVersion=1.11.0-20230831-224400-d2491ed # Stdlib Level 08 -stdlibPersistVersion=1.0.0-20230529-125900-cf8337e +stdlibPersistVersion=1.2.0-20230831-142100-b7b968f # Persist Tool -persistToolVersion=1.0.0-20230529-142100-07201b3 +persistToolVersion=1.2.0-20230901-122800-012fa8e # Dev Tools -devToolsVersion=1.0.0 +devToolsVersion=1.2.1-20230731-195900-6f87361 ballerinaCommandVersion=1.3.15 # GraphQL Tool -graphqlVersion=0.5.0-20230518-121300-d22805d +graphqlVersion=0.8.0-20230901-070600-c734e6a # Protoc Tool -protocToolVersion=0.1.1-20230517-114400-1af2c22 +protocToolVersion=0.2.0-20230821-121200-8933a55 # OpenAPI Module -openapiVersion=1.6.0-20230426-115700-1eb8448 +openapiVersion=1.8.0-20230901-110600-c7d4d0e # AsyncAPI Module -asyncapiVersion=0.5.0 +asyncapiVersion=0.6.0 -c2cVersion=2.6.0 +c2cVersion=2.11.0-20230901-110400-1333149 -dataMapperVersion=2.2.0 +dataMapperVersion=2.2.1-20230831-150600-0e37f32 installerVersion=69c0a0e-9c6a-4062-ae1e-2209c25e4f51 - -stdlibYamlVersion=0.1.0 -stdlibTomlVersion=0.2.0 diff --git a/gradle/javaProject.gradle b/gradle/javaProject.gradle index 67ebf4c15f..3b6e27902f 100644 --- a/gradle/javaProject.gradle +++ b/gradle/javaProject.gradle @@ -66,14 +66,14 @@ dependencies { checkstyle "com.puppycrawl.tools:checkstyle:${puppycrawlCheckstyleVersion}" } -sourceCompatibility = JavaVersion.VERSION_11 +sourceCompatibility = JavaVersion.VERSION_17 tasks.withType(JavaCompile) { options.encoding = 'UTF-8' } jacoco { - toolVersion = "0.8.6" + toolVersion = "0.8.10" } test { @@ -94,7 +94,7 @@ test { } checkstyle { - toolVersion '7.8.2' + toolVersion '10.12.1' configFile rootProject.file("config/checkstyle/build/checkstyle.xml") configProperties = ["suppressionFile": rootProject.file("config/checkstyle/build/suppressions.xml")] checkstyleTest.enabled = true @@ -122,9 +122,9 @@ spotbugsTest { jacocoTestReport { reports { - xml.enabled true + xml.required = true } } checkstyleMain.dependsOn(":config:checkstyle:downloadMultipleFiles") - +checkstyleTest.dependsOn(":config:checkstyle:downloadMultipleFiles") diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 9ab0a83589..033e24c4cd 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 0ee9713588..9f4197d5f4 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-all.zip diff --git a/gradlew b/gradlew index cccdd3d517..fcb6fca147 100755 --- a/gradlew +++ b/gradlew @@ -1,78 +1,126 @@ -#!/usr/bin/env sh +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -81,92 +129,120 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=$((i+1)) + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" fi +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index e95643d6a2..6689b85bee 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,4 +1,20 @@ -@if "%DEBUG%" == "" @echo off +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -9,19 +25,23 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -35,7 +55,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -45,38 +65,26 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/installers/linux-deb/resources/DEBIAN/postinst b/installers/linux-deb/resources/DEBIAN/postinst index 88dfcb05ff..011f81f664 100755 --- a/installers/linux-deb/resources/DEBIAN/postinst +++ b/installers/linux-deb/resources/DEBIAN/postinst @@ -17,3 +17,4 @@ elif [ "$(basename -- "$SHELL")" = "zsh" ]; then \cp /usr/lib/ballerina/scripts/_bal ~/.ballerina/completion/ chmod 766 ~/.ballerina/completion/_bal fi + diff --git a/installers/linux-rpm/resources/ballerina-runtime.spec b/installers/linux-rpm/resources/ballerina-runtime.spec index dbde3e68a5..8a3a7aa973 100644 --- a/installers/linux-rpm/resources/ballerina-runtime.spec +++ b/installers/linux-rpm/resources/ballerina-runtime.spec @@ -46,6 +46,7 @@ fi %clean rm -rf %{_topdir}/BUILD/* rm -rf %{buildroot} +bal -v %files %{_libdir}/ballerina/%{_ballerina_name}-runtime-%{_ballerina_version} diff --git a/installers/linux-rpm/resources/ballerina-tools.spec b/installers/linux-rpm/resources/ballerina-tools.spec index 1714b2e0eb..9cf8f435b6 100644 --- a/installers/linux-rpm/resources/ballerina-tools.spec +++ b/installers/linux-rpm/resources/ballerina-tools.spec @@ -63,6 +63,7 @@ fi %clean rm -rf %{_topdir}/BUILD/* rm -rf %{buildroot} +bal -v %files %{_libdir}/ballerina/ diff --git a/language-server-simulator/build.gradle b/language-server-simulator/build.gradle new file mode 100644 index 0000000000..20a562a5e7 --- /dev/null +++ b/language-server-simulator/build.gradle @@ -0,0 +1,138 @@ +description = 'Ballerina Language Server Simulator' + +apply from: "$rootDir/gradle/javaProject.gradle" + +ext { + distributionDir = "distribution" + nbalSourceDir = "nBallerinaSrc" + fhirSourceDir = "fhirSrc" + shortVersion = "${version}".split("-")[0] +} + +configurations { + jBallerinaDistribution + ballerinaDistribution +} + +dependencies { + implementation "org.slf4j:slf4j-api:${project.slf4jApiVersion}" + implementation group: 'org.ballerinalang', name: 'ballerina-lang', version: "${ballerinaLangVersion}" + implementation group: 'org.ballerinalang', name: 'ballerina-parser', version: "${ballerinaLangVersion}" + implementation group: 'org.ballerinalang', name: 'language-server-core', version: "${ballerinaLangVersion}" + implementation group: 'org.ballerinalang', name: 'ballerina-tools-api', version: "${ballerinaLangVersion}" + implementation group: 'org.ballerinalang', name: 'language-server-commons', version: "${ballerinaLangVersion}" + implementation(group: 'org.eclipse.lsp4j', name:'org.eclipse.lsp4j', version:"${eclipseLsp4jVersion}") { + exclude group: 'com.google.guava', module: 'guava' + } + implementation (group: 'org.eclipse.lsp4j', name:'org.eclipse.lsp4j.jsonrpc', version:"${eclipseLsp4jJsonrpcVersion}"){ + exclude group: 'com.google.guava', module: 'guava' + } + implementation "org.slf4j:slf4j-jdk14:${slf4jJdk14Version}" + implementation "com.google.code.gson:gson:${gsonVersion}" + + jBallerinaDistribution project(path: ":ballerina", configuration: "jBallerinaDistribution") + ballerinaDistribution project(path: ":ballerina", configuration: "ballerinaDistribution") +} + +task unpackBallerinaDistribution(type: Copy) { + dependsOn configurations.jBallerinaDistribution + dependsOn configurations.ballerinaDistribution + def sourceDir = "${buildDir}/${distributionDir}" + from zipTree { "${rootDir}/ballerina/build/distributions/ballerina-${version}-swan-lake.zip" } + new File("${sourceDir}").mkdirs() + into new File("${sourceDir}") +} + +task copyPackages() { + dependsOn unpackBallerinaDistribution + def sourceDir = "${buildDir}/${distributionDir}" + + "/ballerina-${version}-swan-lake/distributions/ballerina-${shortVersion}/repo" + copy { + from "${sourceDir}" + into "${buildDir}/repo" + } +} + +task downloadBalTestProject(type: Download) { + // Download nBallerina latest tag + src "https://github.com/ballerina-platform/nballerina/archive/refs/heads/main.zip" + onlyIfModified true + dest new File("${buildDir}/nballeirna-src.zip") +} + +task downloadBalFHIRTestProject(type: Download) { + // Download nBallerina latest tag + src "https://github.com/ballerina-platform/module-ballerinax-health.fhir.r4/archive/refs/tags/uscore-v1.0.5.zip" + onlyIfModified true + dest new File("${buildDir}/fhir-src.zip") +} + +task unpackBalTestProject(type: Copy) { + dependsOn downloadBalTestProject + def sourceDir = "${buildDir}/${nbalSourceDir}" + from zipTree { "${buildDir}/nballeirna-src.zip" } + new File("${sourceDir}").mkdirs() + into new File("${sourceDir}") +} + +task unpackBalFHIRTestProject(type: Copy) { + dependsOn downloadBalFHIRTestProject + def sourceDir = "${buildDir}/${fhirSourceDir}" + from zipTree { "${buildDir}/fhir-src.zip" } + new File("${sourceDir}").mkdirs() + into new File("${sourceDir}") +} + +task runLSSimulatorOnnBallerina(type: JavaExec) { + dependsOn copyPackages + dependsOn unpackBalTestProject + + def extractedBalSrcDir = "${buildDir}/${nbalSourceDir}/nballerina-main/compiler" + systemProperty "ls.simulation.src", "${extractedBalSrcDir}" + + systemProperty "ballerina.home", "$buildDir/" + systemProperty "ballerina.version", "${ballerinaLangVersion}" + systemProperty "ls.simulation.duration", "60" + systemProperty "ls.simulation.skipGenerators", System.getProperty("ls.simulation.skipGenerators") + systemProperty "LANG_REPO_BUILD", "false" + + jvmArgs = ['-XX:+HeapDumpOnOutOfMemoryError', "-XX:HeapDumpPath=$rootDir/dump.hprof"] + + maxHeapSize "1536m" + group = "Execution" + description = "Run the main class with JavaExecTask" + classpath = sourceSets.main.runtimeClasspath + main = "org.ballerinalang.langserver.simulator.EditorSimulator" +} + +task runLSSimulatorOnFHIR(type: JavaExec) { + dependsOn copyPackages + dependsOn unpackBalFHIRTestProject + + def extractedBalSrcDir = "${buildDir}/${fhirSourceDir}/module-ballerinax-health.fhir.r4-uscore-v1.0.5/base" + systemProperty "ls.simulation.src", "${extractedBalSrcDir}" + + systemProperty "ballerina.home", "$buildDir/" + systemProperty "ballerina.version", "${ballerinaLangVersion}" + systemProperty "ls.simulation.duration", "60" + systemProperty "ls.simulation.skipGenerators", System.getProperty("ls.simulation.skipGenerators") + systemProperty "LANG_REPO_BUILD", "false" + + jvmArgs = ['-XX:+HeapDumpOnOutOfMemoryError', "-XX:HeapDumpPath=$rootDir/dump.hprof"] + + maxHeapSize "1536m" + group = "Execution" + description = "Run the main class with JavaExecTask" + classpath = sourceSets.main.runtimeClasspath + main = "org.ballerinalang.langserver.simulator.EditorSimulator" +} + +tasks.compileJava { + doFirst { + options.encoding = 'UTF-8' + options.compilerArgs = [ + '--module-path', classpath.asPath, + ] + classpath = files() + } +} diff --git a/language-server-simulator/gradle.properties b/language-server-simulator/gradle.properties new file mode 100644 index 0000000000..cfad0a361c --- /dev/null +++ b/language-server-simulator/gradle.properties @@ -0,0 +1,5 @@ +eclipseLsp4jVersion=0.15.0 +eclipseLsp4jJsonrpcVersion=0.15.0 +slf4jJdk14Version=1.7.26 +gsonVersion=2.9.1 +slf4jApiVersion=1.7.s26 diff --git a/language-server-simulator/src/main/java/module-info.java b/language-server-simulator/src/main/java/module-info.java new file mode 100644 index 0000000000..2af683a511 --- /dev/null +++ b/language-server-simulator/src/main/java/module-info.java @@ -0,0 +1,12 @@ +module io.ballerina.language.server.simulator { + uses org.ballerinalang.langserver.simulator.generators.CodeSnippetGenerator; + requires org.eclipse.lsp4j; + requires io.ballerina.language.server.commons; + requires io.ballerina.language.server.core; + requires org.eclipse.lsp4j.jsonrpc; + requires io.ballerina.lang; + requires io.ballerina.parser; + requires io.ballerina.tools.api; + requires com.google.gson; + requires org.slf4j; +} diff --git a/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/Editor.java b/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/Editor.java new file mode 100644 index 0000000000..cc4f436f10 --- /dev/null +++ b/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/Editor.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://wso2.com) All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.ballerinalang.langserver.simulator; + +import org.ballerinalang.langserver.BallerinaLanguageServer; +import org.ballerinalang.langserver.commons.command.CommandArgument; +import org.ballerinalang.langserver.util.TestUtil; +import org.eclipse.lsp4j.ExecuteCommandParams; +import org.eclipse.lsp4j.jsonrpc.Endpoint; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * Represents the editor used by the end user, which editor consists of a set of open tabs. + * + * @since 2201.8.0 + */ +public class Editor { + + private final BallerinaLanguageServer languageServer; + private final Endpoint endpoint; + + private final List tabs = new ArrayList<>(); + private EditorTab activeTab; + + private boolean isPulled = false; + + private Editor(BallerinaLanguageServer languageServer, Endpoint endpoint) { + this.languageServer = languageServer; + this.endpoint = endpoint; + } + + /** + * Simulates opening the editor. Here we initialize the language server. + * + * @return Editor instance + */ + public static Editor open() { + BallerinaLanguageServer languageServer = new BallerinaLanguageServer(); + + EditorOutputStream outputStream = new EditorOutputStream(); + Endpoint endpoint = TestUtil.initializeLanguageSever(languageServer, outputStream); + Editor editor = new Editor(languageServer, endpoint); + outputStream.setEditor(editor); + return editor; + } + + public EditorTab openFile(Path filePath) { + //Pull missing modules from central + if (!isPulled) { + CommandArgument uriArg = CommandArgument.from("doc.uri", filePath); + List args = new ArrayList<>(); + args.add(uriArg); + ExecuteCommandParams params = new ExecuteCommandParams("PULL_MODULE", args); + TestUtil.getExecuteCommandResponse(params, endpoint); + isPulled = true; + } + + EditorTab editorTab = tabs.stream() + .filter(tab -> tab.filePath().equals(filePath)) + .findFirst() + .orElseGet(() -> { + EditorTab tab = new EditorTab(filePath, endpoint, languageServer); + tabs.add(tab); + return tab; + }); + this.activeTab = editorTab; + return editorTab; + } + + public void closeFile(Path filePath) { + Iterator iterator = tabs.iterator(); + while (iterator.hasNext()) { + EditorTab tab = iterator.next(); + if (filePath.equals(tab.filePath())) { + if (activeTab != null && activeTab.equals(tab)) { + activeTab = null; + } + iterator.remove(); + } + } + } + + public void closeTab(EditorTab tab) { + tabs.remove(tab); + if (activeTab != null && activeTab.equals(tab)) { + activeTab = null; + } + } + + public void close() { + this.languageServer.shutdown(); + tabs.forEach(EditorTab::close); + } + + public EditorTab activeTab() { + return activeTab; + } +} diff --git a/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/EditorOutputStream.java b/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/EditorOutputStream.java new file mode 100644 index 0000000000..82cb2cee7b --- /dev/null +++ b/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/EditorOutputStream.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://wso2.com) All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.ballerinalang.langserver.simulator; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.eclipse.lsp4j.jsonrpc.RemoteEndpoint; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.Charset; + +/** + * A custom output stream to consume messages sent from LS to the LS client side. + * + * @since 2201.8.0 + */ +class EditorOutputStream extends ByteArrayOutputStream { + + private static final Logger logger = LoggerFactory.getLogger(EditorOutputStream.class); + + private Editor editor; + + /** + * LSP4J invokes this method after writing a message to the stream. At that point, we should have the complete + * message in the byte array. Here we consume that and reset the array. + * + * @throws IOException IO errors + * @see RemoteEndpoint#request(String, Object) + */ + @Override + public void flush() throws IOException { + String message = this.toString(Charset.defaultCharset()); + reset(); + try { + process(message); + } catch (Throwable t) { + logger.error("Error processing message", t); + } + } + + /** + * Process a received message. We are interested in log message events and telemetry events to identify errors + * occurred. + * + * @param message JSON RPC message received + */ + void process(String message) { + String[] parts = message.replace("\r\n", "\n").split("\n"); + if (parts.length > 1) { + message = parts[parts.length - 1]; + JsonElement jsonMsg = JsonParser.parseString(message); + + if (jsonMsg.isJsonObject()) { + JsonObject obj = jsonMsg.getAsJsonObject(); + String method = obj.get("method").getAsString(); + + switch (method) { + case "telemetry/event": + logger.info("Got telemetry event: {}", obj); + if (editor != null && editor.activeTab() != null) { + logger.info("Current file: {}", editor.activeTab().filePath()); + logger.info("Current file content: \n{}\n========================", + editor.activeTab().textDocument().toString()); + } + break; + case "window/logMessage": + logger.info("Received log message event: {}", obj); + break; + case "textDocument/publishDiagnostics": + // pass + default: + // pass + } + } + } + } + + public void setEditor(Editor editor) { + this.editor = editor; + } +} diff --git a/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/EditorSimulator.java b/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/EditorSimulator.java new file mode 100644 index 0000000000..967537e4b9 --- /dev/null +++ b/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/EditorSimulator.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://wso2.com) All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.ballerinalang.langserver.simulator; + +import io.ballerina.compiler.syntax.tree.ModuleMemberDeclarationNode; +import io.ballerina.compiler.syntax.tree.ModulePartNode; +import io.ballerina.compiler.syntax.tree.NodeList; +import io.ballerina.tools.text.LinePosition; +import org.ballerinalang.langserver.simulator.generators.Generators; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.SecureRandom; +import java.time.Instant; +import java.util.Arrays; +import java.util.List; +import java.util.Random; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * The main class to simulate the behavior of language server. Similarly to how vscode client use LSP to send different + * updates, this sends similar messages via JSON RPC to the language server. + * + * @since 2201.8.0 + */ +public class EditorSimulator { + + private static final Logger logger = LoggerFactory.getLogger(EditorSimulator.class); + + private static final String PROP_DURATION = "ls.simulation.duration"; + public static final String PROP_SOURCE_DIR = "ls.simulation.src"; + + private static final SecureRandom random = new SecureRandom(); + + public static void main(String[] args) throws IOException { + try { + run(); + } catch (Exception e) { + logger.error("Error occurred while running the simulator", e); + throw e; + } + } + + public static void run() throws IOException { + int durationSeconds = Integer.parseInt(System.getProperty(PROP_DURATION, "60")) * 60; + String projectPath = System.getProperty(PROP_SOURCE_DIR); + if (projectPath == null) { + throw new IllegalArgumentException("No ballerina project path provided"); + } + + Path path = Paths.get(projectPath); + logger.info("Using project: {}, path: {}", path.toString(), projectPath); + + List balFiles = Files.list(path) + .filter(Files::isRegularFile) + .filter(p -> p.getFileName() != null) + .filter(p -> p.getFileName().toString().endsWith(".bal")) + .collect(Collectors.toList()); + + if (balFiles.isEmpty()) { + throw new IllegalArgumentException("No bal files found in the provided directory"); + } + + Path modulesPath = path.resolve("modules"); + if (Files.exists(modulesPath)) { + Files.list(modulesPath) + .filter(Files::isDirectory) + .flatMap(modPath -> { + try { + return Files.list(modPath) + .filter(Files::isRegularFile) + .filter(p -> p.getFileName() != null) + .filter(p -> p.getFileName().toString().endsWith(".bal")); + } catch (IOException e) { + logger.error("Unable to read path: {}", modPath); + return Stream.empty(); + } + }) + .forEach(balFiles::add); + } + + logger.info("Found bal files in project: {}", balFiles.stream() + .map(Path::toString).collect(Collectors.joining("\n"))); + + Editor editor = Editor.open(); + Runtime.getRuntime().addShutdownHook(new Thread(editor::close)); + + long endTime = Instant.now().getEpochSecond() + durationSeconds; + while (Instant.now().getEpochSecond() < endTime) { + int i = random.nextInt(balFiles.size()); + Path balFile = balFiles.get(i); + EditorTab editorTab = editor.openFile(balFile); + + logger.info("Generating random code snippet"); + // Get random generator type + Generators.Type type = getRandomGenerator(); + logger.info("Generating snippet of type: {}", type); + String content = Generators.generate(type); + + if (type == Generators.Type.IMPORT_STATEMENT) { + // Set cursor to start of the file + editorTab.cursor(0, 0); + } else { + // Select a random place to type random code + ModulePartNode modulePartNode = editorTab.syntaxTree().rootNode(); + NodeList members = modulePartNode.members(); + ModuleMemberDeclarationNode moduleMemberDeclarationNode = members.get(random.nextInt(members.size())); + LinePosition linePosition = moduleMemberDeclarationNode.location().lineRange().startLine(); + // Set cursor to start of random node + editorTab.cursor(linePosition.line(), linePosition.offset()); + } + + logger.info("Typing in editor tab: {} -> {}", editorTab, content); + CompletableFuture future = CompletableFuture.runAsync(() -> { + editorTab.type(content); + editorTab.completions(); + }); + + // While the snippet is being typed, check if we have reached a timeout + while (!future.isDone() && Instant.now().getEpochSecond() < endTime) { + logger.info("Remaining time: {}", endTime - Instant.now().getEpochSecond()); + try { + Thread.sleep(60 * 1000L); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + logger.warn("Interrupted editing", e); + break; + } + } + + try { + int sleepSecs = 1 + random.nextInt(5); + Thread.sleep(sleepSecs * 1000L); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + logger.warn("Interrupted simulation", e); + break; + } + } + + logger.info("Exiting..."); + editor.close(); + System.exit(0); + } + + /** + * Generate a random syntax tree node (top level) to be inserted to the source document. + * + * @return Source for a random top level node. + */ + public static Generators.Type getRandomGenerator() { + List types = Arrays.stream(Generators.Type.values()) + .filter(Generators.Type::isTopLevelNode) + .collect(Collectors.toList()); + + // Get random generator + return types.get(random.nextInt(types.size())); + } +} diff --git a/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/EditorTab.java b/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/EditorTab.java new file mode 100644 index 0000000000..ca69e276d7 --- /dev/null +++ b/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/EditorTab.java @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://wso2.com) All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.ballerinalang.langserver.simulator; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import io.ballerina.compiler.syntax.tree.SyntaxTree; +import io.ballerina.projects.Document; +import io.ballerina.tools.text.LinePosition; +import io.ballerina.tools.text.TextDocument; +import io.ballerina.tools.text.TextDocumentChange; +import io.ballerina.tools.text.TextDocuments; +import io.ballerina.tools.text.TextEdit; +import io.ballerina.tools.text.TextRange; +import org.ballerinalang.langserver.BallerinaLanguageServer; +import org.ballerinalang.langserver.util.TestUtil; +import org.eclipse.lsp4j.CodeActionContext; +import org.eclipse.lsp4j.Position; +import org.eclipse.lsp4j.Range; +import org.eclipse.lsp4j.jsonrpc.Endpoint; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.SecureRandom; +import java.util.Collections; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +/** + * Represents a tab in the {@link Editor}. Simulates the behavior of cursor and current text in the document. + * + * @since 2201.8.0 + */ +public class EditorTab { + + private static final Logger logger = LoggerFactory.getLogger(EditorTab.class); + + private final Path filePath; + private final Endpoint endpoint; + private final BallerinaLanguageServer languageServer; + + private TextDocument textDocument; + private Position cursor; + + private final SecureRandom random = new SecureRandom(); + private final PrintWriter writer = new PrintWriter(System.out, true, Charset.defaultCharset()); + + public EditorTab(Path filePath, Endpoint endpoint, BallerinaLanguageServer languageServer) { + this.filePath = filePath; + this.endpoint = endpoint; + this.languageServer = languageServer; + try { + String content = Files.readString(filePath); + this.textDocument = TextDocuments.from(content); + logger.info("Opening document: {}", filePath); + TestUtil.openDocument(endpoint, filePath); + LinePosition linePosition = textDocument.linePositionFrom(content.length() - 1); + cursor(linePosition.line(), linePosition.offset()); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + } + + /** + * Simulates a user typing the provided content in the editor. Content is typed character by character similarly to + * how a user does it. + * + * @param content Text content to be typed in the editor. + */ + public void type(String content) { + int missCount = 0; + for (int i = 0; i < content.length(); i++) { + String typedChar = Character.toString(content.charAt(i)); + + int startOffset = textDocument.textPositionFrom(LinePosition.from(cursor.getLine(), cursor.getCharacter())); + TextEdit edit = TextEdit.from(TextRange.from(startOffset, 0), typedChar); + TextDocumentChange change = TextDocumentChange.from(new TextEdit[]{edit}); + textDocument = textDocument.apply(change); + + LinePosition newLinePos = textDocument.linePositionFrom(startOffset + 1); + try { + TestUtil.didChangeDocument(this.endpoint, this.filePath, textDocument.toString()); + } catch (Throwable t) { + logger.error("Caught error in didChange", t); + } + cursor(newLinePos.line(), newLinePos.offset()); + + if (i % 10 == 0) { + float completionPercentage = ((float) i / (float) content.length()) * 100; + writer.printf("%.1f%%\r", completionPercentage); + } + + // Get completions in the background + if (i % 3 == 0) { + CompletableFuture.runAsync(this::completions); + CompletableFuture.runAsync(this::codeActions); + } + + if (isDocumentNotInSync()) { + missCount++; + } + + try { + Thread.sleep(100 + (long) random.nextInt(300)); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + logger.error("Interrupted", e); + break; + } + } + logger.info("Typed provided content in file: {} -> \n{}", + filePath, content.substring(0, Math.min(20, content.length()))); + logger.info("Typed {} characters with {} out of sync scenarios", content.length(), missCount); + + while (isDocumentNotInSync()) { + logger.info("Document out of sync. Waiting 30 seconds and syncing..."); + try { + Thread.sleep(30 * (long) 1000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + break; + } + TestUtil.didChangeDocument(this.endpoint, this.filePath, textDocument.toString()); + } + } + + /** + * Check if the document in this instance is similar to that is in the language server. + * + * @return True if the document content is not equal to that in workspace manager + */ + private boolean isDocumentNotInSync() { + Optional document = languageServer.getWorkspaceManager().document(filePath); + if (document.isPresent()) { + return !document.get().textDocument().toString().equals(textDocument.toString()); + } else { + logger.warn("Document not found in workspace manager: {}", filePath); + } + + return true; + } + + /** + * Get completions for the current cursor position. + */ + public void completions() { + String completionResponse = TestUtil.getCompletionResponse(filePath.toString(), cursor, endpoint, ""); + JsonObject json = JsonParser.parseString(completionResponse).getAsJsonObject(); + boolean hasError = false; + String resultProp = "result"; + if (json.has(resultProp) && json.get(resultProp).isJsonObject()) { + JsonObject result = json.getAsJsonObject(resultProp); + if (!result.has("left") || !result.get("left").isJsonArray()) { + hasError = true; + } + } else { + hasError = true; + } + + if (hasError) { + logger.warn("Completion request unsuccessful! cursor: {} -> {}", filePath, cursor); + } + } + + /** + * Get code actions for the current cursor position. + */ + public void codeActions() { + CodeActionContext codeActionContext = new CodeActionContext(Collections.emptyList()); + Range range = new Range(cursor, cursor); + TestUtil.getCodeActionResponse(endpoint, filePath.toString(), range, codeActionContext); + } + + public void cursor(int line, int offset) { + this.cursor = new Position(line, offset); + } + + public Position cursor() { + return this.cursor; + } + + public SyntaxTree syntaxTree() { + return SyntaxTree.from(textDocument); + } + + public TextDocument textDocument() { + return textDocument; + } + + public Path filePath() { + return filePath; + } + + public void close() { + logger.info("Closing document: {}", filePath()); + TestUtil.closeDocument(endpoint, filePath()); + } + + @Override + public String toString() { + return "EditorTab{" + + "filePath=" + filePath + + ", cursor=(" + cursor.getLine() + ", " + cursor.getCharacter() + ")" + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + EditorTab editorTab = (EditorTab) o; + return Objects.equals(filePath, editorTab.filePath); + } + + @Override + public int hashCode() { + return Objects.hash(filePath); + } +} diff --git a/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/generators/ClassGenerator.java b/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/generators/ClassGenerator.java new file mode 100644 index 0000000000..e176d36f80 --- /dev/null +++ b/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/generators/ClassGenerator.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://wso2.com) All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.ballerinalang.langserver.simulator.generators; + +import org.ballerinalang.annotation.JavaSPIService; + +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +/** + * Class code snippet generator. + * + * @since 2201.8.0 + */ +@JavaSPIService("org.ballerinalang.langserver.org.ballerinalang.langserver.simulator.generators.CodeSnippetGenerator") +public class ClassGenerator extends CodeSnippetGenerator { + + @Override + public String generate() { + return generateRandomClass(); + } + + @Override + public Generators.Type type() { + return Generators.Type.CLASS; + } + + private String generateRandomClass() { + FunctionGenerator functionGenerator = Generators.getGenerator(Generators.Type.FUNCTION); + + int numOfFunctions = 1 + random.nextInt(100); + String body = IntStream.range(0, numOfFunctions) + .mapToObj(i -> functionGenerator.generateRandomFunction("fn" + i, "string")) + .collect(Collectors.joining("\n")); + return "class AClass {\n" + + " " + body + "\n" + + "}"; + } +} diff --git a/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/generators/CodeSnippetGenerator.java b/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/generators/CodeSnippetGenerator.java new file mode 100644 index 0000000000..97eec1ba36 --- /dev/null +++ b/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/generators/CodeSnippetGenerator.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://wso2.com) All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.ballerinalang.langserver.simulator.generators; + +import java.security.SecureRandom; +import java.util.List; + +/** + * Abstract implementation of code snippet generator for the LS simulator. + * + * @since 2201.8.0 + */ +public abstract class CodeSnippetGenerator { + + protected final List primitiveTypes = List.of("string", "int", "float", "decimal", "boolean"); + protected SecureRandom random = new SecureRandom(); + + public abstract String generate(); + + public abstract Generators.Type type(); +} diff --git a/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/generators/FunctionGenerator.java b/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/generators/FunctionGenerator.java new file mode 100644 index 0000000000..41a5ebd030 --- /dev/null +++ b/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/generators/FunctionGenerator.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://wso2.com) All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.ballerinalang.langserver.simulator.generators; + +import org.ballerinalang.annotation.JavaSPIService; + +/** + * Function code snippet generator. + * + * @since 2201.8.0 + */ +@JavaSPIService("org.ballerinalang.langserver.org.ballerinalang.langserver.simulator.generators.CodeSnippetGenerator") +public class FunctionGenerator extends CodeSnippetGenerator { + + @Override + public String generate() { + return generateRandomFunction(); + } + + @Override + public Generators.Type type() { + return Generators.Type.FUNCTION; + } + + public String generateRandomFunction() { + String name = "fn"; + String returnType = "string"; + return generateRandomFunction(name, returnType); + } + + public String generateRandomFunction(String name, String returnType) { + return "\npublic function " + name + "() returns " + returnType + " {\n" + + " " + getRandomFunctionBody(returnType) + "\n" + + "}\n"; + } + + public String getRandomFunctionBody(String returnType) { + StatementGenerator statementGenerator = Generators.getGenerator(Generators.Type.STATEMENT); + String body = ""; + body += "\t" + statementGenerator.getRandomStatement(); + body += "\t" + statementGenerator.getRandomStatement(); + body += "\t" + statementGenerator.getRandomStatement(); + body += "\treturn " + returnType + ";"; + return body; + } +} diff --git a/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/generators/Generators.java b/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/generators/Generators.java new file mode 100644 index 0000000000..f0865c11f8 --- /dev/null +++ b/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/generators/Generators.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://wso2.com) All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.ballerinalang.langserver.simulator.generators; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.EnumMap; +import java.util.ServiceLoader; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Factory to access {@link CodeSnippetGenerator}s. + * + * @since 2201.8.0 + */ +public class Generators { + + private static final Logger logger = LoggerFactory.getLogger(Generators.class); + private static final String PROP_SKIPPED_GENERATORS = "ls.simulation.skipGenerators"; + private static final Generators instance = new Generators(); + private final EnumMap GENERATORS; + + private Generators() { + // Get skipped generators + String property = System.getProperty(PROP_SKIPPED_GENERATORS, ""); + Set skippedGenerators = Stream.of(property.split(",")) + .filter(type -> !type.isBlank()) + .map(Type::valueOf) + .collect(Collectors.toSet()); + logger.info("Skipping generators of type: " + skippedGenerators); + + // Load generators + GENERATORS = new EnumMap<>(Generators.Type.class); + ServiceLoader.load(CodeSnippetGenerator.class) + .forEach(generator -> { + if (!skippedGenerators.contains(generator.type())) { + GENERATORS.put(generator.type(), generator); + } + }); + } + + /** + * Generate a code snippet of provided type. + * + * @param type Type of the required code snippet. + * @return Generated code snippet. + */ + public static String generate(Type type) { + if (getInstance().GENERATORS.containsKey(type)) { + return instance.GENERATORS.get(type).generate(); + } + + return ""; + } + + public static T getGenerator(Type type) { + return (T) instance.GENERATORS.get(type); + } + + public static Generators getInstance() { + return instance; + } + + /** + * Different types of code snippets which can be generated. + */ + public enum Type { + FUNCTION(true), + CLASS(true), + SERVICE(true), + TYPE_DEFINITION(true), + STATEMENT(false), + MATCH_STATEMENT(false), + VARIABLE_DECLARATION_STATEMENT(true), + IMPORT_STATEMENT(true); + + private final boolean topLevelNode; + + Type(boolean topLevelNode) { + this.topLevelNode = topLevelNode; + } + + public boolean isTopLevelNode() { + return topLevelNode; + } + } +} diff --git a/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/generators/ImportStatementGenerator.java b/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/generators/ImportStatementGenerator.java new file mode 100644 index 0000000000..b706507962 --- /dev/null +++ b/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/generators/ImportStatementGenerator.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://wso2.com) All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.ballerinalang.langserver.simulator.generators; + +import org.ballerinalang.annotation.JavaSPIService; +import org.ballerinalang.langserver.simulator.EditorSimulator; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Import statement snippet generator. + * + * @since 2201.8.0 + */ +@JavaSPIService("org.ballerinalang.langserver.org.ballerinalang.langserver.simulator.generators.CodeSnippetGenerator") +public class ImportStatementGenerator extends CodeSnippetGenerator { + + private static final String PACKAGE_NAME = "nballerina"; + + @Override + public String generate() { + //Look for modules in the source and generate import statements for them. + String projectPath = System.getProperty(EditorSimulator.PROP_SOURCE_DIR); + if (projectPath == null) { + return ""; + } + Path path = Paths.get(projectPath); + Path modulesPath = path.resolve("modules"); + if (Files.exists(modulesPath)) { + try (Stream paths = Files.list(modulesPath)) { + List imports = paths.filter(Files::isDirectory) + .map(p -> "import " + PACKAGE_NAME + "." + p.getFileName() + ";") + .collect(Collectors.toList()); + if (!imports.isEmpty()) { + return imports.get(random.nextInt(imports.size())); + } + } catch (IOException e) { + //ignore + } + } + return ""; + } + + @Override + public Generators.Type type() { + return Generators.Type.IMPORT_STATEMENT; + } +} diff --git a/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/generators/MatchStatementGenerator.java b/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/generators/MatchStatementGenerator.java new file mode 100644 index 0000000000..34d20c7b0e --- /dev/null +++ b/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/generators/MatchStatementGenerator.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://wso2.com) All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.ballerinalang.langserver.simulator.generators; + +import org.ballerinalang.annotation.JavaSPIService; + +/** + * Match statement code snippet generator. + * + * @since 2201.8.0 + */ +@JavaSPIService("org.ballerinalang.langserver.org.ballerinalang.langserver.simulator.generators.CodeSnippetGenerator") +public class MatchStatementGenerator extends CodeSnippetGenerator { + + /** + * Generates a match statement. + * + * @return Match statement + */ + @Override + public String generate() { + // This statement has intentionally added syntax errors. + return "\nmatch t {\n" + + " () => {\n}" + + " [1, 2] => {\n}" + + " [1, 2, 10] => {\n}" + + " [int => {\n" + + " _ => {\n}" + + "}\n"; + } + + @Override + public Generators.Type type() { + return Generators.Type.MATCH_STATEMENT; + } +} diff --git a/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/generators/ServiceGenerator.java b/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/generators/ServiceGenerator.java new file mode 100644 index 0000000000..76cb513ad9 --- /dev/null +++ b/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/generators/ServiceGenerator.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://wso2.com) All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.ballerinalang.langserver.simulator.generators; + +import org.ballerinalang.annotation.JavaSPIService; + +/** + * Service code snippet generator. + * + * @since 2201.8.0 + */ +@JavaSPIService("org.ballerinalang.langserver.org.ballerinalang.langserver.simulator.generators.CodeSnippetGenerator") +public class ServiceGenerator extends CodeSnippetGenerator { + + @Override + public String generate() { + return generateRandomService(); + } + + @Override + public Generators.Type type() { + return Generators.Type.SERVICE; + } + + public String generateRandomService() { + return "\nservice /context1 on new http:Listener(8080) {\n" + + " resource function get path1(http:Caller caller, http:Request req) {\n" + + " \n" + + " }\n" + + "}\n"; + } +} diff --git a/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/generators/StatementGenerator.java b/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/generators/StatementGenerator.java new file mode 100644 index 0000000000..31e4093695 --- /dev/null +++ b/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/generators/StatementGenerator.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://wso2.com) All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.ballerinalang.langserver.simulator.generators; + +import org.ballerinalang.annotation.JavaSPIService; + +/** + * Statement code snippet generator. + * + * @since 2201.8.0 + */ +@JavaSPIService("org.ballerinalang.langserver.org.ballerinalang.langserver.simulator.generators.CodeSnippetGenerator") +public class StatementGenerator extends CodeSnippetGenerator { + + @Override + public String generate() { + return getRandomStatement(); + } + + @Override + public Generators.Type type() { + return Generators.Type.STATEMENT; + } + + public String getRandomStatement() { + switch (random.nextInt(2)) { + case 0: + return Generators.generate(Generators.Type.MATCH_STATEMENT); + case 1: + default: + return Generators.generate(Generators.Type.VARIABLE_DECLARATION_STATEMENT); + } + } + +} diff --git a/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/generators/TypeDefinitionGenerator.java b/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/generators/TypeDefinitionGenerator.java new file mode 100644 index 0000000000..07d20d2893 --- /dev/null +++ b/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/generators/TypeDefinitionGenerator.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://wso2.com) All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.ballerinalang.langserver.simulator.generators; + +import org.ballerinalang.annotation.JavaSPIService; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Type definition code snippet generator. + * + * @since 2201.8.0 + */ +@JavaSPIService("org.ballerinalang.langserver.org.ballerinalang.langserver.simulator.generators.CodeSnippetGenerator") +public class TypeDefinitionGenerator extends CodeSnippetGenerator { + + private final List generatedTypeDefNames = new ArrayList<>(); + private int typeCount = 0; + + @Override + public String generate() { + switch (random.nextInt(3)) { + case 1: + return generateUnionType(); + case 2: + return generateRecordType(); + case 3: + default: + return generateObjectTypeDef(); + } + } + + public String generateRecordType() { + String typeName = "Rec" + typeCount; + + List fields = new ArrayList<>(); + for (int i = 0; i < 2 + random.nextInt(100); i++) { + String field; + if (random.nextBoolean() || generatedTypeDefNames.isEmpty()) { + field = String.format("\t%s field%d;", primitiveTypes.get(random.nextInt(primitiveTypes.size())), i); + } else { + field = String.format("\t%s field%d;", + generatedTypeDefNames.get(random.nextInt(generatedTypeDefNames.size())), i); + } + fields.add(field); + } + + typeCount++; + generatedTypeDefNames.add(typeName); + return String.format("%ntype %s {|%n%s%n|};%n", typeName, String.join("\n", fields)); + } + + public String generateUnionType() { + // Member types + Set memberTypes = new HashSet<>(); + for (int i = 0; i < 2 + random.nextInt(3); i++) { + String memberType; + do { + if (random.nextBoolean() || generatedTypeDefNames.isEmpty()) { + memberType = primitiveTypes.get(random.nextInt(primitiveTypes.size())); + } else { + memberType = generatedTypeDefNames.get(random.nextInt(generatedTypeDefNames.size())); + } + } while (memberTypes.contains(memberType)); + memberTypes.add(memberType); + } + + String typeName = "Type" + typeCount; + typeCount++; + generatedTypeDefNames.add(typeName); + return String.format("%ntype %s %s;%n", typeName, String.join(" | ", memberTypes)); + } + + public String generateObjectTypeDef() { + String typeName = "ObjectDef" + typeCount; + typeCount++; + generatedTypeDefNames.add(typeName); + return "\ntype " + typeName + " object {\n" + + "\n\tpublic function doSomething() returns UnkType;\n" + + "};\n"; + } + + @Override + public Generators.Type type() { + return Generators.Type.TYPE_DEFINITION; + } +} diff --git a/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/generators/VarDeclarationStatementGenerator.java b/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/generators/VarDeclarationStatementGenerator.java new file mode 100644 index 0000000000..5eaf6a41da --- /dev/null +++ b/language-server-simulator/src/main/java/org/ballerinalang/langserver/simulator/generators/VarDeclarationStatementGenerator.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://wso2.com) All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.ballerinalang.langserver.simulator.generators; + +import org.ballerinalang.annotation.JavaSPIService; + +/** + * Variable declaration code snippet generator. + * + * @since 2.0.0 + */ +@JavaSPIService("org.ballerinalang.langserver.org.ballerinalang.langserver.simulator.generators.CodeSnippetGenerator") +public class VarDeclarationStatementGenerator extends CodeSnippetGenerator { + + private int varCount = 0; + + public String generate() { + varCount++; + return String.format("%n%s %s = createVar();%n", + primitiveTypes.get(random.nextInt(primitiveTypes.size())), "myVar" + varCount); + } + + @Override + public Generators.Type type() { + return Generators.Type.VARIABLE_DECLARATION_STATEMENT; + } +} diff --git a/language-server-simulator/src/main/resources/META-INF/services/org.ballerinalang.langserver.simulator.generators.CodeSnippetGenerator b/language-server-simulator/src/main/resources/META-INF/services/org.ballerinalang.langserver.simulator.generators.CodeSnippetGenerator new file mode 100644 index 0000000000..003b872e40 --- /dev/null +++ b/language-server-simulator/src/main/resources/META-INF/services/org.ballerinalang.langserver.simulator.generators.CodeSnippetGenerator @@ -0,0 +1,8 @@ +org.ballerinalang.langserver.simulator.generators.VarDeclarationStatementGenerator +org.ballerinalang.langserver.simulator.generators.TypeDefinitionGenerator +org.ballerinalang.langserver.simulator.generators.StatementGenerator +org.ballerinalang.langserver.simulator.generators.ImportStatementGenerator +org.ballerinalang.langserver.simulator.generators.ServiceGenerator +org.ballerinalang.langserver.simulator.generators.ClassGenerator +org.ballerinalang.langserver.simulator.generators.MatchStatementGenerator +org.ballerinalang.langserver.simulator.generators.FunctionGenerator diff --git a/project-api-tests/build.gradle b/project-api-tests/build.gradle index a6b152fb35..06b8e8648a 100644 --- a/project-api-tests/build.gradle +++ b/project-api-tests/build.gradle @@ -31,6 +31,7 @@ dependencies { testImplementation "net.lingala.zip4j:zip4j:${netLingalaZip4jVersion}" testImplementation "commons-io:commons-io:${commonsIoVersion}" testImplementation "org.apache.commons:commons-lang3:${commonsLang3Version}" + testImplementation "org.ballerinalang:ballerina-lang:${ballerinaLangVersion}" testImplementation "org.ballerinalang:jballerina-debugger-integration-test:${ballerinaLangVersion}" testImplementation "org.ballerinalang:ballerina-test-utils:${ballerinaLangVersion}" testImplementation "org.eclipse.lsp4j:org.eclipse.lsp4j.debug:${lsp4jDebugVersion}" @@ -48,7 +49,6 @@ task centralTests { dependsOn configurations.jBallerinaDistribution dependsOn configurations.ballerinaDistribution dependsOn configurations.ballerinaLinuxDistribution - dependsOn configurations.ballerinaLinuxDistribution dependsOn configurations.ballerinaWindowsDistribution test { systemProperty "distributions.dir", "$buildDir/../../ballerina/build/distributions" @@ -69,4 +69,41 @@ task centralTests { } } -test.dependsOn centralTests + + task checkURL { + doLast { + try { + URL url = new URL("${devIdpUrl}") + HttpURLConnection connection = (HttpURLConnection) url.openConnection() + connection.setRequestMethod("GET") + connection.connect() + + int code = connection.getResponseCode() + if (code == 200) { + logger.lifecycle("Connection to ${devIdpUrl} is successful. Running tests...") + ext.isURLAvailable = true + } else { + logger.lifecycle("Connection to ${devIdpUrl} is not successful. Skipping tests...") + logger.lifecycle("-----------------------------------------") + logger.lifecycle(" WARNING: Skipping the project api tests") + logger.lifecycle("-----------------------------------------") + ext.isURLAvailable = false + } + } catch(Exception ex) { + logger.lifecycle("Connection to ${devIdpUrl} is not successful. Exception while connecting to " + + "${devIdpUrl}. Skipping tests...") + logger.lifecycle("-----------------------------------------") + logger.lifecycle(" WARNING: Skipping the project api tests") + logger.lifecycle("-----------------------------------------") + ext.isURLAvailable = false + } + } + } + + test { + dependsOn checkURL + onlyIf { + checkURL.isURLAvailable + } + dependsOn centralTests + } diff --git a/project-api-tests/src/test/java/org/ballerina/projectapi/CentralTest.java b/project-api-tests/src/test/java/org/ballerina/projectapi/CentralTest.java index 8389f9d1f3..c9bbab97de 100644 --- a/project-api-tests/src/test/java/org/ballerina/projectapi/CentralTest.java +++ b/project-api-tests/src/test/java/org/ballerina/projectapi/CentralTest.java @@ -41,7 +41,7 @@ import static org.ballerina.projectapi.CentralTestUtils.ANY_PLATFORM; import static org.ballerina.projectapi.CentralTestUtils.BALLERINA_TOML; import static org.ballerina.projectapi.CentralTestUtils.COMMON_VERSION; -import static org.ballerina.projectapi.CentralTestUtils.JAVA11_PLATFORM; +import static org.ballerina.projectapi.CentralTestUtils.JAVA_PLATFORM; import static org.ballerina.projectapi.CentralTestUtils.MAIN_BAL; import static org.ballerina.projectapi.CentralTestUtils.OUTPUT_NOT_CONTAINS_EXP_MSG; import static org.ballerina.projectapi.CentralTestUtils.PULLED_FROM_CENTRAL_MSG; @@ -195,7 +195,7 @@ public void testPushPackageA() throws IOException, InterruptedException { } } - @Test(description = "Build package B which has java11 platform dependency") + @Test(description = "Build package B which has java17 platform dependency") public void testBuildPackageB() throws IOException, InterruptedException { Process build = executePackCommand(DISTRIBUTION_FILE_NAME, this.tempWorkspaceDirectory.resolve(PROJECT_B), new LinkedList<>(), this.envVariables); @@ -206,12 +206,12 @@ public void testBuildPackageB() throws IOException, InterruptedException { } String buildOutput = getString(build.getInputStream()); - if (!buildOutput.contains(getGenerateBalaLog(orgName, this.packageBName, JAVA11_PLATFORM, COMMON_VERSION))) { - Assert.fail(OUTPUT_NOT_CONTAINS_EXP_MSG + getGenerateBalaLog(orgName, this.packageBName, JAVA11_PLATFORM, + if (!buildOutput.contains(getGenerateBalaLog(orgName, this.packageBName, JAVA_PLATFORM, COMMON_VERSION))) { + Assert.fail(OUTPUT_NOT_CONTAINS_EXP_MSG + getGenerateBalaLog(orgName, this.packageBName, JAVA_PLATFORM, COMMON_VERSION)); } Assert.assertTrue( - getBalaPath(this.tempWorkspaceDirectory.resolve(PROJECT_B), orgName, this.packageBName, JAVA11_PLATFORM, + getBalaPath(this.tempWorkspaceDirectory.resolve(PROJECT_B), orgName, this.packageBName, JAVA_PLATFORM, COMMON_VERSION).toFile().exists()); } diff --git a/project-api-tests/src/test/java/org/ballerina/projectapi/CentralTestUtils.java b/project-api-tests/src/test/java/org/ballerina/projectapi/CentralTestUtils.java index c26bf8b31f..4c4b974da9 100644 --- a/project-api-tests/src/test/java/org/ballerina/projectapi/CentralTestUtils.java +++ b/project-api-tests/src/test/java/org/ballerina/projectapi/CentralTestUtils.java @@ -65,7 +65,7 @@ private CentralTestUtils() { static final String COMMON_VERSION = "1.0.0"; static final String TEST_PREFIX = "test_"; static final String ANY_PLATFORM = "any"; - static final String JAVA11_PLATFORM = "java11"; + static final String JAVA_PLATFORM = "java17"; static final String BALLERINA_ARTIFACT_TYPE = "bala"; static final String OUTPUT_NOT_CONTAINS_EXP_MSG = "build output does not contain expected message:"; static final String PULLED_FROM_CENTRAL_MSG = " pulled from central successfully"; diff --git a/project-api-tests/src/test/resources/central/projectB/Ballerina.toml b/project-api-tests/src/test/resources/central/projectB/Ballerina.toml index 4ee7faa566..29be49ed1b 100644 --- a/project-api-tests/src/test/resources/central/projectB/Ballerina.toml +++ b/project-api-tests/src/test/resources/central/projectB/Ballerina.toml @@ -3,7 +3,10 @@ org = "bctestorg" name = "my_package" version = "1.0.0" -[[platform.java11.dependency]] +[platform.java17] +graalvmCompatible=true + +[[platform.java17.dependency]] groupId = "org.slf4j" artifactId = "slf4j-api" version = "1.7.30" diff --git a/resources/tools/INSTALL.txt b/resources/tools/INSTALL.txt index 72a091a2fb..99158fd75b 100644 --- a/resources/tools/INSTALL.txt +++ b/resources/tools/INSTALL.txt @@ -5,8 +5,8 @@ PREREQUISITES ------------- -Ballerina requires JRE 11. -Check https://adoptopenjdk.net/releases.html?variant=openjdk11&jvmVariant=hotspot to download the JRE relevant to your system. +Ballerina requires JRE 17. +Check https://adoptopenjdk.net/releases.html?variant=openjdk17&jvmVariant=hotspot to download the JRE relevant to your system. This is the Java version we have used when testing Ballerina. @@ -20,14 +20,14 @@ INSTALLING BALLERINA - Add the `/bin` path to your system's path variable. -- If you have installed Java 11 already, you are all set! Just make sure that the JAVA_HOME environment variable is set correctly. +- If you have installed Java 17 already, you are all set! Just make sure that the JAVA_HOME environment variable is set correctly. -- If you do not have Java 11 or if you have a different version of Java, download a compatible JRE 11 version as specified in the prerequisites. +- If you do not have Java 17 or if you have a different version of Java, download a compatible JRE 17 version as specified in the prerequisites. - - To set the obtained JRE as the one used by Ballerina, extract the downloaded JRE `zip/tar.gz` to the `/dependencies/jdk-11.0.8+10-jre` directory. + - To set the obtained JRE as the one used by Ballerina, extract the downloaded JRE `zip/tar.gz` to the `/dependencies/jdk-17.0.7+7-jre` directory. - Once you are done, the directory structure should look exactly like the following: /dependencies/ - └── jdk-11.0.8+10-jre + └── jdk-17.0.7+7-jre ├── bin ├── bundle ├── conf @@ -35,7 +35,7 @@ INSTALLING BALLERINA ├── lib ├── man └── release - - Ensure that the directory which contains the JRE is named "jdk-11.0.8+10-jre" + - Ensure that the directory which contains the JRE is named "jdk-17.0.7+7-jre" - Finally, to verify whether Ballerina is installed properly, you can run the `bal version` command. If Ballerina was installed correctly, you should see an output similar to the following: $ bal version diff --git a/settings.gradle b/settings.gradle index c4c06eaa4c..2eb3751824 100644 --- a/settings.gradle +++ b/settings.gradle @@ -16,7 +16,7 @@ */ plugins { - id "com.gradle.enterprise" version "3.2" + id "com.gradle.enterprise" version "3.13.2" } rootProject.name = 'ballerina-distribution' @@ -41,4 +41,5 @@ gradleEnterprise { termsOfServiceAgree = 'yes' } } +include 'language-server-simulator' diff --git a/stdlib-integration-tests/oauth2/tests/oauth2_test.bal b/stdlib-integration-tests/oauth2/tests/oauth2_test.bal index ba260299ec..4c9696e9f2 100644 --- a/stdlib-integration-tests/oauth2/tests/oauth2_test.bal +++ b/stdlib-integration-tests/oauth2/tests/oauth2_test.bal @@ -15,7 +15,6 @@ // under the License. import ballerina/http; -import ballerina/regex; import ballerina/test; listener http:Listener oauth2Listener = new(25003, { @@ -93,10 +92,10 @@ service /oauth2 on authorizationServer { resource function post token/introspect(http:Request request) returns json { string|http:ClientError payload = request.getTextPayload(); if (payload is string) { - string[] parts = regex:split(payload, "&"); + string[] parts = re `&`.split(payload); foreach string part in parts { if (part.indexOf("token=") is int) { - string token = regex:split(part, "=")[1]; + string token = re `=`.split(part)[1]; if (token == ACCESS_TOKEN) { json response = { "active": true, "exp": 3600, "scp": "read write" }; return response;