mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-07-15 12:53:40 +00:00
9de904dd4c
* feat(sshid) - sshid.io equivalent for termix (#919) * feat(ssh-id): database schema, migrations and field encryption Adds ssh_identities, ssh_identity_keys and ssh_identity_ca tables (public keys stored plaintext for the unauthenticated resolver; CA private key registered for per-user field encryption), with UNIQUE(user_id), an index on ssh_identity_keys(identity_id), and idempotent CREATE TABLE migrations. * feat(ssh-id): backend API — resolver, key management, CA and certificates Mounts /sshid (nginx route added). Public text/plain authorized_keys resolver (+ exact /:algo filter, HTML viewer) and CA public-key endpoint; no-store + noindex headers on every resolver response including early 404s. Authenticated management: claim/rename/delete handle, add/import/generate/enable/delete keys, and a per-user CA (create/rotate/delete) with pure-Node OpenSSH certificate issuance. Audit logging on all mutations; UNIQUE races map to a precise 409. Unit tests for key parsing and certificate signing (ssh-keygen-validated). * feat(ssh-id): frontend panel, API client and i18n SSH ID panel wired into the app rail and AppShell: claim handle, resolver URL + curl one-liner, key list, generate, paste/import, CA enable/rotate/remove with server trust command, and per-key certificate issuance. API client re-exported through main-axios.ts; all strings i18n'd. * style(ssh-id): align panel and resolver page with Termix theme - Rebuild the SSH ID sidebar panel with the theme's square components (SectionCard / SettingRow / FakeSwitch) instead of rounded ad-hoc cards; use accent-brand and destructive tokens rather than raw red/green. - Fix panel scrolling: move overflow to a block scroll container so the cards keep their natural height instead of being clipped. - Restyle the public resolver HTML page (/sshid/u/:handle) to the Termix dark theme: square corners, #18181b/#303032 palette, #f59145 accent, uppercase section labels. - Tidy copy: 'Save To Credentials' label, drop the redundant generate intro, and correct the generate tooltip (the key is stored when saving to vault). * feat: rename to Termix ID, improve UI, backend inconsistencies, and general bug fixes --------- Co-authored-by: LukeGus <bugattiguy527@gmail.com> * ci(deps): bump actions/checkout from 6 to 7 in the github-actions group (#922) Bumps the github-actions group with 1 update: [actions/checkout](https://github.com/actions/checkout). Updates `actions/checkout` from 6 to 7 - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump the dev-patch-updates group with 11 updates (#923) Bumps the dev-patch-updates group with 11 updates: | Package | From | To | | --- | --- | --- | | [@codemirror/search](https://github.com/codemirror/search) | `6.7.0` | `6.7.1` | | [@codemirror/view](https://github.com/codemirror/view) | `6.43.0` | `6.43.1` | | [@tailwindcss/vite](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite) | `4.3.0` | `4.3.1` | | [@vitest/coverage-v8](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-v8) | `4.1.8` | `4.1.9` | | [@vitest/ui](https://github.com/vitest-dev/vitest/tree/HEAD/packages/ui) | `4.1.8` | `4.1.9` | | [eslint-plugin-react-refresh](https://github.com/ArnaudBarre/eslint-plugin-react-refresh) | `0.5.2` | `0.5.3` | | [lint-staged](https://github.com/lint-staged/lint-staged) | `17.0.7` | `17.0.8` | | [prettier](https://github.com/prettier/prettier) | `3.8.3` | `3.8.4` | | [sharp](https://github.com/lovell/sharp) | `0.35.1` | `0.35.2` | | [tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss) | `4.3.0` | `4.3.1` | | [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) | `4.1.8` | `4.1.9` | Updates `@codemirror/search` from 6.7.0 to 6.7.1 - [Changelog](https://github.com/codemirror/search/blob/main/CHANGELOG.md) - [Commits](https://github.com/codemirror/search/commits) Updates `@codemirror/view` from 6.43.0 to 6.43.1 - [Changelog](https://github.com/codemirror/view/blob/main/CHANGELOG.md) - [Commits](https://github.com/codemirror/view/commits) Updates `@tailwindcss/vite` from 4.3.0 to 4.3.1 - [Release notes](https://github.com/tailwindlabs/tailwindcss/releases) - [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.3.1/packages/@tailwindcss-vite) Updates `@vitest/coverage-v8` from 4.1.8 to 4.1.9 - [Release notes](https://github.com/vitest-dev/vitest/releases) - [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md) - [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.9/packages/coverage-v8) Updates `@vitest/ui` from 4.1.8 to 4.1.9 - [Release notes](https://github.com/vitest-dev/vitest/releases) - [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md) - [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.9/packages/ui) Updates `eslint-plugin-react-refresh` from 0.5.2 to 0.5.3 - [Release notes](https://github.com/ArnaudBarre/eslint-plugin-react-refresh/releases) - [Changelog](https://github.com/ArnaudBarre/eslint-plugin-react-refresh/blob/main/CHANGELOG.md) - [Commits](https://github.com/ArnaudBarre/eslint-plugin-react-refresh/compare/v0.5.2...v0.5.3) Updates `lint-staged` from 17.0.7 to 17.0.8 - [Release notes](https://github.com/lint-staged/lint-staged/releases) - [Changelog](https://github.com/lint-staged/lint-staged/blob/main/CHANGELOG.md) - [Commits](https://github.com/lint-staged/lint-staged/compare/v17.0.7...v17.0.8) Updates `prettier` from 3.8.3 to 3.8.4 - [Release notes](https://github.com/prettier/prettier/releases) - [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md) - [Commits](https://github.com/prettier/prettier/compare/3.8.3...3.8.4) Updates `sharp` from 0.35.1 to 0.35.2 - [Release notes](https://github.com/lovell/sharp/releases) - [Commits](https://github.com/lovell/sharp/compare/v0.35.1...v0.35.2) Updates `tailwindcss` from 4.3.0 to 4.3.1 - [Release notes](https://github.com/tailwindlabs/tailwindcss/releases) - [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.3.1/packages/tailwindcss) Updates `vitest` from 4.1.8 to 4.1.9 - [Release notes](https://github.com/vitest-dev/vitest/releases) - [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md) - [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.9/packages/vitest) --- updated-dependencies: - dependency-name: "@codemirror/search" dependency-version: 6.7.1 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-patch-updates - dependency-name: "@codemirror/view" dependency-version: 6.43.1 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-patch-updates - dependency-name: "@tailwindcss/vite" dependency-version: 4.3.1 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-patch-updates - dependency-name: "@vitest/coverage-v8" dependency-version: 4.1.9 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-patch-updates - dependency-name: "@vitest/ui" dependency-version: 4.1.9 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-patch-updates - dependency-name: eslint-plugin-react-refresh dependency-version: 0.5.3 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-patch-updates - dependency-name: lint-staged dependency-version: 17.0.8 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-patch-updates - dependency-name: prettier dependency-version: 3.8.4 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-patch-updates - dependency-name: sharp dependency-version: 0.35.2 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-patch-updates - dependency-name: tailwindcss dependency-version: 4.3.1 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-patch-updates - dependency-name: vitest dependency-version: 4.1.9 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-patch-updates ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump nanoid in the prod-patch-updates group (#925) Bumps the prod-patch-updates group with 1 update: [nanoid](https://github.com/ai/nanoid). Updates `nanoid` from 5.1.11 to 5.1.15 - [Release notes](https://github.com/ai/nanoid/releases) - [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md) - [Commits](https://github.com/ai/nanoid/compare/5.1.11...5.1.15) --- updated-dependencies: - dependency-name: nanoid dependency-version: 5.1.15 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: prod-patch-updates ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump the major-updates group with 5 updates (#926) Bumps the major-updates group with 5 updates: | Package | From | To | | --- | --- | --- | | [js-yaml](https://github.com/nodeca/js-yaml) | `4.2.0` | `5.0.0` | | [@eslint/js](https://github.com/eslint/eslint/tree/HEAD/packages/js) | `9.39.4` | `10.0.1` | | [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `25.9.2` | `26.0.0` | | [concurrently](https://github.com/open-cli-tools/concurrently) | `9.2.1` | `10.0.3` | | [eslint](https://github.com/eslint/eslint) | `9.39.4` | `10.5.0` | Updates `js-yaml` from 4.2.0 to 5.0.0 - [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md) - [Commits](https://github.com/nodeca/js-yaml/compare/4.2.0...5.0.0) Updates `@eslint/js` from 9.39.4 to 10.0.1 - [Release notes](https://github.com/eslint/eslint/releases) - [Commits](https://github.com/eslint/eslint/commits/v10.0.1/packages/js) Updates `@types/node` from 25.9.2 to 26.0.0 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) Updates `concurrently` from 9.2.1 to 10.0.3 - [Release notes](https://github.com/open-cli-tools/concurrently/releases) - [Commits](https://github.com/open-cli-tools/concurrently/compare/v9.2.1...v10.0.3) Updates `eslint` from 9.39.4 to 10.5.0 - [Release notes](https://github.com/eslint/eslint/releases) - [Commits](https://github.com/eslint/eslint/compare/v9.39.4...v10.5.0) --- updated-dependencies: - dependency-name: js-yaml dependency-version: 5.0.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: major-updates - dependency-name: "@eslint/js" dependency-version: 10.0.1 dependency-type: direct:development update-type: version-update:semver-major dependency-group: major-updates - dependency-name: "@types/node" dependency-version: 26.0.0 dependency-type: direct:development update-type: version-update:semver-major dependency-group: major-updates - dependency-name: concurrently dependency-version: 10.0.3 dependency-type: direct:development update-type: version-update:semver-major dependency-group: major-updates - dependency-name: eslint dependency-version: 10.5.0 dependency-type: direct:development update-type: version-update:semver-major dependency-group: major-updates ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * feat(ssh): add HashiCorp Vault SSH signer authentication * fix: small fixes to vault feature to align with Termix codebase * chore: add view docs links for vault/termix id * fix: file upload fails with 400 and missing schema migrations on upgrade (#929) Two bugs introduced in v2.4.1: 1. uploadFileStream uses fileManagerApi.post() which triggers axios's transformRequest to JSON-serialize the FormData because the instance default Content-Type is application/json. Change to postForm() which sets Content-Type: multipart/form-data so the browser XHR sends the correct multipart body with boundary. 2. Two schema items added to schema.ts were not included in migrateSchema() in db/index.ts, causing 500 errors on existing installations upgrading from v2.4.0: - user_preferences.status_color_scheme (no such column) - dashboard_service_links table (no such table) Fixes #928 Co-authored-by: sash <sash@fominykh.io> * fix: support PuTTY PPK ssh keys (#930) * fix: chunk large file manager uploads (#932) * fix: route dashboard hosts by protocol (#934) * fix: resolve tunnel endpoints reliably (#935) * Fix Electron OIDC browser auth failures (#936) * Allow RDP connections without stored credentials (#937) * Sync role credential shares for OIDC users (#938) * Fix terminal link dialog layering (#940) * Confirm large files before opening editor (#942) * Confirm closing active host connections (#943) * Preserve file path case in file manager UI (#941) * fix: preserve unicode guacamole tokens (#933) * Persist VNC authentication settings (#944) * Fix Guacamole websocket base path (#946) * Promote file manager terminals to tabs (#939) * Guard Guacamole disconnect during startup (#945) * chore: increment ver * feat: bitwarden ssh agent integration * feat: serial connections support * fix: various small bug fixes * feat: open all sessions in a folder and terminal custom theme color support * feat: cross host file manager clipboard and several small bug fixes * feat: tailscale/wireguard support and added a new status state for when backend is checking status * feat: grafana like server stats history, new alert system, ntfy/webhook support * feat: new grid and widget based homepage function * feat: new donate button in dashboard * fix: alert ui incorrectly using termix css and fixed issue with alert system not loading * chore: fix ci checks (#966) * Fix dashboard service link creation (#950) * Fix jump host SOCKS5 proxy selection (#951) * Fix jump host SOCKS5 proxy selection * fix: type jump host socks proxy config * Fix tmux detection path handling (#949) * Support GUACD_URL environment config (#952) * Retry autostart tunnel host fetches (#953) * Retry autostart tunnel host fetches * chore: format tunnel route * Fix PUID html ownership in Docker entrypoint (#954) * feat: allow custom tunnel endpoints (#977) * fix: skip metrics start for non-ssh hosts (#976) * Fix Proxmox import auth fallback (#956) * Fix Proxmox import auth fallback * chore: format proxmox import auth * Fix SSH heading syntax highlighting (#955) * Fix SSH heading syntax highlighting * chore: format terminal highlighter * Initialize auth before fullscreen terminal routes (#957) * Add WebAuthn passkey authentication (#959) * chore: add Biome tooling (#965) * chore: add biome tooling * chore: support tailwind syntax in biome * Fix VNC required argument handshake (#968) * Prioritize host results in command palette search (#969) * Prevent sidebar host hover layout shift (#970) * Add terminal font zoom with mouse wheel (#971) * Add host temperature metrics card (#972) * Make file downloads reliable in desktop app (#973) * Add app rail hover expansion setting (#974) * fix: use correct translation key for nav.close (#964) * fix(tunnel): skip endpoint credential validation for direct tunnels (#963) * fix: SSH port connection bug (#975) * fix: chunked upload for files >=1.5GB to bypass browser ArrayBuffer limit (#948) * feat: support SSH agent auth across SSH features (#960) * feat: add Podman container runtime support (#958) * chore: update readme and release notes * fix: stabilize Windows app icon (#978) * Add safe host sharing export (#979) * Add external editor support for file manager (#985) * Rework SSH credential password handling (#984) * Support password fallback for SSH key credentials * Complete SSH credential password fallback * Fix runtime base path for auth callbacks (#982) * Fix TUI terminal output highlighting (#983) Co-authored-by: LukeGus <bugattiguy527@gmail.com> * Add app fullscreen mode (#993) * Fix host metrics startup polling (#986) * chore: update release notes * fix: line chart text overlap * chore: update RELEASE_NOTES.md * chore: add donation goal to readme * chore: update readme * fix: hide full-screen button in electron app * fix: failed unit tests * chore: lint, format, and bump version to 2.5.0 * chore: remove timeout from crowdin translate * chore: sync Crowdin translations for 2.5.0 --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: DivByZero <mr.oplus@yahoo.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: devdanetra <46488477+devdanetra@users.noreply.github.com> Co-authored-by: Aleksandr Fominykh <neoformalex@users.noreply.github.com> Co-authored-by: sash <sash@fominykh.io> Co-authored-by: ZacharyZcR <zacharyzcr1984@gmail.com>
1060 lines
41 KiB
YAML
1060 lines
41 KiB
YAML
name: Build and Push Electron App
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
build_type:
|
|
description: "Platform to build for"
|
|
required: true
|
|
default: "all"
|
|
type: choice
|
|
options:
|
|
- all
|
|
- windows
|
|
- linux
|
|
- macos
|
|
artifact_destination:
|
|
description: "What to do with the built app"
|
|
required: true
|
|
default: "file"
|
|
type: choice
|
|
options:
|
|
- none
|
|
- file
|
|
- release
|
|
- submit
|
|
workflow_call:
|
|
inputs:
|
|
build_type:
|
|
description: "Platform to build for (all, windows, linux, macos)"
|
|
required: true
|
|
type: string
|
|
artifact_destination:
|
|
description: "What to do with the built app (none, file, release, submit)"
|
|
required: true
|
|
type: string
|
|
release_tag:
|
|
description: "Explicit release tag to upload assets to (defaults to latest release when empty)"
|
|
required: false
|
|
type: string
|
|
default: ""
|
|
outputs:
|
|
macos_universal_dmg_sha256:
|
|
description: "SHA256 of the universal macOS DMG (for Homebrew cask)"
|
|
value: ${{ jobs.build-macos.outputs.dmg_sha256 }}
|
|
|
|
jobs:
|
|
build-windows:
|
|
runs-on: blacksmith-4vcpu-windows-2025
|
|
if: (inputs.build_type == 'all' || inputs.build_type == 'windows' || inputs.build_type == '') && inputs.artifact_destination != 'submit'
|
|
permissions:
|
|
contents: write
|
|
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v7
|
|
with:
|
|
fetch-depth: 1
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v6
|
|
with:
|
|
node-version-file: ".nvmrc"
|
|
cache: "npm"
|
|
|
|
- name: Install dependencies
|
|
run: npm ci
|
|
|
|
- name: Get version
|
|
id: package-version
|
|
run: |
|
|
$VERSION = (Get-Content package.json | ConvertFrom-Json).version
|
|
echo "version=$VERSION" >> $env:GITHUB_OUTPUT
|
|
|
|
- name: Build Windows (All Architectures)
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: npm run build && npx electron-builder --win --x64 --ia32
|
|
|
|
- name: Upload Windows x64 NSIS Installer
|
|
uses: actions/upload-artifact@v7
|
|
if: hashFiles('release/termix_windows_x64_nsis.exe') != '' && inputs.artifact_destination != 'none'
|
|
with:
|
|
name: termix_windows_x64_nsis
|
|
path: release/termix_windows_x64_nsis.exe
|
|
retention-days: 30
|
|
|
|
- name: Upload Windows ia32 NSIS Installer
|
|
uses: actions/upload-artifact@v7
|
|
if: hashFiles('release/termix_windows_ia32_nsis.exe') != '' && inputs.artifact_destination != 'none'
|
|
with:
|
|
name: termix_windows_ia32_nsis
|
|
path: release/termix_windows_ia32_nsis.exe
|
|
retention-days: 30
|
|
|
|
- name: Upload Windows x64 MSI Installer
|
|
uses: actions/upload-artifact@v7
|
|
if: hashFiles('release/termix_windows_x64_msi.msi') != '' && inputs.artifact_destination != 'none'
|
|
with:
|
|
name: termix_windows_x64_msi
|
|
path: release/termix_windows_x64_msi.msi
|
|
retention-days: 30
|
|
|
|
- name: Upload Windows ia32 MSI Installer
|
|
uses: actions/upload-artifact@v7
|
|
if: hashFiles('release/termix_windows_ia32_msi.msi') != '' && inputs.artifact_destination != 'none'
|
|
with:
|
|
name: termix_windows_ia32_msi
|
|
path: release/termix_windows_ia32_msi.msi
|
|
retention-days: 30
|
|
|
|
- name: Create Windows x64 Portable zip
|
|
if: hashFiles('release/win-unpacked/*') != ''
|
|
run: |
|
|
Compress-Archive -Path "release\win-unpacked\*" -DestinationPath "termix_windows_x64_portable.zip"
|
|
|
|
- name: Create Windows ia32 Portable zip
|
|
if: hashFiles('release/win-ia32-unpacked/*') != ''
|
|
run: |
|
|
Compress-Archive -Path "release\win-ia32-unpacked\*" -DestinationPath "termix_windows_ia32_portable.zip"
|
|
|
|
- name: Upload Windows x64 Portable
|
|
uses: actions/upload-artifact@v7
|
|
if: hashFiles('termix_windows_x64_portable.zip') != '' && inputs.artifact_destination != 'none'
|
|
with:
|
|
name: termix_windows_x64_portable
|
|
path: termix_windows_x64_portable.zip
|
|
retention-days: 30
|
|
|
|
- name: Upload Windows ia32 Portable
|
|
uses: actions/upload-artifact@v7
|
|
if: hashFiles('termix_windows_ia32_portable.zip') != '' && inputs.artifact_destination != 'none'
|
|
with:
|
|
name: termix_windows_ia32_portable
|
|
path: termix_windows_ia32_portable.zip
|
|
retention-days: 30
|
|
|
|
build-linux:
|
|
runs-on: blacksmith-8vcpu-ubuntu-2404
|
|
if: (inputs.build_type == 'all' || inputs.build_type == 'linux' || inputs.build_type == '') && inputs.artifact_destination != 'submit'
|
|
permissions:
|
|
contents: write
|
|
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v7
|
|
with:
|
|
fetch-depth: 1
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v6
|
|
with:
|
|
node-version-file: ".nvmrc"
|
|
cache: "npm"
|
|
|
|
- name: Install system dependencies
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y libfuse2 flatpak flatpak-builder imagemagick
|
|
|
|
- name: Install dependencies
|
|
run: |
|
|
npm ci
|
|
npm install --force @rollup/rollup-linux-x64-gnu
|
|
npm install --force @rollup/rollup-linux-arm64-gnu
|
|
npm install --force @rollup/rollup-linux-arm-gnueabihf
|
|
|
|
- name: Build Linux x64
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
DEBUG: electron-builder
|
|
run: npm run build && npx electron-builder --linux --x64
|
|
|
|
- name: Build Linux arm64 and armv7l
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: npx electron-builder --linux --arm64 --armv7l
|
|
|
|
- name: Rename Linux artifacts for consistency
|
|
run: |
|
|
cd release
|
|
|
|
if [ -f "termix_linux_amd64_deb.deb" ]; then
|
|
mv "termix_linux_amd64_deb.deb" "termix_linux_x64_deb.deb"
|
|
fi
|
|
|
|
if [ -f "termix_linux_x86_64_appimage.AppImage" ]; then
|
|
mv "termix_linux_x86_64_appimage.AppImage" "termix_linux_x64_appimage.AppImage"
|
|
fi
|
|
|
|
cd ..
|
|
|
|
- name: Upload Linux x64 AppImage
|
|
uses: actions/upload-artifact@v7
|
|
if: hashFiles('release/termix_linux_x64_appimage.AppImage') != '' && inputs.artifact_destination != 'none'
|
|
with:
|
|
name: termix_linux_x64_appimage
|
|
path: release/termix_linux_x64_appimage.AppImage
|
|
retention-days: 30
|
|
|
|
- name: Upload Linux arm64 AppImage
|
|
uses: actions/upload-artifact@v7
|
|
if: hashFiles('release/termix_linux_arm64_appimage.AppImage') != '' && inputs.artifact_destination != 'none'
|
|
with:
|
|
name: termix_linux_arm64_appimage
|
|
path: release/termix_linux_arm64_appimage.AppImage
|
|
retention-days: 30
|
|
|
|
- name: Upload Linux armv7l AppImage
|
|
uses: actions/upload-artifact@v7
|
|
if: hashFiles('release/termix_linux_armv7l_appimage.AppImage') != '' && inputs.artifact_destination != 'none'
|
|
with:
|
|
name: termix_linux_armv7l_appimage
|
|
path: release/termix_linux_armv7l_appimage.AppImage
|
|
retention-days: 30
|
|
|
|
- name: Upload Linux x64 DEB
|
|
uses: actions/upload-artifact@v7
|
|
if: hashFiles('release/termix_linux_x64_deb.deb') != '' && inputs.artifact_destination != 'none'
|
|
with:
|
|
name: termix_linux_x64_deb
|
|
path: release/termix_linux_x64_deb.deb
|
|
retention-days: 30
|
|
|
|
- name: Upload Linux arm64 DEB
|
|
uses: actions/upload-artifact@v7
|
|
if: hashFiles('release/termix_linux_arm64_deb.deb') != '' && inputs.artifact_destination != 'none'
|
|
with:
|
|
name: termix_linux_arm64_deb
|
|
path: release/termix_linux_arm64_deb.deb
|
|
retention-days: 30
|
|
|
|
- name: Upload Linux armv7l DEB
|
|
uses: actions/upload-artifact@v7
|
|
if: hashFiles('release/termix_linux_armv7l_deb.deb') != '' && inputs.artifact_destination != 'none'
|
|
with:
|
|
name: termix_linux_armv7l_deb
|
|
path: release/termix_linux_armv7l_deb.deb
|
|
retention-days: 30
|
|
|
|
- name: Upload Linux x64 tar.gz
|
|
uses: actions/upload-artifact@v7
|
|
if: hashFiles('release/termix_linux_x64_portable.tar.gz') != '' && inputs.artifact_destination != 'none'
|
|
with:
|
|
name: termix_linux_x64_portable
|
|
path: release/termix_linux_x64_portable.tar.gz
|
|
retention-days: 30
|
|
|
|
- name: Upload Linux arm64 tar.gz
|
|
uses: actions/upload-artifact@v7
|
|
if: hashFiles('release/termix_linux_arm64_portable.tar.gz') != '' && inputs.artifact_destination != 'none'
|
|
with:
|
|
name: termix_linux_arm64_portable
|
|
path: release/termix_linux_arm64_portable.tar.gz
|
|
retention-days: 30
|
|
|
|
- name: Upload Linux armv7l tar.gz
|
|
uses: actions/upload-artifact@v7
|
|
if: hashFiles('release/termix_linux_armv7l_portable.tar.gz') != '' && inputs.artifact_destination != 'none'
|
|
with:
|
|
name: termix_linux_armv7l_portable
|
|
path: release/termix_linux_armv7l_portable.tar.gz
|
|
retention-days: 30
|
|
|
|
- name: Add Flathub repository
|
|
run: |
|
|
sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
|
|
|
- name: Install Flatpak runtime and SDK
|
|
run: |
|
|
sudo flatpak install -y flathub org.freedesktop.Platform//24.08
|
|
sudo flatpak install -y flathub org.freedesktop.Sdk//24.08
|
|
sudo flatpak install -y flathub org.electronjs.Electron2.BaseApp//24.08
|
|
|
|
- name: Get version for Flatpak
|
|
id: flatpak-version
|
|
run: |
|
|
VERSION=$(node -p "require('./package.json').version")
|
|
RELEASE_DATE=$(date +%Y-%m-%d)
|
|
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
|
echo "release_date=$RELEASE_DATE" >> $GITHUB_OUTPUT
|
|
|
|
- name: Prepare Flatpak files
|
|
run: |
|
|
VERSION="${{ steps.flatpak-version.outputs.version }}"
|
|
RELEASE_DATE="${{ steps.flatpak-version.outputs.release_date }}"
|
|
|
|
CHECKSUM_X64=$(sha256sum "release/termix_linux_x64_appimage.AppImage" | awk '{print $1}')
|
|
CHECKSUM_ARM64=$(sha256sum "release/termix_linux_arm64_appimage.AppImage" | awk '{print $1}')
|
|
|
|
mkdir -p flatpak-build
|
|
cp flatpak/com.karmaa.termix.yml flatpak-build/
|
|
cp flatpak/com.karmaa.termix.desktop flatpak-build/
|
|
cp flatpak/com.karmaa.termix.metainfo.xml flatpak-build/
|
|
cp public/icon.svg flatpak-build/com.karmaa.termix.svg
|
|
convert public/icon.png -resize 256x256 flatpak-build/icon-256.png
|
|
convert public/icon.png -resize 128x128 flatpak-build/icon-128.png
|
|
|
|
cd flatpak-build
|
|
sed -i "s|https://github.com/Termix-SSH/Termix/releases/download/release-VERSION_PLACEHOLDER-tag/termix_linux_x64_appimage.AppImage|file://$(realpath ../release/termix_linux_x64_appimage.AppImage)|g" com.karmaa.termix.yml
|
|
sed -i "s|https://github.com/Termix-SSH/Termix/releases/download/release-VERSION_PLACEHOLDER-tag/termix_linux_arm64_appimage.AppImage|file://$(realpath ../release/termix_linux_arm64_appimage.AppImage)|g" com.karmaa.termix.yml
|
|
sed -i "s/CHECKSUM_X64_PLACEHOLDER/$CHECKSUM_X64/g" com.karmaa.termix.yml
|
|
sed -i "s/CHECKSUM_ARM64_PLACEHOLDER/$CHECKSUM_ARM64/g" com.karmaa.termix.yml
|
|
sed -i "s/VERSION_PLACEHOLDER/$VERSION/g" com.karmaa.termix.metainfo.xml
|
|
sed -i "s/DATE_PLACEHOLDER/$RELEASE_DATE/g" com.karmaa.termix.metainfo.xml
|
|
|
|
- name: Build Flatpak bundle
|
|
run: |
|
|
cd flatpak-build
|
|
flatpak-builder --repo=repo --force-clean --disable-rofiles-fuse build-dir com.karmaa.termix.yml
|
|
|
|
ARCH=$(uname -m)
|
|
if [ "$ARCH" = "x86_64" ]; then
|
|
FLATPAK_ARCH="x86_64"
|
|
elif [ "$ARCH" = "aarch64" ]; then
|
|
FLATPAK_ARCH="aarch64"
|
|
else
|
|
FLATPAK_ARCH="$ARCH"
|
|
fi
|
|
|
|
flatpak build-bundle repo ../release/termix_linux_flatpak.flatpak com.karmaa.termix --runtime-repo=https://flathub.org/repo/flathub.flatpakrepo
|
|
|
|
- name: Create flatpakref file
|
|
run: |
|
|
VERSION="${{ steps.flatpak-version.outputs.version }}"
|
|
cp flatpak/com.karmaa.termix.flatpakref release/
|
|
sed -i "s|VERSION_PLACEHOLDER|release-${VERSION}-tag|g" release/com.karmaa.termix.flatpakref
|
|
|
|
- name: Upload Flatpak bundle
|
|
uses: actions/upload-artifact@v7
|
|
if: hashFiles('release/termix_linux_flatpak.flatpak') != '' && inputs.artifact_destination != 'none'
|
|
with:
|
|
name: termix_linux_flatpak
|
|
path: release/termix_linux_flatpak.flatpak
|
|
retention-days: 30
|
|
|
|
- name: Upload Flatpakref
|
|
uses: actions/upload-artifact@v7
|
|
if: hashFiles('release/com.karmaa.termix.flatpakref') != '' && inputs.artifact_destination != 'none'
|
|
with:
|
|
name: termix_linux_flatpakref
|
|
path: release/com.karmaa.termix.flatpakref
|
|
retention-days: 30
|
|
|
|
build-macos:
|
|
runs-on: blacksmith-6vcpu-macos-latest
|
|
if: (inputs.build_type == 'macos' || inputs.build_type == 'all') && inputs.artifact_destination != 'submit'
|
|
needs: []
|
|
permissions:
|
|
contents: write
|
|
outputs:
|
|
dmg_sha256: ${{ steps.dmg-checksum.outputs.sha256 }}
|
|
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v7
|
|
with:
|
|
fetch-depth: 1
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v6
|
|
with:
|
|
node-version-file: ".nvmrc"
|
|
cache: "npm"
|
|
|
|
- name: Install dependencies
|
|
run: |
|
|
npm ci
|
|
npm install --force @rollup/rollup-darwin-arm64
|
|
npm install dmg-license
|
|
|
|
- name: Check for Code Signing Certificates
|
|
id: check_certs
|
|
run: |
|
|
if [ -n "${{ secrets.MAC_BUILD_CERTIFICATE_BASE64 }}" ] && [ -n "${{ secrets.MAC_P12_PASSWORD }}" ]; then
|
|
echo "has_certs=true" >> $GITHUB_OUTPUT
|
|
fi
|
|
|
|
- name: Import Code Signing Certificates
|
|
if: steps.check_certs.outputs.has_certs == 'true'
|
|
env:
|
|
MAC_BUILD_CERTIFICATE_BASE64: ${{ secrets.MAC_BUILD_CERTIFICATE_BASE64 }}
|
|
MAC_INSTALLER_CERTIFICATE_BASE64: ${{ secrets.MAC_INSTALLER_CERTIFICATE_BASE64 }}
|
|
MAC_P12_PASSWORD: ${{ secrets.MAC_P12_PASSWORD }}
|
|
MAC_KEYCHAIN_PASSWORD: ${{ secrets.MAC_KEYCHAIN_PASSWORD }}
|
|
run: |
|
|
APP_CERT_PATH=$RUNNER_TEMP/app_certificate.p12
|
|
INSTALLER_CERT_PATH=$RUNNER_TEMP/installer_certificate.p12
|
|
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
|
|
|
|
echo -n "$MAC_BUILD_CERTIFICATE_BASE64" | base64 --decode -o $APP_CERT_PATH
|
|
|
|
if [ -n "$MAC_INSTALLER_CERTIFICATE_BASE64" ]; then
|
|
echo -n "$MAC_INSTALLER_CERTIFICATE_BASE64" | base64 --decode -o $INSTALLER_CERT_PATH
|
|
fi
|
|
|
|
security create-keychain -p "$MAC_KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
|
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
|
|
security unlock-keychain -p "$MAC_KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
|
|
|
security import $APP_CERT_PATH -P "$MAC_P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
|
|
|
|
if [ -f "$INSTALLER_CERT_PATH" ]; then
|
|
security import $INSTALLER_CERT_PATH -P "$MAC_P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
|
|
fi
|
|
|
|
security list-keychain -d user -s $KEYCHAIN_PATH
|
|
|
|
security find-identity -v -p codesigning $KEYCHAIN_PATH
|
|
|
|
- name: Build macOS App Store Package
|
|
if: steps.check_certs.outputs.has_certs == 'true'
|
|
env:
|
|
ELECTRON_BUILDER_ALLOW_UNRESOLVED_DEPENDENCIES: true
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
NODE_OPTIONS: --max-old-space-size=4096
|
|
run: |
|
|
CURRENT_VERSION=$(node -p "require('./package.json').version")
|
|
BUILD_VERSION="${{ github.run_number }}"
|
|
|
|
npm run build && npx electron-builder --mac mas --universal --config.buildVersion="$BUILD_VERSION"
|
|
|
|
- name: Clean up MAS keychain before DMG build
|
|
if: steps.check_certs.outputs.has_certs == 'true'
|
|
run: |
|
|
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db || true
|
|
|
|
- name: Check for Developer ID Certificates
|
|
id: check_dev_id_certs
|
|
run: |
|
|
if [ -n "${{ secrets.DEVELOPER_ID_CERTIFICATE_BASE64 }}" ] && [ -n "${{ secrets.DEVELOPER_ID_P12_PASSWORD }}" ]; then
|
|
echo "has_dev_id_certs=true" >> $GITHUB_OUTPUT
|
|
fi
|
|
|
|
- name: Import Developer ID Certificates
|
|
if: steps.check_dev_id_certs.outputs.has_dev_id_certs == 'true'
|
|
env:
|
|
DEVELOPER_ID_CERTIFICATE_BASE64: ${{ secrets.DEVELOPER_ID_CERTIFICATE_BASE64 }}
|
|
DEVELOPER_ID_INSTALLER_CERTIFICATE_BASE64: ${{ secrets.DEVELOPER_ID_INSTALLER_CERTIFICATE_BASE64 }}
|
|
DEVELOPER_ID_P12_PASSWORD: ${{ secrets.DEVELOPER_ID_P12_PASSWORD }}
|
|
MAC_KEYCHAIN_PASSWORD: ${{ secrets.MAC_KEYCHAIN_PASSWORD }}
|
|
run: |
|
|
DEV_CERT_PATH=$RUNNER_TEMP/dev_certificate.p12
|
|
DEV_INSTALLER_CERT_PATH=$RUNNER_TEMP/dev_installer_certificate.p12
|
|
KEYCHAIN_PATH=$RUNNER_TEMP/dev-signing.keychain-db
|
|
|
|
echo -n "$DEVELOPER_ID_CERTIFICATE_BASE64" | base64 --decode -o $DEV_CERT_PATH
|
|
|
|
if [ -n "$DEVELOPER_ID_INSTALLER_CERTIFICATE_BASE64" ]; then
|
|
echo -n "$DEVELOPER_ID_INSTALLER_CERTIFICATE_BASE64" | base64 --decode -o $DEV_INSTALLER_CERT_PATH
|
|
fi
|
|
|
|
security create-keychain -p "$MAC_KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
|
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
|
|
security unlock-keychain -p "$MAC_KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
|
|
|
security import $DEV_CERT_PATH -P "$DEVELOPER_ID_P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
|
|
|
|
if [ -f "$DEV_INSTALLER_CERT_PATH" ]; then
|
|
security import $DEV_INSTALLER_CERT_PATH -P "$DEVELOPER_ID_P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
|
|
fi
|
|
|
|
security list-keychain -d user -s $KEYCHAIN_PATH
|
|
|
|
security find-identity -v -p codesigning $KEYCHAIN_PATH
|
|
|
|
- name: Build macOS DMG
|
|
env:
|
|
ELECTRON_BUILDER_ALLOW_UNRESOLVED_DEPENDENCIES: true
|
|
APPLE_ID: ${{ secrets.APPLE_ID }}
|
|
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
|
|
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
|
|
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
|
NODE_OPTIONS: --max-old-space-size=4096
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
if [ "${{ steps.check_certs.outputs.has_certs }}" != "true" ]; then
|
|
npm run build
|
|
fi
|
|
npx electron-builder --mac dmg --universal --x64 --arm64 --publish never
|
|
|
|
- name: Upload macOS MAS PKG
|
|
if: steps.check_certs.outputs.has_certs == 'true' && hashFiles('release/termix_macos_universal_mas.pkg') != '' && (inputs.artifact_destination == 'file' || inputs.artifact_destination == 'release' || inputs.artifact_destination == 'submit')
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: termix_macos_universal_mas
|
|
path: release/termix_macos_universal_mas.pkg
|
|
retention-days: 30
|
|
if-no-files-found: warn
|
|
|
|
- name: Upload macOS Universal DMG
|
|
uses: actions/upload-artifact@v7
|
|
if: hashFiles('release/termix_macos_universal_dmg.dmg') != '' && inputs.artifact_destination != 'none'
|
|
with:
|
|
name: termix_macos_universal_dmg
|
|
path: release/termix_macos_universal_dmg.dmg
|
|
retention-days: 30
|
|
|
|
- name: Upload macOS x64 DMG
|
|
uses: actions/upload-artifact@v7
|
|
if: hashFiles('release/termix_macos_x64_dmg.dmg') != '' && inputs.artifact_destination != 'none'
|
|
with:
|
|
name: termix_macos_x64_dmg
|
|
path: release/termix_macos_x64_dmg.dmg
|
|
retention-days: 30
|
|
|
|
- name: Upload macOS arm64 DMG
|
|
uses: actions/upload-artifact@v7
|
|
if: hashFiles('release/termix_macos_arm64_dmg.dmg') != '' && inputs.artifact_destination != 'none'
|
|
with:
|
|
name: termix_macos_arm64_dmg
|
|
path: release/termix_macos_arm64_dmg.dmg
|
|
retention-days: 30
|
|
|
|
- name: Get version for Homebrew
|
|
id: homebrew-version
|
|
run: |
|
|
VERSION=$(node -p "require('./package.json').version")
|
|
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
|
|
|
- name: Compute universal DMG checksum
|
|
id: dmg-checksum
|
|
if: hashFiles('release/termix_macos_universal_dmg.dmg') != ''
|
|
run: |
|
|
CHECKSUM=$(shasum -a 256 "release/termix_macos_universal_dmg.dmg" | awk '{print $1}')
|
|
echo "sha256=$CHECKSUM" >> $GITHUB_OUTPUT
|
|
|
|
- name: Generate Homebrew Cask
|
|
if: hashFiles('release/termix_macos_universal_dmg.dmg') != '' && (inputs.artifact_destination == 'file' || inputs.artifact_destination == 'release')
|
|
run: |
|
|
VERSION="${{ steps.homebrew-version.outputs.version }}"
|
|
DMG_PATH="release/termix_macos_universal_dmg.dmg"
|
|
|
|
CHECKSUM=$(shasum -a 256 "$DMG_PATH" | awk '{print $1}')
|
|
|
|
mkdir -p homebrew-generated
|
|
cp Casks/termix.rb homebrew-generated/termix.rb
|
|
|
|
sed -i '' "s/VERSION_PLACEHOLDER/$VERSION/g" homebrew-generated/termix.rb
|
|
sed -i '' "s/CHECKSUM_PLACEHOLDER/$CHECKSUM/g" homebrew-generated/termix.rb
|
|
sed -i '' "s|version \".*\"|version \"$VERSION\"|g" homebrew-generated/termix.rb
|
|
sed -i '' "s|sha256 \".*\"|sha256 \"$CHECKSUM\"|g" homebrew-generated/termix.rb
|
|
sed -i '' "s|release-[0-9.]*-tag|release-$VERSION-tag|g" homebrew-generated/termix.rb
|
|
|
|
- name: Upload Homebrew Cask as artifact
|
|
uses: actions/upload-artifact@v7
|
|
if: hashFiles('homebrew-generated/termix.rb') != '' && inputs.artifact_destination == 'file'
|
|
with:
|
|
name: termix_macos_homebrew_cask
|
|
path: homebrew-generated/termix.rb
|
|
retention-days: 30
|
|
|
|
- name: Upload Homebrew Cask to release
|
|
if: hashFiles('homebrew-generated/termix.rb') != '' && inputs.artifact_destination == 'release'
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
VERSION="${{ steps.homebrew-version.outputs.version }}"
|
|
RELEASE_TAG="release-$VERSION-tag"
|
|
|
|
gh release list --repo ${{ github.repository }} --limit 100 | grep -q "$RELEASE_TAG" || {
|
|
echo "Release $RELEASE_TAG not found"
|
|
exit 1
|
|
}
|
|
|
|
gh release upload "$RELEASE_TAG" homebrew-generated/termix.rb --repo ${{ github.repository }} --clobber
|
|
|
|
- name: Clean up keychains
|
|
if: always()
|
|
run: |
|
|
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db || true
|
|
security delete-keychain $RUNNER_TEMP/dev-signing.keychain-db || true
|
|
|
|
submit-to-chocolatey:
|
|
runs-on: blacksmith-4vcpu-windows-2025
|
|
if: inputs.artifact_destination == 'submit' && (inputs.build_type == 'all' || inputs.build_type == 'windows' || inputs.build_type == '')
|
|
permissions:
|
|
contents: read
|
|
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v7
|
|
with:
|
|
fetch-depth: 1
|
|
|
|
- name: Get version from package.json
|
|
id: package-version
|
|
run: |
|
|
$VERSION = (Get-Content package.json | ConvertFrom-Json).version
|
|
echo "version=$VERSION" >> $env:GITHUB_OUTPUT
|
|
|
|
- name: Download and prepare MSI info from public release
|
|
id: msi-info
|
|
run: |
|
|
$VERSION = "${{ steps.package-version.outputs.version }}"
|
|
$MSI_NAME = "termix_windows_x64_msi.msi"
|
|
$DOWNLOAD_URL = "https://github.com/Termix-SSH/Termix/releases/download/release-$($VERSION)-tag/$($MSI_NAME)"
|
|
|
|
Write-Host "Downloading from $DOWNLOAD_URL"
|
|
New-Item -ItemType Directory -Force -Path "release_asset"
|
|
$DOWNLOAD_PATH = "release_asset\$MSI_NAME"
|
|
|
|
try {
|
|
Invoke-WebRequest -Uri $DOWNLOAD_URL -OutFile $DOWNLOAD_PATH -UseBasicParsing
|
|
} catch {
|
|
Write-Error "Failed to download MSI from $DOWNLOAD_URL. Please ensure the release and asset exist."
|
|
exit 1
|
|
}
|
|
|
|
$CHECKSUM = (Get-FileHash -Path $DOWNLOAD_PATH -Algorithm SHA256).Hash
|
|
echo "msi_name=$MSI_NAME" >> $env:GITHUB_OUTPUT
|
|
echo "checksum=$CHECKSUM" >> $env:GITHUB_OUTPUT
|
|
|
|
- name: Prepare Chocolatey package
|
|
run: |
|
|
$VERSION = "${{ steps.package-version.outputs.version }}"
|
|
$CHECKSUM = "${{ steps.msi-info.outputs.checksum }}"
|
|
$MSI_NAME = "${{ steps.msi-info.outputs.msi_name }}"
|
|
|
|
$DOWNLOAD_URL = "https://github.com/Termix-SSH/Termix/releases/download/release-$VERSION-tag/$MSI_NAME"
|
|
|
|
New-Item -ItemType Directory -Force -Path "choco-build"
|
|
Copy-Item -Path "chocolatey\*" -Destination "choco-build" -Recurse -Force
|
|
|
|
$installScript = Get-Content "choco-build\tools\chocolateyinstall.ps1" -Raw -Encoding UTF8
|
|
$installScript = $installScript -replace 'DOWNLOAD_URL_PLACEHOLDER', $DOWNLOAD_URL
|
|
$installScript = $installScript -replace 'CHECKSUM_PLACEHOLDER', $CHECKSUM
|
|
[System.IO.File]::WriteAllText("$PWD\choco-build\tools\chocolateyinstall.ps1", $installScript, [System.Text.UTF8Encoding]::new($false))
|
|
|
|
$nuspec = Get-Content "choco-build\termix-ssh.nuspec" -Raw -Encoding UTF8
|
|
$nuspec = $nuspec -replace 'VERSION_PLACEHOLDER', $VERSION
|
|
[System.IO.File]::WriteAllText("$PWD\choco-build\termix-ssh.nuspec", $nuspec, [System.Text.UTF8Encoding]::new($false))
|
|
|
|
- name: Install Chocolatey
|
|
run: |
|
|
Set-ExecutionPolicy Bypass -Scope Process -Force
|
|
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
|
|
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
|
|
|
|
- name: Pack Chocolatey package
|
|
run: |
|
|
cd choco-build
|
|
choco pack termix-ssh.nuspec
|
|
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "Chocolatey push failed with exit code $LASTEXITCODE"
|
|
}
|
|
|
|
- name: Check for Chocolatey API Key
|
|
id: check_choco_key
|
|
run: |
|
|
if ("${{ secrets.CHOCOLATEY_API_KEY }}" -ne "") {
|
|
echo "has_key=true" >> $env:GITHUB_OUTPUT
|
|
}
|
|
|
|
- name: Push to Chocolatey
|
|
if: steps.check_choco_key.outputs.has_key == 'true'
|
|
run: |
|
|
$VERSION = "${{ steps.package-version.outputs.version }}"
|
|
cd choco-build
|
|
choco apikey --key "${{ secrets.CHOCOLATEY_API_KEY }}" --source https://push.chocolatey.org/
|
|
|
|
try {
|
|
choco push "termix-ssh.$VERSION.nupkg" --source https://push.chocolatey.org/
|
|
if ($LASTEXITCODE -eq 0) {
|
|
} else {
|
|
throw "Chocolatey push failed with exit code $LASTEXITCODE"
|
|
}
|
|
} catch {
|
|
}
|
|
|
|
- name: Upload Chocolatey package as artifact
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: chocolatey-package
|
|
path: choco-build/*.nupkg
|
|
retention-days: 30
|
|
|
|
submit-to-flatpak:
|
|
runs-on: blacksmith-8vcpu-ubuntu-2404
|
|
if: inputs.artifact_destination == 'submit' && (inputs.build_type == 'all' || inputs.build_type == 'linux' || inputs.build_type == '')
|
|
needs: []
|
|
permissions:
|
|
contents: read
|
|
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v7
|
|
with:
|
|
fetch-depth: 1
|
|
|
|
- name: Get version from package.json
|
|
id: package-version
|
|
run: |
|
|
VERSION=$(node -p "require('./package.json').version")
|
|
RELEASE_DATE=$(date +%Y-%m-%d)
|
|
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
|
echo "release_date=$RELEASE_DATE" >> $GITHUB_OUTPUT
|
|
|
|
- name: Download and prepare AppImage info from public release
|
|
id: appimage-info
|
|
run: |
|
|
VERSION="${{ steps.package-version.outputs.version }}"
|
|
mkdir -p release_assets
|
|
|
|
APPIMAGE_X64_NAME="termix_linux_x64_appimage.AppImage"
|
|
URL_X64="https://github.com/Termix-SSH/Termix/releases/download/release-$VERSION-tag/$APPIMAGE_X64_NAME"
|
|
PATH_X64="release_assets/$APPIMAGE_X64_NAME"
|
|
echo "Downloading x64 AppImage from $URL_X64"
|
|
curl -L -o "$PATH_X64" "$URL_X64"
|
|
chmod +x "$PATH_X64"
|
|
CHECKSUM_X64=$(sha256sum "$PATH_X64" | awk '{print $1}')
|
|
|
|
APPIMAGE_ARM64_NAME="termix_linux_arm64_appimage.AppImage"
|
|
URL_ARM64="https://github.com/Termix-SSH/Termix/releases/download/release-$VERSION-tag/$APPIMAGE_ARM64_NAME"
|
|
PATH_ARM64="release_assets/$APPIMAGE_ARM64_NAME"
|
|
echo "Downloading arm64 AppImage from $URL_ARM64"
|
|
curl -L -o "$PATH_ARM64" "$URL_ARM64"
|
|
chmod +x "$PATH_ARM64"
|
|
CHECKSUM_ARM64=$(sha256sum "$PATH_ARM64" | awk '{print $1}')
|
|
|
|
echo "appimage_x64_name=$APPIMAGE_X64_NAME" >> $GITHUB_OUTPUT
|
|
echo "checksum_x64=$CHECKSUM_X64" >> $GITHUB_OUTPUT
|
|
echo "appimage_arm64_name=$APPIMAGE_ARM64_NAME" >> $GITHUB_OUTPUT
|
|
echo "checksum_arm64=$CHECKSUM_ARM64" >> $GITHUB_OUTPUT
|
|
|
|
- name: Install dependencies
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y imagemagick
|
|
|
|
- name: Prepare Flatpak submission files
|
|
run: |
|
|
VERSION="${{ steps.package-version.outputs.version }}"
|
|
CHECKSUM_X64="${{ steps.appimage-info.outputs.checksum_x64 }}"
|
|
CHECKSUM_ARM64="${{ steps.appimage-info.outputs.checksum_arm64 }}"
|
|
RELEASE_DATE="${{ steps.package-version.outputs.release_date }}"
|
|
|
|
mkdir -p flatpak-submission
|
|
|
|
cp flatpak/com.karmaa.termix.yml flatpak-submission/
|
|
cp flatpak/com.karmaa.termix.desktop flatpak-submission/
|
|
cp flatpak/com.karmaa.termix.metainfo.xml flatpak-submission/
|
|
cp flatpak/flathub.json flatpak-submission/
|
|
|
|
cp public/icon.svg flatpak-submission/com.karmaa.termix.svg
|
|
convert public/icon.png -resize 256x256 flatpak-submission/icon-256.png
|
|
convert public/icon.png -resize 128x128 flatpak-submission/icon-128.png
|
|
|
|
sed -i "s/VERSION_PLACEHOLDER/$VERSION/g" flatpak-submission/com.karmaa.termix.yml
|
|
sed -i "s/CHECKSUM_X64_PLACEHOLDER/$CHECKSUM_X64/g" flatpak-submission/com.karmaa.termix.yml
|
|
sed -i "s/CHECKSUM_ARM64_PLACEHOLDER/$CHECKSUM_ARM64/g" flatpak-submission/com.karmaa.termix.yml
|
|
|
|
sed -i "s/VERSION_PLACEHOLDER/$VERSION/g" flatpak-submission/com.karmaa.termix.metainfo.xml
|
|
sed -i "s/DATE_PLACEHOLDER/$RELEASE_DATE/g" flatpak-submission/com.karmaa.termix.metainfo.xml
|
|
|
|
- name: Upload Flatpak submission as artifact
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: flatpak-submission
|
|
path: flatpak-submission/*
|
|
retention-days: 30
|
|
|
|
- name: Check for Flathub token
|
|
id: check_flathub_token
|
|
run: |
|
|
if [ -n "${{ secrets.FLATHUB_TOKEN }}" ]; then
|
|
echo "has_token=true" >> $GITHUB_OUTPUT
|
|
fi
|
|
|
|
- name: Open PR on Flathub repo
|
|
if: steps.check_flathub_token.outputs.has_token == 'true'
|
|
env:
|
|
GH_TOKEN: ${{ secrets.FLATHUB_TOKEN }}
|
|
VERSION: ${{ steps.package-version.outputs.version }}
|
|
run: |
|
|
FLATHUB_REPO="flathub/com.karmaa.termix"
|
|
BRANCH="release-$VERSION"
|
|
|
|
git config --global user.name "LukeGus"
|
|
git config --global user.email "bugattiguy527@gmail.com"
|
|
|
|
git clone "https://x-access-token:${GH_TOKEN}@github.com/${FLATHUB_REPO}.git" flathub-repo
|
|
cd flathub-repo
|
|
|
|
git checkout -b "$BRANCH"
|
|
|
|
cp ../flatpak-submission/com.karmaa.termix.yml ./
|
|
cp ../flatpak-submission/com.karmaa.termix.desktop ./
|
|
cp ../flatpak-submission/com.karmaa.termix.metainfo.xml ./
|
|
cp ../flatpak-submission/flathub.json ./
|
|
cp ../flatpak-submission/com.karmaa.termix.svg ./
|
|
cp ../flatpak-submission/icon-256.png ./
|
|
cp ../flatpak-submission/icon-128.png ./
|
|
|
|
if git diff --quiet && git diff --cached --quiet; then
|
|
echo "No changes to submit for $VERSION; Flathub repo already up to date."
|
|
exit 0
|
|
fi
|
|
|
|
git add -A
|
|
git commit -m "Update to $VERSION"
|
|
git push origin "$BRANCH"
|
|
|
|
EXISTING_PR=$(gh pr list --repo "$FLATHUB_REPO" --head "$BRANCH" --state open --json number -q '.[0].number' || true)
|
|
if [ -z "$EXISTING_PR" ]; then
|
|
gh pr create --repo "$FLATHUB_REPO" \
|
|
--base master \
|
|
--head "$BRANCH" \
|
|
--title "Update to $VERSION" \
|
|
--body "Automated release update to version $VERSION."
|
|
else
|
|
echo "PR #$EXISTING_PR already open for $BRANCH."
|
|
fi
|
|
|
|
submit-to-homebrew:
|
|
runs-on: blacksmith-6vcpu-macos-latest
|
|
if: inputs.artifact_destination == 'submit' && (inputs.build_type == 'all' || inputs.build_type == 'macos')
|
|
needs: []
|
|
permissions:
|
|
contents: read
|
|
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v7
|
|
with:
|
|
fetch-depth: 1
|
|
|
|
- name: Get version from package.json
|
|
id: package-version
|
|
run: |
|
|
VERSION=$(node -p "require('./package.json').version")
|
|
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
|
|
|
- name: Download and prepare DMG info from public release
|
|
id: dmg-info
|
|
run: |
|
|
VERSION="${{ steps.package-version.outputs.version }}"
|
|
DMG_NAME="termix_macos_universal_dmg.dmg"
|
|
URL="https://github.com/Termix-SSH/Termix/releases/download/release-$VERSION-tag/$DMG_NAME"
|
|
|
|
mkdir -p release_asset
|
|
DOWNLOAD_PATH="release_asset/$DMG_NAME"
|
|
echo "Downloading DMG from $URL"
|
|
|
|
if command -v curl &> /dev/null; then
|
|
curl -L -o "$DOWNLOAD_PATH" "$URL"
|
|
elif command -v wget &> /dev/null; then
|
|
wget -O "$DOWNLOAD_PATH" "$URL"
|
|
else
|
|
echo "Neither curl nor wget is available, installing curl"
|
|
brew install curl
|
|
curl -L -o "$DOWNLOAD_PATH" "$URL"
|
|
fi
|
|
|
|
CHECKSUM=$(shasum -a 256 "$DOWNLOAD_PATH" | awk '{print $1}')
|
|
|
|
echo "dmg_name=$DMG_NAME" >> $GITHUB_OUTPUT
|
|
echo "checksum=$CHECKSUM" >> $GITHUB_OUTPUT
|
|
|
|
- name: Prepare Homebrew submission files
|
|
run: |
|
|
VERSION="${{ steps.package-version.outputs.version }}"
|
|
CHECKSUM="${{ steps.dmg-info.outputs.checksum }}"
|
|
DMG_NAME="${{ steps.dmg-info.outputs.dmg_name }}"
|
|
|
|
mkdir -p homebrew-submission/Casks/t
|
|
|
|
cp Casks/termix.rb homebrew-submission/Casks/t/termix.rb
|
|
|
|
sed -i '' "s/VERSION_PLACEHOLDER/$VERSION/g" homebrew-submission/Casks/t/termix.rb
|
|
sed -i '' "s/CHECKSUM_PLACEHOLDER/$CHECKSUM/g" homebrew-submission/Casks/t/termix.rb
|
|
|
|
- name: Verify Cask syntax
|
|
run: |
|
|
ruby -c homebrew-submission/Casks/t/termix.rb
|
|
|
|
- name: Upload Homebrew submission as artifact
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: homebrew-submission
|
|
path: homebrew-submission/*
|
|
retention-days: 30
|
|
|
|
upload-to-release:
|
|
runs-on: blacksmith-8vcpu-ubuntu-2404
|
|
if: inputs.artifact_destination == 'release'
|
|
needs: [build-windows, build-linux, build-macos]
|
|
permissions:
|
|
contents: write
|
|
|
|
steps:
|
|
- name: Download all artifacts
|
|
uses: actions/download-artifact@v8
|
|
with:
|
|
path: artifacts
|
|
|
|
- name: Resolve release tag
|
|
id: get_release
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
INPUT_TAG: ${{ inputs.release_tag }}
|
|
run: |
|
|
if [ -n "$INPUT_TAG" ]; then
|
|
echo "RELEASE_TAG=$INPUT_TAG" >> $GITHUB_ENV
|
|
else
|
|
echo "RELEASE_TAG=$(gh release list --repo ${{ github.repository }} --limit 1 --json tagName -q '.[0].tagName')" >> $GITHUB_ENV
|
|
fi
|
|
|
|
- name: Upload artifacts to latest release
|
|
run: |
|
|
cd artifacts
|
|
for dir in */; do
|
|
cd "$dir"
|
|
for file in *;
|
|
do
|
|
if [ -f "$file" ]; then
|
|
gh release upload "$RELEASE_TAG" "$file" --repo ${{ github.repository }} --clobber
|
|
fi
|
|
done
|
|
cd ..
|
|
done
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
|
|
submit-to-app-store:
|
|
runs-on: blacksmith-6vcpu-macos-latest
|
|
if: inputs.artifact_destination == 'submit' && (inputs.build_type == 'all' || inputs.build_type == 'macos')
|
|
needs: []
|
|
permissions:
|
|
contents: write
|
|
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v7
|
|
with:
|
|
fetch-depth: 1
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v6
|
|
with:
|
|
node-version-file: ".nvmrc"
|
|
cache: "npm"
|
|
|
|
- name: Install dependencies
|
|
run: |
|
|
npm ci
|
|
npm install --force @rollup/rollup-darwin-arm64
|
|
npm install dmg-license
|
|
|
|
- name: Check for Code Signing Certificates
|
|
id: check_certs
|
|
run: |
|
|
if [ -n "${{ secrets.MAC_BUILD_CERTIFICATE_BASE64 }}" ] && [ -n "${{ secrets.MAC_P12_PASSWORD }}" ]; then
|
|
echo "has_certs=true" >> $GITHUB_OUTPUT
|
|
fi
|
|
|
|
- name: Import Code Signing Certificates
|
|
if: steps.check_certs.outputs.has_certs == 'true'
|
|
env:
|
|
MAC_BUILD_CERTIFICATE_BASE64: ${{ secrets.MAC_BUILD_CERTIFICATE_BASE64 }}
|
|
MAC_INSTALLER_CERTIFICATE_BASE64: ${{ secrets.MAC_INSTALLER_CERTIFICATE_BASE64 }}
|
|
MAC_P12_PASSWORD: ${{ secrets.MAC_P12_PASSWORD }}
|
|
MAC_KEYCHAIN_PASSWORD: ${{ secrets.MAC_KEYCHAIN_PASSWORD }}
|
|
run: |
|
|
APP_CERT_PATH=$RUNNER_TEMP/app_certificate.p12
|
|
INSTALLER_CERT_PATH=$RUNNER_TEMP/installer_certificate.p12
|
|
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
|
|
|
|
echo -n "$MAC_BUILD_CERTIFICATE_BASE64" | base64 --decode -o $APP_CERT_PATH
|
|
|
|
if [ -n "$MAC_INSTALLER_CERTIFICATE_BASE64" ]; then
|
|
echo -n "$MAC_INSTALLER_CERTIFICATE_BASE64" | base64 --decode -o $INSTALLER_CERT_PATH
|
|
fi
|
|
|
|
security create-keychain -p "$MAC_KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
|
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
|
|
security unlock-keychain -p "$MAC_KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
|
|
|
security import $APP_CERT_PATH -P "$MAC_P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
|
|
|
|
if [ -f "$INSTALLER_CERT_PATH" ]; then
|
|
security import $INSTALLER_CERT_PATH -P "$MAC_P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
|
|
fi
|
|
|
|
security list-keychain -d user -s $KEYCHAIN_PATH
|
|
|
|
security find-identity -v -p codesigning $KEYCHAIN_PATH
|
|
|
|
- name: Build macOS App Store Package
|
|
if: steps.check_certs.outputs.has_certs == 'true'
|
|
env:
|
|
ELECTRON_BUILDER_ALLOW_UNRESOLVED_DEPENDENCIES: true
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
NODE_OPTIONS: --max-old-space-size=4096
|
|
run: |
|
|
BUILD_VERSION="${{ github.run_number }}"
|
|
npm run build && npx electron-builder --mac mas --universal --config.buildVersion="$BUILD_VERSION"
|
|
|
|
- name: Check for App Store Connect API credentials
|
|
id: check_asc_creds
|
|
run: |
|
|
if [ -n "${{ secrets.APPLE_KEY_ID }}" ] && [ -n "${{ secrets.APPLE_ISSUER_ID }}" ] && [ -n "${{ secrets.APPLE_KEY_CONTENT }}" ]; then
|
|
echo "has_credentials=true" >> $GITHUB_OUTPUT
|
|
fi
|
|
|
|
- name: Setup Ruby for Fastlane
|
|
if: steps.check_certs.outputs.has_certs == 'true' && steps.check_asc_creds.outputs.has_credentials == 'true'
|
|
uses: ruby/setup-ruby@v1
|
|
with:
|
|
ruby-version: "3.3"
|
|
bundler-cache: false
|
|
|
|
- name: Install Fastlane
|
|
if: steps.check_certs.outputs.has_certs == 'true' && steps.check_asc_creds.outputs.has_credentials == 'true'
|
|
run: gem install fastlane -N
|
|
|
|
- name: Upload and submit to Mac App Store
|
|
if: steps.check_certs.outputs.has_certs == 'true' && steps.check_asc_creds.outputs.has_credentials == 'true'
|
|
env:
|
|
APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
|
|
APPLE_ISSUER_ID: ${{ secrets.APPLE_ISSUER_ID }}
|
|
APPLE_KEY_CONTENT: ${{ secrets.APPLE_KEY_CONTENT }}
|
|
run: |
|
|
PKG_FILE=$(find release -name "termix_macos_universal_mas.pkg" -type f | head -n 1)
|
|
if [ -z "$PKG_FILE" ]; then
|
|
echo "PKG file not found in release/; aborting."
|
|
exit 1
|
|
fi
|
|
|
|
VERSION=$(node -p "require('./package.json').version")
|
|
|
|
# Write API key JSON that Fastlane deliver expects
|
|
mkdir -p /tmp/asc_keys
|
|
KEY_P8_PATH="/tmp/asc_keys/AuthKey_${APPLE_KEY_ID}.p8"
|
|
API_KEY_JSON="/tmp/asc_keys/api_key.json"
|
|
|
|
echo "$APPLE_KEY_CONTENT" | base64 --decode > "$KEY_P8_PATH"
|
|
|
|
printf '{\n "key_id": "%s",\n "issuer_id": "%s",\n "key": "%s",\n "in_house": false\n}\n' \
|
|
"$APPLE_KEY_ID" \
|
|
"$APPLE_ISSUER_ID" \
|
|
"$(tr -d '\n' < "$KEY_P8_PATH")" \
|
|
> "$API_KEY_JSON"
|
|
|
|
fastlane deliver \
|
|
--pkg "$PKG_FILE" \
|
|
--api_key_path "$API_KEY_JSON" \
|
|
--app_version "$VERSION" \
|
|
--skip_metadata true \
|
|
--skip_screenshots true \
|
|
--submit_for_review true \
|
|
--automatic_release true \
|
|
--force true
|
|
|
|
- name: Clean up keychains
|
|
if: always()
|
|
run: |
|
|
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db || true
|
|
rm -rf /tmp/asc_keys
|