Files
tuxmate/CONTRIBUTING.md

546 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 <name>`
2. **Casks**: Search [formulae.brew.sh/cask](https://formulae.brew.sh/cask/) or run `brew search --cask <name>`
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
- [ ] Nix packages checked for unfree license (add to `KNOWN_UNFREE_PACKAGES` if needed)
- [ ] 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)
<!-- Add screenshots for UI changes -->
```
---
## 💻 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/):
```
<type>(<scope>): <description>
[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 declarative config generator
├── flatpak.ts # Flatpak (parallel install)
├── snap.ts # Snap packages
└── homebrew.ts # Homebrew (formulae + casks)
```
### Nix Unfree Packages
When adding Nix packages, check if they require `allowUnfree = true`. Unfree packages are detected in [`src/lib/nixUnfree.ts`](src/lib/nixUnfree.ts).
**Known unfree packages** (add new ones to `KNOWN_UNFREE_PACKAGES`):
- Communication: `discord`, `slack`, `zoom-us`, `teams`, `skypeforlinux`
- Browsers: `google-chrome`, `vivaldi`, `opera`
- Media: `spotify`
- Gaming: `steam`
- Dev: `vscode`, `sublime-text`, `postman`, `code-cursor`, `vagrant`, JetBrains IDEs
- Creative: `davinci-resolve`
- Other: `obsidian`, `dropbox`, `1password`
**How it works:**
1. User selects unfree packages with Nix distro
2. UI shows amber warning listing affected apps
3. Downloaded `configuration.nix` includes comment with `allowUnfree` instructions
### 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).