Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ root = true
insert_final_newline = true
indent_style = space
indent_size = 4
guidelines = 120
guidelines = 140


# C# files
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
74 changes: 74 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -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
<EmbeddedResource Include="Data/dockerignore" />
<EmbeddedResource Include="Data/editorconfig" />
```
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 `<Version>` 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/[email protected]` action for NuGet deployment
- Build scripts in `build/` folder provide cross-platform local testing
6 changes: 4 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
78 changes: 78 additions & 0 deletions .github/workflows/claude-code-review.yml
Original file line number Diff line number Diff line change
@@ -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]')

64 changes: 64 additions & 0 deletions .github/workflows/claude.yml
Original file line number Diff line number Diff line change
@@ -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

1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"Figgle",
"gitattributes",
"locproj",
"myfolder",
"nativeproj",
"NOLOGO",
"Nuget",
Expand Down
62 changes: 62 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -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 `<Version>` property in the .csproj file.
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
Loading
Loading