Skip to content
Draft
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
4 changes: 2 additions & 2 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
"ghcr.io/devcontainers-contrib/features/starship:1": {},
// https://github.com/devcontainers/features/blob/main/src/dotnet/README.md
"ghcr.io/devcontainers/features/dotnet:2": {
"version": "9.0",
"additionalVersions": "8.0"
"version": "10.0",
"additionalVersions": "9.0,8.0"
}
},
"overrideFeatureInstallOrder": [
Expand Down
128 changes: 121 additions & 7 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,75 @@
We prefer the latest F# 9 features over the old syntax
# Copilot Instructions

Prefer `voption` over `option`
## Project Details

Prefer `task` CE over `async` CE
* .NET SDK pinned in #file:'global.json'
* Common parameters specified in #file:'Directory.Build.props'
* Central NuGet package version management – versions go in #file:'Directory.Packages.props', not in `.fsproj` files
* Build: `dotnet build FSharp.Azure.Cosmos.slnx`
* Test: `dotnet test FSharp.Azure.Cosmos.slnx` (requires Azure Cosmos DB Emulator – see below)

## Solution Structure

```text
/
├── src/Cosmos/ – main library (FSharp.Azure.Cosmos)
│ ├── Cosmos.fs – core types and container extensions
│ ├── Create.fs – item creation operations
│ ├── Read.fs – single-item read operations
│ ├── ReadMany.fs – multi-item read operations
│ ├── Replace.fs – item replace operations
│ ├── Upsert.fs – item upsert operations
│ ├── Patch.fs – item patch operations
│ ├── Delete.fs – item delete operations
│ ├── CosmosResponse.fs – response type wrappers
│ ├── TaskSeq.fs – TaskSeq integration
│ └── UniqueKey.fs – unique key helpers
├── tests/Cosmos.Tests/ – MSTest integration test project
├── build/ – FAKE build scripts
└── docsSrc/ – FSharp.Formatting documentation source
```

## Libraries in Use

* [`Microsoft.Azure.Cosmos`](https://github.com/Azure/azure-cosmos-dotnet-v3) – Azure Cosmos DB SDK v3
* [`FSharp.Control.TaskSeq`](https://github.com/fsprojects/FSharp.Control.TaskSeq) – `IAsyncEnumerable` / `taskSeq` support
* [`FSharp.Control.Reactive`](https://github.com/fsprojects/FSharp.Reactive) – Rx extensions for F#
* [`FsToolkit.ErrorHandling`](https://github.com/demystifyfp/FsToolkit.ErrorHandling) – `taskResult`, `Result`, `voption` CEs
* [`Unquote`](https://github.com/SwensenSoftware/unquote) – test assertions
* [`MSTest`](https://github.com/microsoft/testfx) – test framework

Use GitHub MCP tools for code search in these repositories when needed.

## F# Coding Guidelines

### Language Preferences

* Always use the latest F# 10 features over old syntax.
* Prefer `voption` over `option`.
* Prefer `task` CE over `async` CE.
* Prefer underscore lambda syntax like `Seq.map _.Name` over `Seq.map (fun x -> x.Name)`, but only when the expression is a simple member access. Complex expressions like `Seq.where (fun x -> x.Name = name)` or `Seq.map (fun x -> x.Field1, x.Field2)` cannot be simplified.
* Simplify `Seq.map (fun x -> someFunction x)` to `Seq.map someFunction`.
* When pipe operators are used on a materializable collection multiple times in a row, prefer `Seq` module for the chain and materialize at the end.
* Prefer interpolated strings over `printf` functions for string formatting.
* Use `withNull` for null checks instead of boxing delegates/functions (avoid `isNull (box value)`).

### Nullable Reference Types

* Declare variables non-nullable; check for `null` at entry points only.
* Trust the SDK null annotations – do not add null checks when the type system says a value cannot be null.
* Prefer `match` on `null` over `if isNull`:

```fsharp
// Preferred
match someObject with
| null -> ()
| someObject -> someObject.SomeProperty
```

### Class Constructors

This is how to define a non-default F# class constructor:

This is how you define a non-default F# class constructor:
```fsharp
type DerivedClass =
inherit BaseClass
Expand All @@ -24,10 +89,13 @@ type DerivedClass =
val mutable otherField : FieldType
```

### Class Instantiation

Always prefer F# class initializers over property assignment! **You absolutely must use F# class initializers instead of property assignment**!

Class declaration:
``` F#

```fsharp
type MyClass (someConstructorParam : string) =
member ReadOnlyProperty = someConstructorParam

Expand All @@ -36,14 +104,16 @@ type MyClass (someConstructorParam : string) =
```

Wrong:
``` F#

```fsharp
let myClass = MyClass("some value")
myClass.MutableProperty1 <- "new value"
myClass.MutableProperty2 <- "new value"
```

Right:
``` F#

```fsharp
let myClass =
MyClass(
// constructor parameters go first without names
Expand All @@ -55,3 +125,47 @@ let myClass =
(5 |> string)
)
```

### C#-Consumable Extension Members

```fsharp
// AutoOpen makes the module automatically available without an explicit open statement
// Extension makes the members visible to C#
[<AutoOpen; Extension>]
module MyTypeExtensions =

type MyType with

// Extension is visible to C#
// CompiledName makes the method name friendly to C#
[<Extension; CompiledName "ExtensionMethod">]
member this.ExtensionMethod (param1 : string) : ReturnType =
()
```

## Naming Conventions

* Use PascalCase for modules, types, and public members.
* Use camelCase for `let` bindings, functions, private fields, and local variables.
* Prefix interface names with `I` (e.g., `ICosmosContext`).
* Do not prefix type parameters with `T` (e.g., use `'Result` instead of `'TResult`).

## Testing

* Tests use MSTest 4.
* Integration tests run against the **Azure Cosmos DB Emulator**.
* The emulator must be running locally or installed via the `copilot-setup-steps.yml` workflow.
* Emulator endpoint: `https://127.0.0.1:8081`
* Emulator primary key: `C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==`
* `CollectionAssert` cannot work with F# lists – use F# array syntax (`[| ... |]`) instead.
* Use Unquote only for complex object/hierarchy assertions; for simple scalar checks prefer standard `Assert.*` APIs.
* Every `Assert.*` call **must include a failure message** so output is self-explanatory.
* Async tests must return `Task`, not `Async` or `Task<unit>` – always declare `) : Task = task {`.

## General

* Make only high-confidence suggestions when reviewing code changes.
* Write code with good maintainability practices, including comments on why certain design decisions were made.
* Handle edge cases and write clear exception handling.
* Never duplicate code unless explicitly allowed.
* All comments, documentation, README files, and markdown files must be written in **English only**.
53 changes: 53 additions & 0 deletions .github/prompts/create-pr-description.prompt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
mode: agent
description: Generates a pull request description for FSharp.Azure.Cosmos by analyzing the current branch's changes and filling in the project's PR template.
---

# Create PR Description

## Context

#file:'.github/PULL_REQUEST_TEMPLATE.md'

> If the `#file:` reference above cannot be resolved, run `Get-Content .github/PULL_REQUEST_TEMPLATE.md` in PowerShell from the repository root to read the template.

## Task

Analyze the current branch's git diff and commit history relative to the remote base branch (`origin/main`), then produce a fully filled-in PR description that conforms to the project's `PULL_REQUEST_TEMPLATE.md`.

## Steps

1. Read `#file:'.github/PULL_REQUEST_TEMPLATE.md'` to identify the exact section structure, checkbox labels, and required ordering.
2. Run `git diff origin/main...HEAD --stat`, `git diff origin/main...HEAD`, and `git log origin/main...HEAD --oneline` to determine exactly what changed in the current branch.
3. Fill `## Proposed Changes` with a concise 3–6 sentence summary of the concrete behavior, API, test, or documentation changes visible in the diff.
4. Set `## Types of changes` checkboxes strictly from evidence in commits and diff:
- mark bugfix only when existing behavior is corrected
- mark new feature only when new user-facing capability is introduced
- mark breaking change only when existing public behavior or API compatibility is intentionally broken
5. Evaluate `## Checklist` strictly from branch evidence:
- mark test-related items only if tests were added or updated in the diff
- mark documentation-related items only if docs or XML comments were changed
- if build/test execution is not visible from evidence, leave relevant items unchecked and add a brief inline note
6. Replace all placeholder/template text with branch-specific content and include `## Further comments` only when the change is large or architecturally significant.

## Guidelines

- Be factual and precise — base every statement on the actual diff and commits, not assumptions.
- Keep the **Proposed Changes** section concise but informative (3–6 sentences max).
- For checklist items that cannot be determined from the diff alone, leave them unchecked and add a short inline note.
- Do not invent issue numbers or links unless they appear in commit messages or branch names.
- Use plain English; avoid vague filler phrases like "various improvements".
- Do not start the summary with "This branch adds".
- Use only en dashes (`–`) for dashes; never use em dashes (`—`).
- Preserve all original template headings, checkbox syntax, and section order exactly.

## Output

A single fenced markdown code block containing the fully filled-out PR description, ready to copy and paste directly into GitHub. Do not escape any markdown syntax inside the block. Match the structure of `PULL_REQUEST_TEMPLATE.md` exactly:

- `## Proposed Changes` — narrative paragraph(s)
- `## Types of changes` — checkboxes with `x` placed in the correct box(es)
- `## Checklist` — checkboxes filled based on evidence from the diff
- `## Further comments` — include only when the change warrants extra explanation; omit the section entirely otherwise

Do not include any explanation or commentary outside the code block.
10 changes: 5 additions & 5 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Build main
name: Build main

on:
push:
Expand All @@ -17,13 +17,13 @@ jobs:
runs-on: ${{ matrix.os }}

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v6
- name: Setup necessary dotnet SDKs
uses: actions/setup-dotnet@v3
uses: actions/setup-dotnet@v5
with:
global-json-file: global.json
dotnet-version: |
9.x
10.x
8.x

- name: Build via Bash
Expand All @@ -47,7 +47,7 @@ jobs:
runs-on: ubuntu-latest
steps:

- uses: actions/checkout@v3
- uses: actions/checkout@v6

- name: Build and run dev container task
uses: devcontainers/ci@v0.3
Expand Down
Loading