From 68c8e295e9a3168303e048aecb939a80d4d46218 Mon Sep 17 00:00:00 2001 From: Gil Desmarais Date: Tue, 9 Sep 2025 20:41:53 +0200 Subject: [PATCH] dev: improve DX for development & contributing --- .cursor/rules/read-copilot-instructions.mdc | 12 ++++ .devcontainer/devcontainer.json | 41 ++++++++++++ .github/copilot-instructions.md | 48 ++++++++++++++ .gitignore | 70 +++++++++++++++++++-- Makefile | 39 ++++++++++++ README.md | 39 ++++++++++++ bin/dev | 20 ++++++ bin/setup | 36 +++++++++++ 8 files changed, 300 insertions(+), 5 deletions(-) create mode 100644 .cursor/rules/read-copilot-instructions.mdc create mode 100644 .devcontainer/devcontainer.json create mode 100644 .github/copilot-instructions.md create mode 100644 Makefile create mode 100755 bin/dev create mode 100755 bin/setup diff --git a/.cursor/rules/read-copilot-instructions.mdc b/.cursor/rules/read-copilot-instructions.mdc new file mode 100644 index 00000000..fdbbd686 --- /dev/null +++ b/.cursor/rules/read-copilot-instructions.mdc @@ -0,0 +1,12 @@ +--- +description: Read and follow .github/copilot-instructions.md for this repo +alwaysApply: true +--- + +Before assisting, open and read `.github/copilot-instructions.md`. +Follow it as the authoritative source for coding practices, docs style, security, and compliance for this project. + +If the file is missing, say so, ask to create it, and proceed with safe defaults. +When β€œCopilot” is mentioned in that file, interpret it as referring to **you (Cursor)**. +Summarize the relevant sections into your working context before you act. + diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..b0cc2012 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,41 @@ +{ + "name": "html2rss-web", + "image": "mcr.microsoft.com/devcontainers/ruby:3.4", + "features": { + "ghcr.io/devcontainers/features/git:1": {}, + "ghcr.io/devcontainers/features/github-cli:1": {} + }, + "customizations": { + "vscode": { + "extensions": [ + "redhat.vscode-yaml", + "esbenp.prettier-vscode", + "github.copilot", + "github.copilot-chat", + "shopify.ruby-lsp" + ], + "settings": { + "ruby.rubocop.executePath": "bundle exec", + "ruby.format": "rubocop", + "ruby.lint": { + "rubocop": true + }, + "files.associations": { + "*.erb": "erb" + } + } + } + }, + "postCreateCommand": "make setup", + "postStartCommand": "echo 'πŸš€ html2rss-web Development Environment Ready!' && echo '' && echo 'πŸ“‹ Quick Start Commands:' && echo ' make dev # Start development server' && echo ' make test # Run tests' && echo ' make lint # Run linter' && echo ' make fix # Auto-fix linting issues' && echo ' make help # Show all commands' && echo '' && echo '🌐 Server will be available at: http://localhost:3000' && echo 'πŸ“ Project files are in: /workspaces/html2rss-web' && echo '' && echo 'πŸ’‘ Tip: Use Ctrl+C to stop the development server' && echo ''", + "forwardPorts": [ + 3000 + ], + "portsAttributes": { + "3000": { + "label": "html2rss-web", + "onAutoForward": "notify" + } + }, + "remoteUser": "vscode" +} diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 00000000..9a3727a6 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,48 @@ +# html2rss-web AI Agent Instructions + +## Overview + +- Ruby web app that converts websites into RSS 2.0 feeds. +- Built with **Roda**, using the **html2rss** gem (+ `html2rss-configs`). +- **Principle:** _All features must work without JavaScript._ JS is only progressive enhancement. + +## Core Rules + +- βœ… Use **Roda routing with `hash_branch`**. Keep routes small. +- βœ… Put logic into `helpers/` or `app/`, not inline in routes. +- βœ… Validate all inputs. Pass outbound requests through **SSRF filter**. +- βœ… Add caching headers where appropriate (`Rack::Cache`). +- βœ… Errors: friendly messages for users, detailed logging internally. +- βœ… CSS: Water.css + small overrides in `public/styles.css`. +- βœ… Specs: RSpec, unit + integration, use VCR for external requests. + +## Don’t + +- ❌ Don’t depend on JS for core flows. +- ❌ Don’t bypass SSRF filter or weaken CSP. +- ❌ Don’t add databases, ORMs, or background jobs. +- ❌ Don’t leak stack traces or secrets in responses. + +## Project Structure + +- `app.rb` – main Roda app +- `app/` – core modules (config, cache, ssrf, health) +- `routes/` – route handlers (`hash_branch`) +- `helpers/` – pure helper modules (`module_function`) +- `views/` – ERB templates +- `public/` – static assets (CSS/JS, minimal) +- `config/feeds.yml` – feed definitions +- `spec/` – RSpec tests + VCR cassettes + +## Environment + +- `RACK_ENV` – environment +- `AUTO_SOURCE_ENABLED`, `AUTO_SOURCE_USERNAME`, `AUTO_SOURCE_PASSWORD`, `AUTO_SOURCE_ALLOWED_ORIGINS` +- `HEALTH_CHECK_USERNAME`, `HEALTH_CHECK_PASSWORD` +- `SENTRY_DSN` (optional) + +## Style + +- Add `# frozen_string_literal: true` +- Follow RuboCop style +- YARD doc comments for public methods diff --git a/.gitignore b/.gitignore index a308967f..cdcc6749 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,65 @@ -tmp/* -!tmp/.keep -.yardoc -coverage -spec/examples.txt +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-journal + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key + +# Ignore environment variables +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# Ignore coverage reports +/coverage/ + +# Ignore VCR cassettes (they should be committed) +# /spec/fixtures/vcr_cassettes/ + +# Ignore IDE files +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# Ignore OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Ignore rack cache +/tmp/rack-cache-* + +# Ignore simplecov +/coverage/ \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..1dd8783e --- /dev/null +++ b/Makefile @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +.PHONY: help test lint fix setup dev clean + +# Default target +help: ## Show this help message + @echo "html2rss-web Development Commands" + @echo "=================================" + @echo "" + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-15s\033[0m %s\n", $$1, $$2}' + +setup: ## Full development setup + @echo "Setting up development environment..." + bundle install + @if [ ! -f .env ]; then \ + cp .env.example .env 2>/dev/null || echo "RACK_ENV=development" > .env; \ + echo "Created .env file"; \ + fi + @mkdir -p tmp/rack-cache-body tmp/rack-cache-meta + @echo "Setup complete!" + +dev: ## Start development server + @echo "Starting development server..." + @echo "Server will be available at: http://localhost:3000" + @echo "Press Ctrl+C to stop" + @bin/dev + +test: ## Run tests + bundle exec rspec + +lint: ## Run linter + bundle exec rubocop + +fix: ## Auto-fix linting issues + bundle exec rubocop -a + +clean: ## Clean temporary files + @rm -rf tmp/rack-cache-* coverage/ + @echo "Clean complete!" diff --git a/README.md b/README.md index 6a12e3fe..e42bf450 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,45 @@ The functionality of scraping websites and building the RSS feeds is provided by For full documentation, please see the [html2rss-web documentation](https://html2rss.github.io/web-application/). +## Development + +### Quick Start with GitHub Codespaces + +The easiest way to get started is using GitHub Codespaces: + +1. Fork this repository +2. Click "Code" β†’ "Codespaces" β†’ "Create codespace on [your-username]/html2rss-web" +3. Wait for the codespace to build (it will automatically run `bundle install`) +4. The development server will be available at the forwarded port (usually 3000) + +### Local Development + +1. **Clone and setup:** + ```bash + git clone https://github.com/html2rss/html2rss-web.git + cd html2rss-web + make setup + ``` + +2. **Start development server:** + ```bash + make dev + ``` + +The application will be available at `http://localhost:3000`. + +### Development Commands + +| Command | Description | +| ------------ | --------------------------- | +| `make help` | Show all available commands | +| `make setup` | Full development setup | +| `make dev` | Start development server | +| `make test` | Run tests | +| `make lint` | Run linter | +| `make fix` | Auto-fix linting issues | +| `make clean` | Clean temporary files | + ## Contributing Contributions are welcome! Please see the [contributing guide](https://html2rss.github.io/get-involved/contributing) for more information. diff --git a/bin/dev b/bin/dev new file mode 100755 index 00000000..4d11845b --- /dev/null +++ b/bin/dev @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# frozen_string_literal: true + +# Development server startup script +set -e + +# Load environment variables if .env file exists +if [ -f .env ]; then + export $(cat .env | grep -v '^#' | xargs) +fi + +# Set default environment +export RACK_ENV=${RACK_ENV:-development} + +echo "Starting html2rss-web in development mode..." +echo "Environment: $RACK_ENV" +echo "Port: ${PORT:-3000}" + +# Start the development server +bundle exec rackup -p ${PORT:-3000} -o 0.0.0.0 diff --git a/bin/setup b/bin/setup new file mode 100755 index 00000000..b8ade628 --- /dev/null +++ b/bin/setup @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +# frozen_string_literal: true + +# Development environment setup script +set -e + +echo "Setting up html2rss-web development environment..." + +# Check if Ruby version is correct +ruby_version=$(ruby -v | cut -d' ' -f2 | cut -d'p' -f1) +echo "Ruby version: $ruby_version" + +# Install dependencies +echo "Installing dependencies..." +bundle install + +# Create .env file if it doesn't exist +if [ ! -f .env ]; then + echo "Creating .env file from .env.example..." + cp .env.example .env + echo "Please edit .env file with your configuration" +fi + +# Create necessary directories +echo "Creating necessary directories..." +mkdir -p tmp/rack-cache-body +mkdir -p tmp/rack-cache-meta + +# Run tests to verify setup +echo "Running tests to verify setup..." +bundle exec rspec + +echo "Setup complete! You can now run:" +echo " bin/dev # Start development server" +echo " bundle exec rspec # Run tests" +echo " bundle exec rubocop # Run linter"