diff --git a/.github/get-dev-version.js b/.github/get-dev-version.js new file mode 100644 index 0000000..d6bfbff --- /dev/null +++ b/.github/get-dev-version.js @@ -0,0 +1,48 @@ +const {Firestore} = require('@google-cloud/firestore'); +const firestore = new Firestore(); +const [commitHash, pkgVersion] = process.argv.slice(2); + +async function getBumpVersion(pkg_version, hash) { + const pairsCollection = firestore.collection('pairs'); + let bump_version; + + await firestore.runTransaction(async (t) => { + const query = pairsCollection.where('pkg_version', '==', pkg_version).where('hash', '==', hash); + const querySnapshot = await t.get(query); + + if (!querySnapshot.empty) { + // Pairing exists + bump_version = querySnapshot.docs[0].data().bump_version; + } else { + // Pairing does not exist + const latestDocSnapshot = await t.get(pairsCollection.where('pkg_version', '==', pkg_version).orderBy('created_at', 'desc').limit(1)); + if (!latestDocSnapshot.empty) { + const latestDoc = latestDocSnapshot.docs[0]; + const latestBumpVersion = latestDoc.data().bump_version; + const parts = latestBumpVersion.split('.'); + parts[2] = String(Number(parts[2]) + 1); // Bump the version + bump_version = parts.join('.'); + } else { + // Collection is empty, start with default bump_version + bump_version = pkg_version; + } + + // Save the new pairing + await t.set(pairsCollection.doc(), { + pkg_version: pkg_version, + hash: hash, + created_at: Firestore.Timestamp.now(), + bump_version: bump_version + }); + } + }); + + return bump_version; +} + +// Use the function +getBumpVersion(pkgVersion, commitHash).then(bump_version => { + console.log(`::set-output name=version::${bump_version}`); +}).catch(err => { + console.error(err); +}); \ No newline at end of file diff --git a/.github/workflows/build-sign-notarize.yml b/.github/workflows/build-sign-notarize.yml index 26b19fb..ced0708 100644 --- a/.github/workflows/build-sign-notarize.yml +++ b/.github/workflows/build-sign-notarize.yml @@ -22,35 +22,21 @@ on: s3-custom-notarized-installers-key: description: 'The S3 build key includes the installer files: [zip, dmg, etc, yml] from notarization strategy done outside of electron' value: ${{ jobs.notarize-mac-installers.outputs.s3-installers-key }} + build-version: + description: 'The version of the build generated for dev' + value: ${{ jobs.build.outputs.build-version }} jobs: build: runs-on: macos-latest outputs: s3-artifacts-key: ${{ steps.s3-artifact-uploader.outputs.key }} + build-version: ${{ steps.gui-version.outputs.version }} steps: - uses: teaxyz/setup@v0 with: version: 0.26.2 - uses: actions/checkout@v3 - - name: get gui version - id: gui-version - run: | - tea +stedolan.github.io/jq - export version=$(echo $(cat modules/desktop/package.json) | jq --raw-output .version) - export postfix= - release="release" - if [ $prefix == $release ]; - then - echo "no postfix" - else - echo "dev" - export postfix=-dev - fi - echo "version=$version$postfix" >> $GITHUB_OUTPUT - env: - prefix: ${{ inputs.s3-prefix }} - - name: cache node_modules build # TODO: cache issue in our self-hosted macos runner ESPIPE: invalid seek, read # but its ok to ignore, its still the fastest builder @@ -73,9 +59,32 @@ jobs: ./modules/desktop/.svelte-kit ./modules/desktop/build + - name: get gui version + id: gui-version + run: | + tea +stedolan.github.io/jq + export version=$(echo $(cat modules/desktop/package.json) | jq --raw-output .version) + export postfix= + release="release" + if [ $prefix == $release ]; + then + echo "no postfix" + else + echo $google_service_account > sa.json + export GOOGLE_APPLICATION_CREDENTIALS="$(pwd)/sa.json" + tea -E pnpm install + tea node .github/get-dev-version.js $hash $version + fi + env: + prefix: ${{ inputs.s3-prefix }} + google_service_account: ${{ secrets.GOOGLE_SERVICE_ACCOUNT }} + hash: ${{ github.sha }} + - name: build dev if: inputs.s3-prefix != 'release' - run: tea -SE xc dist + run: | + jq ".version=\"$PUBLIC_VERSION\"" modules/desktop/package.json > temp.json && mv temp.json modules/desktop/package.json + tea -SE xc dist env: SYNC_I18N: 1 PUBLIC_MIXPANEL_TOKEN: ${{ secrets.MIXPANEL_PROJECT_TOKEN }} @@ -86,6 +95,7 @@ jobs: CSC_LINK: ${{ secrets.GUI_APPLE_CERTIFICATE }} CSC_KEY_PASSWORD: ${{ secrets.GUI_APPLE_CERTIFICATE_PASSWORD }} CSC_NAME: ${{ secrets.APPLE_IDENTITY_NO_PREFIX }} + PUBLISH_URL: "https://gui.tea.xyz/dev" # slower build but dmg output is much nicer looking - name: build release diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7531dd7..1af1039 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -119,12 +119,9 @@ jobs: arm64: ${{ steps.app_files.outputs.dmg_arm64 }} x86: ${{ steps.app_files.outputs.dmg_x86 }} run: | - aws s3 cp \ - "dist/$arm64" \ - "s3://preview.gui.tea.xyz/main/$arm64" - aws s3 cp \ - "dist/$x86" \ - "s3://preview.gui.tea.xyz/main/$x86" + cd dist && \ + aws s3 sync . \ + "s3://preview.gui.tea.xyz/dev/" - uses: actions/setup-node@v3 with: @@ -136,7 +133,8 @@ jobs: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} PLATFORM: darwin-aarch64 EXT: dmg - DOWNLOAD_URL: http://preview.gui.tea.xyz.s3-website-us-east-1.amazonaws.com/main/${{ steps.app_files.outputs.dmg_arm64 }} + VERSION: ${{ needs.build_desktop.outputs.build-version }}-dev + DOWNLOAD_URL: http://preview.gui.tea.xyz.s3-website-us-east-1.amazonaws.com/dev/${{ steps.app_files.outputs.dmg_arm64 }} - name: Slack Notification X86 run: ./.github/notify-slack.js @@ -144,4 +142,9 @@ jobs: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} PLATFORM: darwin-x86+64 EXT: dmg - DOWNLOAD_URL: http://preview.gui.tea.xyz.s3-website-us-east-1.amazonaws.com/main/${{ steps.app_files.outputs.dmg_x86 }} + VERSION: ${{ needs.build_desktop.outputs.build-version }}-dev + DOWNLOAD_URL: http://preview.gui.tea.xyz.s3-website-us-east-1.amazonaws.com/dev/${{ steps.app_files.outputs.dmg_x86 }} + - run: | + aws cloudfront create-invalidation \ + --distribution-id ${{ secrets.AWS_CF_GUI_RELEASE_ID }} \ + --paths '/dev/latest-mac.yml' \ No newline at end of file diff --git a/modules/desktop/electron-builder.config.cjs b/modules/desktop/electron-builder.config.cjs index b7f4249..1f26f0a 100644 --- a/modules/desktop/electron-builder.config.cjs +++ b/modules/desktop/electron-builder.config.cjs @@ -56,6 +56,6 @@ module.exports = { // this determines the configuration of the auto-update feature publish: { provider: "generic", - url: "https://gui.tea.xyz/release" + url: process.env.PUBLISH_URL || "https://gui.tea.xyz/release" } }; diff --git a/modules/desktop/electron/libs/auto-updater.ts b/modules/desktop/electron/libs/auto-updater.ts index db25332..c638fcd 100644 --- a/modules/desktop/electron/libs/auto-updater.ts +++ b/modules/desktop/electron/libs/auto-updater.ts @@ -1,6 +1,9 @@ import { type AppUpdater, autoUpdater } from "electron-updater"; import log from "./logger"; import { MainWindowNotifier } from "./types"; +import { getTeaPath } from "./tea-dir"; +import path from "path"; +import fs from "fs"; type AutoUpdateStatus = { status: "up-to-date" | "available" | "ready"; @@ -30,6 +33,8 @@ export function checkUpdater(notifier: MainWindowNotifier): AppUpdater { checkForUpdates(); }, 1000 * 60 * 30); // check for updates every 30 minutes } + + setPublishURL(); } catch (error) { log.error(error); } @@ -103,3 +108,15 @@ autoUpdater.on("update-downloaded", (info) => { log.info("update-downloaded"); sendStatusToWindow({ status: "ready", version: info.version }); }); + +export const isDev = () => fs.existsSync(path.join(getTeaPath(), "tea.xyz/gui/dev")); + +async function setPublishURL() { + try { + const feedUrl = `https://gui.tea.xyz/${isDev() ? "dev" : "release"}`; + log.info(`feedUrl$: ${feedUrl}`); + autoUpdater.setFeedURL(feedUrl); + } catch (error) { + log.error(error); + } +} diff --git a/modules/desktop/electron/libs/ipc.ts b/modules/desktop/electron/libs/ipc.ts index cdf7ebd..e72a0ab 100644 --- a/modules/desktop/electron/libs/ipc.ts +++ b/modules/desktop/electron/libs/ipc.ts @@ -8,7 +8,7 @@ import { installPackage, openPackageEntrypointInTerminal, syncPantry } from "./c import { initializeTeaCli, cliInitializationState } from "./initialize"; -import { getAutoUpdateStatus, getUpdater } from "./auto-updater"; +import { getAutoUpdateStatus, getUpdater, isDev } from "./auto-updater"; import { loadPackageCache, writePackageCache } from "./package"; import { nanoid } from "nanoid"; @@ -217,4 +217,13 @@ export default function initializeHandlers({ notifyMainWindow }: HandlerOptions) log.error(error); } }); + + ipcMain.handle("is-dev", async () => { + try { + return isDev(); + } catch (error) { + log.error(error); + return false; + } + }); } diff --git a/modules/desktop/electron/libs/tea-dir.ts b/modules/desktop/electron/libs/tea-dir.ts index fbfcafa..4e09d19 100644 --- a/modules/desktop/electron/libs/tea-dir.ts +++ b/modules/desktop/electron/libs/tea-dir.ts @@ -25,7 +25,7 @@ export const getTeaPath = () => { teaPath = execSync("tea --prefix", { encoding: "utf8" }).trim(); log.info(teaPath); } catch (error) { - log.info("Could not run tea --prefix. Using default path.", info); + log.info("Could not run tea --prefix. Using default path."); teaPath = path.join(homePath, "./.tea"); } diff --git a/modules/desktop/electron/vite.config.js b/modules/desktop/electron/vite.config.js index ca33946..0214153 100644 --- a/modules/desktop/electron/vite.config.js +++ b/modules/desktop/electron/vite.config.js @@ -23,7 +23,7 @@ const config = { sourcemap: true, outDir: "dist", assetsDir: ".", - minify: process.env.MODE !== "development", + minify: false, lib: { entry: "electron.ts", formats: ["cjs"] diff --git a/modules/desktop/src/components/top-bar/top-bar.svelte b/modules/desktop/src/components/top-bar/top-bar.svelte index a2c1dba..9c93972 100644 --- a/modules/desktop/src/components/top-bar/top-bar.svelte +++ b/modules/desktop/src/components/top-bar/top-bar.svelte @@ -5,9 +5,15 @@ import { t } from "$libs/translations"; import TopBarMenu from "./top-bar-menu.svelte"; - import { topbarDoubleClick } from "$libs/native-electron"; + import { isDev, topbarDoubleClick } from "$libs/native-electron"; + import { onMount } from "svelte"; let { nextPath, prevPath } = navStore; + + let dev = false; + onMount(async () => { + dev = await isDev(); + });
-

beta

+

{dev ? "dev" : "beta"}