diff --git a/.editorconfig b/.editorconfig index c7f74e0..c636a36 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,7 +11,7 @@ root = true insert_final_newline = true indent_style = space indent_size = 4 -guidelines = 120 +guidelines = 140 # C# files @@ -85,8 +85,8 @@ csharp_preserve_single_line_blocks = true csharp_preserve_single_line_statements = false dotnet_separate_import_directive_groups = false -# IDE0005: Remove unnessecary using statements -dotnet_diagnostic.IDE0005.severity = warning +# IDE0005: Remove unnecessary using statements +dotnet_diagnostic.IDE0005.severity = error # Expression-level preferences dotnet_style_object_initializer = true:suggestion @@ -169,10 +169,16 @@ dotnet_naming_style.end_in_async.required_suffix = Async dotnet_naming_style.end_in_async.capitalization = pascal_case dotnet_naming_style.end_in_async.word_separator = -# ---- Latest csharp features ----- # +# IDE0290 Use primary constructor +# https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-12#primary-constructors +# https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/primary-constructors +# will disable this rule for now until I decide if I like it and want to use it. +# dotnet_diagnostic.IDE0290.severity = none | error | suggestion + +# IDE0290 Use primary constructor +dotnet_diagnostic.IDE0290.severity = none -# guidelines support -guidelines = 120 +# ---- Latest csharp features ----- # # CA1031: Do not catch general exception types dotnet_diagnostic.CA1031.severity = none diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..68dda83 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,74 @@ +# AI Coding Agent Instructions for SeedFolder + +## Project Overview +This is a .NET Global Tool that creates project directories and seeds them with standard dotfiles. The entire application is contained in a single file (`src/Program.cs`) for simplicity. + +## Architecture Patterns + +### Single-File Console Application +- All logic exists in `src/Program.cs` - no complex project structure +- Uses `McMaster.Extensions.CommandLineUtils` for CLI interactions, `Figgle` for ASCII headers, `Colorful.Console` for output formatting +- Command-line parsing is handled manually in `Main()` - check for help flags before processing folder names + +### Embedded Resources Pattern +Template files in `src/Data/` are embedded as resources, not file system copies: +```xml + + +``` +Access via `Assembly.GetManifestResourceStream("solrevdev.seedfolder.Data.{filename}")` in `WriteFileAsync()` + +### Multi-Framework Targeting +Targets `net8.0;net9.0` for modern .NET compatibility. .NET 8 is LTS (supported until November 2026) and .NET 9 is STS (18-month support). Version bumps in `.csproj` trigger NuGet deployment. + +## Key Development Workflows + +### Local Testing Cycle +```bash +# Build and test locally (use build/test-local.sh script) +dotnet pack -c release -o artifacts/nupkg +dotnet tool uninstall -g solrevdev.seedfolder +dotnet tool install -g --add-source artifacts/nupkg solrevdev.seedfolder +``` + +### Version Management +- Bump `` in `src/solrevdev.seedfolder.csproj` to trigger CI/CD +- CI only runs on pushes to `master` branch (exclude commits with `***NO_CI***`, `[ci skip]`, `[skip ci]`) +- GitHub Actions automatically publishes to NuGet on master pushes + +### Running During Development +```bash +# Interactive mode +dotnet run --project src/solrevdev.seedfolder.csproj + +# With folder name argument +dotnet run --project src/solrevdev.seedfolder.csproj myfolder +``` + +## Project-Specific Conventions + +### Input Sanitization +Always use `RemoveSpaces()` and `SafeNameForFileSystem()` for folder names: +```csharp +folderName = RemoveSpaces(folderName); // Spaces → dashes +folderName = SafeNameForFileSystem(folderName); // Invalid chars → dashes +``` + +### Date Prefixing Logic +Interactive mode offers date prefixing: `YYYY-MM-DD_foldername` format using `StringBuilder` for performance. + +### Error Handling Pattern +- Check if folder exists before creation - exit with colored error message +- Use `Directory.Exists()` check, then `ConsoleColor.DarkRed` for error output +- No exceptions for user errors - graceful CLI messaging + +## File Structure Details +- `src/Data/` contains template files without leading dots (e.g., `gitignore` not `.gitignore`) +- Files are copied with proper dotfile names during `WriteFileAsync()` +- `omnisharp.json` is copied without dot prefix (special case) + +## CI/CD Integration Points +- GitHub Actions workflow in `.github/workflows/ci.yml` handles build → pack → publish +- Requires `NUGET_API_KEY` secret for automated publishing +- Uses `rohith/publish-nuget@v2.1.1` action for NuGet deployment +- Build scripts in `build/` folder provide cross-platform local testing diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eb2e357..6023235 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,9 +37,11 @@ jobs: uses: actions/checkout@v4 - name: setup .net core sdk - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: - dotnet-version: '8.0.x' # SDK Version to use; x will use the latest version of the 3.1 channel + dotnet-version: | + 8.0.x + 9.0.x - name: dotnet build run: dotnet build solrevdev.seedfolder.sln --configuration Release diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml new file mode 100644 index 0000000..a12225a --- /dev/null +++ b/.github/workflows/claude-code-review.yml @@ -0,0 +1,78 @@ +name: Claude Code Review + +on: + pull_request: + types: [opened, synchronize] + # Optional: Only run on specific file changes + # paths: + # - "src/**/*.ts" + # - "src/**/*.tsx" + # - "src/**/*.js" + # - "src/**/*.jsx" + +jobs: + claude-review: + # Optional: Filter by PR author + # if: | + # github.event.pull_request.user.login == 'external-contributor' || + # github.event.pull_request.user.login == 'new-developer' || + # github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR' + + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: read + issues: read + id-token: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Run Claude Code Review + id: claude-review + uses: anthropics/claude-code-action@beta + with: + claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + + # Optional: Specify model (defaults to Claude Sonnet 4, uncomment for Claude Opus 4.1) + # model: "claude-opus-4-1-20250805" + + # Direct prompt for automated review (no @claude mention needed) + direct_prompt: | + Please review this pull request and provide feedback on: + - Code quality and best practices + - Potential bugs or issues + - Performance considerations + - Security concerns + - Test coverage + + Be constructive and helpful in your feedback. + + # Optional: Use sticky comments to make Claude reuse the same comment on subsequent pushes to the same PR + # use_sticky_comment: true + + # Optional: Customize review based on file types + # direct_prompt: | + # Review this PR focusing on: + # - For TypeScript files: Type safety and proper interface usage + # - For API endpoints: Security, input validation, and error handling + # - For React components: Performance, accessibility, and best practices + # - For tests: Coverage, edge cases, and test quality + + # Optional: Different prompts for different authors + # direct_prompt: | + # ${{ github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR' && + # 'Welcome! Please review this PR from a first-time contributor. Be encouraging and provide detailed explanations for any suggestions.' || + # 'Please provide a thorough code review focusing on our coding standards and best practices.' }} + + # Optional: Add specific tools for running tests or linting + # allowed_tools: "Bash(npm run test),Bash(npm run lint),Bash(npm run typecheck)" + + # Optional: Skip review for certain conditions + # if: | + # !contains(github.event.pull_request.title, '[skip-review]') && + # !contains(github.event.pull_request.title, '[WIP]') + diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml new file mode 100644 index 0000000..bc77307 --- /dev/null +++ b/.github/workflows/claude.yml @@ -0,0 +1,64 @@ +name: Claude Code + +on: + issue_comment: + types: [created] + pull_request_review_comment: + types: [created] + issues: + types: [opened, assigned] + pull_request_review: + types: [submitted] + +jobs: + claude: + if: | + (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) || + (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) || + (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) || + (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))) + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: read + issues: read + id-token: write + actions: read # Required for Claude to read CI results on PRs + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Run Claude Code + id: claude + uses: anthropics/claude-code-action@beta + with: + claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + + # This is an optional setting that allows Claude to read CI results on PRs + additional_permissions: | + actions: read + + # Optional: Specify model (defaults to Claude Sonnet 4, uncomment for Claude Opus 4.1) + # model: "claude-opus-4-1-20250805" + + # Optional: Customize the trigger phrase (default: @claude) + # trigger_phrase: "/claude" + + # Optional: Trigger when specific user is assigned to an issue + # assignee_trigger: "claude-bot" + + # Optional: Allow Claude to run specific commands + # allowed_tools: "Bash(npm install),Bash(npm run build),Bash(npm run test:*),Bash(npm run lint:*)" + + # Optional: Add custom instructions for Claude to customize its behavior for your project + # custom_instructions: | + # Follow our coding standards + # Ensure all new code has tests + # Use TypeScript for new files + + # Optional: Custom environment variables for Claude + # claude_env: | + # NODE_ENV: test + diff --git a/.vscode/settings.json b/.vscode/settings.json index 94c98dc..65ba3a1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,6 +9,7 @@ "Figgle", "gitattributes", "locproj", + "myfolder", "nativeproj", "NOLOGO", "Nuget", diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..772be31 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,62 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +This is a .NET Core Global Tool called `seedfolder` that creates directories and populates them with standard dotfiles. The tool is designed to quickly scaffold project folders with common configuration files. + +## Development Commands + +### Build and Test +```bash +# Build the solution +dotnet build solrevdev.seedfolder.sln --configuration Release + +# Pack for local installation +dotnet pack + +# Install locally for testing +dotnet tool install --global --add-source ./nupkg solrevdev.seedfolder + +# Uninstall after testing +dotnet tool uninstall -g solrevdev.seedfolder +``` + +### Run the Tool During Development +```bash +# Run with interactive prompts +dotnet run --project src/solrevdev.seedfolder.csproj + +# Run with folder name argument +dotnet run --project src/solrevdev.seedfolder.csproj myfolder +``` + +## Architecture + +### Single File Structure +The entire application is contained in `src/Program.cs` - a single-file console application using: +- **McMaster.Extensions.CommandLineUtils** for command-line parsing and prompts +- **Figgle** for ASCII art header generation +- **Colorful.Console** for colored console output + +### Embedded Resources +Template files are stored as embedded resources in `src/Data/` and copied to new folders: +- `dockerignore` → `.dockerignore` +- `editorconfig` → `.editorconfig` +- `gitattributes` → `.gitattributes` +- `gitignore` → `.gitignore` +- `prettierignore` → `.prettierignore` +- `prettierrc` → `.prettierrc` +- `omnisharp.json` → `omnisharp.json` + +### Key Methods +- `WriteFileAsync()` - Extracts embedded resources and writes them to the target directory +- `RemoveSpaces()` - Sanitizes folder names by replacing spaces with dashes +- `SafeNameForFileSystem()` - Removes invalid filesystem characters from folder names + +## Multi-Target Framework Support +The project targets .NET 8.0 (LTS) and 9.0 (STS) to support current and modern .NET versions. .NET 8 provides long-term support until November 2026, while .NET 9 offers the latest features with 18-month support. + +## CI/CD +GitHub Actions workflow builds, packs, and publishes to NuGet on pushes to master branch. Version is controlled by the `` property in the .csproj file. \ No newline at end of file diff --git a/README.md b/README.md index 0eb0646..1d8102c 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ For example: ```bash seedfolder -dotnet run --project src/solrevdev.seedfolder.csproj +dotnet run --project src/solrevdev.seedfolder.csproj --framework net8.0 ▲ Do you want to prefix the folder with the date? [Y/n] y ▲ What do you want the folder to be named? temp ‍▲ Creating the directory 2020-12-10_temp @@ -35,7 +35,7 @@ dotnet run --project src/solrevdev.seedfolder.csproj ▲ Done! seedfolder -dotnet run --project src/solrevdev.seedfolder.csproj +dotnet run --project src/solrevdev.seedfolder.csproj --framework net9.0 ▲ Do you want to prefix the folder with the date? [Y/n] n ▲ What do you want the folder to be named? temp ‍▲ Creating the directory temp @@ -49,7 +49,7 @@ dotnet run --project src/solrevdev.seedfolder.csproj ▲ Done! seedfolder temp -dotnet run --project src/solrevdev.seedfolder.csproj temp +dotnet run --project src/solrevdev.seedfolder.csproj --framework net8.0 temp ▲ Found 1 params to process. ‍▲ Creating the directory temp ‍▲ Copying .dockerignore to temp/.dockerignore @@ -72,6 +72,10 @@ It will also copy the following dotfiles from the `src/Data` folder over: * .prettierignore * .prettierrc +## Requirements + +This tool requires .NET 8.0 or .NET 9.0 SDK to be installed on your system. + ## Installation Locally without publishing it on NuGet diff --git a/src/solrevdev.seedfolder.csproj b/src/solrevdev.seedfolder.csproj index 71dd073..a90d73d 100644 --- a/src/solrevdev.seedfolder.csproj +++ b/src/solrevdev.seedfolder.csproj @@ -2,14 +2,14 @@ Exe - net6.0;net7.0;net8.0 + net8.0;net9.0 latest enable true seedfolder ./nupkg true - 1.2.6 + 1.3.1 solrevdev.seedfolder .NET Core Global Tool that creates a folder and copies dotfiles into it therefore seeding a folder. .NET Core Global Tool that creates a folder and copies dotfiles into it therefore seeding a folder. @@ -25,11 +25,11 @@ - + - +