Skip to content

Packaging and Publishing via pipeline

Create an OIDC Service Client:

  • Go to https://developer.bentley.com/my-apps/ and create an OIDC service client. NOTE- clients created in https://imsoidcui.bentley.com/ will not work correctly.
  • Choose “Service” client type.
  • The client is responsible for publishing your apps to the marketplace, so ensure that your client the itwin-platform scope.
  • Make sure to note down the client secret, it will be required later.
  • In your app’s app.config.json, give your app the itwin-platform scope.
  • Separate clients are required for QA and PROD.

Whitelist Your Client ID:

Test the studio-cli apps package command:

  • Prerequisites:
    • @bentley/studio-cli
    • iTwin Studio >= 1.0.34 installed.
  • Build your app with studio-cli apps build.
  • Run studio-cli apps package. Optionally add --dev to include source maps and skip minimization. If packaging for a QA release, add the --forQARelease flag.

This will produce a .zip file named, by default, <appName>-0.0.0.zip. If packaging for a QA release, the name will be prefixed by -qa, i.e. qa-<appName>-0.0.0.zip. The .zip file should contain:

.
├── dist/ // the app's javascript bundle/
│ ├── frontend-bundle.js
│ ├── backend-bundle.js
│ └── assets/
│ └── asset.png
├── app.config.json // the app config file
├── package.json // app's manifest
├── icon.ico // app icon, set in app.config.json
├── install-macos.sh // this is what you click if you have linux or macos
├── install-linux.sh // this is what you click if you have linux
└── install.bat // this is what you click if you have windows

All Studio apps developed inside Bentley should have a “proper” release pipeline in PackagedReleases.

To create a new pipeline, please follow their guidelines and create a help ticket.

Make sure to indicate in the help ticket that the new release pipelines should be created using iTwin Studio app release template.

Example pipeline created like this can be found here.

Pipelines created from this template will:

In addition to the usual GPR variables, the following are required for a successful release:

  • APP_PUBLISHER_CLIENT_ID - separate OIDC clients for QA and PROD (mentioned at the start of this article)
  • APP_PUBLISHER_SECRET - separate OIDC client secrets for QA and PROD (mentioned at the start of this article). Should be a secret variable.
  • APP_NAME - app name from package.json and appId from app.config.json. They should be the same.
  • ARTIFACT_FOLDER - Location where the .zip artifact was published. E.g. if published to $(Build.ArtifactStagingDirectory)/product during build, ARTIFACT_FOLDER should be {Replace with artifact source alias}/product

Other things to keep in mind:

  • Ensure that the version in package.json is bumped after each release. Uploading the same version twice will fail.
  • Ensure that the release pipeline downloads the app .zip artifact for audit and release steps.

Release pipelines not managed by release services

Section titled “Release pipelines not managed by release services”
  • Add the following steps to your pipeline YAML file:

    # ...
    - name: Build iTwin Studio App
    working-directory: ./path/to/my/app # Update this line to the path of your app
    run: pnpm build
    # Package the app.
    # These instructions change depending on the publishing environment.
    # See the "Packaging apps" section below.
    # Sign your apps here before publishing them to the artifacts.
    # See the "Signing apps" section below.
    # Publish the app to the Studio Extensions Marketplace.
    # These instructions change depending on the publishing environment.
    # See the "Publishing apps" section below.
  • Packaging apps:

    • If packaging for QA, the package command should be used in conjunction with the --forQARelease flag, which won’t strip away QA authentication credentials and will output a qa-<appName>-<appVersion>.zip file;

    • Most build pipelines will need to run the package step twice — once for QA and once for PROD.

      # ...
      - name: Package iTwin Studio App
      working-directory: ./path/to/my/app # Update this line to the path of your app
      run: |
      pnpm package
      pnpm package --forQARelease
  • Signing the apps:

    • Code signing is a process in which a software developer or distributor digitally signs a file to verify its integrity and authenticity. This ensures users that the software has not been altered or tampered with, and it operates as the creator intended. The digital signature serves as proof that the code remains in its original form.

      # ...
      # Sign the zips only in master branch before publishing them.
      # Nuget authenticate is necessary since we'll be using internal registry to install the SignToolClient
      - task: NuGetAuthenticate@1
      condition: eq(variables['Build.SourceBranchName'], 'master')
      - task: UseDotNet@2
      condition: eq(variables['Build.SourceBranchName'], 'main')
      displayName: "Use .NET 8 for SignToolClient"
      inputs:
      packageType: "sdk"
      version: "8.x"
      - task: CmdLine@2
      displayName: Install SignToolClient
      condition: eq(variables['Build.SourceBranchName'], 'master')
      inputs:
      script: |
      dotnet tool install --global SignToolClient --add-source https://pkgs.dev.azure.com/bentleycs/_packaging/Packages/nuget/v3/index.json
      - powershell: |
      $files = Get-ChildItem -Path $(Build.ArtifactStagingDirectory)/studioApps -Recurse -Include *.zip
      foreach ($file in $files) {
      # Renaming the zip file to opc is necessary since SignToolClient only signs the opc extension
      $opcFile = $file.FullName -replace '\.zip$', '.opc'
      Rename-Item -Path $file.FullName -NewName $opcFile
      # Signing the apps
      SignToolClient sign $opcFile --service-url https://signingservice.bentley.com --BsiToken $env:BSI_SIGNING_TOKEN --verbosity error
      # Renaming back to .zip so that iTwinStudio can install the app and use it
      $zipFile = $opcFile -replace '\.opc$', '.zip'
      Rename-Item -Path $opcFile -NewName $zipFile
      }
      displayName: Sign studio apps
      condition: eq(variables['Build.SourceBranchName'], 'master')
      env:
      BSI_SIGNING_TOKEN: $(SIGNING_TOKEN)
  • Publishing apps:

    • If the package is being published for QA, the publish command should be used in conjunction with the --env-prefix "qa-" flag. The publish command will look for a .zip file with a certain name, depending on the value of --env-prefix:

      • "qa-": will look for qa-<appName>-<appVersion>.zip;
      • "" or omitted: will look for <appName>-<appVersion>.zip.
      • "dev-": not supported. If you want to release and test your app on DEV, please contact the iTwin Studio team to discuss.
      - name: Publish the app
      working-directory: ./path/to/my/app # Update this line to the path of your app
      run: pnpm publish-app app-name --app-publisher-client-id="${{ secrets.app_publisher_client_id }}" # --env-prefix "qa-" if publishing for the QA environment
      env:
      APP_PUBLISHER_SECRET: ${{ secrets.app_publisher_secret }}

Check App Upload Status:

  • After running the pipeline, you can verify that the app has successfully uploaded.
  • Visit the web portal, click “Try it out,” and enter the extensionId along with the version that you uploaded (as specified in package.json) (you must be logged in to developer.bentley.com).

Use the command iTwinStudio apps install app-name to install Studio Aps from the Studio Extensions Marketplace. The CLI download the Studio apps and install them in your local iTwin Studio instance.

  1. Install iTwin Studio
  2. Enable developer support
  3. From the terminal/command line, run iTwinStudio apps install <full-path-to-zip>.
  4. Run the app by clicking its desktop shortcut. Alternatively, you can run iTwinStudio apps run <appId>.
  5. The app should auto-update when updates are available.

Next: Best practices for iTwin Studio packages