From 5b7535d08fe59bc6868c4f7ed2f31735ccd22fa6 Mon Sep 17 00:00:00 2001 From: Evan Simkowitz Date: Tue, 17 Sep 2024 13:10:35 -0700 Subject: [PATCH] Add release channels (#385) ## New release flow 1. Run "Bump Version" workflow with the desired version bump and the prerelease flag set to `true`. This will push a new version bump to the target branch and create a new git tag. - See below for more info on how the version bumping works. 2. A new "Build Helper" workflow run will kick off automatically for the new tag. Once it is complete, test the new build locally by downloading with the [download script](https://github.com/wavetermdev/thenextwave/blob/main/scripts/artifacts/download-staged-artifact.sh). 3. Release the new build using the [publish script](https://github.com/wavetermdev/thenextwave/blob/main/scripts/artifacts/publish-from-staging.sh). This will trigger electron-updater to distribute the package to beta users. 4. Run "Bump Version" again with a release bump (either `major`, `minor`, or `patch`) and the prerelease flag set to `false`. 6. Release the new build to all channels using the [publish script](https://github.com/wavetermdev/thenextwave/blob/main/scripts/artifacts/publish-from-staging.sh). This will trigger electron-updater to distribute the package to all users. ## Change Summary Creates a new "Bump Version" workflow to manage versioning and tag creation. Build Helper is now automated. ### Version bumps Updates the `version.cjs` script so that an argument can be passed to trigger a version bump. Under the hood, this utilizes NPM's `semver` package. If arguments are present, the version will be bumped. If only a single argument is given, the following are valid inputs: - `none`: No-op. - `patch`: Bumps the patch version. - `minor`: Bumps the minor version. - `major`: Bumps the major version. - '1', 'true': Bumps the prerelease version. If two arguments are given, the first argument must be either `none`, `patch`, `minor`, or `major`. The second argument must be `1` or `true` to bump the prerelease version. ### electron-builder We are now using the release channels support in electron-builder. This will automatically detect the channel being built based on the package version to determine which channel update files need to be generated. See [here](https://www.electron.build/tutorials/release-using-channels.html) for more information. ### Github Actions #### Bump Version This adds a new "Bump Version" workflow for managing versioning and queuing new builds. When run, this workflow will bump the version, create a new tag, and push the changes to the target branch. There is a new dropdown when queuing the "Bump Version" workflow to select what kind of version bump to perform. A bump must always be performed when running a new build to ensure consistency. I had to create a GitHub App to grant write permissions to our main branch for the version bump commits. I've made a separate workflow file to manage the version bump commits, which should help prevent tampering. Thanks to using the GitHub API directly, I am able to make these commits signed! #### Build Helper Build Helper is now triggered when new tags are created, rather than being triggered automatically. This ensures we're always creating artifacts from known checkpoints. ### Settings Adds a new `autoupdate:channel` configuration to the settings file. If unset, the default from the artifact will be used (should correspond to the channel of the artifact when downloaded). ## Future Work I want to add a release workflow that will automatically copy over the corresponding version artifacts to the release bucket when a new GitHub Release is created. I also want to separate versions into separate subdirectories in the release bucket so we can clean them up more-easily. --------- Co-authored-by: wave-builder Co-authored-by: wave-builder[bot] <181805596+wave-builder[bot]@users.noreply.github.com> --- .github/workflows/build-helper.yml | 19 +- .github/workflows/bump-version.yml | 52 +++-- Taskfile.yml | 13 ++ electron-builder.config.cjs | 1 + emain/updater.ts | 6 + frontend/types/gotypes.d.ts | 1 + package.json | 260 +++++++++++----------- pkg/wconfig/metaconsts.go | 1 + pkg/wconfig/settingsconfig.go | 1 + scripts/artifacts/README.md | 18 +- scripts/artifacts/publish-from-staging.sh | 2 + version.cjs | 52 ++++- yarn.lock | 9 + 13 files changed, 282 insertions(+), 153 deletions(-) diff --git a/.github/workflows/build-helper.yml b/.github/workflows/build-helper.yml index f627d8c8a..acbcbe1c6 100644 --- a/.github/workflows/build-helper.yml +++ b/.github/workflows/build-helper.yml @@ -2,13 +2,19 @@ # For more information on the macOS signing and notarization, see https://www.electron.build/code-signing and https://www.electron.build/configuration/mac # For more information on the Windows Code Signing, see https://docs.digicert.com/en/digicert-keylocker/ci-cd-integrations/plugins/github-custom-action-for-keypair-signing.html and https://docs.digicert.com/en/digicert-keylocker/signing-tools/sign-authenticode-with-electron-builder-using-ksp-integration.html -name: "Build Helper" -on: workflow_dispatch +name: Build Helper +run-name: Version ${{ github.ref_name }} +on: + push: + tags: + - "[0-9]+.[0-9]+.[0-9]+*" env: GO_VERSION: "1.22.5" NODE_VERSION: "22.5.1" jobs: runbuild: + outputs: + version: ${{ steps.set-version.outputs.WAVETERM_VERSION }} strategy: matrix: include: @@ -53,7 +59,7 @@ jobs: - uses: actions/setup-node@v4 with: node-version: ${{env.NODE_VERSION}} - - name: Install yarn + - name: Install Yarn run: | corepack enable yarn install @@ -62,9 +68,10 @@ jobs: with: version: 3.x repo-token: ${{ secrets.GITHUB_TOKEN }} - - name: Set Version + + - name: "Set Version" id: set-version - run: echo "WAVETERM_VERSION=$(node "./version.cjs")" >> "$GITHUB_OUTPUT" + run: echo "WAVETERM_VERSION=$(task version)" >> "$GITHUB_OUTPUT" shell: bash # Windows Code Signing Setup @@ -90,7 +97,7 @@ jobs: - name: Setup Keylocker KSP (Windows only) if: matrix.platform == 'windows' run: | - curl -X GET https://one.digicert.com/signingmanager/api-ui/v1/releases/Keylockertools-windows-x64.msi/download -H "x-api-key:%SM_API_KEY%" -o Keylockertools-windows-x64.msi + curl -X GET https://one.digicert.com/signingmanager/api-ui/v1/releases/Keylockertools-windows-x64.msi/download -H "x-api-key:%SM_API_KEY%" -o Keylockertools-windows-x64.msi msiexec /i Keylockertools-windows-x64.msi /quiet /qn C:\Windows\System32\certutil.exe -csp "DigiCert Signing Manager KSP" -key -user smctl windows certsync diff --git a/.github/workflows/bump-version.yml b/.github/workflows/bump-version.yml index 40e2dac85..16b1b424b 100644 --- a/.github/workflows/bump-version.yml +++ b/.github/workflows/bump-version.yml @@ -1,19 +1,27 @@ -# Workflow to manage bumping the package version and pushing it to the target branch. +# Workflow to manage bumping the package version and pushing it to the target branch with a new tag. +# This workflow uses a GitHub App to bypass branch protection and uses the GitHub API directly to ensure commits and tags are signed. +# For more information, see this doc: https://github.com/Nautilus-Cyberneering/pygithub/blob/main/docs/how_to_sign_automatic_commits_in_github_actions.md -name: Bump version +name: Bump Version +run-name: "branch: ${{ github.ref_name }}; version: ${{ inputs.bump }}; prerelease: ${{ inputs.is-prerelease }}" on: workflow_dispatch: inputs: bump: description: SemVer Bump required: true - default: beta type: choice + default: none options: - - beta + - none - patch - minor - major + is-prerelease: + description: Is Prerelease + required: true + type: boolean + default: true env: NODE_VERSION: "22.5.1" jobs: @@ -44,16 +52,32 @@ jobs: version: 3.x repo-token: ${{ secrets.GITHUB_TOKEN }} - - name: "Set Version: ${{ inputs.bump }}" - id: set-version - run: echo "WAVETERM_VERSION=$(task version:${{ inputs.bump }})" >> "$GITHUB_OUTPUT" + - name: "Bump Version: ${{ inputs.bump }}" + id: bump-version + run: echo "WAVETERM_VERSION=$( task version -- ${{ inputs.bump }} ${{inputs.is-prerelease}} )" >> "$GITHUB_OUTPUT" shell: bash - - name: "Push version bump: ${{ steps.set-version.outputs.WAVETERM_VERSION }}" + - name: "Push version bump: ${{ steps.bump-version.outputs.WAVETERM_VERSION }}" run: | - git config user.name wave-builder - git config user.email builds@commandline.dev - git add package.json - git commit -m "Bump version to ${{ steps.set-version.outputs.WAVETERM_VERSION }}" - git tag -a ${{ steps.set-version.outputs.WAVETERM_VERSION }} -m "Bump version to ${{ steps.set-version.outputs.WAVETERM_VERSION }}" - git push + # Create a new commit for the package version bump in package.json + export VERSION=${{ steps.bump-version.outputs.WAVETERM_VERSION }} + export MESSAGE="chore: bump package version to $VERSION" + export FILE=package.json + export BRANCH=${{github.ref_name}} + export SHA=$( git rev-parse $BRANCH:$FILE ) + export CONTENT=$( base64 -i $FILE ) + gh api --method PUT /repos/:owner/:repo/contents/$FILE \ + --field branch="$BRANCH" \ + --field message="$MESSAGE" \ + --field content="$CONTENT" \ + --field sha="$SHA" + + # Fetch the new commit and create a tag referencing it + git fetch + export TAG_SHA=$( git rev-parse origin/$BRANCH ) + gh api --method POST /repos/:owner/:repo/git/refs \ + --field ref="refs/tags/$VERSION" \ + --field sha="$TAG_SHA" + shell: bash + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} diff --git a/Taskfile.yml b/Taskfile.yml index 923db2d69..998f2367a 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -200,6 +200,19 @@ tasks: - frontend/app/store/services.ts - frontend/app/store/wshserver.ts + version: + desc: Get the current package version, or bump version if args are present. + summary: | + If no arguments are present, the current version will be returned. + If only a single argument is given, the following are valid inputs: + - `none`: No-op. + - `patch`: Bumps the patch version. + - `minor`: Bumps the minor version. + - `major`: Bumps the major version. + - '1', 'true': Bumps the prerelease version. + If two arguments are given, the first argument must be either `none`, `patch`, `minor`, or `major`. The second argument must be `1` or `true` to bump the prerelease version. + cmd: node version.cjs {{.CLI_ARGS}} + yarn: desc: Runs `yarn` internal: true diff --git a/electron-builder.config.cjs b/electron-builder.config.cjs index f72f9369e..8ff672a26 100644 --- a/electron-builder.config.cjs +++ b/electron-builder.config.cjs @@ -12,6 +12,7 @@ const config = { productName: pkg.productName, executableName: pkg.name, artifactName: "${productName}-${platform}-${arch}-${version}.${ext}", + generateUpdatesFilesForAllChannels: true, npmRebuild: false, nodeGypRebuild: false, electronCompile: false, diff --git a/emain/updater.ts b/emain/updater.ts index e75f98550..8665d0f97 100644 --- a/emain/updater.ts +++ b/emain/updater.ts @@ -29,6 +29,12 @@ export class Updater { autoUpdater.autoInstallOnAppQuit = settings["autoupdate:installonquit"]; + // Only update the release channel if it's specified, otherwise use the one configured in the artifact. + const channel = settings["autoupdate:channel"]; + if (channel) { + autoUpdater.channel = channel; + } + autoUpdater.removeAllListeners(); autoUpdater.on("error", (err) => { diff --git a/frontend/types/gotypes.d.ts b/frontend/types/gotypes.d.ts index c61308762..4eafb43a4 100644 --- a/frontend/types/gotypes.d.ts +++ b/frontend/types/gotypes.d.ts @@ -410,6 +410,7 @@ declare global { "autoupdate:enabled"?: boolean; "autoupdate:intervalms"?: number; "autoupdate:installonquit"?: boolean; + "autoupdate:channel"?: string; "widget:*"?: boolean; "widget:showhelp"?: boolean; "window:*"?: boolean; diff --git a/package.json b/package.json index 62d3c66ab..acadd80df 100644 --- a/package.json +++ b/package.json @@ -1,131 +1,133 @@ { - "name": "thenextwave", - "author": { - "name": "Command Line Inc", - "email": "info@commandline.dev" - }, - "productName": "TheNextWave", - "description": "An Open-Source, AI-Native, Terminal Built for Seamless Workflows", - "license": "Apache-2.0", - "version": "0.1.12", - "homepage": "https://waveterm.dev", - "build": { - "appId": "dev.commandline.thenextwave" - }, - "private": true, - "main": "./dist/main/index.js", - "type": "module", - "scripts": { - "dev": "electron-vite dev", - "start": "electron-vite preview", - "build:dev": "electron-vite build --mode development", - "build:prod": "electron-vite build --mode production", - "storybook": "storybook dev -p 6006 --no-open", - "build-storybook": "storybook build", - "coverage": "vitest run --coverage", - "test": "vitest", - "postinstall": "electron-builder install-app-deps" - }, - "devDependencies": { - "@chromatic-com/storybook": "^2.0.2", - "@eslint/js": "^9.10.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@storybook/addon-essentials": "^8.3.0", - "@storybook/addon-interactions": "^8.3.0", - "@storybook/addon-links": "^8.3.0", - "@storybook/blocks": "^8.3.0", - "@storybook/react": "^8.3.0", - "@storybook/react-vite": "^8.3.0", - "@storybook/test": "^8.3.0", - "@types/css-tree": "^2", - "@types/debug": "^4", - "@types/electron": "^1.6.10", - "@types/node": "^22.5.4", - "@types/papaparse": "^5", - "@types/pngjs": "^6.0.5", - "@types/react": "^18.3.5", - "@types/react-dom": "^18.3.0", - "@types/shell-quote": "^1", - "@types/sprintf-js": "^1", - "@types/throttle-debounce": "^5", - "@types/tinycolor2": "^1", - "@types/uuid": "^10.0.0", - "@vitejs/plugin-react-swc": "^3.7.0", - "@vitest/coverage-istanbul": "^2.1.1", - "electron": "^32.1.0", - "electron-builder": "^25.0.5", - "electron-vite": "^2.3.0", - "eslint": "^9.10.0", - "eslint-config-prettier": "^9.1.0", - "less": "^4.2.0", - "prettier": "^3.3.3", - "prettier-plugin-jsdoc": "^1.3.0", - "prettier-plugin-organize-imports": "^4.0.0", - "rollup-plugin-flow": "^1.1.1", - "storybook": "^8.3.0", - "ts-node": "^10.9.2", - "tslib": "^2.6.3", - "tsx": "^4.19.1", - "typescript": "^5.6.2", - "typescript-eslint": "^8.5.0", - "vite": "^5.4.6", - "vite-plugin-image-optimizer": "^1.1.8", - "vite-plugin-static-copy": "^1.0.6", - "vite-plugin-svgr": "^4.2.0", - "vite-tsconfig-paths": "^5.0.1", - "vitest": "^2.1.1" - }, - "dependencies": { - "@monaco-editor/loader": "^1.4.0", - "@monaco-editor/react": "^4.6.0", - "@observablehq/plot": "^0.6.16", - "@react-hook/resize-observer": "^2.0.2", - "@table-nav/core": "^0.0.7", - "@table-nav/react": "^0.0.7", - "@tanstack/react-table": "^8.20.5", - "@types/color": "^3.0.6", - "@xterm/addon-fit": "^0.10.0", - "@xterm/addon-serialize": "^0.13.0", - "@xterm/addon-web-links": "^0.11.0", - "@xterm/addon-webgl": "^0.18.0", - "@xterm/xterm": "^5.5.0", - "base64-js": "^1.5.1", - "clsx": "^2.1.1", - "color": "^4.2.3", - "css-tree": "^3.0.0", - "dayjs": "^1.11.13", - "debug": "^4.3.7", - "electron-updater": "6.3.4", - "fast-average-color": "^9.4.0", - "htl": "^0.3.1", - "html-to-image": "^1.11.11", - "immer": "^10.1.1", - "jotai": "^2.9.3", - "monaco-editor": "^0.51.0", - "overlayscrollbars": "^2.10.0", - "overlayscrollbars-react": "^0.5.6", - "papaparse": "^5.4.1", - "pngjs": "^7.0.0", - "react": "^18.3.1", - "react-dnd": "^16.0.1", - "react-dnd-html5-backend": "^16.0.1", - "react-dom": "^18.3.1", - "react-frame-component": "^5.2.7", - "react-gauge-chart": "^0.5.1", - "react-markdown": "^9.0.1", - "rehype-highlight": "^7.0.0", - "rehype-raw": "^7.0.0", - "rehype-sanitize": "^6.0.0", - "rehype-slug": "^6.0.0", - "remark-flexible-toc": "^1.1.1", - "remark-gfm": "^4.0.0", - "rxjs": "^7.8.1", - "shell-quote": "^1.8.1", - "sprintf-js": "^1.1.3", - "throttle-debounce": "^5.0.2", - "tinycolor2": "^1.6.0", - "use-device-pixel-ratio": "^1.1.2", - "winston": "^3.14.2" - }, - "packageManager": "yarn@4.4.1" + "name": "thenextwave", + "author": { + "name": "Command Line Inc", + "email": "info@commandline.dev" + }, + "productName": "TheNextWave", + "description": "An Open-Source, AI-Native, Terminal Built for Seamless Workflows", + "license": "Apache-2.0", + "version": "0.1.13-beta.20", + "homepage": "https://waveterm.dev", + "build": { + "appId": "dev.commandline.thenextwave" + }, + "private": true, + "main": "./dist/main/index.js", + "type": "module", + "scripts": { + "dev": "electron-vite dev", + "start": "electron-vite preview", + "build:dev": "electron-vite build --mode development", + "build:prod": "electron-vite build --mode production", + "storybook": "storybook dev -p 6006 --no-open", + "build-storybook": "storybook build", + "coverage": "vitest run --coverage", + "test": "vitest", + "postinstall": "electron-builder install-app-deps" + }, + "devDependencies": { + "@chromatic-com/storybook": "^2.0.2", + "@eslint/js": "^9.10.0", + "@rollup/plugin-node-resolve": "^15.2.3", + "@storybook/addon-essentials": "^8.3.0", + "@storybook/addon-interactions": "^8.3.0", + "@storybook/addon-links": "^8.3.0", + "@storybook/blocks": "^8.3.0", + "@storybook/react": "^8.3.0", + "@storybook/react-vite": "^8.3.0", + "@storybook/test": "^8.3.0", + "@types/css-tree": "^2", + "@types/debug": "^4", + "@types/electron": "^1.6.10", + "@types/node": "^22.5.4", + "@types/papaparse": "^5", + "@types/pngjs": "^6.0.5", + "@types/react": "^18.3.5", + "@types/react-dom": "^18.3.0", + "@types/semver": "^7", + "@types/shell-quote": "^1", + "@types/sprintf-js": "^1", + "@types/throttle-debounce": "^5", + "@types/tinycolor2": "^1", + "@types/uuid": "^10.0.0", + "@vitejs/plugin-react-swc": "^3.7.0", + "@vitest/coverage-istanbul": "^2.1.1", + "electron": "^32.1.0", + "electron-builder": "^25.0.5", + "electron-vite": "^2.3.0", + "eslint": "^9.10.0", + "eslint-config-prettier": "^9.1.0", + "less": "^4.2.0", + "prettier": "^3.3.3", + "prettier-plugin-jsdoc": "^1.3.0", + "prettier-plugin-organize-imports": "^4.0.0", + "rollup-plugin-flow": "^1.1.1", + "semver": "^7.6.3", + "storybook": "^8.3.0", + "ts-node": "^10.9.2", + "tslib": "^2.6.3", + "tsx": "^4.19.1", + "typescript": "^5.6.2", + "typescript-eslint": "^8.5.0", + "vite": "^5.4.6", + "vite-plugin-image-optimizer": "^1.1.8", + "vite-plugin-static-copy": "^1.0.6", + "vite-plugin-svgr": "^4.2.0", + "vite-tsconfig-paths": "^5.0.1", + "vitest": "^2.1.1" + }, + "dependencies": { + "@monaco-editor/loader": "^1.4.0", + "@monaco-editor/react": "^4.6.0", + "@observablehq/plot": "^0.6.16", + "@react-hook/resize-observer": "^2.0.2", + "@table-nav/core": "^0.0.7", + "@table-nav/react": "^0.0.7", + "@tanstack/react-table": "^8.20.5", + "@types/color": "^3.0.6", + "@xterm/addon-fit": "^0.10.0", + "@xterm/addon-serialize": "^0.13.0", + "@xterm/addon-web-links": "^0.11.0", + "@xterm/addon-webgl": "^0.18.0", + "@xterm/xterm": "^5.5.0", + "base64-js": "^1.5.1", + "clsx": "^2.1.1", + "color": "^4.2.3", + "css-tree": "^3.0.0", + "dayjs": "^1.11.13", + "debug": "^4.3.7", + "electron-updater": "6.3.4", + "fast-average-color": "^9.4.0", + "htl": "^0.3.1", + "html-to-image": "^1.11.11", + "immer": "^10.1.1", + "jotai": "^2.9.3", + "monaco-editor": "^0.51.0", + "overlayscrollbars": "^2.10.0", + "overlayscrollbars-react": "^0.5.6", + "papaparse": "^5.4.1", + "pngjs": "^7.0.0", + "react": "^18.3.1", + "react-dnd": "^16.0.1", + "react-dnd-html5-backend": "^16.0.1", + "react-dom": "^18.3.1", + "react-frame-component": "^5.2.7", + "react-gauge-chart": "^0.5.1", + "react-markdown": "^9.0.1", + "rehype-highlight": "^7.0.0", + "rehype-raw": "^7.0.0", + "rehype-sanitize": "^6.0.0", + "rehype-slug": "^6.0.0", + "remark-flexible-toc": "^1.1.1", + "remark-gfm": "^4.0.0", + "rxjs": "^7.8.1", + "shell-quote": "^1.8.1", + "sprintf-js": "^1.1.3", + "throttle-debounce": "^5.0.2", + "tinycolor2": "^1.6.0", + "use-device-pixel-ratio": "^1.1.2", + "winston": "^3.14.2" + }, + "packageManager": "yarn@4.4.1" } diff --git a/pkg/wconfig/metaconsts.go b/pkg/wconfig/metaconsts.go index 92c31ae34..ea4c5908f 100644 --- a/pkg/wconfig/metaconsts.go +++ b/pkg/wconfig/metaconsts.go @@ -32,6 +32,7 @@ const ( ConfigKey_AutoUpdateEnabled = "autoupdate:enabled" ConfigKey_AutoUpdateIntervalMs = "autoupdate:intervalms" ConfigKey_AutoUpdateInstallOnQuit = "autoupdate:installonquit" + ConfigKey_AutoUpdateChannel = "autoupdate:channel" ConfigKey_WidgetClear = "widget:*" ConfigKey_WidgetShowHelp = "widget:showhelp" diff --git a/pkg/wconfig/settingsconfig.go b/pkg/wconfig/settingsconfig.go index 7f1da030b..f3de678a6 100644 --- a/pkg/wconfig/settingsconfig.go +++ b/pkg/wconfig/settingsconfig.go @@ -64,6 +64,7 @@ type SettingsType struct { AutoUpdateEnabled bool `json:"autoupdate:enabled,omitempty"` AutoUpdateIntervalMs float64 `json:"autoupdate:intervalms,omitempty"` AutoUpdateInstallOnQuit bool `json:"autoupdate:installonquit,omitempty"` + AutoUpdateChannel string `json:"autoupdate:channel,omitempty"` WidgetClear bool `json:"widget:*,omitempty"` WidgetShowHelp bool `json:"widget:showhelp,omitempty"` diff --git a/scripts/artifacts/README.md b/scripts/artifacts/README.md index d5d315fed..58796d813 100644 --- a/scripts/artifacts/README.md +++ b/scripts/artifacts/README.md @@ -1,9 +1,18 @@ # Building for release +## Bump Version workflow + +All releases start by first bumping the package version and creating a new Git tag. We have a workflow set up to automate this. + +To run it, trigger a new run of the [Bump Version workflow](https://github.com/wavetermdev/thenextwave/actions/workflows/bump-version.yml). When triggering the run, you will be +prompted to select a version bump type, either `none`, `patch`, `minor`, or `major`, and whether the version is prerelease or not. This determines how much the version number is incremented. +See [`version.cjs`](../../version.cjs) for more details on how this works. + +Once the tag has been created, a new [Build Helper](#build-helper-workflow) run will be automatically queued to generate the artifacts. + ## Build Helper workflow -Our release builds are managed by the "Build Helper" GitHub Action, which is defined -in [`build-helper.yml`](../../.github/workflows/build-helper.yml). +Our release builds are managed by the [Build Helper workflow](https://github.com/wavetermdev/thenextwave/actions/workflows/build-helper.yml). Under the hood, this will call the `package` task in [`Taskfile.yml`](../../Taskfile.yml), which will build the Electron codebase using @@ -34,6 +43,11 @@ With each release, `latest-mac.yml`, `latest-linux.yml`, and `latest-linux-arm64 newest release. These also include file sizes and checksums to aid in validating the packages. The app will check these files in our S3 bucket every hour to see if a new version is available. +### Update channels + +We utilize update channels to roll out beta and stable releases. These are determined based on the package versioning [described above](#bump-version-workflow). Users can +select their update channel using the `autoupdate:channel` setting in Wave. See [here](https://www.electron.build/tutorials/release-using-channels.html) for more information. + ### Homebrew Homebrew is automatically bumped when new artifacts are published. diff --git a/scripts/artifacts/publish-from-staging.sh b/scripts/artifacts/publish-from-staging.sh index a1785a7c3..5b8e433f4 100755 --- a/scripts/artifacts/publish-from-staging.sh +++ b/scripts/artifacts/publish-from-staging.sh @@ -1,3 +1,5 @@ +#!/bin/bash + # Takes a release from our staging bucket and publishes it to the public download bucket. # Usage: publish-from-staging.sh # Example: publish-from-staging.sh 0.1.0 storage diff --git a/version.cjs b/version.cjs index 512131da9..fca8c93e0 100644 --- a/version.cjs +++ b/version.cjs @@ -1,9 +1,57 @@ +/** + * Script to get the current package version and bump the version, if specified. + * + * If no arguments are present, the current version will returned. + * If only a single argument is given, the following are valid inputs: + * - `none`: No-op. + * - `patch`: Bumps the patch version. + * - `minor`: Bumps the minor version. + * - `major`: Bumps the major version. + * - '1', 'true': Bumps the prerelease version. + * If two arguments are given, the first argument must be either `none`, `patch`, `minor`, or `major`. The second argument must be `1` or `true` to bump the prerelease version. + */ + const path = require("path"); -const packageJson = require(path.resolve(__dirname, "package.json")); +const packageJsonPath = path.resolve(__dirname, "package.json"); +const packageJson = require(packageJsonPath); const VERSION = `${packageJson.version}`; module.exports = VERSION; if (typeof require !== "undefined" && require.main === module) { - console.log(VERSION); + if (process.argv.length > 2) { + const fs = require("fs"); + const semver = require("semver"); + + const action = process.argv[2]; + const isPrerelease = + process.argv.length > 3 + ? process.argv[3] === "true" || process.argv[3] === "1" + : action === "true" || action === "1"; + let newVersion = packageJson.version; + switch (action) { + case "major": + case "minor": + case "patch": + newVersion = semver.inc( + VERSION, + `${isPrerelease ? "pre" : ""}${action}`, + null, + isPrerelease ? "beta" : null + ); + break; + case "none": + case "true": + case "1": + if (isPrerelease) newVersion = semver.inc(VERSION, "prerelease", null, "beta"); + break; + default: + throw new Error(`Unknown action ${action}`); + } + packageJson.version = newVersion; + fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 4) + "\n"); + console.log(newVersion); + } else { + console.log(VERSION); + } } diff --git a/yarn.lock b/yarn.lock index eff1e917f..2f517643b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2496,6 +2496,13 @@ __metadata: languageName: node linkType: hard +"@types/semver@npm:^7": + version: 7.5.8 + resolution: "@types/semver@npm:7.5.8" + checksum: 10c0/8663ff927234d1c5fcc04b33062cb2b9fcfbe0f5f351ed26c4d1e1581657deebd506b41ff7fdf89e787e3d33ce05854bc01686379b89e9c49b564c4cfa988efa + languageName: node + linkType: hard + "@types/send@npm:*": version: 0.17.4 resolution: "@types/send@npm:0.17.4" @@ -10208,6 +10215,7 @@ __metadata: "@types/pngjs": "npm:^6.0.5" "@types/react": "npm:^18.3.5" "@types/react-dom": "npm:^18.3.0" + "@types/semver": "npm:^7" "@types/shell-quote": "npm:^1" "@types/sprintf-js": "npm:^1" "@types/throttle-debounce": "npm:^5" @@ -10261,6 +10269,7 @@ __metadata: remark-gfm: "npm:^4.0.0" rollup-plugin-flow: "npm:^1.1.1" rxjs: "npm:^7.8.1" + semver: "npm:^7.6.3" shell-quote: "npm:^1.8.1" sprintf-js: "npm:^1.1.3" storybook: "npm:^8.3.0"