# Contributing to TuxMate Thank you for your interest in contributing! This guide ensures high-quality, error-free contributions. --- ## ⚠️ Before You Start **Your PR will be rejected if you:** - ❌ Submit unverified package names - ❌ Use wrong package name casing (e.g., `firefox` vs `MozillaFirefox`) - ❌ Put `pacman` packages in `arch` when they're AUR-only - ❌ Use partial Flatpak IDs instead of full App IDs - ❌ Forget `--classic` for Snap packages that require it - ❌ Include PPAs or unofficial repos for apt packages - ❌ Incorrect Homebrew format (GUI apps require `'--cask name'` with a space separator) --- ## 📦 Adding Applications All applications are defined in [`src/lib/data.ts`](src/lib/data.ts). ### Mandatory Research Protocol **You MUST verify every package on these official sources before submitting:** | Source | What to Check | URL | |--------|--------------|-----| | **Repology** | Global package index (check first!) | `https://repology.org/project/[app-name]/versions` | | **Arch Linux** | Official repos (`core`, `extra`) | [archlinux.org/packages](https://archlinux.org/packages/) | | **AUR** | User repos (only if not in official!) | [aur.archlinux.org](https://aur.archlinux.org/) | | **Ubuntu/Debian** | Main/Universe repos only, **NO PPAs** | [packages.ubuntu.com](https://packages.ubuntu.com/) / [packages.debian.org](https://packages.debian.org/) | | **Fedora** | Official packages | [packages.fedoraproject.org](https://packages.fedoraproject.org/) | | **OpenSUSE** | Official packages | [software.opensuse.org](https://software.opensuse.org/) | | **NixOS** | Nix packages | [search.nixos.org](https://search.nixos.org/packages) | | **Flathub** | Flatpak apps (get the App ID!) | [flathub.org](https://flathub.org/) | | **Snapcraft** | Snap packages | [snapcraft.io](https://snapcraft.io/) | | **Homebrew Formulae** | CLI tools (works on macOS + Linux) | [formulae.brew.sh](https://formulae.brew.sh/) | | **Homebrew Casks** | GUI apps (macOS only) | [formulae.brew.sh/cask](https://formulae.brew.sh/cask/) | --- ### Entry Structure ```typescript { id: 'app-id', // Unique, lowercase, kebab-case name: 'App Name', // Official display name description: 'Short description', // Max ~25 characters category: 'Category', // Must match valid categories iconUrl: si('icon-slug', '#color'), // See Icon System section targets: { ubuntu: 'exact-package-name', // apt package (official repos ONLY) debian: 'exact-package-name', // apt package (official repos ONLY) arch: 'exact-package-name', // pacman OR AUR package name fedora: 'exact-package-name', // dnf package opensuse: 'exact-package-name', // zypper package (CASE SENSITIVE!) nix: 'exact-package-name', // nix package flatpak: 'com.vendor.AppId', // FULL Flatpak App ID (reverse DNS) snap: 'snap-name', // Add --classic if needed homebrew: 'formula-name', // Formula (CLI) or '--cask cask-name' (GUI) }, unavailableReason?: 'Markdown install instructions' } ``` --- ### ⛔ Strict Rules (Read Carefully!) #### Package Name Rules | Rule | ✅ Correct | ❌ Wrong | |------|-----------|---------| | **Case sensitivity** | `MozillaFirefox` (openSUSE) | `firefox` | | **Exact package name** | `firefox-esr` (Debian) | `firefox` | | **OpenJDK versions** | `openjdk-21-jdk` (Ubuntu) | `openjdk` | | **Arch package** | `firefox` | `firefox-bin` (when official exists) | #### Arch Linux: `arch` vs AUR | Situation | Field to Use | Example | |-----------|-------------|---------| | Package in official repos (`core`/`extra`) | `arch: 'package'` | `arch: 'firefox'` | | Package NOT in official repos | `arch: 'package-bin'` | `arch: 'brave-bin'` | | NEVER mix both | Use only ONE | — | **How to check:** 1. Search [archlinux.org/packages](https://archlinux.org/packages/) 2. If found → use `arch` field 3. If NOT found → search [aur.archlinux.org](https://aur.archlinux.org/) → use `arch` field with AUR package name 4. Prefer `-bin` suffix packages in AUR (pre-built, faster install) 5. **IMPORTANT**: If your AUR package name does **NOT** end in `-bin`, `-git`, or `-appimage`, you **MUST** add it to `KNOWN_AUR_PACKAGES` in [`src/lib/aur.ts`](src/lib/aur.ts) so the app knows it's from AUR. #### Ubuntu/Debian: Official Repos Only | ✅ Allowed | ❌ NOT Allowed | |-----------|---------------| | Main repository packages | PPAs | | Universe repository packages | Third-party repos | | Packages on packages.ubuntu.com | Manual .deb downloads | **If a package requires a PPA:** Leave the field empty and add install instructions to `unavailableReason`. #### Flatpak: Full App ID Required | ✅ Correct | ❌ Wrong | |-----------|---------| | `com.spotify.Client` | `spotify` | | `org.mozilla.firefox` | `firefox` | | `app.zen_browser.zen` | `zen-browser` | **How to find:** Go to [flathub.org](https://flathub.org/), search the app, copy the full App ID from the app page. #### Snap: Classic Confinement Some snaps require `--classic` flag. Check [snapcraft.io](https://snapcraft.io/) for the app and look for "classic" confinement. | App Type | Format | |----------|--------| | Regular snap | `'snap-name'` | | Classic confinement | `'snap-name --classic'` | #### Homebrew: Formulae vs Casks Homebrew has two types of packages: | Type | What It Is | Platform | Format in `targets` | |------|-----------|----------|--------------------| | **Formula** | CLI tools, libraries | macOS + Linux | `'package-name'` | | **Cask** | GUI applications (.app) | macOS only | `'--cask package-name'` | **Examples:** | App | Type | Correct Format | |-----|------|----------------| | Git | Formula (CLI) | `homebrew: 'git'` | | Node.js | Formula (CLI) | `homebrew: 'node'` | | Python | Formula (versioned) | `homebrew: 'python@3.12'` | | Firefox | Cask (GUI) | `homebrew: '--cask firefox'` | | VS Code | Cask (GUI) | `homebrew: '--cask visual-studio-code'` | | Discord | Cask (GUI) | `homebrew: '--cask discord'` | | VLC | Cask (GUI) | `homebrew: '--cask vlc'` | **How to verify package names:** 1. **Formulae**: Search [formulae.brew.sh](https://formulae.brew.sh/) or run `brew search ` 2. **Casks**: Search [formulae.brew.sh/cask](https://formulae.brew.sh/cask/) or run `brew search --cask ` 3. Check the exact name on the package page (e.g., `visual-studio-code` not `vscode`) **Important notes:** - Casks are **macOS-only** — the generated script will skip them on Linux - Always prefix GUI apps with `--cask ` (note the space after) - Some apps exist as both formula AND cask (e.g., `emacs` formula vs `emacs-app` cask) — choose based on user expectation - For versioned packages, use the explicit version: `python@3.12`, `node@20` --- ### Empty Fields **If a package doesn't exist in a source, leave the field empty (omit it entirely):** ```typescript // ✅ Correct - Discord not in apt repos targets: { arch: 'discord', flatpak: 'com.discordapp.Discord', snap: 'discord' } // ❌ Wrong - Empty strings clutter the code targets: { ubuntu: '', debian: '', arch: 'discord', fedora: '', opensuse: '', nix: '', flatpak: 'com.discordapp.Discord', snap: 'discord' } ``` --- ### The `unavailableReason` Field Use this to provide helpful installation alternatives when an app isn't available in most package managers. **Format:** Markdown with clickable links ```typescript // ✅ Good example unavailableReason: 'Not in official repos. Use [Flatpak](https://flathub.org/apps/com.example.App) or download from [example.com](https://example.com/download).' // ❌ Bad examples unavailableReason: 'Not available' // No helpful info unavailableReason: 'Download from website' // No link provided ``` --- ### Valid Categories Use **exactly** one of these: ``` Web Browsers • Communication • Dev: Languages • Dev: Editors • Dev: Tools Terminal • CLI Tools • Media • Creative • Gaming • Office VPN & Network • Security • File Sharing • System ``` --- ## 🎨 Icon System TuxMate uses the [Iconify API](https://iconify.design/) for icons. Icon helpers are defined in [`src/lib/data.ts`](src/lib/data.ts). ### Helper Functions | Function | Use Case | Example | |----------|----------|---------| | `si('slug', '#color')` | Simple Icons (brands) | `si('firefox', '#FF7139')` | | `lo('slug')` | Logos (already colorful) | `lo('chrome')` | | `vs('slug')` | VS Code file icons | `vs('file-type-shell')` | | `mdi('slug', '#color')` | Material Design icons | `mdi('console', '#57F287')` | ### Finding Icon Slugs | Source | URL | Notes | |--------|-----|-------| | **Simple Icons** | [simpleicons.org](https://simpleicons.org/) | Use lowercase slug, add hex color | | **Material Design** | [pictogrammers.com/library/mdi](https://pictogrammers.com/library/mdi/) | Use icon name | | **Iconify Search** | [icon-sets.iconify.design](https://icon-sets.iconify.design/) | Search all sets | | **Fallback** | — | Use `mdi('application', '#color')` | ### Icon Requirements - ✅ Must be recognizable at 24×24px - ✅ Use [official brand colors](https://simpleicons.org) - click icon to copy hex - ✅ Monochrome icons (si, mdi) require a color parameter - ✅ Colorful icons (lo, sk, vs) don't need color - ❌ Don't use blurry or low-quality external URLs --- ## 🔀 Pull Request Checklist **Before submitting, verify ALL of these:** ### Package Verification - [ ] Checked [Repology](https://repology.org/) for global package availability - [ ] Verified **exact** package names on each distro's official package search - [ ] Confirmed case sensitivity (especially openSUSE: `MozillaFirefox`, `MozillaThunderbird`) - [ ] Arch packages confirmed in [official repos](https://archlinux.org/packages/) OR [AUR](https://aur.archlinux.org/) - [ ] Ubuntu/Debian packages are in **Main/Universe only** (no PPAs) - [ ] Flatpak uses **full App ID** from [Flathub](https://flathub.org/) - [ ] Snap packages checked for `--classic` requirement - [ ] Homebrew uses correct format: `'formula'` for CLI, `'--cask name'` for GUI apps ### Code Quality - [ ] Tested locally with `npm run dev` - [ ] Production build passes: `npm run build` - [ ] Lint passes: `npm run lint` - [ ] Unit tests pass: `npm run test` - [ ] Apps added in **alphabetical order** within their category - [ ] Icons display correctly at small sizes --- ## 📝 Pull Request Template Use the following template when submitting a pull request: ```markdown ## Summary Brief description of changes made. ## Changes ### Apps Added | App Name | Category | Package Sources | |----------|----------|-----------------| | Example App | Dev: Tools | apt, pacman, flatpak, homebrew | ### Apps Modified - `app-id`: Description of change ## Verification > All package names have been verified against official sources. | Source | Verification Link | |--------|-------------------| | Repology | [repology.org/project/...](https://repology.org/) | | Arch Linux | [archlinux.org/packages/...](https://archlinux.org/packages/) | | AUR | [aur.archlinux.org/packages/...](https://aur.archlinux.org/) | | Ubuntu | [packages.ubuntu.com/...](https://packages.ubuntu.com/) | | Fedora | [packages.fedoraproject.org/...](https://packages.fedoraproject.org/) | | openSUSE | [software.opensuse.org/...](https://software.opensuse.org/) | | NixOS | [search.nixos.org/packages/...](https://search.nixos.org/packages) | | Flathub | [flathub.org/apps/...](https://flathub.org/) | | Snapcraft | [snapcraft.io/...](https://snapcraft.io/) | | Homebrew | [formulae.brew.sh/...](https://formulae.brew.sh/) | ## Testing - [ ] `npm run dev` — Local development server works - [ ] `npm run build` — Production build passes - [ ] `npm run lint` — No linting errors - [ ] `npm run test` — All unit tests pass - [ ] Verified in browser — UI renders correctly ## Screenshots (if applicable) ``` --- ## 💻 Development Workflow ### Initial Setup ```bash # Clone the repository git clone https://github.com/abusoww/tuxmate.git cd tuxmate # Install dependencies npm install # Start development server npm run dev ``` The development server will be available at `http://localhost:5173`. ### Quality Assurance Run these commands before every commit: | Command | Purpose | |---------|---------| | `npm run lint` | Check for code style issues | | `npm run lint -- --fix` | Auto-fix linting errors | | `npm run test` | Run unit test suite | | `npm run build` | Verify production build | ### Branch Naming Convention | Type | Format | Example | |------|--------|---------| | New feature | `feature/description` | `feature/add-homebrew-support` | | Bug fix | `fix/description` | `fix/arch-aur-detection` | | Documentation | `docs/description` | `docs/update-contributing` | | Refactor | `refactor/description` | `refactor/script-generation` | ### Commit Message Format Follow [Conventional Commits](https://www.conventionalcommits.org/): ``` (): [optional body] [optional footer] ``` **Types:** | Type | Description | |------|-------------| | `feat` | New feature or functionality | | `fix` | Bug fix | | `docs` | Documentation changes | | `style` | Code style (formatting, no logic change) | | `refactor` | Code restructuring (no feature change) | | `test` | Adding or updating tests | | `chore` | Maintenance tasks | **Examples:** ```bash feat(data): add Homebrew support for 50+ apps fix(scripts): correct AUR package detection for -git suffix docs(contributing): add Homebrew verification guidelines ``` --- ## 🐧 Adding Distributions Distributions are defined in [`src/lib/data.ts`](src/lib/data.ts). ### Distro Structure ```typescript { id: 'distro-id', name: 'Display Name', iconUrl: si('distro-slug', '#color'), color: '#HexColor', installPrefix: 'sudo pkg install -y' } ``` ### After Adding a Distro 1. Add the distro ID to the `DistroId` type in `src/lib/data.ts` 2. Create a new script generator file: `src/lib/scripts/[distro].ts` 3. Export the generator from `src/lib/scripts/index.ts` 4. Add the case in `src/lib/generateInstallScript.ts` (both functions) 5. Handle distro-specific logic (repo setup, package detection, etc.) 6. Add `targets.[distro]` entries to relevant apps in `data.ts` --- ## ⚙️ Script Generation Script generation is modular. Each distro has its own generator: ``` src/lib/ ├── generateInstallScript.ts # Main entry point ├── aur.ts # AUR package detection └── scripts/ ├── index.ts # Exports all generators ├── shared.ts # Colors, progress bars, utilities ├── arch.ts # Arch + AUR (yay) ├── debian.ts # Debian apt ├── ubuntu.ts # Ubuntu apt + PPA handling ├── fedora.ts # Fedora dnf + RPM Fusion ├── opensuse.ts # openSUSE zypper ├── nix.ts # Nix package manager ├── flatpak.ts # Flatpak (parallel install) ├── snap.ts # Snap packages └── homebrew.ts # Homebrew (formulae + casks) ``` ### Script Generator Features Each script generator implements these core capabilities: | Feature | Description | Implementation | |---------|-------------|----------------| | **Package Detection** | Skip already-installed packages | Distro-specific checks (e.g., `dpkg -l`, `brew list`) | | **AUR Handling** | Auto-install `yay`/`paru` helper for Arch | See [`aur.ts`](src/lib/aur.ts) for detection patterns | | **RPM Fusion** | Auto-enable repos for Fedora multimedia | Enabled when proprietary codecs needed | | **Parallel Install** | Concurrent package installation | Flatpak uses background jobs for speed | | **Network Retry** | Exponential backoff on failures | `with_retry()` in [`shared.ts`](src/lib/scripts/shared.ts) | | **Progress UI** | Colored output with ETA | Progress bars, timing, summary | | **Shell Escaping** | Prevent command injection | `escapeShellString()` in [`shared.ts`](src/lib/scripts/shared.ts) | | **Homebrew Casks** | Platform-aware formula/cask handling | Separate commands, skip casks on Linux | ### Testing Script Changes #### Automated Testing ```bash # Run the full test suite npm run test # Run tests in watch mode during development npm run test -- --watch # Run specific test file npm run test -- src/__tests__/aur.test.ts ``` #### Manual Testing Workflow | Step | Action | Purpose | |------|--------|---------| | 1 | `npm run dev` | Start development server | | 2 | Select test packages | Choose mix of package types | | 3 | Copy generated script | Use "Copy" button | | 4 | Test in isolated environment | VM or container (see below) | | 5 | Verify installation | Check packages installed correctly | #### Container Testing Use Docker containers for safe, isolated testing: ```bash # Arch Linux docker run -it --rm archlinux:latest bash -c "pacman -Sy && bash" # Ubuntu docker run -it --rm ubuntu:latest bash -c "apt update && bash" # Fedora docker run -it --rm fedora:latest bash -c "dnf check-update; bash" # Debian docker run -it --rm debian:latest bash -c "apt update && bash" ``` > [!TIP] > For Homebrew testing, use a macOS environment or [Homebrew on Linux](https://docs.brew.sh/Homebrew-on-Linux). --- ## 🐛 Reporting Issues ### Bug Reports — Include: - Browser & OS (e.g., Firefox 120 on Arch Linux) - Steps to reproduce (numbered list) - Expected vs actual behavior - Console errors (F12 → Console tab) - Screenshots if UI-related ### Feature Requests — Include: - Use case and why it's needed - Proposed solution - Alternatives considered --- ## ❓ Questions? Open a [Discussion](https://github.com/abusoww/tuxmate/discussions) or create an [Issue](https://github.com/abusoww/tuxmate/issues).