diff --git a/.github/workflows/Tauri-Release.yml b/.github/workflows/Tauri-Release.yml new file mode 100644 index 000000000..0cf9db8e3 --- /dev/null +++ b/.github/workflows/Tauri-Release.yml @@ -0,0 +1,312 @@ +name: Manually Triggered Desktop Release + +permissions: + contents: write + actions: read + +concurrency: + group: desktop-release-${{ github.ref }} + cancel-in-progress: true + +on: + workflow_dispatch: + inputs: + version-bump: + description: 'The type of version bump (major, minor, or patch)' + required: true + default: 'patch' + type: choice + options: + - patch + - minor + - major + +jobs: + version: + runs-on: ubuntu-latest + outputs: + new_version: ${{ steps.bump.outputs.new_version }} + changelog: ${{ steps.changelog.outputs.clean_changelog }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Configure Git + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + - name: Compute New Version + id: bump + run: | + set -euo pipefail + + # Fetch the latest tag from the repository + LATEST_TAG=$(git tag --sort=-v:refname | head -n 1) + if [[ -z "$LATEST_TAG" ]]; then + LATEST_TAG="v0.0.0" + fi + + # Parse the latest tag to get major, minor, and patch numbers + if [[ "$LATEST_TAG" =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+) ]]; then + MAJOR=${BASH_REMATCH[1]} + MINOR=${BASH_REMATCH[2]} + PATCH=${BASH_REMATCH[3]} + else + echo "Could not parse latest tag: $LATEST_TAG. Starting from v0.0.0." + MAJOR=0; MINOR=0; PATCH=0 + fi + + # Increment the version based on the manual input + BUMP_TYPE="${{ github.event.inputs.version-bump }}" + if [ "$BUMP_TYPE" == "major" ]; then + MAJOR=$((MAJOR + 1)); MINOR=0; PATCH=0 + elif [ "$BUMP_TYPE" == "minor" ]; then + MINOR=$((MINOR + 1)); PATCH=0 + else + PATCH=$((PATCH + 1)) + fi + + NEW_VERSION="v$MAJOR.$MINOR.$PATCH" + VERSION_NO_V="$MAJOR.$MINOR.$PATCH" + + echo "new_version=$NEW_VERSION" >> "$GITHUB_OUTPUT" + echo "version_no_v=$VERSION_NO_V" >> "$GITHUB_OUTPUT" + echo "New version will be: $NEW_VERSION" + + - name: Update Version Files + run: | + VERSION_NO_V="${{ steps.bump.outputs.version_no_v }}" + + # Update package.json + jq --arg ver "$VERSION_NO_V" '.version = $ver' package.json > package.json.tmp + mv package.json.tmp package.json + + # Update src-tauri/tauri.conf.json + jq --arg ver "$VERSION_NO_V" '.version = $ver' src-tauri/tauri.conf.json > src-tauri/tauri.conf.json.tmp + mv src-tauri/tauri.conf.json.tmp src-tauri/tauri.conf.json + + # Update src-tauri/Cargo.toml + sed -i "s/^version = \".*\"/version = \"$VERSION_NO_V\"/" src-tauri/Cargo.toml + + echo "Updated version files to $VERSION_NO_V" + + - name: Generate Changelog + id: changelog + uses: TriPSs/conventional-changelog-action@v6 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + skip-on-empty: 'false' + skip-commit: 'true' + skip-version-file: 'true' + skip-git-pull: 'true' + skip-tag: 'true' + git-push: 'false' + output-file: 'false' + release-count: 0 + tag-prefix: 'v' + + - name: Commit Version Bump + run: | + NEW_VERSION="${{ steps.bump.outputs.new_version }}" + + git add package.json src-tauri/tauri.conf.json src-tauri/Cargo.toml + git commit -m "chore: bump version to $NEW_VERSION" + git tag "$NEW_VERSION" + git push origin HEAD:${{ github.ref_name }} + git push origin "$NEW_VERSION" + + build-tauri: + runs-on: ${{ matrix.os }} + needs: version + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-2022, macos-latest] + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + ref: ${{ github.ref_name }} + fetch-depth: 0 + + - name: Pull latest changes + run: git pull origin ${{ github.ref_name }} + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 22 + + - name: Cache Node.js Dependencies + uses: actions/cache@v4 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: ${{ runner.os }}-node- + + - name: Install Dependencies + run: npm ci + shell: bash + + - name: Setup Rust (stable) + uses: dtolnay/rust-toolchain@stable + + - name: Install Linux Dependencies (Ubuntu) + if: matrix.os == 'ubuntu-latest' + run: | + sudo apt update + sudo apt install -y libwebkit2gtk-4.1-dev \ + build-essential \ + curl \ + wget \ + file \ + libxdo-dev \ + libssl-dev \ + libayatana-appindicator3-dev \ + librsvg2-dev + shell: bash + + - name: Install macOS Dependencies + if: matrix.os == 'macos-latest' + run: | + brew update + brew install pkg-config + shell: bash + + - name: Install Windows Dependencies + if: matrix.os == 'windows-2022' + shell: powershell + run: | + choco install -y wixtoolset nsis webview2-runtime + + - name: Cache Rust Dependencies + uses: Swatinem/rust-cache@v2 + with: + workspaces: './src-tauri' + + - name: Build Tauri App + run: npm run tauri build + shell: bash + + # TODO: Add code signing steps here once certificates are obtained + # - Windows: Sign .msi and .exe files with Authenticode via SignPath + # - macOS: Sign .app bundles and .dmg with Apple Developer ID + # - Linux: Sign .deb and .AppImage with GPG + # Reference: Issue #631 + + - name: Upload Tauri Build Artifacts + uses: actions/upload-artifact@v4 + with: + name: Tauri Build Artifacts (${{ matrix.os }}) + path: | + src-tauri/target/release/bundle + + create-release: + runs-on: ubuntu-latest + needs: [version, build-tauri] + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + ref: ${{ github.ref_name }} + + - name: Configure Git + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + - name: Update Repository Changelog + run: | + set -euo pipefail + CHANGELOG_FILE="CHANGELOG.md" + TEMP_CHANGELOG="$(mktemp)" + + cat <<'EOF' > "$TEMP_CHANGELOG" + ${{ needs.version.outputs.changelog }} + EOF + + if [ -f "$CHANGELOG_FILE" ]; then + printf "\n" >> "$TEMP_CHANGELOG" + cat "$CHANGELOG_FILE" >> "$TEMP_CHANGELOG" + fi + + mv "$TEMP_CHANGELOG" "$CHANGELOG_FILE" + + - name: Commit and Push Changelog + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -euo pipefail + + # Pull latest changes (version job pushed new commits) + git pull origin ${{ github.ref_name }} --rebase + + if git diff --quiet -- CHANGELOG.md; then + echo "No changelog updates to commit." + exit 0 + fi + + git add CHANGELOG.md + git commit -m "chore: update changelog for ${{ needs.version.outputs.new_version }}" + git push origin HEAD:${{ github.ref_name }} + + - name: Download all build artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + + - name: Prepare Release Assets + run: | + mkdir -p release-assets + find artifacts -type f \( -name "*.deb" -o -name "*.AppImage" -o -name "*.msi" -o -name "*.dmg" \) -exec cp {} release-assets/ \; || true + + if [ -d "artifacts/Tauri Build Artifacts (macos-latest)/src-tauri/target/release/bundle/macos" ]; then + MACOS_BUNDLE_DIR="artifacts/Tauri Build Artifacts (macos-latest)/src-tauri/target/release/bundle/macos" + cd "$MACOS_BUNDLE_DIR" + shopt -s nullglob + apps=( *.app ) + if [ ${#apps[@]} -gt 0 ]; then + for app in "${apps[@]}"; do + zip -r "$GITHUB_WORKSPACE/release-assets/${app%.app}.zip" "$app" + done + fi + cd - + fi + + echo "Prepared release assets:" + ls -l release-assets/ + + - name: Install GitHub CLI + run: | + type -p curl >/dev/null || (sudo apt update && sudo apt install curl -y) + curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \ + && sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \ + && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \ + && sudo apt update \ + && sudo apt install gh -y + + - name: Create GitHub Release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -euo pipefail + + NEW_VERSION="${{ needs.version.outputs.new_version }}" + echo "Creating release: $NEW_VERSION" + + CHANGELOG_NOTES_FILE="RELEASE_NOTES.md" + cat <<'EOF' > "$CHANGELOG_NOTES_FILE" + ${{ needs.version.outputs.changelog }} + EOF + + gh release create "$NEW_VERSION" \ + --title "CircuitVerse Desktop $NEW_VERSION" \ + --notes-file "$CHANGELOG_NOTES_FILE" \ + release-assets/* \ No newline at end of file diff --git a/build-desktop.js b/build-desktop.js new file mode 100644 index 000000000..3d7dbfa71 --- /dev/null +++ b/build-desktop.js @@ -0,0 +1,35 @@ + +const os = require('os'); +const { execSync } = require('child_process'); + + +function runCommand(command) { + try { + execSync(command, { stdio: 'inherit' }) + } catch (error) { + console.error(`Error executing command: ${command}`) + process.exit(1) + } +} + +process.env.DESKTOP_MODE = 'true' + +const platform = os.platform() +console.log( + `Building for ${platform === 'win32' ? 'Windows' : 'Unix-based system'}...` +) + +runCommand('npm run build') + +const fs = require('fs') + +if (!fs.existsSync('dist/index-cv.html')) { + console.error('Error: dist/index-cv.html not found after build') + process.exit(1) +} + +if (platform === 'win32') { + runCommand('copy dist\\index-cv.html dist\\index.html') +} else { + runCommand('cp dist/index-cv.html dist/index.html') +} diff --git a/package.json b/package.json index 5561dfa6d..f9b15c70a 100644 --- a/package.json +++ b/package.json @@ -1,79 +1,79 @@ { - "name": "cv-frontend-vue", - "version": "0.0.0", - "private": true, - "scripts": { - "serve": "vite preview", - "build": "node scripts/multi-build.js", - "dev": "node scripts/dev.js", - "tauri": "tauri", - "preview": "vite preview", - "lint": "eslint --ext .js,.vue --ignore-path .gitignore --fix src", - "format": "prettier . --write", - "postinstall": "husky install", - "test": "vitest --silent" - }, - "dependencies": { - "@fortawesome/fontawesome-free": "^6.5.1", - "@mdi/font": "5.9.55", - "@mdi/js": "^7.4.47", - "@tauri-apps/api": "2.3.0", - "@tauri-apps/plugin-fs": "2.2.0", - "@tiptap/core": "^2.0.3", - "@tiptap/extension-character-count": "^2.0.3", - "@tiptap/extension-subscript": "^2.0.3", - "@tiptap/extension-superscript": "^2.0.3", - "@tiptap/extension-text-align": "^2.0.3", - "@tiptap/extension-underline": "^2.0.3", - "@tiptap/starter-kit": "^2.0.3", - "@tiptap/vue-3": "^2.0.3", - "bootstrap": "^4.6.1", - "canvas-to-svg": "^1.0.3", - "codemirror": "^5.65.1", - "codemirror-editor-vue3": "^2.1.7", - "dom-to-image": "^2.6.0", - "driver.js": "^0.9.8", - "esbuild": "^0.14.45", - "interactjs": "^1.10.17", - "jquery": "^3.6.0", - "pinia": "^2.0.14", - "vue": "^3.2.25", - "vue-i18n": "^9.14.3", - "vue-router": "^4.0.15", - "vuedraggable": "^4.1.0", - "vuetify": "^3.0.0-beta.0", - "webfontloader": "^1.0.0" - }, - "devDependencies": { - "@commitlint/cli": "^17.0.2", - "@commitlint/config-conventional": "^17.0.2", - "@intlify/vite-plugin-vue-i18n": "^3.4.0", - "@tauri-apps/cli": "2.3.1", - "@types/jquery": "^3.5.14", - "@types/webfontloader": "^1.0.0", - "@typescript-eslint/eslint-plugin": "^8.52.0", - "@typescript-eslint/parser": "^8.52.0", - "@vitejs/plugin-vue": "^2.3.3", - "@vue/test-utils": "^2.4.6", - "cross-env": "^10.1.0", - "eslint": "^8.17.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-vue": "^9.1.0", - "husky": "^8.0.1", - "jsdoc": "^4.0.3", - "jsdom": "^27.4.0", - "prettier": "2.6.2", - "sass": "^1.77.6", - "typescript": "^4.5.4", - "vite": "^2.9.18", - "vite-plugin-css-injected-by-js": "^3.5.2", - "vite-plugin-html": "^3.2.2", - "vite-plugin-vuetify": "^1.0.0-alpha.0", - "vitest": "^2.1.9", - "vue-cli-plugin-vuetify": "~2.5.1", - "vue-tsc": "^0.34.7" - }, - "optionalDependencies": { - "esbuild-linux-64": "^0.15.18" - } -} \ No newline at end of file + "name": "cv-frontend-vue", + "version": "0.0.0", + "private": true, + "scripts": { + "serve": "vite preview", + "build": "node scripts/multi-build.js", + "dev": "node scripts/dev.js", + "tauri": "tauri", + "preview": "vite preview", + "lint": "eslint --ext .js,.vue --ignore-path .gitignore --fix src", + "format": "prettier . --write", + "postinstall": "husky install", + "test": "vitest --silent" + }, + "dependencies": { + "@fortawesome/fontawesome-free": "^6.5.1", + "@mdi/font": "5.9.55", + "@mdi/js": "^7.4.47", + "@tauri-apps/api": "2.3.0", + "@tauri-apps/plugin-fs": "2.2.0", + "@tiptap/core": "^2.0.3", + "@tiptap/extension-character-count": "^2.0.3", + "@tiptap/extension-subscript": "^2.0.3", + "@tiptap/extension-superscript": "^2.0.3", + "@tiptap/extension-text-align": "^2.0.3", + "@tiptap/extension-underline": "^2.0.3", + "@tiptap/starter-kit": "^2.0.3", + "@tiptap/vue-3": "^2.0.3", + "bootstrap": "^4.6.1", + "canvas-to-svg": "^1.0.3", + "codemirror": "^5.65.1", + "codemirror-editor-vue3": "^2.1.7", + "dom-to-image": "^2.6.0", + "driver.js": "^0.9.8", + "esbuild": "^0.14.45", + "interactjs": "^1.10.17", + "jquery": "^3.6.0", + "pinia": "^2.0.14", + "vue": "^3.2.25", + "vue-i18n": "^9.14.3", + "vue-router": "^4.0.15", + "vuedraggable": "^4.1.0", + "vuetify": "^3.0.0-beta.0", + "webfontloader": "^1.0.0" + }, + "devDependencies": { + "@commitlint/cli": "^17.0.2", + "@commitlint/config-conventional": "^17.0.2", + "@intlify/vite-plugin-vue-i18n": "^3.4.0", + "@tauri-apps/cli": "2.3.1", + "@types/jquery": "^3.5.14", + "@types/webfontloader": "^1.0.0", + "@typescript-eslint/eslint-plugin": "^8.52.0", + "@typescript-eslint/parser": "^8.52.0", + "@vitejs/plugin-vue": "^2.3.3", + "@vue/test-utils": "^2.4.6", + "cross-env": "^10.1.0", + "eslint": "^8.17.0", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-vue": "^9.1.0", + "husky": "^8.0.1", + "jsdoc": "^4.0.3", + "jsdom": "^27.4.0", + "prettier": "2.6.2", + "sass": "^1.77.6", + "typescript": "^4.5.4", + "vite": "^2.9.18", + "vite-plugin-css-injected-by-js": "^3.5.2", + "vite-plugin-html": "^3.2.2", + "vite-plugin-vuetify": "^1.0.0-alpha.0", + "vitest": "^2.1.9", + "vue-cli-plugin-vuetify": "~2.5.1", + "vue-tsc": "^0.34.7" + }, + "optionalDependencies": { + "esbuild-linux-64": "^0.15.18" + } +} diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 1cbe75874..339b8a3a8 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "CircuitVerse" -version = "0.1.0" +version = "0.0.0" description = "CircuitVerse Simulator" authors = ["CircuitVerse Team"] license = "" @@ -24,4 +24,4 @@ log = "0.4" tauri = { version = "2.3.1", features = ["devtools"] } tauri-plugin-http = "2" tauri-plugin-log = "2.0.0-rc" -tauri-plugin-fs = "2" +tauri-plugin-fs = "2.3.0" diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index e78e60588..58a11fd41 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "../node_modules/@tauri-apps/cli/config.schema.json", "productName": "CircuitVerse", - "version": "0.1.0", + "version": "0.0.0", "identifier": "org.circuitVerse.simulator", "build": { "frontendDist": "../dist/simulatorvue/v0", @@ -35,4 +35,4 @@ "icons/icon.ico" ] } -} \ No newline at end of file +}