From 12ed4d59256b712c74efcf5aff920494b33c60e5 Mon Sep 17 00:00:00 2001 From: Pierre Jacquier Date: Mon, 5 Aug 2024 11:58:53 -0400 Subject: [PATCH] First steps for electron app build and packaging in Github Actions Builds on the ci.yml refactor started at !2815 commit 6813adf86d1d7b78a9a4e77039313dccd67c3083 Author: Pierre Jacquier Date: Mon Aug 5 11:27:03 2024 -0400 Lint commit fe95e2e1302beb213da9f9bde5feeda255e116fd Author: Pierre Jacquier Date: Mon Aug 5 10:34:34 2024 -0400 Disable sign if not BUILD_RELEASE commit 8f31952e217f1dc1c683705cdb28bdd7042ccdc7 Author: Pierre Jacquier Date: Mon Aug 5 08:31:42 2024 -0400 WIP sign windows commit fbabc874d41e8e57011454afec68c2b4926c842b Author: Pierre Jacquier Date: Mon Aug 5 07:51:20 2024 -0400 WIP macos commit 6a8cc629e45b0c041fb31f1daf5f3a56f10871cc Author: Pierre Jacquier Date: Mon Aug 5 11:15:28 2024 +0000 Change executable name for deb commit b616aece2673086c2bf376d583dd4f0d8c09a23d Author: Pierre Jacquier Date: Mon Aug 5 05:56:26 2024 -0400 WIP macos signing, ubuntu build commit b4c7ac8b9b73d18f26d2d1e7cfe0494e713e5231 Author: Pierre Jacquier Date: Mon Aug 5 05:41:53 2024 -0400 Fix ubuntu target commit 23b694327e2c5ee570257fb66f51ff65b7b6f6f4 Author: Pierre Jacquier Date: Mon Aug 5 05:23:29 2024 -0400 Fix upload for Windows, add ubuntu commit 54df186f632a277e68b280fccd547f83208c2b8b Author: Pierre Jacquier Date: Mon Aug 5 05:00:47 2024 -0400 Fix tsc, remove e2e/tauri tests commit 1c76e793d1b2d8781f5fce7399b3118438331428 Author: Pierre Jacquier Date: Sat Aug 3 08:25:39 2024 -0400 Lint, codespell, remove tauri/wdio ref, add author commit 51e91558978e634677e58c8c7248b0bbda0a82d6 Author: Pierre Jacquier Date: Sat Aug 3 08:11:24 2024 -0400 Add new ci.yml breakdown from pierremtb/issue2805. Windows and macOS only for now --- .codespellrc | 4 +- .github/workflows/build-test-publish-apps.yml | 405 ++++++++++++ .github/workflows/build-test-web.yml | 79 +++ .github/workflows/ci.yml | 586 ------------------ add-osx-cert.sh | 24 + e2e/tauri/specs/app.spec.ts | 155 ----- e2e/tauri/utils.ts | 18 - forge.config.ts | 9 + make-release.sh | 3 +- package.json | 8 +- src/lib/desktop.ts | 6 +- tsconfig.json | 1 - 12 files changed, 529 insertions(+), 769 deletions(-) create mode 100644 .github/workflows/build-test-publish-apps.yml create mode 100644 .github/workflows/build-test-web.yml delete mode 100644 .github/workflows/ci.yml create mode 100644 add-osx-cert.sh delete mode 100644 e2e/tauri/specs/app.spec.ts delete mode 100644 e2e/tauri/utils.ts diff --git a/.codespellrc b/.codespellrc index 335462ff5..b68145ee8 100644 --- a/.codespellrc +++ b/.codespellrc @@ -1,3 +1,3 @@ [codespell] -ignore-words-list: crate,everytime,inout,co-ordinate,ot,nwo,absolutey,atleast,ue,afterall -skip: **/target,node_modules,build,**/Cargo.lock,./docs/kcl/*.md,./src-tauri/gen/schemas +ignore-words-list: crate,everytime,inout,co-ordinate,ot,nwo,absolutey,atleast,ue,afterall skip: +**/target,node_modules,build,**/Cargo.lock,./docs/kcl/*.md,./src-tauri/gen/schemas,.yarn.lock diff --git a/.github/workflows/build-test-publish-apps.yml b/.github/workflows/build-test-publish-apps.yml new file mode 100644 index 000000000..490b0c25d --- /dev/null +++ b/.github/workflows/build-test-publish-apps.yml @@ -0,0 +1,405 @@ +name: build-test-publish-apps + +on: + pull_request: + push: + branches: + - main + - pierremtb/tauri-to-electron-ci + release: + types: [published] + schedule: + - cron: '0 4 * * *' + # Daily at 04:00 AM UTC + # Will checkout the last commit from the default branch (main as of 2023-10-04) + +env: + CUT_RELEASE_PR: ${{ github.event_name == 'pull_request' && (contains(github.event.pull_request.title, 'Cut release v')) }} + BUILD_RELEASE: ${{ github.event_name == 'release' || github.event_name == 'schedule' || github.event_name == 'pull_request' && (contains(github.event.pull_request.title, 'Cut release v')) }} + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + prepare-json-files: + runs-on: ubuntu-22.04 # seperate job on Ubuntu for easy string manipulations (compared to Windows) + outputs: + version: ${{ steps.export_version.outputs.version }} + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: 'yarn' + + - name: Set nightly version + if: github.event_name == 'schedule' + run: | + VERSION=$(date +'%-y.%-m.%-d') yarn bump-jsons + + # TODO: see if we need to inject updater nightly URL here https://dl.zoo.dev/releases/modeling-app/nightly/last_update.json + # TODO: see if we ned to add updater test URL here https://dl.zoo.dev/releases/modeling-app/updater-test/last_update.json + + - uses: actions/upload-artifact@v3 + if: ${{ github.event_name == 'schedule' || env.CUT_RELEASE_PR == 'true' }} + with: + path: | + package.json + + - id: export_version + run: echo "version=`cat package.json | jq -r '.version'`" >> "$GITHUB_OUTPUT" + + + build-test-app-macos: + needs: [prepare-json-files] + runs-on: macos-14 + env: + APPLE_ID: ${{ secrets.APPLE_ID }} + APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }} + APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} + APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} + APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} + APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }} + steps: + - uses: actions/checkout@v4 + + - uses: actions/download-artifact@v3 + if: github.event_name == 'schedule' + + - name: Copy updated .json files + if: github.event_name == 'schedule' + run: | + ls -l artifact + cp artifact/package.json package.json + + - name: Sync node version and setup cache + uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: 'yarn' # Set this to npm, yarn or pnpm. + + - run: yarn install + + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable + + - uses: Swatinem/rust-cache@v2 + with: + workspaces: './src/wasm-lib' + + - name: Run build:wasm + run: "yarn build:wasm${{ env.BUILD_RELEASE == 'true' && '-dev' || ''}}" + + # TODO: sign the app (and updater bundle potentially) + - name: Add signing certificate + if: ${{ env.BUILD_RELEASE == 'true' }} + run: chmod +x add-osx-cert.sh && ./add-osx-cert.sh + + - name: Build the app for arm64 + run: "yarn electron-forge make" + + - name: Build the app for x64 + run: "yarn electron-forge make --arch x64" + + - name: List artifacts + run: "ls -R out/make" + + # TODO: add the 'Build for Mac TestFlight (nightly)' stage back + + - uses: actions/upload-artifact@v3 + with: + path: "out/make/*/*/*/*" + + + build-test-app-windows: + needs: [prepare-json-files] + runs-on: windows-2022 + steps: + - uses: actions/checkout@v4 + + - uses: actions/download-artifact@v3 + + - name: Copy updated .json files + if: github.event_name == 'schedule' + run: | + ls -l artifact + cp artifact/package.json package.json + + - name: Sync node version and setup cache + uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: 'yarn' # Set this to npm, yarn or pnpm. + + - run: yarn install + + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable + + - uses: Swatinem/rust-cache@v2 + with: + workspaces: './src/wasm-lib' + + - name: Run build:wasm manually + shell: bash + env: + MODE: ${{ env.BUILD_RELEASE == 'true' && '--release' || '--debug' }} + run: | + mkdir src/wasm-lib/pkg; cd src/wasm-lib + echo "building with ${{ env.MODE }}" + npx wasm-pack build --target web --out-dir pkg ${{ env.MODE }} + cd ../../ + cp src/wasm-lib/pkg/wasm_lib_bg.wasm public + + - name: Prepare certificate and variables (Windows only) + if: ${{ env.BUILD_RELEASE == 'true' }} + run: | + echo "${{secrets.SM_CLIENT_CERT_FILE_B64 }}" | base64 --decode > /d/Certificate_pkcs12.p12 + cat /d/Certificate_pkcs12.p12 + echo "::set-output name=version::${GITHUB_REF#refs/tags/v}" + echo "SM_HOST=${{ secrets.SM_HOST }}" >> "$GITHUB_ENV" + echo "SM_API_KEY=${{ secrets.SM_API_KEY }}" >> "$GITHUB_ENV" + echo "SM_CLIENT_CERT_FILE=D:\\Certificate_pkcs12.p12" >> "$GITHUB_ENV" + echo "SM_CLIENT_CERT_PASSWORD=${{ secrets.SM_CLIENT_CERT_PASSWORD }}" >> "$GITHUB_ENV" + echo "C:\Program Files (x86)\Windows Kits\10\App Certification Kit" >> $GITHUB_PATH + echo "C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools" >> $GITHUB_PATH + echo "C:\Program Files\DigiCert\DigiCert One Signing Manager Tools" >> $GITHUB_PATH + shell: bash + + - name: Setup certicate with SSM KSP (Windows only) + if: ${{ env.BUILD_RELEASE == 'true' }} + run: | + curl -X GET https://one.digicert.com/signingmanager/api-ui/v1/releases/smtools-windows-x64.msi/download -H "x-api-key:%SM_API_KEY%" -o smtools-windows-x64.msi + msiexec /i smtools-windows-x64.msi /quiet /qn + smksp_registrar.exe list + smctl.exe keypair ls + C:\Windows\System32\certutil.exe -csp "DigiCert Signing Manager KSP" -key -user + smksp_cert_sync.exe + shell: cmd + + - name: Build the app for x64 + run: "yarn electron-forge make --arch x64" + + - name: Build the app for arm64 + run: "yarn electron-forge make --arch arm64" + + - name: List artifacts + run: "ls -R out/make" + + # TODO: sign the app (and updater bundle potentially) + - name: Sign using signtool + if: ${{ env.BUILD_RELEASE == 'true' }} + env: + THUMBPRINT: "F4C9A52FF7BC26EE5E054946F6B11DEEA94C748D" + FILE: "out\\make\\squirrel.windows\\arm64\\Zoo Modeling App-0.24.3 Setup.exe" + run: | + signtool.exe sign /sha1 $THUMBPRINT /tr http://timestamp.digicert.com /td SHA256 /fd SHA256 $FILE + shell: cmd + + - uses: actions/upload-artifact@v3 + with: + path: "out/make/*/*/*" + + # TODO: Run e2e tests + + + build-test-app-ubuntu: + needs: [prepare-json-files] + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + + - uses: actions/download-artifact@v3 + if: github.event_name == 'schedule' + + - name: Copy updated .json files + if: github.event_name == 'schedule' + run: | + ls -l artifact + cp artifact/package.json package.json + + - name: Sync node version and setup cache + uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: 'yarn' # Set this to npm, yarn or pnpm. + + - run: yarn install + + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable + + - uses: Swatinem/rust-cache@v2 + with: + workspaces: './src/wasm-lib' + + - name: Run build:wasm + run: "yarn build:wasm${{ env.BUILD_RELEASE == 'true' && '-dev' || ''}}" + + - name: Build the app for arm64 + run: "yarn electron-forge make --arch arm64" + + - name: Build the app for x64 + run: "yarn electron-forge make --arch x64" + + - name: List artifacts + run: "ls -R out/make" + + # TODO: add the 'Build for Mac TestFlight (nightly)' stage back + + # TODO: sign the app (and updater bundle potentially) + + - uses: actions/upload-artifact@v3 + with: + path: "out/make/*/*/*" + + + publish-apps-release: + runs-on: ubuntu-22.04 + permissions: + contents: write + if: ${{ github.event_name == 'release' || github.event_name == 'schedule' }} + needs: [prepare-json-files, build-test-app-macos, build-test-app-windows, build-test-app-ubuntu] + env: + VERSION_NO_V: ${{ needs.prepare-json-files.outputs.version }} + VERSION: ${{ github.event_name == 'release' && format('v{0}', needs.prepare-json-files.outputs.version) || needs.prepare-json-files.outputs.version }} + PUB_DATE: ${{ github.event_name == 'release' && github.event.release.created_at || github.event.repository.updated_at }} + NOTES: ${{ github.event_name == 'release' && github.event.release.body || format('Nightly build, commit {0}', github.sha) }} + BUCKET_DIR: ${{ github.event_name == 'release' && 'dl.kittycad.io/releases/modeling-app' || 'dl.kittycad.io/releases/modeling-app/nightly' }} + WEBSITE_DIR: ${{ github.event_name == 'release' && 'dl.zoo.dev/releases/modeling-app' || 'dl.zoo.dev/releases/modeling-app/nightly' }} + URL_CODED_NAME: ${{ github.event_name == 'schedule' && 'Zoo%20Modeling%20App%20%28Nightly%29' || 'Zoo%20Modeling%20App' }} + steps: + - uses: actions/download-artifact@v3 + + - name: Generate the update static endpoint + run: | + ls -l artifact/*/*oo* + DARWIN_SIG=`cat artifact/macos/*.app.tar.gz.sig` + WINDOWS_X86_64_SIG=`cat artifact/msi/*x64*.msi.zip.sig` + WINDOWS_AARCH64_SIG=`cat artifact/msi/*arm64*.msi.zip.sig` + RELEASE_DIR=https://${WEBSITE_DIR}/${VERSION} + jq --null-input \ + --arg version "${VERSION}" \ + --arg pub_date "${PUB_DATE}" \ + --arg notes "${NOTES}" \ + --arg darwin_sig "$DARWIN_SIG" \ + --arg darwin_url "$RELEASE_DIR/macos/${{ env.URL_CODED_NAME }}.app.tar.gz" \ + --arg windows_x86_64_sig "$WINDOWS_X86_64_SIG" \ + --arg windows_x86_64_url "$RELEASE_DIR/msi/${{ env.URL_CODED_NAME }}_${VERSION_NO_V}_x64_en-US.msi.zip" \ + --arg windows_aarch64_sig "$WINDOWS_AARCH64_SIG" \ + --arg windows_aarch64_url "$RELEASE_DIR/msi/${{ env.URL_CODED_NAME }}_${VERSION_NO_V}_arm64_en-US.msi.zip" \ + '{ + "version": $version, + "pub_date": $pub_date, + "notes": $notes, + "platforms": { + "darwin-x86_64": { + "signature": $darwin_sig, + "url": $darwin_url + }, + "darwin-aarch64": { + "signature": $darwin_sig, + "url": $darwin_url + }, + "windows-x86_64": { + "signature": $windows_x86_64_sig, + "url": $windows_x86_64_url + }, + "windows-aarch64": { + "signature": $windows_aarch64_sig, + "url": $windows_aarch64_url + } + } + }' > last_update.json + cat last_update.json + + - name: Generate the download static endpoint + run: | + RELEASE_DIR=https://${WEBSITE_DIR}/${VERSION} + jq --null-input \ + --arg version "${VERSION}" \ + --arg pub_date "${PUB_DATE}" \ + --arg notes "${NOTES}" \ + --arg darwin_url "$RELEASE_DIR/dmg/${{ env.URL_CODED_NAME }}_${VERSION_NO_V}_universal.dmg" \ + --arg windows_x86_64_url "$RELEASE_DIR/msi/${{ env.URL_CODED_NAME }}_${VERSION_NO_V}_x64_en-US.msi" \ + --arg windows_aarch64_url "$RELEASE_DIR/msi/${{ env.URL_CODED_NAME }}_${VERSION_NO_V}_arm64_en-US.msi" \ + '{ + "version": $version, + "pub_date": $pub_date, + "notes": $notes, + "platforms": { + "dmg-universal": { + "url": $darwin_url + }, + "msi-x86_64": { + "url": $windows_x86_64_url + }, + "msi-aarch64": { + "url": $windows_aarch64_url + } + } + }' > last_download.json + cat last_download.json + + - name: Authenticate to Google Cloud + uses: 'google-github-actions/auth@v2.1.3' + with: + credentials_json: '${{ secrets.GOOGLE_CLOUD_DL_SA }}' + + - name: Set up Google Cloud SDK + uses: google-github-actions/setup-gcloud@v2.1.0 + with: + project_id: kittycadapi + + - name: Upload release files to public bucket + uses: google-github-actions/upload-cloud-storage@v2.1.0 + with: + path: artifact + glob: '*/Zoo*' + parent: false + destination: ${{ env.BUCKET_DIR }}/${{ env.VERSION }} + + - name: Upload update endpoint to public bucket + uses: google-github-actions/upload-cloud-storage@v2.1.0 + with: + path: last_update.json + destination: ${{ env.BUCKET_DIR }} + + - name: Upload download endpoint to public bucket + uses: google-github-actions/upload-cloud-storage@v2.1.0 + with: + path: last_download.json + destination: ${{ env.BUCKET_DIR }} + + - name: Upload release files to Github + if: ${{ github.event_name == 'release' }} + uses: softprops/action-gh-release@v2 + with: + files: 'artifact/*/Zoo*' + + announce_release: + needs: [publish-apps-release] + runs-on: ubuntu-22.04 + if: github.event_name == 'release' + steps: + - name: Check out code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.x' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install requests + + - name: Announce Release + env: + DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} + RELEASE_VERSION: ${{ github.event.release.tag_name }} + RELEASE_BODY: ${{ github.event.release.body}} + run: python public/announce_release.py diff --git a/.github/workflows/build-test-web.yml b/.github/workflows/build-test-web.yml new file mode 100644 index 000000000..b288fa381 --- /dev/null +++ b/.github/workflows/build-test-web.yml @@ -0,0 +1,79 @@ +name: build-test-web + +on: + pull_request: + push: + branches: + - main + - pierremtb/tauri-to-electron-ci + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + check-format: + runs-on: 'ubuntu-22.04' + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: 'yarn' + - run: yarn install + - run: yarn fmt-check + + check-types: + runs-on: ubuntu-22.04 + + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: 'yarn' + - run: yarn install + - uses: Swatinem/rust-cache@v2 + with: + workspaces: './src/wasm-lib' + + - run: yarn build:wasm + - run: yarn xstate:typegen + - run: yarn tsc + + + check-typos: + runs-on: ubuntu-22.04 + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + - name: Install codespell + run: | + python -m pip install codespell + - name: Run codespell + run: codespell --config .codespellrc # Edit this file to tweak the typo list and other configuration. + + + build-test-web: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: 'yarn' + + - run: yarn install + + - uses: Swatinem/rust-cache@v2 + with: + workspaces: './src/wasm-lib' + + - run: yarn build:wasm + + - run: yarn simpleserver:ci + + - run: yarn test:nowatch diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 4322df327..000000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,586 +0,0 @@ -name: CI - -on: - pull_request: - push: - branches: - - main - release: - types: [published] - schedule: - - cron: '0 4 * * *' - # Daily at 04:00 AM UTC - # Will checkout the last commit from the default branch (main as of 2023-10-04) - -env: - CUT_RELEASE_PR: ${{ github.event_name == 'pull_request' && (contains(github.event.pull_request.title, 'Cut release v')) }} - BUILD_RELEASE: ${{ github.event_name == 'release' || github.event_name == 'schedule' || github.event_name == 'pull_request' && (contains(github.event.pull_request.title, 'Cut release v')) }} - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -permissions: - contents: write - pull-requests: write - actions: read - -jobs: - check-format: - runs-on: 'ubuntu-latest' - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version-file: '.nvmrc' - cache: 'yarn' - - run: yarn install - - run: yarn fmt-check - - check-types: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version-file: '.nvmrc' - cache: 'yarn' - - run: yarn install - - uses: Swatinem/rust-cache@v2 - with: - workspaces: './src/wasm-lib' - - - run: yarn build:wasm - - run: yarn xstate:typegen - - run: yarn tsc - - - check-typos: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Set up Python - uses: actions/setup-python@v5 - - name: Install codespell - run: | - python -m pip install codespell - - name: Run codespell - run: codespell --config .codespellrc # Edit this file to tweak the typo list and other configuration. - - - build-test-web: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-node@v4 - with: - node-version-file: '.nvmrc' - cache: 'yarn' - - - run: yarn install - - - uses: Swatinem/rust-cache@v2 - with: - workspaces: './src/wasm-lib' - - - run: yarn build:wasm - - - run: yarn simpleserver:ci - if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }} - - - name: Install Chromium Browser - if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }} - run: yarn playwright install chromium --with-deps - - - name: run unit tests - if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }} - run: yarn test:nowatch - env: - VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }} - - - name: check for changes - if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }} - id: git-check - run: | - git add src/lang/std/artifactMapGraphs - if git status src/lang/std/artifactMapGraphs | grep -q "Changes to be committed" - then echo "modified=true" >> $GITHUB_OUTPUT - else echo "modified=false" >> $GITHUB_OUTPUT - fi - - name: Commit changes, if any - if: ${{ github.event_name != 'release' && github.event_name != 'schedule' && steps.git-check.outputs.modified == 'true' }} - run: | - git config --local user.email "github-actions[bot]@users.noreply.github.com" - git config --local user.name "github-actions[bot]" - git remote set-url origin https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git - git fetch origin - echo ${{ github.head_ref }} - git checkout ${{ github.head_ref }} - # TODO when webkit works on ubuntu remove the os part of the commit message - git commit -am "Look at this (photo)Graph *in the voice of Nickelback*" || true - git push - git push origin ${{ github.head_ref }} - - - - - - prepare-json-files: - runs-on: ubuntu-latest # seperate job on Ubuntu for easy string manipulations (compared to Windows) - outputs: - version: ${{ steps.export_version.outputs.version }} - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-node@v4 - with: - node-version-file: '.nvmrc' - cache: 'yarn' - - - name: Set nightly version - if: github.event_name == 'schedule' - run: | - VERSION=$(date +'%-y.%-m.%-d') yarn bump-jsons - echo "$(jq --arg url 'https://dl.zoo.dev/releases/modeling-app/nightly/last_update.json' \ - '.plugins.updater.endpoints[]=$url' src-tauri/tauri.release.conf.json --indent 2)" > src-tauri/tauri.release.conf.json - echo "$(jq --arg id 'dev.zoo.modeling-app-nightly' \ - '.identifier=$id' src-tauri/tauri.release.conf.json --indent 2)" > src-tauri/tauri.release.conf.json - echo "$(jq --arg name 'Zoo Modeling App (Nightly)' \ - '.productName=$name' src-tauri/tauri.release.conf.json --indent 2)" > src-tauri/tauri.release.conf.json - - - name: Set updater test version - if: ${{ env.CUT_RELEASE_PR == 'true' }} - run: | - echo "$(jq --arg url 'https://dl.zoo.dev/releases/modeling-app/test/last_update.json' \ - '.plugins.updater.endpoints[]=$url' src-tauri/tauri.release.conf.json --indent 2)" > src-tauri/tauri.release.conf.json - - - uses: actions/upload-artifact@v3 - if: ${{ github.event_name == 'schedule' || env.CUT_RELEASE_PR == 'true' }} - with: - path: | - package.json - src-tauri/tauri.conf.json - src-tauri/tauri.release.conf.json - - - id: export_version - run: echo "version=`cat package.json | jq -r '.version'`" >> "$GITHUB_OUTPUT" - - - build-test-apps: - needs: [prepare-json-files] - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [macos-14, ubuntu-latest, windows-latest] - env: - # Specific Apple Universal target for macos - TAURI_ARGS_MACOS: ${{ matrix.os == 'macos-14' && '--target universal-apple-darwin' || '' }} - # Only build executable on linux (no appimage or deb) - TAURI_ARGS_UBUNTU: ${{ matrix.os == 'ubuntu-latest' && '--bundles' || '' }} - steps: - - uses: actions/checkout@v4 - - - uses: actions/download-artifact@v3 - if: github.event_name == 'schedule' - - - name: Copy updated .json files - if: github.event_name == 'schedule' - run: | - ls -l artifact - cp artifact/package.json package.json - cp artifact/src-tauri/tauri.conf.json src-tauri/tauri.conf.json - cp artifact/src-tauri/tauri.release.conf.json src-tauri/tauri.release.conf.json - - - name: Update WebView2 on Windows - if: matrix.os == 'windows-latest' - # Workaround needed to build the tauri windows app with matching edge version. - # From https://github.com/actions/runner-images/issues/9538 - run: | - Invoke-WebRequest -Uri 'https://go.microsoft.com/fwlink/p/?LinkId=2124703' -OutFile 'setup.exe' - Start-Process -FilePath setup.exe -Verb RunAs -Wait - - - name: Install ubuntu system dependencies - if: matrix.os == 'ubuntu-latest' - run: | - sudo apt-get update - sudo apt-get install -y \ - libgtk-3-dev \ - libayatana-appindicator3-dev \ - webkit2gtk-driver \ - libsoup-3.0-dev \ - libjavascriptcoregtk-4.1-dev \ - libwebkit2gtk-4.1-dev \ - at-spi2-core \ - xvfb - - - name: Sync node version and setup cache - uses: actions/setup-node@v4 - with: - node-version-file: '.nvmrc' - cache: 'yarn' # Set this to npm, yarn or pnpm. - - - run: yarn install - - - name: Setup Rust - uses: dtolnay/rust-toolchain@stable - - - name: Setup Rust cache - uses: swatinem/rust-cache@v2 - with: - workspaces: './src-tauri -> target' - - - uses: Swatinem/rust-cache@v2 - with: - workspaces: './src/wasm-lib' - - - name: Run build:wasm manually - shell: bash - env: - MODE: ${{ env.BUILD_RELEASE == 'true' && '--release' || '--debug' }} - run: | - mkdir src/wasm-lib/pkg; cd src/wasm-lib - echo "building with ${{ env.MODE }}" - npx wasm-pack build --target web --out-dir pkg ${{ env.MODE }} - cd ../../ - cp src/wasm-lib/pkg/wasm_lib_bg.wasm public - - - name: Run vite build (build:both) - run: yarn vite build --mode ${{ env.BUILD_RELEASE == 'true' && 'production' || 'development' }} - - - name: Fix format - run: yarn fmt - - - name: Install x86 target for Universal builds (MacOS only) - if: matrix.os == 'macos-14' - run: | - rustup target add x86_64-apple-darwin - - - name: Prepare certificate and variables (Windows only) - if: ${{ matrix.os == 'windows-latest' && env.BUILD_RELEASE == 'true' }} - run: | - echo "${{secrets.SM_CLIENT_CERT_FILE_B64 }}" | base64 --decode > /d/Certificate_pkcs12.p12 - cat /d/Certificate_pkcs12.p12 - echo "::set-output name=version::${GITHUB_REF#refs/tags/v}" - echo "SM_HOST=${{ secrets.SM_HOST }}" >> "$GITHUB_ENV" - echo "SM_API_KEY=${{ secrets.SM_API_KEY }}" >> "$GITHUB_ENV" - echo "SM_CLIENT_CERT_FILE=D:\\Certificate_pkcs12.p12" >> "$GITHUB_ENV" - echo "SM_CLIENT_CERT_PASSWORD=${{ secrets.SM_CLIENT_CERT_PASSWORD }}" >> "$GITHUB_ENV" - echo "C:\Program Files (x86)\Windows Kits\10\App Certification Kit" >> $GITHUB_PATH - echo "C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools" >> $GITHUB_PATH - echo "C:\Program Files\DigiCert\DigiCert One Signing Manager Tools" >> $GITHUB_PATH - shell: bash - - - name: Setup certicate with SSM KSP (Windows only) - if: ${{ matrix.os == 'windows-latest' && env.BUILD_RELEASE == 'true' }} - run: | - curl -X GET https://one.digicert.com/signingmanager/api-ui/v1/releases/smtools-windows-x64.msi/download -H "x-api-key:%SM_API_KEY%" -o smtools-windows-x64.msi - msiexec /i smtools-windows-x64.msi /quiet /qn - smksp_registrar.exe list - smctl.exe keypair ls - C:\Windows\System32\certutil.exe -csp "DigiCert Signing Manager KSP" -key -user - smksp_cert_sync.exe - shell: cmd - - - name: Build the app (debug) - if: ${{ env.BUILD_RELEASE == 'false' }} - run: "yarn tauri build --debug ${{ env.TAURI_ARGS_MACOS }} ${{ env.TAURI_ARGS_UBUNTU }}" - - - name: Build for Mac TestFlight (nightly) - if: ${{ github.event_name == 'schedule' && matrix.os == 'macos-14' }} - shell: bash - run: | - unset APPLE_SIGNING_IDENTITY - unset APPLE_CERTIFICATE - sign_app="3rd Party Mac Developer Application: KittyCAD Inc (${APPLE_TEAM_ID})" - sign_install="3rd Party Mac Developer Installer: KittyCAD Inc (${APPLE_TEAM_ID})" - profile="src-tauri/entitlements/Mac_App_Distribution.provisionprofile" - - mkdir -p src-tauri/entitlements - echo -n "${APPLE_STORE_PROVISIONING_PROFILE}" | base64 --decode -o "${profile}" - - echo -n "${APPLE_STORE_DISTRIBUTION_CERT}" | base64 --decode -o "dist.cer" - echo -n "${APPLE_STORE_INSTALLER_CERT}" | base64 --decode -o "installer.cer" - - KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db - KEYCHAIN_PASSWORD="password" - - # create temporary keychain - security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH - security set-keychain-settings -lut 21600 $KEYCHAIN_PATH - security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH - - # import certificate to keychain - security import "dist.cer" -P "$APPLE_STORE_P12_PASSWORD" -k $KEYCHAIN_PATH -f pkcs12 -t cert -A - security import "installer.cer" -P "$APPLE_STORE_P12_PASSWORD" -k $KEYCHAIN_PATH -f pkcs12 -t cert -A - - security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH - security list-keychain -d user -s $KEYCHAIN_PATH - - target="universal-apple-darwin" - - # Turn off the default target - # We don't want to install the updater for the apple store build - sed -i.bu "s/default =/# default =/" src-tauri/Cargo.toml - rm src-tauri/Cargo.toml.bu - git diff src-tauri/Cargo.toml - - yarn tauri build --target "${target}" --verbose --config src-tauri/tauri.app-store.conf.json - - app_path="src-tauri/target/${target}/release/bundle/macos/Zoo Modeling App.app" - build_name="src-tauri/target/${target}/release/bundle/macos/Zoo Modeling App.pkg" - cp_dir="src-tauri/target/${target}/release/bundle/macos/Zoo Modeling App.app/Contents/embedded.provisionprofile" - entitlements="src-tauri/entitlements/app-store.entitlements" - - cp "${profile}" "${cp_dir}" - - codesign --deep --force -s "${sign_app}" --entitlements "${entitlements}" "${app_path}" - - productbuild --component "${app_path}" /Applications/ --sign "${sign_install}" "${build_name}" - - # Undo the changes to the Cargo.toml - git checkout src-tauri/Cargo.toml - - env: - APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} - APPLE_STORE_PROVISIONING_PROFILE: ${{ secrets.APPLE_STORE_PROVISIONING_PROFILE }} - APPLE_STORE_DISTRIBUTION_CERT: ${{ secrets.APPLE_STORE_DISTRIBUTION_CERT }} - APPLE_STORE_INSTALLER_CERT: ${{ secrets.APPLE_STORE_INSTALLER_CERT }} - APPLE_STORE_P12_PASSWORD: ${{ secrets.APPLE_STORE_P12_PASSWORD }} - - - - name: 'Upload to Mac TestFlight (nightly)' - uses: apple-actions/upload-testflight-build@v1 - if: ${{ github.event_name == 'schedule' && matrix.os == 'macos-14' }} - with: - app-path: 'src-tauri/target/universal-apple-darwin/release/bundle/macos/Zoo Modeling App.pkg' - issuer-id: ${{ secrets.APPLE_STORE_ISSUER_ID }} - api-key-id: ${{ secrets.APPLE_STORE_API_KEY_ID }} - api-private-key: ${{ secrets.APPLE_STORE_API_PRIVATE_KEY }} - app-type: osx - - - - name: Clean up after Mac TestFlight (nightly) - if: ${{ github.event_name == 'schedule' && matrix.os == 'macos-14' }} - shell: bash - run: | - git status - # remove our target builds because we want to make sure the later build - # includes the updater, and that anything we changed with the target - # does not persist - rm -rf src-tauri/target - # Lets get rid of the info.plist for the normal mac builds since its - # being sketchy. - rm src-tauri/Info.plist - - # We do this after the apple store because the apple store build is - # specific and we want to overwrite it with the this new build after and - # not upload the apple store build to the public bucket - - name: Build the app (release) and sign - if: ${{ env.BUILD_RELEASE == 'true' }} - env: - TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} - TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} - APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} - APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} - APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }} - APPLE_ID: ${{ secrets.APPLE_ID }} - APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }} - APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} - TAURI_CONF_ARGS: "--config ${{ matrix.os == 'windows-latest' && 'src-tauri\\tauri.release.conf.json' || 'src-tauri/tauri.release.conf.json' }}" - run: "yarn tauri build ${{ env.TAURI_CONF_ARGS }} ${{ env.TAURI_ARGS_MACOS }} ${{ env.TAURI_ARGS_UBUNTU }}" - - - uses: actions/upload-artifact@v3 - if: matrix.os != 'ubuntu-latest' - env: - PREFIX: ${{ matrix.os == 'macos-14' && 'src-tauri/target/universal-apple-darwin' || 'src-tauri/target' }} - MODE: ${{ env.BUILD_RELEASE == 'true' && 'release' || 'debug' }} - with: - path: "${{ env.PREFIX }}/${{ env.MODE }}/bundle/*/*" - - - name: Run e2e tests (linux only) - if: ${{ matrix.os == 'ubuntu-latest' && github.event_name != 'release' && github.event_name != 'schedule' }} - run: | - cargo install tauri-driver --force - source .env.${{ env.BUILD_RELEASE == 'true' && 'production' || 'development' }} - export VITE_KC_API_BASE_URL - xvfb-run yarn test:e2e:tauri - env: - E2E_APPLICATION: "./src-tauri/target/${{ env.BUILD_RELEASE == 'true' && 'release' || 'debug' }}/zoo-modeling-app" - KITTYCAD_API_TOKEN: ${{ env.BUILD_RELEASE == 'true' && secrets.KITTYCAD_API_TOKEN || secrets.KITTYCAD_API_TOKEN_DEV }} - - - name: Run e2e tests (windows only) - if: ${{ matrix.os == 'windows-latest' && github.event_name != 'release' && github.event_name != 'schedule' }} - run: | - cargo install tauri-driver --force - yarn wdio run wdio.conf.ts - env: - E2E_APPLICATION: ".\\src-tauri\\target\\${{ env.BUILD_RELEASE == 'true' && 'release' || 'debug' }}\\Zoo Modeling App.exe" - KITTYCAD_API_TOKEN: ${{ env.BUILD_RELEASE == 'true' && secrets.KITTYCAD_API_TOKEN || secrets.KITTYCAD_API_TOKEN_DEV }} - VITE_KC_API_BASE_URL: ${{ env.BUILD_RELEASE == 'true' && 'https://api.zoo.dev' || 'https://api.dev.zoo.dev' }} - E2E_TAURI_ENABLED: true - TS_NODE_COMPILER_OPTIONS: '{"module": "commonjs"}' - - - uses: actions/download-artifact@v3 - if: ${{ env.CUT_RELEASE_PR == 'true' }} - - - name: Copy updated .json file for updater test - if: ${{ env.CUT_RELEASE_PR == 'true' }} - run: | - ls -l artifact - cp artifact/src-tauri/tauri.release.conf.json src-tauri/tauri.release.conf.json - cat src-tauri/tauri.release.conf.json - - - name: Build the app (release, updater test) - if: ${{ env.CUT_RELEASE_PR == 'true' && matrix.os != 'ubuntu-latest' }} - env: - TAURI_CONF_ARGS: "-c ${{ matrix.os == 'windows-latest' && 'src-tauri\\tauri.release.conf.json' || 'src-tauri/tauri.release.conf.json' }}" - TAURI_BUNDLE_ARGS: "-b ${{ matrix.os == 'windows-latest' && 'msi' || 'dmg' }}" - run: "yarn tauri build ${{ env.TAURI_CONF_ARGS }} ${{ env.TAURI_BUNDLE_ARGS }} ${{ env.TAURI_ARGS_MACOS }}" - - - uses: actions/upload-artifact@v3 - if: ${{ env.CUT_RELEASE_PR == 'true' && matrix.os != 'ubuntu-latest' }} - with: - path: "${{ matrix.os == 'macos-14' && 'src-tauri/target/universal-apple-darwin/release/bundle/dmg/*.dmg' || 'src-tauri/target/release/bundle/msi/*.msi' }}" - name: updater-test - - - publish-apps-release: - permissions: - contents: write - runs-on: ubuntu-latest - if: ${{ github.event_name == 'release' || github.event_name == 'schedule' }} - needs: [check-format, check-types, check-typos, build-test-web, prepare-json-files, build-test-apps] - env: - VERSION_NO_V: ${{ needs.prepare-json-files.outputs.version }} - VERSION: ${{ github.event_name == 'release' && format('v{0}', needs.prepare-json-files.outputs.version) || needs.prepare-json-files.outputs.version }} - PUB_DATE: ${{ github.event_name == 'release' && github.event.release.created_at || github.event.repository.updated_at }} - NOTES: ${{ github.event_name == 'release' && github.event.release.body || format('Nightly build, commit {0}', github.sha) }} - BUCKET_DIR: ${{ github.event_name == 'release' && 'dl.kittycad.io/releases/modeling-app' || 'dl.kittycad.io/releases/modeling-app/nightly' }} - WEBSITE_DIR: ${{ github.event_name == 'release' && 'dl.zoo.dev/releases/modeling-app' || 'dl.zoo.dev/releases/modeling-app/nightly' }} - URL_CODED_NAME: ${{ github.event_name == 'schedule' && 'Zoo%20Modeling%20App%20%28Nightly%29' || 'Zoo%20Modeling%20App' }} - steps: - - uses: actions/download-artifact@v3 - - - name: Generate the update static endpoint - run: | - ls -l artifact/*/*oo* - DARWIN_SIG=`cat artifact/macos/*.app.tar.gz.sig` - WINDOWS_SIG=`cat artifact/msi/*.msi.zip.sig` - RELEASE_DIR=https://${WEBSITE_DIR}/${VERSION} - jq --null-input \ - --arg version "${VERSION}" \ - --arg pub_date "${PUB_DATE}" \ - --arg notes "${NOTES}" \ - --arg darwin_sig "$DARWIN_SIG" \ - --arg darwin_url "$RELEASE_DIR/macos/${{ env.URL_CODED_NAME }}.app.tar.gz" \ - --arg windows_sig "$WINDOWS_SIG" \ - --arg windows_url "$RELEASE_DIR/msi/${{ env.URL_CODED_NAME }}_${VERSION_NO_V}_x64_en-US.msi.zip" \ - '{ - "version": $version, - "pub_date": $pub_date, - "notes": $notes, - "platforms": { - "darwin-x86_64": { - "signature": $darwin_sig, - "url": $darwin_url - }, - "darwin-aarch64": { - "signature": $darwin_sig, - "url": $darwin_url - }, - "windows-x86_64": { - "signature": $windows_sig, - "url": $windows_url - } - } - }' > last_update.json - cat last_update.json - - - name: Generate the download static endpoint - run: | - RELEASE_DIR=https://${WEBSITE_DIR}/${VERSION} - jq --null-input \ - --arg version "${VERSION}" \ - --arg pub_date "${PUB_DATE}" \ - --arg notes "${NOTES}" \ - --arg darwin_url "$RELEASE_DIR/dmg/${{ env.URL_CODED_NAME }}_${VERSION_NO_V}_universal.dmg" \ - --arg windows_url "$RELEASE_DIR/msi/${{ env.URL_CODED_NAME }}_${VERSION_NO_V}_x64_en-US.msi" \ - '{ - "version": $version, - "pub_date": $pub_date, - "notes": $notes, - "platforms": { - "dmg-universal": { - "url": $darwin_url - }, - "msi-x86_64": { - "url": $windows_url - } - } - }' > last_download.json - cat last_download.json - - - name: Authenticate to Google Cloud - uses: 'google-github-actions/auth@v2.1.3' - with: - credentials_json: '${{ secrets.GOOGLE_CLOUD_DL_SA }}' - - - name: Set up Google Cloud SDK - uses: google-github-actions/setup-gcloud@v2.1.0 - with: - project_id: kittycadapi - - - name: Upload release files to public bucket - uses: google-github-actions/upload-cloud-storage@v2.1.1 - with: - path: artifact - glob: '*/Zoo*' - parent: false - destination: ${{ env.BUCKET_DIR }}/${{ env.VERSION }} - - - name: Upload update endpoint to public bucket - uses: google-github-actions/upload-cloud-storage@v2.1.1 - with: - path: last_update.json - destination: ${{ env.BUCKET_DIR }} - - - name: Upload download endpoint to public bucket - uses: google-github-actions/upload-cloud-storage@v2.1.1 - with: - path: last_download.json - destination: ${{ env.BUCKET_DIR }} - - - name: Upload release files to Github - if: ${{ github.event_name == 'release' }} - uses: softprops/action-gh-release@v2 - with: - files: 'artifact/*/Zoo*' - - announce_release: - needs: [publish-apps-release] - runs-on: ubuntu-latest - if: github.event_name == 'release' - steps: - - name: Check out code - uses: actions/checkout@v4 - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: '3.x' - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install requests - - - name: Announce Release - env: - DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} - RELEASE_VERSION: ${{ github.event.release.tag_name }} - RELEASE_BODY: ${{ github.event.release.body}} - run: python public/announce_release.py diff --git a/add-osx-cert.sh b/add-osx-cert.sh new file mode 100644 index 000000000..173322565 --- /dev/null +++ b/add-osx-cert.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env sh +# From https://dev.to/rwwagner90/signing-electron-apps-with-github-actions-4cof + +KEY_CHAIN=build.keychain +CERTIFICATE_P12=certificate.p12 + +# Recreate the certificate from the secure environment variable +echo $APPLE_CERTIFICATE | base64 --decode > $CERTIFICATE_P12 + +#create a keychain +security create-keychain -p actions $KEY_CHAIN + +# Make the keychain the default so identities are found +security default-keychain -s $KEY_CHAIN + +# Unlock the keychain +security unlock-keychain -p actions $KEY_CHAIN + +security import $CERTIFICATE_P12 -k $KEY_CHAIN -P $APPLE_CERTIFICATE_PASSWORD -T /usr/bin/codesign; + +security set-key-partition-list -S apple-tool:,apple: -s -k actions $KEY_CHAIN + +# remove certs +rm -fr *.p12 \ No newline at end of file diff --git a/e2e/tauri/specs/app.spec.ts b/e2e/tauri/specs/app.spec.ts deleted file mode 100644 index 99e428189..000000000 --- a/e2e/tauri/specs/app.spec.ts +++ /dev/null @@ -1,155 +0,0 @@ -import { browser, $, expect } from '@wdio/globals' -import fs from 'fs/promises' -import path from 'path' -import os from 'os' -import { click, setDatasetValue } from '../utils' - -const isWin32 = os.platform() === 'win32' -const documentsDir = path.join(os.homedir(), 'Documents') -const userSettingsDir = path.join( - os.homedir(), - '.config', - 'dev.zoo.modeling-app' -) -const defaultProjectDir = path.join(documentsDir, 'zoo-modeling-app-projects') -const newProjectDir = path.join(documentsDir, 'a-different-directory') -const tmp = process.env.TEMP || '/tmp' -const userCodeDir = path.join(tmp, 'kittycad_user_code') - -describe('ZMA sign in flow', () => { - before(async () => { - // Clean up filesystem from previous tests - await new Promise((resolve) => setTimeout(resolve, 100)) - await fs.rm(defaultProjectDir, { force: true, recursive: true }) - await fs.rm(newProjectDir, { force: true, recursive: true }) - await fs.rm(userCodeDir, { force: true }) - await fs.rm(userSettingsDir, { force: true, recursive: true }) - await fs.mkdir(defaultProjectDir, { recursive: true }) - await fs.mkdir(newProjectDir, { recursive: true }) - }) - - it('opens the auth page and signs in', async () => { - const signInButton = await $('[data-testid="sign-in-button"]') - expect(await signInButton.getText()).toEqual('Sign in') - - await click(signInButton) - await new Promise((resolve) => setTimeout(resolve, 2000)) - - // Get from main.rs - const userCode = await (await fs.readFile(userCodeDir)).toString() - console.log(`Found user code ${userCode}`) - - // Device flow: verify - const token = process.env.KITTYCAD_API_TOKEN - const headers = { - Authorization: `Bearer ${token}`, - Accept: 'application/json', - 'Content-Type': 'application/json', - } - const apiBaseUrl = process.env.VITE_KC_API_BASE_URL - const verifyUrl = `${apiBaseUrl}/oauth2/device/verify?user_code=${userCode}` - console.log(`GET ${verifyUrl}`) - const vr = await fetch(verifyUrl, { headers }) - console.log(vr.status) - - // Device flow: confirm - const confirmUrl = `${apiBaseUrl}/oauth2/device/confirm` - const data = JSON.stringify({ user_code: userCode }) - console.log(`POST ${confirmUrl} ${data}`) - const cr = await fetch(confirmUrl, { - headers, - method: 'POST', - body: data, - }) - console.log(cr.status) - - // Now should be signed in - await new Promise((resolve) => setTimeout(resolve, 10000)) - const newFileButton = await $('[data-testid="home-new-file"]') - expect(await newFileButton.getText()).toEqual('New project') - }) -}) - -describe('ZMA authorized user flows', () => { - // Note: each flow below is intended to start *and* end from the home page - - it('opens the settings page, checks filesystem settings, and closes the settings page', async () => { - const menuButton = await $('[data-testid="user-sidebar-toggle"]') - await click(menuButton) - - const settingsButton = await $('[data-testid="user-settings"]') - await click(settingsButton) - - const projectDirInput = await $('[data-testid="project-directory-input"]') - expect(await projectDirInput.getValue()).toEqual(defaultProjectDir) - - /* - * We've set up the project directory input (in initialSettings.tsx) - * to be able to skip the folder selection dialog if data-testValue - * has a value, allowing us to test the input otherwise works. - */ - // TODO: understand why we need to force double \ on Windows - await setDatasetValue( - projectDirInput, - 'testValue', - isWin32 ? newProjectDir.replaceAll('\\', '\\\\') : newProjectDir - ) - const projectDirButton = await $('[data-testid="project-directory-button"]') - await click(projectDirButton) - await new Promise((resolve) => setTimeout(resolve, 500)) - // This line is broken. I need a different way to grab the toast - await expect(await $('div*=Set project directory to')).toBeDisplayed() - - const nameInput = await $('[data-testid="projects-defaultProjectName"]') - expect(await nameInput.getValue()).toEqual('project-$nnn') - - // Setting it back (for back to back local tests) - await new Promise((resolve) => setTimeout(resolve, 5000)) - await setDatasetValue( - projectDirInput, - 'testValue', - isWin32 ? defaultProjectDir.replaceAll('\\', '\\\\') : newProjectDir - ) - await click(projectDirButton) - - const closeButton = await $('[data-testid="settings-close-button"]') - await click(closeButton) - }) - - it('checks that no file exists, creates a new file', async () => { - const homeSection = await $('[data-testid="home-section"]') - expect(await homeSection.getText()).toContain('No Projects found') - - const newFileButton = await $('[data-testid="home-new-file"]') - await click(newFileButton) - await new Promise((resolve) => setTimeout(resolve, 1000)) - - expect(await homeSection.getText()).toContain('project-000') - }) - - it('opens the new file and expects a loading stream', async () => { - const projectLink = await $('[data-testid="project-link"]') - await click(projectLink) - if (isWin32) { - // TODO: actually do something to check that the stream is up - await new Promise((resolve) => setTimeout(resolve, 5000)) - } else { - const errorText = await $('[data-testid="unexpected-error"]') - expect(await errorText.getText()).toContain('unexpected error') - } - const base = isWin32 ? 'http://tauri.localhost' : 'tauri://localhost' - await browser.execute(`window.location.href = "${base}/home"`) - }) -}) - -describe('ZMA sign out flow', () => { - it('signs out', async () => { - await new Promise((resolve) => setTimeout(resolve, 1000)) - const menuButton = await $('[data-testid="user-sidebar-toggle"]') - await click(menuButton) - const signoutButton = await $('[data-testid="user-sidebar-sign-out"]') - await click(signoutButton) - const newSignInButton = await $('[data-testid="sign-in-button"]') - expect(await newSignInButton.getText()).toEqual('Sign in') - }) -}) diff --git a/e2e/tauri/utils.ts b/e2e/tauri/utils.ts deleted file mode 100644 index 4af446e6f..000000000 --- a/e2e/tauri/utils.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { browser } from '@wdio/globals' - -export async function click(element: WebdriverIO.Element): Promise { - // Workaround for .click(), see https://github.com/tauri-apps/tauri/issues/6541 - await element.waitForClickable() - await browser.execute('arguments[0].click();', element) -} - -/* Shoutout to @Sheap on Github for a great workaround utility: - * https://github.com/tauri-apps/tauri/issues/6541#issue-1638944060 - */ -export async function setDatasetValue( - field: WebdriverIO.Element, - property: string, - value: string -) { - await browser.execute(`arguments[0].dataset.${property} = "${value}"`, field) -} diff --git a/forge.config.ts b/forge.config.ts index 0e8e3b379..f701bf02d 100644 --- a/forge.config.ts +++ b/forge.config.ts @@ -10,6 +10,15 @@ import { FuseV1Options, FuseVersion } from '@electron/fuses' const config: ForgeConfig = { packagerConfig: { asar: true, + osxSign: (process.env.BUILD_RELEASE === 'true' && {}) || undefined, + osxNotarize: + (process.env.BUILD_RELEASE === 'true' && { + appleId: process.env.APPLE_ID || '', + appleIdPassword: process.env.APPLE_PASSWORD || '', + teamId: process.env.APPLE_TEAM_ID || '', + }) || + undefined, + executableName: 'zoo-modeling-app', }, rebuildConfig: {}, makers: [ diff --git a/make-release.sh b/make-release.sh index 59deee7f8..39e0b3a4c 100755 --- a/make-release.sh +++ b/make-release.sh @@ -57,9 +57,8 @@ echo "New version number without 'v': $new_version_number" git checkout -b "cut-release-$new_version" echo "$(jq --arg v "$new_version_number" '.version=$v' package.json --indent 2)" > package.json -echo "$(jq --arg v "$new_version_number" '.version=$v' src-tauri/tauri.conf.json --indent 2)" > src-tauri/tauri.conf.json -git add package.json src-tauri/tauri.conf.json +git add package.json git commit -m "Cut release $new_version" echo "" diff --git a/package.json b/package.json index 4f4820c8a..439fb2190 100644 --- a/package.json +++ b/package.json @@ -2,8 +2,13 @@ "private": true, "name": "zoo-modeling-app", "productName": "Zoo Modeling App", - "description": "CAD", "version": "0.24.10", + "author": { + "name": "Zoo Corporation", + "email": "info@zoo.dev", + "url": "https://zoo.dev" + }, + "description": "Edit CAD visually or with code", "main": ".vite/build/main.js", "license": "none", "dependencies": { @@ -69,7 +74,6 @@ "test": "vitest --mode development", "test:nowatch": "vitest run --mode development", "test:rust": "(cd src/wasm-lib && cargo test --all && cargo clippy --all --tests --benches)", - "test:e2e:tauri": "E2E_TAURI_ENABLED=true TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\"}' wdio run wdio.conf.ts", "simpleserver:ci": "yarn pretest && http-server ./public --cors -p 3000 &", "simpleserver": "yarn pretest && http-server ./public --cors -p 3000", "fmt": "prettier --write ./src *.ts *.json *.js ./e2e ./packages", diff --git a/src/lib/desktop.ts b/src/lib/desktop.ts index aeeaf4fc7..1b9c4b77b 100644 --- a/src/lib/desktop.ts +++ b/src/lib/desktop.ts @@ -67,7 +67,7 @@ export async function renameProjectDirectory( ) ) } catch (e) { - // Otherwise if it failed and the failure is "it doesnt exist" then rename it! + // Otherwise if it failed and the failure is "it doesn't exist" then rename it! if (e === 'ENOENT') { await window.electron.rename(projectPath, newPath) return newPath @@ -253,10 +253,10 @@ const collectAllFilesRecursiveFrom = async (path: string) => { return entry } -export const getDefaultKclFileForDir = async ( +export async function getDefaultKclFileForDir( projectDir: string, file: FileEntry -) => { +) { // Make sure the dir is a directory. const isFileEntryDir = await window.electron.statIsDirectory(projectDir) if (!isFileEntryDir) { diff --git a/tsconfig.json b/tsconfig.json index 90de78d11..b47cad924 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,7 +11,6 @@ "vite/client", "@types/wicg-file-system-access", "node", - "@wdio/globals/types", "mocha", "@lezer/generator" ],